Extract syncing protocol from sc-network (#12828)

* 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.

* Move stuff to SyncingEngine

* Move `ChainSync` instanation to `SyncingEngine`

Some of the tests have to be rewritten

* Move peer hashmap to `SyncingEngine`

* Let `SyncingEngine` to implement `ChainSyncInterface`

* Introduce `SyncStatusProvider`

* Move `sync_peer_(connected|disconnected)` to `SyncingEngine`

* Implement `SyncEventStream`

Remove `SyncConnected`/`SyncDisconnected` events from
`NetworkEvenStream` and provide those events through
`ChainSyncInterface` instead.

Modify BEEFY/GRANDPA/transactions protocol and `NetworkGossip` to take
`SyncEventStream` object which they listen to for incoming sync peer
events.

* Introduce `ChainSyncInterface`

This interface provides a set of miscellaneous functions that other
subsystems can use to query, for example, the syncing status.

* Move event stream polling to `SyncingEngine`

Subscribe to `NetworkStreamEvent` and poll the incoming notifications
and substream events from `SyncingEngine`.

The code needs refactoring.

* Make `SyncingEngine` into an asynchronous runner

This commits removes the last hard dependency of syncing from
`sc-network` meaning the protocol now lives completely outside of
`sc-network`, ignoring the hardcoded peerset entry which will be
addressed in the future.

Code needs a lot of refactoring.

* Fix warnings

* Code refactoring

* Use `SyncingService` for BEEFY

* Use `SyncingService` for GRANDPA

* Remove call delegation from `NetworkService`

* Remove `ChainSyncService`

* Remove `ChainSync` service tests

They were written for the sole purpose of verifying that `NetworWorker`
continues to function while the calls are being dispatched to
`ChainSync`.

* Refactor code

* Refactor code

* Update client/finality-grandpa/src/communication/tests.rs

Co-authored-by: Anton <anton.kalyaev@gmail.com>

* Fix warnings

* Apply review comments

* Fix docs

* Fix test

* cargo-fmt

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

Co-authored-by: Anton <anton.kalyaev@gmail.com>

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

Co-authored-by: Anton <anton.kalyaev@gmail.com>

* Add missing docs

* Refactor code

---------

Co-authored-by: Anton <anton.kalyaev@gmail.com>
This commit is contained in:
Aaro Altonen
2023-03-06 18:33:38 +02:00
committed by GitHub
parent 8adde84330
commit 1a7f5be07f
57 changed files with 2904 additions and 2877 deletions
@@ -59,7 +59,10 @@ use crate::{
use gossip::{
FullCatchUpMessage, FullCommitMessage, GossipMessage, GossipValidator, PeerReport, VoteMessage,
};
use sc_network_common::service::{NetworkBlock, NetworkSyncForkRequest};
use sc_network_common::{
service::{NetworkBlock, NetworkSyncForkRequest},
sync::SyncEventStream,
};
use sc_utils::mpsc::TracingUnboundedReceiver;
use sp_consensus_grandpa::{AuthorityId, AuthoritySignature, RoundNumber, SetId as SetIdNumber};
@@ -163,24 +166,35 @@ const TELEMETRY_VOTERS_LIMIT: usize = 10;
/// A handle to the network.
///
/// Something that provides both the capabilities needed for the `gossip_network::Network` trait as
/// well as the ability to set a fork sync request for a particular block.
pub trait Network<Block: BlockT>:
/// Something that provides the capabilities needed for the `gossip_network::Network` trait.
pub trait Network<Block: BlockT>: GossipNetwork<Block> + Clone + Send + 'static {}
impl<Block, T> Network<Block> for T
where
Block: BlockT,
T: GossipNetwork<Block> + Clone + Send + 'static,
{
}
/// A handle to syncing-related services.
///
/// Something that provides the ability to set a fork sync request for a particular block.
pub trait Syncing<Block: BlockT>:
NetworkSyncForkRequest<Block::Hash, NumberFor<Block>>
+ NetworkBlock<Block::Hash, NumberFor<Block>>
+ GossipNetwork<Block>
+ SyncEventStream
+ Clone
+ Send
+ 'static
{
}
impl<Block, T> Network<Block> for T
impl<Block, T> Syncing<Block> for T
where
Block: BlockT,
T: NetworkSyncForkRequest<Block::Hash, NumberFor<Block>>
+ NetworkBlock<Block::Hash, NumberFor<Block>>
+ GossipNetwork<Block>
+ SyncEventStream
+ Clone
+ Send
+ 'static,
@@ -198,8 +212,9 @@ pub(crate) fn global_topic<B: BlockT>(set_id: SetIdNumber) -> B::Hash {
}
/// Bridge between the underlying network service, gossiping consensus messages and Grandpa
pub(crate) struct NetworkBridge<B: BlockT, N: Network<B>> {
pub(crate) struct NetworkBridge<B: BlockT, N: Network<B>, S: Syncing<B>> {
service: N,
sync: S,
gossip_engine: Arc<Mutex<GossipEngine<B>>>,
validator: Arc<GossipValidator<B>>,
@@ -225,15 +240,16 @@ pub(crate) struct NetworkBridge<B: BlockT, N: Network<B>> {
telemetry: Option<TelemetryHandle>,
}
impl<B: BlockT, N: Network<B>> Unpin for NetworkBridge<B, N> {}
impl<B: BlockT, N: Network<B>, S: Syncing<B>> Unpin for NetworkBridge<B, N, S> {}
impl<B: BlockT, N: Network<B>> NetworkBridge<B, N> {
impl<B: BlockT, N: Network<B>, S: Syncing<B>> NetworkBridge<B, N, S> {
/// Create a new NetworkBridge to the given NetworkService. Returns the service
/// handle.
/// On creation it will register previous rounds' votes with the gossip
/// service taken from the VoterSetState.
pub(crate) fn new(
service: N,
sync: S,
config: crate::Config,
set_state: crate::environment::SharedVoterSetState<B>,
prometheus_registry: Option<&Registry>,
@@ -246,6 +262,7 @@ impl<B: BlockT, N: Network<B>> NetworkBridge<B, N> {
let validator = Arc::new(validator);
let gossip_engine = Arc::new(Mutex::new(GossipEngine::new(
service.clone(),
sync.clone(),
protocol,
validator.clone(),
prometheus_registry,
@@ -290,6 +307,7 @@ impl<B: BlockT, N: Network<B>> NetworkBridge<B, N> {
NetworkBridge {
service,
sync,
gossip_engine,
validator,
neighbor_sender: neighbor_packet_sender,
@@ -475,11 +493,11 @@ impl<B: BlockT, N: Network<B>> NetworkBridge<B, N> {
hash: B::Hash,
number: NumberFor<B>,
) {
self.service.set_sync_fork_request(peers, hash, number)
self.sync.set_sync_fork_request(peers, hash, number)
}
}
impl<B: BlockT, N: Network<B>> Future for NetworkBridge<B, N> {
impl<B: BlockT, N: Network<B>, S: Syncing<B>> Future for NetworkBridge<B, N, S> {
type Output = Result<(), Error>;
fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
@@ -661,10 +679,11 @@ fn incoming_global<B: BlockT>(
})
}
impl<B: BlockT, N: Network<B>> Clone for NetworkBridge<B, N> {
impl<B: BlockT, N: Network<B>, S: Syncing<B>> Clone for NetworkBridge<B, N, S> {
fn clone(&self) -> Self {
NetworkBridge {
service: self.service.clone(),
sync: self.sync.clone(),
gossip_engine: self.gossip_engine.clone(),
validator: Arc::clone(&self.validator),
neighbor_sender: self.neighbor_sender.clone(),
@@ -33,6 +33,7 @@ use sc_network_common::{
NetworkBlock, NetworkEventStream, NetworkNotification, NetworkPeers,
NetworkSyncForkRequest, NotificationSender, NotificationSenderError,
},
sync::{SyncEvent as SyncStreamEvent, SyncEventStream},
};
use sc_network_gossip::Validator;
use sc_network_test::{Block, Hash};
@@ -153,6 +154,10 @@ impl NetworkNotification for TestNetwork {
) -> Result<Box<dyn NotificationSender>, NotificationSenderError> {
unimplemented!();
}
fn set_notification_handshake(&self, _protocol: ProtocolName, _handshake: Vec<u8>) {
unimplemented!();
}
}
impl NetworkBlock<Hash, NumberFor<Block>> for TestNetwork {
@@ -186,8 +191,34 @@ impl sc_network_gossip::ValidatorContext<Block> for TestNetwork {
fn send_topic(&mut self, _: &PeerId, _: Hash, _: bool) {}
}
#[derive(Clone)]
pub(crate) struct TestSync;
impl SyncEventStream for TestSync {
fn event_stream(
&self,
_name: &'static str,
) -> Pin<Box<dyn Stream<Item = SyncStreamEvent> + Send>> {
Box::pin(futures::stream::pending())
}
}
impl NetworkBlock<Hash, NumberFor<Block>> for TestSync {
fn announce_block(&self, _hash: Hash, _data: Option<Vec<u8>>) {
unimplemented!();
}
fn new_best_block_imported(&self, _hash: Hash, _number: NumberFor<Block>) {
unimplemented!();
}
}
impl NetworkSyncForkRequest<Hash, NumberFor<Block>> for TestSync {
fn set_sync_fork_request(&self, _peers: Vec<PeerId>, _hash: Hash, _number: NumberFor<Block>) {}
}
pub(crate) struct Tester {
pub(crate) net_handle: super::NetworkBridge<Block, TestNetwork>,
pub(crate) net_handle: super::NetworkBridge<Block, TestNetwork, TestSync>,
gossip_validator: Arc<GossipValidator<Block>>,
pub(crate) events: TracingUnboundedReceiver<Event>,
}
@@ -255,6 +286,7 @@ fn voter_set_state() -> SharedVoterSetState<Block> {
pub(crate) fn make_test_network() -> (impl Future<Output = Tester>, TestNetwork) {
let (tx, rx) = tracing_unbounded("test", 100_000);
let net = TestNetwork { sender: tx };
let sync = TestSync {};
#[derive(Clone)]
struct Exit;
@@ -267,7 +299,8 @@ pub(crate) fn make_test_network() -> (impl Future<Output = Tester>, TestNetwork)
}
}
let bridge = super::NetworkBridge::new(net.clone(), config(), voter_set_state(), None, None);
let bridge =
super::NetworkBridge::new(net.clone(), sync, config(), voter_set_state(), None, None);
(
futures::future::ready(Tester {
@@ -370,6 +403,7 @@ fn good_commit_leads_to_relay() {
protocol: grandpa_protocol_name::NAME.into(),
negotiated_fallback: None,
role: ObservedRole::Full,
received_handshake: vec![],
});
let _ = sender.unbounded_send(NetworkEvent::NotificationsReceived {
@@ -387,6 +421,7 @@ fn good_commit_leads_to_relay() {
protocol: grandpa_protocol_name::NAME.into(),
negotiated_fallback: None,
role: ObservedRole::Full,
received_handshake: vec![],
});
// Announce its local set has being on the current set id through a neighbor
@@ -519,6 +554,7 @@ fn bad_commit_leads_to_report() {
protocol: grandpa_protocol_name::NAME.into(),
negotiated_fallback: None,
role: ObservedRole::Full,
received_handshake: vec![],
});
let _ = sender.unbounded_send(NetworkEvent::NotificationsReceived {
remote: sender_id,