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 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
4 changes: 4 additions & 0 deletions bin/node/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1160,6 +1160,10 @@ impl_runtime_apis! {
Babe::current_epoch()
}

fn next_epoch() -> sp_consensus_babe::Epoch {
Babe::next_epoch()
}

fn generate_key_ownership_proof(
_slot_number: sp_consensus_babe::SlotNumber,
authority_id: sp_consensus_babe::AuthorityId,
Expand Down
43 changes: 42 additions & 1 deletion frame/babe/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ pub use equivocation::{BabeEquivocationOffence, EquivocationHandler, HandleEquiv

pub trait Config: pallet_timestamp::Config {
/// The amount of time, in slots, that each epoch should last.
/// NOTE: Currently it is not possible to change the epoch duration after
/// the chain has started. Attempting to do so will brick block production.
type EpochDuration: Get<SlotNumber>;

/// The expected average block time at which BABE should be creating
Expand Down Expand Up @@ -192,6 +194,9 @@ decl_storage! {
/// Next epoch randomness.
NextRandomness: schnorrkel::Randomness;

/// Next epoch authorities.
NextAuthorities: Vec<(AuthorityId, BabeAuthorityWeight)>;

/// Randomness under construction.
///
/// We make a tradeoff between storage accesses and list length.
Expand Down Expand Up @@ -233,6 +238,9 @@ decl_module! {
pub struct Module<T: Config> for enum Call where origin: T::Origin {
/// The number of **slots** that an epoch takes. We couple sessions to
/// epochs, i.e. we start a new session once the new epoch begins.
/// NOTE: Currently it is not possible to change the epoch duration
/// after the chain has started. Attempting to do so will brick block
/// production.
const EpochDuration: u64 = T::EpochDuration::get();

/// The expected average block time at which BABE should be creating
Expand Down Expand Up @@ -464,6 +472,9 @@ impl<T: Config> Module<T> {
let randomness = Self::randomness_change_epoch(next_epoch_index);
Randomness::put(randomness);

// Update the next epoch authorities.
NextAuthorities::put(&next_authorities);

// After we update the current epoch, we signal the *next* epoch change
// so that nodes can track changes.
let next_randomness = NextRandomness::get();
Expand All @@ -483,7 +494,7 @@ impl<T: Config> Module<T> {
// give correct results after `do_initialize` of the first block
// in the chain (as its result is based off of `GenesisSlot`).
pub fn current_epoch_start() -> SlotNumber {
(EpochIndex::get() * T::EpochDuration::get()) + GenesisSlot::get()
Self::epoch_start(EpochIndex::get())
}

/// Produces information about the current epoch.
Expand All @@ -497,6 +508,36 @@ impl<T: Config> Module<T> {
}
}

/// Produces information about the next epoch (which was already previously
/// announced).
pub fn next_epoch() -> Epoch {
let next_epoch_index = EpochIndex::get().checked_add(1).expect(
"epoch index is u64; it is always only incremented by one; \
if u64 is not enough we should crash for safety; qed.",
);

Epoch {
epoch_index: next_epoch_index,
start_slot: Self::epoch_start(next_epoch_index),
duration: T::EpochDuration::get(),
authorities: NextAuthorities::get(),
randomness: NextRandomness::get(),
}
}

fn epoch_start(epoch_index: u64) -> SlotNumber {
// (epoch_index * epoch_duration) + genesis_slot

const PROOF: &str = "slot number is u64; it should relate in some way to wall clock time; \
if u64 is not enough we should crash for safety; qed.";

let epoch_start = epoch_index
.checked_mul(T::EpochDuration::get())
.expect(PROOF);

epoch_start.checked_add(GenesisSlot::get()).expect(PROOF)
}

fn deposit_consensus<U: Encode>(new: U) {
let log: DigestItem<T::Hash> = DigestItem::Consensus(BABE_ENGINE_ID, new.encode());
<frame_system::Module<T>>::deposit_log(log.into())
Expand Down
2 changes: 1 addition & 1 deletion frame/babe/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,7 @@ pub fn start_era(era_index: EraIndex) {
assert_eq!(Staking::current_era(), Some(era_index));
}

pub fn make_pre_digest(
pub fn make_primary_pre_digest(
authority_index: sp_consensus_babe::AuthorityIndex,
slot_number: sp_consensus_babe::SlotNumber,
vrf_output: VRFOutput,
Expand Down
31 changes: 29 additions & 2 deletions frame/babe/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ fn first_block_epoch_zero_start() {
let (vrf_output, vrf_proof, vrf_randomness) = make_vrf_output(genesis_slot, &pairs[0]);

let first_vrf = vrf_output;
let pre_digest = make_pre_digest(
let pre_digest = make_primary_pre_digest(
0,
genesis_slot,
first_vrf.clone(),
Expand Down Expand Up @@ -122,7 +122,7 @@ fn author_vrf_output_for_primary() {
ext.execute_with(|| {
let genesis_slot = 10;
let (vrf_output, vrf_proof, vrf_randomness) = make_vrf_output(genesis_slot, &pairs[0]);
let primary_pre_digest = make_pre_digest(0, genesis_slot, vrf_output, vrf_proof);
let primary_pre_digest = make_primary_pre_digest(0, genesis_slot, vrf_output, vrf_proof);

System::initialize(
&1,
Expand Down Expand Up @@ -252,6 +252,33 @@ fn can_enact_next_config() {
});
}

#[test]
fn can_fetch_current_and_next_epoch_data() {
new_test_ext(5).execute_with(|| {
// 1 era = 3 epochs
// 1 epoch = 3 slots
// Eras start from 0.
// Therefore at era 1 we should be starting epoch 3 with slot 10.
start_era(1);

let current_epoch = Babe::current_epoch();
assert_eq!(current_epoch.epoch_index, 3);
assert_eq!(current_epoch.start_slot, 10);
assert_eq!(current_epoch.authorities.len(), 5);

let next_epoch = Babe::next_epoch();
assert_eq!(next_epoch.epoch_index, 4);
assert_eq!(next_epoch.start_slot, 13);
assert_eq!(next_epoch.authorities.len(), 5);

// the on-chain randomness should always change across epochs
assert!(current_epoch.randomness != next_epoch.randomness);

// but in this case the authorities stay the same
assert!(current_epoch.authorities == next_epoch.authorities);
});
}

#[test]
fn report_equivocation_current_session_works() {
let (pairs, mut ext) = new_test_ext_with_pairs(3);
Expand Down
4 changes: 4 additions & 0 deletions primitives/consensus/babe/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,10 @@ sp_api::decl_runtime_apis! {
/// Returns information regarding the current epoch.
fn current_epoch() -> Epoch;

/// Returns information regarding the next epoch (which was already
/// previously announced).
fn next_epoch() -> Epoch;

/// Generates a proof of key ownership for the given authority in the
/// current epoch. An example usage of this module is coupled with the
/// session historical module to prove that a given authority key is
Expand Down
8 changes: 8 additions & 0 deletions test-utils/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -741,6 +741,10 @@ cfg_if! {
<pallet_babe::Module<Runtime>>::current_epoch()
}

fn next_epoch() -> sp_consensus_babe::Epoch {
<pallet_babe::Module<Runtime>>::next_epoch()
}

fn submit_report_equivocation_unsigned_extrinsic(
_equivocation_proof: sp_consensus_babe::EquivocationProof<
<Block as BlockT>::Header,
Expand Down Expand Up @@ -996,6 +1000,10 @@ cfg_if! {
<pallet_babe::Module<Runtime>>::current_epoch()
}

fn next_epoch() -> sp_consensus_babe::Epoch {
<pallet_babe::Module<Runtime>>::next_epoch()
}

fn submit_report_equivocation_unsigned_extrinsic(
_equivocation_proof: sp_consensus_babe::EquivocationProof<
<Block as BlockT>::Header,
Expand Down