sp_consensus_sassafras/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 Sassafras consensus.
19
20#![deny(warnings)]
21#![forbid(unsafe_code, missing_docs, unused_variables, unused_imports)]
22#![cfg_attr(not(feature = "std"), no_std)]
23
24extern crate alloc;
25
26use alloc::vec::Vec;
27use codec::{Decode, DecodeWithMemTracking, Encode, MaxEncodedLen};
28use scale_info::TypeInfo;
29use sp_core::crypto::KeyTypeId;
30use sp_runtime::{ConsensusEngineId, RuntimeDebug};
31
32pub use sp_consensus_slots::{Slot, SlotDuration};
33
34#[cfg(feature = "serde")]
35use serde::{Deserialize, Serialize};
36
37pub mod digests;
38pub mod ticket;
39pub mod vrf;
40
41pub use ticket::{
42 ticket_id_threshold, EphemeralPublic, EphemeralSignature, TicketBody, TicketClaim,
43 TicketEnvelope, TicketId,
44};
45
46mod app {
47 use sp_application_crypto::{app_crypto, bandersnatch, key_types::SASSAFRAS};
48 app_crypto!(bandersnatch, SASSAFRAS);
49}
50
51/// Key type identifier.
52pub const KEY_TYPE: KeyTypeId = sp_application_crypto::key_types::SASSAFRAS;
53
54/// Consensus engine identifier.
55pub const SASSAFRAS_ENGINE_ID: ConsensusEngineId = *b"SASS";
56
57/// VRF output length for per-slot randomness.
58pub const RANDOMNESS_LENGTH: usize = 32;
59
60/// Index of an authority.
61pub type AuthorityIndex = u32;
62
63/// Sassafras authority keypair. Necessarily equivalent to the schnorrkel public key used in
64/// the main Sassafras module. If that ever changes, then this must, too.
65#[cfg(feature = "std")]
66pub type AuthorityPair = app::Pair;
67
68/// Sassafras authority signature.
69pub type AuthoritySignature = app::Signature;
70
71/// Sassafras authority identifier. Necessarily equivalent to the schnorrkel public key used in
72/// the main Sassafras module. If that ever changes, then this must, too.
73pub type AuthorityId = app::Public;
74
75/// Weight of a Sassafras block.
76/// Primary blocks have a weight of 1 whereas secondary blocks have a weight of 0.
77pub type SassafrasBlockWeight = u32;
78
79/// An equivocation proof for multiple block authorships on the same slot (i.e. double vote).
80pub type EquivocationProof<H> = sp_consensus_slots::EquivocationProof<H, AuthorityId>;
81
82/// Randomness required by some protocol's operations.
83pub type Randomness = [u8; RANDOMNESS_LENGTH];
84
85/// Protocol configuration that can be modified on epoch change.
86///
87/// Mostly tweaks to the ticketing system parameters.
88#[derive(
89 Copy,
90 Clone,
91 PartialEq,
92 Eq,
93 Encode,
94 Decode,
95 DecodeWithMemTracking,
96 RuntimeDebug,
97 MaxEncodedLen,
98 TypeInfo,
99 Default,
100)]
101#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
102pub struct EpochConfiguration {
103 /// Tickets redundancy factor.
104 ///
105 /// Expected ratio between epoch's slots and the cumulative number of tickets which can
106 /// be submitted by the set of epoch validators.
107 pub redundancy_factor: u32,
108 /// Tickets max attempts for each validator.
109 ///
110 /// Influences the anonymity of block producers. As all published tickets have a public
111 /// attempt number less than `attempts_number` if two tickets share an attempt number
112 /// then they must belong to two different validators, which reduces anonymity late as
113 /// we approach the epoch tail.
114 ///
115 /// This anonymity loss already becomes small when `attempts_number = 64` or `128`.
116 pub attempts_number: u32,
117}
118
119/// Sassafras epoch information
120#[derive(Debug, Clone, PartialEq, Eq, Encode, Decode, TypeInfo)]
121pub struct Epoch {
122 /// Epoch index.
123 pub index: u64,
124 /// Starting slot of the epoch.
125 pub start: Slot,
126 /// Number of slots in the epoch.
127 pub length: u32,
128 /// Randomness value.
129 pub randomness: Randomness,
130 /// Authorities list.
131 pub authorities: Vec<AuthorityId>,
132 /// Epoch configuration.
133 pub config: EpochConfiguration,
134}
135
136/// An opaque type used to represent the key ownership proof at the runtime API boundary.
137///
138/// The inner value is an encoded representation of the actual key ownership proof which will be
139/// parameterized when defining the runtime. At the runtime API boundary this type is unknown and
140/// as such we keep this opaque representation, implementors of the runtime API will have to make
141/// sure that all usages of `OpaqueKeyOwnershipProof` refer to the same type.
142#[derive(Decode, Encode, PartialEq, TypeInfo)]
143#[repr(transparent)]
144pub struct OpaqueKeyOwnershipProof(Vec<u8>);
145
146// Runtime API.
147sp_api::decl_runtime_apis! {
148 /// API necessary for block authorship with Sassafras.
149 pub trait SassafrasApi {
150 /// Get ring context to be used for ticket construction and verification.
151 fn ring_context() -> Option<vrf::RingContext>;
152
153 /// Submit next epoch validator tickets via an unsigned extrinsic.
154 /// This method returns `false` when creation of the extrinsics fails.
155 fn submit_tickets_unsigned_extrinsic(tickets: Vec<TicketEnvelope>) -> bool;
156
157 /// Get ticket id associated to the given slot.
158 fn slot_ticket_id(slot: Slot) -> Option<TicketId>;
159
160 /// Get ticket id and data associated to the given slot.
161 fn slot_ticket(slot: Slot) -> Option<(TicketId, TicketBody)>;
162
163 /// Current epoch information.
164 fn current_epoch() -> Epoch;
165
166 /// Next epoch information.
167 fn next_epoch() -> Epoch;
168
169 /// Generates a proof of key ownership for the given authority in the current epoch.
170 ///
171 /// An example usage of this module is coupled with the session historical module to prove
172 /// that a given authority key is tied to a given staking identity during a specific
173 /// session.
174 ///
175 /// Proofs of key ownership are necessary for submitting equivocation reports.
176 fn generate_key_ownership_proof(authority_id: AuthorityId) -> Option<OpaqueKeyOwnershipProof>;
177
178 /// Submits an unsigned extrinsic to report an equivocation.
179 ///
180 /// The caller must provide the equivocation proof and a key ownership proof (should be
181 /// obtained using `generate_key_ownership_proof`). The extrinsic will be unsigned and
182 /// should only be accepted for local authorship (not to be broadcast to the network). This
183 /// method returns `false` when creation of the extrinsic fails.
184 ///
185 /// Only useful in an offchain context.
186 fn submit_report_equivocation_unsigned_extrinsic(
187 equivocation_proof: EquivocationProof<Block::Header>,
188 key_owner_proof: OpaqueKeyOwnershipProof,
189 ) -> bool;
190 }
191}