tests.rs 8.25 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 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/>.

//! Tests for polkadot and consensus network.

use super::{PolkadotProtocol, Status, CurrentConsensus, Knowledge, Message, FullStatus};

use parking_lot::Mutex;
use polkadot_consensus::GenericStatement;
use polkadot_primitives::{Block, Hash, SessionKey};
use polkadot_primitives::parachain::{CandidateReceipt, HeadData, BlockData};
25
use substrate_primitives::H512;
Arkadiy Paronyan's avatar
Arkadiy Paronyan committed
26
use codec::Encode;
Gav Wood's avatar
Gav Wood committed
27
use substrate_network::{Severity, NodeIndex, PeerInfo, ClientHandle, Context, Roles, message::Message as SubstrateMessage, specialization::Specialization, generic_message::Message as GenericMessage};
28
29
30
31
32
33

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

#[derive(Default)]
struct TestContext {
Gav Wood's avatar
Gav Wood committed
34
35
36
	disabled: Vec<NodeIndex>,
	disconnected: Vec<NodeIndex>,
	messages: Vec<(NodeIndex, SubstrateMessage<Block>)>,
37
38
39
40
41
42
43
}

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

Gav Wood's avatar
Gav Wood committed
44
	fn report_peer(&mut self, peer: NodeIndex, reason: Severity) {
45
46
47
48
		match reason {
			Severity::Bad(_) => self.disabled.push(peer),
			_ => self.disconnected.push(peer),
		}
49
50
	}

Gav Wood's avatar
Gav Wood committed
51
	fn peer_info(&self, _peer: NodeIndex) -> Option<PeerInfo<Block>> {
52
53
54
		unimplemented!()
	}

Gav Wood's avatar
Gav Wood committed
55
56
	fn send_message(&mut self, who: NodeIndex, data: SubstrateMessage<Block>) {
		self.messages.push((who, data))
57
58
59
60
	}
}

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

64
		let encoded = message.encode();
65
66
67
68
69
70
71
		self.messages.iter().any(|&(ref peer, ref msg)| match msg {
			GenericMessage::ChainSpecific(ref data) => peer == &to && data == &encoded,
			_ => false,
		})
	}
}

72
fn make_status(status: &Status, roles: Roles) -> FullStatus {
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
	FullStatus {
		version: 1,
		roles,
		best_number: 0,
		best_hash: Default::default(),
		genesis_hash: Default::default(),
		chain_status: status.encode(),
	}
}

fn make_consensus(parent_hash: Hash, local_key: SessionKey) -> (CurrentConsensus, Arc<Mutex<Knowledge>>) {
	let knowledge = Arc::new(Mutex::new(Knowledge::new()));
	let c = CurrentConsensus {
		knowledge: knowledge.clone(),
		parent_hash,
		local_session_key: local_key,
	};

	(c, knowledge)
}

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

#[test]
fn sends_session_key() {
101
	let mut protocol = PolkadotProtocol::new(None);
102
103
104
105
106
107

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

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

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

	{
		let mut ctx = TestContext::default();
		let (consensus, _knowledge) = make_consensus(parent_hash, local_key);
		protocol.new_consensus(&mut ctx, consensus);
121
		assert!(ctx.has_message(peer_a, Message::SessionKey(local_key)));
122
123
124
125
	}

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

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

	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]),
146
		signature: H512::from([1; 64]).into(),
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
		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 };

	let (consensus, knowledge) = make_consensus(parent_hash, local_key);
	protocol.new_consensus(&mut TestContext::default(), consensus);

	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();
168
		protocol.on_connect(&mut ctx, peer_a, make_status(&status, Roles::AUTHORITY));
169
		assert!(ctx.has_message(peer_a, Message::SessionKey(local_key)));
170
171
172
173
174
	}

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

	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();
185
		protocol.on_connect(&mut ctx, peer_b, make_status(&status, Roles::AUTHORITY));
186
		on_message(&mut protocol, &mut ctx, peer_b, Message::SessionKey(b_key));
187
		assert!(!ctx.has_message(peer_b, Message::RequestBlockData(2, parent_hash, candidate_hash)));
188
189
190
191
192
193
194

	}

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

	// 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);
	}
}
207

208
209
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
#[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))));
	}
}

258
259
#[test]
fn remove_bad_collator() {
260
	let mut protocol = PolkadotProtocol::new(None);
261

Gav Wood's avatar
Gav Wood committed
262
	let who = 1;
263
264
265
266
267
268
	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
269
		protocol.on_connect(&mut ctx, who, make_status(&status, Roles::NONE));
270
271
272
273
274
	}

	{
		let mut ctx = TestContext::default();
		protocol.disconnect_bad_collator(&mut ctx, account_id);
Gav Wood's avatar
Gav Wood committed
275
		assert!(ctx.disabled.contains(&who));
276
277
	}
}