1#![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
37pub const CLIENT_LOG_TARGET: &str = "grandpa";
39pub const RUNTIME_LOG_TARGET: &str = "runtime::grandpa";
41
42pub 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 pub type AuthorityPair = app::Pair;
53}
54
55pub type AuthorityId = app::Public;
57
58pub type AuthoritySignature = app::Signature;
60
61pub const GRANDPA_ENGINE_ID: ConsensusEngineId = *b"FRNK";
63
64pub type AuthorityWeight = u64;
66
67pub type AuthorityIndex = u64;
69
70pub type SetId = u64;
72
73pub type RoundNumber = u64;
75
76pub type AuthorityList = Vec<(AuthorityId, AuthorityWeight)>;
78
79pub type Message<Header> =
81 finality_grandpa::Message<<Header as HeaderT>::Hash, <Header as HeaderT>::Number>;
82
83pub type SignedMessage<Header> = finality_grandpa::SignedMessage<
85 <Header as HeaderT>::Hash,
86 <Header as HeaderT>::Number,
87 AuthoritySignature,
88 AuthorityId,
89>;
90
91pub type PrimaryPropose<Header> =
93 finality_grandpa::PrimaryPropose<<Header as HeaderT>::Hash, <Header as HeaderT>::Number>;
94pub type Prevote<Header> =
96 finality_grandpa::Prevote<<Header as HeaderT>::Hash, <Header as HeaderT>::Number>;
97pub type Precommit<Header> =
99 finality_grandpa::Precommit<<Header as HeaderT>::Hash, <Header as HeaderT>::Number>;
100pub type CatchUp<Header> = finality_grandpa::CatchUp<
102 <Header as HeaderT>::Hash,
103 <Header as HeaderT>::Number,
104 AuthoritySignature,
105 AuthorityId,
106>;
107pub type Commit<Header> = finality_grandpa::Commit<
109 <Header as HeaderT>::Hash,
110 <Header as HeaderT>::Number,
111 AuthoritySignature,
112 AuthorityId,
113>;
114
115pub type CompactCommit<Header> = finality_grandpa::CompactCommit<
117 <Header as HeaderT>::Hash,
118 <Header as HeaderT>::Number,
119 AuthoritySignature,
120 AuthorityId,
121>;
122
123#[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#[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo)]
141#[cfg_attr(feature = "serde", derive(Serialize))]
142pub struct ScheduledChange<N> {
143 pub next_authorities: AuthorityList,
145 pub delay: N,
147}
148
149#[derive(Decode, Encode, PartialEq, Eq, Clone, RuntimeDebug)]
151#[cfg_attr(feature = "serde", derive(Serialize))]
152pub enum ConsensusLog<N: Codec> {
153 #[codec(index = 1)]
166 ScheduledChange(ScheduledChange<N>),
167 #[codec(index = 2)]
182 ForcedChange(N, ScheduledChange<N>),
183 #[codec(index = 3)]
185 OnDisabled(AuthorityIndex),
186 #[codec(index = 4)]
189 Pause(N),
190 #[codec(index = 5)]
193 Resume(N),
194}
195
196impl<N: Codec> ConsensusLog<N> {
197 pub fn try_into_change(self) -> Option<ScheduledChange<N>> {
199 match self {
200 ConsensusLog::ScheduledChange(change) => Some(change),
201 _ => None,
202 }
203 }
204
205 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 pub fn try_into_pause(self) -> Option<N> {
215 match self {
216 ConsensusLog::Pause(delay) => Some(delay),
217 _ => None,
218 }
219 }
220
221 pub fn try_into_resume(self) -> Option<N> {
223 match self {
224 ConsensusLog::Resume(delay) => Some(delay),
225 _ => None,
226 }
227 }
228}
229
230#[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 pub fn new(set_id: SetId, equivocation: Equivocation<H, N>) -> Self {
244 EquivocationProof { set_id, equivocation }
245 }
246
247 pub fn set_id(&self) -> SetId {
249 self.set_id
250 }
251
252 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 pub fn offender(&self) -> &AuthorityId {
262 self.equivocation.offender()
263 }
264}
265
266#[derive(Clone, Debug, Decode, DecodeWithMemTracking, Encode, PartialEq, Eq, TypeInfo)]
269pub enum Equivocation<H, N> {
270 Prevote(
272 finality_grandpa::Equivocation<
273 AuthorityId,
274 finality_grandpa::Prevote<H, N>,
275 AuthoritySignature,
276 >,
277 ),
278 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 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 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
346pub fn check_equivocation_proof<H, N>(report: EquivocationProof<H, N>) -> bool
349where
350 H: Clone + Encode + PartialEq,
351 N: Clone + Encode + PartialEq,
352{
353 macro_rules! check {
356 ( $equivocation:expr, $message:expr ) => {
357 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 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
373 let valid_second = check_message_signature(
374 &$message($equivocation.second.0),
375 &$equivocation.identity,
376 &$equivocation.second.1,
377 $equivocation.round_number,
378 report.set_id,
379 );
380
381 return valid_first && valid_second
382 };
383 }
384
385 match report.equivocation {
386 Equivocation::Prevote(equivocation) => {
387 check!(equivocation, finality_grandpa::Message::Prevote);
388 },
389 Equivocation::Precommit(equivocation) => {
390 check!(equivocation, finality_grandpa::Message::Precommit);
391 },
392 }
393}
394
395pub fn localized_payload<E: Encode>(round: RoundNumber, set_id: SetId, message: &E) -> Vec<u8> {
397 let mut buf = Vec::new();
398 localized_payload_with_buffer(round, set_id, message, &mut buf);
399 buf
400}
401
402pub fn localized_payload_with_buffer<E: Encode>(
406 round: RoundNumber,
407 set_id: SetId,
408 message: &E,
409 buf: &mut Vec<u8>,
410) {
411 buf.clear();
412 (message, round, set_id).encode_to(buf)
413}
414
415pub fn check_message_signature<H, N>(
418 message: &finality_grandpa::Message<H, N>,
419 id: &AuthorityId,
420 signature: &AuthoritySignature,
421 round: RoundNumber,
422 set_id: SetId,
423) -> bool
424where
425 H: Encode,
426 N: Encode,
427{
428 check_message_signature_with_buffer(message, id, signature, round, set_id, &mut Vec::new())
429}
430
431pub fn check_message_signature_with_buffer<H, N>(
436 message: &finality_grandpa::Message<H, N>,
437 id: &AuthorityId,
438 signature: &AuthoritySignature,
439 round: RoundNumber,
440 set_id: SetId,
441 buf: &mut Vec<u8>,
442) -> bool
443where
444 H: Encode,
445 N: Encode,
446{
447 use sp_application_crypto::RuntimeAppPublic;
448
449 localized_payload_with_buffer(round, set_id, message, buf);
450
451 let valid = id.verify(&buf, signature);
452
453 if !valid {
454 let log_target = if cfg!(feature = "std") { CLIENT_LOG_TARGET } else { RUNTIME_LOG_TARGET };
455
456 log::debug!(target: log_target, "Bad signature on message from {:?}", id);
457 }
458
459 valid
460}
461
462#[cfg(feature = "std")]
464pub fn sign_message<H, N>(
465 keystore: KeystorePtr,
466 message: finality_grandpa::Message<H, N>,
467 public: AuthorityId,
468 round: RoundNumber,
469 set_id: SetId,
470) -> Option<finality_grandpa::SignedMessage<H, N, AuthoritySignature, AuthorityId>>
471where
472 H: Encode,
473 N: Encode,
474{
475 use sp_application_crypto::AppCrypto;
476
477 let encoded = localized_payload(round, set_id, &message);
478 let signature = keystore
479 .ed25519_sign(AuthorityId::ID, public.as_ref(), &encoded[..])
480 .ok()
481 .flatten()?
482 .try_into()
483 .ok()?;
484
485 Some(finality_grandpa::SignedMessage { message, signature, id: public })
486}
487
488pub type OpaqueKeyOwnershipProof = OpaqueValue;
495
496sp_api::decl_runtime_apis! {
497 #[api_version(3)]
507 pub trait GrandpaApi {
508 fn grandpa_authorities() -> AuthorityList;
515
516 fn submit_report_equivocation_unsigned_extrinsic(
525 equivocation_proof: EquivocationProof<Block::Hash, NumberFor<Block>>,
526 key_owner_proof: OpaqueKeyOwnershipProof,
527 ) -> Option<()>;
528
529 fn generate_key_ownership_proof(
541 set_id: SetId,
542 authority_id: AuthorityId,
543 ) -> Option<OpaqueKeyOwnershipProof>;
544
545 fn current_set_id() -> SetId;
547 }
548}