grandpa_support.rs 15.1 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// Copyright 2017-2020 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/>.

//! Polkadot-specific GRANDPA integration utilities.

19
20
use std::sync::Arc;

21
use polkadot_primitives::v1::Hash;
22

23
use sp_runtime::traits::{Block as BlockT, NumberFor};
24
25
26
use sp_runtime::generic::BlockId;
use sp_runtime::traits::Header as _;

27
#[cfg(feature = "real-overseer")]
28
29
30
31
32
33
34
use {
	polkadot_primitives::v1::{Block as PolkadotBlock, Header as PolkadotHeader, BlockNumber},
	polkadot_subsystem::messages::ApprovalVotingMessage,
	prometheus_endpoint::{self, Registry},
	polkadot_overseer::OverseerHandler,
	futures::channel::oneshot,
};
35
36
37
38
39
40
41

/// A custom GRANDPA voting rule that acts as a diagnostic for the approval
/// voting subsystem's desired votes.
///
/// The practical effect of this voting rule is to implement a fixed delay of
/// blocks and to issue a prometheus metric on the lag behind the head that
/// approval checking would indicate.
42
#[cfg(feature = "real-overseer")]
43
44
45
46
47
48
#[derive(Clone)]
pub(crate) struct ApprovalCheckingDiagnostic {
	checking_lag: Option<prometheus_endpoint::Histogram>,
	overseer: OverseerHandler,
}

49
#[cfg(feature = "real-overseer")]
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
impl ApprovalCheckingDiagnostic {
	/// Create a new approval checking diagnostic voting rule.
	pub fn new(overseer: OverseerHandler, registry: Option<&Registry>)
		-> Result<Self, prometheus_endpoint::PrometheusError>
	{
		Ok(ApprovalCheckingDiagnostic {
			checking_lag: if let Some(registry) = registry {
				Some(prometheus_endpoint::register(
					prometheus_endpoint::Histogram::with_opts(
						prometheus_endpoint::HistogramOpts::new(
							"approval_checking_finality_lag",
							"How far behind the head of the chain the Approval Checking protocol wants to vote",
						).buckets(vec![1.0, 2.0, 3.0, 4.0, 5.0, 10.0, 20.0, 30.0, 40.0, 50.0])
					)?,
					registry,
				)?)
			} else {
				None
			},
			overseer,
		})
	}
}

74
#[cfg(feature = "real-overseer")]
75
76
77
78
79
80
81
impl<B> grandpa::VotingRule<PolkadotBlock, B> for ApprovalCheckingDiagnostic
	where B: sp_blockchain::HeaderBackend<PolkadotBlock>
{
	fn restrict_vote(
		&self,
		backend: Arc<B>,
		base: &PolkadotHeader,
82
		best_target: &PolkadotHeader,
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
		current_target: &PolkadotHeader,
	) -> grandpa::VotingRuleResult<PolkadotBlock> {
		// always wait 50 blocks behind the head to finalize.
		const DIAGNOSTIC_GRANDPA_DELAY: BlockNumber = 50;

		let aux = || {
			let find_target = |target_number: BlockNumber, current_header: &PolkadotHeader| {
				let mut target_hash = current_header.hash();
				let mut target_header = current_header.clone();

				loop {
					if *target_header.number() < target_number {
						unreachable!(
							"we are traversing backwards from a known block; \
							blocks are stored contiguously; \
							qed"
						);
					}

					if *target_header.number() == target_number {
						return Some((target_hash, target_number));
					}

					target_hash = *target_header.parent_hash();
					target_header = backend.header(BlockId::Hash(target_hash)).ok()?
						.expect("Header known to exist due to the existence of one of its descendents; qed");
				}
			};

112
113
114
115
116
117
118
119
			// delay blocks behind the head, but make sure we're not ahead of the current
			// target.
			let target_number = std::cmp::min(
				best_target.number().saturating_sub(DIAGNOSTIC_GRANDPA_DELAY),
				current_target.number().clone(),
			);

			// don't go below base
120
			let target_number = std::cmp::max(
121
				target_number,
122
123
124
125
126
127
128
129
130
131
132
133
				base.number().clone(),
			);

			find_target(target_number, current_target)
		};

		let actual_vote_target = aux();

		// Query approval checking and issue metrics.
		let mut overseer = self.overseer.clone();
		let checking_lag = self.checking_lag.clone();

134
135
		let best_hash = best_target.hash();
		let best_number = best_target.number.clone();
136
137
138
139
140
141
142

		let base_number = base.number;

		Box::pin(async move {
			let (tx, rx) = oneshot::channel();
			let approval_checking_subsystem_vote = {
				overseer.send_msg(ApprovalVotingMessage::ApprovedAncestor(
143
					best_hash,
144
145
146
147
148
149
150
151
					base_number,
					tx,
				)).await;

				rx.await.ok().and_then(|v| v)
			};

			let approval_checking_subsystem_lag = approval_checking_subsystem_vote.map_or(
152
153
				best_number - base_number,
				|(_h, n)| best_number - n,
154
155
156
157
158
159
			);

			if let Some(ref checking_lag) = checking_lag {
				checking_lag.observe(approval_checking_subsystem_lag as _);
			}

160
161
162
163
164
165
166
			tracing::debug!(
				target: "approval_voting",
				"GRANDPA: voting on {:?}. Approval-checking lag behind best is {}",
				actual_vote_target,
				approval_checking_subsystem_lag,
			);

167
168
169
170
			actual_vote_target
		})
	}
}
171
172
173
174
175

