mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-12 17:01:09 +00:00
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
This commit is contained in:
committed by
Gavin Wood
parent
7ae6556a02
commit
5bd806bd9b
@@ -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]
|
||||
|
||||
Reference in New Issue
Block a user