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>>;