// Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Polkadot. // Polkadot is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // Polkadot is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . //! Network protocol types for parachains. #![deny(unused_crate_dependencies)] #![warn(missing_docs)] use parity_scale_codec::{Decode, Encode}; use polkadot_primitives::{BlockNumber, Hash}; use std::{collections::HashMap, fmt}; #[doc(hidden)] pub use polkadot_node_jaeger as jaeger; pub use sc_network::{IfDisconnected, PeerId}; #[doc(hidden)] pub use std::sync::Arc; mod reputation; pub use self::reputation::{ReputationChange, UnifiedReputationChange}; /// Peer-sets and protocols used for parachains. pub mod peer_set; /// Request/response protocols used in Polkadot. pub mod request_response; /// Accessing authority discovery service pub mod authority_discovery; /// Grid topology support module pub mod grid_topology; /// The minimum amount of peers to send gossip messages to. pub const MIN_GOSSIP_PEERS: usize = 25; /// An error indicating that this the over-arching message type had the wrong variant #[derive(Debug, Clone, Copy, PartialEq)] pub struct WrongVariant; impl fmt::Display for WrongVariant { fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { write!(formatter, "Wrong message variant") } } impl std::error::Error for WrongVariant {} /// The advertised role of a node. #[derive(Debug, Clone, Copy, PartialEq)] pub enum ObservedRole { /// A light node. Light, /// A full node. Full, /// A node claiming to be an authority (unauthenticated) Authority, } impl From for ObservedRole { fn from(role: sc_network::ObservedRole) -> ObservedRole { match role { sc_network::ObservedRole::Light => ObservedRole::Light, sc_network::ObservedRole::Authority => ObservedRole::Authority, sc_network::ObservedRole::Full => ObservedRole::Full, } } } impl Into for ObservedRole { fn into(self) -> sc_network::ObservedRole { match self { ObservedRole::Light => sc_network::ObservedRole::Light, ObservedRole::Full => sc_network::ObservedRole::Full, ObservedRole::Authority => sc_network::ObservedRole::Authority, } } } /// Specialized wrapper around [`View`]. /// /// Besides the access to the view itself, it also gives access to the [`jaeger::Span`] per /// leave/head. #[derive(Debug, Clone, Default)] pub struct OurView { view: View, span_per_head: HashMap>, } impl OurView { /// Creates a new instance. pub fn new( heads: impl IntoIterator)>, finalized_number: BlockNumber, ) -> Self { let state_per_head = heads.into_iter().collect::>(); let view = View::new(state_per_head.keys().cloned(), finalized_number); Self { view, span_per_head: state_per_head } } /// Returns the span per head map. /// /// For each head there exists one span in this map. pub fn span_per_head(&self) -> &HashMap> { &self.span_per_head } } impl PartialEq for OurView { fn eq(&self, other: &Self) -> bool { self.view == other.view } } impl std::ops::Deref for OurView { type Target = View; fn deref(&self) -> &View { &self.view } } /// Construct a new [`OurView`] with the given chain heads, finalized number 0 and disabled /// [`jaeger::Span`]'s. /// /// NOTE: Use for tests only. /// /// # Example /// /// ``` /// # use polkadot_node_network_protocol::our_view; /// # use polkadot_primitives::Hash; /// let our_view = our_view![Hash::repeat_byte(1), Hash::repeat_byte(2)]; /// ``` #[macro_export] macro_rules! our_view { ( $( $hash:expr ),* $(,)? ) => { $crate::OurView::new( vec![ $( $hash.clone() ),* ].into_iter().map(|h| (h, $crate::Arc::new($crate::jaeger::Span::Disabled))), 0, ) }; } /// A succinct representation of a peer's view. This consists of a bounded amount of chain heads /// and the highest known finalized block number. /// /// Up to `N` (5?) chain heads. #[derive(Default, Debug, Clone, PartialEq, Eq, Encode, Decode)] pub struct View { /// A bounded amount of chain heads. /// Invariant: Sorted. heads: Vec, /// The highest known finalized block number. pub finalized_number: BlockNumber, } /// Construct a new view with the given chain heads and finalized number 0. /// /// NOTE: Use for tests only. /// /// # Example /// /// ``` /// # use polkadot_node_network_protocol::view; /// # use polkadot_primitives::Hash; /// let view = view![Hash::repeat_byte(1), Hash::repeat_byte(2)]; /// ``` #[macro_export] macro_rules! view { ( $( $hash:expr ),* $(,)? ) => { $crate::View::new(vec![ $( $hash.clone() ),* ], 0) }; } impl View { /// Construct a new view based on heads and a finalized block number. pub fn new(heads: impl IntoIterator, finalized_number: BlockNumber) -> Self { let mut heads = heads.into_iter().collect::>(); heads.sort(); Self { heads, finalized_number } } /// Start with no heads, but only a finalized block number. pub fn with_finalized(finalized_number: BlockNumber) -> Self { Self { heads: Vec::new(), finalized_number } } /// Obtain the number of heads that are in view. pub fn len(&self) -> usize { self.heads.len() } /// Check if the number of heads contained, is null. pub fn is_empty(&self) -> bool { self.heads.is_empty() } /// Obtain an iterator over all heads. pub fn iter(&self) -> impl Iterator { self.heads.iter() } /// Obtain an iterator over all heads. pub fn into_iter(self) -> impl Iterator { self.heads.into_iter() } /// Replace `self` with `new`. /// /// Returns an iterator that will yield all elements of `new` that were not part of `self`. pub fn replace_difference(&mut self, new: View) -> impl Iterator { let old = std::mem::replace(self, new); self.heads.iter().filter(move |h| !old.contains(h)) } /// Returns an iterator of the hashes present in `Self` but not in `other`. pub fn difference<'a>(&'a self, other: &'a View) -> impl Iterator + 'a { self.heads.iter().filter(move |h| !other.contains(h)) } /// An iterator containing hashes present in both `Self` and in `other`. pub fn intersection<'a>(&'a self, other: &'a View) -> impl Iterator + 'a { self.heads.iter().filter(move |h| other.contains(h)) } /// Whether the view contains a given hash. pub fn contains(&self, hash: &Hash) -> bool { self.heads.contains(hash) } /// Check if two views have the same heads. /// /// Equivalent to the `PartialEq` function, /// but ignores the `finalized_number` field. pub fn check_heads_eq(&self, other: &Self) -> bool { self.heads == other.heads } } /// A protocol-versioned type. #[derive(Debug, Clone, PartialEq, Eq)] pub enum Versioned { /// V1 type. V1(V1), /// V2 type. V2(V2), /// V3 type V3(V3), } impl Versioned<&'_ V1, &'_ V2, &'_ V3> { /// Convert to a fully-owned version of the message. pub fn clone_inner(&self) -> Versioned { match *self { Versioned::V1(inner) => Versioned::V1(inner.clone()), Versioned::V2(inner) => Versioned::V2(inner.clone()), Versioned::V3(inner) => Versioned::V3(inner.clone()), } } } /// All supported versions of the validation protocol message. pub type VersionedValidationProtocol = Versioned; impl From for VersionedValidationProtocol { fn from(v1: v1::ValidationProtocol) -> Self { VersionedValidationProtocol::V1(v1) } } impl From for VersionedValidationProtocol { fn from(v2: v2::ValidationProtocol) -> Self { VersionedValidationProtocol::V2(v2) } } impl From for VersionedValidationProtocol { fn from(v3: v3::ValidationProtocol) -> Self { VersionedValidationProtocol::V3(v3) } } /// All supported versions of the collation protocol message. pub type VersionedCollationProtocol = Versioned; impl From for VersionedCollationProtocol { fn from(v1: v1::CollationProtocol) -> Self { VersionedCollationProtocol::V1(v1) } } impl From for VersionedCollationProtocol { fn from(v2: v2::CollationProtocol) -> Self { VersionedCollationProtocol::V2(v2) } } macro_rules! impl_versioned_full_protocol_from { ($from:ty, $out:ty, $variant:ident) => { impl From<$from> for $out { fn from(versioned_from: $from) -> $out { match versioned_from { Versioned::V1(x) => Versioned::V1(x.into()), Versioned::V2(x) => Versioned::V2(x.into()), Versioned::V3(x) => Versioned::V3(x.into()), } } } }; } /// Implement `TryFrom` for one versioned enum variant into the inner type. /// `$m_ty::$variant(inner) -> Ok(inner)` macro_rules! impl_versioned_try_from { ( $from:ty, $out:ty, $v1_pat:pat => $v1_out:expr, $v2_pat:pat => $v2_out:expr, $v3_pat:pat => $v3_out:expr ) => { impl TryFrom<$from> for $out { type Error = crate::WrongVariant; fn try_from(x: $from) -> Result<$out, Self::Error> { #[allow(unreachable_patterns)] // when there is only one variant match x { Versioned::V1($v1_pat) => Ok(Versioned::V1($v1_out)), Versioned::V2($v2_pat) => Ok(Versioned::V2($v2_out)), Versioned::V3($v3_pat) => Ok(Versioned::V3($v3_out)), _ => Err(crate::WrongVariant), } } } impl<'a> TryFrom<&'a $from> for $out { type Error = crate::WrongVariant; fn try_from(x: &'a $from) -> Result<$out, Self::Error> { #[allow(unreachable_patterns)] // when there is only one variant match x { Versioned::V1($v1_pat) => Ok(Versioned::V1($v1_out.clone())), Versioned::V2($v2_pat) => Ok(Versioned::V2($v2_out.clone())), Versioned::V3($v3_pat) => Ok(Versioned::V3($v3_out.clone())), _ => Err(crate::WrongVariant), } } } }; } /// Version-annotated messages used by the bitfield distribution subsystem. pub type BitfieldDistributionMessage = Versioned< v1::BitfieldDistributionMessage, v2::BitfieldDistributionMessage, v3::BitfieldDistributionMessage, >; impl_versioned_full_protocol_from!( BitfieldDistributionMessage, VersionedValidationProtocol, BitfieldDistribution ); impl_versioned_try_from!( VersionedValidationProtocol, BitfieldDistributionMessage, v1::ValidationProtocol::BitfieldDistribution(x) => x, v2::ValidationProtocol::BitfieldDistribution(x) => x, v3::ValidationProtocol::BitfieldDistribution(x) => x ); /// Version-annotated messages used by the statement distribution subsystem. pub type StatementDistributionMessage = Versioned< v1::StatementDistributionMessage, v2::StatementDistributionMessage, v3::StatementDistributionMessage, >; impl_versioned_full_protocol_from!( StatementDistributionMessage, VersionedValidationProtocol, StatementDistribution ); impl_versioned_try_from!( VersionedValidationProtocol, StatementDistributionMessage, v1::ValidationProtocol::StatementDistribution(x) => x, v2::ValidationProtocol::StatementDistribution(x) => x, v3::ValidationProtocol::StatementDistribution(x) => x ); /// Version-annotated messages used by the approval distribution subsystem. pub type ApprovalDistributionMessage = Versioned< v1::ApprovalDistributionMessage, v2::ApprovalDistributionMessage, v3::ApprovalDistributionMessage, >; impl_versioned_full_protocol_from!( ApprovalDistributionMessage, VersionedValidationProtocol, ApprovalDistribution ); impl_versioned_try_from!( VersionedValidationProtocol, ApprovalDistributionMessage, v1::ValidationProtocol::ApprovalDistribution(x) => x, v2::ValidationProtocol::ApprovalDistribution(x) => x, v3::ValidationProtocol::ApprovalDistribution(x) => x ); /// Version-annotated messages used by the gossip-support subsystem (this is void). pub type GossipSupportNetworkMessage = Versioned< v1::GossipSupportNetworkMessage, v2::GossipSupportNetworkMessage, v3::GossipSupportNetworkMessage, >; // This is a void enum placeholder, so never gets sent over the wire. impl TryFrom for GossipSupportNetworkMessage { type Error = WrongVariant; fn try_from(_: VersionedValidationProtocol) -> Result { Err(WrongVariant) } } impl<'a> TryFrom<&'a VersionedValidationProtocol> for GossipSupportNetworkMessage { type Error = WrongVariant; fn try_from(_: &'a VersionedValidationProtocol) -> Result { Err(WrongVariant) } } /// Version-annotated messages used by the bitfield distribution subsystem. pub type CollatorProtocolMessage = Versioned; impl_versioned_full_protocol_from!( CollatorProtocolMessage, VersionedCollationProtocol, CollatorProtocol ); impl_versioned_try_from!( VersionedCollationProtocol, CollatorProtocolMessage, v1::CollationProtocol::CollatorProtocol(x) => x, v2::CollationProtocol::CollatorProtocol(x) => x, v2::CollationProtocol::CollatorProtocol(x) => x ); /// v1 notification protocol types. pub mod v1 { use parity_scale_codec::{Decode, Encode}; use polkadot_primitives::{ CandidateHash, CandidateIndex, CollatorId, CollatorSignature, CompactStatement, Hash, Id as ParaId, UncheckedSignedAvailabilityBitfield, ValidatorIndex, ValidatorSignature, }; use polkadot_node_primitives::{ approval::v1::{IndirectAssignmentCert, IndirectSignedApprovalVote}, UncheckedSignedFullStatement, }; /// Network messages used by the bitfield distribution subsystem. #[derive(Debug, Clone, Encode, Decode, PartialEq, Eq)] pub enum BitfieldDistributionMessage { /// A signed availability bitfield for a given relay-parent hash. #[codec(index = 0)] Bitfield(Hash, UncheckedSignedAvailabilityBitfield), } /// Network messages used by the statement distribution subsystem. #[derive(Debug, Clone, Encode, Decode, PartialEq, Eq)] pub enum StatementDistributionMessage { /// A signed full statement under a given relay-parent. #[codec(index = 0)] Statement(Hash, UncheckedSignedFullStatement), /// Seconded statement with large payload (e.g. containing a runtime upgrade). /// /// We only gossip the hash in that case, actual payloads can be fetched from sending node /// via request/response. #[codec(index = 1)] LargeStatement(StatementMetadata), } /// Data that makes a statement unique. #[derive(Debug, Clone, Encode, Decode, PartialEq, Eq, Hash)] pub struct StatementMetadata { /// Relay parent this statement is relevant under. pub relay_parent: Hash, /// Hash of the candidate that got validated. pub candidate_hash: CandidateHash, /// Validator that attested the validity. pub signed_by: ValidatorIndex, /// Signature of seconding validator. pub signature: ValidatorSignature, } impl StatementDistributionMessage { /// Get fingerprint describing the contained statement uniquely. pub fn get_fingerprint(&self) -> (CompactStatement, ValidatorIndex) { match self { Self::Statement(_, statement) => ( statement.unchecked_payload().to_compact(), statement.unchecked_validator_index(), ), Self::LargeStatement(meta) => (CompactStatement::Seconded(meta.candidate_hash), meta.signed_by), } } /// Get the signature from the statement. pub fn get_signature(&self) -> ValidatorSignature { match self { Self::Statement(_, statement) => statement.unchecked_signature().clone(), Self::LargeStatement(metadata) => metadata.signature.clone(), } } /// Get contained relay parent. pub fn get_relay_parent(&self) -> Hash { match self { Self::Statement(r, _) => *r, Self::LargeStatement(meta) => meta.relay_parent, } } /// Whether this message contains a large statement. pub fn is_large_statement(&self) -> bool { if let Self::LargeStatement(_) = self { true } else { false } } } /// Network messages used by the approval distribution subsystem. #[derive(Debug, Clone, Encode, Decode, PartialEq, Eq)] pub enum ApprovalDistributionMessage { /// Assignments for candidates in recent, unfinalized blocks. /// /// Actually checking the assignment may yield a different result. #[codec(index = 0)] Assignments(Vec<(IndirectAssignmentCert, CandidateIndex)>), /// Approvals for candidates in some recent, unfinalized block. #[codec(index = 1)] Approvals(Vec), } /// Dummy network message type, so we will receive connect/disconnect events. #[derive(Debug, Clone, PartialEq, Eq)] pub enum GossipSupportNetworkMessage {} /// Network messages used by the collator protocol subsystem #[derive(Debug, Clone, Encode, Decode, PartialEq, Eq)] pub enum CollatorProtocolMessage { /// Declare the intent to advertise collations under a collator ID, attaching a /// signature of the `PeerId` of the node using the given collator ID key. #[codec(index = 0)] Declare(CollatorId, ParaId, CollatorSignature), /// Advertise a collation to a validator. Can only be sent once the peer has /// declared that they are a collator with given ID. #[codec(index = 1)] AdvertiseCollation(Hash), /// A collation sent to a validator was seconded. #[codec(index = 4)] CollationSeconded(Hash, UncheckedSignedFullStatement), } /// All network messages on the validation peer-set. #[derive(Debug, Clone, Encode, Decode, PartialEq, Eq, derive_more::From)] pub enum ValidationProtocol { /// Bitfield distribution messages #[codec(index = 1)] #[from] BitfieldDistribution(BitfieldDistributionMessage), /// Statement distribution messages #[codec(index = 3)] #[from] StatementDistribution(StatementDistributionMessage), /// Approval distribution messages #[codec(index = 4)] #[from] ApprovalDistribution(ApprovalDistributionMessage), } /// All network messages on the collation peer-set. #[derive(Debug, Clone, Encode, Decode, PartialEq, Eq, derive_more::From)] pub enum CollationProtocol { /// Collator protocol messages #[codec(index = 0)] #[from] CollatorProtocol(CollatorProtocolMessage), } /// Get the payload that should be signed and included in a `Declare` message. /// /// The payload is the local peer id of the node, which serves to prove that it /// controls the collator key it is declaring an intention to collate under. pub fn declare_signature_payload(peer_id: &sc_network::PeerId) -> Vec { let mut payload = peer_id.to_bytes(); payload.extend_from_slice(b"COLL"); payload } } /// v2 network protocol types. pub mod v2 { use bitvec::{order::Lsb0, slice::BitSlice, vec::BitVec}; use parity_scale_codec::{Decode, Encode}; use polkadot_primitives::{ CandidateHash, CandidateIndex, CollatorId, CollatorSignature, GroupIndex, Hash, Id as ParaId, UncheckedSignedAvailabilityBitfield, UncheckedSignedStatement, }; use polkadot_node_primitives::{ approval::v1::{IndirectAssignmentCert, IndirectSignedApprovalVote}, UncheckedSignedFullStatement, }; /// Network messages used by the bitfield distribution subsystem. #[derive(Debug, Clone, Encode, Decode, PartialEq, Eq)] pub enum BitfieldDistributionMessage { /// A signed availability bitfield for a given relay-parent hash. #[codec(index = 0)] Bitfield(Hash, UncheckedSignedAvailabilityBitfield), } /// Bitfields indicating the statements that are known or undesired /// about a candidate. #[derive(Debug, Clone, Encode, Decode, PartialEq, Eq)] pub struct StatementFilter { /// Seconded statements. '1' is known or undesired. pub seconded_in_group: BitVec, /// Valid statements. '1' is known or undesired. pub validated_in_group: BitVec, } impl StatementFilter { /// Create a new blank filter with the given group size. pub fn blank(group_size: usize) -> Self { StatementFilter { seconded_in_group: BitVec::repeat(false, group_size), validated_in_group: BitVec::repeat(false, group_size), } } /// Create a new full filter with the given group size. pub fn full(group_size: usize) -> Self { StatementFilter { seconded_in_group: BitVec::repeat(true, group_size), validated_in_group: BitVec::repeat(true, group_size), } } /// Whether the filter has a specific expected length, consistent across both /// bitfields. pub fn has_len(&self, len: usize) -> bool { self.seconded_in_group.len() == len && self.validated_in_group.len() == len } /// Determine the number of backing validators in the statement filter. pub fn backing_validators(&self) -> usize { self.seconded_in_group .iter() .by_vals() .zip(self.validated_in_group.iter().by_vals()) .filter(|&(s, v)| s || v) // no double-counting .count() } /// Whether the statement filter has at least one seconded statement. pub fn has_seconded(&self) -> bool { self.seconded_in_group.iter().by_vals().any(|x| x) } /// Mask out `Seconded` statements in `self` according to the provided /// bitvec. Bits appearing in `mask` will not appear in `self` afterwards. pub fn mask_seconded(&mut self, mask: &BitSlice) { for (mut x, mask) in self .seconded_in_group .iter_mut() .zip(mask.iter().by_vals().chain(std::iter::repeat(false))) { // (x, mask) => x // (true, true) => false // (true, false) => true // (false, true) => false // (false, false) => false *x = *x && !mask; } } /// Mask out `Valid` statements in `self` according to the provided /// bitvec. Bits appearing in `mask` will not appear in `self` afterwards. pub fn mask_valid(&mut self, mask: &BitSlice) { for (mut x, mask) in self .validated_in_group .iter_mut() .zip(mask.iter().by_vals().chain(std::iter::repeat(false))) { // (x, mask) => x // (true, true) => false // (true, false) => true // (false, true) => false // (false, false) => false *x = *x && !mask; } } } /// A manifest of a known backed candidate, along with a description /// of the statements backing it. #[derive(Debug, Clone, Encode, Decode, PartialEq, Eq)] pub struct BackedCandidateManifest { /// The relay-parent of the candidate. pub relay_parent: Hash, /// The hash of the candidate. pub candidate_hash: CandidateHash, /// The group index backing the candidate at the relay-parent. pub group_index: GroupIndex, /// The para ID of the candidate. It is illegal for this to /// be a para ID which is not assigned to the group indicated /// in this manifest. pub para_id: ParaId, /// The head-data corresponding to the candidate. pub parent_head_data_hash: Hash, /// A statement filter which indicates which validators in the /// para's group at the relay-parent have validated this candidate /// and issued statements about it, to the advertiser's knowledge. /// /// This MUST have exactly the minimum amount of bytes /// necessary to represent the number of validators in the assigned /// backing group as-of the relay-parent. pub statement_knowledge: StatementFilter, } /// An acknowledgement of a backed candidate being known. #[derive(Debug, Clone, Encode, Decode, PartialEq, Eq)] pub struct BackedCandidateAcknowledgement { /// The hash of the candidate. pub candidate_hash: CandidateHash, /// A statement filter which indicates which validators in the /// para's group at the relay-parent have validated this candidate /// and issued statements about it, to the advertiser's knowledge. /// /// This MUST have exactly the minimum amount of bytes /// necessary to represent the number of validators in the assigned /// backing group as-of the relay-parent. pub statement_knowledge: StatementFilter, } /// Network messages used by the statement distribution subsystem. #[derive(Debug, Clone, Encode, Decode, PartialEq, Eq)] pub enum StatementDistributionMessage { /// A notification of a signed statement in compact form, for a given relay parent. #[codec(index = 0)] Statement(Hash, UncheckedSignedStatement), /// A notification of a backed candidate being known by the /// sending node, for the purpose of being requested by the receiving node /// if needed. #[codec(index = 1)] BackedCandidateManifest(BackedCandidateManifest), /// A notification of a backed candidate being known by the sending node, /// for the purpose of informing a receiving node which already has the candidate. #[codec(index = 2)] BackedCandidateKnown(BackedCandidateAcknowledgement), /// All messages for V1 for compatibility with the statement distribution /// protocol, for relay-parents that don't support asynchronous backing. /// /// These are illegal to send to V1 peers, and illegal to send concerning relay-parents /// which support asynchronous backing. This backwards compatibility should be /// considered immediately deprecated and can be removed once the node software /// is not required to support logic from before asynchronous backing anymore. #[codec(index = 255)] V1Compatibility(crate::v1::StatementDistributionMessage), } /// Network messages used by the approval distribution subsystem. #[derive(Debug, Clone, Encode, Decode, PartialEq, Eq)] pub enum ApprovalDistributionMessage { /// Assignments for candidates in recent, unfinalized blocks. /// /// Actually checking the assignment may yield a different result. #[codec(index = 0)] Assignments(Vec<(IndirectAssignmentCert, CandidateIndex)>), /// Approvals for candidates in some recent, unfinalized block. #[codec(index = 1)] Approvals(Vec), } /// Dummy network message type, so we will receive connect/disconnect events. #[derive(Debug, Clone, PartialEq, Eq)] pub enum GossipSupportNetworkMessage {} /// Network messages used by the collator protocol subsystem #[derive(Debug, Clone, Encode, Decode, PartialEq, Eq)] pub enum CollatorProtocolMessage { /// Declare the intent to advertise collations under a collator ID, attaching a /// signature of the `PeerId` of the node using the given collator ID key. #[codec(index = 0)] Declare(CollatorId, ParaId, CollatorSignature), /// Advertise a collation to a validator. Can only be sent once the peer has /// declared that they are a collator with given ID. #[codec(index = 1)] AdvertiseCollation { /// Hash of the relay parent advertised collation is based on. relay_parent: Hash, /// Candidate hash. candidate_hash: CandidateHash, /// Parachain head data hash before candidate execution. parent_head_data_hash: Hash, }, /// A collation sent to a validator was seconded. #[codec(index = 4)] CollationSeconded(Hash, UncheckedSignedFullStatement), } /// All network messages on the validation peer-set. #[derive(Debug, Clone, Encode, Decode, PartialEq, Eq, derive_more::From)] pub enum ValidationProtocol { /// Bitfield distribution messages #[codec(index = 1)] #[from] BitfieldDistribution(BitfieldDistributionMessage), /// Statement distribution messages #[codec(index = 3)] #[from] StatementDistribution(StatementDistributionMessage), /// Approval distribution messages #[codec(index = 4)] #[from] ApprovalDistribution(ApprovalDistributionMessage), } /// All network messages on the collation peer-set. #[derive(Debug, Clone, Encode, Decode, PartialEq, Eq, derive_more::From)] pub enum CollationProtocol { /// Collator protocol messages #[codec(index = 0)] #[from] CollatorProtocol(CollatorProtocolMessage), } /// Get the payload that should be signed and included in a `Declare` message. /// /// The payload is the local peer id of the node, which serves to prove that it /// controls the collator key it is declaring an intention to collate under. pub fn declare_signature_payload(peer_id: &sc_network::PeerId) -> Vec { let mut payload = peer_id.to_bytes(); payload.extend_from_slice(b"COLL"); payload } } /// v3 network protocol types. /// Purpose is for changing ApprovalDistributionMessage to /// include more than one assignment and approval in a message. pub mod v3 { use parity_scale_codec::{Decode, Encode}; use polkadot_node_primitives::approval::v2::{ CandidateBitfield, IndirectAssignmentCertV2, IndirectSignedApprovalVoteV2, }; /// This parts of the protocol did not change from v2, so just alias them in v3. pub use super::v2::{ declare_signature_payload, BackedCandidateAcknowledgement, BackedCandidateManifest, BitfieldDistributionMessage, GossipSupportNetworkMessage, StatementDistributionMessage, StatementFilter, }; /// Network messages used by the approval distribution subsystem. #[derive(Debug, Clone, Encode, Decode, PartialEq, Eq)] pub enum ApprovalDistributionMessage { /// Assignments for candidates in recent, unfinalized blocks. /// We use a bitfield to reference claimed candidates, where the bit index is equal to /// candidate index. /// /// Actually checking the assignment may yield a different result. /// /// TODO at next protocol upgrade opportunity: /// - remove redundancy `candidate_index` vs `core_index` /// - `` #[codec(index = 0)] Assignments(Vec<(IndirectAssignmentCertV2, CandidateBitfield)>), /// Approvals for candidates in some recent, unfinalized block. #[codec(index = 1)] Approvals(Vec), } /// All network messages on the validation peer-set. #[derive(Debug, Clone, Encode, Decode, PartialEq, Eq, derive_more::From)] pub enum ValidationProtocol { /// Bitfield distribution messages #[codec(index = 1)] #[from] BitfieldDistribution(BitfieldDistributionMessage), /// Statement distribution messages #[codec(index = 3)] #[from] StatementDistribution(StatementDistributionMessage), /// Approval distribution messages #[codec(index = 4)] #[from] ApprovalDistribution(ApprovalDistributionMessage), } } /// Returns the subset of `peers` with the specified `version`. pub fn filter_by_peer_version( peers: &[(PeerId, peer_set::ProtocolVersion)], version: peer_set::ProtocolVersion, ) -> Vec { peers.iter().filter(|(_, v)| v == &version).map(|(p, _)| *p).collect::>() }