Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

Fix the BABE epoch logic in SRML #3611

Merged
merged 5 commits into from
Sep 16, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions core/client/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1528,7 +1528,7 @@ impl<B, E, Block, RA> consensus::BlockImport<Block> for Client<B, E, Block, RA>
}
}

impl<B, E, Block, RA> Finalizer<Block, Blake2Hasher, B> for Client<B, E, Block, RA> where
impl<B, E, Block, RA> Finalizer<Block, Blake2Hasher, B> for Client<B, E, Block, RA> where
B: backend::Backend<Block, Blake2Hasher>,
E: CallExecutor<Block, Blake2Hasher>,
Block: BlockT<Hash=H256>,
Expand All @@ -1552,7 +1552,7 @@ impl<B, E, Block, RA> Finalizer<Block, Blake2Hasher, B> for Client<B, E, Block,
}
}

impl<B, E, Block, RA> Finalizer<Block, Blake2Hasher, B> for &Client<B, E, Block, RA> where
impl<B, E, Block, RA> Finalizer<Block, Blake2Hasher, B> for &Client<B, E, Block, RA> where
B: backend::Backend<Block, Blake2Hasher>,
E: CallExecutor<Block, Blake2Hasher>,
Block: BlockT<Hash=H256>,
Expand Down Expand Up @@ -1833,7 +1833,7 @@ impl<B, E, Block, RA> backend::AuxStore for &Client<B, E, Block, RA>
B: backend::Backend<Block, Blake2Hasher>,
E: CallExecutor<Block, Blake2Hasher>,
Block: BlockT<Hash=H256>,
{
{

fn insert_aux<
'a,
Expand Down
53 changes: 23 additions & 30 deletions core/consensus/babe/primitives/src/digest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,10 @@
//! Private implementation details of BABE digests.

#[cfg(feature = "std")]
use super::AuthoritySignature;
#[cfg(feature = "std")]
use super::{BABE_ENGINE_ID, Epoch};
use super::{BABE_ENGINE_ID, AuthoritySignature};
#[cfg(not(feature = "std"))]
use super::{VRF_OUTPUT_LENGTH, VRF_PROOF_LENGTH};
use super::{AuthorityIndex, BabeBlockWeight, SlotNumber};
use super::{AuthorityId, AuthorityIndex, SlotNumber, BabeAuthorityWeight};
#[cfg(feature = "std")]
use sr_primitives::{DigestItem, generic::OpaqueDigestItemId};
#[cfg(feature = "std")]
Expand All @@ -35,6 +33,8 @@ use schnorrkel::{
SignatureError, errors::MultiSignatureStage,
vrf::{VRFProof, VRFOutput, VRF_OUTPUT_LENGTH, VRF_PROOF_LENGTH}
};
use rstd::vec::Vec;


/// 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
Expand All @@ -52,17 +52,13 @@ pub enum BabePreDigest {
authority_index: super::AuthorityIndex,
/// Slot number
slot_number: SlotNumber,
/// Chain weight (measured in number of Primary blocks)
weight: BabeBlockWeight,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where should this go then?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it'll be maintained off-chain; it's a bit redundant to put it in the block header.

},
/// 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,
},
}

