pezkuwi_node_network_protocol/
lib.rs

1// Copyright (C) Parity Technologies (UK) Ltd. and Dijital Kurdistan Tech Institute
2// This file is part of Pezkuwi.
3
4// Pezkuwi 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// Pezkuwi 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 Pezkuwi.  If not, see <http://www.gnu.org/licenses/>.
16
17//! Network protocol types for teyrchains.
18
19#![deny(unused_crate_dependencies)]
20#![warn(missing_docs)]
21
22use codec::{Decode, Encode};
23use pezkuwi_primitives::{BlockNumber, Hash};
24use std::fmt;
25
26#[doc(hidden)]
27pub use pezsc_network::IfDisconnected;
28pub use pezsc_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 teyrchains.
36pub mod peer_set;
37
38/// Request/response protocols used in Pezkuwi.
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<pezsc_network::ObservedRole> for ObservedRole {
73	fn from(role: pezsc_network::ObservedRole) -> ObservedRole {
74		match role {
75			pezsc_network::ObservedRole::Light => ObservedRole::Light,
76			pezsc_network::ObservedRole::Authority => ObservedRole::Authority,
77			pezsc_network::ObservedRole::Full => ObservedRole::Full,
78		}
79	}
80}
81
82impl Into<pezsc_network::ObservedRole> for ObservedRole {
83	fn into(self) -> pezsc_network::ObservedRole {
84		match self {
85			ObservedRole::Light => pezsc_network::ObservedRole::Light,
86			ObservedRole::Full => pezsc_network::ObservedRole::Full,
87			ObservedRole::Authority => pezsc_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 pezkuwi_node_network_protocol::our_view;
128/// # use pezkuwi_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 pezkuwi_node_network_protocol::view;
162/// # use pezkuwi_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> {
248	/// V1 type.
249	V1(V1),
250	/// V2 type.
251	V2(V2),
252}
253
254impl<V3: Clone> ValidationProtocols<&'_ V3> {
255	/// Convert to a fully-owned version of the message.
256	pub fn clone_inner(&self) -> ValidationProtocols<V3> {
257		match *self {
258			ValidationProtocols::V3(inner) => ValidationProtocols::V3(inner.clone()),
259		}
260	}
261}
262
263impl<V1: Clone, V2: Clone> CollationProtocols<&'_ V1, &'_ V2> {
264	/// Convert to a fully-owned version of the message.
265	pub fn clone_inner(&self) -> CollationProtocols<V1, V2> {
266		match *self {
267			CollationProtocols::V1(inner) => CollationProtocols::V1(inner.clone()),
268			CollationProtocols::V2(inner) => CollationProtocols::V2(inner.clone()),
269		}
270	}
271}
272
273/// All supported versions of the validation protocol message.
274pub type VersionedValidationProtocol = ValidationProtocols<v3::ValidationProtocol>;
275
276impl From<v3::ValidationProtocol> for VersionedValidationProtocol {
277	fn from(v3: v3::ValidationProtocol) -> Self {
278		VersionedValidationProtocol::V3(v3)
279	}
280}
281
282/// All supported versions of the collation protocol message.
283pub type VersionedCollationProtocol =
284	CollationProtocols<v1::CollationProtocol, v2::CollationProtocol>;
285
286impl From<v1::CollationProtocol> for VersionedCollationProtocol {
287	fn from(v1: v1::CollationProtocol) -> Self {
288		VersionedCollationProtocol::V1(v1)
289	}
290}
291
292impl From<v2::CollationProtocol> for VersionedCollationProtocol {
293	fn from(v2: v2::CollationProtocol) -> Self {
294		VersionedCollationProtocol::V2(v2)
295	}
296}
297
298macro_rules! impl_versioned_validation_full_protocol_from {
299	($from:ty, $out:ty, $variant:ident) => {
300		impl From<$from> for $out {
301			fn from(versioned_from: $from) -> $out {
302				match versioned_from {
303					ValidationProtocols::V3(x) => ValidationProtocols::V3(x.into()),
304				}
305			}
306		}
307	};
308}
309
310macro_rules! impl_versioned_collation_full_protocol_from {
311	($from:ty, $out:ty, $variant:ident) => {
312		impl From<$from> for $out {
313			fn from(versioned_from: $from) -> $out {
314				match versioned_from {
315					CollationProtocols::V1(x) => CollationProtocols::V1(x.into()),
316					CollationProtocols::V2(x) => CollationProtocols::V2(x.into()),
317				}
318			}
319		}
320	};
321}
322
323/// Implement `TryFrom` for one versioned validation enum variant into the inner type.
324/// `$m_ty::$variant(inner) -> Ok(inner)`
325macro_rules! impl_versioned_validation_try_from {
326	(
327		$from:ty,
328		$out:ty,
329		$v3_pat:pat => $v3_out:expr
330	) => {
331		impl TryFrom<$from> for $out {
332			type Error = crate::WrongVariant;
333
334			fn try_from(x: $from) -> Result<$out, Self::Error> {
335				#[allow(unreachable_patterns)] // when there is only one variant
336				match x {
337					ValidationProtocols::V3($v3_pat) => Ok(ValidationProtocols::V3($v3_out)),
338					_ => Err(crate::WrongVariant),
339				}
340			}
341		}
342
343		impl<'a> TryFrom<&'a $from> for $out {
344			type Error = crate::WrongVariant;
345
346			fn try_from(x: &'a $from) -> Result<$out, Self::Error> {
347				#[allow(unreachable_patterns)] // when there is only one variant
348				match x {
349					ValidationProtocols::V3($v3_pat) => {
350						Ok(ValidationProtocols::V3($v3_out.clone()))
351					},
352					_ => Err(crate::WrongVariant),
353				}
354			}
355		}
356	};
357}
358
359/// Implement `TryFrom` for one versioned collation enum variant into the inner type.
360/// `$m_ty::$variant(inner) -> Ok(inner)`
361macro_rules! impl_versioned_collation_try_from {
362	(
363		$from:ty,
364		$out:ty,
365		$v1_pat:pat => $v1_out:expr,
366		$v2_pat:pat => $v2_out:expr
367	) => {
368		impl TryFrom<$from> for $out {
369			type Error = crate::WrongVariant;
370
371			fn try_from(x: $from) -> Result<$out, Self::Error> {
372				#[allow(unreachable_patterns)] // when there is only one variant
373				match x {
374					CollationProtocols::V1($v1_pat) => Ok(CollationProtocols::V1($v1_out)),
375					CollationProtocols::V2($v2_pat) => Ok(CollationProtocols::V2($v2_out)),
376					_ => Err(crate::WrongVariant),
377				}
378			}
379		}
380
381		impl<'a> TryFrom<&'a $from> for $out {
382			type Error = crate::WrongVariant;
383
384			fn try_from(x: &'a $from) -> Result<$out, Self::Error> {
385				#[allow(unreachable_patterns)] // when there is only one variant
386				match x {
387					CollationProtocols::V1($v1_pat) => Ok(CollationProtocols::V1($v1_out.clone())),
388					CollationProtocols::V2($v2_pat) => Ok(CollationProtocols::V2($v2_out.clone())),
389					_ => Err(crate::WrongVariant),
390				}
391			}
392		}
393	};
394}
395
396/// Version-annotated messages used by the bitfield distribution subsystem.
397pub type BitfieldDistributionMessage = ValidationProtocols<v3::BitfieldDistributionMessage>;
398impl_versioned_validation_full_protocol_from!(
399	BitfieldDistributionMessage,
400	VersionedValidationProtocol,
401	BitfieldDistribution
402);
403impl_versioned_validation_try_from!(
404	VersionedValidationProtocol,
405	BitfieldDistributionMessage,
406	v3::ValidationProtocol::BitfieldDistribution(x) => x
407);
408
409/// Version-annotated messages used by the statement distribution subsystem.
410pub type StatementDistributionMessage = ValidationProtocols<v3::StatementDistributionMessage>;
411impl_versioned_validation_full_protocol_from!(
412	StatementDistributionMessage,
413	VersionedValidationProtocol,
414	StatementDistribution
415);
416impl_versioned_validation_try_from!(
417	VersionedValidationProtocol,
418	StatementDistributionMessage,
419	v3::ValidationProtocol::StatementDistribution(x) => x
420);
421
422/// Version-annotated messages used by the approval distribution subsystem.
423pub type ApprovalDistributionMessage = ValidationProtocols<v3::ApprovalDistributionMessage>;
424impl_versioned_validation_full_protocol_from!(
425	ApprovalDistributionMessage,
426	VersionedValidationProtocol,
427	ApprovalDistribution
428);
429impl_versioned_validation_try_from!(
430	VersionedValidationProtocol,
431	ApprovalDistributionMessage,
432	v3::ValidationProtocol::ApprovalDistribution(x) => x
433
434);
435
436/// Version-annotated messages used by the gossip-support subsystem (this is void).
437pub type GossipSupportNetworkMessage = ValidationProtocols<v3::GossipSupportNetworkMessage>;
438
439// This is a void enum placeholder, so never gets sent over the wire.
440impl TryFrom<VersionedValidationProtocol> for GossipSupportNetworkMessage {
441	type Error = WrongVariant;
442	fn try_from(_: VersionedValidationProtocol) -> Result<Self, Self::Error> {
443		Err(WrongVariant)
444	}
445}
446
447impl<'a> TryFrom<&'a VersionedValidationProtocol> for GossipSupportNetworkMessage {
448	type Error = WrongVariant;
449	fn try_from(_: &'a VersionedValidationProtocol) -> Result<Self, Self::Error> {
450		Err(WrongVariant)
451	}
452}
453
454/// Version-annotated messages used by the collator protocol subsystem.
455pub type CollatorProtocolMessage =
456	CollationProtocols<v1::CollatorProtocolMessage, v2::CollatorProtocolMessage>;
457impl_versioned_collation_full_protocol_from!(
458	CollatorProtocolMessage,
459	VersionedCollationProtocol,
460	CollatorProtocol
461);
462impl_versioned_collation_try_from!(
463	VersionedCollationProtocol,
464	CollatorProtocolMessage,
465	v1::CollationProtocol::CollatorProtocol(x) => x,
466	v2::CollationProtocol::CollatorProtocol(x) => x
467);
468
469/// v1 notification protocol types.
470pub mod v1 {
471	use codec::{Decode, Encode};
472
473	use pezkuwi_primitives::{CollatorId, CollatorSignature, Hash, Id as ParaId};
474
475	use pezkuwi_pez_node_primitives::UncheckedSignedFullStatement;
476
477	/// Network messages used by the collator protocol subsystem
478	#[derive(Debug, Clone, Encode, Decode, PartialEq, Eq)]
479	pub enum CollatorProtocolMessage {
480		/// Declare the intent to advertise collations under a collator ID, attaching a
481		/// signature of the `PeerId` of the node using the given collator ID key.
482		#[codec(index = 0)]
483		Declare(CollatorId, ParaId, CollatorSignature),
484		/// Advertise a collation to a validator. Can only be sent once the peer has
485		/// declared that they are a collator with given ID.
486		#[codec(index = 1)]
487		AdvertiseCollation(Hash),
488		/// A collation sent to a validator was seconded.
489		#[codec(index = 4)]
490		CollationSeconded(Hash, UncheckedSignedFullStatement),
491	}
492
493	/// All network messages on the collation peer-set.
494	#[derive(Debug, Clone, Encode, Decode, PartialEq, Eq, derive_more::From)]
495	pub enum CollationProtocol {
496		/// Collator protocol messages
497		#[codec(index = 0)]
498		#[from]
499		CollatorProtocol(CollatorProtocolMessage),
500	}
501
502	/// Get the payload that should be signed and included in a `Declare` message.
503	///
504	/// The payload is the local peer id of the node, which serves to prove that it
505	/// controls the collator key it is declaring an intention to collate under.
506	pub fn declare_signature_payload(peer_id: &pezsc_network_types::PeerId) -> Vec<u8> {
507		let mut payload = peer_id.to_bytes();
508		payload.extend_from_slice(b"COLL");
509		payload
510	}
511}
512
513/// v2 network protocol types.
514pub mod v2 {
515	use codec::{Decode, Encode};
516
517	use pezkuwi_primitives::{CandidateHash, CollatorId, CollatorSignature, Hash, Id as ParaId};
518
519	use pezkuwi_pez_node_primitives::UncheckedSignedFullStatement;
520
521	/// This parts of the protocol did not change from v1, so just alias them in v2.
522	pub use super::v1::declare_signature_payload;
523
524	/// Network messages used by the collator protocol subsystem
525	#[derive(Debug, Clone, Encode, Decode, PartialEq, Eq)]
526	pub enum CollatorProtocolMessage {
527		/// Declare the intent to advertise collations under a collator ID, attaching a
528		/// signature of the `PeerId` of the node using the given collator ID key.
529		#[codec(index = 0)]
530		Declare(CollatorId, ParaId, CollatorSignature),
531		/// Advertise a collation to a validator. Can only be sent once the peer has
532		/// declared that they are a collator with given ID.
533		#[codec(index = 1)]
534		AdvertiseCollation {
535			/// Hash of the relay parent advertised collation is based on.
536			relay_parent: Hash,
537			/// Candidate hash.
538			candidate_hash: CandidateHash,
539			/// Teyrchain head data hash before candidate execution.
540			parent_head_data_hash: Hash,
541		},
542		/// A collation sent to a validator was seconded.
543		#[codec(index = 4)]
544		CollationSeconded(Hash, UncheckedSignedFullStatement),
545	}
546
547	/// All network messages on the collation peer-set.
548	#[derive(Debug, Clone, Encode, Decode, PartialEq, Eq, derive_more::From)]
549	pub enum CollationProtocol {
550		/// Collator protocol messages
551		#[codec(index = 0)]
552		#[from]
553		CollatorProtocol(CollatorProtocolMessage),
554	}
555}
556
557/// v3 network protocol types.
558/// Purpose is for changing ApprovalDistributionMessage to
559/// include more than one assignment and approval in a message.
560pub mod v3 {
561	use bitvec::{order::Lsb0, slice::BitSlice, vec::BitVec};
562	use codec::{Decode, Encode};
563
564	use pezkuwi_primitives::{
565		CandidateHash, GroupIndex, Hash, Id as ParaId, UncheckedSignedAvailabilityBitfield,
566		UncheckedSignedStatement,
567	};
568
569	use pezkuwi_pez_node_primitives::approval::v2::{
570		CandidateBitfield, IndirectAssignmentCertV2, IndirectSignedApprovalVoteV2,
571	};
572
573	/// This parts of the protocol did not change from v2, so just alias them in v3.
574	pub use super::v2::declare_signature_payload;
575
576	/// Network messages used by the bitfield distribution subsystem.
577	#[derive(Debug, Clone, Encode, Decode, PartialEq, Eq)]
578	pub enum BitfieldDistributionMessage {
579		/// A signed availability bitfield for a given relay-parent hash.
580		#[codec(index = 0)]
581		Bitfield(Hash, UncheckedSignedAvailabilityBitfield),
582	}
583
584	/// Bitfields indicating the statements that are known or undesired
585	/// about a candidate.
586	#[derive(Debug, Clone, Encode, Decode, PartialEq, Eq)]
587	pub struct StatementFilter {
588		/// Seconded statements. '1' is known or undesired.
589		pub seconded_in_group: BitVec<u8, Lsb0>,
590		/// Valid statements. '1' is known or undesired.
591		pub validated_in_group: BitVec<u8, Lsb0>,
592	}
593
594	impl StatementFilter {
595		/// Create a new blank filter with the given group size.
596		pub fn blank(group_size: usize) -> Self {
597			StatementFilter {
598				seconded_in_group: BitVec::repeat(false, group_size),
599				validated_in_group: BitVec::repeat(false, group_size),
600			}
601		}
602
603		/// Create a new full filter with the given group size.
604		pub fn full(group_size: usize) -> Self {
605			StatementFilter {
606				seconded_in_group: BitVec::repeat(true, group_size),
607				validated_in_group: BitVec::repeat(true, group_size),
608			}
609		}
610
611		/// Whether the filter has a specific expected length, consistent across both
612		/// bitfields.
613		pub fn has_len(&self, len: usize) -> bool {
614			self.seconded_in_group.len() == len && self.validated_in_group.len() == len
615		}
616
617		/// Determine the number of backing validators in the statement filter.
618		pub fn backing_validators(&self) -> usize {
619			self.seconded_in_group
620				.iter()
621				.by_vals()
622				.zip(self.validated_in_group.iter().by_vals())
623				.filter(|&(s, v)| s || v) // no double-counting
624				.count()
625		}
626
627		/// Whether the statement filter has at least one seconded statement.
628		pub fn has_seconded(&self) -> bool {
629			self.seconded_in_group.iter().by_vals().any(|x| x)
630		}
631
632		/// Mask out `Seconded` statements in `self` according to the provided
633		/// bitvec. Bits appearing in `mask` will not appear in `self` afterwards.
634		pub fn mask_seconded(&mut self, mask: &BitSlice<u8, Lsb0>) {
635			for (mut x, mask) in self
636				.seconded_in_group
637				.iter_mut()
638				.zip(mask.iter().by_vals().chain(std::iter::repeat(false)))
639			{
640				// (x, mask) => x
641				// (true, true) => false
642				// (true, false) => true
643				// (false, true) => false
644				// (false, false) => false
645				*x = *x && !mask;
646			}
647		}
648
649		/// Mask out `Valid` statements in `self` according to the provided
650		/// bitvec. Bits appearing in `mask` will not appear in `self` afterwards.
651		pub fn mask_valid(&mut self, mask: &BitSlice<u8, Lsb0>) {
652			for (mut x, mask) in self
653				.validated_in_group
654				.iter_mut()
655				.zip(mask.iter().by_vals().chain(std::iter::repeat(false)))
656			{
657				// (x, mask) => x
658				// (true, true) => false
659				// (true, false) => true
660				// (false, true) => false
661				// (false, false) => false
662				*x = *x && !mask;
663			}
664		}
665	}
666
667	/// A manifest of a known backed candidate, along with a description
668	/// of the statements backing it.
669	#[derive(Debug, Clone, Encode, Decode, PartialEq, Eq)]
670	pub struct BackedCandidateManifest {
671		/// The relay-parent of the candidate.
672		pub relay_parent: Hash,
673		/// The hash of the candidate.
674		pub candidate_hash: CandidateHash,
675		/// The group index backing the candidate at the relay-parent.
676		pub group_index: GroupIndex,
677		/// The para ID of the candidate. It is illegal for this to
678		/// be a para ID which is not assigned to the group indicated
679		/// in this manifest.
680		pub para_id: ParaId,
681		/// The head-data corresponding to the candidate.
682		pub parent_head_data_hash: Hash,
683		/// A statement filter which indicates which validators in the
684		/// para's group at the relay-parent have validated this candidate
685		/// and issued statements about it, to the advertiser's knowledge.
686		///
687		/// This MUST have exactly the minimum amount of bytes
688		/// necessary to represent the number of validators in the assigned
689		/// backing group as-of the relay-parent.
690		pub statement_knowledge: StatementFilter,
691	}
692
693	/// An acknowledgement of a backed candidate being known.
694	#[derive(Debug, Clone, Encode, Decode, PartialEq, Eq)]
695	pub struct BackedCandidateAcknowledgement {
696		/// The hash of the candidate.
697		pub candidate_hash: CandidateHash,
698		/// A statement filter which indicates which validators in the
699		/// para's group at the relay-parent have validated this candidate
700		/// and issued statements about it, to the advertiser's knowledge.
701		///
702		/// This MUST have exactly the minimum amount of bytes
703		/// necessary to represent the number of validators in the assigned
704		/// backing group as-of the relay-parent.
705		pub statement_knowledge: StatementFilter,
706	}
707
708	/// Network messages used by the statement distribution subsystem.
709	#[derive(Debug, Clone, Encode, Decode, PartialEq, Eq)]
710	pub enum StatementDistributionMessage {
711		/// A notification of a signed statement in compact form, for a given relay parent.
712		#[codec(index = 0)]
713		Statement(Hash, UncheckedSignedStatement),
714
715		/// A notification of a backed candidate being known by the
716		/// sending node, for the purpose of being requested by the receiving node
717		/// if needed.
718		#[codec(index = 1)]
719		BackedCandidateManifest(BackedCandidateManifest),
720
721		/// A notification of a backed candidate being known by the sending node,
722		/// for the purpose of informing a receiving node which already has the candidate.
723		#[codec(index = 2)]
724		BackedCandidateKnown(BackedCandidateAcknowledgement),
725	}
726
727	/// Network messages used by the approval distribution subsystem.
728	#[derive(Debug, Clone, Encode, Decode, PartialEq, Eq)]
729	pub enum ApprovalDistributionMessage {
730		/// Assignments for candidates in recent, unfinalized blocks.
731		/// We use a bitfield to reference claimed candidates, where the bit index is equal to
732		/// candidate index.
733		///
734		/// Actually checking the assignment may yield a different result.
735		///
736		/// TODO at next protocol upgrade opportunity:
737		/// - remove redundancy `candidate_index` vs `core_index`
738		/// - `<https://github.com/pezkuwichain/pezkuwi-sdk/issues/252>`
739		#[codec(index = 0)]
740		Assignments(Vec<(IndirectAssignmentCertV2, CandidateBitfield)>),
741		/// Approvals for candidates in some recent, unfinalized block.
742		#[codec(index = 1)]
743		Approvals(Vec<IndirectSignedApprovalVoteV2>),
744	}
745
746	/// Dummy network message type, so we will receive connect/disconnect events.
747	#[derive(Debug, Clone, PartialEq, Eq)]
748	pub enum GossipSupportNetworkMessage {}
749
750	/// All network messages on the validation peer-set.
751	#[derive(Debug, Clone, Encode, Decode, PartialEq, Eq, derive_more::From)]
752	pub enum ValidationProtocol {
753		/// Bitfield distribution messages
754		#[codec(index = 1)]
755		#[from]
756		BitfieldDistribution(BitfieldDistributionMessage),
757		/// Statement distribution messages
758		#[codec(index = 3)]
759		#[from]
760		StatementDistribution(StatementDistributionMessage),
761		/// Approval distribution messages
762		#[codec(index = 4)]
763		#[from]
764		ApprovalDistribution(ApprovalDistributionMessage),
765	}
766}
767
768/// Returns the subset of `peers` with the specified `version`.
769pub fn filter_by_peer_version(
770	peers: &[(PeerId, peer_set::ProtocolVersion)],
771	version: peer_set::ProtocolVersion,
772) -> Vec<PeerId> {
773	peers.iter().filter(|(_, v)| v == &version).map(|(p, _)| *p).collect::<Vec<_>>()
774}