diff --git a/substrate/client/consensus/babe/src/authorship.rs b/substrate/client/consensus/babe/src/authorship.rs index fb7be52766c70d3b93a03ac8842a8f1f82a9b1f9..074e582bff252395a18e691211eda944b380c723 100644 --- a/substrate/client/consensus/babe/src/authorship.rs +++ b/substrate/client/consensus/babe/src/authorship.rs @@ -21,7 +21,7 @@ use sp_consensus_babe::{ AuthorityId, BabeAuthorityWeight, BABE_ENGINE_ID, BABE_VRF_PREFIX, SlotNumber, AuthorityPair, BabeConfiguration }; -use sp_consensus_babe::digests::PreDigest; +use sp_consensus_babe::digests::{PreDigest, PrimaryPreDigest, SecondaryPreDigest}; use sp_consensus_vrf::schnorrkel::{VRFOutput, VRFProof}; use sp_core::{U256, blake2_256}; use codec::Encode; @@ -128,10 +128,10 @@ fn claim_secondary_slot( }) { if pair.public() == *expected_author { - let pre_digest = PreDigest::Secondary { + let pre_digest = PreDigest::Secondary(SecondaryPreDigest { slot_number, authority_index: authority_index as u32, - }; + }); return Some((pre_digest, pair)); } @@ -200,12 +200,12 @@ fn claim_primary_slot( let pre_digest = get_keypair(&pair) .vrf_sign_after_check(transcript, |inout| super::authorship::check_primary_threshold(inout, threshold)) .map(|s| { - PreDigest::Primary { + PreDigest::Primary(PrimaryPreDigest { slot_number, vrf_output: VRFOutput(s.0.to_output()), vrf_proof: VRFProof(s.1), authority_index: authority_index as u32, - } + }) }); // early exit on first successful claim diff --git a/substrate/client/consensus/babe/src/lib.rs b/substrate/client/consensus/babe/src/lib.rs index f4373da47f26cca9145e93316a1c6692555cf719..6ce9fc7e72ceb95b2bcf0587732dbd8d4874bb12 100644 --- a/substrate/client/consensus/babe/src/lib.rs +++ b/substrate/client/consensus/babe/src/lib.rs @@ -62,7 +62,9 @@ pub use sp_consensus_babe::{ BabeApi, ConsensusLog, BABE_ENGINE_ID, SlotNumber, BabeConfiguration, AuthorityId, AuthorityPair, AuthoritySignature, BabeAuthorityWeight, VRF_OUTPUT_LENGTH, - digests::{PreDigest, CompatibleDigestItem, NextEpochDescriptor}, + digests::{ + CompatibleDigestItem, NextEpochDescriptor, PreDigest, PrimaryPreDigest, SecondaryPreDigest, + }, }; pub use sp_consensus::SyncOracle; use std::{ @@ -580,10 +582,10 @@ fn find_pre_digest<B: BlockT>(header: &B::Header) -> Result<PreDigest, Error<B>> // genesis block doesn't contain a pre digest so let's generate a // dummy one to not break any invariants in the rest of the code if header.number().is_zero() { - return Ok(PreDigest::Secondary { + return Ok(PreDigest::Secondary(SecondaryPreDigest { slot_number: 0, authority_index: 0, - }); + })); } let mut pre_digest: Option<_> = None; diff --git a/substrate/client/consensus/babe/src/tests.rs b/substrate/client/consensus/babe/src/tests.rs index ec5a6032f5f3489876c573353046d68dc0e392a2..20b924669d6147816c0fbf9c0c8e85937b17c1af 100644 --- a/substrate/client/consensus/babe/src/tests.rs +++ b/substrate/client/consensus/babe/src/tests.rs @@ -553,10 +553,10 @@ fn propose_and_import_block<Transaction>( let pre_digest = sp_runtime::generic::Digest { logs: vec![ Item::babe_pre_digest( - PreDigest::Secondary { + PreDigest::Secondary(SecondaryPreDigest { authority_index: 0, slot_number, - }, + }), ), ], }; diff --git a/substrate/client/consensus/babe/src/verification.rs b/substrate/client/consensus/babe/src/verification.rs index 1eb73588a87bcad63cafe09e2f4ed8972bbe094d..2fd37280b3b369bdb1e73895dc9ae683030eaa23 100644 --- a/substrate/client/consensus/babe/src/verification.rs +++ b/substrate/client/consensus/babe/src/verification.rs @@ -17,9 +17,10 @@ //! Verification for BABE headers. 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 sp_consensus_babe::{AuthoritySignature, SlotNumber, AuthorityPair, AuthorityId}; +use sp_consensus_babe::digests::{ + PreDigest, PrimaryPreDigest, SecondaryPreDigest, CompatibleDigestItem +}; use sc_consensus_slots::CheckedHeader; use log::{debug, trace}; use super::{find_pre_digest, babe_err, Epoch, BlockT, Error}; @@ -93,27 +94,23 @@ pub(super) fn check_header<B: BlockT + Sized>( }; match &pre_digest { - PreDigest::Primary { vrf_output, vrf_proof, authority_index, slot_number } => { + PreDigest::Primary(primary) => { debug!(target: "babe", "Verifying Primary block"); - let digest = (vrf_output, vrf_proof, *authority_index, *slot_number); - check_primary_header::<B>( pre_hash, - digest, + primary, sig, &epoch, config.c, )?; }, - PreDigest::Secondary { authority_index, slot_number } if config.secondary_slots => { + PreDigest::Secondary(secondary) if config.secondary_slots => { debug!(target: "babe", "Verifying Secondary block"); - let digest = (*authority_index, *slot_number); - check_secondary_header::<B>( pre_hash, - digest, + secondary, sig, &epoch, )?; @@ -143,25 +140,23 @@ pub(super) struct VerifiedHeaderInfo<B: BlockT> { /// its parent since it is a primary block. fn check_primary_header<B: BlockT + Sized>( pre_hash: B::Hash, - pre_digest: (&VRFOutput, &VRFProof, AuthorityIndex, SlotNumber), + pre_digest: &PrimaryPreDigest, signature: AuthoritySignature, epoch: &Epoch, c: (u64, u64), ) -> Result<(), Error<B>> { - let (vrf_output, vrf_proof, authority_index, slot_number) = pre_digest; - - let author = &epoch.authorities[authority_index as usize].0; + let author = &epoch.authorities[pre_digest.authority_index as usize].0; if AuthorityPair::verify(&signature, pre_hash, &author) { let (inout, _) = { let transcript = make_transcript( &epoch.randomness, - slot_number, + pre_digest.slot_number, epoch.epoch_index, ); schnorrkel::PublicKey::from_bytes(author.as_slice()).and_then(|p| { - p.vrf_verify(transcript, vrf_output, vrf_proof) + p.vrf_verify(transcript, &pre_digest.vrf_output, &pre_digest.vrf_proof) }).map_err(|s| { babe_err(Error::VRFVerificationFailed(s)) })? @@ -170,7 +165,7 @@ fn check_primary_header<B: BlockT + Sized>( let threshold = calculate_primary_threshold( c, &epoch.authorities, - authority_index as usize, + pre_digest.authority_index as usize, ); if !check_primary_threshold(&inout, threshold) { @@ -189,21 +184,19 @@ fn check_primary_header<B: BlockT + Sized>( /// compared to its parent since it is a secondary block. fn check_secondary_header<B: BlockT>( pre_hash: B::Hash, - pre_digest: (AuthorityIndex, SlotNumber), + pre_digest: &SecondaryPreDigest, signature: AuthoritySignature, epoch: &Epoch, ) -> Result<(), Error<B>> { - let (authority_index, slot_number) = pre_digest; - // check the signature is valid under the expected authority and // chain state. let expected_author = secondary_slot_author( - slot_number, + pre_digest.slot_number, &epoch.authorities, epoch.randomness, ).ok_or_else(|| Error::NoSecondaryAuthorExpected)?; - let author = &epoch.authorities[authority_index as usize].0; + let author = &epoch.authorities[pre_digest.authority_index as usize].0; if expected_author != author { return Err(Error::InvalidAuthor(expected_author.clone(), author.clone())); diff --git a/substrate/frame/babe/src/lib.rs b/substrate/frame/babe/src/lib.rs index 27a471f6f8f10f0c0d773edcb26ac1a044a5429d..51c1bdb553a9cf2bb9800f62ce2ea56c2071190e 100644 --- a/substrate/frame/babe/src/lib.rs +++ b/substrate/frame/babe/src/lib.rs @@ -209,12 +209,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 = RawPreDigest::decode(&mut data).ok()?; - return Some(match pre_digest { - RawPreDigest::Primary { authority_index, .. } => - authority_index, - RawPreDigest::Secondary { authority_index, .. } => - authority_index, - }); + return Some(pre_digest.authority_index()) } } @@ -426,11 +421,11 @@ impl<T: Trait> Module<T> { CurrentSlot::put(digest.slot_number()); - if let RawPreDigest::Primary { vrf_output, .. } = digest { + if let RawPreDigest::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(vrf_output) + Some(primary.vrf_output) } else { None } diff --git a/substrate/frame/babe/src/tests.rs b/substrate/frame/babe/src/tests.rs index 3fcb78ae5fb56181db91ef08577a299e73389a8b..c13d77c1160f300f1894f86c8b5381aa43d05e89 100644 --- a/substrate/frame/babe/src/tests.rs +++ b/substrate/frame/babe/src/tests.rs @@ -35,12 +35,14 @@ fn make_pre_digest( vrf_output: RawVRFOutput, vrf_proof: RawVRFProof, ) -> Digest { - let digest_data = sp_consensus_babe::digests::RawPreDigest::Primary { - authority_index, - slot_number, - vrf_output, - vrf_proof, - }; + let digest_data = sp_consensus_babe::digests::RawPreDigest::Primary( + sp_consensus_babe::digests::RawPrimaryPreDigest { + authority_index, + slot_number, + vrf_output, + vrf_proof, + } + ); let log = DigestItem::PreRuntime(sp_consensus_babe::BABE_ENGINE_ID, digest_data.encode()); Digest { logs: vec![log] } } diff --git a/substrate/primitives/consensus/babe/src/digests.rs b/substrate/primitives/consensus/babe/src/digests.rs index fca0c3a7b31a65f5476db11d4ed8f12efe445533..6079aa88c87492538fbf3caefdd3775d4cdd9292 100644 --- a/substrate/primitives/consensus/babe/src/digests.rs +++ b/substrate/primitives/consensus/babe/src/digests.rs @@ -27,40 +27,67 @@ 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; +/// Raw BABE primary slot assignment pre-digest. +#[derive(Clone, RuntimeDebug, Encode, Decode)] +pub struct RawPrimaryPreDigest<VRFOutput=schnorrkel::RawVRFOutput, VRFProof=schnorrkel::RawVRFProof> { + /// Authority index + pub authority_index: super::AuthorityIndex, + /// Slot number + pub slot_number: SlotNumber, + /// VRF output + pub vrf_output: VRFOutput, + /// VRF proof + pub vrf_proof: VRFProof, +} + +#[cfg(feature = "std")] +/// BABE primary slot assignment pre-digest for std environment. +pub type PrimaryPreDigest = RawPrimaryPreDigest<schnorrkel::VRFOutput, schnorrkel::VRFProof>; + +#[cfg(feature = "std")] +impl TryFrom<RawPrimaryPreDigest> for PrimaryPreDigest { + type Error = SignatureError; + + fn try_from(raw: RawPrimaryPreDigest) -> Result<PrimaryPreDigest, SignatureError> { + 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 SecondaryPreDigest { + /// Authority index + /// + /// This is not strictly-speaking necessary, since the secondary slots + /// 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. + pub authority_index: super::AuthorityIndex, + /// Slot number + pub slot_number: SlotNumber, +} + /// 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, Debug, Encode, Decode)] +#[derive(Clone, RuntimeDebug, 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: super::AuthorityIndex, - /// Slot number - slot_number: SlotNumber, - /// VRF output - vrf_output: VRFOutput, - /// VRF proof - vrf_proof: VRFProof, - }, + Primary(RawPrimaryPreDigest<VRFOutput, VRFProof>), /// A secondary deterministic slot assignment. #[codec(index = "2")] - Secondary { - /// Authority index - /// - /// This is not strictly-speaking necessary, since the secondary slots - /// 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: super::AuthorityIndex, - /// Slot number - slot_number: SlotNumber, - }, + Secondary(SecondaryPreDigest), } #[cfg(feature = "std")] @@ -71,16 +98,16 @@ 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, + RawPreDigest::Primary(primary) => primary.authority_index, + RawPreDigest::Secondary(secondary) => secondary.authority_index, } } /// Returns the slot number of the pre digest. pub fn slot_number(&self) -> SlotNumber { match self { - RawPreDigest::Primary { slot_number, .. } => *slot_number, - RawPreDigest::Secondary { slot_number, .. } => *slot_number, + RawPreDigest::Primary(primary) => primary.slot_number, + RawPreDigest::Secondary(secondary) => secondary.slot_number, } } @@ -88,8 +115,8 @@ impl<VRFOutput, VRFProof> RawPreDigest<VRFOutput, VRFProof> { /// of the chain. pub fn added_weight(&self) -> crate::BabeBlockWeight { match self { - RawPreDigest::Primary { .. } => 1, - RawPreDigest::Secondary { .. } => 0, + RawPreDigest::Primary(_) => 1, + RawPreDigest::Secondary(_) => 0, } } } @@ -100,25 +127,15 @@ impl TryFrom<RawPreDigest> for PreDigest { 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::Primary(primary) => PreDigest::Primary(primary.try_into()?), + RawPreDigest::Secondary(secondary) => PreDigest::Secondary(secondary), }) } } /// Information about the next epoch. This is broadcast in the first block /// of the epoch. -#[derive(Decode, Encode, Default, PartialEq, Eq, Clone, sp_runtime::RuntimeDebug)] +#[derive(Decode, Encode, Default, PartialEq, Eq, Clone, RuntimeDebug)] pub struct NextEpochDescriptor { /// The authorities. pub authorities: Vec<(AuthorityId, BabeAuthorityWeight)>, diff --git a/substrate/primitives/consensus/vrf/src/schnorrkel.rs b/substrate/primitives/consensus/vrf/src/schnorrkel.rs index e4ae68ced41902a13dc8ec752dd946ef314293db..635160aa00b711435a6bccd1d91ea2a741af011a 100644 --- a/substrate/primitives/consensus/vrf/src/schnorrkel.rs +++ b/substrate/primitives/consensus/vrf/src/schnorrkel.rs @@ -17,6 +17,7 @@ //! Schnorrkel-based VRF. use codec::{Encode, Decode}; +#[cfg(feature = "std")] use sp_core::U512; use sp_runtime::RuntimeDebug; use sp_std::ops::{Deref, DerefMut};