1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
// 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 <http://www.gnu.org/licenses/>.

//! Requests and responses as sent over the wire for the individual protocols.

use parity_scale_codec::{Decode, Encode};

use polkadot_node_primitives::{
	AvailableData, DisputeMessage, ErasureChunk, PoV, Proof, UncheckedDisputeMessage,
};
use polkadot_primitives::{
	CandidateHash, CandidateReceipt, CommittedCandidateReceipt, Hash, HeadData, Id as ParaId,
	ValidatorIndex,
};

use super::{IsRequest, Protocol};

/// Request an availability chunk.
#[derive(Debug, Copy, Clone, Encode, Decode)]
pub struct ChunkFetchingRequest {
	/// Hash of candidate we want a chunk for.
	pub candidate_hash: CandidateHash,
	/// The index of the chunk to fetch.
	pub index: ValidatorIndex,
}

/// Receive a requested erasure chunk.
#[derive(Debug, Clone, Encode, Decode)]
pub enum ChunkFetchingResponse {
	/// The requested chunk data.
	#[codec(index = 0)]
	Chunk(ChunkResponse),
	/// Node was not in possession of the requested chunk.
	#[codec(index = 1)]
	NoSuchChunk,
}

impl From<Option<ChunkResponse>> for ChunkFetchingResponse {
	fn from(x: Option<ChunkResponse>) -> Self {
		match x {
			Some(c) => ChunkFetchingResponse::Chunk(c),
			None => ChunkFetchingResponse::NoSuchChunk,
		}
	}
}

/// Skimmed down variant of `ErasureChunk`.
///
/// Instead of transmitting a full `ErasureChunk` we transmit `ChunkResponse` in
/// `ChunkFetchingResponse`, which omits the chunk's index. The index is already known by
/// the requester and by not transmitting it, we ensure the requester is going to use his index
/// value for validating the response, thus making sure he got what he requested.
#[derive(Debug, Clone, Encode, Decode)]
pub struct ChunkResponse {
	/// The erasure-encoded chunk of data belonging to the candidate block.
	pub chunk: Vec<u8>,
	/// Proof for this chunk's branch in the Merkle tree.
	pub proof: Proof,
}

impl From<ErasureChunk> for ChunkResponse {
	fn from(ErasureChunk { chunk, index: _, proof }: ErasureChunk) -> Self {
		ChunkResponse { chunk, proof }
	}
}

impl ChunkResponse {
	/// Re-build an `ErasureChunk` from response and request.
	pub fn recombine_into_chunk(self, req: &ChunkFetchingRequest) -> ErasureChunk {
		ErasureChunk { chunk: self.chunk, proof: self.proof, index: req.index }
	}
}

impl IsRequest for ChunkFetchingRequest {
	type Response = ChunkFetchingResponse;
	const PROTOCOL: Protocol = Protocol::ChunkFetchingV1;
}

/// Request the advertised collation at that relay-parent.
#[derive(Debug, Clone, Encode, Decode)]
pub struct CollationFetchingRequest {
	/// Relay parent we want a collation for.
	pub relay_parent: Hash,
	/// The `ParaId` of the collation.
	pub para_id: ParaId,
}

/// Responses as sent by collators.
#[derive(Debug, Clone, Encode, Decode)]
pub enum CollationFetchingResponse {
	/// Deliver requested collation.
	#[codec(index = 0)]
	Collation(CandidateReceipt, PoV),

	/// Deliver requested collation along with parent head data.
	#[codec(index = 1)]
	CollationWithParentHeadData {
		/// The receipt of the candidate.
		receipt: CandidateReceipt,
		/// Candidate's proof of validity.
		pov: PoV,
		/// The head data of the candidate's parent.
		/// This is needed for elastic scaling to work.
		parent_head_data: HeadData,
	},
}

impl IsRequest for CollationFetchingRequest {
	type Response = CollationFetchingResponse;
	const PROTOCOL: Protocol = Protocol::CollationFetchingV1;
}

/// Request the advertised collation at that relay-parent.
#[derive(Debug, Clone, Encode, Decode)]
pub struct PoVFetchingRequest {
	/// Candidate we want a PoV for.
	pub candidate_hash: CandidateHash,
}

/// Responses to `PoVFetchingRequest`.
#[derive(Debug, Clone, Encode, Decode)]
pub enum PoVFetchingResponse {
	/// Deliver requested PoV.
	#[codec(index = 0)]
	PoV(PoV),
	/// PoV was not found in store.
	#[codec(index = 1)]
	NoSuchPoV,
}

impl IsRequest for PoVFetchingRequest {
	type Response = PoVFetchingResponse;
	const PROTOCOL: Protocol = Protocol::PoVFetchingV1;
}

/// Request the entire available data for a candidate.
#[derive(Debug, Clone, Encode, Decode)]
pub struct AvailableDataFetchingRequest {
	/// The candidate hash to get the available data for.
	pub candidate_hash: CandidateHash,
}

/// Receive a requested available data.
#[derive(Debug, Clone, Encode, Decode)]
pub enum AvailableDataFetchingResponse {
	/// The requested data.
	#[codec(index = 0)]
	AvailableData(AvailableData),
	/// Node was not in possession of the requested data.
	#[codec(index = 1)]
	NoSuchData,
}

impl From<Option<AvailableData>> for AvailableDataFetchingResponse {
	fn from(x: Option<AvailableData>) -> Self {
		match x {
			Some(data) => AvailableDataFetchingResponse::AvailableData(data),
			None => AvailableDataFetchingResponse::NoSuchData,
		}
	}
}

impl IsRequest for AvailableDataFetchingRequest {
	type Response = AvailableDataFetchingResponse;
	const PROTOCOL: Protocol = Protocol::AvailableDataFetchingV1;
}

/// Request for fetching a large statement via request/response.
#[derive(Debug, Clone, Encode, Decode)]
pub struct StatementFetchingRequest {
	/// Data needed to locate and identify the needed statement.
	pub relay_parent: Hash,
	/// Hash of candidate that was used create the `CommittedCandidateReceipt`.
	pub candidate_hash: CandidateHash,
}

/// Respond with found full statement.
///
/// In this protocol the requester will only request data it was previously notified about,
/// therefore not having the data is not really an option and would just result in a
/// `RequestFailure`.
#[derive(Debug, Clone, Encode, Decode)]
pub enum StatementFetchingResponse {
	/// Data missing to reconstruct the full signed statement.
	#[codec(index = 0)]
	Statement(CommittedCandidateReceipt),
}

impl IsRequest for StatementFetchingRequest {
	type Response = StatementFetchingResponse;
	const PROTOCOL: Protocol = Protocol::StatementFetchingV1;
}

/// A dispute request.
///
/// Contains an invalid vote a valid one for a particular candidate in a given session.
#[derive(Clone, Encode, Decode, Debug)]
pub struct DisputeRequest(pub UncheckedDisputeMessage);

impl From<DisputeMessage> for DisputeRequest {
	fn from(msg: DisputeMessage) -> Self {
		Self(msg.into())
	}
}

/// Possible responses to a `DisputeRequest`.
#[derive(Encode, Decode, Debug, PartialEq, Eq)]
pub enum DisputeResponse {
	/// Recipient successfully processed the dispute request.
	#[codec(index = 0)]
	Confirmed,
}

impl IsRequest for DisputeRequest {
	type Response = DisputeResponse;
	const PROTOCOL: Protocol = Protocol::DisputeSendingV1;
}