/// A custom GRANDPA voting rule that "pauses" voting (i.e. keeps voting for the
/// same last finalized block) after a given block at height `N` has been
/// finalized and for a delay of `M` blocks, i.e. until the best block reaches
/// `N` + `M`, the voter will keep voting for block `N`.
176
#[derive(Clone)]
177
178
pub(crate) struct PauseAfterBlockFor<N>(pub(crate) N, pub(crate) N);

179
180
impl<Block, B> grandpa::VotingRule<Block, B> for PauseAfterBlockFor<NumberFor<Block>>
where
181
182
183
184
185
	Block: BlockT,
	B: sp_blockchain::HeaderBackend<Block>,
{
	fn restrict_vote(
		&self,
186
		backend: Arc<B>,
187
188
189
		base: &Block::Header,
		best_target: &Block::Header,
		current_target: &Block::Header,
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
	) -> grandpa::VotingRuleResult<Block> {
		let aux = || {
			// walk backwards until we find the target block
			let find_target = |target_number: NumberFor<Block>, current_header: &Block::Header| {
				let mut target_hash = current_header.hash();
				let mut target_header = current_header.clone();

				loop {
					if *target_header.number() < target_number {
						unreachable!(
							"we are traversing backwards from a known block; \
							 blocks are stored contiguously; \
							 qed"
						);
					}

					if *target_header.number() == target_number {
						return Some((target_hash, target_number));
					}

					target_hash = *target_header.parent_hash();
					target_header = backend.header(BlockId::Hash(target_hash)).ok()?.expect(
						"Header known to exist due to the existence of one of its descendents; qed",
213
214
					);
				}
215
216
217
218
219
220
221
222
223
			};

			// only restrict votes targeting a block higher than the block
			// we've set for the pause
			if *current_target.number() > self.0 {
				// if we're past the pause period (i.e. `self.0 + self.1`)
				// then we no longer need to restrict any votes
				if *best_target.number() > self.0 + self.1 {
					return None;
224
225
				}

226
227
228
229
230
				// if we've finalized the pause block, just keep returning it
				// until best number increases enough to pass the condition above
				if *base.number() >= self.0 {
					return Some((base.hash(), *base.number()));
				}
231

232
233
234
				// otherwise find the target header at the pause block
				// to vote on
				return find_target(self.0, current_target);
235
236
			}

237
238
			None
		};
239

240
		let target = aux();
241

242
		Box::pin(async move { target })
243
244
245
246
247
248
249
250
251
	}
}

