mod.rs 9.65 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Copyright 2018 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/>.

17
//! Tests for polkadot and validation network.
18

19
use super::{PolkadotProtocol, Status, Message, FullStatus};
20
use validation::{ValidationSession, Knowledge};
21
22

use parking_lot::Mutex;
23
use polkadot_validation::GenericStatement;
24
use polkadot_primitives::{Block, SessionKey};
25
use polkadot_primitives::parachain::{CandidateReceipt, HeadData, BlockData};
26
use substrate_primitives::H512;
Arkadiy Paronyan's avatar
Arkadiy Paronyan committed
27
use codec::Encode;
28
29
30
31
32
use substrate_network::{
	Severity, NodeIndex, PeerInfo, ClientHandle, Context, config::Roles,
	message::Message as SubstrateMessage, specialization::NetworkSpecialization,
	generic_message::Message as GenericMessage
};
33
34
35
36

use std::sync::Arc;
use futures::Future;

37
mod validation;
38

39
40
#[derive(Default)]
struct TestContext {
Gav Wood's avatar
Gav Wood committed
41
42
43
	disabled: Vec<NodeIndex>,
	disconnected: Vec<NodeIndex>,
	messages: Vec<(NodeIndex, SubstrateMessage<Block>)>,
44
45
46
47
48
49
50
}

impl Context<Block> for TestContext {
	fn client(&self) -> &ClientHandle<Block> {
		unimplemented!()
	}

Gav Wood's avatar
Gav Wood committed
51
	fn report_peer(&mut self, peer: NodeIndex, reason: Severity) {
52
53
54
55
		match reason {
			Severity::Bad(_) => self.disabled.push(peer),
			_ => self.disconnected.push(peer),
		}
56
57
	}

Gav Wood's avatar
Gav Wood committed
58
	fn peer_info(&self, _peer: NodeIndex) -> Option<PeerInfo<Block>> {
59
60
61
		unimplemented!()
	}

Gav Wood's avatar
Gav Wood committed
62
63
	fn send_message(&mut self, who: NodeIndex, data: SubstrateMessage<Block>) {
		self.messages.push((who, data))
64
65
66
67
	}
}

impl TestContext {
Gav Wood's avatar
Gav Wood committed
68
	fn has_message(&self, to: NodeIndex, message: Message) -> bool {
69
70
		use substrate_network::generic_message::Message as GenericMessage;

71
		let encoded = message.encode();
72
73
74
75
76
77
78
		self.messages.iter().any(|&(ref peer, ref msg)| match msg {
			GenericMessage::ChainSpecific(ref data) => peer == &to && data == &encoded,
			_ => false,
		})
	}
}

79
fn make_status(status: &Status, roles: Roles) -> FullStatus {
80
81
82
83
84
85
86
87
88
89
	FullStatus {
		version: 1,
		roles,
		best_number: 0,
		best_hash: Default::default(),
		genesis_hash: Default::default(),
		chain_status: status.encode(),
	}
}

90
fn make_validation_session(local_key: SessionKey) -> (ValidationSession, Arc<Mutex<Knowledge>>) {
91
	let knowledge = Arc::new(Mutex::new(Knowledge::new()));
92
	let c = ValidationSession::new(knowledge.clone(), local_key);
93
94
95
96

	(c, knowledge)
}

Gav Wood's avatar
Gav Wood committed
97
fn on_message(protocol: &mut PolkadotProtocol, ctx: &mut TestContext, from: NodeIndex, message: Message) {
98
	let encoded = message.encode();
99
	protocol.on_message(ctx, from, &mut Some(GenericMessage::ChainSpecific(encoded)));
100
101
102
103
}

