Sync block justifications (#1410)

* core: sync protocol for justifications

* core: basic test for justification sync

* core: pass block number with justification

* grandpa: request justifications when importing change blocks

* core: pass finality notifications to chain sync

* core: require justifications for pending change blocks on start

* core: avoid requesting justifications from previous failed peers

* core: timeout block justification requests

* core: add some docs

* core: fix unused variables warning

* core: tick pending justifications fetch periodically

* grandpa: add test for syncing justifications

* core: early exit dispatch of pending justifications

* core: style fix

* core: grandpa: change logging level

* core: sync: add missing docs

* core: network: report peer on bad justification

* core: replace mem::replace with Option::take

* core: revert authority set changes on failed block finalization

* core: grandpa: add docs to import_justification

* core: warn on re-finalization of last finalized block

* core: only notify sync with last finality notification

* core: style fix

* core: add docs for PendingJustifications

* core: network: use BlockRequest messages for justification requests

* core: reference issues in todo comments

* core: grandpa: revert authority set changes on db

* core: grandpa: remove inconsistent state warning
This commit is contained in:
André Silva
2019-01-21 06:04:01 +00:00
committed by Gav Wood
parent 3ea681998a
commit 399cee310a
13 changed files with 747 additions and 140 deletions
@@ -16,7 +16,7 @@
//! Block import helpers.
use runtime_primitives::traits::{AuthorityIdFor, Block as BlockT, Header as HeaderT, DigestItemFor};
use runtime_primitives::traits::{AuthorityIdFor, Block as BlockT, DigestItemFor, Header as HeaderT, NumberFor};
use runtime_primitives::Justification;
use std::borrow::Cow;
@@ -33,6 +33,9 @@ pub enum ImportResult {
KnownBad,
/// Block parent is not in the chain.
UnknownParent,
/// Added to the import queue but must be justified
/// (usually required to safely enact consensus changes).
NeedsJustification,
}
/// Block data origin.
@@ -140,9 +143,22 @@ impl<Block: BlockT> ImportBlock<Block> {
/// Block import trait.
pub trait BlockImport<B: BlockT> {
type Error: ::std::error::Error + Send + 'static;
/// Import a Block alongside the new authorities valid form this block forward
fn import_block(&self,
/// Called by the import queue when it is started.
fn on_start(&self, _link: &::import_queue::Link<B>) { }
/// Import a Block alongside the new authorities valid from this block forward
fn import_block(
&self,
block: ImportBlock<B>,
new_authorities: Option<Vec<AuthorityIdFor<B>>>
new_authorities: Option<Vec<AuthorityIdFor<B>>>,
) -> Result<ImportResult, Self::Error>;
/// Import a Block justification and finalize the given block.
fn import_justification(
&self,
hash: B::Hash,
number: NumberFor<B>,
justification: Justification,
) -> Result<(), Self::Error>;
}
@@ -92,6 +92,8 @@ pub trait ImportQueue<B: BlockT>: Send + Sync {
fn is_importing(&self, hash: &B::Hash) -> bool;
/// Import bunch of blocks.
fn import_blocks(&self, origin: BlockOrigin, blocks: Vec<IncomingBlock<B>>);
/// Import a block justification.
fn import_justification(&self, hash: B::Hash, number: NumberFor<B>, justification: Justification) -> bool;
}
/// Import queue status. It isn't completely accurate.
@@ -161,6 +163,7 @@ impl<B: BlockT, V: 'static + Verifier<B>> ImportQueue<B> for BasicQueue<B, V> {
let verifier = self.verifier.clone();
let block_import = self.block_import.clone();
*self.handle.lock() = Some(::std::thread::Builder::new().name("ImportQueue".into()).spawn(move || {
block_import.on_start(&link);
import_thread(block_import, link, qdata, verifier)
})?);
Ok(())
@@ -218,6 +221,10 @@ impl<B: BlockT, V: 'static + Verifier<B>> ImportQueue<B> for BasicQueue<B, V> {
queue.push_back((origin, blocks));
self.data.signal.notify_one();
}
fn import_justification(&self, hash: B::Hash, number: NumberFor<B>, justification: Justification) -> bool {
self.block_import.import_justification(hash, number, justification).is_ok()
}
}
impl<B: BlockT, V: 'static + Verifier<B>> Drop for BasicQueue<B, V> {
@@ -279,6 +286,8 @@ fn import_thread<B: BlockT, L: Link<B>, V: Verifier<B>>(
pub trait Link<B: BlockT>: Send {
/// Block imported.
fn block_imported(&self, _hash: &B::Hash, _number: NumberFor<B>) { }
/// Request a justification for the given block.
fn request_justification(&self, _hash: &B::Hash, _number: NumberFor<B>) { }
/// Maintain sync.
fn maintain_sync(&self) { }
/// Disconnect from peer.
@@ -296,6 +305,8 @@ pub enum BlockImportResult<H: ::std::fmt::Debug + PartialEq, N: ::std::fmt::Debu
ImportedKnown(H, N),
/// Imported unknown block.
ImportedUnknown(H, N),
/// Imported unjustified block that requires one.
ImportedUnjustified(H, N),
}
/// Block import error.
@@ -409,6 +420,10 @@ pub fn import_single_block<B: BlockT, V: Verifier<B>>(
trace!(target: "sync", "Block queued {}: {:?}", number, hash);
Ok(BlockImportResult::ImportedUnknown(hash, number))
},
Ok(ImportResult::NeedsJustification) => {
trace!(target: "sync", "Block queued but requires justification {}: {:?}", number, hash);
Ok(BlockImportResult::ImportedUnjustified(hash, number))
},
Ok(ImportResult::UnknownParent) => {
debug!(target: "sync", "Block with unknown parent {}: {:?}, parent: {:?}", number, hash, parent);
Err(BlockImportError::UnknownParent)
@@ -416,7 +431,7 @@ pub fn import_single_block<B: BlockT, V: Verifier<B>>(
Ok(ImportResult::KnownBad) => {
debug!(target: "sync", "Peer gave us a bad block {}: {:?}", number, hash);
Err(BlockImportError::BadBlock(peer)) //TODO: use persistent ID
}
},
Err(e) => {
debug!(target: "sync", "Error importing block {}: {:?}: {:?}", number, hash, e);
Err(BlockImportError::Error)
@@ -439,6 +454,11 @@ pub fn process_import_result<B: BlockT>(
link.block_imported(&hash, number);
1
},
Ok(BlockImportResult::ImportedUnjustified(hash, number)) => {
link.block_imported(&hash, number);
link.request_justification(&hash, number);
1
},
Err(BlockImportError::IncompleteHeader(who)) => {
if let Some(peer) = who {
link.useless_peer(peer, "Sent block with incomplete header to import");