// 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 .
//! Integration of the GRANDPA finality gadget into substrate.
//!
//! This crate provides a long-running future that produces finality notifications.
//!
//! # Usage
//!
//! First, create a block-import wrapper with the `block_import` function.
//! The GRANDPA worker needs to be linked together with this block import object,
//! so a `LinkHalf` is returned as well. All blocks imported (from network or consensus or otherwise)
//! must pass through this wrapper, otherwise consensus is likely to break in
//! unexpected ways.
//!
//! Next, use the `LinkHalf` and a local configuration to `run_grandpa`. This requires a
//! `Network` implementation. The returned future should be driven to completion and
//! will finalize blocks in the background.
//!
//! # Changing authority sets
//!
//! The rough idea behind changing authority sets in GRANDPA is that at some point,
//! we obtain agreement for some maximum block height that the current set can
//! finalize, and once a block with that height is finalized the next set will
//! pick up finalization from there.
//!
//! Technically speaking, this would be implemented as a voting rule which says,
//! "if there is a signal for a change in N blocks in block B, only vote on
//! chains with length NUM(B) + N if they contain B". This conditional-inclusion
//! logic is complex to compute because it requires looking arbitrarily far
//! back in the chain.
//!
//! Instead, we keep track of a list of all signals we've seen so far,
//! sorted ascending by the block number they would be applied at. We never vote
//! on chains with number higher than the earliest handoff block number
//! (this is num(signal) + N). When finalizing a block, we either apply or prune
//! any signaled changes based on whether the signaling block is included in the
//! newly-finalized chain.
extern crate finality_grandpa as grandpa;
extern crate futures;
extern crate substrate_client as client;
extern crate sr_primitives as runtime_primitives;
extern crate substrate_consensus_common as consensus_common;
extern crate substrate_network as network;
extern crate substrate_primitives;
extern crate tokio;
extern crate parking_lot;
extern crate parity_codec as codec;
extern crate substrate_finality_grandpa_primitives as fg_primitives;
#[macro_use]
extern crate log;
#[cfg(feature="service-integration")]
extern crate substrate_service as service;
#[cfg(test)]
extern crate substrate_keyring as keyring;
#[cfg(test)]
extern crate substrate_test_client as test_client;
#[cfg(test)]
extern crate env_logger;
#[macro_use]
extern crate parity_codec_derive;
use futures::prelude::*;
use futures::stream::Fuse;
use futures::sync::mpsc;
use client::{Client, error::Error as ClientError, ImportNotifications, backend::Backend, CallExecutor};
use client::blockchain::HeaderBackend;
use client::runtime_api::TaggedTransactionQueue;
use codec::{Encode, Decode};
use consensus_common::{BlockImport, ImportBlock, ImportResult, Authorities};
use runtime_primitives::traits::{
NumberFor, Block as BlockT, Header as HeaderT, DigestFor, ProvideRuntimeApi
};
use fg_primitives::GrandpaApi;
use runtime_primitives::generic::BlockId;
use substrate_primitives::{ed25519, H256, AuthorityId, Blake2Hasher};
use tokio::timer::Interval;
use grandpa::Error as GrandpaError;
use grandpa::{voter, round::State as RoundState, Equivocation, BlockNumberOps};
use network::{Service as NetworkService, ExHashT};
use network::consensus_gossip::{ConsensusMessage};
use std::collections::{VecDeque, HashMap};
use std::sync::Arc;
use std::time::{Instant, Duration};
use authorities::SharedAuthoritySet;
pub use fg_primitives::ScheduledChange;
mod authorities;
#[cfg(feature="service-integration")]
mod service_integration;
#[cfg(feature="service-integration")]
pub use service_integration::{LinkHalfForService, BlockImportForService};
#[cfg(test)]
mod tests;
const LAST_COMPLETED_KEY: &[u8] = b"grandpa_completed_round";
const AUTHORITY_SET_KEY: &[u8] = b"grandpa_voters";
/// round-number, round-state
type LastCompleted = (u64, RoundState);
/// A GRANDPA message for a substrate chain.
pub type Message = grandpa::Message<::Hash, NumberFor>;
/// A signed message.
pub type SignedMessage = grandpa::SignedMessage<
::Hash,
NumberFor,
ed25519::Signature,
AuthorityId,
>;
/// A prevote message for this chain's block type.
pub type Prevote = grandpa::Prevote<::Hash, NumberFor>;
/// A precommit message for this chain's block type.
pub type Precommit = grandpa::Precommit<::Hash, NumberFor>;
/// Configuration for the GRANDPA service.
#[derive(Clone)]
pub struct Config {
/// The expected duration for a message to be gossiped across the network.
pub gossip_duration: Duration,
/// The local signing key.
pub local_key: Option>,
/// Some local identifier of the voter.
pub name: Option,
}
impl Config {
fn name(&self) -> &str {
self.name.as_ref().map(|s| s.as_str()).unwrap_or("")
}
}
/// Errors that can occur while voting in GRANDPA.
#[derive(Debug)]
pub enum Error {
/// An error within grandpa.
Grandpa(GrandpaError),
/// A network error.
Network(String),
/// A blockchain error.
Blockchain(String),
/// Could not complete a round on disk.
Client(ClientError),
/// A timer failed to fire.
Timer(::tokio::timer::Error),
}
impl From for Error {
fn from(e: GrandpaError) -> Self {
Error::Grandpa(e)
}
}
/// 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`.
pub trait Network : Clone {
/// A stream of input messages for a topic.
type In: Stream,Error=()>;
/// Get a stream of messages for a specific round. This stream should
/// never logically conclude.
fn messages_for(&self, round: u64, set_id: u64) -> Self::In;
/// Send a message at a specific round out.
fn send_message(&self, round: u64, set_id: u64, message: Vec);
/// Clean up messages for a round.
fn drop_messages(&self, round: u64, set_id: u64);
}
/// Bridge between NetworkService, gossiping consensus messages and Grandpa
pub struct NetworkBridge, H: ExHashT> {
service: Arc>
}
impl, H: ExHashT> NetworkBridge {
/// Create a new NetworkBridge to the given NetworkService
pub fn new(service: Arc>) -> Self {
NetworkBridge { service }
}
}
impl, H: ExHashT> Clone for NetworkBridge {
fn clone(&self) -> Self {
NetworkBridge {
service: Arc::clone(&self.service)
}
}
}
fn message_topic(round: u64, set_id: u64) -> B::Hash {
use runtime_primitives::traits::Hash as HashT;
<::Hashing as HashT>::hash(format!("{}-{}", set_id, round).as_bytes())
}
impl, H: ExHashT> Network for NetworkBridge {
type In = mpsc::UnboundedReceiver;
fn messages_for(&self, round: u64, set_id: u64) -> Self::In {
self.service.consensus_gossip().write().messages_for(message_topic::(round, set_id))
}
fn send_message(&self, round: u64, set_id: u64, message: Vec) {
let topic = message_topic::(round, set_id);
let gossip = self.service.consensus_gossip();
self.service.with_spec(move |_s, context|{
gossip.write().multicast(context, topic, message);
});
}
fn drop_messages(&self, round: u64, set_id: u64) {
let topic = message_topic::(round, set_id);
self.service.consensus_gossip().write().collect_garbage(|t| t == &topic);
}
}
/// Something which can determine if a block is known.
pub trait BlockStatus {
/// Return `Ok(Some(number))` or `Ok(None)` depending on whether the block
/// is definitely known and has been imported.
/// If an unexpected error occurs, return that.
fn block_number(&self, hash: Block::Hash) -> Result