sp_consensus_babe/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 BABE.
19#![deny(warnings)]
20#![forbid(unsafe_code, missing_docs, unused_variables, unused_imports)]
21#![cfg_attr(not(feature = "std"), no_std)]
22
23extern crate alloc;
24
25pub mod digests;
26pub mod inherents;
27
28#[cfg(not(feature = "std"))]
29use alloc::vec::Vec;
30use codec::{Decode, DecodeWithMemTracking, Encode, MaxEncodedLen};
31use scale_info::TypeInfo;
32#[cfg(feature = "serde")]
33use serde::{Deserialize, Serialize};
34use sp_runtime::{traits::Header, ConsensusEngineId, RuntimeDebug};
35
36use crate::digests::{NextConfigDescriptor, NextEpochDescriptor};
37
38pub use sp_core::sr25519::vrf::{
39 VrfInput, VrfPreOutput, VrfProof, VrfSignData, VrfSignature, VrfTranscript,
40};
41
42/// Key type for BABE module.
43pub const KEY_TYPE: sp_core::crypto::KeyTypeId = sp_application_crypto::key_types::BABE;
44
45mod app {
46 use sp_application_crypto::{app_crypto, key_types::BABE, sr25519};
47 app_crypto!(sr25519, BABE);
48}
49
50/// VRF context used for per-slot randomness generation.
51pub const RANDOMNESS_VRF_CONTEXT: &[u8] = b"BabeVRFInOutContext";
52
53/// VRF output length for per-slot randomness.
54pub const RANDOMNESS_LENGTH: usize = 32;
55
56/// Randomness type required by BABE operations.
57pub type Randomness = [u8; RANDOMNESS_LENGTH];
58
59/// A Babe authority keypair. Necessarily equivalent to the schnorrkel public key used in
60/// the main Babe module. If that ever changes, then this must, too.
61#[cfg(feature = "std")]
62pub type AuthorityPair = app::Pair;
63
64/// A Babe authority signature.
65pub type AuthoritySignature = app::Signature;
66
67/// A Babe authority identifier. Necessarily equivalent to the schnorrkel public key used in
68/// the main Babe module. If that ever changes, then this must, too.
69pub type AuthorityId = app::Public;
70
71/// The `ConsensusEngineId` of BABE.
72pub const BABE_ENGINE_ID: ConsensusEngineId = *b"BABE";
73
74/// The length of the public key
75pub const PUBLIC_KEY_LENGTH: usize = 32;
76
77/// How many blocks to wait before running the median algorithm for relative time
78/// This will not vary from chain to chain as it is not dependent on slot duration
79/// or epoch length.
80pub const MEDIAN_ALGORITHM_CARDINALITY: usize = 1200; // arbitrary suggestion by w3f-research.
81
82/// The index of an authority.
83pub type AuthorityIndex = u32;
84
85pub use sp_consensus_slots::{Slot, SlotDuration};
86
87/// An equivocation proof for multiple block authorships on the same slot (i.e. double vote).
88pub type EquivocationProof<H> = sp_consensus_slots::EquivocationProof<H, AuthorityId>;
89
90/// The weight of an authority.
91// NOTE: we use a unique name for the weight to avoid conflicts with other
92// `Weight` types, since the metadata isn't able to disambiguate.
93pub type BabeAuthorityWeight = u64;
94
95/// The cumulative weight of a BABE block, i.e. sum of block weights starting
96/// at this block until the genesis block.
97///
98/// Primary blocks have a weight of 1 whereas secondary blocks have a weight
99/// of 0 (regardless of whether they are plain or vrf secondary blocks).
100pub type BabeBlockWeight = u32;
101
102/// Make VRF input suitable for BABE's randomness generation.
103pub fn make_vrf_transcript(randomness: &Randomness, slot: Slot, epoch: u64) -> VrfInput {
104 VrfInput::new(
105 &BABE_ENGINE_ID,
106 &[
107 (b"slot number", &slot.to_le_bytes()),
108 (b"current epoch", &epoch.to_le_bytes()),
109 (b"chain randomness", randomness),
110 ],
111 )
112}
113
114/// Make VRF signing data suitable for BABE's protocol.
115pub fn make_vrf_sign_data(randomness: &Randomness, slot: Slot, epoch: u64) -> VrfSignData {
116 make_vrf_transcript(randomness, slot, epoch).into()
117}
118
119/// An consensus log item for BABE.
120#[derive(Decode, Encode, Clone, PartialEq, Eq)]
121pub enum ConsensusLog {
122 /// The epoch has changed. This provides information about the _next_
123 /// epoch - information about the _current_ epoch (i.e. the one we've just
124 /// entered) should already be available earlier in the chain.
125 #[codec(index = 1)]
126 NextEpochData(NextEpochDescriptor),
127 /// Disable the authority with given index.
128 #[codec(index = 2)]
129 OnDisabled(AuthorityIndex),
130 /// The epoch has changed, and the epoch after the current one will
131 /// enact different epoch configurations.
132 #[codec(index = 3)]
133 NextConfigData(NextConfigDescriptor),
134}
135
136/// Configuration data used by the BABE consensus engine.
137#[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug, TypeInfo)]
138pub struct BabeConfigurationV1 {
139 /// The slot duration in milliseconds for BABE. Currently, only
140 /// the value provided by this type at genesis will be used.
141 ///
142 /// Dynamic slot duration may be supported in the future.
143 pub slot_duration: u64,
144
145 /// The duration of epochs in slots.
146 pub epoch_length: u64,
147
148 /// A constant value that is used in the threshold calculation formula.
149 /// Expressed as a rational where the first member of the tuple is the
150 /// numerator and the second is the denominator. The rational should
151 /// represent a value between 0 and 1.
152 /// In the threshold formula calculation, `1 - c` represents the probability
153 /// of a slot being empty.
154 pub c: (u64, u64),
155
156 /// The authorities for the genesis epoch.
157 pub authorities: Vec<(AuthorityId, BabeAuthorityWeight)>,
158
159 /// The randomness for the genesis epoch.
160 pub randomness: Randomness,
161
162 /// Whether this chain should run with secondary slots, which are assigned
163 /// in round-robin manner.
164 pub secondary_slots: bool,
165}
166
167impl From<BabeConfigurationV1> for BabeConfiguration {
168 fn from(v1: BabeConfigurationV1) -> Self {
169 Self {
170 slot_duration: v1.slot_duration,
171 epoch_length: v1.epoch_length,
172 c: v1.c,
173 authorities: v1.authorities,
174 randomness: v1.randomness,
175 allowed_slots: if v1.secondary_slots {
176 AllowedSlots::PrimaryAndSecondaryPlainSlots
177 } else {
178 AllowedSlots::PrimarySlots
179 },
180 }
181 }
182}
183
184/// Configuration data used by the BABE consensus engine.
185#[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug, TypeInfo)]
186pub struct BabeConfiguration {
187 /// The slot duration in milliseconds for BABE. Currently, only
188 /// the value provided by this type at genesis will be used.
189 ///
190 /// Dynamic slot duration may be supported in the future.
191 pub slot_duration: u64,
192
193 /// The duration of epochs in slots.
194 pub epoch_length: u64,
195
196 /// A constant value that is used in the threshold calculation formula.
197 /// Expressed as a rational where the first member of the tuple is the
198 /// numerator and the second is the denominator. The rational should
199 /// represent a value between 0 and 1.
200 /// In the threshold formula calculation, `1 - c` represents the probability
201 /// of a slot being empty.
202 pub c: (u64, u64),
203
204 /// The authorities
205 pub authorities: Vec<(AuthorityId, BabeAuthorityWeight)>,
206
207 /// The randomness
208 pub randomness: Randomness,
209
210 /// Type of allowed slots.
211 pub allowed_slots: AllowedSlots,
212}
213
214impl BabeConfiguration {
215 /// Convenience method to get the slot duration as a `SlotDuration` value.
216 pub fn slot_duration(&self) -> SlotDuration {
217 SlotDuration::from_millis(self.slot_duration)
218 }
219}
220
221/// Types of allowed slots.
222#[derive(
223 Clone,
224 Copy,
225 PartialEq,
226 Eq,
227 Encode,
228 Decode,
229 DecodeWithMemTracking,
230 RuntimeDebug,
231 MaxEncodedLen,
232 TypeInfo,
233)]
234#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
235pub enum AllowedSlots {
236 /// Only allow primary slots.
237 PrimarySlots,
238 /// Allow primary and secondary plain slots.
239 PrimaryAndSecondaryPlainSlots,
240 /// Allow primary and secondary VRF slots.
241 PrimaryAndSecondaryVRFSlots,
242}
243
244impl AllowedSlots {
245 /// Whether plain secondary slots are allowed.
246 pub fn is_secondary_plain_slots_allowed(&self) -> bool {
247 *self == Self::PrimaryAndSecondaryPlainSlots
248 }
249
250 /// Whether VRF secondary slots are allowed.
251 pub fn is_secondary_vrf_slots_allowed(&self) -> bool {
252 *self == Self::PrimaryAndSecondaryVRFSlots
253 }
254}
255
256/// Configuration data used by the BABE consensus engine that may change with epochs.
257#[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug, MaxEncodedLen, TypeInfo)]
258#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
259pub struct BabeEpochConfiguration {
260 /// A constant value that is used in the threshold calculation formula.
261 /// Expressed as a rational where the first member of the tuple is the
262 /// numerator and the second is the denominator. The rational should
263 /// represent a value between 0 and 1.
264 /// In the threshold formula calculation, `1 - c` represents the probability
265 /// of a slot being empty.
266 pub c: (u64, u64),
267
268 /// Whether this chain should run with secondary slots, which are assigned
269 /// in round-robin manner.
270 pub allowed_slots: AllowedSlots,
271}
272
273impl Default for BabeEpochConfiguration {
274 fn default() -> Self {
275 Self { c: (1, 4), allowed_slots: AllowedSlots::PrimaryAndSecondaryVRFSlots }
276 }
277}
278
279/// Verifies the equivocation proof by making sure that: both headers have
280/// different hashes, are targeting the same slot, and have valid signatures by
281/// the same authority.
282pub fn check_equivocation_proof<H>(proof: EquivocationProof<H>) -> bool
283where
284 H: Header,
285{
286 use digests::*;
287 use sp_application_crypto::RuntimeAppPublic;
288
289 let find_pre_digest =
290 |header: &H| header.digest().logs().iter().find_map(|log| log.as_babe_pre_digest());
291
292 let verify_seal_signature = |mut header: H, offender: &AuthorityId| {
293 let seal = header.digest_mut().pop()?.as_babe_seal()?;
294 let pre_hash = header.hash();
295
296 if !offender.verify(&pre_hash.as_ref(), &seal) {
297 return None
298 }
299
300 Some(())
301 };
302
303 let verify_proof = || {
304 // we must have different headers for the equivocation to be valid
305 if proof.first_header.hash() == proof.second_header.hash() {
306 return None
307 }
308
309 let first_pre_digest = find_pre_digest(&proof.first_header)?;
310 let second_pre_digest = find_pre_digest(&proof.second_header)?;
311
312 // both headers must be targeting the same slot and it must
313 // be the same as the one in the proof.
314 if proof.slot != first_pre_digest.slot() ||
315 first_pre_digest.slot() != second_pre_digest.slot()
316 {
317 return None
318 }
319
320 // both headers must have been authored by the same authority
321 if first_pre_digest.authority_index() != second_pre_digest.authority_index() {
322 return None
323 }
324
325 // we finally verify that the expected authority has signed both headers and
326 // that the signature is valid.
327 verify_seal_signature(proof.first_header, &proof.offender)?;
328 verify_seal_signature(proof.second_header, &proof.offender)?;
329
330 Some(())
331 };
332
333 // NOTE: we isolate the verification code into an helper function that
334 // returns `Option<()>` so that we can use `?` to deal with any intermediate
335 // errors and discard the proof as invalid.
336 verify_proof().is_some()
337}
338
339/// An opaque type used to represent the key ownership proof at the runtime API
340/// boundary. The inner value is an encoded representation of the actual key
341/// ownership proof which will be parameterized when defining the runtime. At
342/// the runtime API boundary this type is unknown and as such we keep this
343/// opaque representation, implementors of the runtime API will have to make
344/// sure that all usages of `OpaqueKeyOwnershipProof` refer to the same type.
345#[derive(Decode, Encode, PartialEq, TypeInfo)]
346pub struct OpaqueKeyOwnershipProof(Vec<u8>);
347impl OpaqueKeyOwnershipProof {
348 /// Create a new `OpaqueKeyOwnershipProof` using the given encoded
349 /// representation.
350 pub fn new(inner: Vec<u8>) -> OpaqueKeyOwnershipProof {
351 OpaqueKeyOwnershipProof(inner)
352 }
353
354 /// Try to decode this `OpaqueKeyOwnershipProof` into the given concrete key
355 /// ownership proof type.
356 pub fn decode<T: Decode>(self) -> Option<T> {
357 Decode::decode(&mut &self.0[..]).ok()
358 }
359}
360
361/// BABE epoch information
362#[derive(Decode, Encode, PartialEq, Eq, Clone, Debug, TypeInfo)]
363pub struct Epoch {
364 /// The epoch index.
365 pub epoch_index: u64,
366 /// The starting slot of the epoch.
367 pub start_slot: Slot,
368 /// The duration of this epoch.
369 pub duration: u64,
370 /// The authorities and their weights.
371 pub authorities: Vec<(AuthorityId, BabeAuthorityWeight)>,
372 /// Randomness for this epoch.
373 pub randomness: Randomness,
374 /// Configuration of the epoch.
375 pub config: BabeEpochConfiguration,
376}
377
378/// Returns the epoch index the given slot belongs to.
379pub fn epoch_index(slot: Slot, genesis_slot: Slot, epoch_duration: u64) -> u64 {
380 *slot.saturating_sub(genesis_slot) / epoch_duration
381}
382
383/// Returns the first slot at the given epoch index.
384pub fn epoch_start_slot(epoch_index: u64, genesis_slot: Slot, epoch_duration: u64) -> Slot {
385 // (epoch_index * epoch_duration) + genesis_slot
386
387 const PROOF: &str = "slot number is u64; it should relate in some way to wall clock time; \
388 if u64 is not enough we should crash for safety; qed.";
389
390 epoch_index
391 .checked_mul(epoch_duration)
392 .and_then(|slot| slot.checked_add(*genesis_slot))
393 .expect(PROOF)
394 .into()
395}
396
397sp_api::decl_runtime_apis! {
398 /// API necessary for block authorship with BABE.
399 #[api_version(2)]
400 pub trait BabeApi {
401 /// Return the configuration for BABE.
402 fn configuration() -> BabeConfiguration;
403
404 /// Return the configuration for BABE. Version 1.
405 #[changed_in(2)]
406 fn configuration() -> BabeConfigurationV1;
407
408 /// Returns the slot that started the current epoch.
409 fn current_epoch_start() -> Slot;
410
411 /// Returns information regarding the current epoch.
412 fn current_epoch() -> Epoch;
413
414 /// Returns information regarding the next epoch (which was already
415 /// previously announced).
416 fn next_epoch() -> Epoch;
417
418 /// Generates a proof of key ownership for the given authority in the
419 /// current epoch. An example usage of this module is coupled with the
420 /// session historical module to prove that a given authority key is
421 /// tied to a given staking identity during a specific session. Proofs
422 /// of key ownership are necessary for submitting equivocation reports.
423 /// NOTE: even though the API takes a `slot` as parameter the current
424 /// implementations ignores this parameter and instead relies on this
425 /// method being called at the correct block height, i.e. any point at
426 /// which the epoch for the given slot is live on-chain. Future
427 /// implementations will instead use indexed data through an offchain
428 /// worker, not requiring older states to be available.
429 fn generate_key_ownership_proof(
430 slot: Slot,
431 authority_id: AuthorityId,
432 ) -> Option<OpaqueKeyOwnershipProof>;
433
434 /// Submits an unsigned extrinsic to report an equivocation. The caller
435 /// must provide the equivocation proof and a key ownership proof
436 /// (should be obtained using `generate_key_ownership_proof`). The
437 /// extrinsic will be unsigned and should only be accepted for local
438 /// authorship (not to be broadcast to the network). This method returns
439 /// `None` when creation of the extrinsic fails, e.g. if equivocation
440 /// reporting is disabled for the given runtime (i.e. this method is
441 /// hardcoded to return `None`). Only useful in an offchain context.
442 fn submit_report_equivocation_unsigned_extrinsic(
443 equivocation_proof: EquivocationProof<Block::Header>,
444 key_owner_proof: OpaqueKeyOwnershipProof,
445 ) -> Option<()>;
446 }
447}