mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-09 20:11:09 +00:00
Use BABE instead of AuRa in node (#3171)
* babe: add babe module trait * babe: track current slot and epoch start slot * babe: implement ShouldEndSession based on epochs * babe: rename weight type to avoid ambiguities * babe: expose epoch start slot in Epoch digest * babe: use epoch start for validating epoch transitions * babe: make the epoch duration a parameter type * babe: remove unused fields from config * node: update runtime to use babe instead of aura * node: use babe instead of aura * core: generate sr25519 keys from seed and add to keystore * core: remove AuthorityKeyring * node: remove unused primitive types related to babe crypto * uniform babe primitives crate import name * wrap long lines * babe: fix find_epoch_digest * fork-tree: fix find_node_where * node: set babe epoch duration to "10 minutes" * babe: cleanup import key cache if authorities don't change * node: make integration test compile (but fail) * node: bump spec_version * node: fix import * babe: don't use constants in storage fields array sizes * babe: account for first epoch slot way in the past * babe: signal next epoch change (not current) * babe: calculate next epoch randomness with next epoch index * babe: track next epoch in node * babe: cache current epoch and authorities separately * babe: generate valid babe vrf proofs in integration test * babe: cleanup claim_slot * babe: perform threshold calculation according to spec * babe: compute relative weight in threshold * babe: more precise threshold calculation * babe: use floats for threshold exponent calculation * babe: update constant c
This commit is contained in:
committed by
DemiMarie-parity
parent
407970406d
commit
9f50c8fce4
@@ -18,11 +18,12 @@
|
||||
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
#![forbid(unused_must_use, unsafe_code, unused_variables, dead_code)]
|
||||
|
||||
pub use timestamp;
|
||||
|
||||
use rstd::{result, prelude::*};
|
||||
use srml_support::{decl_storage, decl_module, StorageValue, traits::FindAuthor, traits::Get};
|
||||
use timestamp::{OnTimestampSet, Trait};
|
||||
use timestamp::{OnTimestampSet};
|
||||
use primitives::{generic::DigestItem, ConsensusEngineId};
|
||||
use primitives::traits::{IsMember, SaturatedConversion, Saturating, RandomnessBeacon, Convert};
|
||||
#[cfg(feature = "std")]
|
||||
@@ -31,7 +32,7 @@ use parity_codec::{Encode, Decode};
|
||||
use inherents::{RuntimeString, InherentIdentifier, InherentData, ProvideInherent, MakeFatalError};
|
||||
#[cfg(feature = "std")]
|
||||
use inherents::{InherentDataProviders, ProvideInherentData};
|
||||
use babe_primitives::{BABE_ENGINE_ID, ConsensusLog, Weight, Epoch, RawBabePreDigest};
|
||||
use babe_primitives::{BABE_ENGINE_ID, ConsensusLog, BabeWeight, Epoch, RawBabePreDigest};
|
||||
pub use babe_primitives::{AuthorityId, VRF_OUTPUT_LENGTH, PUBLIC_KEY_LENGTH};
|
||||
|
||||
/// The BABE inherent identifier.
|
||||
@@ -106,18 +107,28 @@ impl ProvideInherentData for InherentDataProvider {
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Trait: timestamp::Trait {
|
||||
type EpochDuration: Get<u64>;
|
||||
}
|
||||
|
||||
/// The length of the BABE randomness
|
||||
pub const RANDOMNESS_LENGTH: usize = 32;
|
||||
|
||||
decl_storage! {
|
||||
trait Store for Module<T: Trait> as Babe {
|
||||
NextRandomness: [u8; RANDOMNESS_LENGTH];
|
||||
/// Current epoch index.
|
||||
pub EpochIndex get(epoch_index): u64;
|
||||
|
||||
/// Randomness under construction
|
||||
UnderConstruction: [u8; VRF_OUTPUT_LENGTH];
|
||||
/// Current epoch authorities.
|
||||
pub Authorities get(authorities) config(): Vec<(AuthorityId, BabeWeight)>;
|
||||
|
||||
/// Current epoch
|
||||
pub Authorities get(authorities) config(): Vec<(AuthorityId, Weight)>;
|
||||
/// Slot at which the current epoch started. It is possible that no
|
||||
/// block was authored at the given slot and the epoch change was
|
||||
/// signalled later than this.
|
||||
pub EpochStartSlot get(epoch_start_slot): u64;
|
||||
|
||||
/// Current slot number.
|
||||
pub CurrentSlot get(current_slot): u64;
|
||||
|
||||
/// The epoch randomness for the *current* epoch.
|
||||
///
|
||||
@@ -129,10 +140,16 @@ decl_storage! {
|
||||
/// (like everything else on-chain) it is public. For example, it can be
|
||||
/// used where a number is needed that cannot have been chosen by an
|
||||
/// adversary, for purposes such as public-coin zero-knowledge proofs.
|
||||
pub Randomness get(randomness): [u8; RANDOMNESS_LENGTH];
|
||||
// NOTE: the following fields don't use the constants to define the
|
||||
// array size because the metadata API currently doesn't resolve the
|
||||
// variable to its underlying value.
|
||||
pub Randomness get(randomness): [u8; 32 /* RANDOMNESS_LENGTH */];
|
||||
|
||||
/// Current epoch index
|
||||
EpochIndex: u64;
|
||||
/// Next epoch randomness.
|
||||
NextRandomness: [u8; 32 /* RANDOMNESS_LENGTH */];
|
||||
|
||||
/// Randomness under construction.
|
||||
UnderConstruction: [u8; 32 /* VRF_OUTPUT_LENGTH */];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,7 +158,7 @@ decl_module! {
|
||||
pub struct Module<T: Trait> for enum Call where origin: T::Origin {
|
||||
/// Initialization
|
||||
fn on_initialize() {
|
||||
for i in Self::get_inherent_digests()
|
||||
for digest in Self::get_inherent_digests()
|
||||
.logs
|
||||
.iter()
|
||||
.filter_map(|s| s.as_pre_runtime())
|
||||
@@ -149,9 +166,15 @@ decl_module! {
|
||||
RawBabePreDigest::decode(&mut data)
|
||||
} else {
|
||||
None
|
||||
}) {
|
||||
})
|
||||
{
|
||||
if EpochStartSlot::get() == 0 {
|
||||
EpochStartSlot::put(digest.slot_number);
|
||||
}
|
||||
|
||||
CurrentSlot::put(digest.slot_number);
|
||||
Self::deposit_vrf_output(&digest.vrf_output);
|
||||
|
||||
Self::deposit_vrf_output(&i.vrf_output);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -180,7 +203,7 @@ impl<T: Trait> FindAuthor<u64> for Module<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: timestamp::Trait> IsMember<AuthorityId> for Module<T> {
|
||||
impl<T: Trait> IsMember<AuthorityId> for Module<T> {
|
||||
fn is_member(authority_id: &AuthorityId) -> bool {
|
||||
<Module<T>>::authorities()
|
||||
.iter()
|
||||
@@ -188,6 +211,13 @@ impl<T: timestamp::Trait> IsMember<AuthorityId> for Module<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Trait> session::ShouldEndSession<T::BlockNumber> for Module<T> {
|
||||
fn should_end_session(_: T::BlockNumber) -> bool {
|
||||
let diff = CurrentSlot::get().saturating_sub(EpochStartSlot::get());
|
||||
diff >= T::EpochDuration::get()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Trait> Module<T> {
|
||||
/// Determine the BABE slot duration based on the Timestamp module configuration.
|
||||
pub fn slot_duration() -> T::Moment {
|
||||
@@ -205,23 +235,17 @@ impl<T: Trait> Module<T> {
|
||||
<system::Module<T>>::digest()
|
||||
}
|
||||
|
||||
fn change_epoch(new: Epoch) {
|
||||
Authorities::put(&new.authorities);
|
||||
Randomness::put(&new.randomness);
|
||||
Self::deposit_consensus(ConsensusLog::NextEpochData(new))
|
||||
}
|
||||
|
||||
fn deposit_vrf_output(vrf_output: &[u8; VRF_OUTPUT_LENGTH]) {
|
||||
UnderConstruction::mutate(|z| z.iter_mut().zip(vrf_output).for_each(|(x, y)| *x^=y))
|
||||
}
|
||||
|
||||
/// Call this function exactly once when an epoch changes, to update the
|
||||
/// randomness. Returns the new randomness.
|
||||
fn randomness_change_epoch(epoch_index: u64) -> [u8; RANDOMNESS_LENGTH] {
|
||||
fn randomness_change_epoch(next_epoch_index: u64) -> [u8; RANDOMNESS_LENGTH] {
|
||||
let this_randomness = NextRandomness::get();
|
||||
let next_randomness = compute_randomness(
|
||||
this_randomness,
|
||||
epoch_index,
|
||||
next_epoch_index,
|
||||
UnderConstruction::get(),
|
||||
);
|
||||
UnderConstruction::put(&[0; RANDOMNESS_LENGTH]);
|
||||
@@ -235,13 +259,9 @@ impl<T: Trait> OnTimestampSet<T::Moment> for Module<T> {
|
||||
fn on_timestamp_set(_moment: T::Moment) { }
|
||||
}
|
||||
|
||||
pub trait Duration {
|
||||
fn babe_epoch_duration() -> u64;
|
||||
}
|
||||
|
||||
impl<T: Trait + staking::Trait + Duration> session::OneSessionHandler<T::AccountId> for Module<T> {
|
||||
impl<T: Trait + staking::Trait> session::OneSessionHandler<T::AccountId> for Module<T> {
|
||||
type Key = AuthorityId;
|
||||
fn on_new_session<'a, I: 'a>(_changed: bool, _validators: I, queued_validators: I)
|
||||
fn on_new_session<'a, I: 'a>(_changed: bool, validators: I, queued_validators: I)
|
||||
where I: Iterator<Item=(&'a T::AccountId, AuthorityId)>
|
||||
{
|
||||
use staking::BalanceOf;
|
||||
@@ -249,25 +269,63 @@ impl<T: Trait + staking::Trait + Duration> session::OneSessionHandler<T::Account
|
||||
<T::CurrencyToVote as Convert<BalanceOf<T>, u64>>::convert(b)
|
||||
};
|
||||
|
||||
// Update epoch index
|
||||
let epoch_index = EpochIndex::get()
|
||||
.checked_add(1)
|
||||
.expect("epoch indices will never reach 2^64 before the death of the universe; qed");
|
||||
|
||||
EpochIndex::put(epoch_index);
|
||||
|
||||
// *Next* epoch's authorities.
|
||||
let authorities = queued_validators.map(|(account, k)| {
|
||||
// Update authorities.
|
||||
let authorities = validators.map(|(account, k)| {
|
||||
(k, to_votes(staking::Module::<T>::stakers(account).total))
|
||||
}).collect::<Vec<_>>();
|
||||
|
||||
// What was the next epoch is now the current epoch
|
||||
let randomness = Self::randomness_change_epoch(epoch_index);
|
||||
Self::change_epoch(Epoch {
|
||||
randomness,
|
||||
authorities,
|
||||
epoch_index,
|
||||
duration: T::babe_epoch_duration(),
|
||||
})
|
||||
Authorities::put(authorities);
|
||||
|
||||
// Update epoch start slot.
|
||||
let now = CurrentSlot::get();
|
||||
EpochStartSlot::mutate(|previous| {
|
||||
loop {
|
||||
// on the first epoch we must account for skipping at least one
|
||||
// whole epoch, in case the first block is authored with a slot
|
||||
// number far in the past.
|
||||
if now.saturating_sub(*previous) < T::EpochDuration::get() {
|
||||
break;
|
||||
}
|
||||
|
||||
*previous = previous.saturating_add(T::EpochDuration::get());
|
||||
}
|
||||
});
|
||||
|
||||
// Update epoch randomness.
|
||||
let next_epoch_index = epoch_index
|
||||
.checked_add(1)
|
||||
.expect("epoch indices will never reach 2^64 before the death of the universe; qed");
|
||||
|
||||
// Returns randomness for the current epoch and computes the *next*
|
||||
// epoch randomness.
|
||||
let randomness = Self::randomness_change_epoch(next_epoch_index);
|
||||
Randomness::put(randomness);
|
||||
|
||||
// After we update the current epoch, we signal the *next* epoch change
|
||||
// so that nodes can track changes.
|
||||
let next_authorities = queued_validators.map(|(account, k)| {
|
||||
(k, to_votes(staking::Module::<T>::stakers(account).total))
|
||||
}).collect::<Vec<_>>();
|
||||
|
||||
let next_epoch_start_slot = EpochStartSlot::get().saturating_add(T::EpochDuration::get());
|
||||
let next_randomness = NextRandomness::get();
|
||||
|
||||
let next = Epoch {
|
||||
epoch_index: next_epoch_index,
|
||||
start_slot: next_epoch_start_slot,
|
||||
duration: T::EpochDuration::get(),
|
||||
authorities: next_authorities,
|
||||
randomness: next_randomness,
|
||||
};
|
||||
|
||||
Self::deposit_consensus(ConsensusLog::NextEpochData(next))
|
||||
}
|
||||
|
||||
fn on_disabled(i: usize) {
|
||||
@@ -304,6 +362,7 @@ impl<T: Trait> ProvideInherent for Module<T> {
|
||||
|
||||
let timestamp_based_slot = (timestamp / Self::slot_duration()).saturated_into::<u64>();
|
||||
let seal_slot = data.babe_inherent_data()?;
|
||||
|
||||
if timestamp_based_slot == seal_slot {
|
||||
Ok(())
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user