/// GRANDPA hard forks due to borked migration of session keys after a runtime
/// upgrade (at #1491596), the signalled authority set changes were invalid
/// (blank keys) and were impossible to finalize. The authorities for these
/// intermediary pending changes are replaced with a static list comprised of
/// w3f validators and randomly selected validators from the latest session (at
/// #1500988).
252
#[cfg(feature = "full-node")]
253
254
pub(crate) fn kusama_hard_forks() -> Vec<(
	grandpa_primitives::SetId,
asynchronous rob's avatar
asynchronous rob committed
255
	(Hash, polkadot_primitives::v1::BlockNumber),
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
	grandpa_primitives::AuthorityList,
)> {
	use sp_core::crypto::Ss58Codec;
	use std::str::FromStr;

	let forks = vec![
		(
			623,
			"01e94e1e7e9cf07b3b0bf4e1717fce7448e5563901c2ef2e3b8e9ecaeba088b1",
			1492283,
		),
		(
			624,
			"ddc4323c5e8966844dfaa87e0c2f74ef6b43115f17bf8e4ff38845a62d02b9a9",
			1492436,
		),
		(
			625,
			"38ba115b296663e424e32d7b1655cd795719cef4fd7d579271a6d01086cf1628",
			1492586,
		),
		(
			626,
			"f3172b6b8497c10fc772f5dada4eeb1f4c4919c97de9de2e1a439444d5a057ff",
			1492955,
		),
		(
			627,
			"b26526aea299e9d24af29fdacd5cf4751a663d24894e3d0a37833aa14c58424a",
			1493338,
		),
		(
			628,
			"3980d024327d53b8d01ef0d198a052cd058dd579508d8ed6283fe3614e0a3694",
			1493913,
		),
		(
			629,
			"31f22997a786c25ee677786373368cae6fd501fd1bc4b212b8e267235c88179d",
			1495083,
		),
		(
			630,
			"1c65eb250cf54b466c64f1a4003d1415a7ee275e49615450c0e0525179857eef",
			1497404,
		),
		(
			631,
			"9e44116467cc9d7e224e36487bf2cf571698cae16b25f54a7430f1278331fdd8",
			1498598,
		),
	];

	let authorities = vec![
		"CwjLJ1zPWK5Ao9WChAFp7rWGEgN3AyXXjTRPrqgm5WwBpoS",
		"Dp8FHpZTzvoKXztkfrUAkF6xNf6sjVU5ZLZ29NEGUazouou",
		"DtK7YfkhNWU6wEPF1dShsFdhtosVAuJPLkoGhKhG1r5LjKq",
		"FLnHYBuoyThzqJ45tdb8P6yMLdocM7ir27Pg1AnpYoygm1K",
		"FWEfJ5UMghr52UopgYjawAg6hQg3ztbQek75pfeRtLVi8pB",
		"ECoLHAu7HKWGTB9od82HAtequYj6hvNHigkGSB9g3ApxAwB",
		"GL1Tg3Uppo8GYL9NjKj4dWKcS6tW98REop9G5hpu7HgFwTa",
		"ExnjU5LZMktrgtQBE3An6FsQfvaKG1ukxPqwhJydgdgarmY",
		"CagLpgCBu5qJqYF2tpFX6BnU4yHvMGSjc7r3Ed1jY3tMbQt",
		"DsrtmMsD4ijh3n4uodxPoiW9NZ7v7no5wVvPVj8fL1dfrWB",
		"HQB4EctrVR68ozZDyBiRJzLRAEGh1YKgCkAsFjJcegL9RQA",
		"H2YTYbXTFkDY1cGnv164ecnDT3hsD2bQXtyiDbcQuXcQZUV",
		"H5WL8jXmbkCoEcLfvqJkbLUeGrDFsJiMXkhhRWn3joct1tE",
		"DpB37GDrJDYcmg2df2eqsrPKMay1u8hyZ6sQi2FuUiUeNLu",
		"FR8yjKRA9MTjvFGK8kfzrdC23Fr6xd7rfBvZXSjAsmuxURE",
		"DxHPty3B9fpj3duu6Gc6gCSCAvsydJHJEY5G3oVYT8S5BYJ",
		"DbVKC8ZJjevrhqSnZyJMMvmPL7oPPL4ed1roxawYnHVgyin",
		"DVJV81kab2J6oTyRJ9T3NCwW2DSrysbWCssvMcE6cwZHnAd",
		"Fg4rDAyzoVzf39Zo8JFPo4W314ntNWNwm3shr4xKe8M1fJg",
		"GUaNcnAruMVxHGTs7gGpSUpigRJboQYQBBQyPohkFcP6NMH",
		"J4BMGF4W9yWiJz4pkhQW73X6QMGpKUzmPppVnqzBCqw5dQq",
		"E1cR61L1tdDEop4WdWVqcq1H1x6VqsDpSHvFyUeC41uruVJ",
		"GoWLzBsj1f23YtdDpyntnvN1LwXKhF5TEeZvBeTVxofgWGR",
		"CwHwmbogSwtRbrkajVBNubPvWmHBGU4bhMido54M9CjuKZD",
		"FLT63y9oVXJnyiWMAL4RvWxsQx21Vymw9961Z7NRFmSG7rw",
		"FoQ2y6JuHuHTG4rHFL3f2hCxfJMvtrq8wwPWdv8tsdkcyA8",
		"D7QQKqqs8ocGorRA12h4QoBSHDia1DkHeXT4eMfjWQ483QH",
		"J6z7FP35F9DiiU985bhkDTS3WxyeTBeoo9MtLdLoD3GiWPj",
		"EjapydCK25AagodRbDECavHAy8yQY1tmeRhwUXhVWx4cFPv",
		"H8admATcRkGCrF1dTDDBCjQDsYjMkuPaN9YwR2mSCj4DWMQ",
		"FtHMRU1fxsoswJjBvyCGvECepC7gP2X77QbNpyikYSqqR6k",
		"DzY5gwr45GVRUFzRMmeg8iffpqYF47nm3XbJhmjG97FijaE",
		"D3HKWAihSUmg8HrfeFrftSwNK7no261yA9RNr3LUUdsuzuJ",
		"D82DwwGJGTcSvtB3SmNrZejnSertbPzpkYvDUp3ibScL3ne",
		"FTPxLXLQvMDQYFA6VqNLGwWPKhemMYP791XVj8TmDpFuV3b",
		"FzGfKmS7N8Z1tvCBU5JH1eBXZQ9pCtRNoMUnNVv38wZNq72",
		"GDfm1MyLAQ7Rh8YPtF6FtMweV4hz91zzeDy2sSABNNqAbmg",
		"DiVQbq7sozeKp7PXPM1HLFc2m7ih8oepKLRK99oBY3QZak1",
		"HErWh7D2RzrjWWB2fTJfcAejD9MJpadeWWZM2Wnk7LiNWfG",
		"Es4DbDauYZYyRJbr6VxrhdcM1iufP9GtdBYf3YtSEvdwNyb",
		"EBgXT6FaVo4WsN2LmfnB2jnpDFf4zay3E492RGSn6v1tY99",
		"Dr9Zg4fxZurexParztL9SezFeHsPwdP8uGgULeRMbk8DDHJ",
		"JEnSTZJpLh91cSryptj57RtFxq9xXqf4U5wBH3qoP91ZZhN",
		"DqtRkrmtPANa8wrYR7Ce2LxJxk2iNFtiCxv1cXbx54uqdTN",
		"GaxmF53xbuTFKopVEseWiaCTa8fC6f99n4YfW8MGPSPYX3s",
		"EiCesgkAaighBKMpwFSAUdvwE4mRjBjNmmd5fP6d4FG8DAx",
		"HVbwWGUx7kCgUGap1Mfcs37g6JAZ5qsfsM7TsDRcSqvfxmd",
		"G45bc8Ajrd6YSXav77gQwjjGoAsR2qiGd1aLzkMy7o1RLwd",
		"Cqix2rD93Mdf7ytg8tBavAig2TvhXPgPZ2mejQvkq7qgRPq",
		"GpodE2S5dPeVjzHB4Drm8R9rEwcQPtwAspXqCVz1ooFWf5K",
		"CwfmfRmzPKLj3ntSCejuVwYmQ1F9iZWY4meQrAVoJ2G8Kce",
		"Fhp5NPvutRCJ4Gx3G8vCYGaveGcU3KgTwfrn5Zr8sLSgwVx",
		"GeYRRPkyi23wSF3cJGjq82117fKJZUbWsAGimUnzb5RPbB1",
		"DzCJ4y5oT611dfKQwbBDVbtCfENTdMCjb4KGMU3Mq6nyUMu",
	];

	let authorities = authorities
		.into_iter()
		.map(|address| {
			(
				grandpa_primitives::AuthorityId::from_ss58check(address)
					.expect("hard fork authority addresses are static and they should be carefully defined; qed."),
				1,
			)
		})
		.collect::<Vec<_>>();

	forks
		.into_iter()
		.map(|(set_id, hash, number)| {
			let hash = Hash::from_str(hash)
				.expect("hard fork hashes are static and they should be carefully defined; qed.");

			(set_id, (hash, number), authorities.clone())
		})
		.collect()
}

