mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-04-28 09:47:56 +00:00
BABE Randomness using PreRuntime digests (#2929)
* Initial work on exposing pre-runtime digests
This provides the primitive API, as well as exposing it from BABE.
* Initial work on using pre-digests in runtimes
This includes both code to expose them from `srml_system`, as well as
using it in (currently dead) code in `srml_babe`.
* Bump `{spec,impl}_version`
* Add `u64_backend` feature to curve25519-dalek
Otherwise, it errors out at compile-time.
* Bump `Cargo.lock`
* Do not depend on the schnorrkel crate in the runtime
The schnorrkel crate does not work on `#![no_std]`, but the runtime only
needs constants from it. This adds our own definitions of those
constants, and checks them for correctness at compile-time.
* Actually implement storage of VRF outputs
* Trivial formatting change
* Provide a `hash_randomness` function in BABE
for processing VRF outputs.
* Implement a basic randomness generating function
It just XORs the VRF outputs together.
* Actually implement on-chain randomness
Blake2b is used for hashing.
* Update dependencies
* Run `cargo update` where needed
* Re-add a newline at EOF
* Remove broken and unsafe code
XOR is not a hash function, and must not be used as such. The
implementation was also needlessly unsafe.
* Run `cargo update` where needed
* Remove spurious dependency
* Document security guarantees of BABE randomness
* Add a `RandomnessBeacon` trait
* Document `RandomnessBeacon::random`
* Fix silly compile error (unexpected type arguments)
* Fix BABE randomness
* Implement `FindAuthor` for `babe::Module`
* Apply suggestions from code review
Co-Authored-By: Bastian Köcher <bkchr@users.noreply.github.com>
Co-Authored-By: Robert Habermeier <rphmeier@gmail.com>
* Respond to suggestions from code review and fix bugs
* Store an authority index, not the authority itself.
* Avoid unnecessary decoding.
* Implement relative slots and BABE randomness fully and correctly.
* Remove spurious dependency
* Fix error reported by rust-analyzer
* Update Cargo.lock files
* `wrapping_add` → `checked_add`
The epoch index will not overflow. Panic if it does.
* Move randomness documentation to trait
* Fix compile error in test suite
* Explain 2^64 limit
Co-Authored-By: Robert Habermeier <rphmeier@gmail.com>
This commit is contained in:
committed by
Gavin Wood
parent
dcb1a590e2
commit
81d8a5d01d
@@ -48,10 +48,6 @@ pub trait SlotWorker<B: Block> {
|
||||
/// triggered.
|
||||
type OnSlot: IntoFuture<Item = (), Error = consensus_common::Error>;
|
||||
|
||||
/// Called when the proposer starts.
|
||||
#[deprecated(note = "Not called. Please perform any initialization before calling start_slot_worker.")]
|
||||
fn on_start(&self, _slot_duration: u64) -> Result<(), consensus_common::Error> { Ok(()) }
|
||||
|
||||
/// Called when a new slot is triggered.
|
||||
fn on_slot(&self, chain_head: B::Header, slot_info: SlotInfo) -> Self::OnSlot;
|
||||
}
|
||||
@@ -60,8 +56,13 @@ pub trait SlotWorker<B: Block> {
|
||||
pub trait SlotCompatible {
|
||||
/// Extract timestamp and slot from inherent data.
|
||||
fn extract_timestamp_and_slot(
|
||||
&self,
|
||||
inherent: &InherentData,
|
||||
) -> Result<(u64, u64), consensus_common::Error>;
|
||||
) -> Result<(u64, u64, std::time::Duration), consensus_common::Error>;
|
||||
|
||||
/// Get the difference between chain time and local time. Defaults to
|
||||
/// always returning zero.
|
||||
fn time_offset() -> SignedDuration { Default::default() }
|
||||
}
|
||||
|
||||
/// Start a new slot worker.
|
||||
@@ -74,6 +75,7 @@ pub fn start_slot_worker<B, C, W, T, SO, SC>(
|
||||
worker: W,
|
||||
sync_oracle: SO,
|
||||
inherent_data_providers: InherentDataProviders,
|
||||
timestamp_extractor: SC,
|
||||
) -> impl Future<Item = (), Error = ()>
|
||||
where
|
||||
B: Block,
|
||||
@@ -86,8 +88,11 @@ where
|
||||
let SlotDuration(slot_duration) = slot_duration;
|
||||
|
||||
// rather than use a timer interval, we schedule our waits ourselves
|
||||
let mut authorship = Slots::<SC>::new(slot_duration.slot_duration(), inherent_data_providers)
|
||||
.map_err(|e| debug!(target: "slots", "Faulty timer: {:?}", e))
|
||||
let mut authorship = Slots::<SC>::new(
|
||||
slot_duration.slot_duration(),
|
||||
inherent_data_providers,
|
||||
timestamp_extractor,
|
||||
).map_err(|e| debug!(target: "slots", "Faulty timer: {:?}", e))
|
||||
.for_each(move |slot_info| {
|
||||
// only propose when we are not syncing.
|
||||
if sync_oracle.is_major_syncing() {
|
||||
|
||||
@@ -24,7 +24,6 @@ use futures::prelude::*;
|
||||
use futures::try_ready;
|
||||
use inherents::{InherentData, InherentDataProviders};
|
||||
|
||||
use std::marker::PhantomData;
|
||||
use std::time::{Duration, Instant};
|
||||
use tokio_timer::Delay;
|
||||
|
||||
@@ -55,11 +54,11 @@ impl SignedDuration {
|
||||
|
||||
/// Get the slot for now. Panics if `slot_duration` is 0.
|
||||
pub fn slot_now(&self, slot_duration: u64) -> u64 {
|
||||
if self.is_positive {
|
||||
(if self.is_positive {
|
||||
duration_now() + self.offset
|
||||
} else {
|
||||
duration_now() - self.offset
|
||||
}.as_secs() / slot_duration
|
||||
}.as_secs()) / slot_duration
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,18 +101,22 @@ pub struct Slots<SC> {
|
||||
slot_duration: u64,
|
||||
inner_delay: Option<Delay>,
|
||||
inherent_data_providers: InherentDataProviders,
|
||||
_marker: PhantomData<SC>,
|
||||
timestamp_extractor: SC,
|
||||
}
|
||||
|
||||
impl<SC> Slots<SC> {
|
||||
/// Create a new `Slots` stream.
|
||||
pub fn new(slot_duration: u64, inherent_data_providers: InherentDataProviders) -> Self {
|
||||
pub fn new(
|
||||
slot_duration: u64,
|
||||
inherent_data_providers: InherentDataProviders,
|
||||
timestamp_extractor: SC,
|
||||
) -> Self {
|
||||
Slots {
|
||||
last_slot: 0,
|
||||
slot_duration,
|
||||
inner_delay: None,
|
||||
inherent_data_providers,
|
||||
_marker: PhantomData,
|
||||
timestamp_extractor,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -123,49 +126,49 @@ impl<SC: SlotCompatible> Stream for Slots<SC> {
|
||||
type Error = Error;
|
||||
|
||||
fn poll(&mut self) -> Poll<Option<SlotInfo>, Self::Error> {
|
||||
let slot_duration = self.slot_duration;
|
||||
self.inner_delay = match self.inner_delay.take() {
|
||||
None => {
|
||||
// schedule wait.
|
||||
let wait_until = Instant::now() + time_until_next(duration_now(), slot_duration);
|
||||
Some(Delay::new(wait_until))
|
||||
loop {
|
||||
let slot_duration = self.slot_duration;
|
||||
self.inner_delay = match self.inner_delay.take() {
|
||||
None => {
|
||||
// schedule wait.
|
||||
let wait_until = Instant::now() + time_until_next(duration_now(), slot_duration);
|
||||
Some(Delay::new(wait_until))
|
||||
}
|
||||
Some(d) => Some(d),
|
||||
};
|
||||
|
||||
if let Some(ref mut inner_delay) = self.inner_delay {
|
||||
try_ready!(inner_delay
|
||||
.poll()
|
||||
.map_err(Error::FaultyTimer));
|
||||
}
|
||||
Some(d) => Some(d),
|
||||
};
|
||||
|
||||
if let Some(ref mut inner_delay) = self.inner_delay {
|
||||
try_ready!(inner_delay
|
||||
.poll()
|
||||
.map_err(Error::FaultyTimer));
|
||||
}
|
||||
// timeout has fired.
|
||||
|
||||
// timeout has fired.
|
||||
let inherent_data = self
|
||||
.inherent_data_providers
|
||||
.create_inherent_data()
|
||||
.map_err(|s| consensus_common::Error::InherentData(s.into_owned()))?;
|
||||
let (timestamp, slot_num, offset) = self
|
||||
.timestamp_extractor
|
||||
.extract_timestamp_and_slot(&inherent_data)?;
|
||||
// reschedule delay for next slot.
|
||||
let ends_at = Instant::now() + offset +
|
||||
time_until_next(Duration::from_secs(timestamp), slot_duration);
|
||||
self.inner_delay = Some(Delay::new(ends_at));
|
||||
|
||||
let inherent_data = self
|
||||
.inherent_data_providers
|
||||
.create_inherent_data()
|
||||
.map_err(|s| consensus_common::Error::InherentData(s.into_owned()))?;
|
||||
let (timestamp, slot_num) = SC::extract_timestamp_and_slot(&inherent_data)?;
|
||||
// never yield the same slot twice.
|
||||
if slot_num > self.last_slot {
|
||||
self.last_slot = slot_num;
|
||||
|
||||
// reschedule delay for next slot.
|
||||
let ends_at =
|
||||
Instant::now() + time_until_next(Duration::from_secs(timestamp), slot_duration);
|
||||
self.inner_delay = Some(Delay::new(ends_at));
|
||||
|
||||
// never yield the same slot twice.
|
||||
if slot_num > self.last_slot {
|
||||
self.last_slot = slot_num;
|
||||
|
||||
Ok(Async::Ready(Some(SlotInfo {
|
||||
number: slot_num,
|
||||
duration: self.slot_duration,
|
||||
timestamp,
|
||||
ends_at,
|
||||
inherent_data,
|
||||
})))
|
||||
} else {
|
||||
// re-poll until we get a new slot.
|
||||
self.poll()
|
||||
break Ok(Async::Ready(Some(SlotInfo {
|
||||
number: slot_num,
|
||||
duration: self.slot_duration,
|
||||
timestamp,
|
||||
ends_at,
|
||||
inherent_data,
|
||||
})))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user