Minimal switch of substrate-node to GRANDPA /Aura (#1128)

* add beginnings of SRML grandpa library

* get srml-grandpa compiling

* tests for srml-grandpa

* add optional session integration to grandpa SRML

* start integration into node runtime

* Allow extracting pending change from header digest

* Make it compile on wasm

* make tests compile again

* Move Authority Key fetching into service, simplify service factory construction

* Generalize Authority Consensus Setup system

* Add Authority Setup Docs

* Allow CLI params to be extensible

 - move params to structopts
 - split parsing and default command execution
 - add custom config to node
 - extended parsing of custom config
 - extending params via structop's flatten

* Minor fixes on cli extension params:
 - added docs
 - re-add actual app name, rather than node-name
 - make strategy and subcommand optional

* better cli params

* synchronize GRANDPA and normal node authorities

* Implement grandpa::network for gossip consensus

* run_grandpa in Node

* Fix missed merge error

* Integrate grandpa import queue

* more specific type def

* link up linkhalf and import block

* make grandpa future send

* get compiling

* Fix new params convention and license header

* get it running

* rebuild node runtime WASM

* change logging level

* Update node/cli/src/params.rs

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

* Update node/cli/src/params.rs

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

* Update node/cli/src/lib.rs

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

* Update node/runtime/src/lib.rs

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

* Update node/cli/src/lib.rs

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

* Clean up and Fixme for mutable config

* Move GrandpaService Integration into grandpa, feature gated but on per default

* Fixing grandpa runtime module test

* Update wasm runtime hashes for tests

* GRANDPA: use post-header hash when logging scheduled changes

* add an extra bit of logging to authorities

* fixing missing constrain

* remove old code

* move `NewAuthorities` to an event in srml-grandpa

* fix node-executor tests to use grandpa log

* Remove GossipConsensus from tests, use newly provided sync-feature, fixes tests

* Update to latest wasm runtimes

* address grumbles

* address grumbles

* only derive deserialize when using std

* Clean up use of Deserialize
This commit is contained in:
Robert Habermeier
2018-11-21 18:42:50 +01:00
committed by GitHub
parent 84da9d4a02
commit 11fe84a742
59 changed files with 1694 additions and 696 deletions
+98 -18
View File
@@ -55,6 +55,7 @@ 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;
@@ -64,8 +65,8 @@ extern crate substrate_finality_grandpa_primitives as fg_primitives;
#[macro_use]
extern crate log;
#[cfg(test)]
extern crate substrate_network as network;
#[cfg(feature="service-integration")]
extern crate substrate_service as service;
#[cfg(test)]
extern crate substrate_keyring as keyring;
@@ -86,7 +87,7 @@ use client::{Client, error::Error as ClientError, ImportNotifications, backend::
use client::blockchain::HeaderBackend;
use client::runtime_api::TaggedTransactionQueue;
use codec::{Encode, Decode};
use consensus_common::{BlockImport, ImportBlock, ImportResult};
use consensus_common::{BlockImport, ImportBlock, ImportResult, Authorities};
use runtime_primitives::traits::{
NumberFor, Block as BlockT, Header as HeaderT, DigestFor, ProvideRuntimeApi
};
@@ -98,6 +99,8 @@ 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};
@@ -108,6 +111,11 @@ 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;
@@ -173,7 +181,7 @@ impl From<GrandpaError> for Error {
/// handle to a gossip service or similar.
///
/// Intended to be a lightweight handle such as an `Arc`.
pub trait Network: Clone {
pub trait Network : Clone {
/// A stream of input messages for a topic.
type In: Stream<Item=Vec<u8>,Error=()>;
@@ -188,6 +196,52 @@ pub trait Network: Clone {
fn drop_messages(&self, round: u64, set_id: u64);
}
/// Bridge between NetworkService, gossiping consensus messages and Grandpa
pub struct NetworkBridge<B: BlockT, S: network::specialization::NetworkSpecialization<B>, H: ExHashT> {
service: Arc<NetworkService<B, S, H>>
}
impl<B: BlockT, S: network::specialization::NetworkSpecialization<B>, H: ExHashT> NetworkBridge<B, S, H> {
/// Create a new NetworkBridge to the given NetworkService
pub fn new(service: Arc<NetworkService<B, S, H>>) -> Self {
NetworkBridge { service }
}
}
impl<B: BlockT, S: network::specialization::NetworkSpecialization<B>, H: ExHashT> Clone for NetworkBridge<B, S, H> {
fn clone(&self) -> Self {
NetworkBridge {
service: Arc::clone(&self.service)
}
}
}
fn message_topic<B: BlockT>(round: u64, set_id: u64) -> B::Hash {
use runtime_primitives::traits::Hash as HashT;
<<B::Header as HeaderT>::Hashing as HashT>::hash(format!("{}-{}", set_id, round).as_bytes())
}
impl<B: BlockT, S: network::specialization::NetworkSpecialization<B>, H: ExHashT> Network for NetworkBridge<B, S, H> {
type In = mpsc::UnboundedReceiver<ConsensusMessage>;
fn messages_for(&self, round: u64, set_id: u64) -> Self::In {
self.service.consensus_gossip().write().messages_for(message_topic::<B>(round, set_id))
}
fn send_message(&self, round: u64, set_id: u64, message: Vec<u8>) {
let topic = message_topic::<B>(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::<B>(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<Block: BlockT> {
/// Return `Ok(Some(number))` or `Ok(None)` depending on whether the block
@@ -523,7 +577,7 @@ impl<Block: BlockT<Hash=H256>, B, E, N, RA> grandpa::Chain<Block::Hash, NumberFo
// once blocks are finalized that make that transition irrelevant or activate it,
// we will proceed onwards. most of the time there will be no pending transition.
let limit = self.authority_set.current_limit();
trace!(target: "afg", "Finding best chain containing block {:?} with number limit {:?}", block, limit);
debug!(target: "afg", "Finding best chain containing block {:?} with number limit {:?}", block, limit);
match self.inner.best_containing(block, limit) {
Ok(Some(hash)) => {
@@ -583,22 +637,22 @@ impl<B, E, Block: BlockT<Hash=H256>, N, RA> voter::Environment<Block::Hash, Numb
Block: 'static,
B: Backend<Block, Blake2Hasher> + 'static,
E: CallExecutor<Block, Blake2Hasher> + 'static + Send + Sync,
N: Network + 'static,
N::In: 'static,
N: Network + 'static + Send,
N::In: 'static + Send,
RA: 'static + Send + Sync,
NumberFor<Block>: BlockNumberOps,
{
type Timer = Box<Future<Item = (), Error = Self::Error>>;
type Timer = Box<dyn Future<Item = (), Error = Self::Error> + Send>;
type Id = AuthorityId;
type Signature = ed25519::Signature;
type In = Box<Stream<
type In = Box<dyn Stream<
Item = ::grandpa::SignedMessage<Block::Hash, NumberFor<Block>, Self::Signature, Self::Id>,
Error = Self::Error,
>>;
type Out = Box<Sink<
> + Send>;
type Out = Box<dyn Sink<
SinkItem = ::grandpa::Message<Block::Hash, NumberFor<Block>>,
SinkError = Self::Error,
>>;
> + Send>;
type Error = ExitOrError<Block::Hash, NumberFor<Block>>;
#[allow(unreachable_code)]
@@ -689,6 +743,8 @@ impl<B, E, Block: BlockT<Hash=H256>, N, RA> voter::Environment<Block::Hash, Numb
return Ok(());
}
debug!(target: "afg", "Finalizing blocks up to ({:?}, {})", number, hash);
// lock must be held through writing to DB to avoid race
let mut authority_set = self.authority_set.inner().write();
let client = &self.inner;
@@ -768,8 +824,6 @@ impl<B, E, Block: BlockT<Hash=H256>, N, RA> voter::Environment<Block::Hash, Numb
}
}
/// A block-import handler for GRANDPA.
///
/// This scans each imported block for signals of changing authority set.
@@ -806,7 +860,7 @@ impl<B, E, Block: BlockT<Hash=H256>, RA, PRA> BlockImport<Block>
// until the block is written to prevent a race if we need to restore
// the old authority set on error.
let just_in_case = maybe_change.map(|change| {
let hash = block.header.hash();
let hash = block.post_header().hash();
let number = block.header.number().clone();
let mut authorities = self.authority_set.inner().write();
@@ -834,12 +888,38 @@ impl<B, E, Block: BlockT<Hash=H256>, RA, PRA> BlockImport<Block>
}
}
impl<B, E, Block: BlockT<Hash=H256>, RA, PRA> Authorities<Block> for GrandpaBlockImport<B, E, Block, RA, PRA>
where
B: Backend<Block, Blake2Hasher> + 'static,
E: CallExecutor<Block, Blake2Hasher> + 'static + Clone + Send + Sync,
RA: TaggedTransactionQueue<Block>, // necessary for client to import `BlockImport`.
{
type Error = <Client<B, E, Block, RA> as Authorities<Block>>::Error;
fn authorities(&self, at: &BlockId<Block>) -> Result<Vec<AuthorityId>, Self::Error> {
self.inner.authorities_at(at)
}
}
/// Half of a link between a block-import worker and a the background voter.
// This should remain non-clone.
pub struct LinkHalf<B, E, Block: BlockT<Hash=H256>, RA> {
client: Arc<Client<B, E, Block, RA>>,
authority_set: SharedAuthoritySet<Block::Hash, NumberFor<Block>>,
}
impl<B, E, Block: BlockT<Hash=H256>, RA> Clone for LinkHalf<B, E, Block, RA>
where
B: Backend<Block, Blake2Hasher> + 'static,
E: CallExecutor<Block, Blake2Hasher> + 'static + Clone + Send + Sync,
RA: TaggedTransactionQueue<Block>, // necessary for client to import `BlockImport`.
{
fn clone(&self) -> Self {
LinkHalf {
client: self.client.clone(),
authority_set: self.authority_set.clone()
}
}
}
/// Make block importer and link half necessary to tie the background voter
/// to it.
@@ -895,12 +975,12 @@ pub fn run_grandpa<B, E, Block: BlockT<Hash=H256>, N, RA>(
config: Config,
link: LinkHalf<B, E, Block, RA>,
network: N,
) -> ::client::error::Result<impl Future<Item=(),Error=()>> where
) -> ::client::error::Result<impl Future<Item=(),Error=()> + Send + 'static> where
Block::Hash: Ord,
B: Backend<Block, Blake2Hasher> + 'static,
E: CallExecutor<Block, Blake2Hasher> + Send + Sync + 'static,
N: Network + 'static,
N::In: 'static,
N: Network + Send + Sync + 'static,
N::In: Send + 'static,
NumberFor<Block>: BlockNumberOps,
DigestFor<Block>: Encode,
RA: Send + Sync + 'static,