mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-11 17:41:08 +00:00
Simplify BABE pre-digest definitions (#5289)
* Init vrf crate without type alias * Generic PreDigest definition for BABE * Fix BABE vrf interface change * Missing default-features def in sp-consensus-babe * Fix sp-consensus-babe compile * frame-babe: fix type inference * Unify type definitions of vrf output/proof and randomness * frame-babe: fix tests * Bump node impl version * Update cargo lock * Derive Copy for RawVRFOutput and RawVRFProof * Fix duplicated derive Co-authored-by: Gavin Wood <gavin@parity.io>
This commit is contained in:
Generated
+14
-1
@@ -3942,6 +3942,7 @@ dependencies = [
|
||||
"parking_lot 0.10.0",
|
||||
"serde",
|
||||
"sp-consensus-babe",
|
||||
"sp-consensus-vrf",
|
||||
"sp-core",
|
||||
"sp-inherents",
|
||||
"sp-io",
|
||||
@@ -5893,6 +5894,7 @@ dependencies = [
|
||||
"sp-blockchain",
|
||||
"sp-consensus",
|
||||
"sp-consensus-babe",
|
||||
"sp-consensus-vrf",
|
||||
"sp-core",
|
||||
"sp-inherents",
|
||||
"sp-io",
|
||||
@@ -7095,10 +7097,10 @@ name = "sp-consensus-babe"
|
||||
version = "0.8.0-alpha.4"
|
||||
dependencies = [
|
||||
"parity-scale-codec",
|
||||
"schnorrkel",
|
||||
"sp-api",
|
||||
"sp-application-crypto",
|
||||
"sp-consensus",
|
||||
"sp-consensus-vrf",
|
||||
"sp-inherents",
|
||||
"sp-runtime",
|
||||
"sp-std",
|
||||
@@ -7116,6 +7118,17 @@ dependencies = [
|
||||
"sp-std",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sp-consensus-vrf"
|
||||
version = "0.8.0-alpha.4"
|
||||
dependencies = [
|
||||
"parity-scale-codec",
|
||||
"schnorrkel",
|
||||
"sp-core",
|
||||
"sp-runtime",
|
||||
"sp-std",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sp-core"
|
||||
version = "2.0.0-alpha.4"
|
||||
|
||||
@@ -118,6 +118,7 @@ members = [
|
||||
"primitives/consensus/babe",
|
||||
"primitives/consensus/common",
|
||||
"primitives/consensus/pow",
|
||||
"primitives/consensus/vrf",
|
||||
"primitives/core",
|
||||
"primitives/debug-derive",
|
||||
"primitives/storage",
|
||||
|
||||
@@ -84,7 +84,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
|
||||
// implementation changes and behavior does not, then leave spec_version as
|
||||
// is and increment impl_version.
|
||||
spec_version: 240,
|
||||
impl_version: 0,
|
||||
impl_version: 1,
|
||||
apis: RUNTIME_API_VERSIONS,
|
||||
};
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@ homepage = "https://substrate.dev"
|
||||
repository = "https://github.com/paritytech/substrate/"
|
||||
documentation = "https://docs.rs/sc-consensus-babe"
|
||||
|
||||
|
||||
[dependencies]
|
||||
codec = { package = "parity-scale-codec", version = "1.2.0", features = ["derive"] }
|
||||
sp-consensus-babe = { version = "0.8.0-alpha.4", path = "../../../primitives/consensus/babe" }
|
||||
@@ -32,6 +31,7 @@ sp-api = { version = "2.0.0-alpha.4", path = "../../../primitives/api" }
|
||||
sp-block-builder = { version = "2.0.0-alpha.4", path = "../../../primitives/block-builder" }
|
||||
sp-blockchain = { version = "2.0.0-alpha.4", path = "../../../primitives/blockchain" }
|
||||
sp-consensus = { version = "0.8.0-alpha.4", path = "../../../primitives/consensus/common" }
|
||||
sp-consensus-vrf = { version = "0.8.0-alpha.4", path = "../../../primitives/consensus/vrf" }
|
||||
sc-consensus-uncles = { version = "0.8.0-alpha.4", path = "../uncles" }
|
||||
sc-consensus-slots = { version = "0.8.0-alpha.4", path = "../slots" }
|
||||
sp-runtime = { version = "2.0.0-alpha.4", path = "../../../primitives/runtime" }
|
||||
|
||||
@@ -22,6 +22,7 @@ use sp_consensus_babe::{
|
||||
SlotNumber, AuthorityPair, BabeConfiguration
|
||||
};
|
||||
use sp_consensus_babe::digests::PreDigest;
|
||||
use sp_consensus_vrf::schnorrkel::{VRFOutput, VRFProof};
|
||||
use sp_core::{U256, blake2_256};
|
||||
use codec::Encode;
|
||||
use schnorrkel::vrf::VRFInOut;
|
||||
@@ -201,8 +202,8 @@ fn claim_primary_slot(
|
||||
.map(|s| {
|
||||
PreDigest::Primary {
|
||||
slot_number,
|
||||
vrf_output: s.0.to_output(),
|
||||
vrf_proof: s.1,
|
||||
vrf_output: VRFOutput(s.0.to_output()),
|
||||
vrf_proof: VRFProof(s.1),
|
||||
authority_index: authority_index as u32,
|
||||
}
|
||||
});
|
||||
|
||||
@@ -15,11 +15,11 @@
|
||||
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Verification for BABE headers.
|
||||
use schnorrkel::vrf::{VRFOutput, VRFProof};
|
||||
use sp_runtime::{traits::Header, traits::DigestItemFor};
|
||||
use sp_core::{Pair, Public};
|
||||
use sp_consensus_babe::{AuthoritySignature, SlotNumber, AuthorityIndex, AuthorityPair, AuthorityId};
|
||||
use sp_consensus_babe::digests::{PreDigest, CompatibleDigestItem};
|
||||
use sp_consensus_vrf::schnorrkel::{VRFOutput, VRFProof};
|
||||
use sc_consensus_slots::CheckedHeader;
|
||||
use log::{debug, trace};
|
||||
use super::{find_pre_digest, babe_err, Epoch, BlockT, Error};
|
||||
|
||||
@@ -22,7 +22,8 @@ pallet-timestamp = { version = "2.0.0-alpha.4", default-features = false, path =
|
||||
sp-timestamp = { version = "2.0.0-alpha.4", default-features = false, path = "../../primitives/timestamp" }
|
||||
pallet-session = { version = "2.0.0-alpha.4", default-features = false, path = "../session" }
|
||||
sp-consensus-babe = { version = "0.8.0-alpha.4", default-features = false, path = "../../primitives/consensus/babe" }
|
||||
sp-io ={ path = "../../primitives/io", default-features = false , version = "2.0.0-alpha.4"}
|
||||
sp-consensus-vrf = { version = "0.8.0-alpha.4", default-features = false, path = "../../primitives/consensus/vrf" }
|
||||
sp-io = { path = "../../primitives/io", default-features = false , version = "2.0.0-alpha.4"}
|
||||
|
||||
[dev-dependencies]
|
||||
lazy_static = "1.4.0"
|
||||
@@ -45,6 +46,7 @@ std = [
|
||||
"sp-timestamp/std",
|
||||
"sp-inherents/std",
|
||||
"sp-consensus-babe/std",
|
||||
"sp-consensus-vrf/std",
|
||||
"pallet-session/std",
|
||||
"sp-io/std",
|
||||
]
|
||||
|
||||
@@ -39,7 +39,8 @@ use sp_consensus_babe::{
|
||||
inherents::{INHERENT_IDENTIFIER, BabeInherentData},
|
||||
digests::{NextEpochDescriptor, RawPreDigest},
|
||||
};
|
||||
pub use sp_consensus_babe::{AuthorityId, VRF_OUTPUT_LENGTH, PUBLIC_KEY_LENGTH};
|
||||
use sp_consensus_vrf::schnorrkel;
|
||||
pub use sp_consensus_babe::{AuthorityId, VRF_OUTPUT_LENGTH, RANDOMNESS_LENGTH, PUBLIC_KEY_LENGTH};
|
||||
|
||||
#[cfg(all(feature = "std", test))]
|
||||
mod tests;
|
||||
@@ -96,12 +97,9 @@ impl EpochChangeTrigger for SameAuthoritiesForever {
|
||||
}
|
||||
}
|
||||
|
||||
/// The length of the BABE randomness
|
||||
pub const RANDOMNESS_LENGTH: usize = 32;
|
||||
|
||||
const UNDER_CONSTRUCTION_SEGMENT_LENGTH: usize = 256;
|
||||
|
||||
type MaybeVrf = Option<[u8; 32 /* VRF_OUTPUT_LENGTH */]>;
|
||||
type MaybeVrf = Option<schnorrkel::RawVRFOutput>;
|
||||
|
||||
decl_storage! {
|
||||
trait Store for Module<T: Trait> as Babe {
|
||||
@@ -131,10 +129,10 @@ decl_storage! {
|
||||
// NOTE: the following fields don't use the constants to define the
|
||||
// array size because the metadata API currently doesn't resolve the
|
||||
// variable to its underlying value.
|
||||
pub Randomness get(fn randomness): [u8; 32 /* RANDOMNESS_LENGTH */];
|
||||
pub Randomness get(fn randomness): schnorrkel::Randomness;
|
||||
|
||||
/// Next epoch randomness.
|
||||
NextRandomness: [u8; 32 /* RANDOMNESS_LENGTH */];
|
||||
NextRandomness: schnorrkel::Randomness;
|
||||
|
||||
/// Randomness under construction.
|
||||
///
|
||||
@@ -146,7 +144,7 @@ decl_storage! {
|
||||
/// We reset all segments and return to `0` at the beginning of every
|
||||
/// epoch.
|
||||
SegmentIndex build(|_| 0): u32;
|
||||
UnderConstruction: map hasher(twox_64_concat) u32 => Vec<[u8; 32 /* VRF_OUTPUT_LENGTH */]>;
|
||||
UnderConstruction: map hasher(twox_64_concat) u32 => Vec<schnorrkel::RawVRFOutput>;
|
||||
|
||||
/// Temporary value (cleared at block finalization) which is `Some`
|
||||
/// if per-block initialization has already been called for current block.
|
||||
@@ -210,7 +208,7 @@ impl<T: Trait> FindAuthor<u32> for Module<T> {
|
||||
{
|
||||
for (id, mut data) in digests.into_iter() {
|
||||
if id == BABE_ENGINE_ID {
|
||||
let pre_digest = RawPreDigest::decode(&mut data).ok()?;
|
||||
let pre_digest: RawPreDigest = RawPreDigest::decode(&mut data).ok()?;
|
||||
return Some(match pre_digest {
|
||||
RawPreDigest::Primary { authority_index, .. } =>
|
||||
authority_index,
|
||||
@@ -373,7 +371,7 @@ impl<T: Trait> Module<T> {
|
||||
<frame_system::Module<T>>::deposit_log(log.into())
|
||||
}
|
||||
|
||||
fn deposit_vrf_output(vrf_output: &[u8; VRF_OUTPUT_LENGTH]) {
|
||||
fn deposit_vrf_output(vrf_output: &schnorrkel::RawVRFOutput) {
|
||||
let segment_idx = <SegmentIndex>::get();
|
||||
let mut segment = <UnderConstruction>::get(&segment_idx);
|
||||
if segment.len() < UNDER_CONSTRUCTION_SEGMENT_LENGTH {
|
||||
@@ -383,7 +381,7 @@ impl<T: Trait> Module<T> {
|
||||
} else {
|
||||
// move onto the next segment and update the index.
|
||||
let segment_idx = segment_idx + 1;
|
||||
<UnderConstruction>::insert(&segment_idx, &vec![*vrf_output]);
|
||||
<UnderConstruction>::insert(&segment_idx, &vec![vrf_output.clone()]);
|
||||
<SegmentIndex>::put(&segment_idx);
|
||||
}
|
||||
}
|
||||
@@ -396,7 +394,7 @@ impl<T: Trait> Module<T> {
|
||||
return;
|
||||
}
|
||||
|
||||
let maybe_pre_digest = <frame_system::Module<T>>::digest()
|
||||
let maybe_pre_digest: Option<RawPreDigest> = <frame_system::Module<T>>::digest()
|
||||
.logs
|
||||
.iter()
|
||||
.filter_map(|s| s.as_pre_runtime())
|
||||
@@ -446,7 +444,7 @@ impl<T: Trait> Module<T> {
|
||||
|
||||
/// Call this function exactly once when an epoch changes, to update the
|
||||
/// randomness. Returns the new randomness.
|
||||
fn randomness_change_epoch(next_epoch_index: u64) -> [u8; RANDOMNESS_LENGTH] {
|
||||
fn randomness_change_epoch(next_epoch_index: u64) -> schnorrkel::Randomness {
|
||||
let this_randomness = NextRandomness::get();
|
||||
let segment_idx: u32 = <SegmentIndex>::mutate(|s| sp_std::mem::replace(s, 0));
|
||||
|
||||
@@ -513,11 +511,11 @@ impl<T: Trait> pallet_session::OneSessionHandler<T::AccountId> for Module<T> {
|
||||
//
|
||||
// an optional size hint as to how many VRF outputs there were may be provided.
|
||||
fn compute_randomness(
|
||||
last_epoch_randomness: [u8; RANDOMNESS_LENGTH],
|
||||
last_epoch_randomness: schnorrkel::Randomness,
|
||||
epoch_index: u64,
|
||||
rho: impl Iterator<Item=[u8; VRF_OUTPUT_LENGTH]>,
|
||||
rho: impl Iterator<Item=schnorrkel::RawVRFOutput>,
|
||||
rho_size_hint: Option<usize>,
|
||||
) -> [u8; RANDOMNESS_LENGTH] {
|
||||
) -> schnorrkel::Randomness {
|
||||
let mut s = Vec::with_capacity(40 + rho_size_hint.unwrap_or(0) * VRF_OUTPUT_LENGTH);
|
||||
s.extend_from_slice(&last_epoch_randomness);
|
||||
s.extend_from_slice(&epoch_index.to_le_bytes());
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
use super::*;
|
||||
use mock::{new_test_ext, Babe, System};
|
||||
use sp_runtime::{traits::OnFinalize, testing::{Digest, DigestItem}};
|
||||
use sp_consensus_vrf::schnorrkel::{RawVRFOutput, RawVRFProof};
|
||||
use pallet_session::ShouldEndSession;
|
||||
|
||||
const EMPTY_RANDOMNESS: [u8; 32] = [
|
||||
@@ -31,8 +32,8 @@ const EMPTY_RANDOMNESS: [u8; 32] = [
|
||||
fn make_pre_digest(
|
||||
authority_index: sp_consensus_babe::AuthorityIndex,
|
||||
slot_number: sp_consensus_babe::SlotNumber,
|
||||
vrf_output: [u8; sp_consensus_babe::VRF_OUTPUT_LENGTH],
|
||||
vrf_proof: [u8; sp_consensus_babe::VRF_PROOF_LENGTH],
|
||||
vrf_output: RawVRFOutput,
|
||||
vrf_proof: RawVRFProof,
|
||||
) -> Digest {
|
||||
let digest_data = sp_consensus_babe::digests::RawPreDigest::Primary {
|
||||
authority_index,
|
||||
@@ -70,12 +71,12 @@ fn check_module() {
|
||||
fn first_block_epoch_zero_start() {
|
||||
new_test_ext(vec![0, 1, 2, 3]).execute_with(|| {
|
||||
let genesis_slot = 100;
|
||||
let first_vrf = [1; 32];
|
||||
let first_vrf = RawVRFOutput([1; 32]);
|
||||
let pre_digest = make_pre_digest(
|
||||
0,
|
||||
genesis_slot,
|
||||
first_vrf,
|
||||
[0xff; 64],
|
||||
first_vrf.clone(),
|
||||
RawVRFProof([0xff; 64]),
|
||||
);
|
||||
|
||||
assert_eq!(Babe::genesis_slot(), 0);
|
||||
|
||||
@@ -12,9 +12,9 @@ repository = "https://github.com/paritytech/substrate/"
|
||||
sp-application-crypto = { version = "2.0.0-alpha.4", default-features = false, path = "../../application-crypto" }
|
||||
codec = { package = "parity-scale-codec", version = "1.2.0", default-features = false }
|
||||
sp-std = { version = "2.0.0-alpha.4", default-features = false, path = "../../std" }
|
||||
schnorrkel = { version = "0.9.1", features = ["preaudit_deprecated"], optional = true }
|
||||
sp-api = { version = "2.0.0-alpha.4", default-features = false, path = "../../api" }
|
||||
sp-consensus = { version = "0.8.0-alpha.4", optional = true, path = "../common" }
|
||||
sp-consensus-vrf = { version = "0.8.0-alpha.4", path = "../vrf", default-features = false }
|
||||
sp-inherents = { version = "2.0.0-alpha.4", default-features = false, path = "../../inherents" }
|
||||
sp-runtime = { version = "2.0.0-alpha.4", default-features = false, path = "../../runtime" }
|
||||
sp-timestamp = { version = "2.0.0-alpha.4", default-features = false, path = "../../timestamp" }
|
||||
@@ -25,9 +25,9 @@ std = [
|
||||
"sp-application-crypto/std",
|
||||
"codec/std",
|
||||
"sp-std/std",
|
||||
"schnorrkel",
|
||||
"sp-api/std",
|
||||
"sp-consensus",
|
||||
"sp-consensus-vrf/std",
|
||||
"sp-inherents/std",
|
||||
"sp-runtime/std",
|
||||
"sp-timestamp/std",
|
||||
|
||||
@@ -18,92 +18,35 @@
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use super::{BABE_ENGINE_ID, AuthoritySignature};
|
||||
#[cfg(not(feature = "std"))]
|
||||
use super::{VRF_OUTPUT_LENGTH, VRF_PROOF_LENGTH};
|
||||
use super::{AuthorityId, AuthorityIndex, SlotNumber, BabeAuthorityWeight};
|
||||
#[cfg(feature = "std")]
|
||||
use sp_runtime::{DigestItem, generic::OpaqueDigestItemId};
|
||||
#[cfg(feature = "std")]
|
||||
use std::fmt::Debug;
|
||||
use std::{fmt::Debug, convert::{TryFrom, TryInto}};
|
||||
use codec::{Decode, Encode};
|
||||
#[cfg(feature = "std")]
|
||||
use codec::{Codec, Input, Error};
|
||||
#[cfg(feature = "std")]
|
||||
use schnorrkel::{
|
||||
SignatureError, errors::MultiSignatureStage,
|
||||
vrf::{VRFProof, VRFOutput, VRF_OUTPUT_LENGTH, VRF_PROOF_LENGTH}
|
||||
};
|
||||
use codec::Codec;
|
||||
use sp_std::vec::Vec;
|
||||
|
||||
use sp_consensus_vrf::schnorrkel::{self, Randomness};
|
||||
#[cfg(feature = "std")]
|
||||
use sp_consensus_vrf::schnorrkel::SignatureError;
|
||||
|
||||
/// A BABE pre-runtime digest. This contains all data required to validate a
|
||||
/// block and for the BABE runtime module. Slots can be assigned to a primary
|
||||
/// (VRF based) and to a secondary (slot number based).
|
||||
#[cfg(feature = "std")]
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum PreDigest {
|
||||
/// A primary VRF-based slot assignment.
|
||||
Primary {
|
||||
/// VRF output
|
||||
vrf_output: VRFOutput,
|
||||
/// VRF proof
|
||||
vrf_proof: VRFProof,
|
||||
/// Authority index
|
||||
authority_index: super::AuthorityIndex,
|
||||
/// Slot number
|
||||
slot_number: SlotNumber,
|
||||
},
|
||||
/// A secondary deterministic slot assignment.
|
||||
Secondary {
|
||||
/// Authority index
|
||||
authority_index: super::AuthorityIndex,
|
||||
/// Slot number
|
||||
slot_number: SlotNumber,
|
||||
},
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl PreDigest {
|
||||
/// Returns the slot number of the pre digest.
|
||||
pub fn authority_index(&self) -> AuthorityIndex {
|
||||
match self {
|
||||
PreDigest::Primary { authority_index, .. } => *authority_index,
|
||||
PreDigest::Secondary { authority_index, .. } => *authority_index,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the slot number of the pre digest.
|
||||
pub fn slot_number(&self) -> SlotNumber {
|
||||
match self {
|
||||
PreDigest::Primary { slot_number, .. } => *slot_number,
|
||||
PreDigest::Secondary { slot_number, .. } => *slot_number,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the weight _added_ by this digest, not the cumulative weight
|
||||
/// of the chain.
|
||||
pub fn added_weight(&self) -> crate::BabeBlockWeight {
|
||||
match self {
|
||||
PreDigest::Primary { .. } => 1,
|
||||
PreDigest::Secondary { .. } => 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A raw version of `BabePreDigest`, usable on `no_std`.
|
||||
#[derive(Copy, Clone, Encode, Decode)]
|
||||
pub enum RawPreDigest {
|
||||
#[derive(Clone, Debug, Encode, Decode)]
|
||||
pub enum RawPreDigest<VRFOutput=schnorrkel::RawVRFOutput, VRFProof=schnorrkel::RawVRFProof> {
|
||||
/// A primary VRF-based slot assignment.
|
||||
#[codec(index = "1")]
|
||||
Primary {
|
||||
/// Authority index
|
||||
authority_index: AuthorityIndex,
|
||||
authority_index: super::AuthorityIndex,
|
||||
/// Slot number
|
||||
slot_number: SlotNumber,
|
||||
/// VRF output
|
||||
vrf_output: [u8; VRF_OUTPUT_LENGTH],
|
||||
vrf_output: VRFOutput,
|
||||
/// VRF proof
|
||||
vrf_proof: [u8; VRF_PROOF_LENGTH],
|
||||
vrf_proof: VRFProof,
|
||||
},
|
||||
/// A secondary deterministic slot assignment.
|
||||
#[codec(index = "2")]
|
||||
@@ -114,13 +57,25 @@ pub enum RawPreDigest {
|
||||
/// are assigned based on slot number and epoch randomness. But including
|
||||
/// it makes things easier for higher-level users of the chain data to
|
||||
/// be aware of the author of a secondary-slot block.
|
||||
authority_index: AuthorityIndex,
|
||||
authority_index: super::AuthorityIndex,
|
||||
/// Slot number
|
||||
slot_number: SlotNumber,
|
||||
},
|
||||
}
|
||||
|
||||
impl RawPreDigest {
|
||||
#[cfg(feature = "std")]
|
||||
/// A BABE pre-runtime digest for std.
|
||||
pub type PreDigest = RawPreDigest<schnorrkel::VRFOutput, schnorrkel::VRFProof>;
|
||||
|
||||
impl<VRFOutput, VRFProof> RawPreDigest<VRFOutput, VRFProof> {
|
||||
/// Returns the slot number of the pre digest.
|
||||
pub fn authority_index(&self) -> AuthorityIndex {
|
||||
match self {
|
||||
RawPreDigest::Primary { authority_index, .. } => *authority_index,
|
||||
RawPreDigest::Secondary { authority_index, .. } => *authority_index,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the slot number of the pre digest.
|
||||
pub fn slot_number(&self) -> SlotNumber {
|
||||
match self {
|
||||
@@ -128,65 +83,36 @@ impl RawPreDigest {
|
||||
RawPreDigest::Secondary { slot_number, .. } => *slot_number,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl Encode for PreDigest {
|
||||
fn encode(&self) -> Vec<u8> {
|
||||
let raw = match self {
|
||||
PreDigest::Primary {
|
||||
vrf_output,
|
||||
vrf_proof,
|
||||
authority_index,
|
||||
slot_number,
|
||||
} => {
|
||||
RawPreDigest::Primary {
|
||||
vrf_output: *vrf_output.as_bytes(),
|
||||
vrf_proof: vrf_proof.to_bytes(),
|
||||
authority_index: *authority_index,
|
||||
slot_number: *slot_number,
|
||||
}
|
||||
},
|
||||
PreDigest::Secondary {
|
||||
authority_index,
|
||||
slot_number,
|
||||
} => {
|
||||
RawPreDigest::Secondary {
|
||||
authority_index: *authority_index,
|
||||
slot_number: *slot_number,
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
codec::Encode::encode(&raw)
|
||||
/// Returns the weight _added_ by this digest, not the cumulative weight
|
||||
/// of the chain.
|
||||
pub fn added_weight(&self) -> crate::BabeBlockWeight {
|
||||
match self {
|
||||
RawPreDigest::Primary { .. } => 1,
|
||||
RawPreDigest::Secondary { .. } => 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl codec::EncodeLike for PreDigest {}
|
||||
impl TryFrom<RawPreDigest> for PreDigest {
|
||||
type Error = SignatureError;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl Decode for PreDigest {
|
||||
fn decode<R: Input>(i: &mut R) -> Result<Self, Error> {
|
||||
let pre_digest = match Decode::decode(i)? {
|
||||
RawPreDigest::Primary { vrf_output, vrf_proof, authority_index, slot_number } => {
|
||||
// Verify (at compile time) that the sizes in babe_primitives are correct
|
||||
let _: [u8; super::VRF_OUTPUT_LENGTH] = vrf_output;
|
||||
let _: [u8; super::VRF_PROOF_LENGTH] = vrf_proof;
|
||||
|
||||
PreDigest::Primary {
|
||||
vrf_proof: VRFProof::from_bytes(&vrf_proof).map_err(convert_error)?,
|
||||
vrf_output: VRFOutput::from_bytes(&vrf_output).map_err(convert_error)?,
|
||||
fn try_from(raw: RawPreDigest) -> Result<PreDigest, SignatureError> {
|
||||
Ok(match raw {
|
||||
RawPreDigest::Primary { authority_index, slot_number, vrf_output, vrf_proof } =>
|
||||
RawPreDigest::Primary {
|
||||
authority_index,
|
||||
slot_number,
|
||||
vrf_output: vrf_output.try_into()?,
|
||||
vrf_proof: vrf_proof.try_into()?,
|
||||
},
|
||||
RawPreDigest::Secondary { authority_index, slot_number } =>
|
||||
RawPreDigest::Secondary {
|
||||
authority_index,
|
||||
slot_number,
|
||||
}
|
||||
},
|
||||
RawPreDigest::Secondary { authority_index, slot_number } => {
|
||||
PreDigest::Secondary { authority_index, slot_number }
|
||||
},
|
||||
};
|
||||
|
||||
Ok(pre_digest)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -198,7 +124,7 @@ pub struct NextEpochDescriptor {
|
||||
pub authorities: Vec<(AuthorityId, BabeAuthorityWeight)>,
|
||||
|
||||
/// The value of randomness to use for the slot-assignment.
|
||||
pub randomness: [u8; VRF_OUTPUT_LENGTH],
|
||||
pub randomness: Randomness,
|
||||
}
|
||||
|
||||
/// A digest item which is usable with BABE consensus.
|
||||
@@ -248,34 +174,3 @@ impl<Hash> CompatibleDigestItem for DigestItem<Hash> where
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
fn convert_error(e: SignatureError) -> codec::Error {
|
||||
use SignatureError::*;
|
||||
use MultiSignatureStage::*;
|
||||
match e {
|
||||
EquationFalse => "Signature error: `EquationFalse`".into(),
|
||||
PointDecompressionError => "Signature error: `PointDecompressionError`".into(),
|
||||
ScalarFormatError => "Signature error: `ScalarFormatError`".into(),
|
||||
NotMarkedSchnorrkel => "Signature error: `NotMarkedSchnorrkel`".into(),
|
||||
BytesLengthError { .. } => "Signature error: `BytesLengthError`".into(),
|
||||
MuSigAbsent { musig_stage: Commitment } =>
|
||||
"Signature error: `MuSigAbsent` at stage `Commitment`".into(),
|
||||
MuSigAbsent { musig_stage: Reveal } =>
|
||||
"Signature error: `MuSigAbsent` at stage `Reveal`".into(),
|
||||
MuSigAbsent { musig_stage: Cosignature } =>
|
||||
"Signature error: `MuSigAbsent` at stage `Commitment`".into(),
|
||||
MuSigInconsistent { musig_stage: Commitment, duplicate: true } =>
|
||||
"Signature error: `MuSigInconsistent` at stage `Commitment` on duplicate".into(),
|
||||
MuSigInconsistent { musig_stage: Commitment, duplicate: false } =>
|
||||
"Signature error: `MuSigInconsistent` at stage `Commitment` on not duplicate".into(),
|
||||
MuSigInconsistent { musig_stage: Reveal, duplicate: true } =>
|
||||
"Signature error: `MuSigInconsistent` at stage `Reveal` on duplicate".into(),
|
||||
MuSigInconsistent { musig_stage: Reveal, duplicate: false } =>
|
||||
"Signature error: `MuSigInconsistent` at stage `Reveal` on not duplicate".into(),
|
||||
MuSigInconsistent { musig_stage: Cosignature, duplicate: true } =>
|
||||
"Signature error: `MuSigInconsistent` at stage `Cosignature` on duplicate".into(),
|
||||
MuSigInconsistent { musig_stage: Cosignature, duplicate: false } =>
|
||||
"Signature error: `MuSigInconsistent` at stage `Cosignature` on not duplicate".into(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,10 @@
|
||||
pub mod digests;
|
||||
pub mod inherents;
|
||||
|
||||
pub use sp_consensus_vrf::schnorrkel::{
|
||||
Randomness, VRF_PROOF_LENGTH, VRF_OUTPUT_LENGTH, RANDOMNESS_LENGTH
|
||||
};
|
||||
|
||||
use codec::{Encode, Decode};
|
||||
use sp_std::vec::Vec;
|
||||
use sp_runtime::{ConsensusEngineId, RuntimeDebug};
|
||||
@@ -50,12 +54,6 @@ pub type AuthorityId = app::Public;
|
||||
/// The `ConsensusEngineId` of BABE.
|
||||
pub const BABE_ENGINE_ID: ConsensusEngineId = *b"BABE";
|
||||
|
||||
/// The length of the VRF output
|
||||
pub const VRF_OUTPUT_LENGTH: usize = 32;
|
||||
|
||||
/// The length of the VRF proof
|
||||
pub const VRF_PROOF_LENGTH: usize = 64;
|
||||
|
||||
/// The length of the public key
|
||||
pub const PUBLIC_KEY_LENGTH: usize = 32;
|
||||
|
||||
@@ -115,7 +113,7 @@ pub struct BabeConfiguration {
|
||||
pub genesis_authorities: Vec<(AuthorityId, BabeAuthorityWeight)>,
|
||||
|
||||
/// The randomness for the genesis epoch.
|
||||
pub randomness: [u8; VRF_OUTPUT_LENGTH],
|
||||
pub randomness: Randomness,
|
||||
|
||||
/// Whether this chain should run with secondary slots, which are assigned
|
||||
/// in round-robin manner.
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
[package]
|
||||
name = "sp-consensus-vrf"
|
||||
version = "0.8.0-alpha.4"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
description = "Primitives for VRF based consensus"
|
||||
edition = "2018"
|
||||
license = "GPL-3.0"
|
||||
|
||||
[dependencies]
|
||||
codec = { version = "1.0.0", package = "parity-scale-codec", default-features = false }
|
||||
schnorrkel = { version = "0.9.1", features = ["preaudit_deprecated"], optional = true }
|
||||
sp-std = { version = "2.0.0-alpha.4", path = "../../std", default-features = false }
|
||||
sp-core = { version = "2.0.0-alpha.4", path = "../../core", default-features = false }
|
||||
sp-runtime = { version = "2.0.0-alpha.4", default-features = false, path = "../../runtime" }
|
||||
|
||||
[features]
|
||||
default = ["std"]
|
||||
std = [
|
||||
"codec/std",
|
||||
"schnorrkel",
|
||||
"sp-std/std",
|
||||
"sp-core/std",
|
||||
"sp-runtime/std",
|
||||
]
|
||||
@@ -0,0 +1,20 @@
|
||||
// Copyright 2019-2020 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Substrate 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.
|
||||
|
||||
// Substrate 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 Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Primitives for VRF-based consensus engines.
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
pub mod schnorrkel;
|
||||
@@ -0,0 +1,249 @@
|
||||
// Copyright 2019-2020 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Substrate 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.
|
||||
|
||||
// Substrate 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 Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Schnorrkel-based VRF.
|
||||
|
||||
use codec::{Encode, Decode};
|
||||
use sp_core::U512;
|
||||
use sp_runtime::RuntimeDebug;
|
||||
use sp_std::ops::{Deref, DerefMut};
|
||||
#[cfg(feature = "std")]
|
||||
use std::convert::TryFrom;
|
||||
#[cfg(feature = "std")]
|
||||
use codec::EncodeLike;
|
||||
#[cfg(feature = "std")]
|
||||
use schnorrkel::errors::MultiSignatureStage;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
pub use schnorrkel::{SignatureError, vrf::{VRF_PROOF_LENGTH, VRF_OUTPUT_LENGTH}};
|
||||
|
||||
/// The length of the VRF proof.
|
||||
#[cfg(not(feature = "std"))]
|
||||
pub const VRF_PROOF_LENGTH: usize = 64;
|
||||
|
||||
/// The length of the VRF output.
|
||||
#[cfg(not(feature = "std"))]
|
||||
pub const VRF_OUTPUT_LENGTH: usize = 32;
|
||||
|
||||
/// The length of the Randomness.
|
||||
pub const RANDOMNESS_LENGTH: usize = VRF_OUTPUT_LENGTH;
|
||||
|
||||
/// Raw VRF output.
|
||||
#[derive(Clone, Copy, Eq, PartialEq, RuntimeDebug, Encode, Decode)]
|
||||
pub struct RawVRFOutput(pub [u8; VRF_OUTPUT_LENGTH]);
|
||||
|
||||
impl Deref for RawVRFOutput {
|
||||
type Target = [u8; VRF_OUTPUT_LENGTH];
|
||||
fn deref(&self) -> &Self::Target { &self.0 }
|
||||
}
|
||||
|
||||
impl DerefMut for RawVRFOutput {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 }
|
||||
}
|
||||
|
||||
/// VRF output type available for `std` environment, suitable for schnorrkel operations.
|
||||
#[cfg(feature = "std")]
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct VRFOutput(pub schnorrkel::vrf::VRFOutput);
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl Deref for VRFOutput {
|
||||
type Target = schnorrkel::vrf::VRFOutput;
|
||||
fn deref(&self) -> &Self::Target { &self.0 }
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl DerefMut for VRFOutput {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 }
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl Encode for VRFOutput {
|
||||
fn encode(&self) -> Vec<u8> {
|
||||
self.0.as_bytes().encode()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl EncodeLike for VRFOutput { }
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl Decode for VRFOutput {
|
||||
fn decode<R: codec::Input>(i: &mut R) -> Result<Self, codec::Error> {
|
||||
let decoded = <[u8; VRF_OUTPUT_LENGTH]>::decode(i)?;
|
||||
Ok(Self(schnorrkel::vrf::VRFOutput::from_bytes(&decoded).map_err(convert_error)?))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl TryFrom<[u8; VRF_OUTPUT_LENGTH]> for VRFOutput {
|
||||
type Error = SignatureError;
|
||||
|
||||
fn try_from(raw: [u8; VRF_OUTPUT_LENGTH]) -> Result<Self, Self::Error> {
|
||||
schnorrkel::vrf::VRFOutput::from_bytes(&raw).map(VRFOutput)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl TryFrom<RawVRFOutput> for VRFOutput {
|
||||
type Error = SignatureError;
|
||||
|
||||
fn try_from(raw: RawVRFOutput) -> Result<VRFOutput, Self::Error> {
|
||||
schnorrkel::vrf::VRFOutput::from_bytes(&raw.0).map(VRFOutput)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl From<VRFOutput> for RawVRFOutput {
|
||||
fn from(output: VRFOutput) -> RawVRFOutput {
|
||||
RawVRFOutput(output.to_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
/// Raw VRF proof.
|
||||
#[derive(Clone, Copy, Encode, Decode)]
|
||||
pub struct RawVRFProof(pub [u8; VRF_PROOF_LENGTH]);
|
||||
|
||||
impl Deref for RawVRFProof {
|
||||
type Target = [u8; VRF_PROOF_LENGTH];
|
||||
fn deref(&self) -> &Self::Target { &self.0 }
|
||||
}
|
||||
|
||||
impl DerefMut for RawVRFProof {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 }
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl std::fmt::Debug for RawVRFProof {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{:?}", &self)
|
||||
}
|
||||
}
|
||||
|
||||
impl core::cmp::PartialEq for RawVRFProof {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self == other
|
||||
}
|
||||
}
|
||||
|
||||
impl core::cmp::Eq for RawVRFProof { }
|
||||
|
||||
/// VRF proof type available for `std` environment, suitable for schnorrkel operations.
|
||||
#[cfg(feature = "std")]
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct VRFProof(pub schnorrkel::vrf::VRFProof);
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl PartialOrd for VRFProof {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl Ord for VRFProof {
|
||||
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
|
||||
U512::from(self.0.to_bytes()).cmp(&U512::from(other.0.to_bytes()))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl Deref for VRFProof {
|
||||
type Target = schnorrkel::vrf::VRFProof;
|
||||
fn deref(&self) -> &Self::Target { &self.0 }
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl DerefMut for VRFProof {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 }
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl Encode for VRFProof {
|
||||
fn encode(&self) -> Vec<u8> {
|
||||
self.0.to_bytes().encode()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl EncodeLike for VRFProof { }
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl Decode for VRFProof {
|
||||
fn decode<R: codec::Input>(i: &mut R) -> Result<Self, codec::Error> {
|
||||
let decoded = <[u8; VRF_PROOF_LENGTH]>::decode(i)?;
|
||||
Ok(Self(schnorrkel::vrf::VRFProof::from_bytes(&decoded).map_err(convert_error)?))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl TryFrom<[u8; VRF_PROOF_LENGTH]> for VRFProof {
|
||||
type Error = SignatureError;
|
||||
|
||||
fn try_from(raw: [u8; VRF_PROOF_LENGTH]) -> Result<Self, Self::Error> {
|
||||
schnorrkel::vrf::VRFProof::from_bytes(&raw).map(VRFProof)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl TryFrom<RawVRFProof> for VRFProof {
|
||||
type Error = SignatureError;
|
||||
|
||||
fn try_from(raw: RawVRFProof) -> Result<VRFProof, Self::Error> {
|
||||
schnorrkel::vrf::VRFProof::from_bytes(&raw.0).map(VRFProof)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl From<VRFProof> for RawVRFProof {
|
||||
fn from(output: VRFProof) -> RawVRFProof {
|
||||
RawVRFProof(output.to_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
fn convert_error(e: SignatureError) -> codec::Error {
|
||||
use SignatureError::*;
|
||||
use MultiSignatureStage::*;
|
||||
match e {
|
||||
EquationFalse => "Signature error: `EquationFalse`".into(),
|
||||
PointDecompressionError => "Signature error: `PointDecompressionError`".into(),
|
||||
ScalarFormatError => "Signature error: `ScalarFormatError`".into(),
|
||||
NotMarkedSchnorrkel => "Signature error: `NotMarkedSchnorrkel`".into(),
|
||||
BytesLengthError { .. } => "Signature error: `BytesLengthError`".into(),
|
||||
MuSigAbsent { musig_stage: Commitment } =>
|
||||
"Signature error: `MuSigAbsent` at stage `Commitment`".into(),
|
||||
MuSigAbsent { musig_stage: Reveal } =>
|
||||
"Signature error: `MuSigAbsent` at stage `Reveal`".into(),
|
||||
MuSigAbsent { musig_stage: Cosignature } =>
|
||||
"Signature error: `MuSigAbsent` at stage `Commitment`".into(),
|
||||
MuSigInconsistent { musig_stage: Commitment, duplicate: true } =>
|
||||
"Signature error: `MuSigInconsistent` at stage `Commitment` on duplicate".into(),
|
||||
MuSigInconsistent { musig_stage: Commitment, duplicate: false } =>
|
||||
"Signature error: `MuSigInconsistent` at stage `Commitment` on not duplicate".into(),
|
||||
MuSigInconsistent { musig_stage: Reveal, duplicate: true } =>
|
||||
"Signature error: `MuSigInconsistent` at stage `Reveal` on duplicate".into(),
|
||||
MuSigInconsistent { musig_stage: Reveal, duplicate: false } =>
|
||||
"Signature error: `MuSigInconsistent` at stage `Reveal` on not duplicate".into(),
|
||||
MuSigInconsistent { musig_stage: Cosignature, duplicate: true } =>
|
||||
"Signature error: `MuSigInconsistent` at stage `Cosignature` on duplicate".into(),
|
||||
MuSigInconsistent { musig_stage: Cosignature, duplicate: false } =>
|
||||
"Signature error: `MuSigInconsistent` at stage `Cosignature` on not duplicate".into(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Schnorrkel randomness value. Same size as `VRFOutput`.
|
||||
pub type Randomness = [u8; RANDOMNESS_LENGTH];
|
||||
@@ -74,7 +74,7 @@ pub mod testing;
|
||||
pub mod tasks;
|
||||
|
||||
pub use self::hash::{H160, H256, H512, convert_hash};
|
||||
pub use self::uint::U256;
|
||||
pub use self::uint::{U256, U512};
|
||||
pub use changes_trie::{ChangesTrieConfiguration, ChangesTrieConfigurationRange};
|
||||
#[cfg(feature = "full_crypto")]
|
||||
pub use crypto::{DeriveJunction, Pair, Public};
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
//! An unsigned fixed-size integer.
|
||||
|
||||
pub use primitive_types::U256;
|
||||
pub use primitive_types::{U256, U512};
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
Reference in New Issue
Block a user