// 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 .
//! BABE testsuite
// FIXME #2532: need to allow deprecated until refactor is done
// https://github.com/paritytech/substrate/issues/2532
#![allow(deprecated)]
use super::*;
use authorship::claim_slot;
use babe_primitives::{AuthorityPair, SlotNumber};
use block_builder::BlockBuilder;
use consensus_common::NoNetwork as DummyOracle;
use consensus_common::import_queue::{
BoxBlockImport, BoxJustificationImport, BoxFinalityProofImport,
};
use network::test::*;
use network::test::{Block as TestBlock, PeersClient};
use network::config::BoxFinalityProofRequestBuilder;
use sr_primitives::{generic::DigestItem, traits::{Block as BlockT, DigestFor}};
use network::config::ProtocolConfig;
use tokio::runtime::current_thread;
use client_api::BlockchainEvents;
use test_client;
use log::debug;
use std::{time::Duration, cell::RefCell};
type Item = DigestItem;
type Error = client::error::Error;
type TestClient = client::Client<
test_client::Backend,
test_client::Executor,
TestBlock,
test_client::runtime::RuntimeApi,
>;
#[derive(Copy, Clone, PartialEq)]
enum Stage {
PreSeal,
PostSeal,
}
type Mutator = Arc;
#[derive(Clone)]
struct DummyFactory {
client: Arc,
epoch_changes: crate::SharedEpochChanges,
config: Config,
mutator: Mutator,
}
struct DummyProposer {
factory: DummyFactory,
parent_hash: Hash,
parent_number: u64,
parent_slot: SlotNumber,
}
impl Environment for DummyFactory {
type Proposer = DummyProposer;
type Error = Error;
fn init(&mut self, parent_header: &::Header)
-> Result
{
let parent_slot = crate::find_pre_digest::(parent_header)
.expect("parent header has a pre-digest")
.slot_number();
Ok(DummyProposer {
factory: self.clone(),
parent_hash: parent_header.hash(),
parent_number: *parent_header.number(),
parent_slot,
})
}
}
impl DummyProposer {
fn propose_with(&mut self, pre_digests: DigestFor)
-> future::Ready>
{
use codec::Encode;
let block_builder = self.factory.client.new_block_at(
&BlockId::Hash(self.parent_hash),
pre_digests,
).unwrap();
let mut block = match block_builder.bake().map_err(|e| e.into()) {
Ok(b) => b,
Err(e) => return future::ready(Err(e)),
};
let this_slot = crate::find_pre_digest::(block.header())
.expect("baked block has valid pre-digest")
.slot_number();
// figure out if we should add a consensus digest, since the test runtime
// doesn't.
let epoch_changes = self.factory.epoch_changes.lock();
let epoch = epoch_changes.epoch_for_child_of(
descendent_query(&*self.factory.client),
&self.parent_hash,
self.parent_number,
this_slot,
|slot| self.factory.config.genesis_epoch(slot),
)
.expect("client has data to find epoch")
.expect("can compute epoch for baked block")
.into_inner();
let first_in_epoch = self.parent_slot < epoch.start_slot;
if first_in_epoch {
// push a `Consensus` digest signalling next change.
// we just reuse the same randomness and authorities as the prior
// epoch. this will break when we add light client support, since
// that will re-check the randomness logic off-chain.
let digest_data = ConsensusLog::NextEpochData(NextEpochDescriptor {
authorities: epoch.authorities.clone(),
randomness: epoch.randomness.clone(),
}).encode();
let digest = DigestItem::Consensus(BABE_ENGINE_ID, digest_data);
block.header.digest_mut().push(digest)
}
// mutate the block header according to the mutator.
(self.factory.mutator)(&mut block.header, Stage::PreSeal);
future::ready(Ok(block))
}
}
impl Proposer for DummyProposer {
type Error = Error;
type Create = future::Ready>;
fn propose(
&mut self,
_: InherentData,
pre_digests: DigestFor,
_: Duration,
) -> Self::Create {
self.propose_with(pre_digests)
}
}
thread_local! {
static MUTATOR: RefCell = RefCell::new(Arc::new(|_, _|()));
}
#[derive(Clone)]
struct PanickingBlockImport(B);
impl> BlockImport for PanickingBlockImport {
type Error = B::Error;
fn import_block(
&mut self,
block: BlockImportParams,
new_cache: HashMap>,
) -> Result {
Ok(self.0.import_block(block, new_cache).expect("importing block failed"))
}
fn check_block(
&mut self,
block: BlockCheckParams,
) -> Result {
Ok(self.0.check_block(block).expect("checking block failed"))
}
}
pub struct BabeTestNet {
peers: Vec, DummySpecialization>>,
}
type TestHeader = ::Header;
type TestExtrinsic = ::Extrinsic;
pub struct TestVerifier {
inner: BabeVerifier<
test_client::Backend,
test_client::Executor,
TestBlock,
test_client::runtime::RuntimeApi,
PeersFullClient,
>,
mutator: Mutator,
}
impl Verifier for TestVerifier {
/// Verify the given data and return the BlockImportParams and an optional
/// new set of validators to import. If not, err with an Error-Message
/// presented to the User in the logs.
fn verify(
&mut self,
origin: BlockOrigin,
mut header: TestHeader,
justification: Option,
body: Option>,
) -> Result<(BlockImportParams, Option)>>), String> {
// apply post-sealing mutations (i.e. stripping seal, if desired).
(self.mutator)(&mut header, Stage::PostSeal);
Ok(self.inner.verify(origin, header, justification, body).expect("verification failed!"))
}
}
pub struct PeerData {
link: BabeLink,
inherent_data_providers: InherentDataProviders,
block_import: Mutex