// Copyright 2018 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 .
//! Tests and test helpers for GRANDPA.
use super::*;
use network::test::{Block, Hash, TestNetFactory, Peer, PeersClient};
use network::import_queue::{PassThroughVerifier};
use network::config::{ProtocolConfig, Roles};
use parking_lot::Mutex;
use tokio::runtime::current_thread;
use keyring::Keyring;
use client::{
BlockchainEvents, runtime_api::{Core, RuntimeVersion, ApiExt, ConstructRuntimeApi, CallApiAt},
error::Result
};
use test_client::{self, runtime::BlockNumber};
use codec::Decode;
use consensus_common::BlockOrigin;
use std::{collections::HashSet, result};
use runtime_primitives::traits::{ApiRef, ProvideRuntimeApi};
use runtime_primitives::generic::BlockId;
use authorities::AuthoritySet;
type PeerData =
Mutex<
Option<
LinkHalf<
test_client::Backend,
test_client::Executor,
Block,
test_client::runtime::ClientWithApi,
>
>
>;
type GrandpaPeer = Peer;
struct GrandpaTestNet {
peers: Vec>,
test_config: TestApi,
started: bool
}
impl GrandpaTestNet {
fn new(test_config: TestApi, n_peers: usize) -> Self {
let mut net = GrandpaTestNet {
peers: Vec::with_capacity(n_peers),
started: false,
test_config,
};
let config = Self::default_config();
for _ in 0..n_peers {
net.add_peer(&config);
}
net
}
}
impl TestNetFactory for GrandpaTestNet {
type Verifier = PassThroughVerifier;
type PeerData = PeerData;
/// Create new test network with peers and given config.
fn from_config(_config: &ProtocolConfig) -> Self {
GrandpaTestNet {
peers: Vec::new(),
test_config: Default::default(),
started: false
}
}
fn default_config() -> ProtocolConfig {
// the authority role ensures gossip hits all nodes here.
ProtocolConfig {
roles: Roles::AUTHORITY,
}
}
fn make_verifier(&self, _client: Arc, _cfg: &ProtocolConfig)
-> Arc
{
Arc::new(PassThroughVerifier(false)) // use non-instant finality.
}
fn make_block_import(&self, client: Arc)
-> (Arc + Send + Sync>, PeerData)
{
let (import, link) = block_import(
client,
Arc::new(self.test_config.clone())
).expect("Could not create block import for fresh peer.");
(Arc::new(import), Mutex::new(Some(link)))
}
fn peer(&self, i: usize) -> &GrandpaPeer {
&self.peers[i]
}
fn peers(&self) -> &Vec> {
&self.peers
}
fn mut_peers>)>(&mut self, closure: F) {
closure(&mut self.peers);
}
fn started(&self) -> bool {
self.started
}
fn set_started(&mut self, new: bool) {
self.started = new;
}
}
#[derive(Clone)]
struct MessageRouting {
inner: Arc>,
peer_id: usize,
}
impl MessageRouting {
fn new(inner: Arc>, peer_id: usize,) -> Self {
MessageRouting {
inner,
peer_id,
}
}
}
fn make_topic(round: u64, set_id: u64) -> Hash {
let mut hash = Hash::default();
round.using_encoded(|s| {
let raw = hash.as_mut();
raw[..8].copy_from_slice(s);
});
set_id.using_encoded(|s| {
let raw = hash.as_mut();
raw[8..16].copy_from_slice(s);
});
hash
}
impl Network for MessageRouting {
type In = Box,Error=()>>;
fn messages_for(&self, round: u64, set_id: u64) -> Self::In {
let messages = self.inner.lock().peer(self.peer_id)
.with_spec(|spec, _| spec.gossip.messages_for(make_topic(round, set_id)));
let messages = messages.map_err(
move |_| panic!("Messages for round {} dropped too early", round)
);
Box::new(messages)
}
fn send_message(&self, round: u64, set_id: u64, message: Vec) {
let mut inner = self.inner.lock();
inner.peer(self.peer_id).gossip_message(make_topic(round, set_id), message);
inner.route_until_complete();
}
fn drop_messages(&self, round: u64, set_id: u64) {
let topic = make_topic(round, set_id);
self.inner.lock().peer(self.peer_id)
.with_spec(|spec, _| spec.gossip.collect_garbage(|t| t == &topic));
}
}
#[derive(Default, Clone)]
struct TestApi {
genesis_authorities: Vec<(AuthorityId, u64)>,
scheduled_changes: Arc>>>,
}
impl TestApi {
fn new(genesis_authorities: Vec<(AuthorityId, u64)>) -> Self {
TestApi {
genesis_authorities,
scheduled_changes: Arc::new(Mutex::new(HashMap::new())),
}
}
}
struct RuntimeApi {
inner: TestApi,
}
impl ProvideRuntimeApi for TestApi {
type Api = RuntimeApi;
fn runtime_api<'a>(&'a self) -> ApiRef<'a, Self::Api> {
RuntimeApi { inner: self.clone() }.into()
}
}
impl Core for RuntimeApi {
fn version(&self, _: &BlockId) -> Result {
unimplemented!("Not required for testing!")
}
fn authorities(&self, _: &BlockId) -> Result> {
unimplemented!("Not required for testing!")
}
fn execute_block(&self, _: &BlockId, _: &Block) -> Result<()> {
unimplemented!("Not required for testing!")
}
fn initialise_block(
&self,
_: &BlockId,
_: &::Header
) -> Result<()> {
unimplemented!("Not required for testing!")
}
}
impl ApiExt for RuntimeApi {
fn map_api_result result::Result, R, E>(
&self,
_: F
) -> result::Result {
unimplemented!("Not required for testing!")
}
}
impl ConstructRuntimeApi for RuntimeApi {
fn construct_runtime_api<'a, T: CallApiAt>(_: &'a T) -> ApiRef<'a, Self> {
unimplemented!("Not required for testing!")
}
}
impl GrandpaApi for RuntimeApi {
fn grandpa_authorities(
&self,
at: &BlockId
) -> Result> {
if at == &BlockId::Number(0) {
Ok(self.inner.genesis_authorities.clone())
} else {
panic!("should generally only request genesis authorities")
}
}
fn grandpa_pending_change(&self, at: &BlockId, _: &DigestFor)
-> Result