#[test]
fn sends_session_key() {
104
	let mut protocol = PolkadotProtocol::new(None);
105
106
107
108
109
110

	let peer_a = 1;
	let peer_b = 2;
	let parent_hash = [0; 32].into();
	let local_key = [1; 32].into();

111
112
	let validator_status = Status { collating_for: None };
	let collator_status = Status { collating_for: Some(([2; 32].into(), 5.into())) };
113
114
115

	{
		let mut ctx = TestContext::default();
116
		protocol.on_connect(&mut ctx, peer_a, make_status(&validator_status, Roles::AUTHORITY));
117
118
119
120
121
		assert!(ctx.messages.is_empty());
	}

	{
		let mut ctx = TestContext::default();
122
123
		let (session, _knowledge) = make_validation_session(local_key);
		protocol.new_validation_session(&mut ctx, parent_hash, session);
124
		assert!(ctx.has_message(peer_a, Message::SessionKey(local_key)));
125
126
127
128
	}

	{
		let mut ctx = TestContext::default();
129
		protocol.on_connect(&mut ctx, peer_b, make_status(&collator_status, Roles::NONE));
130
		assert!(ctx.has_message(peer_b, Message::SessionKey(local_key)));
131
132
133
134
135
	}
}

#[test]
fn fetches_from_those_with_knowledge() {
136
	let mut protocol = PolkadotProtocol::new(None);
137
138
139
140
141
142
143
144
145
146
147
148

	let peer_a = 1;
	let peer_b = 2;
	let parent_hash = [0; 32].into();
	let local_key = [1; 32].into();

	let block_data = BlockData(vec![1, 2, 3, 4]);
	let block_data_hash = block_data.hash();
	let candidate_receipt = CandidateReceipt {
		parachain_index: 5.into(),
		collator: [255; 32].into(),
		head_data: HeadData(vec![9, 9, 9]),
149
		signature: H512::from([1; 64]).into(),
150
151
152
153
154
155
156
157
158
159
160
161
		balance_uploads: Vec::new(),
		egress_queue_roots: Vec::new(),
		fees: 1_000_000,
		block_data_hash,
	};

	let candidate_hash = candidate_receipt.hash();
	let a_key = [3; 32].into();
	let b_key = [4; 32].into();

	let status = Status { collating_for: None };

162
163
	let (session, knowledge) = make_validation_session(local_key);
	protocol.new_validation_session(&mut TestContext::default(), parent_hash, session);
164
165
166
167
168
169
170

	knowledge.lock().note_statement(a_key, &GenericStatement::Valid(candidate_hash));
	let recv = protocol.fetch_block_data(&mut TestContext::default(), &candidate_receipt, parent_hash);

	// connect peer A
	{
		let mut ctx = TestContext::default();
171
		protocol.on_connect(&mut ctx, peer_a, make_status(&status, Roles::AUTHORITY));
172
		assert!(ctx.has_message(peer_a, Message::SessionKey(local_key)));
173
174
175
176
177
	}

	// peer A gives session key and gets asked for data.
	{
		let mut ctx = TestContext::default();
178
179
		on_message(&mut protocol, &mut ctx, peer_a, Message::SessionKey(a_key));
		assert!(protocol.validators.contains_key(&a_key));
180
		assert!(ctx.has_message(peer_a, Message::RequestBlockData(1, parent_hash, candidate_hash)));
181
182
183
184
185
186
187
	}

	knowledge.lock().note_statement(b_key, &GenericStatement::Valid(candidate_hash));

	// peer B connects and sends session key. request already assigned to A
	{
		let mut ctx = TestContext::default();
188
		protocol.on_connect(&mut ctx, peer_b, make_status(&status, Roles::AUTHORITY));
189
		on_message(&mut protocol, &mut ctx, peer_b, Message::SessionKey(b_key));
190
		assert!(!ctx.has_message(peer_b, Message::RequestBlockData(2, parent_hash, candidate_hash)));
191
192
193
194
195
196
197

	}

	// peer A disconnects, triggering reassignment
	{
		let mut ctx = TestContext::default();
		protocol.on_disconnect(&mut ctx, peer_a);
198
		assert!(!protocol.validators.contains_key(&a_key));
199
		assert!(ctx.has_message(peer_b, Message::RequestBlockData(2, parent_hash, candidate_hash)));
200
201
202
203
204
205
206
207
208
209
	}

	// peer B comes back with block data.
	{
		let mut ctx = TestContext::default();
		on_message(&mut protocol, &mut ctx, peer_b, Message::BlockData(2, Some(block_data.clone())));
		drop(protocol);
		assert_eq!(recv.wait().unwrap(), block_data);
	}
}
210

