New sessions, kill consensus module (#2802)

* Draft of new sessions

* Reintroduce tuple impls

* Move staking module to new session API

* More work on staking and grandpa.

* Use iterator to avoid cloning and tuple macro

* Make runtime build again

* Polish the OpaqueKeys devex

* Move consensus logic into system & aura.

* Fix up system module

* Get build mostly going. Stuck at service.rs

* Building again

* Update srml/staking/src/lib.rs

Co-Authored-By: DemiMarie-parity <48690212+DemiMarie-parity@users.noreply.github.com>

* Refactoring out Consensus module, AuthorityIdOf, &c.

* Refactored out DigestItem::AuthoritiesChanged. Building.

* Remove tentative code

* Remove invalid comment

* Make Seal opaque and introduce nice methods for handling opaque items.

* Start to use proper digest for Aura authorities tracking.

* Fix up grandpa, remove system::Raw/Log

* Refactor Grandpa to use new logging infrastructure.

Also make authorityid/sessionkey static. Switch over to storing
authorities in a straight Vec.

* Building again

* Tidy up some AuthorityIds

* Expunge most of the rest of the AuthorityKey confusion.

Also, de-generify Babe and re-generify Aura.

* Remove cruft

* Untangle last of the `AuthorityId`s.

* Sort out finality_tracker

* Refactor median getting

* Apply suggestions from code review

Co-Authored-By: Robert Habermeier <rphmeier@gmail.com>

* Session tests works

* Update core/sr-primitives/src/generic/digest.rs

Co-Authored-By: DemiMarie-parity <48690212+DemiMarie-parity@users.noreply.github.com>

* Session tests works

* Fix for staking from @dvc94ch

* log an error

* fix test runtime build

* Some test fixes

* Staking mock update to new session api.

* Fix build.

* Move OpaqueKeys to primitives.

* Use on_initialize instead of check_rotate_session.

* Update tests to new staking api.

* fixup mock

* Fix bond_extra_and_withdraw_unbonded_works.

* Fix bond_with_little_staked_value_bounded_by_slot_stake.

* Fix bond_with_no_staked_value.

* Fix change_controller_works.

* Fix less_than_needed_candidates_works.

* Fix multi_era_reward_should_work.

* Fix nominating_and_rewards_should_work.

* Fix nominators_also_get_slashed.

* Fix phragmen_large_scale_test.

* Fix phragmen_poc_works.

* Fix phragmen_score_should_be_accurate_on_large_stakes.

* Fix phragmen_should_not_overflow.

* Fix reward_destination_works.

* Fix rewards_should_work.

* Fix sessions_and_eras_should_work.

* Fix slot_stake_is_least_staked_validator.

* Fix too_many_unbond_calls_should_not_work.

* Fix wrong_vote_is_null.

* Fix runtime.

* Fix wasm runtime build.

* Update Cargo.lock

* Fix warnings.

* Fix grandpa tests.

* Fix test-runtime build.

* Fix template node build.

* Fix stuff.

* Update Cargo.lock to fix CI

* Re-add missing AuRa logs

Runtimes are required to know about every digest they receive ― they
panic otherwise.  This re-adds support for AuRa pre-runtime digests.

* Update core/consensus/babe/src/digest.rs

Co-Authored-By: DemiMarie-parity <48690212+DemiMarie-parity@users.noreply.github.com>

* Kill log trait and all that jazz.

* Refactor staking tests.

* Fix ci runtime wasm check.

* Line length 120.

* Make tests build again

* Remove trailing commas in function declarations

The `extern_functions!` macro doesn’t like them, perhaps due to a bug in
rustc.

* Fix type error

* Fix compilation errors

* Fix a test

* Another couple of fixes

* Fix another test

* More test fixes

* Another test fix

* Bump runtime.

* Wrap long line

* Fix build, remove redundant code.

* Issue to track TODO

* Leave the benchmark code alone.

* Fix missing `std::time::{Instant, Duration}`

* Indentation

* Aura ConsensusLog as enum
This commit is contained in:
Gavin Wood
2019-06-14 16:34:34 +02:00
committed by GitHub
parent 0f44a28ce3
commit bda8641892
128 changed files with 2646 additions and 3671 deletions
-2
View File
@@ -14,12 +14,10 @@ runtime_io = { package = "sr-io", path = "../../sr-io" }
slots = { package = "substrate-consensus-slots", path = "../slots" }
aura_primitives = { package = "substrate-consensus-aura-primitives", path = "primitives" }
inherents = { package = "substrate-inherents", path = "../../inherents" }
srml-consensus = { path = "../../../srml/consensus" }
srml-aura = { path = "../../../srml/aura" }
client = { package = "substrate-client", path = "../../client" }
substrate-telemetry = { path = "../../telemetry" }
consensus_common = { package = "substrate-consensus-common", path = "../common" }
authorities = { package = "substrate-consensus-authorities", path = "../authorities" }
runtime_primitives = { package = "sr-primitives", path = "../../sr-primitives" }
futures = "0.1.17"
tokio-timer = "0.2.11"
@@ -6,12 +6,18 @@ description = "Primitives for Aura consensus"
edition = "2018"
[dependencies]
parity-codec = { version = "3.5", default-features = false }
substrate-client = { path = "../../../client", default-features = false }
substrate-primitives = { path = "../../../primitives", default-features = false }
rstd = { package = "sr-std", path = "../../../sr-std", default-features = false }
runtime_primitives = { package = "sr-primitives", path = "../../../sr-primitives", default-features = false }
[features]
default = ["std"]
std = [
"rstd/std",
"parity-codec/std",
"runtime_primitives/std",
"substrate-client/std",
"substrate-primitives/std",
]
@@ -18,20 +18,32 @@
#![cfg_attr(not(feature = "std"), no_std)]
use parity_codec::{Encode, Decode, Codec};
use substrate_client::decl_runtime_apis;
use rstd::vec::Vec;
use runtime_primitives::ConsensusEngineId;
/// The `ConsensusEngineId` of AuRa.
pub const AURA_ENGINE_ID: ConsensusEngineId = [b'a', b'u', b'r', b'a'];
/// An consensus log item for Aura.
#[derive(Decode, Encode)]
pub enum ConsensusLog<AuthorityId: Codec> {
/// The authorities have changed.
AuthoritiesChange(Vec<AuthorityId>),
}
decl_runtime_apis! {
/// API necessary for block authorship with aura.
pub trait AuraApi {
pub trait AuraApi<AuthorityId: Codec> {
/// Return the slot duration in seconds for Aura.
/// Currently, only the value provided by this type at genesis
/// will be used.
///
/// Dynamic slot duration may be supported in the future.
fn slot_duration() -> u64;
// Return the current set of authorities.
fn authorities() -> Vec<AuthorityId>;
}
}
+15 -17
View File
@@ -18,20 +18,22 @@
//!
//! This implements the digests for AuRa, to allow the private
//! `CompatibleDigestItem` trait to appear in public interfaces.
use primitives::Pair;
use aura_primitives::AURA_ENGINE_ID;
use runtime_primitives::generic::DigestItem;
use parity_codec::{Encode, Decode};
use runtime_primitives::generic::{DigestItem, OpaqueDigestItemId};
use parity_codec::{Encode, Codec};
use std::fmt::Debug;
type Signature<P> = <P as Pair>::Signature;
/// A digest item which is usable with aura consensus.
pub trait CompatibleDigestItem<T: Pair>: Sized {
pub trait CompatibleDigestItem<P: Pair>: Sized {
/// Construct a digest item which contains a signature on the hash.
fn aura_seal(signature: Signature<T>) -> Self;
fn aura_seal(signature: Signature<P>) -> Self;
/// If this item is an Aura seal, return the signature.
fn as_aura_seal(&self) -> Option<&Signature<T>>;
fn as_aura_seal(&self) -> Option<Signature<P>>;
/// Construct a digest item which contains the slot number
fn aura_pre_digest(slot_num: u64) -> Self;
@@ -40,18 +42,17 @@ pub trait CompatibleDigestItem<T: Pair>: Sized {
fn as_aura_pre_digest(&self) -> Option<u64>;
}
impl<P, Hash> CompatibleDigestItem<P> for DigestItem<Hash, P::Public, P::Signature>
where P: Pair, P::Signature: Clone + Encode + Decode,
impl<P, Hash> CompatibleDigestItem<P> for DigestItem<Hash> where
P: Pair,
Signature<P>: Codec,
Hash: Debug + Send + Sync + Eq + Clone + Codec + 'static
{
fn aura_seal(signature: Signature<P>) -> Self {
DigestItem::Seal(AURA_ENGINE_ID, signature)
DigestItem::Seal(AURA_ENGINE_ID, signature.encode())
}
fn as_aura_seal(&self) -> Option<&Signature<P>> {
match self {
DigestItem::Seal(AURA_ENGINE_ID, ref sig) => Some(sig),
_ => None,
}
fn as_aura_seal(&self) -> Option<Signature<P>> {
self.try_to(OpaqueDigestItemId::Seal(&AURA_ENGINE_ID))
}
fn aura_pre_digest(slot_num: u64) -> Self {
@@ -59,9 +60,6 @@ impl<P, Hash> CompatibleDigestItem<P> for DigestItem<Hash, P::Public, P::Signatu
}
fn as_aura_pre_digest(&self) -> Option<u64> {
match self {
DigestItem::PreRuntime(AURA_ENGINE_ID, ref buffer) => Decode::decode(&mut &buffer[..]),
_ => None,
}
self.try_to(OpaqueDigestItemId::PreRuntime(&AURA_ENGINE_ID))
}
}
+48 -57
View File
@@ -25,13 +25,15 @@
//!
//! Blocks from future steps will be either deferred or rejected depending on how
//! far in the future they are.
//!
//! NOTE: Aura itself is designed to be generic over the crypto used.
#![forbid(missing_docs, unsafe_code)]
use std::{sync::Arc, time::Duration, thread, marker::PhantomData, hash::Hash, fmt::Debug};
use parity_codec::{Encode, Decode};
use consensus_common::{self, Authorities, BlockImport, Environment, Proposer,
use parity_codec::{Encode, Decode, Codec};
use consensus_common::{self, BlockImport, Environment, Proposer,
ForkChoiceStrategy, ImportBlock, BlockOrigin, Error as ConsensusError,
SelectChain, well_known_cache_keys
SelectChain, well_known_cache_keys::{self, Id as CacheKeyId}
};
use consensus_common::import_queue::{
Verifier, BasicQueue, SharedBlockImport, SharedJustificationImport, SharedFinalityProofImport,
@@ -45,15 +47,11 @@ use client::{
backend::AuxStore,
};
use runtime_primitives::{generic::{self, BlockId}, Justification};
use runtime_primitives::traits::{
Block, Header, Digest, DigestItemFor, DigestItem, ProvideRuntimeApi, AuthorityIdFor,
Zero, Member,
};
use runtime_primitives::{generic::{self, BlockId, OpaqueDigestItemId}, Justification};
use runtime_primitives::traits::{Block, Header, DigestItemFor, ProvideRuntimeApi, Zero, Member};
use primitives::Pair;
use inherents::{InherentDataProviders, InherentData};
use authorities::AuthoritiesApi;
use futures::{Future, IntoFuture, future};
use tokio_timer::Timeout;
@@ -82,9 +80,12 @@ pub struct SlotDuration(slots::SlotDuration<u64>);
impl SlotDuration {
/// Either fetch the slot duration from disk or compute it from the genesis
/// state.
pub fn get_or_compute<B: Block, C>(client: &C) -> CResult<Self>
pub fn get_or_compute<A, B, C>(client: &C) -> CResult<Self>
where
C: AuxStore, C: ProvideRuntimeApi, C::Api: AuraApi<B>,
A: Codec,
B: Block,
C: AuxStore + ProvideRuntimeApi,
C::Api: AuraApi<B, A>,
{
slots::SlotDuration::get_or_compute(client, |a, b| a.slot_duration(b)).map(Self)
}
@@ -138,19 +139,14 @@ pub fn start_aura<B, C, SC, E, I, P, SO, Error, H>(
) -> Result<impl Future<Item=(), Error=()>, consensus_common::Error> where
B: Block<Header=H>,
C: ProvideRuntimeApi + ProvideCache<B> + AuxStore + Send + Sync,
C::Api: AuthoritiesApi<B>,
C::Api: AuraApi<B, AuthorityId<P>>,
SC: SelectChain<B>,
generic::DigestItem<B::Hash, P::Public, P::Signature>: DigestItem<Hash=B::Hash>,
E::Proposer: Proposer<B, Error=Error>,
<<E::Proposer as Proposer<B>>::Create as IntoFuture>::Future: Send + 'static,
P: Pair + Send + Sync + 'static,
P::Public: Hash + Member + Encode + Decode,
P::Signature: Hash + Member + Encode + Decode,
DigestItemFor<B>: CompatibleDigestItem<P> + DigestItem<AuthorityId=AuthorityId<P>>,
H: Header<
Digest=generic::Digest<generic::DigestItem<B::Hash, P::Public, P::Signature>>,
Hash=B::Hash,
>,
H: Header<Hash=B::Hash>,
E: Environment<B, Error=Error>,
I: BlockImport<B> + Send + Sync + 'static,
Error: ::std::error::Error + Send + From<::consensus_common::Error> + From<I::Error> + 'static,
@@ -189,20 +185,16 @@ struct AuraWorker<C, E, I, P, SO> {
impl<H, B, C, E, I, P, Error, SO> SlotWorker<B> for AuraWorker<C, E, I, P, SO> where
B: Block<Header=H>,
C: ProvideRuntimeApi + ProvideCache<B> + Sync,
C::Api: AuthoritiesApi<B>,
C::Api: AuraApi<B, AuthorityId<P>>,
E: Environment<B, Error=Error>,
E::Proposer: Proposer<B, Error=Error>,
<<E::Proposer as Proposer<B>>::Create as IntoFuture>::Future: Send + 'static,
H: Header<
Digest=generic::Digest<generic::DigestItem<B::Hash, P::Public, P::Signature>>,
Hash=B::Hash,
>,
H: Header<Hash=B::Hash>,
I: BlockImport<B> + Send + Sync + 'static,
P: Pair + Send + Sync + 'static,
P::Public: Member + Encode + Decode + Hash,
P::Signature: Member + Encode + Decode + Hash + Debug,
SO: SyncOracle + Send + Clone,
DigestItemFor<B>: CompatibleDigestItem<P> + DigestItem<AuthorityId=AuthorityId<P>, Hash=B::Hash>,
Error: ::std::error::Error + Send + From<::consensus_common::Error> + From<I::Error> + 'static,
{
type OnSlot = Box<dyn Future<Item=(), Error=consensus_common::Error> + Send>;
@@ -257,7 +249,7 @@ impl<H, B, C, E, I, P, Error, SO> SlotWorker<B> for AuraWorker<C, E, I, P, SO> w
);
// we are the slot author. make a block and sign it.
let proposer = match env.init(&chain_head, &authorities) {
let proposer = match env.init(&chain_head) {
Ok(p) => p,
Err(e) => {
warn!("Unable to author block in slot {:?}: {:?}", slot_num, e);
@@ -506,13 +498,12 @@ impl<C, P> AuraVerifier<C, P>
#[forbid(deprecated)]
impl<B: Block, C, P> Verifier<B> for AuraVerifier<C, P> where
C: ProvideRuntimeApi + Send + Sync + client::backend::AuxStore,
C::Api: BlockBuilderApi<B>,
DigestItemFor<B>: CompatibleDigestItem<P> + DigestItem<AuthorityId=AuthorityId<P>>,
C: ProvideRuntimeApi + Send + Sync + client::backend::AuxStore + ProvideCache<B>,
C::Api: BlockBuilderApi<B> + AuraApi<B, AuthorityId<P>>,
DigestItemFor<B>: CompatibleDigestItem<P>,
P: Pair + Send + Sync + 'static,
P::Public: Send + Sync + Hash + Eq + Clone + Decode + Encode + Debug + AsRef<P::Public> + 'static,
P::Signature: Encode + Decode,
Self: Authorities<B>,
{
fn verify(
&self,
@@ -520,13 +511,13 @@ impl<B: Block, C, P> Verifier<B> for AuraVerifier<C, P> where
header: B::Header,
justification: Option<Justification>,
mut body: Option<Vec<B::Extrinsic>>,
) -> Result<(ImportBlock<B>, Option<Vec<AuthorityId<P>>>), String> {
) -> 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)
.map_err(|e| format!("Could not extract timestamp and slot: {:?}", e))?;
let hash = header.hash();
let parent_hash = *header.parent_hash();
let authorities = self.authorities(&BlockId::Hash(parent_hash))
let authorities = authorities(self.client.as_ref(), &BlockId::Hash(parent_hash))
.map_err(|e| format!("Could not fetch authorities at {:?}: {:?}", parent_hash, e))?;
// we add one to allow for some small drift.
@@ -569,9 +560,14 @@ impl<B: Block, C, P> Verifier<B> for AuraVerifier<C, P> where
trace!(target: "aura", "Checked {:?}; importing.", pre_header);
telemetry!(CONSENSUS_TRACE; "aura.checked_and_importing"; "pre_header" => ?pre_header);
let new_authorities = pre_header.digest()
.log(DigestItem::as_authorities_change)
.map(|digest| digest.to_vec());
// `Consensus` is the Aura-specific authorities change log.
let maybe_keys = pre_header.digest()
.convert_first(|l| l.try_to::<ConsensusLog<AuthorityId<P>>>(
OpaqueDigestItemId::Consensus(&AURA_ENGINE_ID)
))
.map(|ConsensusLog::AuthoritiesChange(a)|
vec![(well_known_cache_keys::AUTHORITIES, a.encode())]
);
let import_block = ImportBlock {
origin,
@@ -584,7 +580,7 @@ impl<B: Block, C, P> Verifier<B> for AuraVerifier<C, P> where
fork_choice: ForkChoiceStrategy::LongestChain,
};
Ok((import_block, new_authorities))
Ok((import_block, maybe_keys))
}
CheckedHeader::Deferred(a, b) => {
debug!(target: "aura", "Checking {:?} failed; {:?}, {:?}.", hash, a, b);
@@ -597,22 +593,11 @@ impl<B: Block, C, P> Verifier<B> for AuraVerifier<C, P> where
}
}
impl<B, C, P> Authorities<B> for AuraVerifier<C, P> where
fn initialize_authorities_cache<A, B, C>(client: &C) -> Result<(), ConsensusError> where
A: Codec,
B: Block,
C: ProvideRuntimeApi + ProvideCache<B>,
C::Api: AuthoritiesApi<B>,
{
type Error = ConsensusError;
fn authorities(&self, at: &BlockId<B>) -> Result<Vec<AuthorityIdFor<B>>, Self::Error> {
authorities(self.client.as_ref(), at)
}
}
fn initialize_authorities_cache<B, C>(client: &C) -> Result<(), ConsensusError> where
B: Block,
C: ProvideRuntimeApi + ProvideCache<B>,
C::Api: AuthoritiesApi<B>,
C::Api: AuraApi<B, A>,
{
// no cache => no initialization
let cache = match client.cache() {
@@ -622,7 +607,7 @@ fn initialize_authorities_cache<B, C>(client: &C) -> Result<(), ConsensusError>
// check if we already have initialized the cache
let genesis_id = BlockId::Number(Zero::zero());
let genesis_authorities: Option<Vec<AuthorityIdFor<B>>> = cache
let genesis_authorities: Option<Vec<A>> = cache
.get_at(&well_known_cache_keys::AUTHORITIES, &genesis_id)
.and_then(|v| Decode::decode(&mut &v[..]));
if genesis_authorities.is_some() {
@@ -642,10 +627,11 @@ fn initialize_authorities_cache<B, C>(client: &C) -> Result<(), ConsensusError>
}
#[allow(deprecated)]
fn authorities<B, C>(client: &C, at: &BlockId<B>) -> Result<Vec<AuthorityIdFor<B>>, ConsensusError> where
fn authorities<A, B, C>(client: &C, at: &BlockId<B>) -> Result<Vec<A>, ConsensusError> where
A: Codec,
B: Block,
C: ProvideRuntimeApi + ProvideCache<B>,
C::Api: AuthoritiesApi<B>,
C::Api: AuraApi<B, A>,
{
client
.cache()
@@ -653,7 +639,7 @@ fn authorities<B, C>(client: &C, at: &BlockId<B>) -> Result<Vec<AuthorityIdFor<B
.get_at(&well_known_cache_keys::AUTHORITIES, at)
.and_then(|v| Decode::decode(&mut &v[..]))
)
.or_else(|| AuthoritiesApi::authorities(&*client.runtime_api(), at).ok())
.or_else(|| AuraApi::authorities(&*client.runtime_api(), at).ok())
.ok_or_else(|| consensus_common::Error::InvalidAuthoritiesSet.into())
}
@@ -687,8 +673,8 @@ pub fn import_queue<B, C, P>(
) -> Result<AuraImportQueue<B>, consensus_common::Error> where
B: Block,
C: 'static + ProvideRuntimeApi + ProvideCache<B> + Send + Sync + AuxStore,
C::Api: BlockBuilderApi<B> + AuthoritiesApi<B>,
DigestItemFor<B>: CompatibleDigestItem<P> + DigestItem<AuthorityId=AuthorityId<P>>,
C::Api: BlockBuilderApi<B> + AuraApi<B, AuthorityId<P>>,
DigestItemFor<B>: CompatibleDigestItem<P>,
P: Pair + Send + Sync + 'static,
P::Public: Clone + Eq + Send + Sync + Hash + Debug + Encode + Decode + AsRef<P::Public>,
P::Signature: Encode + Decode,
@@ -730,7 +716,12 @@ mod tests {
type Error = client::error::Error;
type TestClient = client::Client<test_client::Backend, test_client::Executor, TestBlock, test_client::runtime::RuntimeApi>;
type TestClient = client::Client<
test_client::Backend,
test_client::Executor,
TestBlock,
test_client::runtime::RuntimeApi
>;
struct DummyFactory(Arc<TestClient>);
struct DummyProposer(u64, Arc<TestClient>);
@@ -739,7 +730,7 @@ mod tests {
type Proposer = DummyProposer;
type Error = Error;
fn init(&self, parent_header: &<TestBlock as BlockT>::Header, _authorities: &[AuthorityId<sr25519::Pair>])
fn init(&self, parent_header: &<TestBlock as BlockT>::Header)
-> Result<DummyProposer, Error>
{
Ok(DummyProposer(parent_header.number + 1, self.0.clone()))
@@ -1,29 +0,0 @@
[package]
name = "substrate-consensus-authorities"
version = "2.0.0"
authors = ["Parity Technologies <admin@parity.io>"]
description = "Primitives for Aura consensus"
edition = "2018"
[dependencies]
parity-codec = { version = "3.3", default-features = false }
substrate-client = { path = "../../client", default-features = false }
primitives = { package = "substrate-primitives", path = "../../primitives", default-features = false }
runtime_support = { package = "srml-support", path = "../../../srml/support", default-features = false }
runtime_primitives = { package = "sr-primitives", path = "../../sr-primitives", default-features = false }
sr-version = { path = "../../sr-version", default-features = false }
runtime_io = { package = "sr-io", path = "../../sr-io", default-features = false }
rstd = { package = "sr-std", path = "../../sr-std", default-features = false }
[features]
default = ["std"]
std = [
"parity-codec/std",
"substrate-client/std",
"primitives/std",
"runtime_support/std",
"runtime_primitives/std",
"sr-version/std",
"runtime_io/std",
"rstd/std"
]
@@ -1,31 +0,0 @@
// Copyright 2019 Parity Technologies (UK) Ltd.
// This file is part of Substrate.
// Substrate is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Substrate is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
//! Authorities API.
#![cfg_attr(not(feature = "std"), no_std)]
use substrate_client::decl_runtime_apis;
use runtime_primitives::traits::AuthorityIdFor;
use rstd::vec::Vec;
decl_runtime_apis! {
/// Authorities API.
pub trait AuthoritiesApi {
/// Returns the authorities at the given block.
fn authorities() -> Vec<AuthorityIdFor<Block>>;
}
}
-2
View File
@@ -14,12 +14,10 @@ runtime_support = { package = "srml-support", path = "../../../srml/support" }
runtime_version = { package = "sr-version", path = "../../sr-version" }
runtime_io = { package = "sr-io", path = "../../sr-io" }
inherents = { package = "substrate-inherents", path = "../../inherents" }
srml-consensus = { path = "../../../srml/consensus" }
substrate-telemetry = { path = "../../telemetry" }
srml-babe = { path = "../../../srml/babe" }
client = { package = "substrate-client", path = "../../client" }
consensus_common = { package = "substrate-consensus-common", path = "../common" }
authorities = { package = "substrate-consensus-authorities", path = "../authorities" }
slots = { package = "substrate-consensus-slots", path = "../slots" }
runtime_primitives = { package = "sr-primitives", path = "../../sr-primitives" }
futures = "0.1.26"
@@ -7,13 +7,16 @@ edition = "2018"
[dependencies]
substrate-client = { path = "../../../client", default-features = false }
rstd = { package = "sr-std", path = "../../../sr-std", default-features = false }
runtime_primitives = { package = "sr-primitives", path = "../../../sr-primitives", default-features = false }
substrate-primitives = { path = "../../../primitives", default-features = false }
slots = { package = "substrate-consensus-slots", path = "../../slots", optional = true }
parity-codec = { version = "3.5.1", default-features = false }
[features]
default = ["std"]
std = [
"rstd/std",
"runtime_primitives/std",
"substrate-client/std",
"parity-codec/std",
@@ -18,13 +18,18 @@
#![deny(warnings, unsafe_code, missing_docs)]
#![cfg_attr(not(feature = "std"), no_std)]
use parity_codec::{Encode, Decode};
use rstd::vec::Vec;
use runtime_primitives::ConsensusEngineId;
use substrate_primitives::sr25519::Public;
use substrate_client::decl_runtime_apis;
use parity_codec::{Encode, Decode};
/// A Babe authority identifier. Necessarily equivalent to the schnorrkel public key used in
/// the main Babe module. If that ever changes, then this must, too.
pub type AuthorityId = Public;
/// The `ConsensusEngineId` of BABE.
pub const BABE_ENGINE_ID: ConsensusEngineId = [b'b', b'a', b'b', b'e'];
pub const BABE_ENGINE_ID: ConsensusEngineId = *b"BABE";
/// Configuration data used by the BABE consensus engine.
#[derive(Copy, Clone, Hash, PartialEq, Eq, Debug, Encode, Decode)]
@@ -69,5 +74,8 @@ decl_runtime_apis! {
///
/// Dynamic configuration may be supported in the future.
fn startup_data() -> BabeConfiguration;
/// Get the current authorites for Babe.
fn authorities() -> Vec<AuthorityId>;
}
}
+7 -46
View File
@@ -15,12 +15,12 @@
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
//! Private mplementation details of BABE digests.
use primitives::sr25519::{Public, Signature};
use babe_primitives::BABE_ENGINE_ID;
use runtime_primitives::generic::DigestItem;
use runtime_primitives::{DigestItem, generic::OpaqueDigestItemId};
use std::fmt::Debug;
use parity_codec::{Decode, Encode, Input};
use log::info;
use parity_codec::{Decode, Encode, Codec, Input};
use schnorrkel::{
vrf::{VRFProof, VRFOutput, VRF_OUTPUT_LENGTH, VRF_PROOF_LENGTH},
PUBLIC_KEY_LENGTH,
@@ -89,26 +89,15 @@ pub trait CompatibleDigestItem: Sized {
fn as_babe_seal(&self) -> Option<Signature>;
}
impl<Hash: Debug> CompatibleDigestItem for DigestItem<Hash, Public, Vec<u8>>
impl<Hash> CompatibleDigestItem for DigestItem<Hash> where
Hash: Debug + Send + Sync + Eq + Clone + Codec + 'static
{
fn babe_pre_digest(digest: BabePreDigest) -> Self {
DigestItem::PreRuntime(BABE_ENGINE_ID, digest.encode())
}
fn as_babe_pre_digest(&self) -> Option<BabePreDigest> {
match self {
DigestItem::PreRuntime(BABE_ENGINE_ID, seal) => {
let decoded = Decode::decode(&mut &seal[..]);
if decoded.is_none() {
info!(target: "babe", "Failed to decode {:?}", seal)
}
decoded
}
_ => {
info!(target: "babe", "Invalid consensus: {:?}!", self);
None
}
}
self.try_to(OpaqueDigestItemId::PreRuntime(&BABE_ENGINE_ID))
}
fn babe_seal(signature: Signature) -> Self {
@@ -116,34 +105,6 @@ impl<Hash: Debug> CompatibleDigestItem for DigestItem<Hash, Public, Vec<u8>>
}
fn as_babe_seal(&self) -> Option<Signature> {
match self {
DigestItem::Seal(BABE_ENGINE_ID, signature) => Decode::decode(&mut &signature[..]),
_ => None,
}
self.try_to(OpaqueDigestItemId::Seal(&BABE_ENGINE_ID))
}
}
impl<Hash: Debug> CompatibleDigestItem for DigestItem<Hash, Public, Signature>
{
fn babe_pre_digest(digest: BabePreDigest) -> Self {
DigestItem::PreRuntime(BABE_ENGINE_ID, digest.encode())
}
fn as_babe_pre_digest(&self) -> Option<BabePreDigest> {
match self {
DigestItem::PreRuntime(BABE_ENGINE_ID, seal) => Decode::decode(&mut &seal[..]),
_ => None,
}
}
fn babe_seal(signature: Signature) -> Self {
DigestItem::Seal(BABE_ENGINE_ID, signature)
}
fn as_babe_seal(&self) -> Option<Signature> {
match self {
DigestItem::Seal(BABE_ENGINE_ID, signature) => Some(signature.clone()),
_ => None,
}
}
}
+34 -54
View File
@@ -31,18 +31,16 @@ use digest::CompatibleDigestItem;
pub use digest::{BabePreDigest, BABE_VRF_PREFIX};
pub use babe_primitives::*;
pub use consensus_common::SyncOracle;
use runtime_primitives::{generic, generic::BlockId, Justification};
use consensus_common::well_known_cache_keys::Id as CacheKeyId;
use runtime_primitives::{generic, generic::{BlockId, OpaqueDigestItemId}, Justification};
use runtime_primitives::traits::{
Block, Header, Digest, DigestItemFor, DigestItem, ProvideRuntimeApi, AuthorityIdFor,
Block, Header, DigestItemFor, ProvideRuntimeApi,
SimpleBitOps,
};
use std::{sync::Arc, u64, fmt::{Debug, Display}};
use runtime_support::serde::{Serialize, Deserialize};
use parity_codec::{Decode, Encode};
use primitives::{
crypto::Pair,
sr25519::{Public, Signature, self},
};
use primitives::{crypto::Pair, sr25519};
use merlin::Transcript;
use inherents::{InherentDataProviders, InherentData};
use substrate_telemetry::{
@@ -58,9 +56,8 @@ use schnorrkel::{
VRFProof, VRFProofBatchable, VRFInOut,
},
};
use authorities::AuthoritiesApi;
use consensus_common::{
self, Authorities, BlockImport, Environment, Proposer,
self, BlockImport, Environment, Proposer,
ForkChoiceStrategy, ImportBlock, BlockOrigin, Error as ConsensusError,
};
use srml_babe::{
@@ -83,6 +80,7 @@ use log::{error, warn, debug, info, trace};
use slots::{SlotWorker, SlotData, SlotInfo, SlotCompatible, slot_now};
pub use babe_primitives::AuthorityId;
/// A slot duration. Create with `get_or_compute`.
// FIXME: Once Rust has higher-kinded types, the duplication between this
@@ -181,16 +179,11 @@ pub fn start_babe<B, C, SC, E, I, SO, Error, H>(BabeParams {
> where
B: Block<Header=H>,
C: ProvideRuntimeApi + ProvideCache<B>,
C::Api: AuthoritiesApi<B>,
C::Api: BabeApi<B>,
SC: SelectChain<B>,
generic::DigestItem<B::Hash, Public, Signature>: DigestItem<Hash=B::Hash>,
E::Proposer: Proposer<B, Error=Error>,
<<E::Proposer as Proposer<B>>::Create as IntoFuture>::Future: Send + 'static,
DigestItemFor<B>: CompatibleDigestItem + DigestItem<AuthorityId=Public>,
H: Header<
Digest=generic::Digest<generic::DigestItem<B::Hash, Public, Signature>>,
Hash=B::Hash,
>,
H: Header<Hash=B::Hash>,
E: Environment<B, Error=Error>,
I: BlockImport<B> + Send + Sync + 'static,
Error: std::error::Error + Send + From<::consensus_common::Error> + From<I::Error> + 'static,
@@ -228,17 +221,14 @@ struct BabeWorker<C, E, I, SO> {
impl<Hash, H, B, C, E, I, Error, SO> SlotWorker<B> for BabeWorker<C, E, I, SO> where
B: Block<Header=H, Hash=Hash>,
C: ProvideRuntimeApi + ProvideCache<B>,
C::Api: AuthoritiesApi<B>,
C::Api: BabeApi<B>,
E: Environment<B, Error=Error>,
E::Proposer: Proposer<B, Error=Error>,
<<E::Proposer as Proposer<B>>::Create as IntoFuture>::Future: Send + 'static,
Hash: Debug + Eq + Copy + SimpleBitOps + Encode + Decode + Serialize +
for<'de> Deserialize<'de> + Debug + Default + AsRef<[u8]> + AsMut<[u8]> +
std::hash::Hash + Display + Send + Sync + 'static,
H: Header<
Digest=generic::Digest<generic::DigestItem<B::Hash, Public, Signature>>,
Hash=B::Hash,
>,
H: Header<Hash=B::Hash>,
I: BlockImport<B> + Send + Sync + 'static,
SO: SyncOracle + Send + Clone,
Error: std::error::Error + Send + From<::consensus_common::Error> + From<I::Error> + 'static,
@@ -304,7 +294,7 @@ impl<Hash, H, B, C, E, I, Error, SO> SlotWorker<B> for BabeWorker<C, E, I, SO> w
);
// we are the slot author. make a block and sign it.
let proposer = match env.init(&chain_head, &authorities) {
let proposer = match env.init(&chain_head) {
Ok(p) => p,
Err(e) => {
warn!(target: "babe", "Unable to author block in slot {:?}: {:?}", slot_num, e);
@@ -450,7 +440,7 @@ fn check_header<B: Block + Sized, C: AuxStore>(
slot_now: u64,
mut header: B::Header,
hash: B::Hash,
authorities: &[Public],
authorities: &[AuthorityId],
threshold: u64,
) -> Result<CheckedHeader<B::Header, (DigestItemFor<B>, DigestItemFor<B>)>, String>
where DigestItemFor<B>: CompatibleDigestItem,
@@ -553,10 +543,9 @@ impl<C> BabeVerifier<C> {
}
impl<B: Block, C> Verifier<B> for BabeVerifier<C> where
C: ProvideRuntimeApi + Send + Sync + AuxStore,
C::Api: BlockBuilderApi<B>,
DigestItemFor<B>: CompatibleDigestItem + DigestItem<AuthorityId=Public>,
Self: Authorities<B>,
C: ProvideRuntimeApi + Send + Sync + AuxStore + ProvideCache<B>,
C::Api: BlockBuilderApi<B> + BabeApi<B>,
DigestItemFor<B>: CompatibleDigestItem,
{
fn verify(
&self,
@@ -564,7 +553,7 @@ impl<B: Block, C> Verifier<B> for BabeVerifier<C> where
header: B::Header,
justification: Option<Justification>,
mut body: Option<Vec<B::Extrinsic>>,
) -> Result<(ImportBlock<B>, Option<Vec<Public>>), String> {
) -> Result<(ImportBlock<B>, Option<Vec<(CacheKeyId, Vec<u8>)>>), String> {
trace!(
target: "babe",
"Verifying origin: {:?} header: {:?} justification: {:?} body: {:?}",
@@ -583,7 +572,7 @@ impl<B: Block, C> Verifier<B> for BabeVerifier<C> where
.map_err(|e| format!("Could not extract timestamp and slot: {:?}", e))?;
let hash = header.hash();
let parent_hash = *header.parent_hash();
let authorities = self.authorities(&BlockId::Hash(parent_hash))
let authorities = authorities(self.client.as_ref(), &BlockId::Hash(parent_hash))
.map_err(|e| format!("Could not fetch authorities at {:?}: {:?}", parent_hash, e))?;
// we add one to allow for some small drift.
@@ -625,9 +614,12 @@ impl<B: Block, C> Verifier<B> for BabeVerifier<C> where
"babe.checked_and_importing";
"pre_header" => ?pre_header);
let new_authorities = pre_header.digest()
.log(DigestItem::as_authorities_change)
.map(|digest| digest.to_vec());
// `Consensus` is the Babe-specific authorities change log.
// It's an encoded `Vec<AuthorityId>`, the same format as is stored in the cache,
// so no need to decode/re-encode.
let maybe_keys = pre_header.digest()
.log(|l| l.try_as_raw(OpaqueDigestItemId::Consensus(&BABE_ENGINE_ID)))
.map(|blob| vec![(well_known_cache_keys::AUTHORITIES, blob.to_vec())]);
let import_block = ImportBlock {
origin,
@@ -641,7 +633,7 @@ impl<B: Block, C> Verifier<B> for BabeVerifier<C> where
};
// FIXME #1019 extract authorities
Ok((import_block, new_authorities))
Ok((import_block, maybe_keys))
}
CheckedHeader::Deferred(a, b) => {
debug!(target: "babe", "Checking {:?} failed; {:?}, {:?}.", hash, a, b);
@@ -654,33 +646,21 @@ impl<B: Block, C> Verifier<B> for BabeVerifier<C> where
}
}
impl<B, C> Authorities<B> for BabeVerifier<C> where
B: Block,
C: ProvideRuntimeApi + ProvideCache<B>,
C::Api: AuthoritiesApi<B>,
{
type Error = ConsensusError;
fn authorities(&self, at: &BlockId<B>) -> Result<Vec<AuthorityIdFor<B>>, Self::Error> {
authorities(self.client.as_ref(), at)
}
}
fn authorities<B, C>(client: &C, at: &BlockId<B>) -> Result<
Vec<AuthorityIdFor<B>>,
Vec<AuthorityId>,
ConsensusError,
> where
B: Block,
C: ProvideRuntimeApi + ProvideCache<B>,
C::Api: AuthoritiesApi<B>,
C::Api: BabeApi<B>,
{
client
.cache()
.and_then(|cache| cache.get_at(&well_known_cache_keys::AUTHORITIES, at)
.and_then(|v| Decode::decode(&mut &v[..])))
.or_else(|| {
if client.runtime_api().has_api::<dyn AuthoritiesApi<B>>(at).unwrap_or(false) {
AuthoritiesApi::authorities(&*client.runtime_api(), at).ok()
if client.runtime_api().has_api::<dyn BabeApi<B>>(at).unwrap_or(false) {
BabeApi::authorities(&*client.runtime_api(), at).ok()
} else {
panic!("We dont support deprecated code with new consensus algorithms, \
therefore this is unreachable; qed")
@@ -740,7 +720,7 @@ fn claim_slot(
slot_number: u64,
genesis_hash: &[u8],
epoch: u64,
authorities: &[sr25519::Public],
authorities: &[AuthorityId],
key: &sr25519::Pair,
threshold: u64,
) -> Option<(VRFInOut, VRFProof, VRFProofBatchable)> {
@@ -784,7 +764,7 @@ mod tests {
use futures::stream::Stream;
use log::debug;
use std::time::Duration;
type Item = generic::DigestItem<Hash, Public, Signature>;
type Item = generic::DigestItem<Hash>;
use test_client::AuthorityKeyring;
type Error = client::error::Error;
@@ -803,7 +783,7 @@ mod tests {
type Proposer = DummyProposer;
type Error = Error;
fn init(&self, parent_header: &<TestBlock as BlockT>::Header, _authorities: &[Public])
fn init(&self, parent_header: &<TestBlock as BlockT>::Header)
-> Result<DummyProposer, Error>
{
Ok(DummyProposer(parent_header.number + 1, self.0.clone()))
@@ -977,7 +957,7 @@ mod tests {
fn wrong_consensus_engine_id_rejected() {
drop(env_logger::try_init());
let sig = sr25519::Pair::generate().0.sign(b"");
let bad_seal: Item = DigestItem::Seal([0; 4], sig);
let bad_seal: Item = DigestItem::Seal([0; 4], sig.0.to_vec());
assert!(bad_seal.as_babe_pre_digest().is_none());
assert!(bad_seal.as_babe_seal().is_none())
}
@@ -985,7 +965,7 @@ mod tests {
#[test]
fn malformed_pre_digest_rejected() {
drop(env_logger::try_init());
let bad_seal: Item = DigestItem::Seal(BABE_ENGINE_ID, Signature([0; 64]));
let bad_seal: Item = DigestItem::Seal(BABE_ENGINE_ID, [0; 64].to_vec());
assert!(bad_seal.as_babe_pre_digest().is_none());
}
@@ -993,7 +973,7 @@ mod tests {
fn sig_is_not_pre_digest() {
drop(env_logger::try_init());
let sig = sr25519::Pair::generate().0.sign(b"");
let bad_seal: Item = DigestItem::Seal(BABE_ENGINE_ID, sig);
let bad_seal: Item = DigestItem::Seal(BABE_ENGINE_ID, sig.0.to_vec());
assert!(bad_seal.as_babe_pre_digest().is_none());
assert!(bad_seal.as_babe_seal().is_some())
}
@@ -154,8 +154,6 @@ impl<Block: BlockT> ImportBlock<Block> {
/// Get a handle to full header (with post-digests applied).
pub fn post_header(&self) -> Cow<Block::Header> {
use runtime_primitives::traits::Digest;
if self.post_digests.is_empty() {
Cow::Borrowed(&self.header)
} else {
@@ -25,24 +25,16 @@
//! instantiated. The `BasicQueue` and `BasicVerifier` traits allow serial
//! queues to be instantiated simply.
use crate::block_import::{
use std::{sync::Arc, thread, collections::HashMap};
use crossbeam_channel::{self as channel, Receiver, Sender};
use parking_lot::Mutex;
use runtime_primitives::{Justification, traits::{
Block as BlockT, Header as HeaderT, NumberFor,
}};
use crate::{error::Error as ConsensusError, well_known_cache_keys::Id as CacheKeyId, block_import::{
BlockImport, BlockOrigin, ImportBlock, ImportedAux, ImportResult, JustificationImport,
FinalityProofImport, FinalityProofRequestBuilder,
};
use crossbeam_channel::{self as channel, Receiver, Sender};
use parity_codec::Encode;
use parking_lot::Mutex;
use std::sync::Arc;
use std::thread;
use runtime_primitives::traits::{
AuthorityIdFor, Block as BlockT, Header as HeaderT, NumberFor, Digest,
};
use runtime_primitives::Justification;
use crate::error::Error as ConsensusError;
use parity_codec::alloc::collections::hash_map::HashMap;
}};
/// Reputation change for peers which send us a block with an incomplete header.
const INCOMPLETE_HEADER_REPUTATION_CHANGE: i32 = -(1 << 20);
@@ -94,7 +86,7 @@ pub trait Verifier<B: BlockT>: Send + Sync {
header: B::Header,
justification: Option<Justification>,
body: Option<Vec<B::Extrinsic>>,
) -> Result<(ImportBlock<B>, Option<Vec<AuthorityIdFor<B>>>), String>;
) -> Result<(ImportBlock<B>, Option<Vec<(CacheKeyId, Vec<u8>)>>), String>;
}
/// Blocks import queue API.
@@ -906,7 +898,7 @@ pub fn import_single_block<B: BlockT, V: Verifier<B>>(
r => return Ok(r), // Any other successful result means that the block is already imported.
}
let (import_block, new_authorities) = verifier.verify(block_origin, header, justification, block.body)
let (import_block, maybe_keys) = verifier.verify(block_origin, header, justification, block.body)
.map_err(|msg| {
if let Some(ref peer) = peer {
trace!(target: "sync", "Verifying {}({}) from {} failed: {}", number, hash, peer, msg);
@@ -917,8 +909,8 @@ pub fn import_single_block<B: BlockT, V: Verifier<B>>(
})?;
let mut cache = HashMap::new();
if let Some(authorities) = new_authorities {
cache.insert(crate::well_known_cache_keys::AUTHORITIES, authorities.encode());
if let Some(keys) = maybe_keys {
cache.extend(keys.into_iter());
}
import_error(import_handle.import_block(import_block, cache))
@@ -979,7 +971,7 @@ mod tests {
header: B::Header,
justification: Option<Justification>,
body: Option<Vec<B::Extrinsic>>,
) -> Result<(ImportBlock<B>, Option<Vec<AuthorityIdFor<B>>>), String> {
) -> Result<(ImportBlock<B>, Option<Vec<(CacheKeyId, Vec<u8>)>>), String> {
Ok((ImportBlock {
origin,
header,
+2 -11
View File
@@ -32,8 +32,7 @@
use std::sync::Arc;
use std::time::Duration;
use runtime_primitives::generic::BlockId;
use runtime_primitives::traits::{AuthorityIdFor, Block, DigestFor};
use runtime_primitives::traits::{Block, DigestFor};
use futures::prelude::*;
pub use inherents::InherentData;
@@ -54,14 +53,6 @@ pub use block_import::{
};
pub use select_chain::SelectChain;
/// Trait for getting the authorities at a given block.
pub trait Authorities<B: Block> {
type Error: std::error::Error + Send + 'static;
/// Get the authorities at the given block.
fn authorities(&self, at: &BlockId<B>) -> Result<Vec<AuthorityIdFor<B>>, Self::Error>;
}
/// Environment producer for a Consensus instance. Creates proposer instance and communication streams.
pub trait Environment<B: Block> {
/// The proposer type this creates.
@@ -71,7 +62,7 @@ pub trait Environment<B: Block> {
/// Initialize the proposal logic on top of a specific header. Provide
/// the authorities at that header.
fn init(&self, parent_header: &B::Header, authorities: &[AuthorityIdFor<B>])
fn init(&self, parent_header: &B::Header)
-> Result<Self::Proposer, Self::Error>;
}
@@ -112,25 +112,24 @@ impl<AuthorityId: Eq + Clone + std::hash::Hash> OfflineTracker<AuthorityId> {
#[cfg(test)]
mod tests {
use super::*;
use primitives::ed25519::Public as AuthorityId;
#[test]
fn validator_offline() {
let mut tracker = OfflineTracker::<AuthorityId>::new();
let v = AuthorityId::from_raw([0; 32]);
let v2 = AuthorityId::from_raw([1; 32]);
let v3 = AuthorityId::from_raw([2; 32]);
tracker.note_round_end(v.clone(), true);
tracker.note_round_end(v2.clone(), true);
tracker.note_round_end(v3.clone(), true);
let mut tracker = OfflineTracker::<u64>::new();
let v1 = 1;
let v2 = 2;
let v3 = 3;
tracker.note_round_end(v1, true);
tracker.note_round_end(v2, true);
tracker.note_round_end(v3, true);
let slash_time = REPORT_TIME + Duration::from_secs(5);
tracker.observed.get_mut(&v).unwrap().offline_since -= slash_time;
tracker.observed.get_mut(&v1).unwrap().offline_since -= slash_time;
tracker.observed.get_mut(&v2).unwrap().offline_since -= slash_time;
assert_eq!(tracker.reports(&[v.clone(), v2.clone(), v3.clone()]), vec![0, 1]);
assert_eq!(tracker.reports(&[v1, v2, v3]), vec![0, 1]);
tracker.note_new_block(&[v.clone(), v3.clone()]);
assert_eq!(tracker.reports(&[v, v2, v3]), vec![0]);
tracker.note_new_block(&[v1, v3]);
assert_eq!(tracker.reports(&[v1, v2, v3]), vec![0]);
}
}
-1
View File
@@ -15,7 +15,6 @@ client = { package = "substrate-client", path = "../../client" }
transaction_pool = { package = "substrate-transaction-pool", path = "../../transaction-pool" }
runtime_support = { package = "srml-support", path = "../../../srml/support" }
srml-system = { path = "../../../srml/system" }
srml-consensus = { path = "../../../srml/consensus" }
runtime_primitives = { package = "sr-primitives", path = "../../sr-primitives" }
runtime_version = { package = "sr-version", path = "../../sr-version" }
runtime_io = { package = "sr-io", path = "../../sr-io" }