// This file is part of Substrate.
// Copyright (C) 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 .
use futures::channel::oneshot;
use libp2p::PeerId;
use sc_consensus::{BlockImportError, BlockImportStatus, JustificationSyncLink, Link};
use sc_network_common::{service::NetworkSyncForkRequest, sync::SyncStatus};
use sc_utils::mpsc::TracingUnboundedSender;
use sp_runtime::traits::{Block as BlockT, NumberFor};
/// Commands send to `ChainSync`
#[derive(Debug)]
pub enum ToServiceCommand {
SetSyncForkRequest(Vec, B::Hash, NumberFor),
RequestJustification(B::Hash, NumberFor),
ClearJustificationRequests,
BlocksProcessed(
usize,
usize,
Vec<(Result>, BlockImportError>, B::Hash)>,
),
JustificationImported(PeerId, B::Hash, NumberFor, bool),
BlockFinalized(B::Hash, NumberFor),
Status {
pending_response: oneshot::Sender>,
},
}
/// Handle for communicating with `ChainSync` asynchronously
#[derive(Clone)]
pub struct ChainSyncInterfaceHandle {
tx: TracingUnboundedSender>,
}
impl ChainSyncInterfaceHandle {
/// Create new handle
pub fn new(tx: TracingUnboundedSender>) -> Self {
Self { tx }
}
/// Notify ChainSync about finalized block
pub fn on_block_finalized(&self, hash: B::Hash, number: NumberFor) {
let _ = self.tx.unbounded_send(ToServiceCommand::BlockFinalized(hash, number));
}
/// Get sync status
///
/// Returns an error if `ChainSync` has terminated.
pub async fn status(&self) -> Result, ()> {
let (tx, rx) = oneshot::channel();
let _ = self.tx.unbounded_send(ToServiceCommand::Status { pending_response: tx });
rx.await.map_err(|_| ())
}
}
impl NetworkSyncForkRequest>
for ChainSyncInterfaceHandle
{
/// Configure an explicit fork sync request.
///
/// Note that this function should not be used for recent blocks.
/// Sync should be able to download all the recent forks normally.
/// `set_sync_fork_request` should only be used if external code detects that there's
/// a stale fork missing.
///
/// Passing empty `peers` set effectively removes the sync request.
fn set_sync_fork_request(&self, peers: Vec, hash: B::Hash, number: NumberFor) {
let _ = self
.tx
.unbounded_send(ToServiceCommand::SetSyncForkRequest(peers, hash, number));
}
}
impl JustificationSyncLink for ChainSyncInterfaceHandle {
/// 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) {
let _ = self.tx.unbounded_send(ToServiceCommand::RequestJustification(*hash, number));
}
fn clear_justification_requests(&self) {
let _ = self.tx.unbounded_send(ToServiceCommand::ClearJustificationRequests);
}
}
impl Link for ChainSyncInterfaceHandle {
fn blocks_processed(
&mut self,
imported: usize,
count: usize,
results: Vec<(Result>, 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,
success: bool,
) {
let _ = self
.tx
.unbounded_send(ToServiceCommand::JustificationImported(who, *hash, number, success));
}
fn request_justification(&mut self, hash: &B::Hash, number: NumberFor) {
let _ = self.tx.unbounded_send(ToServiceCommand::RequestJustification(*hash, number));
}
}