referrerpolicy=no-referrer-when-downgrade

polkadot_node_network_protocol/
lib.rs

1// Copyright (C) Parity Technologies (UK) Ltd.
2// This file is part of Polkadot.
3
4// Polkadot is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8
9// Polkadot is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12// GNU General Public License for more details.
13
14// You should have received a copy of the GNU General Public License
15// along with Polkadot.  If not, see <http://www.gnu.org/licenses/>.
16
17//! Network protocol types for parachains.
18
19#![deny(unused_crate_dependencies)]
20#![warn(missing_docs)]
21
22use codec::{Decode, Encode};
23use polkadot_primitives::{BlockNumber, Hash};
24use std::fmt;
25
26#[doc(hidden)]
27pub use sc_network::IfDisconnected;
28pub use sc_network_types::PeerId;
29#[doc(hidden)]
30pub use std::sync::Arc;
31
32mod reputation;
33pub use self::reputation::{ReputationChange, UnifiedReputationChange};
34
35/// Peer-sets and protocols used for parachains.
36pub mod peer_set;
37
38/// Request/response protocols used in Polkadot.
39pub mod request_response;
40
41/// Accessing authority discovery service
42pub mod authority_discovery;
43/// Grid topology support module
44pub mod grid_topology;
45
46/// The minimum amount of peers to send gossip messages to.
47pub const MIN_GOSSIP_PEERS: usize = 25;
48
49/// An error indicating that this the over-arching message type had the wrong variant
50#[derive(Debug, Clone, Copy, PartialEq)]
51pub struct WrongVariant;
52
53impl fmt::Display for WrongVariant {
54	fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
55		write!(formatter, "Wrong message variant")
56	}
57}
58
59impl std::error::Error for WrongVariant {}
60
61/// The advertised role of a node.
62#[derive(Debug, Clone, Copy, PartialEq)]
63pub enum ObservedRole {
64	/// A light node.
65	Light,
66	/// A full node.
67	Full,
68	/// A node claiming to be an authority (unauthenticated)
69	Authority,
70}
71
72impl From<sc_network::ObservedRole> for ObservedRole {
73	fn from(role: sc_network::ObservedRole) -> ObservedRole {
74		match role {
75			sc_network::ObservedRole::Light => ObservedRole::Light,
76			sc_network::ObservedRole::Authority => ObservedRole::Authority,
77			sc_network::ObservedRole::Full => ObservedRole::Full,
78		}
79	}
80}
81
82impl Into<sc_network::ObservedRole> for ObservedRole {
83	fn into(self) -> sc_network::ObservedRole {
84		match self {
85			ObservedRole::Light => sc_network::ObservedRole::Light,
86			ObservedRole::Full => sc_network::ObservedRole::Full,
87			ObservedRole::Authority => sc_network::ObservedRole::Authority,
88		}
89	}
90}
91
92/// Specialized wrapper around [`View`].
93#[derive(Debug, Clone, Default)]
94pub struct OurView {
95	view: View,
96}
97
98impl OurView {
99	/// Creates a new instance.
100	pub fn new(heads: impl IntoIterator<Item = Hash>, finalized_number: BlockNumber) -> Self {
101		let view = View::new(heads, finalized_number);
102		Self { view }
103	}
104}
105
106impl PartialEq for OurView {
107	fn eq(&self, other: &Self) -> bool {
108		self.view == other.view
109	}
110}
111
112impl std::ops::Deref for OurView {
113	type Target = View;
114
115	fn deref(&self) -> &View {
116		&self.view
117	}
118}
119
120/// Construct a new [`OurView`] with the given chain heads, finalized number 0
121///
122/// NOTE: Use for tests only.
123///
124/// # Example
125///
126/// ```
127/// # use polkadot_node_network_protocol::our_view;
128/// # use polkadot_primitives::Hash;
129/// let our_view = our_view![Hash::repeat_byte(1), Hash::repeat_byte(2)];
130/// ```
131#[macro_export]
132macro_rules! our_view {
133	( $( $hash:expr ),* $(,)? ) => {
134		$crate::OurView::new(
135			vec![ $( $hash.clone() ),* ].into_iter().map(|h| h),
136			0,
137		)
138	};
139}
140
141/// A succinct representation of a peer's view. This consists of a bounded amount of chain heads
142/// and the highest known finalized block number.
143///
144/// Up to `N` (5?) chain heads.
145#[derive(Default, Debug, Clone, PartialEq, Eq, Encode, Decode)]
146pub struct View {
147	/// A bounded amount of chain heads.
148	/// Invariant: Sorted.
149	heads: Vec<Hash>,
150	/// The highest known finalized block number.
151	pub finalized_number: BlockNumber,
152}
153
154/// Construct a new view with the given chain heads and finalized number 0.
155///
156/// NOTE: Use for tests only.
157///
158/// # Example
159///
160/// ```
161/// # use polkadot_node_network_protocol::view;
162/// # use polkadot_primitives::Hash;
163/// let view = view![Hash::repeat_byte(1), Hash::repeat_byte(2)];
164/// ```
165#[macro_export]
166macro_rules! view {
167	( $( $hash:expr ),* $(,)? ) => {
168		$crate::View::new(vec![ $( $hash.clone() ),* ], 0)
169	};
170}
171
172impl View {
173	/// Construct a new view based on heads and a finalized block number.
174	pub fn new(heads: impl IntoIterator<Item = Hash>, finalized_number: BlockNumber) -> Self {
175		let mut heads = heads.into_iter().collect::<Vec<Hash>>();
176		heads.sort();
177		Self { heads, finalized_number }
178	}
179
180	/// Start with no heads, but only a finalized block number.
181	pub fn with_finalized(finalized_number: BlockNumber) -> Self {
182		Self { heads: Vec::new(), finalized_number }
183	}
184
185	/// Obtain the number of heads that are in view.
186	pub fn len(&self) -> usize {
187		self.heads.len()
188	}
189
190	/// Check if the number of heads contained, is null.
191	pub fn is_empty(&self) -> bool {
192		self.heads.is_empty()
193	}
194
195	/// Obtain an iterator over all heads.
196	pub fn iter(&self) -> impl Iterator<Item = &Hash> {
197		self.heads.iter()
198	}
199
200	/// Obtain an iterator over all heads.
201	pub fn into_iter(self) -> impl Iterator<Item = Hash> {
202		self.heads.into_iter()
203	}
204
205	/// Replace `self` with `new`.
206	///
207	/// Returns an iterator that will yield all elements of `new` that were not part of `self`.
208	pub fn replace_difference(&mut self, new: View) -> impl Iterator<Item = &Hash> {
209		let old = std::mem::replace(self, new);
210
211		self.heads.iter().filter(move |h| !old.contains(h))
212	}
213
214	/// Returns an iterator of the hashes present in `Self` but not in `other`.
215	pub fn difference<'a>(&'a self, other: &'a View) -> impl Iterator<Item = &'a Hash> + 'a {
216		self.heads.iter().filter(move |h| !other.contains(h))
217	}
218
219	/// An iterator containing hashes present in both `Self` and in `other`.
220	pub fn intersection<'a>(&'a self, other: &'a View) -> impl Iterator<Item = &'a Hash> + 'a {
221		self.heads.iter().filter(move |h| other.contains(h))
222	}
223
224	/// Whether the view contains a given hash.
225	pub fn contains(&self, hash: &Hash) -> bool {
226		self.heads.contains(hash)
227	}
228
229	/// Check if two views have the same heads.
230	///
231	/// Equivalent to the `PartialEq` function,
232	/// but ignores the `finalized_number` field.
233	pub fn check_heads_eq(&self, other: &Self) -> bool {
234		self.heads == other.heads
235	}
236}
237
238/// A protocol-versioned type for validation.
239#[derive(Debug, Clone, PartialEq, Eq)]
240pub enum ValidationProtocols<V3> {
241	/// V3 type.
242	V3(V3),
243}
244
245/// A protocol-versioned type for collation.
246#[derive(Debug, Clone, PartialEq, Eq)]
247pub enum CollationProtocols<V1, V2, V3, V4> {
248	/// V1 type.
249	V1(V1),
250	/// V2 type.
251	V2(V2),
252	/// V3 type.
253	V3(V3),
254	/// V4 type.
255	V4(V4),
256}
257
258impl<V3: Clone> ValidationProtocols<&'_ V3> {
259	/// Convert to a fully-owned version of the message.
260	pub fn clone_inner(&self) -> ValidationProtocols<V3> {
261		match *self {
262			ValidationProtocols::V3(inner) => ValidationProtocols::V3(inner.clone()),
263		}
264	}
265}
266
267impl<V1: Clone, V2: Clone, V3: Clone, V4: Clone>
268	CollationProtocols<&'_ V1, &'_ V2, &'_ V3, &'_ V4>
269{
270	/// Convert to a fully-owned version of the message.
271	pub fn clone_inner(&self) -> CollationProtocols<V1, V2, V3, V4> {
272		match *self {
273			CollationProtocols::V1(inner) => CollationProtocols::V1(inner.clone()),
274			CollationProtocols::V2(inner) => CollationProtocols::V2(inner.clone()),
275			CollationProtocols::V3(inner) => CollationProtocols::V3(inner.clone()),
276			CollationProtocols::V4(inner) => CollationProtocols::V4(inner.clone()),
277		}
278	}
279}
280
281/// All supported versions of the validation protocol message.
282pub type VersionedValidationProtocol = ValidationProtocols<v3::ValidationProtocol>;
283
284impl From<v3::ValidationProtocol> for VersionedValidationProtocol {
285	fn from(v3: v3::ValidationProtocol) -> Self {
286		VersionedValidationProtocol::V3(v3)
287	}
288}
289
290/// All supported versions of the collation protocol message.
291pub type VersionedCollationProtocol = CollationProtocols<
292	v1::CollationProtocol,
293	v2::CollationProtocol,
294	v3_collation::CollationProtocol,
295	v4_collation::CollationProtocol,
296>;
297
298impl From<v1::CollationProtocol> for VersionedCollationProtocol {
299	fn from(v1: v1::CollationProtocol) -> Self {
300		VersionedCollationProtocol::V1(v1)
301	}
302}
303
304impl From<v2::CollationProtocol> for VersionedCollationProtocol {
305	fn from(v2: v2::CollationProtocol) -> Self {
306		VersionedCollationProtocol::V2(v2)
307	}
308}
309
310impl From<v3_collation::CollationProtocol> for VersionedCollationProtocol {
311	fn from(v3: v3_collation::CollationProtocol) -> Self {
312		VersionedCollationProtocol::V3(v3)
313	}
314}
315
316impl From<v4_collation::CollationProtocol> for VersionedCollationProtocol {
317	fn from(v4: v4_collation::CollationProtocol) -> Self {
318		VersionedCollationProtocol::V4(v4)
319	}
320}
321
322macro_rules! impl_versioned_validation_full_protocol_from {
323	($from:ty, $out:ty, $variant:ident) => {
324		impl From<$from> for $out {
325			fn from(versioned_from: $from) -> $out {
326				match versioned_from {
327					ValidationProtocols::V3(x) => ValidationProtocols::V3(x.into()),
328				}
329			}
330		}
331	};
332}
333
334macro_rules! impl_versioned_collation_full_protocol_from {
335	($from:ty, $out:ty, $variant:ident) => {
336		impl From<$from> for $out {
337			fn from(versioned_from: $from) -> $out {
338				match versioned_from {
339					CollationProtocols::V1(x) => CollationProtocols::V1(x.into()),
340					CollationProtocols::V2(x) => CollationProtocols::V2(x.into()),
341					CollationProtocols::V3(x) => CollationProtocols::V3(x.into()),
342					CollationProtocols::V4(x) => CollationProtocols::V4(x.into()),
343				}
344			}
345		}
346	};
347}
348
349/// Implement `TryFrom` for one versioned validation enum variant into the inner type.
350/// `$m_ty::$variant(inner) -> Ok(inner)`
351macro_rules! impl_versioned_validation_try_from {
352	(
353		$from:ty,
354		$out:ty,
355		$v3_pat:pat => $v3_out:expr
356	) => {
357		impl TryFrom<$from> for $out {
358			type Error = crate::WrongVariant;
359
360			fn try_from(x: $from) -> Result<$out, Self::Error> {
361				#[allow(unreachable_patterns)] // when there is only one variant
362				match x {
363					ValidationProtocols::V3($v3_pat) => Ok(ValidationProtocols::V3($v3_out)),
364					_ => Err(crate::WrongVariant),
365				}
366			}
367		}
368
369		impl<'a> TryFrom<&'a $from> for $out {
370			type Error = crate::WrongVariant;
371
372			fn try_from(x: &'a $from) -> Result<$out, Self::Error> {
373				#[allow(unreachable_patterns)] // when there is only one variant
374				match x {
375					ValidationProtocols::V3($v3_pat) => {
376						Ok(ValidationProtocols::V3($v3_out.clone()))
377					},
378					_ => Err(crate::WrongVariant),
379				}
380			}
381		}
382	};
383}
384
385/// Implement `TryFrom` for one versioned collation enum variant into the inner type.
386/// `$m_ty::$variant(inner) -> Ok(inner)`
387macro_rules! impl_versioned_collation_try_from {
388	(
389		$from:ty,
390		$out:ty,
391		$v1_pat:pat => $v1_out:expr,
392		$v2_pat:pat => $v2_out:expr,
393		$v3_pat:pat => $v3_out:expr,
394		$v4_pat:pat => $v4_out:expr
395	) => {
396		impl TryFrom<$from> for $out {
397			type Error = crate::WrongVariant;
398
399			fn try_from(x: $from) -> Result<$out, Self::Error> {
400				#[allow(unreachable_patterns)] // when there is only one variant
401				match x {
402					CollationProtocols::V1($v1_pat) => Ok(CollationProtocols::V1($v1_out)),
403					CollationProtocols::V2($v2_pat) => Ok(CollationProtocols::V2($v2_out)),
404					CollationProtocols::V3($v3_pat) => Ok(CollationProtocols::V3($v3_out)),
405					CollationProtocols::V4($v4_pat) => Ok(CollationProtocols::V4($v4_out)),
406					_ => Err(crate::WrongVariant),
407				}
408			}
409		}
410
411		impl<'a> TryFrom<&'a $from> for $out {
412			type Error = crate::WrongVariant;
413
414			fn try_from(x: &'a $from) -> Result<$out, Self::Error> {
415				#[allow(unreachable_patterns)] // when there is only one variant
416				match x {
417					CollationProtocols::V1($v1_pat) => Ok(CollationProtocols::V1($v1_out.clone())),
418					CollationProtocols::V2($v2_pat) => Ok(CollationProtocols::V2($v2_out.clone())),
419					CollationProtocols::V3($v3_pat) => Ok(CollationProtocols::V3($v3_out.clone())),
420					CollationProtocols::V4($v4_pat) => Ok(CollationProtocols::V4($v4_out.clone())),
421					_ => Err(crate::WrongVariant),
422				}
423			}
424		}
425	};
426}
427
428/// Version-annotated messages used by the bitfield distribution subsystem.
429pub type BitfieldDistributionMessage = ValidationProtocols<v3::BitfieldDistributionMessage>;
430impl_versioned_validation_full_protocol_from!(
431	BitfieldDistributionMessage,
432	VersionedValidationProtocol,
433	BitfieldDistribution
434);
435impl_versioned_validation_try_from!(
436	VersionedValidationProtocol,
437	BitfieldDistributionMessage,
438	v3::ValidationProtocol::BitfieldDistribution(x) => x
439);
440
441/// Version-annotated messages used by the statement distribution subsystem.
442pub type StatementDistributionMessage = ValidationProtocols<v3::StatementDistributionMessage>;
443impl_versioned_validation_full_protocol_from!(
444	StatementDistributionMessage,
445	VersionedValidationProtocol,
446	StatementDistribution
447);
448impl_versioned_validation_try_from!(
449	VersionedValidationProtocol,
450	StatementDistributionMessage,
451	v3::ValidationProtocol::StatementDistribution(x) => x
452);
453
454/// Version-annotated messages used by the approval distribution subsystem.
455pub type ApprovalDistributionMessage = ValidationProtocols<v3::ApprovalDistributionMessage>;
456impl_versioned_validation_full_protocol_from!(
457	ApprovalDistributionMessage,
458	VersionedValidationProtocol,
459	ApprovalDistribution
460);
461impl_versioned_validation_try_from!(
462	VersionedValidationProtocol,
463	ApprovalDistributionMessage,
464	v3::ValidationProtocol::ApprovalDistribution(x) => x
465
466);
467
468/// Version-annotated messages used by the gossip-support subsystem (this is void).
469pub type GossipSupportNetworkMessage = ValidationProtocols<v3::GossipSupportNetworkMessage>;
470
471// This is a void enum placeholder, so never gets sent over the wire.
472impl TryFrom<VersionedValidationProtocol> for GossipSupportNetworkMessage {
473	type Error = WrongVariant;
474	fn try_from(_: VersionedValidationProtocol) -> Result<Self, Self::Error> {
475		Err(WrongVariant)
476	}
477}
478
479impl<'a> TryFrom<&'a VersionedValidationProtocol> for GossipSupportNetworkMessage {
480	type Error = WrongVariant;
481	fn try_from(_: &'a VersionedValidationProtocol) -> Result<Self, Self::Error> {
482		Err(WrongVariant)
483	}
484}
485
486/// Version-annotated messages used by the collator protocol subsystem.
487pub type CollatorProtocolMessage = CollationProtocols<
488	v1::CollatorProtocolMessage,
489	v2::CollatorProtocolMessage,
490	v3_collation::CollatorProtocolMessage,
491	v4_collation::AdvertiseSegment,
492>;
493impl_versioned_collation_full_protocol_from!(
494	CollatorProtocolMessage,
495	VersionedCollationProtocol,
496	CollatorProtocol
497);
498impl_versioned_collation_try_from!(
499	VersionedCollationProtocol,
500	CollatorProtocolMessage,
501	v1::CollationProtocol::CollatorProtocol(x) => x,
502	v2::CollationProtocol::CollatorProtocol(x) => x,
503	v3_collation::CollationProtocol::CollatorProtocol(x) => x,
504	x => x
505);
506
507/// v1 notification protocol types.
508pub mod v1 {
509	use codec::{Decode, Encode};
510
511	use polkadot_primitives::{CollatorId, CollatorSignature, Hash, Id as ParaId};
512
513	use polkadot_node_primitives::UncheckedSignedFullStatement;
514
515	/// Network messages used by the collator protocol subsystem
516	#[derive(Debug, Clone, Encode, Decode, PartialEq, Eq)]
517	pub enum CollatorProtocolMessage {
518		/// Declare the intent to advertise collations under a collator ID, attaching a
519		/// signature of the `PeerId` of the node using the given collator ID key.
520		#[codec(index = 0)]
521		Declare(CollatorId, ParaId, CollatorSignature),
522		/// Advertise a collation to a validator. Can only be sent once the peer has
523		/// declared that they are a collator with given ID.
524		#[codec(index = 1)]
525		AdvertiseCollation(Hash),
526		/// A collation sent to a validator was seconded.
527		#[codec(index = 4)]
528		CollationSeconded(Hash, UncheckedSignedFullStatement),
529	}
530
531	/// All network messages on the collation peer-set.
532	#[derive(Debug, Clone, Encode, Decode, PartialEq, Eq, derive_more::From)]
533	pub enum CollationProtocol {
534		/// Collator protocol messages
535		#[codec(index = 0)]
536		#[from]
537		CollatorProtocol(CollatorProtocolMessage),
538	}
539
540	/// Get the payload that should be signed and included in a `Declare` message.
541	///
542	/// The payload is the local peer id of the node, which serves to prove that it
543	/// controls the collator key it is declaring an intention to collate under.
544	pub fn declare_signature_payload(peer_id: &sc_network_types::PeerId) -> Vec<u8> {
545		let mut payload = peer_id.to_bytes();
546		payload.extend_from_slice(b"COLL");
547		payload
548	}
549}
550
551/// v2 network protocol types.
552pub mod v2 {
553	use codec::{Decode, Encode};
554
555	use polkadot_primitives::{CandidateHash, CollatorId, CollatorSignature, Hash, Id as ParaId};
556
557	use polkadot_node_primitives::UncheckedSignedFullStatement;
558
559	/// This parts of the protocol did not change from v1, so just alias them in v2.
560	pub use super::v1::declare_signature_payload;
561
562	/// Network messages used by the collator protocol subsystem
563	#[derive(Debug, Clone, Encode, Decode, PartialEq, Eq)]
564	pub enum CollatorProtocolMessage {
565		/// Declare the intent to advertise collations under a collator ID, attaching a
566		/// signature of the `PeerId` of the node using the given collator ID key.
567		#[codec(index = 0)]
568		Declare(CollatorId, ParaId, CollatorSignature),
569		/// Advertise a collation to a validator. Can only be sent once the peer has
570		/// declared that they are a collator with given ID.
571		#[codec(index = 1)]
572		AdvertiseCollation {
573			/// Hash of the scheduling parent - used for validator assignment.
574			scheduling_parent: Hash,
575			/// Candidate hash.
576			candidate_hash: CandidateHash,
577			/// Parachain head data hash before candidate execution.
578			parent_head_data_hash: Hash,
579		},
580		/// A collation sent to a validator was seconded.
581		#[codec(index = 4)]
582		CollationSeconded(Hash, UncheckedSignedFullStatement),
583	}
584
585	/// All network messages on the collation peer-set.
586	#[derive(Debug, Clone, Encode, Decode, PartialEq, Eq, derive_more::From)]
587	pub enum CollationProtocol {
588		/// Collator protocol messages
589		#[codec(index = 0)]
590		#[from]
591		CollatorProtocol(CollatorProtocolMessage),
592	}
593}
594
595/// v3 collation protocol types.
596pub mod v3_collation {
597	use codec::{Decode, Encode};
598
599	use polkadot_primitives::{
600		CandidateDescriptorVersion, CandidateHash, CollatorId, CollatorSignature, Hash,
601		Id as ParaId,
602	};
603
604	use polkadot_node_primitives::UncheckedSignedFullStatement;
605
606	/// This part of the protocol did not change from v2, so just alias it in v3.
607	pub use super::v2::declare_signature_payload;
608
609	/// Network messages used by the collator protocol subsystem
610	#[derive(Debug, Clone, Encode, Decode, PartialEq, Eq)]
611	pub enum CollatorProtocolMessage {
612		/// Declare the intent to advertise collations under a collator ID, attaching a
613		/// signature of the `PeerId` of the node using the given collator ID key.
614		#[codec(index = 0)]
615		Declare(CollatorId, ParaId, CollatorSignature),
616		/// Advertise a collation to a validator. Can only be sent once the peer has
617		/// declared that they are a collator with given ID.
618		#[codec(index = 1)]
619		AdvertiseCollation {
620			/// Hash of the scheduling parent - used for validator assignment.
621			/// For non-v3 descriptors, this must be equal to the relay parent.
622			scheduling_parent: Hash,
623			/// Candidate hash.
624			candidate_hash: CandidateHash,
625			/// Parachain head data hash before candidate execution.
626			parent_head_data_hash: Hash,
627			/// The version of the candidate descriptor.
628			candidate_descriptor_version: CandidateDescriptorVersion,
629			/// The relay parent of the candidate.
630			relay_parent: Hash,
631		},
632		/// A collation sent to a validator was seconded.
633		#[codec(index = 4)]
634		CollationSeconded(Hash, UncheckedSignedFullStatement),
635	}
636
637	/// All network messages on the collation peer-set.
638	#[derive(Debug, Clone, Encode, Decode, PartialEq, Eq, derive_more::From)]
639	pub enum CollationProtocol {
640		/// Collator protocol messages
641		#[codec(index = 0)]
642		#[from]
643		CollatorProtocol(CollatorProtocolMessage),
644	}
645}
646
647/// v4 collation protocol types.
648pub mod v4_collation {
649	use codec::{Decode, Encode};
650	// Re-exported so external code can name the bound on `AdvertiseSegment::candidates`.
651	pub use polkadot_node_primitives::MAX_SEGMENT_LEN;
652	use polkadot_primitives::{CandidateDescriptorVersion, Hash, Id as ParaId};
653	use sp_runtime::{traits::ConstU32, BoundedVec};
654
655	/// Advertise an ordered list of unincluded candidates. The list
656	/// is ordered by age. A length 1 segment is the V3 single-candidate
657	/// equivalent.
658	///
659	/// This is the *only* message on the V4 collation peer-set, so it is a struct
660	/// rather than a single-variant enum: there is nothing to discriminate, and a
661	/// tag byte would carry no information. If V4 ever gains a second message, this
662	/// becomes an enum again and the match sites below regain their inner pattern.
663	///
664	/// V4 has no `Declare` message. Although every `AdvertiseSegment`
665	/// carries a `para_id`, the peer is bound to a single para by its
666	/// first advertisement. Sending a different `para_id` in a
667	/// subsequent message results in disconnection.
668	#[derive(Debug, Clone, Encode, Decode, PartialEq, Eq)]
669	pub struct AdvertiseSegment {
670		/// Hash of the scheduling parent
671		pub scheduling_parent: Hash,
672		/// The para this segment collates for.
673		pub para_id: ParaId,
674		/// Descriptor version for the candidate.
675		pub candidates_descriptor_version: CandidateDescriptorVersion,
676		/// Candidates ordered by age; the list may have gaps.
677		pub candidates: BoundedVec<CandidateFingerprint, ConstU32<MAX_SEGMENT_LEN>>,
678	}
679
680	/// A single entry in the segment advertised by the collator.
681	#[derive(Debug, Clone, Encode, Decode, PartialEq, Eq)]
682	pub struct CandidateFingerprint {
683		/// Unique and stable identifier of the underlying parachain
684		/// block. Because it's stable across resubmissions this will
685		/// be used for deduplication against validator's fragment chain.
686		pub output_head_data_hash: Hash,
687		/// Parachain head data hash before candidate execution.
688		pub parent_head_data_hash: Hash,
689		/// The claim queue offset.
690		pub claim_queue_offset: u8,
691	}
692
693	/// All network messages on the collation peer-set.
694	///
695	/// V4 carries exactly one message, so the peer-set type is that message itself:
696	/// neither a wrapper enum nor a message enum earns its tag byte here.
697	pub type CollationProtocol = AdvertiseSegment;
698}
699
700/// v3 network protocol types.
701/// Purpose is for changing ApprovalDistributionMessage to
702/// include more than one assignment and approval in a message.
703pub mod v3 {
704	use bitvec::{order::Lsb0, slice::BitSlice, vec::BitVec};
705	use codec::{Decode, Encode};
706
707	use polkadot_primitives::{
708		CandidateHash, GroupIndex, Hash, Id as ParaId, UncheckedSignedAvailabilityBitfield,
709		UncheckedSignedStatement,
710	};
711
712	use polkadot_node_primitives::approval::v2::{
713		CandidateBitfield, IndirectAssignmentCertV2, IndirectSignedApprovalVoteV2,
714	};
715
716	/// This parts of the protocol did not change from v2, so just alias them in v3.
717	pub use super::v2::declare_signature_payload;
718
719	/// Network messages used by the bitfield distribution subsystem.
720	#[derive(Debug, Clone, Encode, Decode, PartialEq, Eq)]
721	pub enum BitfieldDistributionMessage {
722		/// A signed availability bitfield for a given relay-parent hash.
723		#[codec(index = 0)]
724		Bitfield(Hash, UncheckedSignedAvailabilityBitfield),
725	}
726
727	/// Bitfields indicating the statements that are known or undesired
728	/// about a candidate.
729	#[derive(Debug, Clone, Encode, Decode, PartialEq, Eq)]
730	pub struct StatementFilter {
731		/// Seconded statements. '1' is known or undesired.
732		pub seconded_in_group: BitVec<u8, Lsb0>,
733		/// Valid statements. '1' is known or undesired.
734		pub validated_in_group: BitVec<u8, Lsb0>,
735	}
736
737	impl StatementFilter {
738		/// Create a new blank filter with the given group size.
739		pub fn blank(group_size: usize) -> Self {
740			StatementFilter {
741				seconded_in_group: BitVec::repeat(false, group_size),
742				validated_in_group: BitVec::repeat(false, group_size),
743			}
744		}
745
746		/// Create a new full filter with the given group size.
747		pub fn full(group_size: usize) -> Self {
748			StatementFilter {
749				seconded_in_group: BitVec::repeat(true, group_size),
750				validated_in_group: BitVec::repeat(true, group_size),
751			}
752		}
753
754		/// Whether the filter has a specific expected length, consistent across both
755		/// bitfields.
756		pub fn has_len(&self, len: usize) -> bool {
757			self.seconded_in_group.len() == len && self.validated_in_group.len() == len
758		}
759
760		/// Determine the number of backing validators in the statement filter.
761		pub fn backing_validators(&self) -> usize {
762			self.seconded_in_group
763				.iter()
764				.by_vals()
765				.zip(self.validated_in_group.iter().by_vals())
766				.filter(|&(s, v)| s || v) // no double-counting
767				.count()
768		}
769
770		/// Whether the statement filter has at least one seconded statement.
771		pub fn has_seconded(&self) -> bool {
772			self.seconded_in_group.iter().by_vals().any(|x| x)
773		}
774
775		/// Mask out `Seconded` statements in `self` according to the provided
776		/// bitvec. Bits appearing in `mask` will not appear in `self` afterwards.
777		pub fn mask_seconded(&mut self, mask: &BitSlice<u8, Lsb0>) {
778			for (mut x, mask) in self
779				.seconded_in_group
780				.iter_mut()
781				.zip(mask.iter().by_vals().chain(std::iter::repeat(false)))
782			{
783				// (x, mask) => x
784				// (true, true) => false
785				// (true, false) => true
786				// (false, true) => false
787				// (false, false) => false
788				*x = *x && !mask;
789			}
790		}
791
792		/// Mask out `Valid` statements in `self` according to the provided
793		/// bitvec. Bits appearing in `mask` will not appear in `self` afterwards.
794		pub fn mask_valid(&mut self, mask: &BitSlice<u8, Lsb0>) {
795			for (mut x, mask) in self
796				.validated_in_group
797				.iter_mut()
798				.zip(mask.iter().by_vals().chain(std::iter::repeat(false)))
799			{
800				// (x, mask) => x
801				// (true, true) => false
802				// (true, false) => true
803				// (false, true) => false
804				// (false, false) => false
805				*x = *x && !mask;
806			}
807		}
808	}
809
810	/// A manifest of a known backed candidate, along with a description
811	/// of the statements backing it.
812	#[derive(Debug, Clone, Encode, Decode, PartialEq, Eq)]
813	pub struct BackedCandidateManifest {
814		/// The scheduling-parent of the candidate.
815		pub scheduling_parent: Hash,
816		/// The hash of the candidate.
817		pub candidate_hash: CandidateHash,
818		/// The group index backing the candidate at the scheduling-parent.
819		pub group_index: GroupIndex,
820		/// The para ID of the candidate. It is illegal for this to
821		/// be a para ID which is not assigned to the group indicated
822		/// in this manifest.
823		pub para_id: ParaId,
824		/// The head-data corresponding to the candidate.
825		pub parent_head_data_hash: Hash,
826		/// A statement filter which indicates which validators in the
827		/// para's group at the scheduling-parent have validated this candidate
828		/// and issued statements about it, to the advertiser's knowledge.
829		///
830		/// This MUST have exactly the minimum amount of bytes
831		/// necessary to represent the number of validators in the assigned
832		/// backing group as-of the scheduling-parent.
833		pub statement_knowledge: StatementFilter,
834	}
835
836	/// An acknowledgement of a backed candidate being known.
837	#[derive(Debug, Clone, Encode, Decode, PartialEq, Eq)]
838	pub struct BackedCandidateAcknowledgement {
839		/// The hash of the candidate.
840		pub candidate_hash: CandidateHash,
841		/// A statement filter which indicates which validators in the
842		/// para's group at the scheduling-parent have validated this candidate
843		/// and issued statements about it, to the advertiser's knowledge.
844		///
845		/// This MUST have exactly the minimum amount of bytes
846		/// necessary to represent the number of validators in the assigned
847		/// backing group as-of the scheduling-parent.
848		pub statement_knowledge: StatementFilter,
849	}
850
851	/// Network messages used by the statement distribution subsystem.
852	#[derive(Debug, Clone, Encode, Decode, PartialEq, Eq)]
853	pub enum StatementDistributionMessage {
854		/// A notification of a signed statement in compact form, for a given relay parent.
855		#[codec(index = 0)]
856		Statement(Hash, UncheckedSignedStatement),
857
858		/// A notification of a backed candidate being known by the
859		/// sending node, for the purpose of being requested by the receiving node
860		/// if needed.
861		#[codec(index = 1)]
862		BackedCandidateManifest(BackedCandidateManifest),
863
864		/// A notification of a backed candidate being known by the sending node,
865		/// for the purpose of informing a receiving node which already has the candidate.
866		#[codec(index = 2)]
867		BackedCandidateKnown(BackedCandidateAcknowledgement),
868	}
869
870	/// Network messages used by the approval distribution subsystem.
871	#[derive(Debug, Clone, Encode, Decode, PartialEq, Eq)]
872	pub enum ApprovalDistributionMessage {
873		/// Assignments for candidates in recent, unfinalized blocks.
874		/// We use a bitfield to reference claimed candidates, where the bit index is equal to
875		/// candidate index.
876		///
877		/// Actually checking the assignment may yield a different result.
878		///
879		/// TODO at next protocol upgrade opportunity:
880		/// - remove redundancy `candidate_index` vs `core_index`
881		/// - `<https://github.com/paritytech/polkadot-sdk/issues/675>`
882		#[codec(index = 0)]
883		Assignments(Vec<(IndirectAssignmentCertV2, CandidateBitfield)>),
884		/// Approvals for candidates in some recent, unfinalized block.
885		#[codec(index = 1)]
886		Approvals(Vec<IndirectSignedApprovalVoteV2>),
887	}
888
889	/// Dummy network message type, so we will receive connect/disconnect events.
890	#[derive(Debug, Clone, PartialEq, Eq)]
891	pub enum GossipSupportNetworkMessage {}
892
893	/// All network messages on the validation peer-set.
894	#[derive(Debug, Clone, Encode, Decode, PartialEq, Eq, derive_more::From)]
895	pub enum ValidationProtocol {
896		/// Bitfield distribution messages
897		#[codec(index = 1)]
898		#[from]
899		BitfieldDistribution(BitfieldDistributionMessage),
900		/// Statement distribution messages
901		#[codec(index = 3)]
902		#[from]
903		StatementDistribution(StatementDistributionMessage),
904		/// Approval distribution messages
905		#[codec(index = 4)]
906		#[from]
907		ApprovalDistribution(ApprovalDistributionMessage),
908	}
909}
910
911/// Returns the subset of `peers` with the specified `version`.
912pub fn filter_by_peer_version(
913	peers: &[(PeerId, peer_set::ProtocolVersion)],
914	version: peer_set::ProtocolVersion,
915) -> Vec<PeerId> {
916	peers.iter().filter(|(_, v)| v == &version).map(|(p, _)| *p).collect::<Vec<_>>()
917}