Isolate the code of ChainSync and turn it into a state machine (#2497)

* Move the is_offline and is_major_syncing logic to service.rs

* Move the ImportQueue to service.rs

* Remove stop() and abort()

* Add some more documentation to sync.rs
This commit is contained in:
Pierre Krieger
2019-05-12 19:23:45 +02:00
committed by Arkadiy Paronyan
parent cbe13c459b
commit 6c41d0b3ec
5 changed files with 164 additions and 170 deletions
+40 -38
View File
@@ -17,9 +17,9 @@
use futures::{prelude::*, sync::mpsc};
use network_libp2p::PeerId;
use primitives::storage::StorageKey;
use runtime_primitives::{generic::BlockId, ConsensusEngineId};
use consensus::{import_queue::IncomingBlock, import_queue::Origin, BlockOrigin};
use runtime_primitives::{generic::BlockId, ConsensusEngineId, Justification};
use runtime_primitives::traits::{As, Block as BlockT, Header as HeaderT, NumberFor, Zero};
use consensus::import_queue::ImportQueue;
use crate::message::{self, BlockRequest as BlockRequestMessage, Message};
use crate::message::generic::{Message as GenericMessage, ConsensusMessage};
use crate::consensus_gossip::{ConsensusGossip, MessageRecipient as GossipMessageRecipient};
@@ -32,7 +32,6 @@ use parking_lot::RwLock;
use rustc_hex::ToHex;
use std::collections::{BTreeMap, HashMap};
use std::sync::Arc;
use std::sync::atomic::AtomicBool;
use std::{cmp, num::NonZeroUsize, time};
use log::{trace, debug, warn, error};
use crate::chain::Client;
@@ -276,10 +275,6 @@ pub enum ProtocolMsg<B: BlockT, S: NetworkSpecialization<B>> {
ExecuteWithGossip(Box<GossipTask<B> + Send + 'static>),
/// Incoming gossip consensus message.
GossipConsensusMessage(B::Hash, ConsensusEngineId, Vec<u8>, GossipMessageRecipient),
/// Tell protocol to abort sync (does not stop protocol).
/// Only used in tests.
#[cfg(any(test, feature = "test-helpers"))]
Abort,
/// Tell protocol to perform regular maintenance.
#[cfg(any(test, feature = "test-helpers"))]
Tick,
@@ -291,20 +286,17 @@ pub enum ProtocolMsg<B: BlockT, S: NetworkSpecialization<B>> {
impl<B: BlockT, S: NetworkSpecialization<B>, H: ExHashT> Protocol<B, S, H> {
/// Create a new instance.
pub fn new(
is_offline: Arc<AtomicBool>,
is_major_syncing: Arc<AtomicBool>,
connected_peers: Arc<RwLock<HashMap<PeerId, ConnectedPeer<B>>>>,
network_chan: NetworkChan<B>,
config: ProtocolConfig,
chain: Arc<Client<B>>,
import_queue: Box<ImportQueue<B>>,
on_demand: Option<Arc<OnDemandService<B>>>,
transaction_pool: Arc<TransactionPool<H, B>>,
specialization: S,
) -> error::Result<(Protocol<B, S, H>, mpsc::UnboundedSender<ProtocolMsg<B, S>>)> {
let (protocol_sender, port) = mpsc::unbounded();
let info = chain.info()?;
let sync = ChainSync::new(is_offline, is_major_syncing, config.roles, &info, import_queue);
let sync = ChainSync::new(config.roles, &info);
let protocol = Protocol {
network_chan,
port,
@@ -341,6 +333,14 @@ impl<B: BlockT, S: NetworkSpecialization<B>, H: ExHashT> Protocol<B, S, H> {
.count(),
}
}
pub fn is_major_syncing(&self) -> bool {
self.sync.status().is_major_syncing()
}
pub fn is_offline(&self) -> bool {
self.sync.status().is_offline()
}
}
impl<B: BlockT, S: NetworkSpecialization<B>, H: ExHashT> Future for Protocol<B, S, H> {
@@ -358,10 +358,7 @@ impl<B: BlockT, S: NetworkSpecialization<B>, H: ExHashT> Future for Protocol<B,
loop {
match self.port.poll() {
Ok(Async::Ready(None)) | Err(_) => {
self.stop();
return Ok(Async::Ready(()))
}
Ok(Async::Ready(None)) | Err(_) => return Ok(Async::Ready(())),
Ok(Async::Ready(Some(msg))) => if !self.handle_client_msg(msg) {
return Ok(Async::Ready(()))
}
@@ -415,8 +412,6 @@ impl<B: BlockT, S: NetworkSpecialization<B>, H: ExHashT> Protocol<B, S, H> {
#[cfg(any(test, feature = "test-helpers"))]
ProtocolMsg::Tick => self.tick(),
#[cfg(any(test, feature = "test-helpers"))]
ProtocolMsg::Abort => self.abort(),
#[cfg(any(test, feature = "test-helpers"))]
ProtocolMsg::Synchronize => {
trace!(target: "sync", "handle_client_msg: received Synchronize msg");
self.network_chan.send(NetworkMsg::Synchronized)
@@ -457,14 +452,15 @@ impl<B: BlockT, S: NetworkSpecialization<B>, H: ExHashT> Protocol<B, S, H> {
}
}
pub fn on_custom_message(&mut self, who: PeerId, message: Message<B>) {
pub fn on_custom_message(&mut self, who: PeerId, message: Message<B>) -> CustomMessageOutcome<B> {
match message {
GenericMessage::Status(s) => self.on_status_message(who, s),
GenericMessage::BlockRequest(r) => self.on_block_request(who, r),
GenericMessage::BlockResponse(r) => {
if let Some(request) = self.handle_response(who.clone(), &r) {
self.on_block_response(who.clone(), request, r);
let outcome = self.on_block_response(who.clone(), request, r);
self.update_peer_info(&who);
return outcome
}
},
GenericMessage::BlockAnnounce(announce) => {
@@ -495,6 +491,8 @@ impl<B: BlockT, S: NetworkSpecialization<B>, H: ExHashT> Protocol<B, S, H> {
&mut Some(other),
),
}
CustomMessageOutcome::None
}
fn send_message(&mut self, who: PeerId, message: Message<B>) {
@@ -643,7 +641,7 @@ impl<B: BlockT, S: NetworkSpecialization<B>, H: ExHashT> Protocol<B, S, H> {
peer: PeerId,
request: message::BlockRequest<B>,
response: message::BlockResponse<B>,
) {
) -> CustomMessageOutcome<B> {
let blocks_range = match (
response.blocks.first().and_then(|b| b.header.as_ref().map(|h| h.number())),
response.blocks.last().and_then(|b| b.header.as_ref().map(|h| h.number())),
@@ -658,14 +656,26 @@ impl<B: BlockT, S: NetworkSpecialization<B>, H: ExHashT> Protocol<B, S, H> {
// TODO [andre]: move this logic to the import queue so that
// justifications are imported asynchronously (#1482)
if request.fields == message::BlockAttributes::JUSTIFICATION {
self.sync.on_block_justification_data(
let outcome = self.sync.on_block_justification_data(
&mut ProtocolContext::new(&mut self.context_data, &self.network_chan),
peer,
request,
response,
);
if let Some((origin, hash, nb, just)) = outcome {
CustomMessageOutcome::JustificationImport(origin, hash, nb, just)
} else {
CustomMessageOutcome::None
}
} else {
self.sync.on_block_data(&mut ProtocolContext::new(&mut self.context_data, &self.network_chan), peer, request, response);
let outcome = self.sync.on_block_data(&mut ProtocolContext::new(&mut self.context_data, &self.network_chan), peer, request, response);
if let Some((origin, blocks)) = outcome {
CustomMessageOutcome::BlockImport(origin, blocks)
} else {
CustomMessageOutcome::None
}
}
}
@@ -891,22 +901,6 @@ impl<B: BlockT, S: NetworkSpecialization<B>, H: ExHashT> Protocol<B, S, H> {
}
}
fn abort(&mut self) {
self.sync.clear();
self.specialization.on_abort();
self.context_data.peers.clear();
self.handshaking_peers.clear();
self.consensus_gossip.abort();
}
fn stop(&mut self) {
// stop processing import requests first (without holding a sync lock)
self.sync.stop();
// and then clear all the sync data
self.abort();
}
fn on_block_announce(&mut self, who: PeerId, announce: message::BlockAnnounce<B::Header>) {
let header = announce.header;
let hash = header.hash();
@@ -1107,6 +1101,14 @@ impl<B: BlockT, S: NetworkSpecialization<B>, H: ExHashT> Protocol<B, S, H> {
}
}
/// Outcome of an incoming custom message.
#[derive(Debug)]
pub enum CustomMessageOutcome<B: BlockT> {
BlockImport(BlockOrigin, Vec<IncomingBlock<B>>),
JustificationImport(Origin, B::Hash, NumberFor<B>, Justification),
None,
}
fn send_message<B: BlockT, H: ExHashT>(
peers: &mut HashMap<PeerId, Peer<B, H>>,
network_chan: &NetworkChan<B>,