#[cfg(test)]
mod tests {
390
	use grandpa::VotingRule;
391
392
393
394
	use polkadot_test_client::{
		TestClientBuilder, TestClientBuilderExt, DefaultTestClientBuilderExt, InitPolkadotBlockBuilder,
		ClientBlockImportExt,
	};
395
	use sp_blockchain::HeaderBackend;
396
397
	use sp_runtime::{generic::BlockId, traits::Header};
	use consensus_common::BlockOrigin;
398
399
400
401
402
403
	use std::sync::Arc;

	#[test]
	fn grandpa_pause_voting_rule_works() {
		let _ = env_logger::try_init();

404
		let client = Arc::new(TestClientBuilder::new().build());
405
406
407

		let mut push_blocks = {
			let mut client = client.clone();
408

409
			move |n| {
410
411
				for _ in 0..n {
					let block = client.init_polkadot_block_builder().build().unwrap().block;
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
					client.import(BlockOrigin::Own, block).unwrap();
				}
			}
		};

		let get_header = {
			let client = client.clone();
			move |n| client.header(&BlockId::Number(n)).unwrap().unwrap()
		};

		// the rule should filter all votes after block #20
		// is finalized until block #50 is imported.
		let voting_rule = super::PauseAfterBlockFor(20, 30);

		// add 10 blocks
		push_blocks(10);
428
		assert_eq!(client.info().best_number, 10);
429
430
431
432

		// we have not reached the pause block
		// therefore nothing should be restricted
		assert_eq!(
433
434
435
436
437
438
			futures::executor::block_on(voting_rule.restrict_vote(
				client.clone(),
				&get_header(0),
				&get_header(10),
				&get_header(10)
			)),
439
440
441
442
443
444
445
446
447
448
			None,
		);

		// add 15 more blocks
		// best block: #25
		push_blocks(15);

		// we are targeting the pause block,
		// the vote should not be restricted
		assert_eq!(
449
450
451
452
453
454
			futures::executor::block_on(voting_rule.restrict_vote(
				client.clone(),
				&get_header(10),
				&get_header(20),
				&get_header(20)
			)),
455
456
457
458
459
460
461
			None,
		);

		// we are past the pause block, votes should
		// be limited to the pause block.
		let pause_block = get_header(20);
		assert_eq!(
462
463
464
465
466
467
			futures::executor::block_on(voting_rule.restrict_vote(
				client.clone(),
				&get_header(10),
				&get_header(21),
				&get_header(21)
			)),
468
469
470
471
472
473
			Some((pause_block.hash(), *pause_block.number())),
		);

		// we've finalized the pause block, so we'll keep
		// restricting our votes to it.
		assert_eq!(
474
475
			futures::executor::block_on(voting_rule.restrict_vote(
				client.clone(),
476
477
478
				&pause_block, // #20
				&get_header(21),
				&get_header(21),
479
			)),
480
481
482
483
484
485
486
487
488
489
			Some((pause_block.hash(), *pause_block.number())),
		);

		// add 30 more blocks
		// best block: #55
		push_blocks(30);

		// we're at the last block of the pause, this block
		// should still be considered in the pause period
		assert_eq!(
490
491
			futures::executor::block_on(voting_rule.restrict_vote(
				client.clone(),
492
493
494
				&pause_block, // #20
				&get_header(50),
				&get_header(50),
495
			)),
496
497
498
499
500
			Some((pause_block.hash(), *pause_block.number())),
		);

		// we're past the pause period, no votes should be filtered
		assert_eq!(
501
502
			futures::executor::block_on(voting_rule.restrict_vote(
				client.clone(),
503
504
505
				&pause_block, // #20
				&get_header(51),
				&get_header(51),
506
			)),
507
508
509
510
			None,
		);
	}
}