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
@@ -766,6 +766,11 @@ mod tests {
fn peers(&self) -> &Vec<AuraPeer> {
&self.peers
}
fn peers_mut(&mut self) -> &mut Vec<AuraPeer> {
&mut self.peers
}
fn mut_peers<F: FnOnce(&mut Vec<AuraPeer>)>(&mut self, closure: F) {
closure(&mut self.peers);
}
@@ -349,6 +349,11 @@ impl TestNetFactory for BabeTestNet {
&self.peers
}
fn peers_mut(&mut self) -> &mut Vec<BabePeer> {
trace!(target: "babe", "Retrieving peers, mutable");
&mut self.peers
}
fn mut_peers<F: FnOnce(&mut Vec<BabePeer>)>(&mut self, closure: F) {
closure(&mut self.peers);
}
@@ -25,6 +25,7 @@ sc-keystore = { version = "4.0.0-dev", path = "../../keystore" }
sc-network = { version = "0.10.0-dev", path = "../../network" }
sc-network-common = { version = "0.10.0-dev", path = "../../network/common" }
sc-network-gossip = { version = "0.10.0-dev", path = "../../network-gossip" }
sc-network-sync = { version = "0.10.0-dev", path = "../../network/sync" }
sc-utils = { version = "4.0.0-dev", path = "../../utils" }
sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" }
sp-application-crypto = { version = "7.0.0", path = "../../../primitives/application-crypto" }
+20 -10
View File
@@ -40,7 +40,7 @@ use sc_client_api::{Backend, BlockBackend, BlockchainEvents, FinalityNotificatio
use sc_consensus::BlockImport;
use sc_network::ProtocolName;
use sc_network_common::service::NetworkRequest;
use sc_network_gossip::{GossipEngine, Network as GossipNetwork};
use sc_network_gossip::{GossipEngine, Network as GossipNetwork, Syncing as GossipSyncing};
use sp_api::{HeaderT, NumberFor, ProvideRuntimeApi};
use sp_blockchain::{
Backend as BlockchainBackend, Error as ClientError, HeaderBackend, Result as ClientResult,
@@ -172,9 +172,11 @@ where
}
/// BEEFY gadget network parameters.
pub struct BeefyNetworkParams<B: Block, N> {
pub struct BeefyNetworkParams<B: Block, N, S> {
/// Network implementing gossip, requests and sync-oracle.
pub network: Arc<N>,
/// Syncing service implementing a sync oracle and an event stream for peers.
pub sync: Arc<S>,
/// Chain specific BEEFY gossip protocol name. See
/// [`communication::beefy_protocol_name::gossip_protocol_name`].
pub gossip_protocol_name: ProtocolName,
@@ -186,7 +188,7 @@ pub struct BeefyNetworkParams<B: Block, N> {
}
/// BEEFY gadget initialization parameters.
pub struct BeefyParams<B: Block, BE, C, N, P, R> {
pub struct BeefyParams<B: Block, BE, C, N, P, R, S> {
/// BEEFY client
pub client: Arc<C>,
/// Client Backend
@@ -198,7 +200,7 @@ pub struct BeefyParams<B: Block, BE, C, N, P, R> {
/// Local key store
pub key_store: Option<SyncCryptoStorePtr>,
/// BEEFY voter network params
pub network_params: BeefyNetworkParams<B, N>,
pub network_params: BeefyNetworkParams<B, N, S>,
/// Minimal delta between blocks, BEEFY should vote for
pub min_block_delta: u32,
/// Prometheus metric registry
@@ -212,15 +214,17 @@ pub struct BeefyParams<B: Block, BE, C, N, P, R> {
/// Start the BEEFY gadget.
///
/// This is a thin shim around running and awaiting a BEEFY worker.
pub async fn start_beefy_gadget<B, BE, C, N, P, R>(beefy_params: BeefyParams<B, BE, C, N, P, R>)
where
pub async fn start_beefy_gadget<B, BE, C, N, P, R, S>(
beefy_params: BeefyParams<B, BE, C, N, P, R, S>,
) where
B: Block,
BE: Backend<B>,
C: Client<B, BE> + BlockBackend<B>,
P: PayloadProvider<B>,
R: ProvideRuntimeApi<B>,
R::Api: BeefyApi<B> + MmrApi<B, MmrRootHash, NumberFor<B>>,
N: GossipNetwork<B> + NetworkRequest + SyncOracle + Send + Sync + 'static,
N: GossipNetwork<B> + NetworkRequest + Send + Sync + 'static,
S: GossipSyncing<B> + SyncOracle + 'static,
{
let BeefyParams {
client,
@@ -235,14 +239,20 @@ where
on_demand_justifications_handler,
} = beefy_params;
let BeefyNetworkParams { network, gossip_protocol_name, justifications_protocol_name, .. } =
network_params;
let BeefyNetworkParams {
network,
sync,
gossip_protocol_name,
justifications_protocol_name,
..
} = network_params;
let known_peers = Arc::new(Mutex::new(KnownPeers::new()));
let gossip_validator =
Arc::new(communication::gossip::GossipValidator::new(known_peers.clone()));
let mut gossip_engine = sc_network_gossip::GossipEngine::new(
network.clone(),
sync.clone(),
gossip_protocol_name,
gossip_validator.clone(),
None,
@@ -280,7 +290,7 @@ where
backend,
payload_provider,
runtime,
network,
sync,
key_store: key_store.into(),
gossip_engine,
gossip_validator,
@@ -223,6 +223,10 @@ impl TestNetFactory for BeefyTestNet {
&self.peers
}
fn peers_mut(&mut self) -> &mut Vec<BeefyPeer> {
&mut self.peers
}
fn mut_peers<F: FnOnce(&mut Vec<BeefyPeer>)>(&mut self, closure: F) {
closure(&mut self.peers);
}
@@ -353,6 +357,7 @@ async fn voter_init_setup(
Arc::new(crate::communication::gossip::GossipValidator::new(known_peers));
let mut gossip_engine = sc_network_gossip::GossipEngine::new(
net.peer(0).network_service().clone(),
net.peer(0).sync_service().clone(),
"/beefy/whatever",
gossip_validator,
None,
@@ -389,6 +394,7 @@ where
let network_params = crate::BeefyNetworkParams {
network: peer.network_service().clone(),
sync: peer.sync_service().clone(),
gossip_protocol_name: beefy_gossip_proto_name(),
justifications_protocol_name: on_demand_justif_handler.protocol_name(),
_phantom: PhantomData,
@@ -407,7 +413,7 @@ where
prometheus_registry: None,
on_demand_justifications_handler: on_demand_justif_handler,
};
let task = crate::start_beefy_gadget::<_, _, _, _, _, _>(beefy_params);
let task = crate::start_beefy_gadget::<_, _, _, _, _, _, _>(beefy_params);
fn assert_send<T: Send>(_: &T) {}
assert_send(&task);
+22 -17
View File
@@ -33,7 +33,6 @@ use codec::{Codec, Decode, Encode};
use futures::{stream::Fuse, FutureExt, StreamExt};
use log::{debug, error, info, log_enabled, trace, warn};
use sc_client_api::{Backend, FinalityNotification, FinalityNotifications, HeaderBackend};
use sc_network_common::service::{NetworkEventStream, NetworkRequest};
use sc_network_gossip::GossipEngine;
use sc_utils::notification::NotificationReceiver;
use sp_api::{BlockId, ProvideRuntimeApi};
@@ -244,11 +243,11 @@ impl<B: Block> VoterOracle<B> {
}
}
pub(crate) struct WorkerParams<B: Block, BE, P, R, N> {
pub(crate) struct WorkerParams<B: Block, BE, P, R, S> {
pub backend: Arc<BE>,
pub payload_provider: P,
pub runtime: Arc<R>,
pub network: N,
pub sync: Arc<S>,
pub key_store: BeefyKeystore,
pub gossip_engine: GossipEngine<B>,
pub gossip_validator: Arc<GossipValidator<B>>,
@@ -296,12 +295,12 @@ impl<B: Block> PersistedState<B> {
}
/// A BEEFY worker plays the BEEFY protocol
pub(crate) struct BeefyWorker<B: Block, BE, P, RuntimeApi, N> {
pub(crate) struct BeefyWorker<B: Block, BE, P, RuntimeApi, S> {
// utilities
backend: Arc<BE>,
payload_provider: P,
runtime: Arc<RuntimeApi>,
network: N,
sync: Arc<S>,
key_store: BeefyKeystore,
// communication
@@ -330,14 +329,14 @@ pub(crate) struct BeefyWorker<B: Block, BE, P, RuntimeApi, N> {
persisted_state: PersistedState<B>,
}
impl<B, BE, P, R, N> BeefyWorker<B, BE, P, R, N>
impl<B, BE, P, R, S> BeefyWorker<B, BE, P, R, S>
where
B: Block + Codec,
BE: Backend<B>,
P: PayloadProvider<B>,
S: SyncOracle,
R: ProvideRuntimeApi<B>,
R::Api: BeefyApi<B>,
N: NetworkEventStream + NetworkRequest + SyncOracle + Send + Sync + Clone + 'static,
{
/// Return a new BEEFY worker instance.
///
@@ -345,13 +344,13 @@ where
/// BEEFY pallet has been deployed on-chain.
///
/// The BEEFY pallet is needed in order to keep track of the BEEFY authority set.
pub(crate) fn new(worker_params: WorkerParams<B, BE, P, R, N>) -> Self {
pub(crate) fn new(worker_params: WorkerParams<B, BE, P, R, S>) -> Self {
let WorkerParams {
backend,
payload_provider,
runtime,
key_store,
network,
sync,
gossip_engine,
gossip_validator,
on_demand_justifications,
@@ -364,7 +363,7 @@ where
backend,
payload_provider,
runtime,
network,
sync,
key_store,
gossip_engine,
gossip_validator,
@@ -836,7 +835,7 @@ where
}
// Don't bother voting or requesting justifications during major sync.
if !self.network.is_major_syncing() {
if !self.sync.is_major_syncing() {
// There were external events, 'state' is changed, author a vote if needed/possible.
if let Err(err) = self.try_to_vote() {
debug!(target: LOG_TARGET, "🥩 {}", err);
@@ -1065,7 +1064,7 @@ pub(crate) mod tests {
use futures::{future::poll_fn, task::Poll};
use parking_lot::Mutex;
use sc_client_api::{Backend as BackendT, HeaderBackend};
use sc_network::NetworkService;
use sc_network_sync::SyncingService;
use sc_network_test::TestNetFactory;
use sp_api::HeaderT;
use sp_blockchain::Backend as BlockchainBackendT;
@@ -1075,7 +1074,7 @@ pub(crate) mod tests {
};
use sp_runtime::traits::One;
use substrate_test_runtime_client::{
runtime::{Block, Digest, DigestItem, Header, H256},
runtime::{Block, Digest, DigestItem, Header},
Backend,
};
@@ -1113,7 +1112,7 @@ pub(crate) mod tests {
Backend,
MmrRootProvider<Block, TestApi>,
TestApi,
Arc<NetworkService<Block, H256>>,
Arc<SyncingService<Block>>,
> {
let keystore = create_beefy_keystore(*key);
@@ -1137,10 +1136,16 @@ pub(crate) mod tests {
let backend = peer.client().as_backend();
let api = Arc::new(TestApi::with_validator_set(&genesis_validator_set));
let network = peer.network_service().clone();
let sync = peer.sync_service().clone();
let known_peers = Arc::new(Mutex::new(KnownPeers::new()));
let gossip_validator = Arc::new(GossipValidator::new(known_peers.clone()));
let gossip_engine =
GossipEngine::new(network.clone(), "/beefy/1", gossip_validator.clone(), None);
let gossip_engine = GossipEngine::new(
network.clone(),
sync.clone(),
"/beefy/1",
gossip_validator.clone(),
None,
);
let metrics = None;
let on_demand_justifications = OnDemandJustificationsEngine::new(
network.clone(),
@@ -1169,7 +1174,7 @@ pub(crate) mod tests {
gossip_engine,
gossip_validator,
metrics,
network,
sync: Arc::new(sync),
on_demand_justifications,
persisted_state,
};
@@ -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,
@@ -50,7 +50,7 @@ use sp_runtime::traits::{Block as BlockT, Header as HeaderT, NumberFor, Zero};
use crate::{
authorities::{AuthoritySet, SharedAuthoritySet},
communication::Network as NetworkT,
communication::{Network as NetworkT, Syncing as SyncingT},
justification::GrandpaJustification,
local_authority_id,
notification::GrandpaJustificationSender,
@@ -423,13 +423,21 @@ impl Metrics {
}
/// The environment we run GRANDPA in.
pub(crate) struct Environment<Backend, Block: BlockT, C, N: NetworkT<Block>, SC, VR> {
pub(crate) struct Environment<
Backend,
Block: BlockT,
C,
N: NetworkT<Block>,
S: SyncingT<Block>,
SC,
VR,
> {
pub(crate) client: Arc<C>,
pub(crate) select_chain: SC,
pub(crate) voters: Arc<VoterSet<AuthorityId>>,
pub(crate) config: Config,
pub(crate) authority_set: SharedAuthoritySet<Block::Hash, NumberFor<Block>>,
pub(crate) network: crate::communication::NetworkBridge<Block, N>,
pub(crate) network: crate::communication::NetworkBridge<Block, N, S>,
pub(crate) set_id: SetId,
pub(crate) voter_set_state: SharedVoterSetState<Block>,
pub(crate) voting_rule: VR,
@@ -439,7 +447,9 @@ pub(crate) struct Environment<Backend, Block: BlockT, C, N: NetworkT<Block>, SC,
pub(crate) _phantom: PhantomData<Backend>,
}
impl<BE, Block: BlockT, C, N: NetworkT<Block>, SC, VR> Environment<BE, Block, C, N, SC, VR> {
impl<BE, Block: BlockT, C, N: NetworkT<Block>, S: SyncingT<Block>, SC, VR>
Environment<BE, Block, C, N, S, SC, VR>
{
/// Updates the voter set state using the given closure. The write lock is
/// held during evaluation of the closure and the environment's voter set
/// state is set to its result if successful.
@@ -469,13 +479,14 @@ impl<BE, Block: BlockT, C, N: NetworkT<Block>, SC, VR> Environment<BE, Block, C,
}
}
impl<BE, Block, C, N, SC, VR> Environment<BE, Block, C, N, SC, VR>
impl<BE, Block, C, N, S, SC, VR> Environment<BE, Block, C, N, S, SC, VR>
where
Block: BlockT,
BE: BackendT<Block>,
C: ClientForGrandpa<Block, BE>,
C::Api: GrandpaApi<Block>,
N: NetworkT<Block>,
S: SyncingT<Block>,
SC: SelectChainT<Block>,
{
/// Report the given equivocation to the GRANDPA runtime module. This method
@@ -572,13 +583,14 @@ where
}
}
impl<BE, Block, C, N, SC, VR> finality_grandpa::Chain<Block::Hash, NumberFor<Block>>
for Environment<BE, Block, C, N, SC, VR>
impl<BE, Block, C, N, S, SC, VR> finality_grandpa::Chain<Block::Hash, NumberFor<Block>>
for Environment<BE, Block, C, N, S, SC, VR>
where
Block: BlockT,
BE: BackendT<Block>,
C: ClientForGrandpa<Block, BE>,
N: NetworkT<Block>,
S: SyncingT<Block>,
SC: SelectChainT<Block>,
VR: VotingRuleT<Block, C>,
NumberFor<Block>: BlockNumberOps,
@@ -630,14 +642,15 @@ where
Ok(tree_route.retracted().iter().skip(1).map(|e| e.hash).collect())
}
impl<B, Block, C, N, SC, VR> voter::Environment<Block::Hash, NumberFor<Block>>
for Environment<B, Block, C, N, SC, VR>
impl<B, Block, C, N, S, SC, VR> voter::Environment<Block::Hash, NumberFor<Block>>
for Environment<B, Block, C, N, S, SC, VR>
where
Block: BlockT,
B: BackendT<Block>,
C: ClientForGrandpa<Block, B> + 'static,
C::Api: GrandpaApi<Block>,
N: NetworkT<Block>,
S: SyncingT<Block>,
SC: SelectChainT<Block> + 'static,
VR: VotingRuleT<Block, C> + Clone + 'static,
NumberFor<Block>: BlockNumberOps,
+22 -13
View File
@@ -141,7 +141,7 @@ pub use voting_rule::{
};
use aux_schema::PersistentData;
use communication::{Network as NetworkT, NetworkBridge};
use communication::{Network as NetworkT, NetworkBridge, Syncing as SyncingT};
use environment::{Environment, VoterSetState};
use until_imported::UntilGlobalMessageBlocksImported;
@@ -349,10 +349,11 @@ pub(crate) trait BlockSyncRequester<Block: BlockT> {
);
}
impl<Block, Network> BlockSyncRequester<Block> for NetworkBridge<Block, Network>
impl<Block, Network, Syncing> BlockSyncRequester<Block> for NetworkBridge<Block, Network, Syncing>
where
Block: BlockT,
Network: NetworkT<Block>,
Syncing: SyncingT<Block>,
{
fn set_sync_fork_request(
&self,
@@ -617,11 +618,11 @@ where
))
}
fn global_communication<BE, Block: BlockT, C, N>(
fn global_communication<BE, Block: BlockT, C, N, S>(
set_id: SetId,
voters: &Arc<VoterSet<AuthorityId>>,
client: Arc<C>,
network: &NetworkBridge<Block, N>,
network: &NetworkBridge<Block, N, S>,
keystore: Option<&SyncCryptoStorePtr>,
metrics: Option<until_imported::Metrics>,
) -> (
@@ -640,6 +641,7 @@ where
BE: Backend<Block> + 'static,
C: ClientForGrandpa<Block, BE> + 'static,
N: NetworkT<Block>,
S: SyncingT<Block>,
NumberFor<Block>: BlockNumberOps,
{
let is_voter = local_authority_id(voters, keystore).is_some();
@@ -665,7 +667,7 @@ where
}
/// Parameters used to run Grandpa.
pub struct GrandpaParams<Block: BlockT, C, N, SC, VR> {
pub struct GrandpaParams<Block: BlockT, C, N, S, SC, VR> {
/// Configuration for the GRANDPA service.
pub config: Config,
/// A link to the block import worker.
@@ -676,6 +678,8 @@ pub struct GrandpaParams<Block: BlockT, C, N, SC, VR> {
/// `sc_network` crate, it is assumed that the Grandpa notifications protocol has been passed
/// to the configuration of the networking. See [`grandpa_peers_set_config`].
pub network: N,
/// Event stream for syncing-related events.
pub sync: S,
/// A voting rule used to potentially restrict target votes.
pub voting_rule: VR,
/// The prometheus metrics registry.
@@ -710,13 +714,14 @@ pub fn grandpa_peers_set_config(
/// Run a GRANDPA voter as a task. Provide configuration and a link to a
/// block import worker that has already been instantiated with `block_import`.
pub fn run_grandpa_voter<Block: BlockT, BE: 'static, C, N, SC, VR>(
grandpa_params: GrandpaParams<Block, C, N, SC, VR>,
pub fn run_grandpa_voter<Block: BlockT, BE: 'static, C, N, S, SC, VR>(
grandpa_params: GrandpaParams<Block, C, N, S, SC, VR>,
) -> sp_blockchain::Result<impl Future<Output = ()> + Send>
where
Block::Hash: Ord,
BE: Backend<Block> + 'static,
N: NetworkT<Block> + Sync + 'static,
S: SyncingT<Block> + Sync + 'static,
SC: SelectChain<Block> + 'static,
VR: VotingRule<Block, C> + Clone + 'static,
NumberFor<Block>: BlockNumberOps,
@@ -727,6 +732,7 @@ where
mut config,
link,
network,
sync,
voting_rule,
prometheus_registry,
shared_voter_state,
@@ -751,6 +757,7 @@ where
let network = NetworkBridge::new(
network,
sync,
config.clone(),
persistent_data.set_state.clone(),
prometheus_registry.as_ref(),
@@ -836,26 +843,27 @@ impl Metrics {
/// Future that powers the voter.
#[must_use]
struct VoterWork<B, Block: BlockT, C, N: NetworkT<Block>, SC, VR> {
struct VoterWork<B, Block: BlockT, C, N: NetworkT<Block>, S: SyncingT<Block>, SC, VR> {
voter: Pin<
Box<dyn Future<Output = Result<(), CommandOrError<Block::Hash, NumberFor<Block>>>> + Send>,
>,
shared_voter_state: SharedVoterState,
env: Arc<Environment<B, Block, C, N, SC, VR>>,
env: Arc<Environment<B, Block, C, N, S, SC, VR>>,
voter_commands_rx: TracingUnboundedReceiver<VoterCommand<Block::Hash, NumberFor<Block>>>,
network: NetworkBridge<Block, N>,
network: NetworkBridge<Block, N, S>,
telemetry: Option<TelemetryHandle>,
/// Prometheus metrics.
metrics: Option<Metrics>,
}
impl<B, Block, C, N, SC, VR> VoterWork<B, Block, C, N, SC, VR>
impl<B, Block, C, N, S, SC, VR> VoterWork<B, Block, C, N, S, SC, VR>
where
Block: BlockT,
B: Backend<Block> + 'static,
C: ClientForGrandpa<Block, B> + 'static,
C::Api: GrandpaApi<Block>,
N: NetworkT<Block> + Sync,
S: SyncingT<Block> + Sync,
NumberFor<Block>: BlockNumberOps,
SC: SelectChain<Block> + 'static,
VR: VotingRule<Block, C> + Clone + 'static,
@@ -863,7 +871,7 @@ where
fn new(
client: Arc<C>,
config: Config,
network: NetworkBridge<Block, N>,
network: NetworkBridge<Block, N, S>,
select_chain: SC,
voting_rule: VR,
persistent_data: PersistentData<Block>,
@@ -1072,11 +1080,12 @@ where
}
}
impl<B, Block, C, N, SC, VR> Future for VoterWork<B, Block, C, N, SC, VR>
impl<B, Block, C, N, S, SC, VR> Future for VoterWork<B, Block, C, N, S, SC, VR>
where
Block: BlockT,
B: Backend<Block> + 'static,
N: NetworkT<Block> + Sync,
S: SyncingT<Block> + Sync,
NumberFor<Block>: BlockNumberOps,
SC: SelectChain<Block> + 'static,
C: ClientForGrandpa<Block, B> + 'static,
@@ -39,7 +39,7 @@ use sp_runtime::traits::{Block as BlockT, NumberFor};
use crate::{
authorities::SharedAuthoritySet,
aux_schema::PersistentData,
communication::{Network as NetworkT, NetworkBridge},
communication::{Network as NetworkT, NetworkBridge, Syncing as SyncingT},
environment, global_communication,
notification::GrandpaJustificationSender,
ClientForGrandpa, CommandOrError, CommunicationIn, Config, Error, LinkHalf, VoterCommand,
@@ -163,14 +163,16 @@ where
/// already been instantiated with `block_import`.
/// NOTE: this is currently not part of the crate's public API since we don't consider
/// it stable enough to use on a live network.
pub fn run_grandpa_observer<BE, Block: BlockT, Client, N, SC>(
pub fn run_grandpa_observer<BE, Block: BlockT, Client, N, S, SC>(
config: Config,
link: LinkHalf<Block, Client, SC>,
network: N,
sync: S,
) -> sp_blockchain::Result<impl Future<Output = ()> + Send>
where
BE: Backend<Block> + Unpin + 'static,
N: NetworkT<Block>,
S: SyncingT<Block>,
SC: SelectChain<Block>,
NumberFor<Block>: BlockNumberOps,
Client: ClientForGrandpa<Block, BE> + 'static,
@@ -186,6 +188,7 @@ where
let network = NetworkBridge::new(
network,
sync,
config.clone(),
persistent_data.set_state.clone(),
None,
@@ -211,11 +214,11 @@ where
/// Future that powers the observer.
#[must_use]
struct ObserverWork<B: BlockT, BE, Client, N: NetworkT<B>> {
struct ObserverWork<B: BlockT, BE, Client, N: NetworkT<B>, S: SyncingT<B>> {
observer:
Pin<Box<dyn Future<Output = Result<(), CommandOrError<B::Hash, NumberFor<B>>>> + Send>>,
client: Arc<Client>,
network: NetworkBridge<B, N>,
network: NetworkBridge<B, N, S>,
persistent_data: PersistentData<B>,
keystore: Option<SyncCryptoStorePtr>,
voter_commands_rx: TracingUnboundedReceiver<VoterCommand<B::Hash, NumberFor<B>>>,
@@ -224,17 +227,18 @@ struct ObserverWork<B: BlockT, BE, Client, N: NetworkT<B>> {
_phantom: PhantomData<BE>,
}
impl<B, BE, Client, Network> ObserverWork<B, BE, Client, Network>
impl<B, BE, Client, Network, Syncing> ObserverWork<B, BE, Client, Network, Syncing>
where
B: BlockT,
BE: Backend<B> + 'static,
Client: ClientForGrandpa<B, BE> + 'static,
Network: NetworkT<B>,
Syncing: SyncingT<B>,
NumberFor<B>: BlockNumberOps,
{
fn new(
client: Arc<Client>,
network: NetworkBridge<B, Network>,
network: NetworkBridge<B, Network, Syncing>,
persistent_data: PersistentData<B>,
keystore: Option<SyncCryptoStorePtr>,
voter_commands_rx: TracingUnboundedReceiver<VoterCommand<B::Hash, NumberFor<B>>>,
@@ -347,12 +351,13 @@ where
}
}
impl<B, BE, C, N> Future for ObserverWork<B, BE, C, N>
impl<B, BE, C, N, S> Future for ObserverWork<B, BE, C, N, S>
where
B: BlockT,
BE: Backend<B> + Unpin + 'static,
C: ClientForGrandpa<B, BE> + 'static,
N: NetworkT<B>,
S: SyncingT<B>,
NumberFor<B>: BlockNumberOps,
{
type Output = Result<(), Error>;
+57 -14
View File
@@ -145,6 +145,10 @@ impl TestNetFactory for GrandpaTestNet {
&self.peers
}
fn peers_mut(&mut self) -> &mut Vec<GrandpaPeer> {
&mut self.peers
}
fn mut_peers<F: FnOnce(&mut Vec<GrandpaPeer>)>(&mut self, closure: F) {
closure(&mut self.peers);
}
@@ -310,6 +314,7 @@ fn initialize_grandpa(
net.peers[peer_id].data.lock().take().expect("link initialized at startup; qed");
(net.peers[peer_id].network_service().clone(), link)
};
let sync = net.peers[peer_id].sync_service().clone();
let grandpa_params = GrandpaParams {
config: Config {
@@ -324,6 +329,7 @@ fn initialize_grandpa(
},
link,
network: net_service,
sync,
voting_rule: (),
prometheus_registry: None,
shared_voter_state: SharedVoterState::empty(),
@@ -451,6 +457,7 @@ async fn finalize_3_voters_1_full_observer() {
tokio::spawn({
let peer_id = 3;
let net_service = net.peers[peer_id].network_service().clone();
let sync = net.peers[peer_id].sync_service().clone();
let link = net.peers[peer_id].data.lock().take().expect("link initialized at startup; qed");
let grandpa_params = GrandpaParams {
@@ -466,6 +473,7 @@ async fn finalize_3_voters_1_full_observer() {
},
link,
network: net_service,
sync,
voting_rule: (),
prometheus_registry: None,
shared_voter_state: SharedVoterState::empty(),
@@ -533,11 +541,15 @@ async fn transition_3_voters_twice_1_full_observer() {
for (peer_id, local_key) in all_peers.clone().into_iter().enumerate() {
let keystore = create_keystore(local_key);
let (net_service, link) = {
let (net_service, link, sync) = {
let net = net.lock();
let link =
net.peers[peer_id].data.lock().take().expect("link initialized at startup; qed");
(net.peers[peer_id].network_service().clone(), link)
(
net.peers[peer_id].network_service().clone(),
link,
net.peers[peer_id].sync_service().clone(),
)
};
let grandpa_params = GrandpaParams {
@@ -553,6 +565,7 @@ async fn transition_3_voters_twice_1_full_observer() {
},
link,
network: net_service,
sync,
voting_rule: (),
prometheus_registry: None,
shared_voter_state: SharedVoterState::empty(),
@@ -999,6 +1012,7 @@ async fn voter_persists_its_votes() {
communication::NetworkBridge::new(
net.peers[1].network_service().clone(),
net.peers[1].sync_service().clone(),
config.clone(),
set_state,
None,
@@ -1016,6 +1030,7 @@ async fn voter_persists_its_votes() {
let link = net.peers[0].data.lock().take().expect("link initialized at startup; qed");
(net.peers[0].network_service().clone(), link)
};
let sync = net.peers[0].sync_service().clone();
let grandpa_params = GrandpaParams {
config: Config {
@@ -1030,6 +1045,7 @@ async fn voter_persists_its_votes() {
},
link,
network: net_service,
sync,
voting_rule: VotingRulesBuilder::default().build(),
prometheus_registry: None,
shared_voter_state: SharedVoterState::empty(),
@@ -1050,6 +1066,7 @@ async fn voter_persists_its_votes() {
// the network service of this new peer
net.add_authority_peer();
let net_service = net.peers[2].network_service().clone();
let sync = net.peers[2].sync_service().clone();
// but we'll reuse the client from the first peer (alice_voter1)
// since we want to share the same database, so that we can
// read the persisted state after aborting alice_voter1.
@@ -1071,6 +1088,7 @@ async fn voter_persists_its_votes() {
},
link,
network: net_service,
sync,
voting_rule: VotingRulesBuilder::default().build(),
prometheus_registry: None,
shared_voter_state: SharedVoterState::empty(),
@@ -1232,6 +1250,7 @@ async fn finalize_3_voters_1_light_observer() {
},
net.peers[3].data.lock().take().expect("link initialized at startup; qed"),
net.peers[3].network_service().clone(),
net.peers[3].sync_service().clone(),
)
.unwrap();
net.peer(0).push_blocks(20, false);
@@ -1265,6 +1284,7 @@ async fn voter_catches_up_to_latest_round_when_behind() {
link,
net: Arc<Mutex<GrandpaTestNet>>|
-> Pin<Box<dyn Future<Output = ()> + Send>> {
let mut net = net.lock();
let grandpa_params = GrandpaParams {
config: Config {
gossip_duration: TEST_GOSSIP_DURATION,
@@ -1277,7 +1297,8 @@ async fn voter_catches_up_to_latest_round_when_behind() {
protocol_name: grandpa_protocol_name::NAME.into(),
},
link,
network: net.lock().peer(peer_id).network_service().clone(),
network: net.peer(peer_id).network_service().clone(),
sync: net.peer(peer_id).sync_service().clone(),
voting_rule: (),
prometheus_registry: None,
shared_voter_state: SharedVoterState::empty(),
@@ -1359,18 +1380,20 @@ async fn voter_catches_up_to_latest_round_when_behind() {
future::select(test, drive_to_completion).await;
}
type TestEnvironment<N, SC, VR> =
Environment<substrate_test_runtime_client::Backend, Block, TestClient, N, SC, VR>;
type TestEnvironment<N, S, SC, VR> =
Environment<substrate_test_runtime_client::Backend, Block, TestClient, N, S, SC, VR>;
fn test_environment_with_select_chain<N, VR, SC>(
fn test_environment_with_select_chain<N, S, VR, SC>(
link: &TestLinkHalf,
keystore: Option<SyncCryptoStorePtr>,
network_service: N,
sync_service: S,
select_chain: SC,
voting_rule: VR,
) -> TestEnvironment<N, SC, VR>
) -> TestEnvironment<N, S, SC, VR>
where
N: NetworkT<Block>,
S: SyncingT<Block>,
VR: VotingRule<Block, TestClient>,
{
let PersistentData { ref authority_set, ref set_state, .. } = link.persistent_data;
@@ -1386,8 +1409,14 @@ where
protocol_name: grandpa_protocol_name::NAME.into(),
};
let network =
NetworkBridge::new(network_service.clone(), config.clone(), set_state.clone(), None, None);
let network = NetworkBridge::new(
network_service.clone(),
sync_service,
config.clone(),
set_state.clone(),
None,
None,
);
Environment {
authority_set: authority_set.clone(),
@@ -1406,20 +1435,23 @@ where
}
}
fn test_environment<N, VR>(
fn test_environment<N, S, VR>(
link: &TestLinkHalf,
keystore: Option<SyncCryptoStorePtr>,
network_service: N,
sync_service: S,
voting_rule: VR,
) -> TestEnvironment<N, LongestChain<substrate_test_runtime_client::Backend, Block>, VR>
) -> TestEnvironment<N, S, LongestChain<substrate_test_runtime_client::Backend, Block>, VR>
where
N: NetworkT<Block>,
S: SyncingT<Block>,
VR: VotingRule<Block, TestClient>,
{
test_environment_with_select_chain(
link,
keystore,
network_service,
sync_service,
link.select_chain.clone(),
voting_rule,
)
@@ -1435,19 +1467,22 @@ async fn grandpa_environment_respects_voting_rules() {
let mut net = GrandpaTestNet::new(TestApi::new(voters), 1, 0);
let peer = net.peer(0);
let network_service = peer.network_service().clone();
let sync_service = peer.sync_service().clone();
let link = peer.data.lock().take().unwrap();
// add 21 blocks
let hashes = peer.push_blocks(21, false);
// create an environment with no voting rule restrictions
let unrestricted_env = test_environment(&link, None, network_service.clone(), ());
let unrestricted_env =
test_environment(&link, None, network_service.clone(), sync_service.clone(), ());
// another with 3/4 unfinalized chain voting rule restriction
let three_quarters_env = test_environment(
&link,
None,
network_service.clone(),
sync_service.clone(),
voting_rule::ThreeQuartersOfTheUnfinalizedChain,
);
@@ -1457,6 +1492,7 @@ async fn grandpa_environment_respects_voting_rules() {
&link,
None,
network_service.clone(),
sync_service,
VotingRulesBuilder::default().build(),
);
@@ -1549,6 +1585,7 @@ async fn grandpa_environment_passes_actual_best_block_to_voting_rules() {
let mut net = GrandpaTestNet::new(TestApi::new(voters), 1, 0);
let peer = net.peer(0);
let network_service = peer.network_service().clone();
let sync_service = peer.sync_service().clone();
let link = peer.data.lock().take().unwrap();
let client = peer.client().as_client().clone();
let select_chain = MockSelectChain::default();
@@ -1562,6 +1599,7 @@ async fn grandpa_environment_passes_actual_best_block_to_voting_rules() {
&link,
None,
network_service.clone(),
sync_service,
select_chain.clone(),
voting_rule::BeforeBestBlockBy(5),
);
@@ -1607,6 +1645,7 @@ async fn grandpa_environment_checks_if_best_block_is_descendent_of_finality_targ
let mut net = GrandpaTestNet::new(TestApi::new(voters), 1, 0);
let peer = net.peer(0);
let network_service = peer.network_service().clone();
let sync_service = peer.sync_service().clone();
let link = peer.data.lock().take().unwrap();
let client = peer.client().as_client().clone();
let select_chain = MockSelectChain::default();
@@ -1615,6 +1654,7 @@ async fn grandpa_environment_checks_if_best_block_is_descendent_of_finality_targ
&link,
None,
network_service.clone(),
sync_service.clone(),
select_chain.clone(),
voting_rule.clone(),
);
@@ -1717,10 +1757,12 @@ async fn grandpa_environment_never_overwrites_round_voter_state() {
let mut net = GrandpaTestNet::new(TestApi::new(voters), 1, 0);
let peer = net.peer(0);
let network_service = peer.network_service().clone();
let sync_service = peer.sync_service().clone();
let link = peer.data.lock().take().unwrap();
let keystore = create_keystore(peers[0]);
let environment = test_environment(&link, Some(keystore), network_service.clone(), ());
let environment =
test_environment(&link, Some(keystore), network_service.clone(), sync_service, ());
let round_state = || finality_grandpa::round::State::genesis(Default::default());
let base = || Default::default();
@@ -1921,9 +1963,10 @@ async fn grandpa_environment_doesnt_send_equivocation_reports_for_itself() {
let mut net = GrandpaTestNet::new(TestApi::new(voters), 1, 0);
let peer = net.peer(0);
let network_service = peer.network_service().clone();
let sync_service = peer.sync_service().clone();
let link = peer.data.lock().take().unwrap();
let keystore = create_keystore(alice);
test_environment(&link, Some(keystore), network_service.clone(), ())
test_environment(&link, Some(keystore), network_service.clone(), sync_service, ())
};
let signed_prevote = {