211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
#[test]
fn fetches_available_block_data() {
	let mut protocol = PolkadotProtocol::new(None);

	let peer_a = 1;
	let parent_hash = [0; 32].into();

	let block_data = BlockData(vec![1, 2, 3, 4]);
	let block_data_hash = block_data.hash();
	let para_id = 5.into();
	let candidate_receipt = CandidateReceipt {
		parachain_index: para_id,
		collator: [255; 32].into(),
		head_data: HeadData(vec![9, 9, 9]),
		signature: H512::from([1; 64]).into(),
		balance_uploads: Vec::new(),
		egress_queue_roots: Vec::new(),
		fees: 1_000_000,
		block_data_hash,
	};

	let candidate_hash = candidate_receipt.hash();
	let av_store = ::av_store::Store::new_in_memory();

	let status = Status { collating_for: None };

	protocol.register_availability_store(av_store.clone());

	av_store.make_available(::av_store::Data {
		relay_parent: parent_hash,
		parachain_id: para_id,
		candidate_hash,
		block_data: block_data.clone(),
		extrinsic: None,
	}).unwrap();

	// connect peer A
	{
		let mut ctx = TestContext::default();
		protocol.on_connect(&mut ctx, peer_a, make_status(&status, Roles::FULL));
	}

	// peer A asks for historic block data and gets response
	{
		let mut ctx = TestContext::default();
		on_message(&mut protocol, &mut ctx, peer_a, Message::RequestBlockData(1, parent_hash, candidate_hash));
		assert!(ctx.has_message(peer_a, Message::BlockData(1, Some(block_data))));
	}
}

261
262
#[test]
fn remove_bad_collator() {
263
	let mut protocol = PolkadotProtocol::new(None);
264

Gav Wood's avatar
Gav Wood committed
265
	let who = 1;
266
267
268
269
270
271
	let account_id = [2; 32].into();

	let status = Status { collating_for: Some((account_id, 5.into())) };

	{
		let mut ctx = TestContext::default();
Gav Wood's avatar
Gav Wood committed
272
		protocol.on_connect(&mut ctx, who, make_status(&status, Roles::NONE));
273
274
275
276
277
	}

	{
		let mut ctx = TestContext::default();
		protocol.disconnect_bad_collator(&mut ctx, account_id);
Gav Wood's avatar
Gav Wood committed
278
		assert!(ctx.disabled.contains(&who));
279
280
	}
}
281
282
283
284
285
286
287
288
289
290
291

#[test]
fn many_session_keys() {
	let mut protocol = PolkadotProtocol::new(None);

	let parent_a = [1; 32].into();
	let parent_b = [2; 32].into();

	let local_key_a = [3; 32].into();
	let local_key_b = [4; 32].into();

292
293
	let (session_a, _knowledge_a) = make_validation_session(local_key_a);
	let (session_b, _knowledge_b) = make_validation_session(local_key_b);
294

295
296
	protocol.new_validation_session(&mut TestContext::default(), parent_a, session_a);
	protocol.new_validation_session(&mut TestContext::default(), parent_b, session_b);
297

298
	assert_eq!(protocol.live_validation_sessions.recent_keys(), &[local_key_a, local_key_b]);
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314

	let peer_a = 1;

	// when connecting a peer, we should get both those keys.
	{
		let mut ctx = TestContext::default();

		let status = Status { collating_for: None };
		protocol.on_connect(&mut ctx, peer_a, make_status(&status, Roles::AUTHORITY));

		assert!(ctx.has_message(peer_a, Message::SessionKey(local_key_a)));
		assert!(ctx.has_message(peer_a, Message::SessionKey(local_key_b)));
	}

	let peer_b = 2;

315
	protocol.remove_validation_session(&parent_a);
316
317
318
319
320
321
322
323
324
325
326

	{
		let mut ctx = TestContext::default();

		let status = Status { collating_for: None };
		protocol.on_connect(&mut ctx, peer_b, make_status(&status, Roles::AUTHORITY));

		assert!(!ctx.has_message(peer_b, Message::SessionKey(local_key_a)));
		assert!(ctx.has_message(peer_b, Message::SessionKey(local_key_b)));
	}
}