Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
7 changes: 3 additions & 4 deletions client/consensus/babe/src/authorship.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
use merlin::Transcript;
use sp_consensus_babe::{
AuthorityId, BabeAuthorityWeight, BABE_ENGINE_ID, BABE_VRF_PREFIX,
SlotNumber, AuthorityPair, BabeConfiguration
SlotNumber, AuthorityPair,
};
use sp_consensus_babe::digests::{PreDigest, PrimaryPreDigest, SecondaryPreDigest};
use sp_consensus_vrf::schnorrkel::{VRFOutput, VRFProof};
Expand Down Expand Up @@ -147,12 +147,11 @@ fn claim_secondary_slot(
pub fn claim_slot(
slot_number: SlotNumber,
epoch: &Epoch,
config: &BabeConfiguration,
keystore: &KeyStorePtr,
) -> Option<(PreDigest, AuthorityPair)> {
claim_primary_slot(slot_number, epoch, config.c, keystore)
claim_primary_slot(slot_number, epoch, epoch.config.c, keystore)
.or_else(|| {
if config.secondary_slots {
if epoch.config.secondary_slots {
claim_secondary_slot(
slot_number,
&epoch.authorities,
Expand Down
106 changes: 74 additions & 32 deletions client/consensus/babe/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,8 @@
#![forbid(unsafe_code)]
#![warn(missing_docs)]
pub use sp_consensus_babe::{
BabeApi, ConsensusLog, BABE_ENGINE_ID, SlotNumber, BabeConfiguration,
BabeApi, ConsensusLog, BABE_ENGINE_ID, SlotNumber,
BabeEpochConfiguration, BabeGenesisConfiguration,
AuthorityId, AuthorityPair, AuthoritySignature,
BabeAuthorityWeight, VRF_OUTPUT_LENGTH,
digests::{
Expand Down Expand Up @@ -123,31 +124,37 @@ pub mod authorship;
mod tests;

/// BABE epoch information
#[derive(Decode, Encode, Default, PartialEq, Eq, Clone, Debug)]
#[derive(Decode, Encode, PartialEq, Eq, Clone, Debug)]
pub struct Epoch {
/// The epoch index
/// The epoch index.
pub epoch_index: u64,
/// The starting slot of the epoch,
/// The starting slot of the epoch.
pub start_slot: SlotNumber,
/// The duration of this epoch
/// The duration of this epoch.
pub duration: SlotNumber,
/// The authorities and their weights
/// The authorities and their weights.
pub authorities: Vec<(AuthorityId, BabeAuthorityWeight)>,
/// Randomness for this epoch
/// Randomness for this epoch.
pub randomness: [u8; VRF_OUTPUT_LENGTH],
/// Configuration of the epoch.
pub config: BabeEpochConfiguration,
}

impl EpochT for Epoch {
type NextEpochDescriptor = NextEpochDescriptor;
type NextEpochDescriptor = (NextEpochDescriptor, BabeEpochConfiguration);
type SlotNumber = SlotNumber;

fn increment(&self, descriptor: NextEpochDescriptor) -> Epoch {
fn increment(
&self,
(descriptor, config): (NextEpochDescriptor, BabeEpochConfiguration)
) -> Epoch {
Epoch {
epoch_index: self.epoch_index + 1,
start_slot: self.start_slot + self.duration,
duration: self.duration,
authorities: descriptor.authorities,
randomness: descriptor.randomness,
config,
}
}

Expand All @@ -160,6 +167,25 @@ impl EpochT for Epoch {
}
}

impl Epoch {
/// Create the genesis epoch (epoch #0). This is defined to start at the slot of
/// the first block, so that has to be provided.
pub fn genesis(
genesis_config: &BabeGenesisConfiguration,
epoch_config: &BabeEpochConfiguration,
slot_number: SlotNumber
) -> Epoch {
Epoch {
epoch_index: 0,
start_slot: slot_number,
duration: epoch_config.epoch_length,
authorities: genesis_config.genesis_authorities.clone(),
randomness: genesis_config.randomness.clone(),
config: epoch_config.clone(),
}
}
}

#[derive(derive_more::Display, Debug)]
enum Error<B: BlockT> {
#[display(fmt = "Multiple BABE pre-runtime digests, rejecting!")]
Expand All @@ -168,6 +194,8 @@ enum Error<B: BlockT> {
NoPreRuntimeDigest,
#[display(fmt = "Multiple BABE epoch change digests, rejecting!")]
MultipleEpochChangeDigests,
#[display(fmt = "Fetch new epoch configuration failed")]
FetchEpochConfig(B::Hash),
#[display(fmt = "Could not extract timestamp and slot: {:?}", _0)]
Extraction(sp_consensus::Error),
#[display(fmt = "Could not fetch epoch at {:?}", _0)]
Expand Down Expand Up @@ -246,7 +274,7 @@ pub static INTERMEDIATE_KEY: &[u8] = b"babe1";
// and `super::babe::Config` can be eliminated.
// https://github.com/paritytech/substrate/issues/2434
#[derive(Clone)]
pub struct Config(sc_consensus_slots::SlotDuration<BabeConfiguration>);
pub struct Config(sc_consensus_slots::SlotDuration<BabeGenesisConfiguration>);

impl Config {
/// Either fetch the slot duration from disk or compute it from the genesis
Expand All @@ -255,32 +283,22 @@ impl Config {
C: AuxStore + ProvideRuntimeApi<B>, C::Api: BabeApi<B, Error = sp_blockchain::Error>,
{
trace!(target: "babe", "Getting slot duration");
match sc_consensus_slots::SlotDuration::get_or_compute(client, |a, b| a.configuration(b)).map(Self) {
match sc_consensus_slots::SlotDuration::get_or_compute(client, |a, b| {
a.genesis_configuration(b)
}).map(Self) {
Ok(s) => Ok(s),
Err(s) => {
warn!(target: "babe", "Failed to get slot duration");
Err(s)
}
}
}

/// Create the genesis epoch (epoch #0). This is defined to start at the slot of
/// the first block, so that has to be provided.
pub fn genesis_epoch(&self, slot_number: SlotNumber) -> Epoch {
Epoch {
epoch_index: 0,
start_slot: slot_number,
duration: self.epoch_length,
authorities: self.genesis_authorities.clone(),
randomness: self.randomness.clone(),
}
}
}

impl std::ops::Deref for Config {
type Target = BabeConfiguration;
type Target = BabeGenesisConfiguration;

fn deref(&self) -> &BabeConfiguration {
fn deref(&self) -> &BabeGenesisConfiguration {
&*self.0
}
}
Expand Down Expand Up @@ -438,7 +456,12 @@ impl<B, C, E, I, Error, SO> sc_consensus_slots::SimpleSlotWorker<B> for BabeWork

fn authorities_len(&self, epoch_descriptor: &Self::EpochData) -> Option<usize> {
self.epoch_changes.lock()
.viable_epoch(&epoch_descriptor, |slot| self.config.genesis_epoch(slot))
.viable_epoch(&epoch_descriptor, |slot| {
let epoch_config = self.client.runtime_api()
.epoch_configuration(&BlockId::number(Zero::zero()))
.ok()?;
Some(Epoch::genesis(&self.config, &epoch_config, slot))
})
.map(|epoch| epoch.as_ref().authorities.len())
}

Expand All @@ -453,9 +476,13 @@ impl<B, C, E, I, Error, SO> sc_consensus_slots::SimpleSlotWorker<B> for BabeWork
slot_number,
self.epoch_changes.lock().viable_epoch(
&epoch_descriptor,
|slot| self.config.genesis_epoch(slot)
|slot| {
let epoch_config = self.client.runtime_api()
.epoch_configuration(&BlockId::number(Zero::zero()))
.ok()?;
Some(Epoch::genesis(&self.config, &epoch_config, slot))
}
)?.as_ref(),
&*self.config,
&self.keystore,
);

Expand Down Expand Up @@ -746,7 +773,12 @@ impl<Block, Client> Verifier<Block> for BabeVerifier<Block, Client> where
.ok_or_else(|| Error::<Block>::FetchEpoch(parent_hash))?;
let viable_epoch = epoch_changes.viable_epoch(
&epoch_descriptor,
|slot| self.config.genesis_epoch(slot)
|slot| {
let epoch_config = self.client.runtime_api()
.epoch_configuration(&BlockId::number(Zero::zero()))
.ok()?;
Some(Epoch::genesis(&self.config, &epoch_config, slot))
}
).ok_or_else(|| Error::<Block>::FetchEpoch(parent_hash))?;

// We add one to the current slot to allow for some small drift.
Expand All @@ -756,7 +788,6 @@ impl<Block, Client> Verifier<Block> for BabeVerifier<Block, Client> where
pre_digest: Some(pre_digest.clone()),
slot_now: slot_now + 1,
epoch: viable_epoch.as_ref(),
config: &self.config,
};

match verification::check_header::<Block>(v_params)? {
Expand Down Expand Up @@ -1005,18 +1036,29 @@ impl<Block, Client, Inner> BlockImport<Block> for BabeBlockImport<Block, Client,

let viable_epoch = epoch_changes.viable_epoch(
&epoch_descriptor,
|slot| self.config.genesis_epoch(slot),
|slot| {
let epoch_config = self.client.runtime_api()
.epoch_configuration(&BlockId::number(Zero::zero()))
.ok()?;
Some(Epoch::genesis(&self.config, &epoch_config, slot))
}
).ok_or_else(|| {
ConsensusError::ClientImport(Error::<Block>::FetchEpoch(parent_hash).into())
})?;

let epoch_config = self.client.runtime_api()
.epoch_configuration(&BlockId::hash(parent_hash))
.map_err(|_| ConsensusError::ClientImport(
Error::<Block>::FetchEpochConfig(parent_hash).into()
))?;

babe_info!("👶 New epoch {} launching at block {} (block slot {} >= start slot {}).",
viable_epoch.as_ref().epoch_index,
hash,
slot_number,
viable_epoch.as_ref().start_slot);

let next_epoch = viable_epoch.increment(next_epoch_descriptor);
let next_epoch = viable_epoch.increment((next_epoch_descriptor, epoch_config));

babe_info!("👶 Next epoch starts at slot {}", next_epoch.as_ref().start_slot);

Expand Down
7 changes: 2 additions & 5 deletions client/consensus/babe/src/verification.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,6 @@ pub(super) struct VerificationParams<'a, B: 'a + BlockT> {
pub(super) slot_now: SlotNumber,
/// epoch descriptor of the epoch this block _should_ be under, if it's valid.
pub(super) epoch: &'a Epoch,
/// genesis config of this BABE chain.
pub(super) config: &'a super::Config,
}

/// Check a header has been signed by the right key. If the slot is too far in
Expand All @@ -63,7 +61,6 @@ pub(super) fn check_header<B: BlockT + Sized>(
pre_digest,
slot_now,
epoch,
config,
} = params;

let authorities = &epoch.authorities;
Expand Down Expand Up @@ -102,10 +99,10 @@ pub(super) fn check_header<B: BlockT + Sized>(
primary,
sig,
&epoch,
config.c,
epoch.config.c,
)?;
},
PreDigest::Secondary(secondary) if config.secondary_slots => {
PreDigest::Secondary(secondary) if epoch.config.secondary_slots => {
debug!(target: "babe", "Verifying Secondary block");

check_secondary_header::<B>(
Expand Down
4 changes: 2 additions & 2 deletions client/consensus/epochs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -394,11 +394,11 @@ impl<Hash, Number, E: Epoch> EpochChanges<Hash, Number, E> where
descriptor: &ViableEpochDescriptor<Hash, Number, E>,
make_genesis: G,
) -> Option<ViableEpoch<E, &E>> where
G: FnOnce(E::SlotNumber) -> E
G: FnOnce(E::SlotNumber) -> Option<E>
{
match descriptor {
ViableEpochDescriptor::UnimportedGenesis(slot_number) => {
Some(ViableEpoch::UnimportedGenesis(make_genesis(*slot_number)))
make_genesis(*slot_number).map(ViableEpoch::UnimportedGenesis)
},
ViableEpochDescriptor::Signaled(identifier, _) => {
self.epoch(&identifier).map(ViableEpoch::Signaled)
Expand Down
50 changes: 26 additions & 24 deletions primitives/consensus/babe/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,15 +89,32 @@ pub enum ConsensusLog {
OnDisabled(AuthorityIndex),
}

/// Configuration data used by the BABE consensus engine.
/// Genesis configuration data used by the BABE consensus engine.
#[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug)]
pub struct BabeConfiguration {
pub struct BabeGenesisConfiguration {
/// 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 authorities for the genesis epoch.
pub genesis_authorities: Vec<(AuthorityId, BabeAuthorityWeight)>,

/// The randomness for the genesis epoch.
pub randomness: Randomness,
}

#[cfg(feature = "std")]
impl sp_consensus::SlotData for BabeGenesisConfiguration {
fn slot_duration(&self) -> u64 {
self.slot_duration
}

const SLOT_KEY: &'static [u8] = b"babe_configuration";
}

/// Configuration data used by the BABE consensus engine.
#[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug)]
pub struct BabeEpochConfiguration {
/// The duration of epochs in slots.
pub epoch_length: SlotNumber,

Expand All @@ -109,34 +126,19 @@ pub struct BabeConfiguration {
/// of a slot being empty.
pub c: (u64, u64),

/// The authorities for the genesis epoch.
pub genesis_authorities: Vec<(AuthorityId, BabeAuthorityWeight)>,

/// The randomness for the genesis epoch.
pub randomness: Randomness,

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

#[cfg(feature = "std")]
impl sp_consensus::SlotData for BabeConfiguration {
fn slot_duration(&self) -> u64 {
self.slot_duration
}

const SLOT_KEY: &'static [u8] = b"babe_configuration";
}

sp_api::decl_runtime_apis! {
/// API necessary for block authorship with BABE.
pub trait BabeApi {
/// Return the configuration for BABE. Currently,
/// only the value provided by this type at genesis will be used.
///
/// Dynamic configuration may be supported in the future.
fn configuration() -> BabeConfiguration;
/// Return the epoch configuration for BABE. The configuration is read once every epoch.
fn epoch_configuration() -> BabeEpochConfiguration;

/// Return the genesis configuration for BABE. The configuration is only read on genesis.
fn genesis_configuration() -> BabeGenesisConfiguration;

/// Returns the slot number that started the current epoch.
fn current_epoch_start() -> SlotNumber;
Expand Down