referrerpolicy=no-referrer-when-downgrade

sp_consensus_grandpa/
lib.rs

1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: Apache-2.0
5
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// 	http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18//! Primitives for GRANDPA integration, suitable for WASM compilation.
19
20#![cfg_attr(not(feature = "std"), no_std)]
21
22extern crate alloc;
23
24#[cfg(feature = "serde")]
25use serde::Serialize;
26
27use alloc::vec::Vec;
28use codec::{Codec, Decode, DecodeWithMemTracking, Encode};
29use scale_info::TypeInfo;
30#[cfg(feature = "std")]
31use sp_keystore::KeystorePtr;
32use sp_runtime::{
33	traits::{Header as HeaderT, NumberFor},
34	ConsensusEngineId, OpaqueValue, RuntimeDebug,
35};
36
37/// The log target to be used by client code.
38pub const CLIENT_LOG_TARGET: &str = "grandpa";
39/// The log target to be used by runtime code.
40pub const RUNTIME_LOG_TARGET: &str = "runtime::grandpa";
41
42/// Key type for GRANDPA module.
43pub const KEY_TYPE: sp_core::crypto::KeyTypeId = sp_application_crypto::key_types::GRANDPA;
44
45mod app {
46	use sp_application_crypto::{app_crypto, ed25519, key_types::GRANDPA};
47	app_crypto!(ed25519, GRANDPA);
48}
49
50sp_application_crypto::with_pair! {
51	/// The grandpa crypto scheme defined via the keypair type.
52	pub type AuthorityPair = app::Pair;
53}
54
55/// Identity of a Grandpa authority.
56pub type AuthorityId = app::Public;
57
58/// Signature for a Grandpa authority.
59pub type AuthoritySignature = app::Signature;
60
61/// The `ConsensusEngineId` of GRANDPA.
62pub const GRANDPA_ENGINE_ID: ConsensusEngineId = *b"FRNK";
63
64/// The weight of an authority.
65pub type AuthorityWeight = u64;
66
67/// The index of an authority.
68pub type AuthorityIndex = u64;
69
70/// The monotonic identifier of a GRANDPA set of authorities.
71pub type SetId = u64;
72
73/// The round indicator.
74pub type RoundNumber = u64;
75
76/// A list of Grandpa authorities with associated weights.
77pub type AuthorityList = Vec<(AuthorityId, AuthorityWeight)>;
78
79/// A GRANDPA message for a substrate chain.
80pub type Message<Header> =
81	finality_grandpa::Message<<Header as HeaderT>::Hash, <Header as HeaderT>::Number>;
82
83/// A signed message.
84pub type SignedMessage<Header> = finality_grandpa::SignedMessage<
85	<Header as HeaderT>::Hash,
86	<Header as HeaderT>::Number,
87	AuthoritySignature,
88	AuthorityId,
89>;
90
91/// A primary propose message for this chain's block type.
92pub type PrimaryPropose<Header> =
93	finality_grandpa::PrimaryPropose<<Header as HeaderT>::Hash, <Header as HeaderT>::Number>;
94/// A prevote message for this chain's block type.
95pub type Prevote<Header> =
96	finality_grandpa::Prevote<<Header as HeaderT>::Hash, <Header as HeaderT>::Number>;
97/// A precommit message for this chain's block type.
98pub type Precommit<Header> =
99	finality_grandpa::Precommit<<Header as HeaderT>::Hash, <Header as HeaderT>::Number>;
100/// A catch up message for this chain's block type.
101pub type CatchUp<Header> = finality_grandpa::CatchUp<
102	<Header as HeaderT>::Hash,
103	<Header as HeaderT>::Number,
104	AuthoritySignature,
105	AuthorityId,
106>;
107/// A commit message for this chain's block type.
108pub type Commit<Header> = finality_grandpa::Commit<
109	<Header as HeaderT>::Hash,
110	<Header as HeaderT>::Number,
111	AuthoritySignature,
112	AuthorityId,
113>;
114
115/// A compact commit message for this chain's block type.
116pub type CompactCommit<Header> = finality_grandpa::CompactCommit<
117	<Header as HeaderT>::Hash,
118	<Header as HeaderT>::Number,
119	AuthoritySignature,
120	AuthorityId,
121>;
122
123/// A GRANDPA justification for block finality, it includes a commit message and
124/// an ancestry proof including all headers routing all precommit target blocks
125/// to the commit target block. Due to the current voting strategy the precommit
126/// targets should be the same as the commit target, since honest voters don't
127/// vote past authority set change blocks.
128///
129/// This is meant to be stored in the db and passed around the network to other
130/// nodes, and are used by syncing nodes to prove authority set handoffs.
131#[derive(Clone, Encode, Decode, PartialEq, Eq, TypeInfo)]
132#[cfg_attr(feature = "std", derive(Debug))]
133pub struct GrandpaJustification<Header: HeaderT> {
134	pub round: u64,
135	pub commit: Commit<Header>,
136	pub votes_ancestries: Vec<Header>,
137}
138
139/// A scheduled change of authority set.
140#[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo)]
141#[cfg_attr(feature = "serde", derive(Serialize))]
142pub struct ScheduledChange<N> {
143	/// The new authorities after the change, along with their respective weights.
144	pub next_authorities: AuthorityList,
145	/// The number of blocks to delay.
146	pub delay: N,
147}
148
149/// An consensus log item for GRANDPA.
150#[derive(Decode, Encode, PartialEq, Eq, Clone, RuntimeDebug)]
151#[cfg_attr(feature = "serde", derive(Serialize))]
152pub enum ConsensusLog<N: Codec> {
153	/// Schedule an authority set change.
154	///
155	/// The earliest digest of this type in a single block will be respected,
156	/// provided that there is no `ForcedChange` digest. If there is, then the
157	/// `ForcedChange` will take precedence.
158	///
159	/// No change should be scheduled if one is already and the delay has not
160	/// passed completely.
161	///
162	/// This should be a pure function: i.e. as long as the runtime can interpret
163	/// the digest type it should return the same result regardless of the current
164	/// state.
165	#[codec(index = 1)]
166	ScheduledChange(ScheduledChange<N>),
167	/// Force an authority set change.
168	///
169	/// Forced changes are applied after a delay of _imported_ blocks,
170	/// while pending changes are applied after a delay of _finalized_ blocks.
171	///
172	/// The earliest digest of this type in a single block will be respected,
173	/// with others ignored.
174	///
175	/// No change should be scheduled if one is already and the delay has not
176	/// passed completely.
177	///
178	/// This should be a pure function: i.e. as long as the runtime can interpret
179	/// the digest type it should return the same result regardless of the current
180	/// state.
181	#[codec(index = 2)]
182	ForcedChange(N, ScheduledChange<N>),
183	/// Note that the authority with given index is disabled until the next change.
184	#[codec(index = 3)]
185	OnDisabled(AuthorityIndex),
186	/// A signal to pause the current authority set after the given delay.
187	/// After finalizing the block at _delay_ the authorities should stop voting.
188	#[codec(index = 4)]
189	Pause(N),
190	/// A signal to resume the current authority set after the given delay.
191	/// After authoring the block at _delay_ the authorities should resume voting.
192	#[codec(index = 5)]
193	Resume(N),
194}
195
196impl<N: Codec> ConsensusLog<N> {
197	/// Try to cast the log entry as a contained signal.
198	pub fn try_into_change(self) -> Option<ScheduledChange<N>> {
199		match self {
200			ConsensusLog::ScheduledChange(change) => Some(change),
201			_ => None,
202		}
203	}
204
205	/// Try to cast the log entry as a contained forced signal.
206	pub fn try_into_forced_change(self) -> Option<(N, ScheduledChange<N>)> {
207		match self {
208			ConsensusLog::ForcedChange(median, change) => Some((median, change)),
209			_ => None,
210		}
211	}
212
213	/// Try to cast the log entry as a contained pause signal.
214	pub fn try_into_pause(self) -> Option<N> {
215		match self {
216			ConsensusLog::Pause(delay) => Some(delay),
217			_ => None,
218		}
219	}
220
221	/// Try to cast the log entry as a contained resume signal.
222	pub fn try_into_resume(self) -> Option<N> {
223		match self {
224			ConsensusLog::Resume(delay) => Some(delay),
225			_ => None,
226		}
227	}
228}
229
230/// Proof of voter misbehavior on a given set id. Misbehavior/equivocation in
231/// GRANDPA happens when a voter votes on the same round (either at prevote or
232/// precommit stage) for different blocks. Proving is achieved by collecting the
233/// signed messages of conflicting votes.
234#[derive(Clone, Debug, Decode, DecodeWithMemTracking, Encode, PartialEq, Eq, TypeInfo)]
235pub struct EquivocationProof<H, N> {
236	set_id: SetId,
237	equivocation: Equivocation<H, N>,
238}
239
240impl<H, N> EquivocationProof<H, N> {
241	/// Create a new `EquivocationProof` for the given set id and using the
242	/// given equivocation as proof.
243	pub fn new(set_id: SetId, equivocation: Equivocation<H, N>) -> Self {
244		EquivocationProof { set_id, equivocation }
245	}
246
247	/// Returns the set id at which the equivocation occurred.
248	pub fn set_id(&self) -> SetId {
249		self.set_id
250	}
251
252	/// Returns the round number at which the equivocation occurred.
253	pub fn round(&self) -> RoundNumber {
254		match self.equivocation {
255			Equivocation::Prevote(ref equivocation) => equivocation.round_number,
256			Equivocation::Precommit(ref equivocation) => equivocation.round_number,
257		}
258	}
259
260	/// Returns the authority id of the equivocator.
261	pub fn offender(&self) -> &AuthorityId {
262		self.equivocation.offender()
263	}
264}
265
266/// Wrapper object for GRANDPA equivocation proofs, useful for unifying prevote
267/// and precommit equivocations under a common type.
268#[derive(Clone, Debug, Decode, DecodeWithMemTracking, Encode, PartialEq, Eq, TypeInfo)]
269pub enum Equivocation<H, N> {
270	/// Proof of equivocation at prevote stage.
271	Prevote(
272		finality_grandpa::Equivocation<
273			AuthorityId,
274			finality_grandpa::Prevote<H, N>,
275			AuthoritySignature,
276		>,
277	),
278	/// Proof of equivocation at precommit stage.
279	Precommit(
280		finality_grandpa::Equivocation<
281			AuthorityId,
282			finality_grandpa::Precommit<H, N>,
283			AuthoritySignature,
284		>,
285	),
286}
287
288impl<H, N>
289	From<
290		finality_grandpa::Equivocation<
291			AuthorityId,
292			finality_grandpa::Prevote<H, N>,
293			AuthoritySignature,
294		>,
295	> for Equivocation<H, N>
296{
297	fn from(
298		equivocation: finality_grandpa::Equivocation<
299			AuthorityId,
300			finality_grandpa::Prevote<H, N>,
301			AuthoritySignature,
302		>,
303	) -> Self {
304		Equivocation::Prevote(equivocation)
305	}
306}
307
308impl<H, N>
309	From<
310		finality_grandpa::Equivocation<
311			AuthorityId,
312			finality_grandpa::Precommit<H, N>,
313			AuthoritySignature,
314		>,
315	> for Equivocation<H, N>
316{
317	fn from(
318		equivocation: finality_grandpa::Equivocation<
319			AuthorityId,
320			finality_grandpa::Precommit<H, N>,
321			AuthoritySignature,
322		>,
323	) -> Self {
324		Equivocation::Precommit(equivocation)
325	}
326}
327
328impl<H, N> Equivocation<H, N> {
329	/// Returns the authority id of the equivocator.
330	pub fn offender(&self) -> &AuthorityId {
331		match self {
332			Equivocation::Prevote(ref equivocation) => &equivocation.identity,
333			Equivocation::Precommit(ref equivocation) => &equivocation.identity,
334		}
335	}
336
337	/// Returns the round number when the equivocation happened.
338	pub fn round_number(&self) -> RoundNumber {
339		match self {
340			Equivocation::Prevote(ref equivocation) => equivocation.round_number,
341			Equivocation::Precommit(ref equivocation) => equivocation.round_number,
342		}
343	}
344}
345
346/// Verifies the equivocation proof by making sure that both votes target
347/// different blocks and that its signatures are valid.
348pub fn check_equivocation_proof<H, N>(report: EquivocationProof<H, N>) -> bool
349where
350	H: Clone + Encode + PartialEq,
351	N: Clone + Encode + PartialEq,
352{
353	// NOTE: the bare `Prevote` and `Precommit` types don't share any trait,
354	// this is implemented as a macro to avoid duplication.
355	macro_rules! check {
356		( $equivocation:expr, $message:expr ) => {
357			// if both votes have the same target the equivocation is invalid.
358			if $equivocation.first.0.target_hash == $equivocation.second.0.target_hash &&
359				$equivocation.first.0.target_number == $equivocation.second.0.target_number
360			{
361				return false
362			}
363
364			// check signatures on both votes are valid
365			let valid_first = check_message_signature(
366				&$message($equivocation.first.0),
367				&$equivocation.identity,
368				&$equivocation.first.1,
369				$equivocation.round_number,
370				report.set_id,
371			)
372			.is_valid();
373
374			let valid_second = check_message_signature(
375				&$message($equivocation.second.0),
376				&$equivocation.identity,
377				&$equivocation.second.1,
378				$equivocation.round_number,
379				report.set_id,
380			)
381			.is_valid();
382
383			return valid_first && valid_second
384		};
385	}
386
387	match report.equivocation {
388		Equivocation::Prevote(equivocation) => {
389			check!(equivocation, finality_grandpa::Message::Prevote);
390		},
391		Equivocation::Precommit(equivocation) => {
392			check!(equivocation, finality_grandpa::Message::Precommit);
393		},
394	}
395}
396
397/// Encode round message localized to a given round and set id.
398pub fn localized_payload<E: Encode>(round: RoundNumber, set_id: SetId, message: &E) -> Vec<u8> {
399	let mut buf = Vec::new();
400	localized_payload_with_buffer(round, set_id, message, &mut buf);
401	buf
402}
403
404/// Encode round message localized to a given round and set id using the given
405/// buffer. The given buffer will be cleared and the resulting encoded payload
406/// will always be written to the start of the buffer.
407pub fn localized_payload_with_buffer<E: Encode>(
408	round: RoundNumber,
409	set_id: SetId,
410	message: &E,
411	buf: &mut Vec<u8>,
412) {
413	buf.clear();
414	(message, round, set_id).encode_to(buf)
415}
416
417/// Result of checking a message signature.
418#[derive(Clone, Encode, Decode, PartialEq, Eq)]
419#[cfg_attr(feature = "std", derive(Debug))]
420pub enum SignatureResult {
421	/// Valid signature.
422	Valid,
423
424	/// Invalid signature.
425	Invalid,
426
427	/// Valid signature, but the message was signed in the previous set.
428	OutdatedSet,
429}
430
431impl SignatureResult {
432	/// Returns `true` if the signature is valid.
433	pub fn is_valid(&self) -> bool {
434		matches!(self, SignatureResult::Valid)
435	}
436}
437
438/// Check a message signature by encoding the message as a localized payload and
439/// verifying the provided signature using the expected authority id.
440pub fn check_message_signature<H, N>(
441	message: &finality_grandpa::Message<H, N>,
442	id: &AuthorityId,
443	signature: &AuthoritySignature,
444	round: RoundNumber,
445	set_id: SetId,
446) -> SignatureResult
447where
448	H: Encode,
449	N: Encode,
450{
451	check_message_signature_with_buffer(message, id, signature, round, set_id, &mut Vec::new())
452}
453
454/// Check a message signature by encoding the message as a localized payload and
455/// verifying the provided signature using the expected authority id.
456/// The encoding necessary to verify the signature will be done using the given
457/// buffer, the original content of the buffer will be cleared.
458pub fn check_message_signature_with_buffer<H, N>(
459	message: &finality_grandpa::Message<H, N>,
460	id: &AuthorityId,
461	signature: &AuthoritySignature,
462	round: RoundNumber,
463	set_id: SetId,
464	buf: &mut Vec<u8>,
465) -> SignatureResult
466where
467	H: Encode,
468	N: Encode,
469{
470	use sp_application_crypto::RuntimeAppPublic;
471
472	localized_payload_with_buffer(round, set_id, message, buf);
473
474	if id.verify(&buf, signature) {
475		return SignatureResult::Valid;
476	}
477
478	let log_target = if cfg!(feature = "std") { CLIENT_LOG_TARGET } else { RUNTIME_LOG_TARGET };
479	log::debug!(
480		target: log_target,
481		"Bad signature on message from id={id:?} round={round:?} set_id={set_id:?}",
482	);
483
484	// Check if the signature is valid in the previous set.
485	if set_id == 0 {
486		return SignatureResult::Invalid;
487	}
488
489	let prev_set_id = set_id - 1;
490	localized_payload_with_buffer(round, prev_set_id, message, buf);
491	let valid = id.verify(&buf, signature);
492	log::debug!(
493		target: log_target,
494		"Previous set signature check for id={id:?} round={round:?} previous_set={prev_set_id:?} valid={valid:?}"
495	);
496
497	if valid {
498		SignatureResult::OutdatedSet
499	} else {
500		SignatureResult::Invalid
501	}
502}
503
504/// Localizes the message to the given set and round and signs the payload.
505#[cfg(feature = "std")]
506pub fn sign_message<H, N>(
507	keystore: KeystorePtr,
508	message: finality_grandpa::Message<H, N>,
509	public: AuthorityId,
510	round: RoundNumber,
511	set_id: SetId,
512) -> Option<finality_grandpa::SignedMessage<H, N, AuthoritySignature, AuthorityId>>
513where
514	H: Encode,
515	N: Encode,
516{
517	use sp_application_crypto::AppCrypto;
518
519	let encoded = localized_payload(round, set_id, &message);
520	let signature = keystore
521		.ed25519_sign(AuthorityId::ID, public.as_ref(), &encoded[..])
522		.ok()
523		.flatten()?
524		.try_into()
525		.ok()?;
526
527	Some(finality_grandpa::SignedMessage { message, signature, id: public })
528}
529
530/// An opaque type used to represent the key ownership proof at the runtime API
531/// boundary. The inner value is an encoded representation of the actual key
532/// ownership proof which will be parameterized when defining the runtime. At
533/// the runtime API boundary this type is unknown and as such we keep this
534/// opaque representation, implementors of the runtime API will have to make
535/// sure that all usages of `OpaqueKeyOwnershipProof` refer to the same type.
536pub type OpaqueKeyOwnershipProof = OpaqueValue;
537
538sp_api::decl_runtime_apis! {
539	/// APIs for integrating the GRANDPA finality gadget into runtimes.
540	/// This should be implemented on the runtime side.
541	///
542	/// This is primarily used for negotiating authority-set changes for the
543	/// gadget. GRANDPA uses a signaling model of changing authority sets:
544	/// changes should be signaled with a delay of N blocks, and then automatically
545	/// applied in the runtime after those N blocks have passed.
546	///
547	/// The consensus protocol will coordinate the handoff externally.
548	#[api_version(3)]
549	pub trait GrandpaApi {
550		/// Get the current GRANDPA authorities and weights. This should not change except
551		/// for when changes are scheduled and the corresponding delay has passed.
552		///
553		/// When called at block B, it will return the set of authorities that should be
554		/// used to finalize descendants of this block (B+1, B+2, ...). The block B itself
555		/// is finalized by the authorities from block B-1.
556		fn grandpa_authorities() -> AuthorityList;
557
558		/// Submits an unsigned extrinsic to report an equivocation. The caller
559		/// must provide the equivocation proof and a key ownership proof
560		/// (should be obtained using `generate_key_ownership_proof`). The
561		/// extrinsic will be unsigned and should only be accepted for local
562		/// authorship (not to be broadcast to the network). This method returns
563		/// `None` when creation of the extrinsic fails, e.g. if equivocation
564		/// reporting is disabled for the given runtime (i.e. this method is
565		/// hardcoded to return `None`). Only useful in an offchain context.
566		fn submit_report_equivocation_unsigned_extrinsic(
567			equivocation_proof: EquivocationProof<Block::Hash, NumberFor<Block>>,
568			key_owner_proof: OpaqueKeyOwnershipProof,
569		) -> Option<()>;
570
571		/// Generates a proof of key ownership for the given authority in the
572		/// given set. An example usage of this module is coupled with the
573		/// session historical module to prove that a given authority key is
574		/// tied to a given staking identity during a specific session. Proofs
575		/// of key ownership are necessary for submitting equivocation reports.
576		/// NOTE: even though the API takes a `set_id` as parameter the current
577		/// implementations ignore this parameter and instead rely on this
578		/// method being called at the correct block height, i.e. any point at
579		/// which the given set id is live on-chain. Future implementations will
580		/// instead use indexed data through an offchain worker, not requiring
581		/// older states to be available.
582		fn generate_key_ownership_proof(
583			set_id: SetId,
584			authority_id: AuthorityId,
585		) -> Option<OpaqueKeyOwnershipProof>;
586
587		/// Get current GRANDPA authority set id.
588		fn current_set_id() -> SetId;
589	}
590}