Skip to content
Snippets Groups Projects
Commit 5bd806bd authored by Pierre Krieger's avatar Pierre Krieger Committed by Gavin Wood
Browse files

Improvements to the import queue (#3101)

* Remove block_imported

* Move blocks results processing to sync

* Remove methods from Link

* Better errors

* Allow cancelling the import queue

* Restore the import trace

* Fix network tests

* Line widths

* Use has_error instead

* Minor style
parent 7ae6556a
No related merge requests found
......@@ -113,14 +113,15 @@ pub trait ImportQueue<B: BlockT>: Send {
/// Hooks that the verification queue can use to influence the synchronization
/// algorithm.
pub trait Link<B: BlockT>: Send {
/// Block imported.
fn block_imported(&mut self, _hash: &B::Hash, _number: NumberFor<B>) {}
/// Batch of blocks imported, with or without error.
fn blocks_processed(&mut self, _processed_blocks: Vec<B::Hash>, _has_error: bool) {}
fn blocks_processed(
&mut self,
_imported: usize,
_count: usize,
_results: Vec<(Result<BlockImportResult<NumberFor<B>>, BlockImportError>, B::Hash)>
) {}
/// Justification import result.
fn justification_imported(&mut self, _who: Origin, _hash: &B::Hash, _number: NumberFor<B>, _success: bool) {}
/// Clear all pending justification requests.
fn clear_justification_requests(&mut self) {}
/// Request a justification for the given block.
fn request_justification(&mut self, _hash: &B::Hash, _number: NumberFor<B>) {}
/// Finality proof import result.
......@@ -136,10 +137,6 @@ pub trait Link<B: BlockT>: Send {
) {}
/// Request a finality proof for the given block.
fn request_finality_proof(&mut self, _hash: &B::Hash, _number: NumberFor<B>) {}
/// Adjusts the reputation of the given peer.
fn report_peer(&mut self, _who: Origin, _reputation_change: i32) {}
/// Restart sync.
fn restart(&mut self) {}
}
/// Block import successful result.
......@@ -152,7 +149,7 @@ pub enum BlockImportResult<N: ::std::fmt::Debug + PartialEq> {
}
/// Block import error.
#[derive(Debug, PartialEq)]
#[derive(Debug)]
pub enum BlockImportError {
/// Block missed header, can't be imported
IncompleteHeader(Option<Origin>),
......@@ -162,8 +159,10 @@ pub enum BlockImportError {
BadBlock(Option<Origin>),
/// Block has an unknown parent
UnknownParent,
/// Other Error.
Error,
/// Block import has been cancelled. This can happen if the parent block fails to be imported.
Cancelled,
/// Other error.
Other(ConsensusError),
}
/// Single block import function.
......@@ -210,7 +209,7 @@ pub fn import_single_block<B: BlockT, V: Verifier<B>>(
},
Err(e) => {
debug!(target: "sync", "Error importing block {}: {:?}: {:?}", number, hash, e);
Err(BlockImportError::Error)
Err(BlockImportError::Other(e))
}
}
};
......
......@@ -27,15 +27,6 @@ use crate::import_queue::{
buffered_link::{self, BufferedLinkSender, BufferedLinkReceiver}
};
/// Reputation change for peers which send us a block with an incomplete header.
const INCOMPLETE_HEADER_REPUTATION_CHANGE: i32 = -(1 << 20);
/// Reputation change for peers which send us a block which we fail to verify.
const VERIFICATION_FAIL_REPUTATION_CHANGE: i32 = -(1 << 20);
/// Reputation change for peers which send us a bad block.
const BAD_BLOCK_REPUTATION_CHANGE: i32 = -(1 << 29);
/// Reputation change for peers which send us a block with bad justifications.
const BAD_JUSTIFICATION_REPUTATION_CHANGE: i32 = -(1 << 16);
/// Interface to a basic block import queue that is importing blocks sequentially in a separate
/// task, with pluggable verification.
pub struct BasicQueue<B: BlockT> {
......@@ -202,88 +193,16 @@ impl<B: BlockT, V: 'static + Verifier<B>> BlockImportWorker<B, V> {
}
fn import_a_batch_of_blocks(&mut self, origin: BlockOrigin, blocks: Vec<IncomingBlock<B>>) {
let result_sender = &self.result_sender;
let (imported, count, results) = import_many_blocks(
&mut *self.block_import,
origin,
blocks,
self.verifier.clone(),
|| !result_sender.is_closed(),
);
trace!(target: "sync", "Imported {} of {}", imported, count);
let mut has_error = false;
let mut hashes = vec![];
for (result, hash) in results {
hashes.push(hash);
if has_error {
continue;
}
if result.is_err() {
has_error = true;
}
match result {
Ok(BlockImportResult::ImportedKnown(number)) => self.result_sender.block_imported(&hash, number),
Ok(BlockImportResult::ImportedUnknown(number, aux, who)) => {
self.result_sender.block_imported(&hash, number);
if aux.clear_justification_requests {
trace!(
target: "sync",
"Block imported clears all pending justification requests {}: {:?}",
number,
hash
);
self.result_sender.clear_justification_requests();
}
if aux.needs_justification {
trace!(target: "sync", "Block imported but requires justification {}: {:?}", number, hash);
self.result_sender.request_justification(&hash, number);
}
if aux.bad_justification {
if let Some(peer) = who {
info!("Sent block with bad justification to import");
self.result_sender.report_peer(peer, BAD_JUSTIFICATION_REPUTATION_CHANGE);
}
}
if aux.needs_finality_proof {
trace!(target: "sync", "Block imported but requires finality proof {}: {:?}", number, hash);
self.result_sender.request_finality_proof(&hash, number);
}
},
Err(BlockImportError::IncompleteHeader(who)) => {
if let Some(peer) = who {
info!("Peer sent block with incomplete header to import");
self.result_sender.report_peer(peer, INCOMPLETE_HEADER_REPUTATION_CHANGE);
self.result_sender.restart();
}
},
Err(BlockImportError::VerificationFailed(who, e)) => {
if let Some(peer) = who {
info!("Verification failed from peer: {}", e);
self.result_sender.report_peer(peer, VERIFICATION_FAIL_REPUTATION_CHANGE);
self.result_sender.restart();
}
},
Err(BlockImportError::BadBlock(who)) => {
if let Some(peer) = who {
info!("Bad block");
self.result_sender.report_peer(peer, BAD_BLOCK_REPUTATION_CHANGE);
self.result_sender.restart();
}
},
Err(BlockImportError::UnknownParent) | Err(BlockImportError::Error) => {
self.result_sender.restart();
},
};
}
self.result_sender.blocks_processed(hashes, has_error);
self.result_sender.blocks_processed(imported, count, results);
}
fn import_finality_proof(&mut self, who: Origin, hash: B::Hash, number: NumberFor<B>, finality_proof: Vec<u8>) {
......@@ -332,11 +251,15 @@ impl<B: BlockT, V: 'static + Verifier<B>> BlockImportWorker<B, V> {
}
/// Import several blocks at once, returning import result for each block.
///
/// The `keep_going` closure will be called regularly. If it returns false, then the function will
/// end prematurely.
fn import_many_blocks<B: BlockT, V: Verifier<B>>(
import_handle: &mut dyn BlockImport<B, Error = ConsensusError>,
blocks_origin: BlockOrigin,
blocks: Vec<IncomingBlock<B>>,
verifier: Arc<V>,
keep_going: impl Fn() -> bool,
) -> (usize, usize, Vec<(
Result<BlockImportResult<NumberFor<B>>, BlockImportError>,
B::Hash,
......@@ -361,9 +284,15 @@ fn import_many_blocks<B: BlockT, V: Verifier<B>>(
// Blocks in the response/drain should be in ascending order.
for block in blocks {
if !keep_going() {
// Setting `has_error` to true cancels the rest of the import.
has_error = true;
}
let block_number = block.header.as_ref().map(|h| h.number().clone());
let block_hash = block.hash;
let import_result = if has_error {
Err(BlockImportError::Error)
Err(BlockImportError::Cancelled)
} else {
import_single_block(
import_handle,
......@@ -373,12 +302,13 @@ fn import_many_blocks<B: BlockT, V: Verifier<B>>(
)
};
let was_ok = import_result.is_ok();
results.push((import_result, block_hash));
if was_ok {
trace!(target: "sync", "Block imported successfully {:?} ({})", block_number, block_hash);
imported += 1;
} else {
has_error = true;
}
results.push((import_result, block_hash));
}
(imported, count, results)
......
......@@ -27,14 +27,14 @@
//! # struct DummyLink; impl Link<Block> for DummyLink {}
//! # let mut my_link = DummyLink;
//! let (mut tx, mut rx) = buffered_link::<Block>();
//! tx.blocks_processed(vec![], false);
//! rx.poll_actions(&mut my_link); // Calls `my_link.blocks_processed(vec![], false)`
//! tx.blocks_processed(0, 0, vec![]);
//! rx.poll_actions(&mut my_link); // Calls `my_link.blocks_processed(0, 0, vec![])`
//! ```
//!
use futures::{prelude::*, sync::mpsc};
use runtime_primitives::traits::{Block as BlockT, NumberFor};
use crate::import_queue::{Origin, Link};
use crate::import_queue::{Origin, Link, BlockImportResult, BlockImportError};
/// Wraps around an unbounded channel from the `futures` crate. The sender implements `Link` and
/// can be used to buffer commands, and the receiver can be used to poll said commands and transfer
......@@ -51,26 +51,32 @@ pub struct BufferedLinkSender<B: BlockT> {
tx: mpsc::UnboundedSender<BlockImportWorkerMsg<B>>,
}
impl<B: BlockT> BufferedLinkSender<B> {
/// Returns true if the sender points to nowhere.
///
/// Once `true` is returned, it is pointless to use the sender anymore.
pub fn is_closed(&self) -> bool {
self.tx.is_closed()
}
}
/// Internal buffered message.
enum BlockImportWorkerMsg<B: BlockT> {
BlockImported(B::Hash, NumberFor<B>),
BlocksProcessed(Vec<B::Hash>, bool),
BlocksProcessed(usize, usize, Vec<(Result<BlockImportResult<NumberFor<B>>, BlockImportError>, B::Hash)>),
JustificationImported(Origin, B::Hash, NumberFor<B>, bool),
ClearJustificationRequests,
RequestJustification(B::Hash, NumberFor<B>),
FinalityProofImported(Origin, (B::Hash, NumberFor<B>), Result<(B::Hash, NumberFor<B>), ()>),
RequestFinalityProof(B::Hash, NumberFor<B>),
ReportPeer(Origin, i32),
Restart,
}
impl<B: BlockT> Link<B> for BufferedLinkSender<B> {
fn block_imported(&mut self, hash: &B::Hash, number: NumberFor<B>) {
let _ = self.tx.unbounded_send(BlockImportWorkerMsg::BlockImported(hash.clone(), number));
}
fn blocks_processed(&mut self, processed_blocks: Vec<B::Hash>, has_error: bool) {
let _ = self.tx.unbounded_send(BlockImportWorkerMsg::BlocksProcessed(processed_blocks, has_error));
fn blocks_processed(
&mut self,
imported: usize,
count: usize,
results: Vec<(Result<BlockImportResult<NumberFor<B>>, BlockImportError>, B::Hash)>
) {
let _ = self.tx.unbounded_send(BlockImportWorkerMsg::BlocksProcessed(imported, count, results));
}
fn justification_imported(
......@@ -84,10 +90,6 @@ impl<B: BlockT> Link<B> for BufferedLinkSender<B> {
let _ = self.tx.unbounded_send(msg);
}
fn clear_justification_requests(&mut self) {
let _ = self.tx.unbounded_send(BlockImportWorkerMsg::ClearJustificationRequests);
}
fn request_justification(&mut self, hash: &B::Hash, number: NumberFor<B>) {
let _ = self.tx.unbounded_send(BlockImportWorkerMsg::RequestJustification(hash.clone(), number));
}
......@@ -105,14 +107,6 @@ impl<B: BlockT> Link<B> for BufferedLinkSender<B> {
fn request_finality_proof(&mut self, hash: &B::Hash, number: NumberFor<B>) {
let _ = self.tx.unbounded_send(BlockImportWorkerMsg::RequestFinalityProof(hash.clone(), number));
}
fn report_peer(&mut self, who: Origin, reputation_change: i32) {
let _ = self.tx.unbounded_send(BlockImportWorkerMsg::ReportPeer(who, reputation_change));
}
fn restart(&mut self) {
let _ = self.tx.unbounded_send(BlockImportWorkerMsg::Restart);
}
}
/// See [`buffered_link`].
......@@ -136,25 +130,30 @@ impl<B: BlockT> BufferedLinkReceiver<B> {
};
match msg {
BlockImportWorkerMsg::BlockImported(hash, number) =>
link.block_imported(&hash, number),
BlockImportWorkerMsg::BlocksProcessed(blocks, has_error) =>
link.blocks_processed(blocks, has_error),
BlockImportWorkerMsg::BlocksProcessed(imported, count, results) =>
link.blocks_processed(imported, count, results),
BlockImportWorkerMsg::JustificationImported(who, hash, number, success) =>
link.justification_imported(who, &hash, number, success),
BlockImportWorkerMsg::ClearJustificationRequests =>
link.clear_justification_requests(),
BlockImportWorkerMsg::RequestJustification(hash, number) =>
link.request_justification(&hash, number),
BlockImportWorkerMsg::FinalityProofImported(who, block, result) =>
link.finality_proof_imported(who, block, result),
BlockImportWorkerMsg::RequestFinalityProof(hash, number) =>
link.request_finality_proof(&hash, number),
BlockImportWorkerMsg::ReportPeer(who, reput) =>
link.report_peer(who, reput),
BlockImportWorkerMsg::Restart =>
link.restart(),
}
}
}
}
#[cfg(test)]
mod tests {
use test_client::runtime::Block;
#[test]
fn is_closed() {
let (tx, rx) = super::buffered_link::<Block>();
assert!(!tx.is_closed());
drop(rx);
assert!(tx.is_closed());
}
}
......@@ -28,6 +28,7 @@ use runtime_primitives::traits::{
Block as BlockT, Header as HeaderT, NumberFor, One, Zero,
CheckedSub, SaturatedConversion
};
use consensus::import_queue::{BlockImportResult, BlockImportError};
use message::{BlockAttributes, Direction, FromBlock, Message, RequestId};
use message::generic::{Message as GenericMessage, ConsensusMessage};
use event::Event;
......@@ -1194,22 +1195,23 @@ impl<B: BlockT, S: NetworkSpecialization<B>, H: ExHashT> Protocol<B, S, H> {
self.sync.request_justification(&hash, number)
}
/// Clears all pending justification requests.
pub fn clear_justification_requests(&mut self) {
self.sync.clear_justification_requests()
}
/// A batch of blocks have been processed, with or without errors.
/// Call this when a batch of blocks have been processed by the import queue, with or without
/// Call this when a batch of blocks have been processed by the importqueue, with or without
/// errors.
pub fn blocks_processed(&mut self, processed_blocks: Vec<B::Hash>, has_error: bool) {
self.sync.on_blocks_processed(processed_blocks, has_error);
}
/// Restart the sync process.
pub fn restart(&mut self) {
pub fn blocks_processed(
&mut self,
imported: usize,
count: usize,
results: Vec<(Result<BlockImportResult<NumberFor<B>>, BlockImportError>, B::Hash)>
) {
let peers = self.context_data.peers.clone();
for result in self.sync.restart(|peer_id| peers.get(peer_id).map(|i| i.info.clone())) {
let results = self.sync.on_blocks_processed(
imported,
count,
results,
|peer_id| peers.get(peer_id).map(|i| i.info.clone())
);
for result in results {
match result {
Ok((id, req)) => {
let msg = GenericMessage::BlockRequest(req);
......@@ -1223,11 +1225,6 @@ impl<B: BlockT, S: NetworkSpecialization<B>, H: ExHashT> Protocol<B, S, H> {
}
}
/// Notify about successful import of the given block.
pub fn block_imported(&mut self, hash: &B::Hash, number: NumberFor<B>) {
trace!(target: "sync", "Block imported successfully {} ({})", number, hash)
}
/// Call this when a justification has been processed by the import queue, with or without
/// errors.
pub fn justification_import_result(&mut self, hash: B::Hash, number: NumberFor<B>, success: bool) {
......
......@@ -29,7 +29,7 @@
use blocks::BlockCollection;
use client::{BlockStatus, ClientInfo, error::Error as ClientError};
use consensus::{BlockOrigin, import_queue::IncomingBlock};
use consensus::{BlockOrigin, import_queue::{IncomingBlock, BlockImportResult, BlockImportError}};
use crate::{
config::{Roles, BoxFinalityProofRequestBuilder},
message::{self, generic::FinalityProofRequest, BlockAttributes, BlockRequest, BlockResponse, FinalityProofResponse},
......@@ -80,6 +80,18 @@ const ANCESTRY_BLOCK_ERROR_REPUTATION_CHANGE: i32 = -(1 << 9);
/// genesis than us.
const GENESIS_MISMATCH_REPUTATION_CHANGE: i32 = i32::min_value() + 1;
/// Reputation change for peers which send us a block with an incomplete header.
const INCOMPLETE_HEADER_REPUTATION_CHANGE: i32 = -(1 << 20);
/// Reputation change for peers which send us a block which we fail to verify.
const VERIFICATION_FAIL_REPUTATION_CHANGE: i32 = -(1 << 20);
/// Reputation change for peers which send us a bad block.
const BAD_BLOCK_REPUTATION_CHANGE: i32 = -(1 << 29);
/// Reputation change for peers which send us a block with bad justifications.
const BAD_JUSTIFICATION_REPUTATION_CHANGE: i32 = -(1 << 16);
/// The main data structure which contains all the state for a chains
/// active syncing strategy.
pub struct ChainSync<B: Block> {
......@@ -414,11 +426,6 @@ impl<B: Block> ChainSync<B> {
})
}
/// Clears all pending justification requests.
pub fn clear_justification_requests(&mut self) {
self.extra_justifications.reset()
}
/// Schedule a finality proof request for the given block.
pub fn request_finality_proof(&mut self, hash: &B::Hash, number: NumberFor<B>) {
let client = &self.client;
......@@ -690,13 +697,99 @@ impl<B: Block> ChainSync<B> {
///
/// Call this when a batch of blocks have been processed by the import
/// queue, with or without errors.
pub fn on_blocks_processed(&mut self, processed_blocks: Vec<B::Hash>, has_error: bool) {
for hash in processed_blocks {
///
/// `peer_info` is passed in case of a restart.
pub fn on_blocks_processed<'a>(
&'a mut self,
imported: usize,
count: usize,
results: Vec<(Result<BlockImportResult<NumberFor<B>>, BlockImportError>, B::Hash)>,
mut peer_info: impl FnMut(&PeerId) -> Option<protocol::PeerInfo<B>>
) -> impl Iterator<Item = Result<(PeerId, BlockRequest<B>), BadPeer>> + 'a {
trace!(target: "sync", "Imported {} of {}", imported, count);
let mut output = Vec::new();
let mut has_error = false;
let mut hashes = vec![];
for (result, hash) in results {
hashes.push(hash);
if has_error {
continue;
}
if result.is_err() {
has_error = true;
}
match result {
Ok(BlockImportResult::ImportedKnown(_number)) => {}
Ok(BlockImportResult::ImportedUnknown(number, aux, who)) => {
if aux.clear_justification_requests {
trace!(
target: "sync",
"Block imported clears all pending justification requests {}: {:?}",
number,
hash
);
self.extra_justifications.reset()
}
if aux.needs_justification {
trace!(target: "sync", "Block imported but requires justification {}: {:?}", number, hash);
self.request_justification(&hash, number);
}
if aux.bad_justification {
if let Some(peer) = who {
info!("Sent block with bad justification to import");
output.push(Err(BadPeer(peer, BAD_JUSTIFICATION_REPUTATION_CHANGE)));
}
}
if aux.needs_finality_proof {
trace!(target: "sync", "Block imported but requires finality proof {}: {:?}", number, hash);
self.request_finality_proof(&hash, number);
}
},
Err(BlockImportError::IncompleteHeader(who)) => {
if let Some(peer) = who {
info!("Peer sent block with incomplete header to import");
output.push(Err(BadPeer(peer, INCOMPLETE_HEADER_REPUTATION_CHANGE)));
output.extend(self.restart(&mut peer_info));
}
},
Err(BlockImportError::VerificationFailed(who, e)) => {
if let Some(peer) = who {
info!("Verification failed from peer: {}", e);
output.push(Err(BadPeer(peer, VERIFICATION_FAIL_REPUTATION_CHANGE)));
output.extend(self.restart(&mut peer_info));
}
},
Err(BlockImportError::BadBlock(who)) => {
if let Some(peer) = who {
info!("Bad block");
output.push(Err(BadPeer(peer, BAD_BLOCK_REPUTATION_CHANGE)));
output.extend(self.restart(&mut peer_info));
}
},
Err(BlockImportError::UnknownParent) |
Err(BlockImportError::Cancelled) |
Err(BlockImportError::Other(_)) => {
output.extend(self.restart(&mut peer_info));
},
};
}
for hash in hashes {
self.queue_blocks.remove(&hash);
}
if has_error {
self.best_importing_number = Zero::zero()
}
output.into_iter()
}
/// Call this when a justification has been processed by the import queue,
......@@ -894,7 +987,7 @@ impl<B: Block> ChainSync<B> {
}
/// Restart the sync process.
pub fn restart<'a, F>
fn restart<'a, F>
(&'a mut self, mut peer_info: F) -> impl Iterator<Item = Result<(PeerId, BlockRequest<B>), BadPeer>> + 'a
where F: FnMut(&PeerId) -> Option<protocol::PeerInfo<B>> + 'a
{
......
......@@ -29,6 +29,7 @@ use std::{collections::HashMap, fs, marker::PhantomData, io, path::Path};
use std::sync::{Arc, atomic::{AtomicBool, AtomicUsize, Ordering}};
use consensus::import_queue::{ImportQueue, Link};
use consensus::import_queue::{BlockImportResult, BlockImportError};
use futures::{prelude::*, sync::mpsc};
use log::{warn, error, info};
use libp2p::core::{swarm::NetworkBehaviour, transport::boxed::Boxed, muxing::StreamMuxerBox};
......@@ -641,11 +642,13 @@ struct NetworkLink<'a, B: BlockT, S: NetworkSpecialization<B>, H: ExHashT> {
}
impl<'a, B: BlockT, S: NetworkSpecialization<B>, H: ExHashT> Link<B> for NetworkLink<'a, B, S, H> {
fn block_imported(&mut self, hash: &B::Hash, number: NumberFor<B>) {
self.protocol.user_protocol_mut().block_imported(&hash, number)
}
fn blocks_processed(&mut self, hashes: Vec<B::Hash>, has_error: bool) {
self.protocol.user_protocol_mut().blocks_processed(hashes, has_error)
fn blocks_processed(
&mut self,
imported: usize,
count: usize,
results: Vec<(Result<BlockImportResult<NumberFor<B>>, BlockImportError>, B::Hash)>
) {
self.protocol.user_protocol_mut().blocks_processed(imported, count, results)
}
fn justification_imported(&mut self, who: PeerId, hash: &B::Hash, number: NumberFor<B>, success: bool) {
self.protocol.user_protocol_mut().justification_import_result(hash.clone(), number, success);
......@@ -655,9 +658,6 @@ impl<'a, B: BlockT, S: NetworkSpecialization<B>, H: ExHashT> Link<B> for Network
self.protocol.user_protocol_mut().report_peer(who, i32::min_value());
}
}
fn clear_justification_requests(&mut self) {
self.protocol.user_protocol_mut().clear_justification_requests()
}
fn request_justification(&mut self, hash: &B::Hash, number: NumberFor<B>) {
self.protocol.user_protocol_mut().request_justification(hash, number)
}
......@@ -678,10 +678,4 @@ impl<'a, B: BlockT, S: NetworkSpecialization<B>, H: ExHashT> Link<B> for Network
self.protocol.user_protocol_mut().report_peer(who, i32::min_value());
}
}
fn report_peer(&mut self, who: PeerId, reputation_change: i32) {
self.protocol.user_protocol_mut().report_peer(who, reputation_change)
}
fn restart(&mut self) {
self.protocol.user_protocol_mut().restart()
}
}
......@@ -45,29 +45,30 @@ fn prepare_good_block() -> (TestClient, Hash, u64, PeerId, IncomingBlock<Block>)
#[test]
fn import_single_good_block_works() {
let (_, _hash, number, peer_id, block) = prepare_good_block();
assert_eq!(
import_single_block(&mut test_client::new(), BlockOrigin::File, block, Arc::new(PassThroughVerifier(true))),
Ok(BlockImportResult::ImportedUnknown(number, Default::default(), Some(peer_id)))
);
match import_single_block(&mut test_client::new(), BlockOrigin::File, block, Arc::new(PassThroughVerifier(true))) {
Ok(BlockImportResult::ImportedUnknown(ref num, ref aux, ref org))
if *num == number && *aux == Default::default() && *org == Some(peer_id) => {}
_ => panic!()
}
}
#[test]
fn import_single_good_known_block_is_ignored() {
let (mut client, _hash, number, _, block) = prepare_good_block();
assert_eq!(
import_single_block(&mut client, BlockOrigin::File, block, Arc::new(PassThroughVerifier(true))),
Ok(BlockImportResult::ImportedKnown(number))
);
match import_single_block(&mut client, BlockOrigin::File, block, Arc::new(PassThroughVerifier(true))) {
Ok(BlockImportResult::ImportedKnown(ref n)) if *n == number => {}
_ => panic!()
}
}
#[test]
fn import_single_good_block_without_header_fails() {
let (_, _, _, peer_id, mut block) = prepare_good_block();
block.header = None;
assert_eq!(
import_single_block(&mut test_client::new(), BlockOrigin::File, block, Arc::new(PassThroughVerifier(true))),
Err(BlockImportError::IncompleteHeader(Some(peer_id)))
);
match import_single_block(&mut test_client::new(), BlockOrigin::File, block, Arc::new(PassThroughVerifier(true))) {
Err(BlockImportError::IncompleteHeader(ref org)) if *org == Some(peer_id) => {}
_ => panic!()
}
}
#[test]
......
......@@ -21,8 +21,8 @@ use futures::prelude::*;
use log::{info, warn};
use runtime_primitives::generic::{SignedBlock, BlockId};
use runtime_primitives::traits::{SaturatedConversion, Zero, One, Block, Header};
use consensus_common::import_queue::{ImportQueue, IncomingBlock, Link};
use runtime_primitives::traits::{SaturatedConversion, Zero, One, Block, Header, NumberFor};
use consensus_common::import_queue::{ImportQueue, IncomingBlock, Link, BlockImportError, BlockImportResult};
use network::message;
use consensus_common::BlockOrigin;
......@@ -111,10 +111,15 @@ impl WaitLink {
}
impl<B: Block> Link<B> for WaitLink {
fn blocks_processed(&mut self, processed_blocks: Vec<B::Hash>, has_error: bool) {
self.imported_blocks += processed_blocks.len() as u64;
if has_error {
warn!("There was an error importing {} blocks", processed_blocks.len());
fn blocks_processed(
&mut self,
imported: usize,
count: usize,
results: Vec<(Result<BlockImportResult<NumberFor<B>>, BlockImportError>, B::Hash)>
) {
self.imported_blocks += imported as u64;
if results.iter().any(|(r, _)| r.is_err()) {
warn!("There was an error importing {} blocks", count);
}
}
}
......
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment