mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-09 20:11:09 +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
Generated
+450
-399
File diff suppressed because it is too large
Load Diff
@@ -117,12 +117,14 @@ struct AuraSlotCompatible;
|
||||
|
||||
impl SlotCompatible for AuraSlotCompatible {
|
||||
fn extract_timestamp_and_slot(
|
||||
&self,
|
||||
data: &InherentData
|
||||
) -> Result<(TimestampInherent, AuraInherent), consensus_common::Error> {
|
||||
) -> Result<(TimestampInherent, AuraInherent, std::time::Duration), consensus_common::Error> {
|
||||
data.timestamp_inherent_data()
|
||||
.and_then(|t| data.aura_inherent_data().map(|a| (t, a)))
|
||||
.map_err(Into::into)
|
||||
.map_err(consensus_common::Error::InherentData)
|
||||
.map(|(x, y)| (x, y, Default::default()))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -170,7 +172,8 @@ pub fn start_aura<B, C, SC, E, I, P, SO, Error, H>(
|
||||
select_chain,
|
||||
worker,
|
||||
sync_oracle,
|
||||
inherent_data_providers
|
||||
inherent_data_providers,
|
||||
AuraSlotCompatible,
|
||||
))
|
||||
}
|
||||
|
||||
@@ -514,7 +517,7 @@ impl<B: Block, C, P> Verifier<B> for AuraVerifier<C, P> where
|
||||
mut body: Option<Vec<B::Extrinsic>>,
|
||||
) -> Result<(ImportBlock<B>, Option<Vec<(CacheKeyId, Vec<u8>)>>), String> {
|
||||
let mut inherent_data = self.inherent_data_providers.create_inherent_data().map_err(String::from)?;
|
||||
let (timestamp_now, slot_now) = AuraSlotCompatible::extract_timestamp_and_slot(&inherent_data)
|
||||
let (timestamp_now, slot_now, _) = AuraSlotCompatible.extract_timestamp_and_slot(&inherent_data)
|
||||
.map_err(|e| format!("Could not extract timestamp and slot: {:?}", e))?;
|
||||
let hash = header.hash();
|
||||
let parent_hash = *header.parent_hash();
|
||||
|
||||
@@ -31,6 +31,15 @@ pub type AuthorityId = Public;
|
||||
/// The `ConsensusEngineId` of BABE.
|
||||
pub const BABE_ENGINE_ID: ConsensusEngineId = *b"BABE";
|
||||
|
||||
/// The length of the VRF output
|
||||
pub const VRF_OUTPUT_LENGTH: usize = 32;
|
||||
|
||||
/// The length of the VRF proof
|
||||
pub const VRF_PROOF_LENGTH: usize = 64;
|
||||
|
||||
/// The length of the public key
|
||||
pub const PUBLIC_KEY_LENGTH: usize = 32;
|
||||
|
||||
/// Configuration data used by the BABE consensus engine.
|
||||
#[derive(Copy, Clone, Hash, PartialEq, Eq, Debug, Encode, Decode)]
|
||||
pub struct BabeConfiguration {
|
||||
|
||||
@@ -16,15 +16,12 @@
|
||||
|
||||
//! Private implementation details of BABE digests.
|
||||
|
||||
use primitives::sr25519::{Public, Signature};
|
||||
use babe_primitives::BABE_ENGINE_ID;
|
||||
use primitives::sr25519::Signature;
|
||||
use babe_primitives::{self, BABE_ENGINE_ID};
|
||||
use runtime_primitives::{DigestItem, generic::OpaqueDigestItemId};
|
||||
use std::fmt::Debug;
|
||||
use parity_codec::{Decode, Encode, Codec, Input};
|
||||
use schnorrkel::{
|
||||
vrf::{VRFProof, VRFOutput, VRF_OUTPUT_LENGTH, VRF_PROOF_LENGTH},
|
||||
PUBLIC_KEY_LENGTH,
|
||||
};
|
||||
use schnorrkel::{vrf::{VRFProof, VRFOutput, VRF_OUTPUT_LENGTH, VRF_PROOF_LENGTH}};
|
||||
|
||||
/// A BABE pre-digest. It includes:
|
||||
///
|
||||
@@ -36,26 +33,26 @@ use schnorrkel::{
|
||||
pub struct BabePreDigest {
|
||||
pub(super) vrf_output: VRFOutput,
|
||||
pub(super) proof: VRFProof,
|
||||
pub(super) author: Public,
|
||||
pub(super) index: u64,
|
||||
pub(super) slot_num: u64,
|
||||
}
|
||||
|
||||
/// The prefix used by BABE for its VRF keys.
|
||||
pub const BABE_VRF_PREFIX: &'static [u8] = b"substrate-babe-vrf";
|
||||
|
||||
type TmpDecode = (
|
||||
type RawBabePreDigest = (
|
||||
[u8; VRF_OUTPUT_LENGTH],
|
||||
[u8; VRF_PROOF_LENGTH],
|
||||
[u8; PUBLIC_KEY_LENGTH],
|
||||
u64,
|
||||
u64,
|
||||
);
|
||||
|
||||
impl Encode for BabePreDigest {
|
||||
fn encode(&self) -> Vec<u8> {
|
||||
let tmp: TmpDecode = (
|
||||
let tmp: RawBabePreDigest = (
|
||||
*self.vrf_output.as_bytes(),
|
||||
self.proof.to_bytes(),
|
||||
self.author.0,
|
||||
self.index,
|
||||
self.slot_num,
|
||||
);
|
||||
parity_codec::Encode::encode(&tmp)
|
||||
@@ -64,11 +61,15 @@ impl Encode for BabePreDigest {
|
||||
|
||||
impl Decode for BabePreDigest {
|
||||
fn decode<R: Input>(i: &mut R) -> Option<Self> {
|
||||
let (output, proof, public_key, slot_num): TmpDecode = Decode::decode(i)?;
|
||||
let (output, proof, index, slot_num): RawBabePreDigest = Decode::decode(i)?;
|
||||
|
||||
// Verify (at compile time) that the sizes in babe_primitives are correct
|
||||
let _: [u8; babe_primitives::VRF_OUTPUT_LENGTH] = output;
|
||||
let _: [u8; babe_primitives::VRF_PROOF_LENGTH] = proof;
|
||||
Some(BabePreDigest {
|
||||
proof: VRFProof::from_bytes(&proof).ok()?,
|
||||
vrf_output: VRFOutput::from_bytes(&output).ok()?,
|
||||
author: Public(public_key),
|
||||
index,
|
||||
slot_num,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -23,7 +23,8 @@
|
||||
//! This crate is highly unstable and experimental. Breaking changes may
|
||||
//! happen at any point. This crate is also missing features, such as banning
|
||||
//! of malicious validators, that are essential for a production network.
|
||||
#![forbid(unsafe_code, missing_docs)]
|
||||
#![forbid(unsafe_code, missing_docs, unused_must_use)]
|
||||
#![cfg_attr(not(test), forbid(dead_code))]
|
||||
extern crate core;
|
||||
mod digest;
|
||||
use digest::CompatibleDigestItem;
|
||||
@@ -120,17 +121,17 @@ impl Config {
|
||||
}
|
||||
}
|
||||
|
||||
struct BabeSlotCompatible;
|
||||
|
||||
impl SlotCompatible for BabeSlotCompatible {
|
||||
impl SlotCompatible for BabeLink {
|
||||
fn extract_timestamp_and_slot(
|
||||
data: &InherentData
|
||||
) -> Result<(TimestampInherent, u64), consensus_common::Error> {
|
||||
&self,
|
||||
data: &InherentData,
|
||||
) -> Result<(TimestampInherent, u64, std::time::Duration), consensus_common::Error> {
|
||||
trace!(target: "babe", "extract timestamp");
|
||||
data.timestamp_inherent_data()
|
||||
.and_then(|t| data.babe_inherent_data().map(|a| (t, a)))
|
||||
.map_err(Into::into)
|
||||
.map_err(consensus_common::Error::InherentData)
|
||||
.map(|(x, y)| (x, y, self.0.lock().0.take().unwrap_or_default()))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,6 +165,9 @@ pub struct BabeParams<C, E, I, SO, SC> {
|
||||
|
||||
/// Force authoring of blocks even if we are offline
|
||||
pub force_authoring: bool,
|
||||
|
||||
/// The source of timestamps for relative slots
|
||||
pub time_source: BabeLink,
|
||||
}
|
||||
|
||||
/// Start the babe worker. The returned future should be run in a tokio runtime.
|
||||
@@ -177,6 +181,7 @@ pub fn start_babe<B, C, SC, E, I, SO, Error, H>(BabeParams {
|
||||
sync_oracle,
|
||||
inherent_data_providers,
|
||||
force_authoring,
|
||||
time_source,
|
||||
}: BabeParams<C, E, I, SO, SC>) -> Result<
|
||||
impl Future<Item=(), Error=()>,
|
||||
consensus_common::Error,
|
||||
@@ -203,12 +208,13 @@ pub fn start_babe<B, C, SC, E, I, SO, Error, H>(BabeParams {
|
||||
threshold: config.threshold(),
|
||||
};
|
||||
register_babe_inherent_data_provider(&inherent_data_providers, config.0.slot_duration())?;
|
||||
Ok(slots::start_slot_worker::<_, _, _, _, _, BabeSlotCompatible>(
|
||||
Ok(slots::start_slot_worker::<_, _, _, _, _, _>(
|
||||
config.0,
|
||||
select_chain,
|
||||
worker,
|
||||
sync_oracle,
|
||||
inherent_data_providers
|
||||
inherent_data_providers,
|
||||
time_source,
|
||||
))
|
||||
}
|
||||
|
||||
@@ -279,7 +285,7 @@ impl<Hash, H, B, C, E, I, Error, SO> SlotWorker<B> for BabeWorker<C, E, I, SO> w
|
||||
// FIXME replace the dummy empty slices with real data
|
||||
// https://github.com/paritytech/substrate/issues/2435
|
||||
// https://github.com/paritytech/substrate/issues/2436
|
||||
let proposal_work = if let Some((inout, proof, _batchable_proof)) = claim_slot(
|
||||
let proposal_work = if let Some(((inout, proof, _batchable_proof), index)) = claim_slot(
|
||||
&[0u8; 0],
|
||||
slot_info.number,
|
||||
&[0u8; 0],
|
||||
@@ -312,7 +318,7 @@ impl<Hash, H, B, C, E, I, Error, SO> SlotWorker<B> for BabeWorker<C, E, I, SO> w
|
||||
let inherent_digest = BabePreDigest {
|
||||
proof,
|
||||
vrf_output: inout.to_output(),
|
||||
author: pair.public(),
|
||||
index: index as u64,
|
||||
slot_num,
|
||||
};
|
||||
|
||||
@@ -459,17 +465,17 @@ fn check_header<B: Block + Sized, C: AuxStore>(
|
||||
})?;
|
||||
|
||||
let pre_digest = find_pre_digest::<B>(&header)?;
|
||||
let BabePreDigest { slot_num, ref author, ref proof, ref vrf_output } = pre_digest;
|
||||
let BabePreDigest { slot_num, index, ref proof, ref vrf_output } = pre_digest;
|
||||
|
||||
if slot_num > slot_now {
|
||||
header.digest_mut().push(seal);
|
||||
Ok(CheckedHeader::Deferred(header, slot_num))
|
||||
} else if !authorities.contains(&author) {
|
||||
} else if index > authorities.len() as u64 {
|
||||
Err(babe_err!("Slot author not found"))
|
||||
} else {
|
||||
let pre_hash = header.hash();
|
||||
let (pre_hash, author): (_, &sr25519::Public) = (header.hash(), &authorities[index as usize]);
|
||||
|
||||
if sr25519::Pair::verify(&sig, pre_hash, author) {
|
||||
if sr25519::Pair::verify(&sig, pre_hash, author.clone()) {
|
||||
let (inout, _batchable_proof) = {
|
||||
let transcript = make_transcript(
|
||||
Default::default(),
|
||||
@@ -513,12 +519,16 @@ fn check_header<B: Block + Sized, C: AuxStore>(
|
||||
}
|
||||
}
|
||||
|
||||
/// State that must be shared between the import queue and the authoring logic.
|
||||
#[derive(Default, Clone, Debug)]
|
||||
pub struct BabeLink(Arc<Mutex<(Option<Duration>, Vec<(Instant, u64)>)>>);
|
||||
|
||||
/// A verifier for Babe blocks.
|
||||
pub struct BabeVerifier<C> {
|
||||
client: Arc<C>,
|
||||
inherent_data_providers: inherents::InherentDataProviders,
|
||||
config: Config,
|
||||
timestamps: Mutex<(Option<Duration>, Vec<(Instant, u64)>)>,
|
||||
time_source: BabeLink,
|
||||
}
|
||||
|
||||
impl<C> BabeVerifier<C> {
|
||||
@@ -551,11 +561,11 @@ fn median_algorithm(
|
||||
slot_duration: u64,
|
||||
slot_num: u64,
|
||||
slot_now: u64,
|
||||
timestamps: &mut (Option<Duration>, Vec<(Instant, u64)>),
|
||||
time_source: &mut (Option<Duration>, Vec<(Instant, u64)>),
|
||||
) {
|
||||
let num_timestamps = timestamps.1.len();
|
||||
let num_timestamps = time_source.1.len();
|
||||
if num_timestamps as u64 >= median_required_blocks && median_required_blocks > 0 {
|
||||
let mut new_list: Vec<_> = timestamps.1.iter().map(|&(t, sl)| {
|
||||
let mut new_list: Vec<_> = time_source.1.iter().map(|&(t, sl)| {
|
||||
let offset: u128 = u128::from(slot_duration)
|
||||
.checked_mul(1_000_000u128) // self.config.get() returns *milliseconds*
|
||||
.and_then(|x| x.checked_mul(u128::from(slot_num).saturating_sub(u128::from(sl))))
|
||||
@@ -570,11 +580,11 @@ fn median_algorithm(
|
||||
let &median = new_list
|
||||
.get(num_timestamps / 2)
|
||||
.expect("we have at least one timestamp, so this is a valid index; qed");
|
||||
timestamps.1.clear();
|
||||
time_source.1.clear();
|
||||
// FIXME #2927: pass this to the block authoring logic somehow
|
||||
timestamps.0.replace(Instant::now() - median);
|
||||
time_source.0.replace(Instant::now() - median);
|
||||
} else {
|
||||
timestamps.1.push((Instant::now(), slot_now))
|
||||
time_source.1.push((Instant::now(), slot_now))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -604,7 +614,7 @@ impl<B: Block, C> Verifier<B> for BabeVerifier<C> where
|
||||
.inherent_data_providers
|
||||
.create_inherent_data()
|
||||
.map_err(String::from)?;
|
||||
let (_, slot_now) = BabeSlotCompatible::extract_timestamp_and_slot(&inherent_data)
|
||||
let (_, slot_now, _) = self.time_source.extract_timestamp_and_slot(&inherent_data)
|
||||
.map_err(|e| format!("Could not extract timestamp and slot: {:?}", e))?;
|
||||
let hash = header.hash();
|
||||
let parent_hash = *header.parent_hash();
|
||||
@@ -672,7 +682,7 @@ impl<B: Block, C> Verifier<B> for BabeVerifier<C> where
|
||||
self.config.get(),
|
||||
slot_num,
|
||||
slot_now,
|
||||
&mut *self.timestamps.lock(),
|
||||
&mut *self.time_source.0.lock(),
|
||||
);
|
||||
// FIXME #1019 extract authorities
|
||||
Ok((import_block, maybe_keys))
|
||||
@@ -765,8 +775,9 @@ fn claim_slot(
|
||||
authorities: &[AuthorityId],
|
||||
key: &sr25519::Pair,
|
||||
threshold: u64,
|
||||
) -> Option<(VRFInOut, VRFProof, VRFProofBatchable)> {
|
||||
if !authorities.contains(&key.public()) { return None }
|
||||
) -> Option<((VRFInOut, VRFProof, VRFProofBatchable), usize)> {
|
||||
let public = &key.public();
|
||||
let index = authorities.iter().position(|s| s == public)?;
|
||||
let transcript = make_transcript(
|
||||
randomness,
|
||||
slot_number,
|
||||
@@ -780,7 +791,9 @@ fn claim_slot(
|
||||
// be empty. Therefore, this division is safe.
|
||||
let threshold = threshold / authorities.len() as u64;
|
||||
|
||||
get_keypair(key).vrf_sign_n_check(transcript, |inout| check(inout, threshold))
|
||||
get_keypair(key)
|
||||
.vrf_sign_n_check(transcript, |inout| check(inout, threshold))
|
||||
.map(|s|(s, index))
|
||||
}
|
||||
|
||||
fn initialize_authorities_cache<B, C>(client: &C) -> Result<(), ConsensusError> where
|
||||
@@ -822,7 +835,7 @@ pub fn import_queue<B, C, E>(
|
||||
finality_proof_request_builder: Option<SharedFinalityProofRequestBuilder<B>>,
|
||||
client: Arc<C>,
|
||||
inherent_data_providers: InherentDataProviders,
|
||||
) -> Result<BabeImportQueue<B>, consensus_common::Error> where
|
||||
) -> Result<(BabeImportQueue<B>, BabeLink), consensus_common::Error> where
|
||||
B: Block,
|
||||
C: 'static + ProvideRuntimeApi + ProvideCache<B> + Send + Sync + AuxStore,
|
||||
C::Api: BlockBuilderApi<B> + BabeApi<B>,
|
||||
@@ -832,28 +845,27 @@ pub fn import_queue<B, C, E>(
|
||||
register_babe_inherent_data_provider(&inherent_data_providers, config.get())?;
|
||||
initialize_authorities_cache(&*client)?;
|
||||
|
||||
let verifier = Arc::new(
|
||||
BabeVerifier {
|
||||
client: client,
|
||||
inherent_data_providers,
|
||||
timestamps: Default::default(),
|
||||
config,
|
||||
}
|
||||
);
|
||||
Ok(BasicQueue::new(
|
||||
verifier,
|
||||
let verifier = BabeVerifier {
|
||||
client: client,
|
||||
inherent_data_providers,
|
||||
time_source: Default::default(),
|
||||
config,
|
||||
};
|
||||
let timestamp_core = verifier.time_source.clone();
|
||||
Ok((BasicQueue::new(
|
||||
Arc::new(verifier),
|
||||
block_import,
|
||||
justification_import,
|
||||
finality_proof_import,
|
||||
finality_proof_request_builder,
|
||||
))
|
||||
), timestamp_core))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(dead_code, unused_imports, deprecated)]
|
||||
// FIXME #2532: need to allow deprecated until refactor is done
|
||||
// https://github.com/paritytech/substrate/issues/2532
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(unused_imports, deprecated)]
|
||||
#[cfg_attr(test, allow(dead_code))]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
@@ -947,7 +959,7 @@ mod tests {
|
||||
client,
|
||||
inherent_data_providers,
|
||||
config,
|
||||
timestamps: Default::default(),
|
||||
time_source: Default::default(),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1028,7 +1040,7 @@ mod tests {
|
||||
#[allow(deprecated)]
|
||||
let select_chain = LongestChain::new(client.backend().clone());
|
||||
|
||||
let babe = start_babe(BabeParams {
|
||||
runtime.spawn(start_babe(BabeParams {
|
||||
config,
|
||||
local_key: Arc::new(key.clone().into()),
|
||||
block_import: client.clone(),
|
||||
@@ -1038,9 +1050,8 @@ mod tests {
|
||||
sync_oracle: DummyOracle,
|
||||
inherent_data_providers,
|
||||
force_authoring: false,
|
||||
}).expect("Starts babe");
|
||||
|
||||
runtime.spawn(babe);
|
||||
time_source: Default::default(),
|
||||
}).expect("Starts babe"));
|
||||
}
|
||||
debug!(target: "babe", "checkpoint 5");
|
||||
|
||||
|
||||
@@ -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,
|
||||
})))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Generated
+17
-17
@@ -15,7 +15,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.3.1"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
@@ -33,12 +33,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "hash-db"
|
||||
version = "0.12.2"
|
||||
version = "0.12.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "hash256-std-hasher"
|
||||
version = "0.12.2"
|
||||
version = "0.12.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"crunchy 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -82,7 +82,7 @@ dependencies = [
|
||||
"proc-macro-crate 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.39 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -157,14 +157,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.91"
|
||||
version = "1.0.94"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "sr-io"
|
||||
version = "2.0.0"
|
||||
dependencies = [
|
||||
"hash-db 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"hash-db 0.12.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-codec 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sr-std 2.0.0",
|
||||
@@ -197,9 +197,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
name = "substrate-primitives"
|
||||
version = "2.0.0"
|
||||
dependencies = [
|
||||
"byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"hash-db 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"hash256-std-hasher 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"hash-db 0.12.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"hash256-std-hasher 0.12.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-codec 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"primitive-types 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -209,7 +209,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "0.15.34"
|
||||
version = "0.15.39"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -222,7 +222,7 @@ name = "toml"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -230,7 +230,7 @@ name = "uint"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"crunchy 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
@@ -243,11 +243,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
[metadata]
|
||||
"checksum arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "92c7fb76bc8826a8b33b4ee5bb07a247a81e76764ab4d55e8f73e3a4d8808c71"
|
||||
"checksum autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "0e49efa51329a5fd37e7c79db4621af617cd4e3e5bc224939808d076077077bf"
|
||||
"checksum byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a019b10a2a7cdeb292db131fc8113e57ea2a908f6e7894b0c3c671893b65dbeb"
|
||||
"checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5"
|
||||
"checksum crunchy 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
|
||||
"checksum fixed-hash 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "516877b7b9a1cc2d0293cbce23cd6203f0edbfd4090e6ca4489fecb5aa73050e"
|
||||
"checksum hash-db 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ba7fb417e5c470acdd61068c79767d0e65962e70836cf6c9dfd2409f06345ce0"
|
||||
"checksum hash256-std-hasher 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f8b2027c19ec91eb304999abae7307d225cf93be42af53b0039f76e98ed5af86"
|
||||
"checksum hash-db 0.12.4 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3c95a428c86ed4633d83e07ef9e0a147a906da01e931f07e74a85bedce5a43"
|
||||
"checksum hash256-std-hasher 0.12.4 (registry+https://github.com/rust-lang/crates.io-index)" = "663ce20dae36902c16d12c6aaae400ca40d922407a8cf2b4caf8cae9b39b4f03"
|
||||
"checksum impl-codec 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "62ed8ff267bc916dd848a800b96d3129aec73d5b23a5e3d018c83655d0c55371"
|
||||
"checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945"
|
||||
"checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32"
|
||||
@@ -261,9 +261,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
|
||||
"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
|
||||
"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
|
||||
"checksum serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)" = "a72e9b96fa45ce22a4bc23da3858dfccfd60acd28a25bcd328a98fdd6bea43fd"
|
||||
"checksum serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)" = "076a696fdea89c19d3baed462576b8f6d663064414b5c793642da8dfeb99475b"
|
||||
"checksum static_assertions 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c19be23126415861cb3a23e501d34a708f7f9b2183c5252d690941c2e69199d5"
|
||||
"checksum syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)" = "a1393e4a97a19c01e900df2aec855a29f71cf02c402e2f443b8d2747c25c5dbe"
|
||||
"checksum syn 0.15.39 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d960b829a55e56db167e861ddb43602c003c7be0bee1d345021703fac2fb7c"
|
||||
"checksum toml 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b8c96d7873fa7ef8bdeb3a9cda3ac48389b4154f32b9803b4bc26220b677b039"
|
||||
"checksum uint 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f5375d2c574f89adad4108ad525c93e39669853a602560bf5ed4ca9943b10799"
|
||||
"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
|
||||
|
||||
@@ -19,7 +19,7 @@ hash256-std-hasher = { version = "0.12", default-features = false }
|
||||
ed25519-dalek = { version = "1.0.0-pre.1", optional = true }
|
||||
base58 = { version = "0.1", optional = true }
|
||||
blake2-rfc = { version = "0.2.18", optional = true }
|
||||
schnorrkel = { version = "0.1", optional = true }
|
||||
schnorrkel = { version = "0.1.1", optional = true }
|
||||
rand = { version = "0.6", optional = true }
|
||||
sha2 = { version = "0.8", optional = true }
|
||||
substrate-bip39 = { git = "https://github.com/paritytech/substrate-bip39", optional = true }
|
||||
|
||||
@@ -594,6 +594,21 @@ pub trait MaybeHash {}
|
||||
#[cfg(not(feature = "std"))]
|
||||
impl<T> MaybeHash for T {}
|
||||
|
||||
/// A type that provides a randomness beacon.
|
||||
pub trait RandomnessBeacon {
|
||||
/// Returns 32 bytes of random data. The output will change eventually, but
|
||||
/// is not guaranteed to be different between any two calls.
|
||||
///
|
||||
/// # Security
|
||||
///
|
||||
/// This MUST NOT be used for gambling, as it can be influenced by a
|
||||
/// malicious validator in the short term. It MAY be used in many
|
||||
/// cryptographic protocols, however, so long as one remembers that this
|
||||
/// (like everything else on-chain) 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.
|
||||
fn random() -> [u8; 32];
|
||||
}
|
||||
|
||||
/// A type that can be used in runtime structures.
|
||||
pub trait Member: Send + Sync + Sized + MaybeDebug + Eq + PartialEq + Clone + 'static {}
|
||||
|
||||
+351
-449
File diff suppressed because it is too large
Load Diff
+355
-453
File diff suppressed because it is too large
Load Diff
@@ -63,11 +63,12 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
|
||||
spec_name: create_runtime_str!("node"),
|
||||
impl_name: create_runtime_str!("substrate-node"),
|
||||
authoring_version: 10,
|
||||
// Per convention: if the runtime behavior changes, increment spec_version and set impl_version
|
||||
// to equal spec_version. If only runtime implementation changes and behavior does not, then
|
||||
// leave spec_version as is and increment impl_version.
|
||||
spec_version: 102,
|
||||
impl_version: 104,
|
||||
// Per convention: if the runtime behavior changes, increment spec_version
|
||||
// and set impl_version to equal spec_version. If only runtime
|
||||
// implementation changes and behavior does not, then leave spec_version as
|
||||
// is and increment impl_version.
|
||||
spec_version: 103,
|
||||
impl_version: 103,
|
||||
apis: RUNTIME_API_VERSIONS,
|
||||
};
|
||||
|
||||
|
||||
Generated
+364
-462
File diff suppressed because it is too large
Load Diff
@@ -7,7 +7,7 @@ edition = "2018"
|
||||
[dependencies]
|
||||
hex-literal = "0.1.4"
|
||||
parity-codec = { version = "4.1.1", default-features = false, features = ["derive"] }
|
||||
serde = { version = "1.0.90", optional = true }
|
||||
serde = { version = "1.0.93", optional = true }
|
||||
inherents = { package = "substrate-inherents", path = "../../core/inherents", default-features = false }
|
||||
rstd = { package = "sr-std", path = "../../core/sr-std", default-features = false }
|
||||
primitives = { package = "sr-primitives", path = "../../core/sr-primitives", default-features = false }
|
||||
@@ -16,12 +16,12 @@ system = { package = "srml-system", path = "../system", default-features = false
|
||||
timestamp = { package = "srml-timestamp", path = "../timestamp", default-features = false }
|
||||
session = { package = "srml-session", path = "../session", default-features = false }
|
||||
babe-primitives = { package = "substrate-consensus-babe-primitives", path = "../../core/consensus/babe/primitives", default-features = false }
|
||||
runtime_io = { package = "sr-io", path = "../../core/sr-io", default-features = false }
|
||||
|
||||
[dev-dependencies]
|
||||
lazy_static = "1.3.0"
|
||||
parking_lot = "0.8.0"
|
||||
substrate-primitives = { path = "../../core/primitives" }
|
||||
runtime_io = { package = "sr-io", path = "../../core/sr-io" }
|
||||
|
||||
[features]
|
||||
default = ["std"]
|
||||
@@ -36,4 +36,5 @@ std = [
|
||||
"inherents/std",
|
||||
"babe-primitives/std",
|
||||
"session/std",
|
||||
"runtime_io/std",
|
||||
]
|
||||
|
||||
+101
-13
@@ -17,13 +17,14 @@
|
||||
//! Consensus extension module for BABE consensus.
|
||||
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
#![forbid(unsafe_code)]
|
||||
#![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};
|
||||
use srml_support::{decl_storage, decl_module, StorageValue, traits::FindAuthor};
|
||||
use timestamp::{OnTimestampSet, Trait};
|
||||
use primitives::{generic::DigestItem, traits::{SaturatedConversion, Saturating}};
|
||||
use primitives::{generic::DigestItem, traits::{SaturatedConversion, Saturating, RandomnessBeacon}};
|
||||
use primitives::ConsensusEngineId;
|
||||
#[cfg(feature = "std")]
|
||||
use timestamp::TimestampInherentData;
|
||||
use parity_codec::{Encode, Decode};
|
||||
@@ -31,8 +32,7 @@ use inherents::{RuntimeString, InherentIdentifier, InherentData, ProvideInherent
|
||||
#[cfg(feature = "std")]
|
||||
use inherents::{InherentDataProviders, ProvideInherentData};
|
||||
use babe_primitives::BABE_ENGINE_ID;
|
||||
|
||||
pub use babe_primitives::AuthorityId;
|
||||
pub use babe_primitives::{AuthorityId, VRF_OUTPUT_LENGTH, VRF_PROOF_LENGTH, PUBLIC_KEY_LENGTH};
|
||||
|
||||
/// The BABE inherent identifier.
|
||||
pub const INHERENT_IDENTIFIER: InherentIdentifier = *b"babeslot";
|
||||
@@ -67,6 +67,7 @@ pub struct InherentDataProvider {
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl InherentDataProvider {
|
||||
/// Constructs `Self`
|
||||
pub fn new(slot_duration: u64) -> Self {
|
||||
Self {
|
||||
slot_duration
|
||||
@@ -106,6 +107,9 @@ impl ProvideInherentData for InherentDataProvider {
|
||||
}
|
||||
}
|
||||
|
||||
/// The length of the BABE randomness
|
||||
pub const RANDOMNESS_LENGTH: usize = 32;
|
||||
|
||||
decl_storage! {
|
||||
trait Store for Module<T: Trait> as Babe {
|
||||
/// The last timestamp.
|
||||
@@ -113,11 +117,75 @@ decl_storage! {
|
||||
|
||||
/// The current authorities set.
|
||||
Authorities get(authorities): Vec<AuthorityId>;
|
||||
|
||||
/// The epoch randomness.
|
||||
///
|
||||
/// # Security
|
||||
///
|
||||
/// This MUST NOT be used for gambling, as it can be influenced by a
|
||||
/// malicious validator in the short term. It MAY be used in many
|
||||
/// cryptographic protocols, however, so long as one remembers that this
|
||||
/// (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.
|
||||
EpochRandomness get(epoch_randomness): [u8; 32];
|
||||
|
||||
/// The randomness under construction
|
||||
UnderConstruction: [u8; 32];
|
||||
|
||||
/// The randomness for the next epoch
|
||||
NextEpochRandomness: [u8; 32];
|
||||
|
||||
/// The current epoch
|
||||
EpochIndex get(epoch_index): u64;
|
||||
}
|
||||
}
|
||||
|
||||
decl_module! {
|
||||
pub struct Module<T: Trait> for enum Call where origin: T::Origin { }
|
||||
/// The BABE SRML module
|
||||
pub struct Module<T: Trait> for enum Call where origin: T::Origin {
|
||||
/// Initialization
|
||||
fn on_initialize() {
|
||||
for i in Self::get_inherent_digests()
|
||||
.logs
|
||||
.iter()
|
||||
.filter_map(|s| s.as_pre_runtime())
|
||||
.filter_map(|(id, mut data)| if id == BABE_ENGINE_ID {
|
||||
<[u8; VRF_OUTPUT_LENGTH]>::decode(&mut data)
|
||||
} else {
|
||||
None
|
||||
}) {
|
||||
Self::deposit_vrf_output(&i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Trait> RandomnessBeacon for Module<T> {
|
||||
fn random() -> [u8; 32] {
|
||||
Self::epoch_randomness()
|
||||
}
|
||||
}
|
||||
|
||||
/// A BABE public key
|
||||
pub type BabeKey = [u8; PUBLIC_KEY_LENGTH];
|
||||
|
||||
impl<T: Trait> FindAuthor<u64> for Module<T> {
|
||||
fn find_author<'a, I>(digests: I) -> Option<u64> where
|
||||
I: 'a + IntoIterator<Item=(ConsensusEngineId, &'a [u8])>
|
||||
{
|
||||
for (id, mut data) in digests.into_iter() {
|
||||
if id == BABE_ENGINE_ID {
|
||||
let (_, _, i): (
|
||||
[u8; VRF_OUTPUT_LENGTH],
|
||||
[u8; VRF_PROOF_LENGTH],
|
||||
u64,
|
||||
) = Decode::decode(&mut data)?;
|
||||
return Some(i)
|
||||
}
|
||||
}
|
||||
return None
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Trait> Module<T> {
|
||||
@@ -127,25 +195,31 @@ impl<T: Trait> Module<T> {
|
||||
// the majority of their slot.
|
||||
<timestamp::Module<T>>::minimum_period().saturating_mul(2.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Trait> OnTimestampSet<T::Moment> for Module<T> {
|
||||
fn on_timestamp_set(_moment: T::Moment) { }
|
||||
}
|
||||
|
||||
impl<T: Trait> Module<T> {
|
||||
fn change_authorities(new: Vec<AuthorityId>) {
|
||||
Authorities::put(&new);
|
||||
|
||||
let log: DigestItem<T::Hash> = DigestItem::Consensus(BABE_ENGINE_ID, new.encode());
|
||||
<system::Module<T>>::deposit_log(log.into());
|
||||
}
|
||||
|
||||
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))
|
||||
}
|
||||
|
||||
fn get_inherent_digests() -> system::DigestOf<T> {
|
||||
<system::Module<T>>::digest()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Trait> OnTimestampSet<T::Moment> for Module<T> {
|
||||
fn on_timestamp_set(_moment: T::Moment) { }
|
||||
}
|
||||
|
||||
impl<T: Trait> session::OneSessionHandler<T::AccountId> for Module<T> {
|
||||
type Key = AuthorityId;
|
||||
fn on_new_session<'a, I: 'a>(changed: bool, validators: I)
|
||||
where I: Iterator<Item=(&'a T::AccountId, AuthorityId)>
|
||||
where I: Iterator<Item=(&'a T::AccountId, AuthorityId)>
|
||||
{
|
||||
// instant changes
|
||||
if changed {
|
||||
@@ -155,6 +229,20 @@ impl<T: Trait> session::OneSessionHandler<T::AccountId> for Module<T> {
|
||||
Self::change_authorities(next_authorities);
|
||||
}
|
||||
}
|
||||
|
||||
let rho = UnderConstruction::get();
|
||||
UnderConstruction::put([0; 32]);
|
||||
let last_epoch_randomness = EpochRandomness::get();
|
||||
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);
|
||||
EpochRandomness::put(NextEpochRandomness::get());
|
||||
let mut s = [0; 72];
|
||||
s[..32].copy_from_slice(&last_epoch_randomness);
|
||||
s[32..40].copy_from_slice(&epoch_index.to_le_bytes());
|
||||
s[40..].copy_from_slice(&rho);
|
||||
NextEpochRandomness::put(runtime_io::blake2_256(&s))
|
||||
}
|
||||
fn on_disabled(_i: usize) {
|
||||
// ignore?
|
||||
|
||||
@@ -865,7 +865,7 @@ pub struct Schedule {
|
||||
/// Base gas cost to call into a contract.
|
||||
pub call_base_cost: Gas,
|
||||
|
||||
/// Base gas cost to instantiate a contract.
|
||||
/// Base gas cost to instantiate a contract.
|
||||
pub instantiate_base_cost: Gas,
|
||||
|
||||
/// Gas cost per one byte read from the sandbox memory.
|
||||
|
||||
@@ -14,7 +14,7 @@ clap = { version = "~2.32", features = ["yaml"] }
|
||||
tiny-bip39 = "0.6.0"
|
||||
rustc-hex = "2.0"
|
||||
substrate-bip39 = { git = "https://github.com/paritytech/substrate-bip39" }
|
||||
schnorrkel = "0.1"
|
||||
schnorrkel = "0.1.1"
|
||||
hex = "0.3"
|
||||
hex-literal = "0.2"
|
||||
parity-codec = "4.1.1"
|
||||
|
||||
Reference in New Issue
Block a user