babe: Introduce secondary slots (Aurababeous) (#3380)

* babe: initial implementation of secondary slots

* babe: validate secondary slot author

* babe: implement weight based fork choice

* babe: remove unused

* aura: cleanup unused imports

* babe: pass in parent weight when authoring and verifying

* babe: use epoch randomness for picking secondary slot authors

* babe: fix tests

* babe: fix wasm build

* babe: node-side code for disabling secondary slots

* babe: allow enabling/disabling secondary slots from runtime

* babe: fix test

* babe: use blake2_256 for secondary slot assignment

* babe: run block initialization in should_end_session

* node: increase slot duration to 6s

* babe: add docs

* node: bump spec_version

* Apply suggestions from code review

Co-Authored-By: joe petrowski <25483142+joepetrowski@users.noreply.github.com>

* babe: simplify secondary slot assignment calculation

* babe: remove unnecessary comment

* node: bump spec_version

* babe: fix bad merge
This commit is contained in:
André Silva
2019-08-16 15:47:53 +02:00
committed by GitHub
parent f735d067c4
commit cb7527d2b2
12 changed files with 720 additions and 202 deletions
@@ -22,7 +22,7 @@ use super::AuthoritySignature;
use super::{BABE_ENGINE_ID, Epoch};
#[cfg(not(feature = "std"))]
use super::{VRF_OUTPUT_LENGTH, VRF_PROOF_LENGTH};
use super::SlotNumber;
use super::{AuthorityIndex, BabeBlockWeight, SlotNumber};
#[cfg(feature = "std")]
use sr_primitives::{DigestItem, generic::OpaqueDigestItemId};
#[cfg(feature = "std")]
@@ -36,18 +36,61 @@ use schnorrkel::{
vrf::{VRFProof, VRFOutput, VRF_OUTPUT_LENGTH, VRF_PROOF_LENGTH}
};
/// A BABE pre-digest
/// 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 struct BabePreDigest {
/// VRF output
pub vrf_output: VRFOutput,
/// VRF proof
pub vrf_proof: VRFProof,
/// Authority index
pub authority_index: super::AuthorityIndex,
/// Slot number
pub slot_number: SlotNumber,
pub enum BabePreDigest {
/// 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,
/// Chain weight (measured in number of Primary blocks)
weight: BabeBlockWeight,
},
/// A secondary deterministic slot assignment.
Secondary {
/// Authority index
authority_index: super::AuthorityIndex,
/// Slot number
slot_number: SlotNumber,
/// Chain weight (measured in number of Primary blocks)
weight: BabeBlockWeight,
},
}
#[cfg(feature = "std")]
impl BabePreDigest {
/// Returns the slot number of the pre digest.
pub fn authority_index(&self) -> AuthorityIndex {
match self {
BabePreDigest::Primary { authority_index, .. } => *authority_index,
BabePreDigest::Secondary { authority_index, .. } => *authority_index,
}
}
/// Returns the slot number of the pre digest.
pub fn slot_number(&self) -> SlotNumber {
match self {
BabePreDigest::Primary { slot_number, .. } => *slot_number,
BabePreDigest::Secondary { slot_number, .. } => *slot_number,
}
}
/// Returns the weight of the pre digest.
pub fn weight(&self) -> BabeBlockWeight {
match self {
BabePreDigest::Primary { weight, .. } => *weight,
BabePreDigest::Secondary { weight, .. } => *weight,
}
}
}
/// The prefix used by BABE for its VRF keys.
@@ -55,27 +98,74 @@ pub const BABE_VRF_PREFIX: &'static [u8] = b"substrate-babe-vrf";
/// A raw version of `BabePreDigest`, usable on `no_std`.
#[derive(Copy, Clone, Encode, Decode)]
pub struct RawBabePreDigest {
/// Slot number
pub slot_number: SlotNumber,
/// Authority index
pub authority_index: super::AuthorityIndex,
/// VRF output
pub vrf_output: [u8; VRF_OUTPUT_LENGTH],
/// VRF proof
pub vrf_proof: [u8; VRF_PROOF_LENGTH],
pub enum RawBabePreDigest {
/// A primary VRF-based slot assignment.
Primary {
/// Authority index
authority_index: AuthorityIndex,
/// Slot number
slot_number: SlotNumber,
/// Chain weight (measured in number of Primary blocks)
weight: BabeBlockWeight,
/// VRF output
vrf_output: [u8; VRF_OUTPUT_LENGTH],
/// VRF proof
vrf_proof: [u8; VRF_PROOF_LENGTH],
},
/// A secondary deterministic slot assignment.
Secondary {
/// Authority index
authority_index: AuthorityIndex,
/// Slot number
slot_number: SlotNumber,
/// Chain weight (measured in number of Primary blocks)
weight: BabeBlockWeight,
},
}
impl RawBabePreDigest {
/// Returns the slot number of the pre digest.
pub fn slot_number(&self) -> SlotNumber {
match self {
RawBabePreDigest::Primary { slot_number, .. } => *slot_number,
RawBabePreDigest::Secondary { slot_number, .. } => *slot_number,
}
}
}
#[cfg(feature = "std")]
impl Encode for BabePreDigest {
fn encode(&self) -> Vec<u8> {
let tmp = RawBabePreDigest {
vrf_output: *self.vrf_output.as_bytes(),
vrf_proof: self.vrf_proof.to_bytes(),
authority_index: self.authority_index,
slot_number: self.slot_number,
let raw = match self {
BabePreDigest::Primary {
vrf_output,
vrf_proof,
authority_index,
slot_number,
weight,
} => {
RawBabePreDigest::Primary {
vrf_output: *vrf_output.as_bytes(),
vrf_proof: vrf_proof.to_bytes(),
authority_index: *authority_index,
slot_number: *slot_number,
weight: *weight,
}
},
BabePreDigest::Secondary {
authority_index,
slot_number,
weight,
} => {
RawBabePreDigest::Secondary {
authority_index: *authority_index,
slot_number: *slot_number,
weight: *weight,
}
},
};
codec::Encode::encode(&tmp)
codec::Encode::encode(&raw)
}
}
@@ -85,19 +175,26 @@ impl codec::EncodeLike for BabePreDigest {}
#[cfg(feature = "std")]
impl Decode for BabePreDigest {
fn decode<R: Input>(i: &mut R) -> Result<Self, Error> {
let RawBabePreDigest { vrf_output, vrf_proof, authority_index, slot_number } = Decode::decode(i)?;
let pre_digest = match Decode::decode(i)? {
RawBabePreDigest::Primary { vrf_output, vrf_proof, authority_index, slot_number, weight } => {
// 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;
// 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;
Ok(BabePreDigest {
vrf_proof: VRFProof::from_bytes(&vrf_proof)
.map_err(convert_error)?,
vrf_output: VRFOutput::from_bytes(&vrf_output)
.map_err(convert_error)?,
authority_index,
slot_number,
})
BabePreDigest::Primary {
vrf_proof: VRFProof::from_bytes(&vrf_proof).map_err(convert_error)?,
vrf_output: VRFOutput::from_bytes(&vrf_output).map_err(convert_error)?,
authority_index,
slot_number,
weight,
}
},
RawBabePreDigest::Secondary { authority_index, slot_number, weight } => {
BabePreDigest::Secondary { authority_index, slot_number, weight }
},
};
Ok(pre_digest)
}
}
@@ -68,7 +68,10 @@ pub type SlotNumber = u64;
/// The weight of an authority.
// NOTE: we use a unique name for the weight to avoid conflicts with other
// `Weight` types, since the metadata isn't able to disambiguate.
pub type BabeWeight = u64;
pub type BabeAuthorityWeight = u64;
/// The weight of a BABE block.
pub type BabeBlockWeight = u32;
/// BABE epoch information
#[derive(Decode, Encode, Default, PartialEq, Eq, Clone)]
@@ -81,9 +84,11 @@ pub struct Epoch {
/// The duration of this epoch
pub duration: SlotNumber,
/// The authorities and their weights
pub authorities: Vec<(AuthorityId, BabeWeight)>,
pub authorities: Vec<(AuthorityId, BabeAuthorityWeight)>,
/// Randomness for this epoch
pub randomness: [u8; VRF_OUTPUT_LENGTH],
/// Whether secondary slot assignments should be used during the epoch.
pub secondary_slots: bool,
}
/// An consensus log item for BABE.