// Copyright 2017-2020 Parity Technologies (UK) Ltd. // This file is part of Polkadot. // Polkadot is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // Polkadot is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . //! V1 Primitives. use sp_std::prelude::*; use parity_scale_codec::{Encode, Decode}; use bitvec::vec::BitVec; use primitives::RuntimeDebug; use runtime_primitives::traits::AppVerify; use inherents::InherentIdentifier; use sp_arithmetic::traits::{BaseArithmetic, Saturating, Zero}; pub use runtime_primitives::traits::{BlakeTwo256, Hash as HashT}; // Export some core primitives. pub use polkadot_core_primitives::v1::{ BlockNumber, Moment, Signature, AccountPublic, AccountId, AccountIndex, ChainId, Hash, Nonce, Balance, Header, Block, BlockId, UncheckedExtrinsic, Remark, DownwardMessage, }; // Export some polkadot-parachain primitives pub use polkadot_parachain::primitives::{ Id, ParachainDispatchOrigin, LOWEST_USER_ID, UpwardMessage, HeadData, BlockData, ValidationCode, }; // Export some basic parachain primitives from v0. pub use crate::v0::{ CollatorId, CollatorSignature, PARACHAIN_KEY_TYPE_ID, ValidatorId, ValidatorIndex, ValidatorSignature, SigningContext, Signed, ValidityAttestation, CompactStatement, SignedStatement, ErasureChunk, EncodeAs, }; // More exports from v0 for std. #[cfg(feature = "std")] pub use crate::v0::{ValidatorPair, CollatorPair}; pub use sp_staking::SessionIndex; /// Unique identifier for the Inclusion Inherent pub const INCLUSION_INHERENT_IDENTIFIER: InherentIdentifier = *b"inclusn0"; /// Get a collator signature payload on a relay-parent, block-data combo. pub fn collator_signature_payload>( relay_parent: &H, para_id: &Id, validation_data_hash: &Hash, pov_hash: &Hash, ) -> [u8; 100] { // 32-byte hash length is protected in a test below. let mut payload = [0u8; 100]; payload[0..32].copy_from_slice(relay_parent.as_ref()); u32::from(*para_id).using_encoded(|s| payload[32..32 + s.len()].copy_from_slice(s)); payload[36..68].copy_from_slice(validation_data_hash.as_ref()); payload[68..100].copy_from_slice(pov_hash.as_ref()); payload } fn check_collator_signature>( relay_parent: &H, para_id: &Id, validation_data_hash: &Hash, pov_hash: &Hash, collator: &CollatorId, signature: &CollatorSignature, ) -> Result<(),()> { let payload = collator_signature_payload( relay_parent, para_id, validation_data_hash, pov_hash, ); if signature.verify(&payload[..], collator) { Ok(()) } else { Err(()) } } /// Compute the `validation_data_hash` from global & local validation data. pub fn validation_data_hash( global: &GlobalValidationData, local: &LocalValidationData, ) -> Hash { BlakeTwo256::hash_of(&(global, local)) } /// A unique descriptor of the candidate receipt. #[derive(PartialEq, Eq, Clone, Encode, Decode)] #[cfg_attr(feature = "std", derive(Debug, Default, Hash))] pub struct CandidateDescriptor { /// The ID of the para this is a candidate for. pub para_id: Id, /// The hash of the relay-chain block this is executed in the context of. pub relay_parent: H, /// The collator's sr25519 public key. pub collator: CollatorId, /// The blake2-256 hash of the validation data. This is extra data derived from /// relay-chain state which may vary based on bitfields included before the candidate. /// Thus it cannot be derived entirely from the relay-parent. pub validation_data_hash: Hash, /// The blake2-256 hash of the pov. pub pov_hash: Hash, /// Signature on blake2-256 of components of this receipt: /// The parachain index, the relay parent, the validation data hash, and the pov_hash. pub signature: CollatorSignature, } impl> CandidateDescriptor { /// Check the signature of the collator within this descriptor. pub fn check_collator_signature(&self) -> Result<(), ()> { check_collator_signature( &self.relay_parent, &self.para_id, &self.validation_data_hash, &self.pov_hash, &self.collator, &self.signature, ) } } /// A candidate-receipt. #[derive(PartialEq, Eq, Clone, Encode, Decode)] #[cfg_attr(feature = "std", derive(Debug, Default))] pub struct CandidateReceipt { /// The descriptor of the candidate. pub descriptor: CandidateDescriptor, /// The hash of the encoded commitments made as a result of candidate execution. pub commitments_hash: Hash, } impl CandidateReceipt { /// Get a reference to the candidate descriptor. pub fn descriptor(&self) -> &CandidateDescriptor { &self.descriptor } /// Computes the blake2-256 hash of the receipt. pub fn hash(&self) -> Hash where H: Encode { BlakeTwo256::hash_of(self) } } /// All data pertaining to the execution of a para candidate. #[derive(PartialEq, Eq, Clone, Encode, Decode)] #[cfg_attr(feature = "std", derive(Debug, Default))] pub struct FullCandidateReceipt { /// The inner candidate receipt. pub inner: CandidateReceipt, /// The global validation schedule. pub global_validation: GlobalValidationData, /// The local validation data. pub local_validation: LocalValidationData, } /// A candidate-receipt with commitments directly included. #[derive(PartialEq, Eq, Clone, Encode, Decode)] #[cfg_attr(feature = "std", derive(Debug, Default, Hash))] pub struct CommittedCandidateReceipt { /// The descriptor of the candidate. pub descriptor: CandidateDescriptor, /// The commitments of the candidate receipt. pub commitments: CandidateCommitments, } impl CommittedCandidateReceipt { /// Get a reference to the candidate descriptor. pub fn descriptor(&self) -> &CandidateDescriptor { &self.descriptor } } impl CommittedCandidateReceipt { /// Transforms this into a plain CandidateReceipt. pub fn to_plain(&self) -> CandidateReceipt { CandidateReceipt { descriptor: self.descriptor.clone(), commitments_hash: self.commitments.hash(), } } /// Computes the hash of the committed candidate receipt. /// /// This computes the canonical hash, not the hash of the directly encoded data. /// Thus this is a shortcut for `candidate.to_plain().hash()`. pub fn hash(&self) -> Hash where H: Encode { self.to_plain().hash() } } impl PartialOrd for CommittedCandidateReceipt { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } impl Ord for CommittedCandidateReceipt { fn cmp(&self, other: &Self) -> sp_std::cmp::Ordering { // TODO: compare signatures or something more sane // https://github.com/paritytech/polkadot/issues/222 self.descriptor().para_id.cmp(&other.descriptor().para_id) .then_with(|| self.commitments.head_data.cmp(&other.commitments.head_data)) } } /// Extra data that is needed along with the other fields in a `CandidateReceipt` /// to fully validate the candidate. These fields are parachain-specific. #[derive(PartialEq, Eq, Clone, Encode, Decode)] #[cfg_attr(feature = "std", derive(Debug, Default))] pub struct LocalValidationData { /// The parent head-data. pub parent_head: HeadData, /// The balance of the parachain at the moment of validation. pub balance: Balance, /// The blake2-256 hash of the validation code used to execute the candidate. pub validation_code_hash: Hash, /// Whether the parachain is allowed to upgrade its validation code. /// /// This is `Some` if so, and contains the number of the minimum relay-chain /// height at which the upgrade will be applied, if an upgrade is signaled /// now. /// /// A parachain should enact its side of the upgrade at the end of the first /// parablock executing in the context of a relay-chain block with at least this /// height. This may be equal to the current perceived relay-chain block height, in /// which case the code upgrade should be applied at the end of the signaling /// block. pub code_upgrade_allowed: Option, } /// Extra data that is needed along with the other fields in a `CandidateReceipt` /// to fully validate the candidate. /// /// These are global parameters that apply to all candidates in a block. #[derive(PartialEq, Eq, Clone, Encode, Decode)] #[cfg_attr(feature = "std", derive(Debug, Default))] pub struct GlobalValidationData { /// The maximum code size permitted, in bytes. pub max_code_size: u32, /// The maximum head-data size permitted, in bytes. pub max_head_data_size: u32, /// The relay-chain block number this is in the context of. pub block_number: N, } /// Commitments made in a `CandidateReceipt`. Many of these are outputs of validation. #[derive(PartialEq, Eq, Clone, Encode, Decode)] #[cfg_attr(feature = "std", derive(Debug, Default, Hash))] pub struct CandidateCommitments { /// Fees paid from the chain to the relay chain validators. pub fees: Balance, /// Messages destined to be interpreted by the Relay chain itself. pub upward_messages: Vec, /// The root of a block's erasure encoding Merkle tree. pub erasure_root: Hash, /// New validation code. pub new_validation_code: Option, /// The head-data produced as a result of execution. pub head_data: HeadData, } impl CandidateCommitments { /// Compute the blake2-256 hash of the commitments. pub fn hash(&self) -> Hash { BlakeTwo256::hash_of(self) } } /// A Proof-of-Validity #[derive(PartialEq, Eq, Clone, Encode, Decode)] #[cfg_attr(feature = "std", derive(Debug))] pub struct PoV { /// The block witness data. pub block_data: BlockData, } impl PoV { /// Get the blake2-256 hash of the PoV. #[cfg(feature = "std")] pub fn hash(&self) -> Hash { BlakeTwo256::hash_of(self) } } /// A bitfield concerning availability of backed candidates. #[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug)] pub struct AvailabilityBitfield(pub BitVec); impl From> for AvailabilityBitfield { fn from(inner: BitVec) -> Self { AvailabilityBitfield(inner) } } /// A bitfield signed by a particular validator about the availability of pending candidates. pub type SignedAvailabilityBitfield = Signed; /// A set of signed availability bitfields. Should be sorted by validator index, ascending. pub type SignedAvailabilityBitfields = Vec; /// A backed (or backable, depending on context) candidate. #[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug)] pub struct BackedCandidate { /// The candidate referred to. pub candidate: CommittedCandidateReceipt, /// The validity votes themselves, expressed as signatures. pub validity_votes: Vec, /// The indices of the validators within the group, expressed as a bitfield. pub validator_indices: BitVec, } impl BackedCandidate { /// Get a reference to the descriptor of the para. pub fn descriptor(&self) -> &CandidateDescriptor { &self.candidate.descriptor } } /// 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>( backed: &BackedCandidate, signing_context: &SigningContext, group_len: usize, validator_lookup: impl Fn(usize) -> Option, ) -> Result { if backed.validator_indices.len() != group_len { return Err(()) } if backed.validity_votes.len() > group_len { return Err(()) } // this is known, even in runtime, to be blake2-256. let hash: Hash = backed.candidate.hash(); let mut signed = 0; for ((val_in_group_idx, _), attestation) in backed.validator_indices.iter().enumerate() .filter(|(_, signed)| **signed) .zip(backed.validity_votes.iter()) { let validator_id = validator_lookup(val_in_group_idx).ok_or(())?; let payload = attestation.signed_payload(hash.clone(), signing_context); let sig = attestation.signature(); if sig.verify(&payload[..], &validator_id) { signed += 1; } else { return Err(()) } } if signed != backed.validity_votes.len() { return Err(()) } Ok(signed) } /// The unique (during session) index of a core. #[derive(Encode, Decode, Default, PartialOrd, Ord, Eq, PartialEq, Clone, Copy)] #[cfg_attr(feature = "std", derive(Debug))] pub struct CoreIndex(pub u32); impl From for CoreIndex { fn from(i: u32) -> CoreIndex { CoreIndex(i) } } /// The unique (during session) index of a validator group. #[derive(Encode, Decode, Default, Clone, Copy)] #[cfg_attr(feature = "std", derive(Eq, Hash, PartialEq, Debug))] pub struct GroupIndex(pub u32); impl From for GroupIndex { fn from(i: u32) -> GroupIndex { GroupIndex(i) } } /// A claim on authoring the next block for a given parathread. #[derive(Clone, Encode, Decode, Default)] #[cfg_attr(feature = "std", derive(PartialEq, Debug))] pub struct ParathreadClaim(pub Id, pub CollatorId); /// An entry tracking a claim to ensure it does not pass the maximum number of retries. #[derive(Clone, Encode, Decode, Default)] #[cfg_attr(feature = "std", derive(PartialEq, Debug))] pub struct ParathreadEntry { /// The claim. pub claim: ParathreadClaim, /// Number of retries. pub retries: u32, } /// What is occupying a specific availability core. #[derive(Clone, Encode, Decode)] #[cfg_attr(feature = "std", derive(PartialEq, Debug))] pub enum CoreOccupied { /// A parathread. Parathread(ParathreadEntry), /// A parachain. Parachain, } /// The assignment type. #[derive(Clone, Encode, Decode)] #[cfg_attr(feature = "std", derive(PartialEq, Debug))] pub enum AssignmentKind { /// A parachain. Parachain, /// A parathread. Parathread(CollatorId, u32), } /// How a free core is scheduled to be assigned. #[derive(Clone, Encode, Decode)] #[cfg_attr(feature = "std", derive(PartialEq, Debug))] pub struct CoreAssignment { /// The core that is assigned. pub core: CoreIndex, /// The unique ID of the para that is assigned to the core. pub para_id: Id, /// The kind of the assignment. pub kind: AssignmentKind, /// The index of the validator group assigned to the core. pub group_idx: GroupIndex, } impl CoreAssignment { /// Get the ID of a collator who is required to collate this block. pub fn required_collator(&self) -> Option<&CollatorId> { match self.kind { AssignmentKind::Parachain => None, AssignmentKind::Parathread(ref id, _) => Some(id), } } /// Get the `CoreOccupied` from this. pub fn to_core_occupied(&self) -> CoreOccupied { match self.kind { AssignmentKind::Parachain => CoreOccupied::Parachain, AssignmentKind::Parathread(ref collator, retries) => CoreOccupied::Parathread( ParathreadEntry { claim: ParathreadClaim(self.para_id, collator.clone()), retries, } ), } } } /// Validation data omitted from most candidate descriptor structs, as it can be derived from the /// relay-parent. #[derive(Clone, Encode, Decode)] #[cfg_attr(feature = "std", derive(PartialEq, Debug, Default))] pub struct OmittedValidationData { /// The global validation schedule. pub global_validation: GlobalValidationData, /// The local validation data. pub local_validation: LocalValidationData, } /// This is the data we keep available for each candidate included in the relay chain. #[derive(Clone, Encode, Decode)] #[cfg_attr(feature = "std", derive(PartialEq, Debug))] pub struct AvailableData { /// The Proof-of-Validation of the candidate. pub pov: PoV, /// The omitted validation data. pub omitted_validation: OmittedValidationData, } /// A helper data-type for tracking validator-group rotations. #[derive(Clone, Encode, Decode)] #[cfg_attr(feature = "std", derive(PartialEq, Debug))] 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 = sp_std::cmp::min(cores, u32::max_value() as usize); let blocks_since_start = self.now.saturating_sub(self.session_start_block); let rotations = blocks_since_start / self.group_rotation_frequency; let idx = (core_index.0 as usize + rotations as usize) % cores; GroupIndex(idx as u32) } } 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. /// /// If the group rotation frequency is 0, returns 0. pub fn next_rotation_at(&self) -> N { if self.group_rotation_frequency.is_zero() { return Zero::zero() } 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. /// /// If the group rotation frequency is 0, returns 0. pub fn last_rotation_at(&self) -> N { if self.group_rotation_frequency.is_zero() { return Zero::zero() } 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)] #[cfg_attr(feature = "std", derive(PartialEq, Debug))] pub struct OccupiedCore { /// The ID of the para occupying the core. pub para_id: Id, /// If this core is freed by availability, this is the assignment that is next up on this /// core, if any. None if there is nothing queued for this core. pub next_up_on_available: Option, /// The relay-chain block number this began occupying the core at. pub occupied_since: N, /// The relay-chain block this will time-out at, if any. pub time_out_at: N, /// If this core is freed by being timed-out, this is the assignment that is next up on this /// core. None if there is nothing queued for this core or there is no possibility of timing /// out. pub next_up_on_time_out: Option, /// A bitfield with 1 bit for each validator in the set. `1` bits mean that the corresponding /// validators has attested to availability on-chain. A 2/3+ majority of `1` bits means that /// this will be available. pub availability: BitVec, /// The group assigned to distribute availability pieces of this candidate. pub group_responsible: GroupIndex, } /// Information about a core which is currently occupied. #[derive(Clone, Encode, Decode)] #[cfg_attr(feature = "std", derive(PartialEq, Debug, Default))] pub struct ScheduledCore { /// The ID of a para scheduled. pub para_id: Id, /// The collator required to author the block, if any. pub collator: Option, } /// The state of a particular availability core. #[derive(Clone, Encode, Decode)] #[cfg_attr(feature = "std", derive(PartialEq, Debug))] pub enum CoreState { /// The core is currently occupied. #[codec(index = "0")] Occupied(OccupiedCore), /// The core is currently free, with a para scheduled and given the opportunity /// to occupy. /// /// If a particular Collator is required to author this block, that is also present in this /// variant. #[codec(index = "1")] Scheduled(ScheduledCore), /// The core is currently free and there is nothing scheduled. This can be the case for parathread /// cores when there are no parathread blocks queued. Parachain cores will never be left idle. #[codec(index = "2")] Free, } impl CoreState { /// If this core state has a `para_id`, return it. pub fn para_id(&self) -> Option { match self { Self::Occupied(OccupiedCore { para_id, ..}) => Some(*para_id), Self::Scheduled(ScheduledCore { para_id, .. }) => Some(*para_id), Self::Free => None, } } } /// An assumption being made about the state of an occupied core. #[derive(Clone, Copy, Encode, Decode)] #[cfg_attr(feature = "std", derive(PartialEq, Debug))] 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, } /// An even concerning a candidate. #[derive(Clone, Encode, Decode)] #[cfg_attr(feature = "std", derive(PartialEq, Debug))] pub enum CandidateEvent { /// This candidate receipt was backed in the most recent block. #[codec(index = "0")] CandidateBacked(CandidateReceipt, HeadData), /// This candidate receipt was included and became a parablock at the most recent block. #[codec(index = "1")] CandidateIncluded(CandidateReceipt, HeadData), /// This candidate receipt was not made available in time and timed out. #[codec(index = "2")] CandidateTimedOut(CandidateReceipt, HeadData), } sp_api::decl_runtime_apis! { /// The API for querying the state of parachains on-chain. pub trait ParachainHost { /// Get the current validators. fn validators() -> Vec; /// Returns the validator groups and rotation info localized based on the block whose state /// this is invoked on. Note that `now` in the `GroupRotationInfo` should be the successor of /// the number of the block. fn validator_groups() -> (Vec>, GroupRotationInfo); /// Yields information on all availability cores. Cores are either free or occupied. Free /// cores can have paras assigned to them. fn availability_cores() -> Vec>; /// Yields the GlobalValidationData. This applies to all para candidates with the /// relay-parent equal to the block in which context this is invoked in. fn global_validation_data() -> GlobalValidationData; /// Yields the LocalValidationData for the given ParaId along with an assumption that /// should be used if the para currently occupies a core. /// /// Returns `None` if either the para is not registered or the assumption is `Freed` /// and the para already occupies a core. fn local_validation_data(para_id: Id, assumption: OccupiedCoreAssumption) -> Option>; /// Returns the session index expected at a child of the block. /// /// This can be used to instantiate a `SigningContext`. fn session_index_for_child() -> SessionIndex; /// Fetch the validation code used by a para, making the given `OccupiedCoreAssumption`. /// /// Returns `None` if either the para is not registered or the assumption is `Freed` /// and the para already occupies a core. fn validation_code(para_id: Id, assumption: OccupiedCoreAssumption) -> Option; /// Get the receipt of a candidate pending availability. This returns `Some` for any paras /// assigned to occupied cores in `availability_cores` and `None` otherwise. fn candidate_pending_availability(para_id: Id) -> Option>; /// Get a vector of events concerning candidates that occurred within a block. // NOTE: this needs to skip block initialization as events are wiped within block // initialization. #[skip_initialize_block] fn candidate_events() -> Vec>; } } #[cfg(test)] mod tests { use super::*; #[test] fn group_rotation_info_calculations() { let info = GroupRotationInfo { session_start_block: 10u32, now: 15, group_rotation_frequency: 5, }; assert_eq!(info.next_rotation_at(), 20); assert_eq!(info.last_rotation_at(), 15); let info = GroupRotationInfo { session_start_block: 10u32, now: 11, group_rotation_frequency: 0, }; assert_eq!(info.next_rotation_at(), 0); assert_eq!(info.last_rotation_at(), 0); } #[test] fn collator_signature_payload_is_valid() { // if this fails, collator signature verification code has to be updated. let h = Hash::default(); assert_eq!(h.as_ref().len(), 32); let _payload = collator_signature_payload( &Hash::from([1; 32]), &5u32.into(), &Hash::from([2; 32]), &Hash::from([3; 32]), ); } }