Move import queue out of sc-network (#12764)

* Move import queue out of `sc-network`

Add supplementary asynchronous API for the import queue which means
it can be run as an independent task and communicated with through
the `ImportQueueService`.

This commit removes removes block and justification imports from
`sc-network` and provides `ChainSync` with a handle to import queue so
it can import blocks and justifications. Polling of the import queue is
moved complete out of `sc-network` and `sc_consensus::Link` is
implemented for `ChainSyncInterfaceHandled` so the import queue
can still influence the syncing process.

* Fix tests

* Apply review comments

* Apply suggestions from code review

Co-authored-by: Bastian Köcher <git@kchr.de>

* Update client/network/sync/src/lib.rs

Co-authored-by: Bastian Köcher <git@kchr.de>

Co-authored-by: Bastian Köcher <git@kchr.de>
This commit is contained in:
Aaro Altonen
2022-12-09 21:50:57 +02:00
committed by GitHub
parent 225c260e07
commit d6827185c3
24 changed files with 716 additions and 490 deletions
+2
View File
@@ -7328,6 +7328,7 @@ dependencies = [
"futures-timer",
"libp2p",
"log",
"mockall",
"parking_lot 0.12.1",
"sc-client-api",
"sc-utils",
@@ -7929,6 +7930,7 @@ dependencies = [
"sp-runtime",
"sp-test-primitives",
"sp-tracing",
"substrate-prometheus-endpoint",
"substrate-test-runtime-client",
"thiserror",
"tokio",
@@ -18,6 +18,7 @@ futures = { version = "0.3.21", features = ["thread-pool"] }
futures-timer = "3.0.1"
libp2p = { version = "0.49.0", default-features = false }
log = "0.4.17"
mockall = "0.11.2"
parking_lot = "0.12.1"
serde = { version = "1.0", features = ["derive"] }
thiserror = "1.0.30"
@@ -53,6 +53,7 @@ pub type DefaultImportQueue<Block, Client> =
mod basic_queue;
pub mod buffered_link;
pub mod mock;
/// Shared block import struct used by the queue.
pub type BoxBlockImport<B, Transaction> =
@@ -105,10 +106,10 @@ pub trait Verifier<B: BlockT>: Send + Sync {
/// Blocks import queue API.
///
/// The `import_*` methods can be called in order to send elements for the import queue to verify.
/// Afterwards, call `poll_actions` to determine how to respond to these elements.
pub trait ImportQueue<B: BlockT>: Send {
pub trait ImportQueueService<B: BlockT>: Send {
/// Import bunch of blocks.
fn import_blocks(&mut self, origin: BlockOrigin, blocks: Vec<IncomingBlock<B>>);
/// Import block justifications.
fn import_justifications(
&mut self,
@@ -117,12 +118,26 @@ pub trait ImportQueue<B: BlockT>: Send {
number: NumberFor<B>,
justifications: Justifications,
);
/// Polls for actions to perform on the network.
///
}
#[async_trait::async_trait]
pub trait ImportQueue<B: BlockT>: Send {
/// Get a copy of the handle to [`ImportQueueService`].
fn service(&self) -> Box<dyn ImportQueueService<B>>;
/// Get a reference to the handle to [`ImportQueueService`].
fn service_ref(&mut self) -> &mut dyn ImportQueueService<B>;
/// This method should behave in a way similar to `Future::poll`. It can register the current
/// task and notify later when more actions are ready to be polled. To continue the comparison,
/// it is as if this method always returned `Poll::Pending`.
fn poll_actions(&mut self, cx: &mut futures::task::Context, link: &mut dyn Link<B>);
/// Start asynchronous runner for import queue.
///
/// Takes an object implementing [`Link`] which allows the import queue to
/// influece the synchronization process.
async fn run(self, link: Box<dyn Link<B>>);
}
/// Hooks that the verification queue can use to influence the synchronization
@@ -34,7 +34,8 @@ use crate::{
import_queue::{
buffered_link::{self, BufferedLinkReceiver, BufferedLinkSender},
import_single_block_metered, BlockImportError, BlockImportStatus, BoxBlockImport,
BoxJustificationImport, ImportQueue, IncomingBlock, Link, RuntimeOrigin, Verifier,
BoxJustificationImport, ImportQueue, ImportQueueService, IncomingBlock, Link,
RuntimeOrigin, Verifier,
},
metrics::Metrics,
};
@@ -42,10 +43,8 @@ use crate::{
/// Interface to a basic block import queue that is importing blocks sequentially in a separate
/// task, with plugable verification.
pub struct BasicQueue<B: BlockT, Transaction> {
/// Channel to send justification import messages to the background task.
justification_sender: TracingUnboundedSender<worker_messages::ImportJustification<B>>,
/// Channel to send block import messages to the background task.
block_import_sender: TracingUnboundedSender<worker_messages::ImportBlocks<B>>,
/// Handle for sending justification and block import messages to the background task.
handle: BasicQueueHandle<B>,
/// Results coming from the worker task.
result_port: BufferedLinkReceiver<B>,
_phantom: PhantomData<Transaction>,
@@ -54,8 +53,7 @@ pub struct BasicQueue<B: BlockT, Transaction> {
impl<B: BlockT, Transaction> Drop for BasicQueue<B, Transaction> {
fn drop(&mut self) {
// Flush the queue and close the receiver to terminate the future.
self.justification_sender.close_channel();
self.block_import_sender.close_channel();
self.handle.close();
self.result_port.close();
}
}
@@ -95,11 +93,37 @@ impl<B: BlockT, Transaction: Send + 'static> BasicQueue<B, Transaction> {
future.boxed(),
);
Self { justification_sender, block_import_sender, result_port, _phantom: PhantomData }
Self {
handle: BasicQueueHandle::new(justification_sender, block_import_sender),
result_port,
_phantom: PhantomData,
}
}
}
impl<B: BlockT, Transaction: Send> ImportQueue<B> for BasicQueue<B, Transaction> {
#[derive(Clone)]
struct BasicQueueHandle<B: BlockT> {
/// Channel to send justification import messages to the background task.
justification_sender: TracingUnboundedSender<worker_messages::ImportJustification<B>>,
/// Channel to send block import messages to the background task.
block_import_sender: TracingUnboundedSender<worker_messages::ImportBlocks<B>>,
}
impl<B: BlockT> BasicQueueHandle<B> {
pub fn new(
justification_sender: TracingUnboundedSender<worker_messages::ImportJustification<B>>,
block_import_sender: TracingUnboundedSender<worker_messages::ImportBlocks<B>>,
) -> Self {
Self { justification_sender, block_import_sender }
}
pub fn close(&mut self) {
self.justification_sender.close_channel();
self.block_import_sender.close_channel();
}
}
impl<B: BlockT> ImportQueueService<B> for BasicQueueHandle<B> {
fn import_blocks(&mut self, origin: BlockOrigin, blocks: Vec<IncomingBlock<B>>) {
if blocks.is_empty() {
return
@@ -138,12 +162,39 @@ impl<B: BlockT, Transaction: Send> ImportQueue<B> for BasicQueue<B, Transaction>
}
}
}
}
#[async_trait::async_trait]
impl<B: BlockT, Transaction: Send> ImportQueue<B> for BasicQueue<B, Transaction> {
/// Get handle to [`ImportQueueService`].
fn service(&self) -> Box<dyn ImportQueueService<B>> {
Box::new(self.handle.clone())
}
/// Get a reference to the handle to [`ImportQueueService`].
fn service_ref(&mut self) -> &mut dyn ImportQueueService<B> {
&mut self.handle
}
/// Poll actions from network.
fn poll_actions(&mut self, cx: &mut Context, link: &mut dyn Link<B>) {
if self.result_port.poll_actions(cx, link).is_err() {
log::error!(target: "sync", "poll_actions: Background import task is no longer alive");
}
}
/// Start asynchronous runner for import queue.
///
/// Takes an object implementing [`Link`] which allows the import queue to
/// influece the synchronization process.
async fn run(mut self, mut link: Box<dyn Link<B>>) {
loop {
if let Err(_) = self.result_port.next_action(&mut *link).await {
log::error!(target: "sync", "poll_actions: Background import task is no longer alive");
return
}
}
}
}
/// Messages destinated to the background worker.
@@ -80,7 +80,7 @@ impl<B: BlockT> Clone for BufferedLinkSender<B> {
}
/// Internal buffered message.
enum BlockImportWorkerMsg<B: BlockT> {
pub enum BlockImportWorkerMsg<B: BlockT> {
BlocksProcessed(usize, usize, Vec<(BlockImportResult<B>, B::Hash)>),
JustificationImported(RuntimeOrigin, B::Hash, NumberFor<B>, bool),
RequestJustification(B::Hash, NumberFor<B>),
@@ -122,6 +122,18 @@ pub struct BufferedLinkReceiver<B: BlockT> {
}
impl<B: BlockT> BufferedLinkReceiver<B> {
/// Send action for the synchronization to perform.
pub fn send_actions(&mut self, msg: BlockImportWorkerMsg<B>, link: &mut dyn Link<B>) {
match msg {
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::RequestJustification(hash, number) =>
link.request_justification(&hash, number),
}
}
/// Polls for the buffered link actions. Any enqueued action will be propagated to the link
/// passed as parameter.
///
@@ -138,17 +150,19 @@ impl<B: BlockT> BufferedLinkReceiver<B> {
Poll::Pending => break Ok(()),
};
match msg {
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::RequestJustification(hash, number) =>
link.request_justification(&hash, number),
}
self.send_actions(msg, &mut *link);
}
}
/// Poll next element from import queue and send the corresponding action command over the link.
pub async fn next_action(&mut self, link: &mut dyn Link<B>) -> Result<(), ()> {
if let Some(msg) = self.rx.next().await {
self.send_actions(msg, link);
return Ok(())
}
Err(())
}
/// Close the channel.
pub fn close(&mut self) {
self.rx.get_mut().close()
@@ -0,0 +1,46 @@
// This file is part of Substrate.
// Copyright (C) 2022 Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
// This program 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.
// This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
use super::*;
mockall::mock! {
pub ImportQueueHandle<B: BlockT> {}
impl<B: BlockT> ImportQueueService<B> for ImportQueueHandle<B> {
fn import_blocks(&mut self, origin: BlockOrigin, blocks: Vec<IncomingBlock<B>>);
fn import_justifications(
&mut self,
who: RuntimeOrigin,
hash: B::Hash,
number: NumberFor<B>,
justifications: Justifications,
);
}
}
mockall::mock! {
pub ImportQueue<B: BlockT> {}
#[async_trait::async_trait]
impl<B: BlockT> ImportQueue<B> for ImportQueue<B> {
fn service(&self) -> Box<dyn ImportQueueService<B>>;
fn service_ref(&mut self) -> &mut dyn ImportQueueService<B>;
fn poll_actions<'a>(&mut self, cx: &mut futures::task::Context<'a>, link: &mut dyn Link<B>);
async fn run(self, link: Box<dyn Link<B>>);
}
}
+12 -16
View File
@@ -24,9 +24,7 @@ pub mod warp;
use libp2p::PeerId;
use message::{BlockAnnounce, BlockData, BlockRequest, BlockResponse};
use sc_consensus::{
import_queue::RuntimeOrigin, BlockImportError, BlockImportStatus, IncomingBlock,
};
use sc_consensus::{import_queue::RuntimeOrigin, IncomingBlock};
use sp_consensus::BlockOrigin;
use sp_runtime::{
traits::{Block as BlockT, NumberFor},
@@ -317,6 +315,12 @@ pub trait ChainSync<Block: BlockT>: Send {
response: BlockResponse<Block>,
) -> Result<OnBlockData<Block>, BadPeer>;
/// Procss received block data.
fn process_block_response_data(
&mut self,
blocks_to_import: Result<OnBlockData<Block>, BadPeer>,
);
/// Handle a response from the remote to a justification request that we made.
///
/// `request` must be the original request that triggered `response`.
@@ -326,17 +330,6 @@ pub trait ChainSync<Block: BlockT>: Send {
response: BlockResponse<Block>,
) -> Result<OnBlockJustification<Block>, BadPeer>;
/// 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 errors.
fn on_blocks_processed(
&mut self,
imported: usize,
count: usize,
results: Vec<(Result<BlockImportStatus<NumberFor<Block>>, BlockImportError>, Block::Hash)>,
) -> Box<dyn Iterator<Item = Result<(PeerId, BlockRequest<Block>), BadPeer>>>;
/// Call this when a justification has been processed by the import queue,
/// with or without errors.
fn on_justification_import(
@@ -378,7 +371,7 @@ pub trait ChainSync<Block: BlockT>: Send {
/// Call when a peer has disconnected.
/// Canceled obsolete block request may result in some blocks being ready for
/// import, so this functions checks for such blocks and returns them.
fn peer_disconnected(&mut self, who: &PeerId) -> Option<OnBlockData<Block>>;
fn peer_disconnected(&mut self, who: &PeerId);
/// Return some key metrics.
fn metrics(&self) -> Metrics;
@@ -395,7 +388,10 @@ pub trait ChainSync<Block: BlockT>: Send {
/// Internally calls [`ChainSync::poll_block_announce_validation()`] and
/// this function should be polled until it returns [`Poll::Pending`] to
/// consume all pending events.
fn poll(&mut self, cx: &mut std::task::Context) -> Poll<PollResult<Block>>;
fn poll(
&mut self,
cx: &mut std::task::Context,
) -> Poll<PollBlockAnnounceValidation<Block::Header>>;
/// Send block request to peer
fn send_block_request(&mut self, who: PeerId, request: BlockRequest<Block>);
+8 -23
View File
@@ -32,7 +32,6 @@ use libp2p::{
NetworkBehaviour,
};
use sc_consensus::import_queue::{IncomingBlock, RuntimeOrigin};
use sc_network_common::{
protocol::{
event::DhtEvent,
@@ -43,18 +42,14 @@ use sc_network_common::{
};
use sc_peerset::{PeersetHandle, ReputationChange};
use sp_blockchain::HeaderBackend;
use sp_consensus::BlockOrigin;
use sp_runtime::{
traits::{Block as BlockT, NumberFor},
Justifications,
};
use sp_runtime::traits::Block as BlockT;
use std::{collections::HashSet, time::Duration};
pub use crate::request_responses::{InboundFailure, OutboundFailure, RequestId, ResponseFailure};
/// General behaviour of the network. Combines all protocols together.
#[derive(NetworkBehaviour)]
#[behaviour(out_event = "BehaviourOut<B>")]
#[behaviour(out_event = "BehaviourOut")]
pub struct Behaviour<B, Client>
where
B: BlockT,
@@ -72,10 +67,7 @@ where
}
/// Event generated by `Behaviour`.
pub enum BehaviourOut<B: BlockT> {
BlockImport(BlockOrigin, Vec<IncomingBlock<B>>),
JustificationImport(RuntimeOrigin, B::Hash, NumberFor<B>, Justifications),
pub enum BehaviourOut {
/// Started a random iterative Kademlia discovery query.
RandomKademliaStarted,
@@ -107,10 +99,7 @@ pub enum BehaviourOut<B: BlockT> {
},
/// A request protocol handler issued reputation changes for the given peer.
ReputationChanges {
peer: PeerId,
changes: Vec<ReputationChange>,
},
ReputationChanges { peer: PeerId, changes: Vec<ReputationChange> },
/// Opened a substream with the given node with the given notifications protocol.
///
@@ -306,13 +295,9 @@ fn reported_roles_to_observed_role(roles: Roles) -> ObservedRole {
}
}
impl<B: BlockT> From<CustomMessageOutcome<B>> for BehaviourOut<B> {
impl<B: BlockT> From<CustomMessageOutcome<B>> for BehaviourOut {
fn from(event: CustomMessageOutcome<B>) -> Self {
match event {
CustomMessageOutcome::BlockImport(origin, blocks) =>
BehaviourOut::BlockImport(origin, blocks),
CustomMessageOutcome::JustificationImport(origin, hash, nb, justification) =>
BehaviourOut::JustificationImport(origin, hash, nb, justification),
CustomMessageOutcome::NotificationStreamOpened {
remote,
protocol,
@@ -344,7 +329,7 @@ impl<B: BlockT> From<CustomMessageOutcome<B>> for BehaviourOut<B> {
}
}
impl<B: BlockT> From<request_responses::Event> for BehaviourOut<B> {
impl From<request_responses::Event> for BehaviourOut {
fn from(event: request_responses::Event) -> Self {
match event {
request_responses::Event::InboundRequest { peer, protocol, result } =>
@@ -357,14 +342,14 @@ impl<B: BlockT> From<request_responses::Event> for BehaviourOut<B> {
}
}
impl<B: BlockT> From<peer_info::PeerInfoEvent> for BehaviourOut<B> {
impl From<peer_info::PeerInfoEvent> for BehaviourOut {
fn from(event: peer_info::PeerInfoEvent) -> Self {
let peer_info::PeerInfoEvent::Identified { peer_id, info } = event;
BehaviourOut::PeerIdentify { peer_id, info }
}
}
impl<B: BlockT> From<DiscoveryOut> for BehaviourOut<B> {
impl From<DiscoveryOut> for BehaviourOut {
fn from(event: DiscoveryOut) -> Self {
match event {
DiscoveryOut::UnroutablePeer(_peer_id) => {
-7
View File
@@ -40,7 +40,6 @@ use libp2p::{
multiaddr, Multiaddr,
};
use prometheus_endpoint::Registry;
use sc_consensus::ImportQueue;
use sc_network_common::{
config::{MultiaddrWithPeerId, NonDefaultSetConfig, SetConfig, TransportConfig},
sync::ChainSync,
@@ -82,12 +81,6 @@ where
/// name on the wire.
pub fork_id: Option<String>,
/// Import queue to use.
///
/// The import queue is the component that verifies that blocks received from other nodes are
/// valid.
pub import_queue: Box<dyn ImportQueue<B>>,
/// Instance of chain sync implementation.
pub chain_sync: Box<dyn ChainSync<B>>,
+7 -2
View File
@@ -258,6 +258,7 @@ pub mod network_state;
#[doc(inline)]
pub use libp2p::{multiaddr, Multiaddr, PeerId};
pub use protocol::PeerInfo;
use sc_consensus::{JustificationSyncLink, Link};
pub use sc_network_common::{
protocol::{
event::{DhtEvent, Event},
@@ -297,11 +298,15 @@ const MAX_CONNECTIONS_ESTABLISHED_INCOMING: u32 = 10_000;
/// Abstraction over syncing-related services
pub trait ChainSyncInterface<B: BlockT>:
NetworkSyncForkRequest<B::Hash, NumberFor<B>> + Send + Sync
NetworkSyncForkRequest<B::Hash, NumberFor<B>> + JustificationSyncLink<B> + Link<B> + Send + Sync
{
}
impl<T, B: BlockT> ChainSyncInterface<B> for T where
T: NetworkSyncForkRequest<B::Hash, NumberFor<B>> + Send + Sync
T: NetworkSyncForkRequest<B::Hash, NumberFor<B>>
+ JustificationSyncLink<B>
+ Link<B>
+ Send
+ Sync
{
}
+8 -99
View File
@@ -29,32 +29,26 @@ use libp2p::{
},
Multiaddr, PeerId,
};
use log::{debug, error, info, log, trace, warn, Level};
use log::{debug, error, log, trace, warn, Level};
use lru::LruCache;
use message::{generic::Message as GenericMessage, Message};
use notifications::{Notifications, NotificationsOut};
use prometheus_endpoint::{register, Gauge, GaugeVec, Opts, PrometheusError, Registry, U64};
use sc_client_api::HeaderBackend;
use sc_consensus::import_queue::{
BlockImportError, BlockImportStatus, IncomingBlock, RuntimeOrigin,
};
use sc_network_common::{
config::NonReservedPeerMode,
error,
protocol::{role::Roles, ProtocolName},
sync::{
message::{BlockAnnounce, BlockAnnouncesHandshake, BlockData, BlockResponse, BlockState},
BadPeer, ChainSync, ImportResult, OnBlockData, PollBlockAnnounceValidation, PollResult,
SyncStatus,
BadPeer, ChainSync, PollBlockAnnounceValidation, SyncStatus,
},
utils::{interval, LruHashSet},
};
use sp_arithmetic::traits::SaturatedConversion;
use sp_consensus::BlockOrigin;
use sp_runtime::{
generic::BlockId,
traits::{Block as BlockT, CheckedSub, Header as HeaderT, NumberFor, Zero},
Justifications,
};
use std::{
collections::{HashMap, HashSet, VecDeque},
@@ -481,12 +475,7 @@ where
}
if let Some(_peer_data) = self.peers.remove(&peer) {
if let Some(OnBlockData::Import(origin, blocks)) =
self.chain_sync.peer_disconnected(&peer)
{
self.pending_messages
.push_back(CustomMessageOutcome::BlockImport(origin, blocks));
}
self.chain_sync.peer_disconnected(&peer);
self.default_peers_set_no_slot_connected_peers.remove(&peer);
Ok(())
} else {
@@ -785,25 +774,13 @@ where
}],
},
);
self.chain_sync.process_block_response_data(blocks_to_import);
if is_best {
self.pending_messages.push_back(CustomMessageOutcome::PeerNewBest(who, number));
}
match blocks_to_import {
Ok(OnBlockData::Import(origin, blocks)) =>
CustomMessageOutcome::BlockImport(origin, blocks),
Ok(OnBlockData::Request(peer, req)) => {
self.chain_sync.send_block_request(peer, req);
CustomMessageOutcome::None
},
Ok(OnBlockData::Continue) => CustomMessageOutcome::None,
Err(BadPeer(id, repu)) => {
self.behaviour.disconnect_peer(&id, HARDCODED_PEERSETS_SYNC);
self.peerset_handle.report_peer(id, repu);
CustomMessageOutcome::None
},
}
CustomMessageOutcome::None
}
/// Call this when a block has been finalized. The sync layer may have some additional
@@ -812,58 +789,6 @@ where
self.chain_sync.on_block_finalized(&hash, *header.number())
}
/// Request a justification for the given block.
///
/// Uses `protocol` to queue a new justification request and tries to dispatch all pending
/// requests.
pub fn request_justification(&mut self, hash: &B::Hash, number: NumberFor<B>) {
self.chain_sync.request_justification(hash, number)
}
/// Clear all pending justification requests.
pub fn clear_justification_requests(&mut self) {
self.chain_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 importqueue, with or without
/// errors.
pub fn on_blocks_processed(
&mut self,
imported: usize,
count: usize,
results: Vec<(Result<BlockImportStatus<NumberFor<B>>, BlockImportError>, B::Hash)>,
) {
let results = self.chain_sync.on_blocks_processed(imported, count, results);
for result in results {
match result {
Ok((id, req)) => self.chain_sync.send_block_request(id, req),
Err(BadPeer(id, repu)) => {
self.behaviour.disconnect_peer(&id, HARDCODED_PEERSETS_SYNC);
self.peerset_handle.report_peer(id, repu)
},
}
}
}
/// Call this when a justification has been processed by the import queue, with or without
/// errors.
pub fn justification_import_result(
&mut self,
who: PeerId,
hash: B::Hash,
number: NumberFor<B>,
success: bool,
) {
self.chain_sync.on_justification_import(hash, number, success);
if !success {
info!("💔 Invalid justification provided by {} for #{}", who, hash);
self.behaviour.disconnect_peer(&who, HARDCODED_PEERSETS_SYNC);
self.peerset_handle
.report_peer(who, sc_peerset::ReputationChange::new_fatal("Invalid justification"));
}
}
/// Set whether the syncing peers set is in reserved-only mode.
pub fn set_reserved_only(&self, reserved_only: bool) {
self.peerset_handle.set_reserved_only(HARDCODED_PEERSETS_SYNC, reserved_only);
@@ -997,8 +922,6 @@ where
#[derive(Debug)]
#[must_use]
pub enum CustomMessageOutcome<B: BlockT> {
BlockImport(BlockOrigin, Vec<IncomingBlock<B>>),
JustificationImport(RuntimeOrigin, B::Hash, NumberFor<B>, Justifications),
/// Notification protocols have been opened with a remote.
NotificationStreamOpened {
remote: PeerId,
@@ -1106,23 +1029,9 @@ where
// Process any received requests received from `NetworkService` and
// check if there is any block announcement validation finished.
while let Poll::Ready(result) = self.chain_sync.poll(cx) {
match result {
PollResult::Import(import) => self.pending_messages.push_back(match import {
ImportResult::BlockImport(origin, blocks) =>
CustomMessageOutcome::BlockImport(origin, blocks),
ImportResult::JustificationImport(origin, hash, number, justifications) =>
CustomMessageOutcome::JustificationImport(
origin,
hash,
number,
justifications,
),
}),
PollResult::Announce(announce) =>
match self.process_block_announce_validation_result(announce) {
CustomMessageOutcome::None => {},
outcome => self.pending_messages.push_back(outcome),
},
match self.process_block_announce_validation_result(result) {
CustomMessageOutcome::None => {},
outcome => self.pending_messages.push_back(outcome),
}
}
+2 -86
View File
@@ -54,7 +54,6 @@ use libp2p::{
use log::{debug, error, info, trace, warn};
use metrics::{Histogram, HistogramVec, MetricSources, Metrics};
use parking_lot::Mutex;
use sc_consensus::{BlockImportError, BlockImportStatus, ImportQueue, Link};
use sc_network_common::{
config::{MultiaddrWithPeerId, TransportConfig},
error::Error,
@@ -450,7 +449,6 @@ where
is_major_syncing,
network_service: swarm,
service,
import_queue: params.import_queue,
from_service,
event_streams: out_events::OutChannels::new(params.metrics_registry.as_ref())?,
peers_notifications_sinks,
@@ -748,13 +746,11 @@ impl<B: BlockT, H: ExHashT> sc_consensus::JustificationSyncLink<B> for NetworkSe
/// On success, the justification will be passed to the import queue that was part at
/// initialization as part of the configuration.
fn request_justification(&self, hash: &B::Hash, number: NumberFor<B>) {
let _ = self
.to_worker
.unbounded_send(ServiceToWorkerMsg::RequestJustification(*hash, number));
let _ = self.chain_sync_service.request_justification(hash, number);
}
fn clear_justification_requests(&self) {
let _ = self.to_worker.unbounded_send(ServiceToWorkerMsg::ClearJustificationRequests);
let _ = self.chain_sync_service.clear_justification_requests();
}
}
@@ -1208,8 +1204,6 @@ impl<'a> NotificationSenderReadyT for NotificationSenderReady<'a> {
///
/// Each entry corresponds to a method of `NetworkService`.
enum ServiceToWorkerMsg<B: BlockT> {
RequestJustification(B::Hash, NumberFor<B>),
ClearJustificationRequests,
AnnounceBlock(B::Hash, Option<Vec<u8>>),
GetValue(KademliaKey),
PutValue(KademliaKey, Vec<u8>),
@@ -1261,8 +1255,6 @@ where
service: Arc<NetworkService<B, H>>,
/// The *actual* network.
network_service: Swarm<Behaviour<B, Client>>,
/// The import queue that was passed at initialization.
import_queue: Box<dyn ImportQueue<B>>,
/// Messages from the [`NetworkService`] that must be processed.
from_service: TracingUnboundedReceiver<ServiceToWorkerMsg<B>>,
/// Senders for events that happen on the network.
@@ -1290,10 +1282,6 @@ where
fn poll(mut self: Pin<&mut Self>, cx: &mut std::task::Context) -> Poll<Self::Output> {
let this = &mut *self;
// Poll the import queue for actions to perform.
this.import_queue
.poll_actions(cx, &mut NetworkLink { protocol: &mut this.network_service });
// At the time of writing of this comment, due to a high volume of messages, the network
// worker sometimes takes a long time to process the loop below. When that happens, the
// rest of the polling is frozen. In order to avoid negative side-effects caused by this
@@ -1322,16 +1310,6 @@ where
.behaviour_mut()
.user_protocol_mut()
.announce_block(hash, data),
ServiceToWorkerMsg::RequestJustification(hash, number) => this
.network_service
.behaviour_mut()
.user_protocol_mut()
.request_justification(&hash, number),
ServiceToWorkerMsg::ClearJustificationRequests => this
.network_service
.behaviour_mut()
.user_protocol_mut()
.clear_justification_requests(),
ServiceToWorkerMsg::GetValue(key) =>
this.network_service.behaviour_mut().get_value(key),
ServiceToWorkerMsg::PutValue(key, value) =>
@@ -1435,23 +1413,6 @@ where
match poll_value {
Poll::Pending => break,
Poll::Ready(SwarmEvent::Behaviour(BehaviourOut::BlockImport(origin, blocks))) => {
if let Some(metrics) = this.metrics.as_ref() {
metrics.import_queue_blocks_submitted.inc();
}
this.import_queue.import_blocks(origin, blocks);
},
Poll::Ready(SwarmEvent::Behaviour(BehaviourOut::JustificationImport(
origin,
hash,
nb,
justifications,
))) => {
if let Some(metrics) = this.metrics.as_ref() {
metrics.import_queue_justifications_submitted.inc();
}
this.import_queue.import_justifications(origin, hash, nb, justifications);
},
Poll::Ready(SwarmEvent::Behaviour(BehaviourOut::InboundRequest {
protocol,
result,
@@ -1952,51 +1913,6 @@ where
{
}
// Implementation of `import_queue::Link` trait using the available local variables.
struct NetworkLink<'a, B, Client>
where
B: BlockT,
Client: HeaderBackend<B> + 'static,
{
protocol: &'a mut Swarm<Behaviour<B, Client>>,
}
impl<'a, B, Client> Link<B> for NetworkLink<'a, B, Client>
where
B: BlockT,
Client: HeaderBackend<B> + 'static,
{
fn blocks_processed(
&mut self,
imported: usize,
count: usize,
results: Vec<(Result<BlockImportStatus<NumberFor<B>>, BlockImportError>, B::Hash)>,
) {
self.protocol
.behaviour_mut()
.user_protocol_mut()
.on_blocks_processed(imported, count, results)
}
fn justification_imported(
&mut self,
who: PeerId,
hash: &B::Hash,
number: NumberFor<B>,
success: bool,
) {
self.protocol
.behaviour_mut()
.user_protocol_mut()
.justification_import_result(who, *hash, number, success);
}
fn request_justification(&mut self, hash: &B::Hash, number: NumberFor<B>) {
self.protocol
.behaviour_mut()
.user_protocol_mut()
.request_justification(hash, number)
}
}
fn ensure_addresses_consistent_with_transport<'a>(
addresses: impl Iterator<Item = &'a Multiaddr>,
transport: &TransportConfig,
@@ -53,8 +53,6 @@ pub struct Metrics {
pub connections_opened_total: CounterVec<U64>,
pub distinct_peers_connections_closed_total: Counter<U64>,
pub distinct_peers_connections_opened_total: Counter<U64>,
pub import_queue_blocks_submitted: Counter<U64>,
pub import_queue_justifications_submitted: Counter<U64>,
pub incoming_connections_errors_total: CounterVec<U64>,
pub incoming_connections_total: Counter<U64>,
pub issued_light_requests: Counter<U64>,
@@ -103,14 +101,6 @@ impl Metrics {
"substrate_sub_libp2p_distinct_peers_connections_opened_total",
"Total number of connections opened with distinct peers"
)?, registry)?,
import_queue_blocks_submitted: prometheus::register(Counter::new(
"substrate_import_queue_blocks_submitted",
"Number of blocks submitted to the import queue.",
)?, registry)?,
import_queue_justifications_submitted: prometheus::register(Counter::new(
"substrate_import_queue_justifications_submitted",
"Number of justifications submitted to the import queue.",
)?, registry)?,
incoming_connections_errors_total: prometheus::register(CounterVec::new(
Opts::new(
"substrate_sub_libp2p_incoming_connections_handshake_errors_total",
@@ -86,27 +86,26 @@ async fn normal_network_poll_no_peers() {
#[tokio::test]
async fn request_justification() {
// build `ChainSyncInterface` provider and set no expecations for it (i.e., it cannot be
// called)
let chain_sync_service =
Box::new(MockChainSyncInterface::<substrate_test_runtime_client::runtime::Block>::new());
// build `ChainSync` and verify that call to `request_justification()` is made
let mut chain_sync =
Box::new(MockChainSync::<substrate_test_runtime_client::runtime::Block>::new());
let hash = H256::random();
let number = 1337u64;
chain_sync
.expect_request_justification()
// build `ChainSyncInterface` provider and and expect
// `JustificationSyncLink::request_justification() to be called once
let mut chain_sync_service =
Box::new(MockChainSyncInterface::<substrate_test_runtime_client::runtime::Block>::new());
chain_sync_service
.expect_justification_sync_link_request_justification()
.withf(move |in_hash, in_number| &hash == in_hash && &number == in_number)
.once()
.returning(|_, _| ());
// build `ChainSync` and set default expecations for it
let mut chain_sync = MockChainSync::<substrate_test_runtime_client::runtime::Block>::new();
set_default_expecations_no_peers(&mut chain_sync);
let mut network = TestNetworkBuilder::new(Handle::current())
.with_chain_sync((chain_sync, chain_sync_service))
.with_chain_sync((Box::new(chain_sync), chain_sync_service))
.build();
// send "request justifiction" message and poll the network
@@ -121,17 +120,20 @@ async fn request_justification() {
#[tokio::test]
async fn clear_justification_requests() {
// build `ChainSyncInterface` provider and set no expecations for it (i.e., it cannot be
// called)
let chain_sync_service =
// build `ChainSyncInterface` provider and expect
// `JustificationSyncLink::clear_justification_requests()` to be called
let mut chain_sync_service =
Box::new(MockChainSyncInterface::<substrate_test_runtime_client::runtime::Block>::new());
// build `ChainSync` and verify that call to `clear_justification_requests()` is made
chain_sync_service
.expect_justification_sync_link_clear_justification_requests()
.once()
.returning(|| ());
// build `ChainSync` and set default expecations for it
let mut chain_sync =
Box::new(MockChainSync::<substrate_test_runtime_client::runtime::Block>::new());
chain_sync.expect_clear_justification_requests().once().returning(|| ());
set_default_expecations_no_peers(&mut chain_sync);
let mut network = TestNetworkBuilder::new(Handle::current())
.with_chain_sync((chain_sync, chain_sync_service))
@@ -235,19 +237,13 @@ async fn on_block_finalized() {
// and verify that connection to the peer is closed
#[tokio::test]
async fn invalid_justification_imported() {
struct DummyImportQueue(
Arc<
RwLock<
Option<(
PeerId,
substrate_test_runtime_client::runtime::Hash,
sp_runtime::traits::NumberFor<substrate_test_runtime_client::runtime::Block>,
)>,
>,
>,
);
struct DummyImportQueueHandle;
impl sc_consensus::ImportQueue<substrate_test_runtime_client::runtime::Block> for DummyImportQueue {
impl
sc_consensus::import_queue::ImportQueueService<
substrate_test_runtime_client::runtime::Block,
> for DummyImportQueueHandle
{
fn import_blocks(
&mut self,
_origin: sp_consensus::BlockOrigin,
@@ -265,7 +261,23 @@ async fn invalid_justification_imported() {
_justifications: sp_runtime::Justifications,
) {
}
}
struct DummyImportQueue(
Arc<
RwLock<
Option<(
PeerId,
substrate_test_runtime_client::runtime::Hash,
sp_runtime::traits::NumberFor<substrate_test_runtime_client::runtime::Block>,
)>,
>,
>,
DummyImportQueueHandle,
);
#[async_trait::async_trait]
impl sc_consensus::ImportQueue<substrate_test_runtime_client::runtime::Block> for DummyImportQueue {
fn poll_actions(
&mut self,
_cx: &mut futures::task::Context,
@@ -275,13 +287,40 @@ async fn invalid_justification_imported() {
link.justification_imported(peer, &hash, number, false);
}
}
fn service(
&self,
) -> Box<
dyn sc_consensus::import_queue::ImportQueueService<
substrate_test_runtime_client::runtime::Block,
>,
> {
Box::new(DummyImportQueueHandle {})
}
fn service_ref(
&mut self,
) -> &mut dyn sc_consensus::import_queue::ImportQueueService<
substrate_test_runtime_client::runtime::Block,
> {
&mut self.1
}
async fn run(
self,
_link: Box<dyn sc_consensus::Link<substrate_test_runtime_client::runtime::Block>>,
) {
}
}
let justification_info = Arc::new(RwLock::new(None));
let listen_addr = config::build_multiaddr![Memory(rand::random::<u64>())];
let (service1, mut event_stream1) = TestNetworkBuilder::new(Handle::current())
.with_import_queue(Box::new(DummyImportQueue(justification_info.clone())))
.with_import_queue(Box::new(DummyImportQueue(
justification_info.clone(),
DummyImportQueueHandle {},
)))
.with_listen_addresses(vec![listen_addr.clone()])
.build()
.start_network();
@@ -331,6 +370,7 @@ async fn disconnect_peer_using_chain_sync_handle() {
let client = Arc::new(TestClientBuilder::with_default_backend().build_with_longest_chain().0);
let listen_addr = config::build_multiaddr![Memory(rand::random::<u64>())];
let import_queue = Box::new(sc_consensus::import_queue::mock::MockImportQueueHandle::new());
let (chain_sync_network_provider, chain_sync_network_handle) =
sc_network_sync::service::network::NetworkServiceProvider::new();
let handle_clone = chain_sync_network_handle.clone();
@@ -344,7 +384,9 @@ async fn disconnect_peer_using_chain_sync_handle() {
Box::new(sp_consensus::block_validation::DefaultBlockAnnounceValidator),
1u32,
None,
None,
chain_sync_network_handle.clone(),
import_queue,
ProtocolName::from("block-request"),
ProtocolName::from("state-request"),
None,
@@ -353,7 +395,7 @@ async fn disconnect_peer_using_chain_sync_handle() {
let (node1, mut event_stream1) = TestNetworkBuilder::new(Handle::current())
.with_listen_addresses(vec![listen_addr.clone()])
.with_chain_sync((Box::new(chain_sync), chain_sync_service))
.with_chain_sync((Box::new(chain_sync), Box::new(chain_sync_service)))
.with_chain_sync_network((chain_sync_network_provider, chain_sync_network_handle))
.with_client(client.clone())
.build()
@@ -21,7 +21,7 @@ use crate::{config, ChainSyncInterface, NetworkService, NetworkWorker};
use futures::prelude::*;
use libp2p::Multiaddr;
use sc_client_api::{BlockBackend, HeaderBackend};
use sc_consensus::ImportQueue;
use sc_consensus::{ImportQueue, Link};
use sc_network_common::{
config::{
NonDefaultSetConfig, NonReservedPeerMode, NotificationHandshake, ProtocolId, SetConfig,
@@ -93,6 +93,7 @@ impl TestNetwork {
struct TestNetworkBuilder {
import_queue: Option<Box<dyn ImportQueue<TestBlock>>>,
link: Option<Box<dyn Link<TestBlock>>>,
client: Option<Arc<substrate_test_runtime_client::TestClient>>,
listen_addresses: Vec<Multiaddr>,
set_config: Option<SetConfig>,
@@ -106,6 +107,7 @@ impl TestNetworkBuilder {
pub fn new(rt_handle: Handle) -> Self {
Self {
import_queue: None,
link: None,
client: None,
listen_addresses: Vec::new(),
set_config: None,
@@ -212,13 +214,14 @@ impl TestNetworkBuilder {
}
}
let import_queue = self.import_queue.unwrap_or(Box::new(sc_consensus::BasicQueue::new(
PassThroughVerifier(false),
Box::new(client.clone()),
None,
&sp_core::testing::TaskExecutor::new(),
None,
)));
let mut import_queue =
self.import_queue.unwrap_or(Box::new(sc_consensus::BasicQueue::new(
PassThroughVerifier(false),
Box::new(client.clone()),
None,
&sp_core::testing::TaskExecutor::new(),
None,
)));
let protocol_id = ProtocolId::from("test-protocol-name");
let fork_id = Some(String::from("test-fork-id"));
@@ -289,15 +292,23 @@ impl TestNetworkBuilder {
Box::new(sp_consensus::block_validation::DefaultBlockAnnounceValidator),
network_config.max_parallel_downloads,
None,
None,
chain_sync_network_handle,
import_queue.service(),
block_request_protocol_config.name.clone(),
state_request_protocol_config.name.clone(),
None,
)
.unwrap();
(Box::new(chain_sync), chain_sync_service)
if let None = self.link {
self.link = Some(Box::new(chain_sync_service.clone()));
}
(Box::new(chain_sync), Box::new(chain_sync_service))
});
let mut link = self
.link
.unwrap_or(Box::new(sc_network_sync::service::mock::MockChainSyncInterface::new()));
let handle = self.rt_handle.clone();
let executor = move |f| {
@@ -316,7 +327,6 @@ impl TestNetworkBuilder {
chain: client.clone(),
protocol_id,
fork_id,
import_queue,
chain_sync,
chain_sync_service,
metrics_registry: None,
@@ -333,6 +343,16 @@ impl TestNetworkBuilder {
self.rt_handle.spawn(async move {
let _ = chain_sync_network_provider.run(service).await;
});
self.rt_handle.spawn(async move {
loop {
futures::future::poll_fn(|cx| {
import_queue.poll_actions(cx, &mut *link);
std::task::Poll::Ready(())
})
.await;
tokio::time::sleep(std::time::Duration::from_millis(250)).await;
}
});
TestNetwork::new(worker, self.rt_handle)
}
+1
View File
@@ -28,6 +28,7 @@ prost = "0.11"
smallvec = "1.8.0"
thiserror = "1.0"
fork-tree = { version = "3.0.0", path = "../../../utils/fork-tree" }
prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.10.0-dev", path = "../../../utils/prometheus" }
sc-client-api = { version = "4.0.0-dev", path = "../../api" }
sc-consensus = { version = "0.10.0-dev", path = "../../consensus/common" }
sc-network-common = { version = "0.10.0-dev", path = "../common" }
+318 -165
View File
@@ -54,9 +54,12 @@ use futures::{
};
use libp2p::{request_response::OutboundFailure, PeerId};
use log::{debug, error, info, trace, warn};
use prometheus_endpoint::{register, Counter, PrometheusError, Registry, U64};
use prost::Message;
use sc_client_api::{BlockBackend, ProofProvider};
use sc_consensus::{BlockImportError, BlockImportStatus, IncomingBlock};
use sc_consensus::{
import_queue::ImportQueueService, BlockImportError, BlockImportStatus, IncomingBlock,
};
use sc_network_common::{
config::{
NonDefaultSetConfig, NonReservedPeerMode, NotificationHandshake, ProtocolId, SetConfig,
@@ -71,8 +74,8 @@ use sc_network_common::{
warp::{EncodedProof, WarpProofRequest, WarpSyncPhase, WarpSyncProgress, WarpSyncProvider},
BadPeer, ChainSync as ChainSyncT, ImportResult, Metrics, OnBlockData, OnBlockJustification,
OnStateData, OpaqueBlockRequest, OpaqueBlockResponse, OpaqueStateRequest,
OpaqueStateResponse, PeerInfo, PeerRequest, PollBlockAnnounceValidation, PollResult,
SyncMode, SyncState, SyncStatus,
OpaqueStateResponse, PeerInfo, PeerRequest, PollBlockAnnounceValidation, SyncMode,
SyncState, SyncStatus,
},
};
use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver};
@@ -233,6 +236,32 @@ impl Default for AllowedRequests {
}
}
struct SyncingMetrics {
pub import_queue_blocks_submitted: Counter<U64>,
pub import_queue_justifications_submitted: Counter<U64>,
}
impl SyncingMetrics {
fn register(registry: &Registry) -> Result<Self, PrometheusError> {
Ok(Self {
import_queue_blocks_submitted: register(
Counter::new(
"substrate_sync_import_queue_blocks_submitted",
"Number of blocks submitted to the import queue.",
)?,
registry,
)?,
import_queue_justifications_submitted: register(
Counter::new(
"substrate_sync_import_queue_justifications_submitted",
"Number of justifications submitted to the import queue.",
)?,
registry,
)?,
})
}
}
struct GapSync<B: BlockT> {
blocks: BlockCollection<B>,
best_queued_number: NumberFor<B>,
@@ -311,6 +340,10 @@ pub struct ChainSync<B: BlockT, Client> {
warp_sync_protocol_name: Option<ProtocolName>,
/// Pending responses
pending_responses: FuturesUnordered<PendingResponse<B>>,
/// Handle to import queue.
import_queue: Box<dyn ImportQueueService<B>>,
/// Metrics.
metrics: Option<SyncingMetrics>,
}
/// All the data we have about a Peer that we are trying to sync with
@@ -961,6 +994,19 @@ where
Ok(self.validate_and_queue_blocks(new_blocks, gap))
}
fn process_block_response_data(&mut self, blocks_to_import: Result<OnBlockData<B>, BadPeer>) {
match blocks_to_import {
Ok(OnBlockData::Import(origin, blocks)) => self.import_blocks(origin, blocks),
Ok(OnBlockData::Request(peer, req)) => self.send_block_request(peer, req),
Ok(OnBlockData::Continue) => {},
Err(BadPeer(id, repu)) => {
self.network_service
.disconnect_peer(id, self.block_announce_protocol_name.clone());
self.network_service.report_peer(id, repu);
},
}
}
fn on_block_justification(
&mut self,
who: PeerId,
@@ -1016,156 +1062,6 @@ where
Ok(OnBlockJustification::Nothing)
}
fn on_blocks_processed(
&mut self,
imported: usize,
count: usize,
results: Vec<(Result<BlockImportStatus<NumberFor<B>>, BlockImportError>, B::Hash)>,
) -> Box<dyn Iterator<Item = Result<(PeerId, BlockRequest<B>), BadPeer>>> {
trace!(target: "sync", "Imported {} of {}", imported, count);
let mut output = Vec::new();
let mut has_error = false;
for (_, hash) in &results {
self.queue_blocks.remove(hash);
self.blocks.clear_queued(hash);
if let Some(gap_sync) = &mut self.gap_sync {
gap_sync.blocks.clear_queued(hash);
}
}
for (result, hash) in results {
if has_error {
break
}
if result.is_err() {
has_error = true;
}
match result {
Ok(BlockImportStatus::ImportedKnown(number, who)) =>
if let Some(peer) = who {
self.update_peer_common_number(&peer, number);
},
Ok(BlockImportStatus::ImportedUnknown(number, aux, who)) => {
if aux.clear_justification_requests {
trace!(
target: "sync",
"Block imported clears all pending justification requests {}: {:?}",
number,
hash,
);
self.clear_justification_requests();
}
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(ref peer) = who {
warn!("💔 Sent block with bad justification to import");
output.push(Err(BadPeer(*peer, rep::BAD_JUSTIFICATION)));
}
}
if let Some(peer) = who {
self.update_peer_common_number(&peer, number);
}
let state_sync_complete =
self.state_sync.as_ref().map_or(false, |s| s.target() == hash);
if state_sync_complete {
info!(
target: "sync",
"State sync is complete ({} MiB), restarting block sync.",
self.state_sync.as_ref().map_or(0, |s| s.progress().size / (1024 * 1024)),
);
self.state_sync = None;
self.mode = SyncMode::Full;
output.extend(self.restart());
}
let warp_sync_complete = self
.warp_sync
.as_ref()
.map_or(false, |s| s.target_block_hash() == Some(hash));
if warp_sync_complete {
info!(
target: "sync",
"Warp sync is complete ({} MiB), restarting block sync.",
self.warp_sync.as_ref().map_or(0, |s| s.progress().total_bytes / (1024 * 1024)),
);
self.warp_sync = None;
self.mode = SyncMode::Full;
output.extend(self.restart());
}
let gap_sync_complete =
self.gap_sync.as_ref().map_or(false, |s| s.target == number);
if gap_sync_complete {
info!(
target: "sync",
"Block history download is complete."
);
self.gap_sync = None;
}
},
Err(BlockImportError::IncompleteHeader(who)) =>
if let Some(peer) = who {
warn!(
target: "sync",
"💔 Peer sent block with incomplete header to import",
);
output.push(Err(BadPeer(peer, rep::INCOMPLETE_HEADER)));
output.extend(self.restart());
},
Err(BlockImportError::VerificationFailed(who, e)) =>
if let Some(peer) = who {
warn!(
target: "sync",
"💔 Verification failed for block {:?} received from peer: {}, {:?}",
hash,
peer,
e,
);
output.push(Err(BadPeer(peer, rep::VERIFICATION_FAIL)));
output.extend(self.restart());
},
Err(BlockImportError::BadBlock(who)) =>
if let Some(peer) = who {
warn!(
target: "sync",
"💔 Block {:?} received from peer {} has been blacklisted",
hash,
peer,
);
output.push(Err(BadPeer(peer, rep::BAD_BLOCK)));
},
Err(BlockImportError::MissingState) => {
// This may happen if the chain we were requesting upon has been discarded
// in the meantime because other chain has been finalized.
// Don't mark it as bad as it still may be synced if explicitly requested.
trace!(target: "sync", "Obsolete block {:?}", hash);
},
e @ Err(BlockImportError::UnknownParent) | e @ Err(BlockImportError::Other(_)) => {
warn!(target: "sync", "💔 Error importing block {:?}: {}", hash, e.unwrap_err());
self.state_sync = None;
self.warp_sync = None;
output.extend(self.restart());
},
Err(BlockImportError::Cancelled) => {},
};
}
self.allowed_requests.set_all();
Box::new(output.into_iter())
}
fn on_justification_import(&mut self, hash: B::Hash, number: NumberFor<B>, success: bool) {
let finalization_result = if success { Ok((hash, number)) } else { Err(()) };
self.extra_justifications
@@ -1331,7 +1227,7 @@ where
}
}
fn peer_disconnected(&mut self, who: &PeerId) -> Option<OnBlockData<B>> {
fn peer_disconnected(&mut self, who: &PeerId) {
self.blocks.clear_peer_download(who);
if let Some(gap_sync) = &mut self.gap_sync {
gap_sync.blocks.clear_peer_download(who)
@@ -1343,8 +1239,13 @@ where
target.peers.remove(who);
!target.peers.is_empty()
});
let blocks = self.ready_blocks();
(!blocks.is_empty()).then(|| self.validate_and_queue_blocks(blocks, false))
if let Some(OnBlockData::Import(origin, blocks)) =
(!blocks.is_empty()).then(|| self.validate_and_queue_blocks(blocks, false))
{
self.import_blocks(origin, blocks);
}
}
fn metrics(&self) -> Metrics {
@@ -1421,22 +1322,56 @@ where
.map_err(|error: codec::Error| error.to_string())
}
fn poll(&mut self, cx: &mut std::task::Context) -> Poll<PollResult<B>> {
fn poll(
&mut self,
cx: &mut std::task::Context,
) -> Poll<PollBlockAnnounceValidation<B::Header>> {
while let Poll::Ready(Some(event)) = self.service_rx.poll_next_unpin(cx) {
match event {
ToServiceCommand::SetSyncForkRequest(peers, hash, number) => {
self.set_sync_fork_request(peers, &hash, number);
},
ToServiceCommand::RequestJustification(hash, number) =>
self.request_justification(&hash, number),
ToServiceCommand::ClearJustificationRequests => self.clear_justification_requests(),
ToServiceCommand::BlocksProcessed(imported, count, results) => {
for result in self.on_blocks_processed(imported, count, results) {
match result {
Ok((id, req)) => self.send_block_request(id, req),
Err(BadPeer(id, repu)) => {
self.network_service
.disconnect_peer(id, self.block_announce_protocol_name.clone());
self.network_service.report_peer(id, repu)
},
}
}
},
ToServiceCommand::JustificationImported(peer, hash, number, success) => {
self.on_justification_import(hash, number, success);
if !success {
info!(target: "sync", "💔 Invalid justification provided by {} for #{}", peer, hash);
self.network_service
.disconnect_peer(peer, self.block_announce_protocol_name.clone());
self.network_service.report_peer(
peer,
sc_peerset::ReputationChange::new_fatal("Invalid justification"),
);
}
},
}
}
self.process_outbound_requests();
if let Poll::Ready(result) = self.poll_pending_responses(cx) {
return Poll::Ready(PollResult::Import(result))
while let Poll::Ready(result) = self.poll_pending_responses(cx) {
match result {
ImportResult::BlockImport(origin, blocks) => self.import_blocks(origin, blocks),
ImportResult::JustificationImport(who, hash, number, justifications) =>
self.import_justifications(who, hash, number, justifications),
}
}
if let Poll::Ready(announce) = self.poll_block_announce_validation(cx) {
return Poll::Ready(PollResult::Announce(announce))
return Poll::Ready(announce)
}
Poll::Pending
@@ -1494,11 +1429,13 @@ where
block_announce_validator: Box<dyn BlockAnnounceValidator<B> + Send>,
max_parallel_downloads: u32,
warp_sync_provider: Option<Arc<dyn WarpSyncProvider<B>>>,
metrics_registry: Option<&Registry>,
network_service: service::network::NetworkServiceHandle,
import_queue: Box<dyn ImportQueueService<B>>,
block_request_protocol_name: ProtocolName,
state_request_protocol_name: ProtocolName,
warp_sync_protocol_name: Option<ProtocolName>,
) -> Result<(Self, Box<ChainSyncInterfaceHandle<B>>, NonDefaultSetConfig), ClientError> {
) -> Result<(Self, ChainSyncInterfaceHandle<B>, NonDefaultSetConfig), ClientError> {
let (tx, service_rx) = tracing_unbounded("mpsc_chain_sync");
let block_announce_config = Self::get_block_announce_proto_config(
protocol_id,
@@ -1544,10 +1481,22 @@ where
.clone()
.into(),
pending_responses: Default::default(),
import_queue,
metrics: if let Some(r) = &metrics_registry {
match SyncingMetrics::register(r) {
Ok(metrics) => Some(metrics),
Err(err) => {
error!(target: "sync", "Failed to register metrics for ChainSync: {err:?}");
None
},
}
} else {
None
},
};
sync.reset_sync_start_point()?;
Ok((sync, Box::new(ChainSyncInterfaceHandle::new(tx)), block_announce_config))
Ok((sync, ChainSyncInterfaceHandle::new(tx), block_announce_config))
}
/// Returns the median seen block number.
@@ -2173,8 +2122,10 @@ where
if request.fields == BlockAttributes::JUSTIFICATION {
match self.on_block_justification(peer_id, block_response) {
Ok(OnBlockJustification::Nothing) => None,
Ok(OnBlockJustification::Import { peer, hash, number, justifications }) =>
Some(ImportResult::JustificationImport(peer, hash, number, justifications)),
Ok(OnBlockJustification::Import { peer, hash, number, justifications }) => {
self.import_justifications(peer, hash, number, justifications);
None
},
Err(BadPeer(id, repu)) => {
self.network_service
.disconnect_peer(id, self.block_announce_protocol_name.clone());
@@ -2184,8 +2135,10 @@ where
}
} else {
match self.on_block_data(&peer_id, Some(request), block_response) {
Ok(OnBlockData::Import(origin, blocks)) =>
Some(ImportResult::BlockImport(origin, blocks)),
Ok(OnBlockData::Import(origin, blocks)) => {
self.import_blocks(origin, blocks);
None
},
Ok(OnBlockData::Request(peer, req)) => {
self.send_block_request(peer, req);
None
@@ -2712,6 +2665,182 @@ where
},
}
}
fn import_blocks(&mut self, origin: BlockOrigin, blocks: Vec<IncomingBlock<B>>) {
if let Some(metrics) = &self.metrics {
metrics.import_queue_blocks_submitted.inc();
}
self.import_queue.import_blocks(origin, blocks);
}
fn import_justifications(
&mut self,
peer: PeerId,
hash: B::Hash,
number: NumberFor<B>,
justifications: Justifications,
) {
if let Some(metrics) = &self.metrics {
metrics.import_queue_justifications_submitted.inc();
}
self.import_queue.import_justifications(peer, hash, number, justifications);
}
/// 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 errors.
fn on_blocks_processed(
&mut self,
imported: usize,
count: usize,
results: Vec<(Result<BlockImportStatus<NumberFor<B>>, BlockImportError>, B::Hash)>,
) -> Box<dyn Iterator<Item = Result<(PeerId, BlockRequest<B>), BadPeer>>> {
trace!(target: "sync", "Imported {} of {}", imported, count);
let mut output = Vec::new();
let mut has_error = false;
for (_, hash) in &results {
self.queue_blocks.remove(hash);
self.blocks.clear_queued(hash);
if let Some(gap_sync) = &mut self.gap_sync {
gap_sync.blocks.clear_queued(hash);
}
}
for (result, hash) in results {
if has_error {
break
}
if result.is_err() {
has_error = true;
}
match result {
Ok(BlockImportStatus::ImportedKnown(number, who)) =>
if let Some(peer) = who {
self.update_peer_common_number(&peer, number);
},
Ok(BlockImportStatus::ImportedUnknown(number, aux, who)) => {
if aux.clear_justification_requests {
trace!(
target: "sync",
"Block imported clears all pending justification requests {}: {:?}",
number,
hash,
);
self.clear_justification_requests();
}
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(ref peer) = who {
warn!("💔 Sent block with bad justification to import");
output.push(Err(BadPeer(*peer, rep::BAD_JUSTIFICATION)));
}
}
if let Some(peer) = who {
self.update_peer_common_number(&peer, number);
}
let state_sync_complete =
self.state_sync.as_ref().map_or(false, |s| s.target() == hash);
if state_sync_complete {
info!(
target: "sync",
"State sync is complete ({} MiB), restarting block sync.",
self.state_sync.as_ref().map_or(0, |s| s.progress().size / (1024 * 1024)),
);
self.state_sync = None;
self.mode = SyncMode::Full;
output.extend(self.restart());
}
let warp_sync_complete = self
.warp_sync
.as_ref()
.map_or(false, |s| s.target_block_hash() == Some(hash));
if warp_sync_complete {
info!(
target: "sync",
"Warp sync is complete ({} MiB), restarting block sync.",
self.warp_sync.as_ref().map_or(0, |s| s.progress().total_bytes / (1024 * 1024)),
);
self.warp_sync = None;
self.mode = SyncMode::Full;
output.extend(self.restart());
}
let gap_sync_complete =
self.gap_sync.as_ref().map_or(false, |s| s.target == number);
if gap_sync_complete {
info!(
target: "sync",
"Block history download is complete."
);
self.gap_sync = None;
}
},
Err(BlockImportError::IncompleteHeader(who)) =>
if let Some(peer) = who {
warn!(
target: "sync",
"💔 Peer sent block with incomplete header to import",
);
output.push(Err(BadPeer(peer, rep::INCOMPLETE_HEADER)));
output.extend(self.restart());
},
Err(BlockImportError::VerificationFailed(who, e)) =>
if let Some(peer) = who {
warn!(
target: "sync",
"💔 Verification failed for block {:?} received from peer: {}, {:?}",
hash,
peer,
e,
);
output.push(Err(BadPeer(peer, rep::VERIFICATION_FAIL)));
output.extend(self.restart());
},
Err(BlockImportError::BadBlock(who)) =>
if let Some(peer) = who {
warn!(
target: "sync",
"💔 Block {:?} received from peer {} has been blacklisted",
hash,
peer,
);
output.push(Err(BadPeer(peer, rep::BAD_BLOCK)));
},
Err(BlockImportError::MissingState) => {
// This may happen if the chain we were requesting upon has been discarded
// in the meantime because other chain has been finalized.
// Don't mark it as bad as it still may be synced if explicitly requested.
trace!(target: "sync", "Obsolete block {:?}", hash);
},
e @ Err(BlockImportError::UnknownParent) | e @ Err(BlockImportError::Other(_)) => {
warn!(target: "sync", "💔 Error importing block {:?}: {}", hash, e.unwrap_err());
self.state_sync = None;
self.warp_sync = None;
output.extend(self.restart());
},
Err(BlockImportError::Cancelled) => {},
};
}
self.allowed_requests.set_all();
Box::new(output.into_iter())
}
}
// This is purely during a backwards compatible transitionary period and should be removed
@@ -3089,6 +3218,7 @@ mod test {
let block_announce_validator = Box::new(DefaultBlockAnnounceValidator);
let peer_id = PeerId::random();
let import_queue = Box::new(sc_consensus::import_queue::mock::MockImportQueueHandle::new());
let (_chain_sync_network_provider, chain_sync_network_handle) =
NetworkServiceProvider::new();
let (mut sync, _, _) = ChainSync::new(
@@ -3100,7 +3230,9 @@ mod test {
block_announce_validator,
1,
None,
None,
chain_sync_network_handle,
import_queue,
ProtocolName::from("block-request"),
ProtocolName::from("state-request"),
None,
@@ -3151,6 +3283,7 @@ mod test {
#[test]
fn restart_doesnt_affect_peers_downloading_finality_data() {
let mut client = Arc::new(TestClientBuilder::new().build());
let import_queue = Box::new(sc_consensus::import_queue::mock::MockImportQueueHandle::new());
let (_chain_sync_network_provider, chain_sync_network_handle) =
NetworkServiceProvider::new();
@@ -3163,7 +3296,9 @@ mod test {
Box::new(DefaultBlockAnnounceValidator),
1,
None,
None,
chain_sync_network_handle,
import_queue,
ProtocolName::from("block-request"),
ProtocolName::from("state-request"),
None,
@@ -3330,6 +3465,7 @@ mod test {
sp_tracing::try_init_simple();
let mut client = Arc::new(TestClientBuilder::new().build());
let import_queue = Box::new(sc_consensus::import_queue::mock::MockImportQueueHandle::new());
let (_chain_sync_network_provider, chain_sync_network_handle) =
NetworkServiceProvider::new();
@@ -3342,7 +3478,9 @@ mod test {
Box::new(DefaultBlockAnnounceValidator),
5,
None,
None,
chain_sync_network_handle,
import_queue,
ProtocolName::from("block-request"),
ProtocolName::from("state-request"),
None,
@@ -3453,6 +3591,7 @@ mod test {
};
let mut client = Arc::new(TestClientBuilder::new().build());
let import_queue = Box::new(sc_consensus::import_queue::mock::MockImportQueueHandle::new());
let (_chain_sync_network_provider, chain_sync_network_handle) =
NetworkServiceProvider::new();
let info = client.info();
@@ -3466,7 +3605,9 @@ mod test {
Box::new(DefaultBlockAnnounceValidator),
5,
None,
None,
chain_sync_network_handle,
import_queue,
ProtocolName::from("block-request"),
ProtocolName::from("state-request"),
None,
@@ -3584,6 +3725,7 @@ mod test {
fn can_sync_huge_fork() {
sp_tracing::try_init_simple();
let import_queue = Box::new(sc_consensus::import_queue::mock::MockImportQueueHandle::new());
let (_chain_sync_network_provider, chain_sync_network_handle) =
NetworkServiceProvider::new();
let mut client = Arc::new(TestClientBuilder::new().build());
@@ -3619,7 +3761,9 @@ mod test {
Box::new(DefaultBlockAnnounceValidator),
5,
None,
None,
chain_sync_network_handle,
import_queue,
ProtocolName::from("block-request"),
ProtocolName::from("state-request"),
None,
@@ -3722,6 +3866,7 @@ mod test {
fn syncs_fork_without_duplicate_requests() {
sp_tracing::try_init_simple();
let import_queue = Box::new(sc_consensus::import_queue::mock::MockImportQueueHandle::new());
let (_chain_sync_network_provider, chain_sync_network_handle) =
NetworkServiceProvider::new();
let mut client = Arc::new(TestClientBuilder::new().build());
@@ -3757,7 +3902,9 @@ mod test {
Box::new(DefaultBlockAnnounceValidator),
5,
None,
None,
chain_sync_network_handle,
import_queue,
ProtocolName::from("block-request"),
ProtocolName::from("state-request"),
None,
@@ -3881,6 +4028,7 @@ mod test {
#[test]
fn removes_target_fork_on_disconnect() {
sp_tracing::try_init_simple();
let import_queue = Box::new(sc_consensus::import_queue::mock::MockImportQueueHandle::new());
let (_chain_sync_network_provider, chain_sync_network_handle) =
NetworkServiceProvider::new();
let mut client = Arc::new(TestClientBuilder::new().build());
@@ -3895,7 +4043,9 @@ mod test {
Box::new(DefaultBlockAnnounceValidator),
1,
None,
None,
chain_sync_network_handle,
import_queue,
ProtocolName::from("block-request"),
ProtocolName::from("state-request"),
None,
@@ -3921,6 +4071,7 @@ mod test {
#[test]
fn can_import_response_with_missing_blocks() {
sp_tracing::try_init_simple();
let import_queue = Box::new(sc_consensus::import_queue::mock::MockImportQueueHandle::new());
let (_chain_sync_network_provider, chain_sync_network_handle) =
NetworkServiceProvider::new();
let mut client2 = Arc::new(TestClientBuilder::new().build());
@@ -3937,7 +4088,9 @@ mod test {
Box::new(DefaultBlockAnnounceValidator),
1,
None,
None,
chain_sync_network_handle,
import_queue,
ProtocolName::from("block-request"),
ProtocolName::from("state-request"),
None,
+4 -10
View File
@@ -21,11 +21,10 @@
use futures::task::Poll;
use libp2p::PeerId;
use sc_consensus::{BlockImportError, BlockImportStatus};
use sc_network_common::sync::{
message::{BlockAnnounce, BlockData, BlockRequest, BlockResponse},
BadPeer, ChainSync as ChainSyncT, Metrics, OnBlockData, OnBlockJustification,
OpaqueBlockResponse, PeerInfo, PollBlockAnnounceValidation, PollResult, SyncStatus,
OpaqueBlockResponse, PeerInfo, PollBlockAnnounceValidation, SyncStatus,
};
use sp_runtime::traits::{Block as BlockT, NumberFor};
@@ -60,17 +59,12 @@ mockall::mock! {
request: Option<BlockRequest<Block>>,
response: BlockResponse<Block>,
) -> Result<OnBlockData<Block>, BadPeer>;
fn process_block_response_data(&mut self, blocks_to_import: Result<OnBlockData<Block>, BadPeer>);
fn on_block_justification(
&mut self,
who: PeerId,
response: BlockResponse<Block>,
) -> Result<OnBlockJustification<Block>, BadPeer>;
fn on_blocks_processed(
&mut self,
imported: usize,
count: usize,
results: Vec<(Result<BlockImportStatus<NumberFor<Block>>, BlockImportError>, Block::Hash)>,
) -> Box<dyn Iterator<Item = Result<(PeerId, BlockRequest<Block>), BadPeer>>>;
fn on_justification_import(
&mut self,
hash: Block::Hash,
@@ -89,7 +83,7 @@ mockall::mock! {
&mut self,
cx: &mut std::task::Context<'a>,
) -> Poll<PollBlockAnnounceValidation<Block::Header>>;
fn peer_disconnected(&mut self, who: &PeerId) -> Option<OnBlockData<Block>>;
fn peer_disconnected(&mut self, who: &PeerId);
fn metrics(&self) -> Metrics;
fn block_response_into_blocks(
&self,
@@ -99,7 +93,7 @@ mockall::mock! {
fn poll<'a>(
&mut self,
cx: &mut std::task::Context<'a>,
) -> Poll<PollResult<Block>>;
) -> Poll<PollBlockAnnounceValidation<Block::Header>>;
fn send_block_request(
&mut self,
who: PeerId,
@@ -17,6 +17,7 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
use libp2p::PeerId;
use sc_consensus::{BlockImportError, BlockImportStatus, JustificationSyncLink, Link};
use sc_network_common::service::NetworkSyncForkRequest;
use sc_utils::mpsc::TracingUnboundedSender;
use sp_runtime::traits::{Block as BlockT, NumberFor};
@@ -25,9 +26,18 @@ use sp_runtime::traits::{Block as BlockT, NumberFor};
#[derive(Debug)]
pub enum ToServiceCommand<B: BlockT> {
SetSyncForkRequest(Vec<PeerId>, B::Hash, NumberFor<B>),
RequestJustification(B::Hash, NumberFor<B>),
ClearJustificationRequests,
BlocksProcessed(
usize,
usize,
Vec<(Result<BlockImportStatus<NumberFor<B>>, BlockImportError>, B::Hash)>,
),
JustificationImported(PeerId, B::Hash, NumberFor<B>, bool),
}
/// Handle for communicating with `ChainSync` asynchronously
#[derive(Clone)]
pub struct ChainSyncInterfaceHandle<B: BlockT> {
tx: TracingUnboundedSender<ToServiceCommand<B>>,
}
@@ -56,3 +66,46 @@ impl<B: BlockT + 'static> NetworkSyncForkRequest<B::Hash, NumberFor<B>>
.unbounded_send(ToServiceCommand::SetSyncForkRequest(peers, hash, number));
}
}
impl<B: BlockT> JustificationSyncLink<B> for ChainSyncInterfaceHandle<B> {
/// Request a justification for the given block from the network.
///
/// On success, the justification will be passed to the import queue that was part at
/// initialization as part of the configuration.
fn request_justification(&self, hash: &B::Hash, number: NumberFor<B>) {
let _ = self.tx.unbounded_send(ToServiceCommand::RequestJustification(*hash, number));
}
fn clear_justification_requests(&self) {
let _ = self.tx.unbounded_send(ToServiceCommand::ClearJustificationRequests);
}
}
impl<B: BlockT> Link<B> for ChainSyncInterfaceHandle<B> {
fn blocks_processed(
&mut self,
imported: usize,
count: usize,
results: Vec<(Result<BlockImportStatus<NumberFor<B>>, BlockImportError>, B::Hash)>,
) {
let _ = self
.tx
.unbounded_send(ToServiceCommand::BlocksProcessed(imported, count, results));
}
fn justification_imported(
&mut self,
who: PeerId,
hash: &B::Hash,
number: NumberFor<B>,
success: bool,
) {
let _ = self
.tx
.unbounded_send(ToServiceCommand::JustificationImported(who, *hash, number, success));
}
fn request_justification(&mut self, hash: &B::Hash, number: NumberFor<B>) {
let _ = self.tx.unbounded_send(ToServiceCommand::RequestJustification(*hash, number));
}
}
@@ -18,6 +18,7 @@
use futures::channel::oneshot;
use libp2p::{Multiaddr, PeerId};
use sc_consensus::{BlockImportError, BlockImportStatus};
use sc_network_common::{
config::MultiaddrWithPeerId,
protocol::ProtocolName,
@@ -29,13 +30,43 @@ use sp_runtime::traits::{Block as BlockT, NumberFor};
use std::collections::HashSet;
mockall::mock! {
pub ChainSyncInterface<B: BlockT> {}
pub ChainSyncInterface<B: BlockT> {
pub fn justification_sync_link_request_justification(&self, hash: &B::Hash, number: NumberFor<B>);
pub fn justification_sync_link_clear_justification_requests(&self);
}
impl<B: BlockT + 'static> NetworkSyncForkRequest<B::Hash, NumberFor<B>>
for ChainSyncInterface<B>
{
fn set_sync_fork_request(&self, peers: Vec<PeerId>, hash: B::Hash, number: NumberFor<B>);
}
impl<B: BlockT> sc_consensus::Link<B> for ChainSyncInterface<B> {
fn blocks_processed(
&mut self,
imported: usize,
count: usize,
results: Vec<(Result<BlockImportStatus<NumberFor<B>>, BlockImportError>, B::Hash)>,
);
fn justification_imported(
&mut self,
who: PeerId,
hash: &B::Hash,
number: NumberFor<B>,
success: bool,
);
fn request_justification(&mut self, hash: &B::Hash, number: NumberFor<B>);
}
}
impl<B: BlockT> sc_consensus::JustificationSyncLink<B> for MockChainSyncInterface<B> {
fn request_justification(&self, hash: &B::Hash, number: NumberFor<B>) {
self.justification_sync_link_request_justification(hash, number);
}
fn clear_justification_requests(&self) {
self.justification_sync_link_clear_justification_requests();
}
}
mockall::mock! {
@@ -37,6 +37,7 @@ use substrate_test_runtime_client::{TestClientBuilder, TestClientBuilderExt as _
// poll `ChainSync` and verify that a new sync fork request has been registered
#[tokio::test]
async fn delegate_to_chainsync() {
let import_queue = Box::new(sc_consensus::import_queue::mock::MockImportQueueHandle::new());
let (_chain_sync_network_provider, chain_sync_network_handle) = NetworkServiceProvider::new();
let (mut chain_sync, chain_sync_service, _) = ChainSync::new(
sc_network_common::sync::SyncMode::Full,
@@ -47,7 +48,9 @@ async fn delegate_to_chainsync() {
Box::new(DefaultBlockAnnounceValidator),
1u32,
None,
None,
chain_sync_network_handle,
import_queue,
ProtocolName::from("block-request"),
ProtocolName::from("state-request"),
None,
+8 -4
View File
@@ -43,8 +43,8 @@ use sc_client_api::{
};
use sc_consensus::{
BasicQueue, BlockCheckParams, BlockImport, BlockImportParams, BoxJustificationImport,
ForkChoiceStrategy, ImportResult, JustificationImport, JustificationSyncLink, LongestChain,
Verifier,
ForkChoiceStrategy, ImportQueue, ImportResult, JustificationImport, JustificationSyncLink,
LongestChain, Verifier,
};
use sc_network::{
config::{NetworkConfiguration, RequestResponseConfig, Role, SyncMode},
@@ -896,7 +896,9 @@ where
block_announce_validator,
network_config.max_parallel_downloads,
Some(warp_sync),
None,
chain_sync_network_handle,
import_queue.service(),
block_request_protocol_config.name.clone(),
state_request_protocol_config.name.clone(),
Some(warp_protocol_config.name.clone()),
@@ -915,9 +917,8 @@ where
chain: client.clone(),
protocol_id,
fork_id,
import_queue,
chain_sync: Box::new(chain_sync),
chain_sync_service,
chain_sync_service: Box::new(chain_sync_service.clone()),
metrics_registry: None,
block_announce_config,
request_response_protocol_configs: [
@@ -936,6 +937,9 @@ where
self.rt_handle().spawn(async move {
chain_sync_network_provider.run(service).await;
});
self.rt_handle().spawn(async move {
import_queue.run(Box::new(chain_sync_service)).await;
});
self.mut_peers(move |peers| {
for peer in peers.iter_mut() {
+4 -2
View File
@@ -853,7 +853,9 @@ where
block_announce_validator,
config.network.max_parallel_downloads,
warp_sync_provider,
config.prometheus_config.as_ref().map(|config| config.registry.clone()).as_ref(),
chain_sync_network_handle,
import_queue.service(),
block_request_protocol_config.name.clone(),
state_request_protocol_config.name.clone(),
warp_sync_protocol_config.as_ref().map(|config| config.name.clone()),
@@ -877,9 +879,8 @@ where
chain: client.clone(),
protocol_id: protocol_id.clone(),
fork_id: config.chain_spec.fork_id().map(ToOwned::to_owned),
import_queue: Box::new(import_queue),
chain_sync: Box::new(chain_sync),
chain_sync_service,
chain_sync_service: Box::new(chain_sync_service.clone()),
metrics_registry: config.prometheus_config.as_ref().map(|config| config.registry.clone()),
block_announce_config,
request_response_protocol_configs: request_response_protocol_configs
@@ -925,6 +926,7 @@ where
Some("networking"),
chain_sync_network_provider.run(network.clone()),
);
spawn_handle.spawn("import-queue", None, import_queue.run(Box::new(chain_sync_service)));
let (system_rpc_tx, system_rpc_rx) = tracing_unbounded("mpsc_system_rpc");
@@ -157,7 +157,7 @@ fn import_block_to_queue<TBl, TImpQu>(
let (header, extrinsics) = signed_block.block.deconstruct();
let hash = header.hash();
// import queue handles verification and importing it into the client.
queue.import_blocks(
queue.service_ref().import_blocks(
BlockOrigin::File,
vec![IncomingBlock::<TBl> {
hash,