Expand All @@ -83,14 +79,6 @@ impl BabePreDigest {
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.
Expand All @@ -100,26 +88,24 @@ pub const BABE_VRF_PREFIX: &'static [u8] = b"substrate-babe-vrf";
#[derive(Copy, Clone, Encode, Decode)]
pub enum RawBabePreDigest {
/// A primary VRF-based slot assignment.
#[codec(index = "1")]
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.
#[codec(index = "2")]
Secondary {
/// Authority index
authority_index: AuthorityIndex,
/// Slot number
slot_number: SlotNumber,
/// Chain weight (measured in number of Primary blocks)
weight: BabeBlockWeight,
},
}

Expand All @@ -142,25 +128,21 @@ impl Encode for BabePreDigest {
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,
}
},
};
Expand All @@ -176,7 +158,7 @@ impl codec::EncodeLike for BabePreDigest {}
impl Decode for BabePreDigest {
fn decode<R: Input>(i: &mut R) -> Result<Self, Error> {
let pre_digest = match Decode::decode(i)? {
RawBabePreDigest::Primary { vrf_output, vrf_proof, authority_index, slot_number, weight } => {
RawBabePreDigest::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;
Expand All @@ -186,18 +168,29 @@ impl Decode for BabePreDigest {
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 }
RawBabePreDigest::Secondary { authority_index, slot_number } => {
BabePreDigest::Secondary { authority_index, slot_number }
},
};

Ok(pre_digest)
}
}

/// Information about the next epoch. This is broadcast in the first block
/// of the epoch.
#[derive(Decode, Encode, Default, PartialEq, Eq, Clone)]
#[cfg_attr(any(feature = "std", test), derive(Debug))]
pub struct NextEpochDescriptor {
/// The authorities.
pub authorities: Vec<(AuthorityId, BabeAuthorityWeight)>,

/// The value of randomness to use for the slot-assignment.
pub randomness: [u8; VRF_OUTPUT_LENGTH],
}

/// A digest item which is usable with BABE consensus.
#[cfg(feature = "std")]
pub trait CompatibleDigestItem: Sized {
Expand All @@ -214,7 +207,7 @@ pub trait CompatibleDigestItem: Sized {
fn as_babe_seal(&self) -> Option<AuthoritySignature>;

/// If this item is a BABE epoch, return it.
fn as_babe_epoch(&self) -> Option<Epoch>;
fn as_next_epoch_descriptor(&self) -> Option<NextEpochDescriptor>;
}

#[cfg(feature = "std")]
Expand All @@ -237,7 +230,7 @@ impl<Hash> CompatibleDigestItem for DigestItem<Hash> where
self.try_to(OpaqueDigestItemId::Seal(&BABE_ENGINE_ID))
}

fn as_babe_epoch(&self) -> Option<Epoch> {
fn as_next_epoch_descriptor(&self) -> Option<NextEpochDescriptor> {
self.try_to(OpaqueDigestItemId::Consensus(&BABE_ENGINE_ID))
}
}
Expand Down
54 changes: 27 additions & 27 deletions core/consensus/babe/primitives/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ use substrate_client::decl_runtime_apis;

#[cfg(feature = "std")]
pub use digest::{BabePreDigest, CompatibleDigestItem};
pub use digest::{BABE_VRF_PREFIX, RawBabePreDigest};
pub use digest::{BABE_VRF_PREFIX, RawBabePreDigest, NextEpochDescriptor};

mod app {
use app_crypto::{app_crypto, key_types::BABE, sr25519};
Expand Down Expand Up @@ -59,6 +59,11 @@ pub const VRF_PROOF_LENGTH: usize = 64;
/// The length of the public key
pub const PUBLIC_KEY_LENGTH: usize = 32;

/// How many blocks to wait before running the median algorithm for relative time
/// This will not vary from chain to chain as it is not dependent on slot duration
/// or epoch length.
pub const MEDIAN_ALGORITHM_CARDINALITY: usize = 1200; // arbitrary suggestion by w3f-research.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It'll become some number of slots maybe, yes?


/// The index of an authority.
pub type AuthorityIndex = u32;

Expand Down Expand Up @@ -87,57 +92,55 @@ pub struct Epoch {
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.
#[derive(Decode, Encode, Clone, PartialEq, Eq)]
pub enum ConsensusLog {
/// The epoch has changed. This provides information about the
/// epoch _after_ next: what slot number it will start at, who are the authorities (and their weights)
/// and the next epoch randomness. The information for the _next_ epoch should already
/// be available.
/// The epoch has changed. This provides information about the _next_
/// epoch - information about the _current_ epoch (i.e. the one we've just
/// entered) should already be available earlier in the chain.
#[codec(index = "1")]
NextEpochData(Epoch),
NextEpochData(NextEpochDescriptor),
/// Disable the authority with given index.
#[codec(index = "2")]
OnDisabled(AuthorityIndex),
}

/// Configuration data used by the BABE consensus engine.
#[derive(Copy, Clone, Hash, PartialEq, Eq, Debug, Encode, Decode)]
#[derive(Clone, PartialEq, Eq, Encode, Decode)]
#[cfg_attr(any(feature = "std", test), derive(Debug))]
pub struct BabeConfiguration {
/// The slot duration in milliseconds for BABE. Currently, only
/// the value provided by this type at genesis will be used.
///
/// Dynamic slot duration may be supported in the future.
pub slot_duration: u64,

/// The duration of epochs in slots.
pub epoch_length: SlotNumber,

/// A constant value that is used in the threshold calculation formula.
/// Expressed as a fraction where the first member of the tuple is the
/// numerator and the second is the denominator. The fraction should
/// Expressed as a rational where the first member of the tuple is the
/// numerator and the second is the denominator. The rational should
/// represent a value between 0 and 1.
/// In the threshold formula calculation, `1 - c` represents the probability
/// of a slot being empty.
pub c: (u64, u64),

/// The minimum number of blocks that must be received before running the
/// median algorithm to compute the offset between the on-chain time and the
/// local time. Currently, only the value provided by this type at genesis
/// will be used, but this is subject to change.
///
/// Blocks less than `self.median_required_blocks` must be generated by an
/// *initial validator* ― that is, a node that was a validator at genesis.
pub median_required_blocks: u64,
/// The authorities for the genesis epoch.
pub genesis_authorities: Vec<(AuthorityId, BabeAuthorityWeight)>,

/// The randomness for this epoch.
pub randomness: [u8; VRF_OUTPUT_LENGTH],

/// Whether this chain should run with secondary slots, which are assigned
/// in round-robin manner.
pub secondary_slots: bool,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another option might be pub secondary_slots: u16, or Option<..> that expresses how many VRF slots should elapse between secondary slots, with u16::MAX or None denoting not to bother with secondary slots.

}

#[cfg(feature = "std")]
impl slots::SlotData for BabeConfiguration {
/// Return the slot duration in milliseconds for BABE. Currently, only
/// the value provided by this type at genesis will be used.
///
/// Dynamic slot duration may be supported in the future.
fn slot_duration(&self) -> u64 {
self.slot_duration
}
Expand All @@ -152,9 +155,6 @@ decl_runtime_apis! {
/// only the value provided by this type at genesis will be used.
///
/// Dynamic configuration may be supported in the future.
fn startup_data() -> BabeConfiguration;

/// Get the current epoch data for Babe.
fn epoch() -> Epoch;
fn configuration() -> BabeConfiguration;
}
}
16 changes: 4 additions & 12 deletions node/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -586,27 +586,19 @@ impl_runtime_apis! {
}

impl babe_primitives::BabeApi<Block> for Runtime {
fn startup_data() -> babe_primitives::BabeConfiguration {
fn configuration() -> babe_primitives::BabeConfiguration {
// The choice of `c` parameter (where `1 - c` represents the
// probability of a slot being empty), is done in accordance to the
// slot duration and expected target block time, for safely
// resisting network delays of maximum two seconds.
// <https://research.web3.foundation/en/latest/polkadot/BABE/Babe/#6-practical-results>
babe_primitives::BabeConfiguration {
median_required_blocks: 1000,
slot_duration: Babe::slot_duration(),
epoch_length: EpochDuration::get(),
c: PRIMARY_PROBABILITY,
}
}

fn epoch() -> babe_primitives::Epoch {
babe_primitives::Epoch {
start_slot: Babe::epoch_start_slot(),
authorities: Babe::authorities(),
epoch_index: Babe::epoch_index(),
genesis_authorities: Babe::authorities(),
randomness: Babe::randomness(),
duration: EpochDuration::get(),
secondary_slots: Babe::secondary_slots().0,
secondary_slots: true,
}
}
}
Expand Down
Loading