// 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 .
use std::{sync::Arc, collections::HashMap};
use log::{debug, trace, info};
use parity_codec::Encode;
use futures::sync::mpsc;
use parking_lot::RwLockWriteGuard;
use client::{blockchain, CallExecutor, Client};
use client::blockchain::HeaderBackend;
use client::backend::Backend;
use client::runtime_api::ApiExt;
use consensus_common::{
BlockImport, Error as ConsensusError,
ImportBlock, ImportResult, JustificationImport, well_known_cache_keys,
SelectChain,
};
use fg_primitives::GrandpaApi;
use runtime_primitives::Justification;
use runtime_primitives::generic::BlockId;
use runtime_primitives::traits::{
Block as BlockT, DigestFor,
Header as HeaderT, NumberFor, ProvideRuntimeApi,
};
use substrate_primitives::{H256, Blake2Hasher};
use crate::{Error, CommandOrError, NewAuthoritySet, VoterCommand};
use crate::authorities::{AuthoritySet, SharedAuthoritySet, DelayKind, PendingChange};
use crate::consensus_changes::SharedConsensusChanges;
use crate::environment::{finalize_block, is_descendent_of};
use crate::justification::GrandpaJustification;
/// A block-import handler for GRANDPA.
///
/// This scans each imported block for signals of changing authority set.
/// If the block being imported enacts an authority set change then:
/// - If the current authority set is still live: we import the block
/// - Otherwise, the block must include a valid justification.
///
/// When using GRANDPA, the block import worker should be using this block import
/// object.
pub struct GrandpaBlockImport, RA, PRA, SC> {
inner: Arc>,
select_chain: SC,
authority_set: SharedAuthoritySet>,
send_voter_commands: mpsc::UnboundedSender>>,
consensus_changes: SharedConsensusChanges>,
api: Arc,
}
impl, RA, PRA, SC> JustificationImport
for GrandpaBlockImport where
NumberFor: grandpa::BlockNumberOps,
B: Backend + 'static,
E: CallExecutor + 'static + Clone + Send + Sync,
DigestFor: Encode,
RA: Send + Sync,
PRA: ProvideRuntimeApi,
PRA::Api: GrandpaApi,
SC: SelectChain,
{
type Error = ConsensusError;
fn on_start(&self, link: &::consensus_common::import_queue::Link) {
let chain_info = match self.inner.info() {
Ok(info) => info.chain,
_ => return,
};
// request justifications for all pending changes for which change blocks have already been imported
let authorities = self.authority_set.inner().read();
for pending_change in authorities.pending_changes() {
if pending_change.delay_kind == DelayKind::Finalized &&
pending_change.effective_number() > chain_info.finalized_number &&
pending_change.effective_number() <= chain_info.best_number
{
let effective_block_hash = self.select_chain.finality_target(
pending_change.canon_hash,
Some(pending_change.effective_number()),
);
if let Ok(Some(hash)) = effective_block_hash {
if let Ok(Some(header)) = self.inner.header(&BlockId::Hash(hash)) {
if *header.number() == pending_change.effective_number() {
link.request_justification(&header.hash(), *header.number());
}
}
}
}
}
}
fn import_justification(
&self,
hash: Block::Hash,
number: NumberFor,
justification: Justification,
) -> Result<(), Self::Error> {
self.import_justification(hash, number, justification, false)
}
}
enum AppliedChanges {
Standard(bool), // true if the change is ready to be applied (i.e. it's a root)
Forced(NewAuthoritySet),
None,
}
impl AppliedChanges {
fn needs_justification(&self) -> bool {
match *self {
AppliedChanges::Standard(_) => true,
AppliedChanges::Forced(_) | AppliedChanges::None => false,
}
}
}
struct PendingSetChanges<'a, Block: 'a + BlockT> {
just_in_case: Option<(
AuthoritySet>,
RwLockWriteGuard<'a, AuthoritySet>>,
)>,
applied_changes: AppliedChanges>,
do_pause: bool,
}
impl<'a, Block: 'a + BlockT> PendingSetChanges<'a, Block> {
// revert the pending set change explicitly.
fn revert(self) { }
fn defuse(mut self) -> (AppliedChanges>, bool) {
self.just_in_case = None;
let applied_changes = ::std::mem::replace(&mut self.applied_changes, AppliedChanges::None);
(applied_changes, self.do_pause)
}
}
impl<'a, Block: 'a + BlockT> Drop for PendingSetChanges<'a, Block> {
fn drop(&mut self) {
if let Some((old_set, mut authorities)) = self.just_in_case.take() {
*authorities = old_set;
}
}
}
impl, RA, PRA, SC>
GrandpaBlockImport
where
NumberFor: grandpa::BlockNumberOps,
B: Backend + 'static,
E: CallExecutor + 'static + Clone + Send + Sync,
DigestFor: Encode,
RA: Send + Sync,
PRA: ProvideRuntimeApi,
PRA::Api: GrandpaApi,
{
// check for a new authority set change.
fn check_new_change(&self, header: &Block::Header, hash: Block::Hash)
-> Result