referrerpolicy=no-referrer-when-downgrade

polkadot_collator_protocol/collator_side/
collation.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//! Primitives for tracking collations-related data.
18
19use std::collections::{HashSet, VecDeque};
20
21use futures::{future::BoxFuture, stream::FuturesUnordered};
22
23use polkadot_node_network_protocol::{
24	request_response::{incoming::OutgoingResponse, v2 as protocol_v2, IncomingRequest},
25	PeerId,
26};
27use polkadot_node_primitives::PoV;
28use polkadot_primitives::{
29	CandidateHash, CandidateReceiptV2 as CandidateReceipt, Hash, HeadData, Id as ParaId,
30};
31
32/// The status of a collation as seen from the collator.
33#[derive(Clone, Debug, PartialEq)]
34pub enum CollationStatus {
35	/// The collation was created, but we did not advertise it to any validator.
36	Created,
37	/// The collation was advertised to at least one validator.
38	Advertised,
39	/// The collation was requested by at least one validator.
40	Requested,
41}
42
43impl CollationStatus {
44	/// Advance to the [`Self::Advertised`] status.
45	///
46	/// This ensures that `self` isn't already [`Self::Requested`].
47	pub fn advance_to_advertised(&mut self) {
48		if !matches!(self, Self::Requested) {
49			*self = Self::Advertised;
50		}
51	}
52
53	/// Advance to the [`Self::Requested`] status.
54	pub fn advance_to_requested(&mut self) {
55		*self = Self::Requested;
56	}
57
58	/// Return label for metrics.
59	pub fn label(&self) -> &'static str {
60		match self {
61			CollationStatus::Created => "created",
62			CollationStatus::Advertised => "advertised",
63			CollationStatus::Requested => "requested",
64		}
65	}
66}
67
68/// A collation built by the collator.
69pub struct Collation {
70	/// Candidate receipt.
71	pub receipt: CandidateReceipt,
72	/// Proof to verify the state transition of the parachain.
73	pub pov: PoV,
74	/// Parent head-data
75	pub parent_head_data: HeadData,
76	/// Collation status.
77	pub status: CollationStatus,
78}
79
80/// Stores the state for waiting collation fetches per relay parent.
81#[derive(Default)]
82pub struct WaitingCollationFetches {
83	/// A flag indicating that we have an ongoing request.
84	/// This limits the number of collations being sent at any moment
85	/// of time to 1 for each relay parent.
86	///
87	/// If set to `true`, any new request will be queued.
88	pub collation_fetch_active: bool,
89	/// The collation fetches waiting to be fulfilled.
90	pub req_queue: VecDeque<VersionedCollationRequest>,
91	/// All peers that are waiting or actively uploading.
92	///
93	/// We will not accept multiple requests from the same peer, otherwise our DoS protection of
94	/// moving on to the next peer after `MAX_UNSHARED_UPLOAD_TIME` would be pointless.
95	pub waiting_peers: HashSet<(PeerId, CandidateHash)>,
96}
97
98/// Backwards-compatible wrapper for incoming collations requests.
99pub enum VersionedCollationRequest {
100	V2(IncomingRequest<protocol_v2::CollationFetchingRequest>),
101}
102
103impl From<IncomingRequest<protocol_v2::CollationFetchingRequest>> for VersionedCollationRequest {
104	fn from(req: IncomingRequest<protocol_v2::CollationFetchingRequest>) -> Self {
105		Self::V2(req)
106	}
107}
108
109impl VersionedCollationRequest {
110	/// Returns parachain id from the request payload.
111	pub fn para_id(&self) -> ParaId {
112		match self {
113			VersionedCollationRequest::V2(req) => req.payload.para_id,
114		}
115	}
116
117	/// Returns candidate hash from the request payload.
118	pub fn candidate_hash(&self) -> CandidateHash {
119		match self {
120			VersionedCollationRequest::V2(req) => req.payload.candidate_hash,
121		}
122	}
123
124	/// Returns relay parent from the request payload.
125	pub fn relay_parent(&self) -> Hash {
126		match self {
127			VersionedCollationRequest::V2(req) => req.payload.relay_parent,
128		}
129	}
130
131	/// Returns id of the peer the request was received from.
132	pub fn peer_id(&self) -> PeerId {
133		match self {
134			VersionedCollationRequest::V2(req) => req.peer,
135		}
136	}
137
138	/// Sends the response back to requester.
139	pub fn send_outgoing_response(
140		self,
141		response: OutgoingResponse<protocol_v2::CollationFetchingResponse>,
142	) -> Result<(), ()> {
143		match self {
144			VersionedCollationRequest::V2(req) => req.send_outgoing_response(response),
145		}
146	}
147}
148
149/// Result of the finished background send-collation task.
150///
151/// Note that if the timeout was hit the request doesn't get
152/// aborted, it only indicates that we should start processing
153/// the next one from the queue.
154pub struct CollationSendResult {
155	/// Candidate's relay parent.
156	pub relay_parent: Hash,
157	/// Candidate hash.
158	pub candidate_hash: CandidateHash,
159	/// Peer id.
160	pub peer_id: PeerId,
161	/// Whether the max unshared timeout was hit.
162	pub timed_out: bool,
163}
164
165pub type ActiveCollationFetches = FuturesUnordered<BoxFuture<'static, CollationSendResult>>;