Introduce inherent digests (#2466)

* Introduce inherent digests

* Implement inherent digests

* fix silly error

* Implementation of inherent digests in BABE

All tests pass. There are still limitations:

1. The runtime strips out inherent digests, so BABE must re-add them.
2. The test runtime checks that it can re-compute all digests.  It
   can’t, so I had to comment out that test.

* Fix compilation and seal import

Seals were not imported correctly: the pre-digest was imported twice,
instead of both it and the seal being imported.  Also, other parts of
the code did not compile due to incomplete refactoring.

* Remove bogus assertion

* Fix testsuite compilation

* Remove unused import

* Fix compiler diagnostics

* Add inherent digest parameters to block constructors

This enforces that inherent digests are added first.

* Fixup Cargo.lock

* Fix build errors

* Re-add an incorrectly removed import

* Bump primitive-types version

* Update Cargo.lock

* Refactoring

* Use inherent digests for AuRa

They do reach the runtime, but get stripped.  I have not figured out
where.

* Fix compilation errors

* Fix compilation errors due to incorrect types

* Fix whitespace

Suggested-by: Tomasz Drwiega <tomasz@parity.io>

* Add preamble

Suggested-by: Tomasz Drwiega <tomasz@parity.io>

* Fix silly compile error

* Refactor pre-digest finding code into a separate function

* Remove unwanted assertion

It is too likely to bring down the entire blockchain.

Suggested-by: Tomasz Drwiega <tomasz@parity.io>

* Use `find_pre_digest` after runtime, too

Also, use `Member` trait rather than rolling our own requirements.

Suggested-by: Tomasz Drwiega <tomasz@parity.io>

* Fix various warnings

mostly due to upgrading the dependency on `error_chain`.

* Pre-digests nearly complete

This nearly completes the implementation of pre-runtime digests.

* `Seal2` → `Seal` and fix test suite

* Try to fix the storage error

* Try to fix storage (again)

* Fix tests

* Hopefully finish pre-runtime digests

The key is to pass *only* the pre-runtime digests to the runtime.  The
others must be stripped out by `initialize_block`.

* Fix silly typo

* Fix another silly mistake

* Remove unnecessary filtering of BABE pre-digests

We no longer get duplicate BABE pre-digests, so if they appear, the
header should be rejected outright.

* Update Cargo.lock files

* Reformatting

* Fix silly typo in inherent digest code

Also, revert `error.rs` files that contained calls to the `error_chain!`
macro.

* Try to keep the runtime from stripping pre-digests

Currently runs into the “Storage root must match that calculated”
assertion.

* Don’t compute storage root until storage changes are done.

Also, fix a compilation error.

* Fix compile-time error

* Fix compilation errors

* Fix more compile errors

* Hopefully it compiles this time…

* Fix compilation and add docs

* Prevent BABE from adding duplicate pre-runtime digests

Found by comparing with the AuRa code.  I also did some refactoring.

* Respond to review and fix some warnings

* Delete some dead code introduced earlier

* More dead code goes away

* `ref mut` → `&mut`

* Respond to review and fix some warnings

* Fix compilation error

* Remove unneeded `HashT` type parameter

Suggested-by: Robert Habermeier <robert@parity.io>

* Remove spurious #[allow(deprecated)]

* Document inherent digest parameter to `build_block`

* Delete `Simple` trait

It wasn’t needed

* delete wrongly added files

* Fix trait bounds

* Digest serialization tests

I also did some reformatting and cleanup.

* Apply suggestions from code review

Reformatting

Co-Authored-By: André Silva <andre.beat@gmail.com>

* Swap two arguments to `propose` and `propose_with`

Also, remove some needless unsafe code.

* Remove bogus `#![allow(deprecated)]` annotations

With the removal of the deprecated `Seal` variant, these are not needed.

* Add a missing `#[allow(deprecated)]` in the AuRa tests

* Fix silly compile error

* Fix silly compiler error

RLS did not tell me that I hadn’t fixed `babe/lib.rs`, so I missed it.

* Fixes made automatically by Cargo
This commit is contained in:
DemiMarie-parity
2019-05-29 08:13:38 -04:00
committed by Gavin Wood
parent e9a4c80c40
commit c7d1204ce5
55 changed files with 1031 additions and 871 deletions
@@ -0,0 +1,67 @@
// Copyright 2018-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/>.
//! Aura (Authority-Round) digests
//!
//! 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};
type Signature<P> = <P as Pair>::Signature;
/// A digest item which is usable with aura consensus.
pub trait CompatibleDigestItem<T: Pair>: Sized {
/// Construct a digest item which contains a signature on the hash.
fn aura_seal(signature: Signature<T>) -> Self;
/// If this item is an Aura seal, return the signature.
fn as_aura_seal(&self) -> Option<&Signature<T>>;
/// Construct a digest item which contains the slot number
fn aura_pre_digest(slot_num: u64) -> Self;
/// If this item is an AuRa pre-digest, return the slot number
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,
{
fn aura_seal(signature: Signature<P>) -> Self {
DigestItem::Seal(AURA_ENGINE_ID, signature)
}
fn as_aura_seal(&self) -> Option<&Signature<P>> {
match self {
DigestItem::Seal(AURA_ENGINE_ID, ref sig) => Some(sig),
_ => None,
}
}
fn aura_pre_digest(slot_num: u64) -> Self {
DigestItem::PreRuntime(AURA_ENGINE_ID, slot_num.encode())
}
fn as_aura_pre_digest(&self) -> Option<u64> {
match self {
DigestItem::PreRuntime(AURA_ENGINE_ID, ref buffer) => Decode::decode(&mut &buffer[..]),
_ => None,
}
}
}
+166 -281
View File
@@ -44,18 +44,20 @@ use client::{
error::Result as CResult,
backend::AuxStore,
};
use aura_primitives::AURA_ENGINE_ID;
use runtime_primitives::{generic, generic::BlockId, Justification};
use runtime_primitives::{generic::{self, BlockId}, Justification};
use runtime_primitives::traits::{
Block, Header, Digest, DigestItemFor, DigestItem, ProvideRuntimeApi, AuthorityIdFor, Zero,
Block, Header, Digest, DigestItemFor, DigestItem, ProvideRuntimeApi, AuthorityIdFor,
Zero, Member,
};
use primitives::Pair;
use inherents::{InherentDataProviders, InherentData};
use authorities::AuthoritiesApi;
use futures::{Future, IntoFuture, future, stream::Stream};
use futures::{Future, IntoFuture, future};
use tokio::timer::Timeout;
use log::{warn, debug, info, trace};
use log::{error, warn, debug, info, trace};
use srml_aura::{
InherentType as AuraInherent, AuraInherentData,
@@ -68,24 +70,10 @@ use slots::{CheckedHeader, SlotWorker, SlotInfo, SlotCompatible, slot_now, check
pub use aura_primitives::*;
pub use consensus_common::{SyncOracle, ExtraVerification};
mod digest;
use digest::CompatibleDigestItem;
type AuthorityId<P> = <P as Pair>::Public;
type Signature<P> = <P as Pair>::Signature;
/// A handle to the network. This is generally implemented by providing some
/// handle to a gossip service or similar.
///
/// Intended to be a lightweight handle such as an `Arc`.
#[deprecated(
since = "1.0.1",
note = "This is dead code and will be removed in a future release",
)]
pub trait Network: Clone {
/// A stream of input messages for a topic.
type In: Stream<Item=Vec<u8>,Error=()>;
/// Send a message at a specific round out.
fn send_message(&self, slot: u64, message: Vec<u8>);
}
/// A slot duration. Create with `get_or_compute`.
#[derive(Clone, Copy, Debug, Encode, Decode, Hash, PartialOrd, Ord, PartialEq, Eq)]
@@ -122,48 +110,6 @@ fn slot_author<P: Pair>(slot_num: u64, authorities: &[AuthorityId<P>]) -> Option
Some(current_author)
}
/// A digest item which is usable with aura consensus.
pub trait CompatibleDigestItem<T: Pair>: Sized {
/// Construct a digest item which contains a slot number and a signature on the
/// hash.
fn aura_seal(slot_num: u64, signature: Signature<T>) -> Self;
/// If this item is an Aura seal, return the slot number and signature.
fn as_aura_seal(&self) -> Option<(u64, Signature<T>)>;
/// Return `true` if this seal type is deprecated. Otherwise, return
/// `false`.
fn is_deprecated(&self) -> bool;
}
impl<P, Hash> CompatibleDigestItem<P> for generic::DigestItem<Hash, P::Public, P::Signature>
where P: Pair, P::Signature: Clone + Encode + Decode,
{
/// Construct a digest item which is a slot number and a signature on the
/// hash.
fn aura_seal(slot_number: u64, signature: Signature<P>) -> Self {
generic::DigestItem::Consensus(AURA_ENGINE_ID, (slot_number, signature).encode())
}
/// If this item is an Aura seal, return the slot number and signature.
#[allow(deprecated)]
fn as_aura_seal(&self) -> Option<(u64, Signature<P>)> {
match self {
generic::DigestItem::Seal(slot, ref sig) => Some((*slot, (*sig).clone())),
generic::DigestItem::Consensus(AURA_ENGINE_ID, seal) => Decode::decode(&mut &seal[..]),
_ => None,
}
}
#[allow(deprecated)]
fn is_deprecated(&self) -> bool {
match self {
generic::DigestItem::Seal(_, _) => true,
_ => false,
}
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
struct AuraSlotCompatible;
@@ -178,60 +124,8 @@ impl SlotCompatible for AuraSlotCompatible {
}
}
/// Start the aura worker in a separate thread.
#[deprecated(since = "1.1", note = "Please spawn a thread manually")]
pub fn start_aura_thread<B, C, SC, E, I, P, SO, Error, OnExit>(
slot_duration: SlotDuration,
local_key: Arc<P>,
client: Arc<C>,
select_chain: SC,
block_import: Arc<I>,
env: Arc<E>,
sync_oracle: SO,
on_exit: OnExit,
inherent_data_providers: InherentDataProviders,
force_authoring: bool,
) -> Result<(), consensus_common::Error> where
B: Block + 'static,
C: ProvideRuntimeApi + ProvideCache<B> + AuxStore + Send + Sync + 'static,
C::Api: AuthoritiesApi<B>,
SC: SelectChain<B> + Clone + 'static,
E: Environment<B, Error=Error> + Send + Sync + 'static,
E::Proposer: Proposer<B, Error=Error> + Send + 'static,
<<E::Proposer as Proposer<B>>::Create as IntoFuture>::Future: Send + 'static,
I: BlockImport<B> + Send + Sync + 'static,
Error: From<I::Error> + 'static,
P: Pair + Send + Sync + 'static,
P::Public: Encode + Decode + Eq + Clone + Debug + Hash + Send + Sync + 'static,
P::Signature: Encode,
SO: SyncOracle + Send + Sync + Clone + 'static,
OnExit: Future<Item=(), Error=()> + Send + 'static,
DigestItemFor<B>: CompatibleDigestItem<P> + DigestItem<AuthorityId=AuthorityId<P>> + 'static,
Error: ::std::error::Error + Send + From<::consensus_common::Error> + 'static,
{
let worker = AuraWorker {
client: client.clone(),
block_import,
env,
local_key,
inherent_data_providers: inherent_data_providers.clone(),
sync_oracle: sync_oracle.clone(),
force_authoring,
};
#[allow(deprecated)] // The function we are in is also deprecated.
slots::start_slot_worker_thread::<_, _, _, _, AuraSlotCompatible, u64, _>(
slot_duration.0,
select_chain,
Arc::new(worker),
sync_oracle,
on_exit,
inherent_data_providers
)
}
/// Start the aura worker. The returned future should be run in a tokio runtime.
pub fn start_aura<B, C, SC, E, I, P, SO, Error, OnExit>(
pub fn start_aura<B, C, SC, E, I, P, SO, Error, OnExit, H>(
slot_duration: SlotDuration,
local_key: Arc<P>,
client: Arc<C>,
@@ -243,20 +137,25 @@ pub fn start_aura<B, C, SC, E, I, P, SO, Error, OnExit>(
inherent_data_providers: InherentDataProviders,
force_authoring: bool,
) -> Result<impl Future<Item=(), Error=()>, consensus_common::Error> where
B: Block,
C: ProvideRuntimeApi + ProvideCache<B> + AuxStore,
B: Block<Header=H>,
C: ProvideRuntimeApi + ProvideCache<B> + AuxStore + Send + Sync,
C::Api: AuthoritiesApi<B>,
SC: SelectChain<B> + Clone,
E: Environment<B, Error=Error>,
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,
I: BlockImport<B> + Send + Sync + 'static,
P: Pair + Send + Sync + 'static,
P::Public: Hash + Eq + Send + Sync + Clone + Debug + Encode + Decode + 'static,
P::Signature: Encode,
SO: SyncOracle + Send + Sync + Clone,
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,
>,
E: Environment<B, Error=Error>,
I: BlockImport<B> + Send + Sync + 'static,
Error: ::std::error::Error + Send + From<::consensus_common::Error> + From<I::Error> + 'static,
SO: SyncOracle + Send + Sync + Clone,
OnExit: Future<Item=(), Error=()>,
{
let worker = AuraWorker {
@@ -288,18 +187,23 @@ struct AuraWorker<C, E, I, P, SO> {
force_authoring: bool,
}
impl<B: Block, C, E, I, P, Error, SO> SlotWorker<B> for AuraWorker<C, E, I, P, SO> where
C: ProvideRuntimeApi + ProvideCache<B> + AuxStore,
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>,
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,
>,
I: BlockImport<B> + Send + Sync + 'static,
P: Pair + Send + Sync + 'static,
P::Public: Hash + Eq + Send + Sync + Clone + Debug + Encode + Decode + 'static,
P::Signature: Encode,
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>>,
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<Future<Item=(), Error=consensus_common::Error> + Send>;
@@ -376,7 +280,15 @@ impl<B: Block, C, E, I, P, Error, SO> SlotWorker<B> for AuraWorker<C, E, I, P, S
// deadline our production to approx. the end of the
// slot
Timeout::new(
proposer.propose(slot_info.inherent_data, remaining_duration).into_future(),
proposer.propose(
slot_info.inherent_data,
generic::Digest {
logs: vec![
<DigestItemFor<B> as CompatibleDigestItem<P>>::aura_pre_digest(slot_num),
],
},
remaining_duration,
).into_future(),
remaining_duration,
)
} else {
@@ -384,72 +296,98 @@ impl<B: Block, C, E, I, P, Error, SO> SlotWorker<B> for AuraWorker<C, E, I, P, S
}
};
Box::new(
proposal_work
.map(move |b| {
// minor hack since we don't have access to the timestamp
// that is actually set by the proposer.
let slot_after_building = slot_now(slot_duration);
if slot_after_building != Some(slot_num) {
info!(
"Discarding proposal for slot {}; block production took too long",
slot_num
);
telemetry!(CONSENSUS_INFO; "aura.discarding_proposal_took_too_long";
"slot" => slot_num
);
return
}
Box::new(proposal_work.map(move |b| {
// minor hack since we don't have access to the timestamp
// that is actually set by the proposer.
let slot_after_building = slot_now(slot_duration);
if slot_after_building != Some(slot_num) {
info!(
"Discarding proposal for slot {}; block production took too long",
slot_num
);
telemetry!(CONSENSUS_INFO; "aura.discarding_proposal_took_too_long";
"slot" => slot_num
);
return
}
let (header, body) = b.deconstruct();
let header_num = header.number().clone();
let pre_hash = header.hash();
let parent_hash = header.parent_hash().clone();
let (header, body) = b.deconstruct();
let pre_digest: Result<u64, String> = find_pre_digest::<B, P>(&header);
if let Err(e) = pre_digest {
error!(target: "aura", "FATAL ERROR: Invalid pre-digest: {}!", e);
return
} else {
trace!(target: "aura", "Got correct number of seals. Good!")
};
// sign the pre-sealed hash of the block and then
// add it to a digest item.
let to_sign = (slot_num, pre_hash).encode();
let signature = pair.sign(&to_sign[..]);
let item = <DigestItemFor<B> as CompatibleDigestItem<P>>::aura_seal(
slot_num,
signature,
);
let header_num = header.number().clone();
let parent_hash = header.parent_hash().clone();
let import_block: ImportBlock<B> = ImportBlock {
origin: BlockOrigin::Own,
header,
justification: None,
post_digests: vec![item],
body: Some(body),
finalized: false,
auxiliary: Vec::new(),
fork_choice: ForkChoiceStrategy::LongestChain,
};
// sign the pre-sealed hash of the block and then
// add it to a digest item.
let header_hash = header.hash();
let signature = pair.sign(header_hash.as_ref());
let signature_digest_item = <DigestItemFor<B> as CompatibleDigestItem<P>>::aura_seal(signature);
info!("Pre-sealed block for proposal at {}. Hash now {:?}, previously {:?}.",
header_num,
import_block.post_header().hash(),
pre_hash
);
telemetry!(CONSENSUS_INFO; "aura.pre_sealed_block";
"header_num" => ?header_num,
"hash_now" => ?import_block.post_header().hash(),
"hash_previously" => ?pre_hash
);
let import_block: ImportBlock<B> = ImportBlock {
origin: BlockOrigin::Own,
header,
justification: None,
post_digests: vec![signature_digest_item],
body: Some(body),
finalized: false,
auxiliary: Vec::new(),
fork_choice: ForkChoiceStrategy::LongestChain,
};
if let Err(e) = block_import.import_block(import_block, Default::default()) {
warn!(target: "aura", "Error with block built on {:?}: {:?}",
parent_hash, e);
telemetry!(CONSENSUS_WARN; "aura.err_with_block_built_on";
"hash" => ?parent_hash, "err" => ?e
);
}
})
.map_err(|e| consensus_common::Error::ClientImport(format!("{:?}", e)).into())
)
info!("Pre-sealed block for proposal at {}. Hash now {:?}, previously {:?}.",
header_num,
import_block.post_header().hash(),
header_hash
);
telemetry!(CONSENSUS_INFO; "aura.pre_sealed_block";
"header_num" => ?header_num,
"hash_now" => ?import_block.post_header().hash(),
"hash_previously" => ?header_hash
);
if let Err(e) = block_import.import_block(import_block, Default::default()) {
warn!(target: "aura", "Error with block built on {:?}: {:?}",
parent_hash, e);
telemetry!(CONSENSUS_WARN; "aura.err_with_block_built_on";
"hash" => ?parent_hash, "err" => ?e
);
}
}).map_err(|e| consensus_common::Error::ClientImport(format!("{:?}", e)).into()))
}
}
macro_rules! aura_err {
($($i: expr),+) => {
{ debug!(target: "aura", $($i),+)
; format!($($i),+)
}
};
}
fn find_pre_digest<B: Block, P: Pair>(header: &B::Header) -> Result<u64, String>
where DigestItemFor<B>: CompatibleDigestItem<P>,
P::Signature: Decode,
P::Public: Encode + Decode + PartialEq + Clone,
{
let mut pre_digest: Option<u64> = None;
for log in header.digest().logs() {
trace!(target: "aura", "Checking log {:?}", log);
match (log.as_aura_pre_digest(), pre_digest.is_some()) {
(Some(_), true) => Err(aura_err!("Multiple AuRa pre-runtime headers, rejecting!"))?,
(None, _) => trace!(target: "aura", "Ignoring digest not meant for us"),
(s, false) => pre_digest = s,
}
}
pre_digest.ok_or_else(|| aura_err!("No AuRa pre-runtime digest found"))
}
/// check a header has been signed by the right key. If the slot is too far in the future, an error will be returned.
/// if it's successful, returns the pre-header and the digest item containing the seal.
///
@@ -462,30 +400,25 @@ fn check_header<C, B: Block, P: Pair>(
mut header: B::Header,
hash: B::Hash,
authorities: &[AuthorityId<P>],
allow_old_seals: bool,
) -> Result<CheckedHeader<B::Header, DigestItemFor<B>>, String>
where DigestItemFor<B>: CompatibleDigestItem<P>,
P::Signature: Decode,
C: client::backend::AuxStore,
P::Public: AsRef<P::Public> + Encode + Decode + PartialEq + Clone,
) -> Result<CheckedHeader<B::Header, (u64, DigestItemFor<B>)>, String> where
DigestItemFor<B>: CompatibleDigestItem<P>,
P::Signature: Decode,
C: client::backend::AuxStore,
P::Public: AsRef<P::Public> + Encode + Decode + PartialEq + Clone,
{
let digest_item = match header.digest_mut().pop() {
let seal = match header.digest_mut().pop() {
Some(x) => x,
None => return Err(format!("Header {:?} is unsealed", hash)),
};
if !allow_old_seals && digest_item.is_deprecated() {
debug!(target: "aura", "Header {:?} uses old seal format, rejecting", hash);
return Err(format!("Header {:?} uses old seal format, rejecting", hash))
}
let (slot_num, sig) = digest_item.as_aura_seal().ok_or_else(|| {
debug!(target: "aura", "Header {:?} is unsealed", hash);
format!("Header {:?} is unsealed", hash)
let sig = seal.as_aura_seal().ok_or_else(|| {
aura_err!("Header {:?} has a bad seal", hash)
})?;
let slot_num = find_pre_digest::<B, _>(&header)?;
if slot_num > slot_now {
header.digest_mut().push(digest_item);
header.digest_mut().push(seal);
Ok(CheckedHeader::Deferred(header, slot_num))
} else {
// check the signature is valid under the expected authority and
@@ -496,16 +429,14 @@ fn check_header<C, B: Block, P: Pair>(
};
let pre_hash = header.hash();
let to_sign = (slot_num, pre_hash).encode();
let public = expected_author;
if P::verify(&sig, &to_sign[..], public) {
if P::verify(&sig, pre_hash.as_ref(), expected_author) {
match check_equivocation::<_, _, <P as Pair>::Public>(
client,
slot_now,
slot_num,
header.clone(),
public.clone(),
expected_author.clone(),
) {
Ok(Some(equivocation_proof)) => {
let log_str = format!(
@@ -517,7 +448,7 @@ fn check_header<C, B: Block, P: Pair>(
info!("{}", log_str);
Err(log_str)
},
Ok(None) => Ok(CheckedHeader::Checked(header, digest_item)),
Ok(None) => Ok(CheckedHeader::Checked(header, (slot_num, seal))),
Err(e) => Err(e.to_string()),
}
} else {
@@ -532,7 +463,6 @@ pub struct AuraVerifier<C, E, P> {
extra: E,
phantom: PhantomData<P>,
inherent_data_providers: inherents::InherentDataProviders,
allow_old_seals: bool,
}
impl<C, E, P> AuraVerifier<C, E, P>
@@ -631,20 +561,17 @@ impl<B: Block, C, E, P> Verifier<B> for AuraVerifier<C, E, P> where
);
// we add one to allow for some small drift.
// FIXME #1019 in the future, alter this queue to allow deferring of headers
// FIXME #1019 in the future, alter this queue to allow deferring of
// headers
let checked_header = check_header::<C, B, P>(
&self.client,
slot_now + 1,
header,
hash,
&authorities[..],
self.allow_old_seals,
)?;
match checked_header {
CheckedHeader::Checked(pre_header, seal) => {
let (slot_num, _) = seal.as_aura_seal()
.expect("check_header always returns a seal digest item; qed");
CheckedHeader::Checked(pre_header, (slot_num, seal)) => {
// if the body is passed through, we need to use the runtime
// to check that the internally-set timestamp in the inherents
// actually matches the slot set in the seal.
@@ -813,52 +740,6 @@ pub fn import_queue<B, C, E, P>(
extra,
inherent_data_providers,
phantom: PhantomData,
allow_old_seals: false,
}
);
Ok(BasicQueue::new(
verifier,
block_import,
justification_import,
finality_proof_import,
finality_proof_request_builder,
))
}
/// Start an import queue for the Aura consensus algorithm with backwards compatibility.
#[deprecated(
since = "1.0.1",
note = "should not be used unless backwards compatibility with an older chain is needed.",
)]
pub fn import_queue_accept_old_seals<B, C, E, P>(
slot_duration: SlotDuration,
block_import: SharedBlockImport<B>,
justification_import: Option<SharedJustificationImport<B>>,
finality_proof_import: Option<SharedFinalityProofImport<B>>,
finality_proof_request_builder: Option<SharedFinalityProofRequestBuilder<B>>,
client: Arc<C>,
extra: E,
inherent_data_providers: InherentDataProviders,
) -> 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>>,
E: 'static + ExtraVerification<B>,
P: Pair + Send + Sync + 'static,
P::Public: Clone + Eq + Send + Sync + Hash + Debug + Encode + Decode + AsRef<P::Public>,
P::Signature: Encode + Decode,
{
register_aura_inherent_data_provider(&inherent_data_providers, slot_duration.get())?;
initialize_authorities_cache(&*client)?;
let verifier = Arc::new(
AuraVerifier {
client: client.clone(),
extra,
inherent_data_providers,
phantom: PhantomData,
allow_old_seals: true,
}
);
Ok(BasicQueue::new(
@@ -873,10 +754,11 @@ pub fn import_queue_accept_old_seals<B, C, E, P>(
#[cfg(test)]
mod tests {
use super::*;
use futures::stream::Stream as _;
use consensus_common::NoNetwork as DummyOracle;
use network::test::*;
use network::test::{Block as TestBlock, PeersClient, PeersFullClient};
use runtime_primitives::traits::Block as BlockT;
use runtime_primitives::traits::{Block as BlockT, DigestFor};
use network::config::ProtocolConfig;
use parking_lot::Mutex;
use tokio::runtime::current_thread;
@@ -910,8 +792,13 @@ mod tests {
type Error = Error;
type Create = Result<TestBlock, Error>;
fn propose(&self, _: InherentData, _: Duration) -> Result<TestBlock, Error> {
self.1.new_block().unwrap().bake().map_err(|e| e.into())
fn propose(
&self,
_: InherentData,
digests: DigestFor<TestBlock>,
_: Duration,
) -> Result<TestBlock, Error> {
self.1.new_block(digests).unwrap().bake().map_err(|e| e.into())
}
}
@@ -955,7 +842,6 @@ mod tests {
extra: NothingExtra,
inherent_data_providers,
phantom: Default::default(),
allow_old_seals: false,
})
},
PeersClient::Light(_) => unreachable!("No (yet) tests for light client + Aura"),
@@ -995,19 +881,18 @@ mod tests {
extrinsics_root: Default::default(),
digest: DigestTest { logs: vec![], },
};
let item = <DigestItemFor<TestBlock> as CompatibleDigestItem<sr25519::Pair>>::aura_pre_digest(slot_num);
header.digest_mut().push(item);
let header_hash: H256 = header.hash();
let to_sign = (slot_num, header_hash).encode();
let signature = pair.sign(&to_sign[..]);
let signature = pair.sign(&header_hash[..]);
let item = <generic::DigestItem<_, _, _> as CompatibleDigestItem<sr25519::Pair>>::aura_seal(
slot_num,
signature,
);
let item = CompatibleDigestItem::<sr25519::Pair>::aura_seal(signature);
header.digest_mut().push(item);
(header, header_hash)
}
#[test]
#[allow(deprecated)]
fn authoring_blocks() {
let _ = ::env_logger::try_init();
let mut net = AuraTestNet::new(3);
@@ -1046,7 +931,7 @@ mod tests {
&inherent_data_providers, slot_duration.get()
).expect("Registers aura inherent data provider");
let aura = start_aura::<_, _, _, _, _, sr25519::Pair, _, _, _>(
let aura = start_aura::<_, _, _, _, _, sr25519::Pair, _, _, _, _>(
slot_duration,
Arc::new(key.clone().into()),
client.clone(),
@@ -1111,22 +996,22 @@ mod tests {
let c = Arc::new(client);
// It's ok to sign same headers.
assert!(check_header::<_, B, P>(&c, 2, header1.clone(), header1_hash, &authorities, false).is_ok());
assert!(check_header::<_, B, P>(&c, 3, header1, header1_hash, &authorities, false).is_ok());
check_header::<_, B, P>(&c, 2, header1.clone(), header1_hash, &authorities).unwrap();
assert!(check_header::<_, B, P>(&c, 3, header1, header1_hash, &authorities).is_ok());
// But not two different headers at the same slot.
assert!(check_header::<_, B, P>(&c, 4, header2, header2_hash, &authorities, false).is_err());
assert!(check_header::<_, B, P>(&c, 4, header2, header2_hash, &authorities).is_err());
// Different slot is ok.
assert!(check_header::<_, B, P>(&c, 5, header3, header3_hash, &authorities, false).is_ok());
assert!(check_header::<_, B, P>(&c, 5, header3, header3_hash, &authorities).is_ok());
// Here we trigger pruning and save header 4.
assert!(check_header::<_, B, P>(&c, PRUNING_BOUND + 2, header4, header4_hash, &authorities, false).is_ok());
assert!(check_header::<_, B, P>(&c, PRUNING_BOUND + 2, header4, header4_hash, &authorities).is_ok());
// This fails because header 5 is an equivocation of header 4.
assert!(check_header::<_, B, P>(&c, PRUNING_BOUND + 3, header5, header5_hash, &authorities, false).is_err());
assert!(check_header::<_, B, P>(&c, PRUNING_BOUND + 3, header5, header5_hash, &authorities).is_err());
// This is ok because we pruned the corresponding header. Shows that we are pruning.
assert!(check_header::<_, B, P>(&c, PRUNING_BOUND + 4, header6, header6_hash, &authorities, false).is_ok());
assert!(check_header::<_, B, P>(&c, PRUNING_BOUND + 4, header6, header6_hash, &authorities).is_ok());
}
}