diff --git a/substrate/Cargo.lock b/substrate/Cargo.lock index 5764942a0d..8e8ef29b74 100644 --- a/substrate/Cargo.lock +++ b/substrate/Cargo.lock @@ -4026,6 +4026,7 @@ dependencies = [ "pallet-timestamp", "parity-scale-codec", "serde", + "sp-application-crypto", "sp-consensus-babe", "sp-consensus-vrf", "sp-core", @@ -7404,6 +7405,7 @@ dependencies = [ name = "sp-consensus-babe" version = "0.8.0-dev" dependencies = [ + "merlin", "parity-scale-codec", "sp-api", "sp-application-crypto", diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index b821eae2df..ad22a9a52f 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -83,8 +83,8 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // and set impl_version to 0. If only runtime // implementation changes and behavior does not, then leave spec_version as // is and increment impl_version. - spec_version: 245, - impl_version: 3, + spec_version: 246, + impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 1, }; diff --git a/substrate/client/consensus/babe/src/authorship.rs b/substrate/client/consensus/babe/src/authorship.rs index 56841225ce..1810f9f5be 100644 --- a/substrate/client/consensus/babe/src/authorship.rs +++ b/substrate/client/consensus/babe/src/authorship.rs @@ -16,9 +16,8 @@ //! BABE authority selection and slot claiming. -use merlin::Transcript; use sp_consensus_babe::{ - AuthorityId, BabeAuthorityWeight, BABE_ENGINE_ID, BABE_VRF_PREFIX, + make_transcript, AuthorityId, BabeAuthorityWeight, BABE_VRF_PREFIX, SlotNumber, AuthorityPair, }; use sp_consensus_babe::digests::{ @@ -119,19 +118,6 @@ pub(super) fn secondary_slot_author( Some(&expected_author.0) } -pub(super) fn make_transcript( - randomness: &[u8], - slot_number: u64, - epoch: u64, -) -> Transcript { - let mut transcript = Transcript::new(&BABE_ENGINE_ID); - transcript.append_u64(b"slot number", slot_number); - transcript.append_u64(b"current epoch", epoch); - transcript.append_message(b"chain randomness", randomness); - transcript -} - - /// Claim a secondary slot if it is our turn to propose, returning the /// pre-digest to use when authoring the block, or `None` if it is not our turn /// to propose. diff --git a/substrate/client/consensus/babe/src/verification.rs b/substrate/client/consensus/babe/src/verification.rs index 1b89bbc643..fd3c27be4f 100644 --- a/substrate/client/consensus/babe/src/verification.rs +++ b/substrate/client/consensus/babe/src/verification.rs @@ -17,7 +17,7 @@ //! Verification for BABE headers. use sp_runtime::{traits::Header, traits::DigestItemFor}; use sp_core::{Pair, Public}; -use sp_consensus_babe::{AuthoritySignature, SlotNumber, AuthorityPair, AuthorityId}; +use sp_consensus_babe::{make_transcript, AuthoritySignature, SlotNumber, AuthorityPair, AuthorityId}; use sp_consensus_babe::digests::{ PreDigest, PrimaryPreDigest, SecondaryPlainPreDigest, SecondaryVRFPreDigest, CompatibleDigestItem @@ -25,7 +25,7 @@ use sp_consensus_babe::digests::{ use sc_consensus_slots::CheckedHeader; use log::{debug, trace}; use super::{find_pre_digest, babe_err, Epoch, BlockT, Error}; -use super::authorship::{make_transcript, calculate_primary_threshold, check_primary_threshold, secondary_slot_author}; +use super::authorship::{calculate_primary_threshold, check_primary_threshold, secondary_slot_author}; /// BABE verification parameters pub(super) struct VerificationParams<'a, B: 'a + BlockT> { diff --git a/substrate/frame/babe/Cargo.toml b/substrate/frame/babe/Cargo.toml index c94ec75b26..631b4ac4d4 100644 --- a/substrate/frame/babe/Cargo.toml +++ b/substrate/frame/babe/Cargo.toml @@ -15,6 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "1.3.0", default-features = false, features = ["derive"] } serde = { version = "1.0.101", optional = true } sp-inherents = { version = "2.0.0-dev", default-features = false, path = "../../primitives/inherents" } +sp-application-crypto = { version = "2.0.0-dev", default-features = false, path = "../../primitives/application-crypto" } sp-std = { version = "2.0.0-dev", default-features = false, path = "../../primitives/std" } sp-runtime = { version = "2.0.0-dev", default-features = false, path = "../../primitives/runtime" } sp-staking = { version = "2.0.0-dev", default-features = false, path = "../../primitives/staking" } @@ -36,6 +37,7 @@ std = [ "serde", "codec/std", "sp-std/std", + "sp-application-crypto/std", "frame-support/std", "sp-runtime/std", "sp-staking/std", diff --git a/substrate/frame/babe/src/lib.rs b/substrate/frame/babe/src/lib.rs index 7357ef75ff..d43fa00e8f 100644 --- a/substrate/frame/babe/src/lib.rs +++ b/substrate/frame/babe/src/lib.rs @@ -34,13 +34,14 @@ use sp_staking::{ SessionIndex, offence::{Offence, Kind}, }; +use sp_application_crypto::Public; use codec::{Encode, Decode}; use sp_inherents::{InherentIdentifier, InherentData, ProvideInherent, MakeFatalError}; use sp_consensus_babe::{ BABE_ENGINE_ID, ConsensusLog, BabeAuthorityWeight, SlotNumber, inherents::{INHERENT_IDENTIFIER, BabeInherentData}, - digests::{NextEpochDescriptor, RawPreDigest}, + digests::{NextEpochDescriptor, PreDigest}, }; use sp_consensus_vrf::schnorrkel; pub use sp_consensus_babe::{AuthorityId, VRF_OUTPUT_LENGTH, RANDOMNESS_LENGTH, PUBLIC_KEY_LENGTH}; @@ -102,7 +103,7 @@ impl EpochChangeTrigger for SameAuthoritiesForever { const UNDER_CONSTRUCTION_SEGMENT_LENGTH: usize = 256; -type MaybeVrf = Option; +type MaybeRandomness = Option; decl_storage! { trait Store for Module as Babe { @@ -147,11 +148,11 @@ 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; + UnderConstruction: map hasher(twox_64_concat) u32 => Vec; /// Temporary value (cleared at block finalization) which is `Some` /// if per-block initialization has already been called for current block. - Initialized get(fn initialized): Option; + Initialized get(fn initialized): Option; /// How late the current block is compared to its parent. /// @@ -194,8 +195,8 @@ decl_module! { // that this block was the first in a new epoch, the changeover logic has // already occurred at this point, so the under-construction randomness // will only contain outputs from the right epoch. - if let Some(Some(vrf_output)) = Initialized::take() { - Self::deposit_vrf_output(&vrf_output); + if let Some(Some(randomness)) = Initialized::take() { + Self::deposit_randomness(&randomness); } // remove temporary "environment" entry from storage @@ -238,7 +239,7 @@ impl FindAuthor for Module { { for (id, mut data) in digests.into_iter() { if id == BABE_ENGINE_ID { - let pre_digest: RawPreDigest = RawPreDigest::decode(&mut data).ok()?; + let pre_digest: PreDigest = PreDigest::decode(&mut data).ok()?; return Some(pre_digest.authority_index()) } } @@ -415,17 +416,17 @@ impl Module { >::deposit_log(log.into()) } - fn deposit_vrf_output(vrf_output: &schnorrkel::RawVRFOutput) { + fn deposit_randomness(randomness: &schnorrkel::Randomness) { let segment_idx = ::get(); let mut segment = ::get(&segment_idx); if segment.len() < UNDER_CONSTRUCTION_SEGMENT_LENGTH { // push onto current segment: not full. - segment.push(*vrf_output); + segment.push(*randomness); ::insert(&segment_idx, &segment); } else { // move onto the next segment and update the index. let segment_idx = segment_idx + 1; - ::insert(&segment_idx, &vec![vrf_output.clone()]); + ::insert(&segment_idx, &vec![randomness.clone()]); ::put(&segment_idx); } } @@ -438,18 +439,18 @@ impl Module { return; } - let maybe_pre_digest: Option = >::digest() + let maybe_pre_digest: Option = >::digest() .logs .iter() .filter_map(|s| s.as_pre_runtime()) .filter_map(|(id, mut data)| if id == BABE_ENGINE_ID { - RawPreDigest::decode(&mut data).ok() + PreDigest::decode(&mut data).ok() } else { None }) .next(); - let maybe_vrf = maybe_pre_digest.and_then(|digest| { + let maybe_randomness: Option = maybe_pre_digest.and_then(|digest| { // on the first non-zero block (i.e. block #1) // this is where the first epoch (epoch #0) actually starts. // we need to adjust internal storage accordingly. @@ -478,17 +479,38 @@ impl Module { Lateness::::put(lateness); CurrentSlot::put(current_slot); - if let RawPreDigest::Primary(primary) = digest { + if let PreDigest::Primary(primary) = digest { // place the VRF output into the `Initialized` storage item // and it'll be put onto the under-construction randomness // later, once we've decided which epoch this block is in. - Some(primary.vrf_output) + // + // Reconstruct the bytes of VRFInOut using the authority id. + Authorities::get() + .get(primary.authority_index as usize) + .and_then(|author| { + schnorrkel::PublicKey::from_bytes(author.0.as_slice()).ok() + }) + .and_then(|pubkey| { + let transcript = sp_consensus_babe::make_transcript( + &Self::randomness(), + current_slot, + EpochIndex::get(), + ); + + primary.vrf_output.0.attach_input_hash( + &pubkey, + transcript + ).ok() + }) + .map(|inout| { + inout.make_bytes(&sp_consensus_babe::BABE_VRF_INOUT_CONTEXT) + }) } else { None } }); - Initialized::put(maybe_vrf); + Initialized::put(maybe_randomness); // enact epoch change, if necessary. T::EpochChangeTrigger::trigger::(now) @@ -577,7 +599,7 @@ impl pallet_session::OneSessionHandler for Module { fn compute_randomness( last_epoch_randomness: schnorrkel::Randomness, epoch_index: u64, - rho: impl Iterator, + rho: impl Iterator, rho_size_hint: Option, ) -> schnorrkel::Randomness { let mut s = Vec::with_capacity(40 + rho_size_hint.unwrap_or(0) * VRF_OUTPUT_LENGTH); diff --git a/substrate/frame/babe/src/mock.rs b/substrate/frame/babe/src/mock.rs index 9f029fd27f..933c69c98a 100644 --- a/substrate/frame/babe/src/mock.rs +++ b/substrate/frame/babe/src/mock.rs @@ -30,11 +30,12 @@ use frame_support::{ weights::Weight, }; use sp_io; -use sp_core::H256; -use sp_consensus_vrf::schnorrkel::{RawVRFOutput, RawVRFProof}; +use sp_core::{H256, U256, crypto::Pair}; +use sp_consensus_babe::AuthorityPair; +use sp_consensus_vrf::schnorrkel::{VRFOutput, VRFProof}; impl_outer_origin!{ - pub enum Origin for Test where system = frame_system {} + pub enum Origin for Test where system = frame_system {} } type DummyValidatorId = u64; @@ -109,16 +110,20 @@ impl Trait for Test { type EpochChangeTrigger = crate::ExternalTrigger; } -pub fn new_test_ext(authorities: Vec) -> sp_io::TestExternalities { +pub fn new_test_ext(authorities_len: usize) -> (Vec, sp_io::TestExternalities) { + let pairs = (0..authorities_len).map(|i| { + AuthorityPair::from_seed(&U256::from(i).into()) + }).collect::>(); + let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); GenesisConfig { - authorities: authorities.into_iter().map(|a| (UintAuthorityId(a).to_public_key(), 1)).collect(), + authorities: pairs.iter().map(|a| (a.public(), 1)).collect(), }.assimilate_storage::(&mut t).unwrap(); - t.into() + (pairs, t.into()) } pub fn go_to_block(n: u64, s: u64) { - let pre_digest = make_pre_digest(0, s, RawVRFOutput([1; 32]), RawVRFProof([0xff; 64])); + let pre_digest = make_secondary_plain_pre_digest(0, s); System::initialize(&n, &Default::default(), &Default::default(), &pre_digest, InitKind::Full); System::set_block_number(n); if s > 1 { @@ -140,11 +145,11 @@ pub fn progress_to_block(n: u64) { pub fn make_pre_digest( authority_index: sp_consensus_babe::AuthorityIndex, slot_number: sp_consensus_babe::SlotNumber, - vrf_output: RawVRFOutput, - vrf_proof: RawVRFProof, + vrf_output: VRFOutput, + vrf_proof: VRFProof, ) -> Digest { - let digest_data = sp_consensus_babe::digests::RawPreDigest::Primary( - sp_consensus_babe::digests::RawPrimaryPreDigest { + let digest_data = sp_consensus_babe::digests::PreDigest::Primary( + sp_consensus_babe::digests::PrimaryPreDigest { authority_index, slot_number, vrf_output, @@ -155,6 +160,20 @@ pub fn make_pre_digest( Digest { logs: vec![log] } } +pub fn make_secondary_plain_pre_digest( + authority_index: sp_consensus_babe::AuthorityIndex, + slot_number: sp_consensus_babe::SlotNumber, +) -> Digest { + let digest_data = sp_consensus_babe::digests::PreDigest::SecondaryPlain( + sp_consensus_babe::digests::SecondaryPlainPreDigest { + authority_index, + slot_number, + } + ); + let log = DigestItem::PreRuntime(sp_consensus_babe::BABE_ENGINE_ID, digest_data.encode()); + Digest { logs: vec![log] } +} + pub type System = frame_system::Module; pub type Babe = Module; pub type Session = pallet_session::Module; diff --git a/substrate/frame/babe/src/tests.rs b/substrate/frame/babe/src/tests.rs index 24aba10017..af2ecd1e1a 100644 --- a/substrate/frame/babe/src/tests.rs +++ b/substrate/frame/babe/src/tests.rs @@ -20,7 +20,8 @@ use super::*; use mock::*; use frame_support::traits::OnFinalize; use pallet_session::ShouldEndSession; -use sp_consensus_vrf::schnorrkel::{RawVRFOutput, RawVRFProof}; +use sp_core::crypto::IsWrappedBy; +use sp_consensus_vrf::schnorrkel::{VRFOutput, VRFProof}; const EMPTY_RANDOMNESS: [u8; 32] = [ 74, 25, 49, 128, 53, 97, 244, 49, @@ -37,14 +38,14 @@ fn empty_randomness_is_correct() { #[test] fn initial_values() { - new_test_ext(vec![0, 1, 2, 3]).execute_with(|| { + new_test_ext(4).1.execute_with(|| { assert_eq!(Babe::authorities().len(), 4) }) } #[test] fn check_module() { - new_test_ext(vec![0, 1, 2, 3]).execute_with(|| { + new_test_ext(4).1.execute_with(|| { assert!(!Babe::should_end_session(0), "Genesis does not change sessions"); assert!(!Babe::should_end_session(200000), "BABE does not include the block number in epoch calculations"); @@ -53,14 +54,29 @@ fn check_module() { #[test] fn first_block_epoch_zero_start() { - new_test_ext(vec![0, 1, 2, 3]).execute_with(|| { + let (pairs, mut ext) = new_test_ext(4); + + ext.execute_with(|| { let genesis_slot = 100; - let first_vrf = RawVRFOutput([1; 32]); + + let pair = sp_core::sr25519::Pair::from_ref(&pairs[0]).as_ref(); + let transcript = sp_consensus_babe::make_transcript( + &Babe::randomness(), + genesis_slot, + 0, + ); + let vrf_inout = pair.vrf_sign(transcript); + let vrf_randomness: sp_consensus_vrf::schnorrkel::Randomness = vrf_inout.0 + .make_bytes::<[u8; 32]>(&sp_consensus_babe::BABE_VRF_INOUT_CONTEXT); + let vrf_output = VRFOutput(vrf_inout.0.to_output()); + let vrf_proof = VRFProof(vrf_inout.1); + + let first_vrf = vrf_output; let pre_digest = make_pre_digest( 0, genesis_slot, first_vrf.clone(), - RawVRFProof([0xff; 64]), + vrf_proof, ); assert_eq!(Babe::genesis_slot(), 0); @@ -83,7 +99,7 @@ fn first_block_epoch_zero_start() { let header = System::finalize(); assert_eq!(SegmentIndex::get(), 0); - assert_eq!(UnderConstruction::get(0), vec![first_vrf]); + assert_eq!(UnderConstruction::get(0), vec![vrf_randomness]); assert_eq!(Babe::randomness(), [0; 32]); assert_eq!(NextRandomness::get(), [0; 32]); @@ -91,10 +107,9 @@ fn first_block_epoch_zero_start() { assert_eq!(pre_digest.logs.len(), 1); assert_eq!(header.digest.logs[0], pre_digest.logs[0]); - let authorities = Babe::authorities(); let consensus_log = sp_consensus_babe::ConsensusLog::NextEpochData( sp_consensus_babe::digests::NextEpochDescriptor { - authorities, + authorities: Babe::authorities(), randomness: Babe::randomness(), } ); @@ -107,7 +122,7 @@ fn first_block_epoch_zero_start() { #[test] fn authority_index() { - new_test_ext(vec![0, 1, 2, 3]).execute_with(|| { + new_test_ext(4).1.execute_with(|| { assert_eq!( Babe::find_author((&[(BABE_ENGINE_ID, &[][..])]).into_iter().cloned()), None, "Trivially invalid authorities are ignored") @@ -116,7 +131,7 @@ fn authority_index() { #[test] fn can_predict_next_epoch_change() { - new_test_ext(vec![]).execute_with(|| { + new_test_ext(0).1.execute_with(|| { assert_eq!(::EpochDuration::get(), 3); // this sets the genesis slot to 6; go_to_block(1, 6); diff --git a/substrate/primitives/consensus/babe/Cargo.toml b/substrate/primitives/consensus/babe/Cargo.toml index ba7e7fffb6..ca097d6a32 100644 --- a/substrate/primitives/consensus/babe/Cargo.toml +++ b/substrate/primitives/consensus/babe/Cargo.toml @@ -14,6 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sp-application-crypto = { version = "2.0.0-dev", default-features = false, path = "../../application-crypto" } codec = { package = "parity-scale-codec", version = "1.3.0", default-features = false } +merlin = { version = "2.0", default-features = false } sp-std = { version = "2.0.0-dev", default-features = false, path = "../../std" } sp-api = { version = "2.0.0-dev", default-features = false, path = "../../api" } sp-consensus = { version = "0.8.0-dev", optional = true, path = "../common" } @@ -27,6 +28,7 @@ default = ["std"] std = [ "sp-application-crypto/std", "codec/std", + "merlin/std", "sp-std/std", "sp-api/std", "sp-consensus", diff --git a/substrate/primitives/consensus/babe/src/digests.rs b/substrate/primitives/consensus/babe/src/digests.rs index 141d6cf4bd..24be9b1b14 100644 --- a/substrate/primitives/consensus/babe/src/digests.rs +++ b/substrate/primitives/consensus/babe/src/digests.rs @@ -22,19 +22,17 @@ use super::{AuthorityId, AuthorityIndex, SlotNumber, BabeAuthorityWeight, BabeEp #[cfg(feature = "std")] use sp_runtime::{DigestItem, generic::OpaqueDigestItemId}; #[cfg(feature = "std")] -use std::{fmt::Debug, convert::{TryFrom, TryInto}}; +use std::fmt::Debug; use codec::{Decode, Encode}; #[cfg(feature = "std")] use codec::Codec; use sp_std::vec::Vec; use sp_runtime::RuntimeDebug; -use sp_consensus_vrf::schnorrkel::{self, Randomness}; -#[cfg(feature = "std")] -use sp_consensus_vrf::schnorrkel::SignatureError; +use sp_consensus_vrf::schnorrkel::{Randomness, VRFOutput, VRFProof}; /// Raw BABE primary slot assignment pre-digest. #[derive(Clone, RuntimeDebug, Encode, Decode)] -pub struct RawPrimaryPreDigest { +pub struct PrimaryPreDigest { /// Authority index pub authority_index: super::AuthorityIndex, /// Slot number @@ -45,24 +43,6 @@ pub struct RawPrimaryPreDigest; - -#[cfg(feature = "std")] -impl TryFrom for PrimaryPreDigest { - type Error = SignatureError; - - fn try_from(raw: RawPrimaryPreDigest) -> Result { - Ok(PrimaryPreDigest { - authority_index: raw.authority_index, - slot_number: raw.slot_number, - vrf_output: raw.vrf_output.try_into()?, - vrf_proof: raw.vrf_proof.try_into()?, - }) - } -} - /// BABE secondary slot assignment pre-digest. #[derive(Clone, RuntimeDebug, Encode, Decode)] pub struct SecondaryPlainPreDigest { @@ -79,7 +59,7 @@ pub struct SecondaryPlainPreDigest { /// BABE secondary deterministic slot assignment with VRF outputs. #[derive(Clone, RuntimeDebug, Encode, Decode)] -pub struct RawSecondaryVRFPreDigest { +pub struct SecondaryVRFPreDigest { /// Authority index pub authority_index: super::AuthorityIndex, /// Slot number @@ -90,60 +70,38 @@ pub struct RawSecondaryVRFPreDigest; - -#[cfg(feature = "std")] -impl TryFrom for SecondaryVRFPreDigest { - type Error = SignatureError; - - fn try_from(raw: RawSecondaryVRFPreDigest) -> Result { - Ok(SecondaryVRFPreDigest { - authority_index: raw.authority_index, - slot_number: raw.slot_number, - vrf_output: raw.vrf_output.try_into()?, - vrf_proof: raw.vrf_proof.try_into()?, - }) - } -} - /// 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). #[derive(Clone, RuntimeDebug, Encode, Decode)] -pub enum RawPreDigest { +pub enum PreDigest { /// A primary VRF-based slot assignment. #[codec(index = "1")] - Primary(RawPrimaryPreDigest), + Primary(PrimaryPreDigest), /// A secondary deterministic slot assignment. #[codec(index = "2")] SecondaryPlain(SecondaryPlainPreDigest), /// A secondary deterministic slot assignment with VRF outputs. #[codec(index = "3")] - SecondaryVRF(RawSecondaryVRFPreDigest), + SecondaryVRF(SecondaryVRFPreDigest), } -#[cfg(feature = "std")] -/// A BABE pre-runtime digest for std. -pub type PreDigest = RawPreDigest; - -impl RawPreDigest { +impl PreDigest { /// Returns the slot number of the pre digest. pub fn authority_index(&self) -> AuthorityIndex { match self { - RawPreDigest::Primary(primary) => primary.authority_index, - RawPreDigest::SecondaryPlain(secondary) => secondary.authority_index, - RawPreDigest::SecondaryVRF(secondary) => secondary.authority_index, + PreDigest::Primary(primary) => primary.authority_index, + PreDigest::SecondaryPlain(secondary) => secondary.authority_index, + PreDigest::SecondaryVRF(secondary) => secondary.authority_index, } } /// Returns the slot number of the pre digest. pub fn slot_number(&self) -> SlotNumber { match self { - RawPreDigest::Primary(primary) => primary.slot_number, - RawPreDigest::SecondaryPlain(secondary) => secondary.slot_number, - RawPreDigest::SecondaryVRF(secondary) => secondary.slot_number, + PreDigest::Primary(primary) => primary.slot_number, + PreDigest::SecondaryPlain(secondary) => secondary.slot_number, + PreDigest::SecondaryVRF(secondary) => secondary.slot_number, } } @@ -151,25 +109,12 @@ impl RawPreDigest { /// of the chain. pub fn added_weight(&self) -> crate::BabeBlockWeight { match self { - RawPreDigest::Primary(_) => 1, - RawPreDigest::SecondaryPlain(_) | RawPreDigest::SecondaryVRF(_) => 0, + PreDigest::Primary(_) => 1, + PreDigest::SecondaryPlain(_) | PreDigest::SecondaryVRF(_) => 0, } } } -#[cfg(feature = "std")] -impl TryFrom for PreDigest { - type Error = SignatureError; - - fn try_from(raw: RawPreDigest) -> Result { - Ok(match raw { - RawPreDigest::Primary(primary) => PreDigest::Primary(primary.try_into()?), - RawPreDigest::SecondaryPlain(secondary) => PreDigest::SecondaryPlain(secondary), - RawPreDigest::SecondaryVRF(secondary) => PreDigest::SecondaryVRF(secondary.try_into()?), - }) - } -} - /// Information about the next epoch. This is broadcast in the first block /// of the epoch. #[derive(Decode, Encode, PartialEq, Eq, Clone, RuntimeDebug)] diff --git a/substrate/primitives/consensus/babe/src/lib.rs b/substrate/primitives/consensus/babe/src/lib.rs index 7cf9483e6f..5f26349ef9 100644 --- a/substrate/primitives/consensus/babe/src/lib.rs +++ b/substrate/primitives/consensus/babe/src/lib.rs @@ -25,6 +25,7 @@ pub mod inherents; pub use sp_consensus_vrf::schnorrkel::{ Randomness, VRF_PROOF_LENGTH, VRF_OUTPUT_LENGTH, RANDOMNESS_LENGTH }; +pub use merlin::Transcript; use codec::{Encode, Decode}; use sp_std::vec::Vec; @@ -39,6 +40,9 @@ mod app { /// The prefix used by BABE for its VRF keys. pub const BABE_VRF_PREFIX: &[u8] = b"substrate-babe-vrf"; +/// BABE VRFInOut context. +pub static BABE_VRF_INOUT_CONTEXT: &[u8] = b"BabeVRFInOutContext"; + /// A Babe authority keypair. Necessarily equivalent to the schnorrkel public key used in /// the main Babe module. If that ever changes, then this must, too. #[cfg(feature = "std")] @@ -76,6 +80,19 @@ pub type BabeAuthorityWeight = u64; /// The weight of a BABE block. pub type BabeBlockWeight = u32; +/// Make a VRF transcript from given randomness, slot number and epoch. +pub fn make_transcript( + randomness: &Randomness, + slot_number: u64, + epoch: u64, +) -> Transcript { + let mut transcript = Transcript::new(&BABE_ENGINE_ID); + transcript.append_u64(b"slot number", slot_number); + transcript.append_u64(b"current epoch", epoch); + transcript.append_message(b"chain randomness", &randomness[..]); + transcript +} + /// An consensus log item for BABE. #[derive(Decode, Encode, Clone, PartialEq, Eq)] pub enum ConsensusLog { diff --git a/substrate/primitives/consensus/vrf/Cargo.toml b/substrate/primitives/consensus/vrf/Cargo.toml index 71b647df59..92d8a77cb4 100644 --- a/substrate/primitives/consensus/vrf/Cargo.toml +++ b/substrate/primitives/consensus/vrf/Cargo.toml @@ -13,7 +13,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { version = "1.0.0", package = "parity-scale-codec", default-features = false } -schnorrkel = { version = "0.9.1", features = ["preaudit_deprecated"], optional = true } +schnorrkel = { version = "0.9.1", features = ["preaudit_deprecated", "u64_backend"], default-features = false } sp-std = { version = "2.0.0-dev", path = "../../std", default-features = false } sp-core = { version = "2.0.0-dev", path = "../../core", default-features = false } sp-runtime = { version = "2.0.0-dev", default-features = false, path = "../../runtime" } @@ -22,7 +22,7 @@ sp-runtime = { version = "2.0.0-dev", default-features = false, path = "../../ru default = ["std"] std = [ "codec/std", - "schnorrkel", + "schnorrkel/std", "sp-std/std", "sp-core/std", "sp-runtime/std", diff --git a/substrate/primitives/consensus/vrf/src/schnorrkel.rs b/substrate/primitives/consensus/vrf/src/schnorrkel.rs index 265572dbda..c1c2a7c21a 100644 --- a/substrate/primitives/consensus/vrf/src/schnorrkel.rs +++ b/substrate/primitives/consensus/vrf/src/schnorrkel.rs @@ -16,72 +16,38 @@ //! Schnorrkel-based VRF. -use codec::{Encode, Decode}; -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")] +use codec::{Encode, Decode, EncodeLike}; +use sp_std::{convert::TryFrom, prelude::*}; use sp_core::U512; +use sp_std::ops::{Deref, DerefMut}; +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; +pub use schnorrkel::{SignatureError, PublicKey, vrf::{VRF_PROOF_LENGTH, VRF_OUTPUT_LENGTH}}; /// 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 { self.0.as_bytes().encode() } } -#[cfg(feature = "std")] impl EncodeLike for VRFOutput { } -#[cfg(feature = "std")] impl Decode for VRFOutput { fn decode(i: &mut R) -> Result { let decoded = <[u8; VRF_OUTPUT_LENGTH]>::decode(i)?; @@ -89,7 +55,6 @@ impl Decode for VRFOutput { } } -#[cfg(feature = "std")] impl TryFrom<[u8; VRF_OUTPUT_LENGTH]> for VRFOutput { type Error = SignatureError; @@ -98,91 +63,39 @@ impl TryFrom<[u8; VRF_OUTPUT_LENGTH]> for VRFOutput { } } -#[cfg(feature = "std")] -impl TryFrom for VRFOutput { - type Error = SignatureError; - - fn try_from(raw: RawVRFOutput) -> Result { - schnorrkel::vrf::VRFOutput::from_bytes(&raw.0).map(VRFOutput) - } -} - -#[cfg(feature = "std")] -impl From 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 { 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 { self.0.to_bytes().encode() } } -#[cfg(feature = "std")] impl EncodeLike for VRFProof { } -#[cfg(feature = "std")] impl Decode for VRFProof { fn decode(i: &mut R) -> Result { let decoded = <[u8; VRF_PROOF_LENGTH]>::decode(i)?; @@ -190,7 +103,6 @@ impl Decode for VRFProof { } } -#[cfg(feature = "std")] impl TryFrom<[u8; VRF_PROOF_LENGTH]> for VRFProof { type Error = SignatureError; @@ -199,23 +111,6 @@ impl TryFrom<[u8; VRF_PROOF_LENGTH]> for VRFProof { } } -#[cfg(feature = "std")] -impl TryFrom for VRFProof { - type Error = SignatureError; - - fn try_from(raw: RawVRFProof) -> Result { - schnorrkel::vrf::VRFProof::from_bytes(&raw.0).map(VRFProof) - } -} - -#[cfg(feature = "std")] -impl From 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::*;