mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-07-11 11:45:44 +00:00
Rework the event system of sc-network (#1370)
This commit introduces a new concept called `NotificationService` which allows Polkadot protocols to communicate with the underlying notification protocol implementation directly, without routing events through `NetworkWorker`. This implies that each protocol has its own service which it uses to communicate with remote peers and that each `NotificationService` is unique with respect to the underlying notification protocol, meaning `NotificationService` for the transaction protocol can only be used to send and receive transaction-related notifications. The `NotificationService` concept introduces two additional benefits: * allow protocols to start using custom handshakes * allow protocols to accept/reject inbound peers Previously the validation of inbound connections was solely the responsibility of `ProtocolController`. This caused issues with light peers and `SyncingEngine` as `ProtocolController` would accept more peers than `SyncingEngine` could accept which caused peers to have differing views of their own states. `SyncingEngine` would reject excess peers but these rejections were not properly communicated to those peers causing them to assume that they were accepted. With `NotificationService`, the local handshake is not sent to remote peer if peer is rejected which allows it to detect that it was rejected. This commit also deprecates the use of `NetworkEventStream` for all notification-related events and going forward only DHT events are provided through `NetworkEventStream`. If protocols wish to follow each other's events, they must introduce additional abtractions, as is done for GRANDPA and transactions protocols by following the syncing protocol through `SyncEventStream`. Fixes https://github.com/paritytech/polkadot-sdk/issues/512 Fixes https://github.com/paritytech/polkadot-sdk/issues/514 Fixes https://github.com/paritytech/polkadot-sdk/issues/515 Fixes https://github.com/paritytech/polkadot-sdk/issues/554 Fixes https://github.com/paritytech/polkadot-sdk/issues/556 --- These changes are transferred from https://github.com/paritytech/substrate/pull/14197 but there are no functional changes compared to that PR --------- Co-authored-by: Dmitry Markin <dmitry@markin.tech> Co-authored-by: Alexandru Vasile <60601340+lexnv@users.noreply.github.com>
This commit is contained in:
@@ -14,23 +14,24 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use std::{collections::HashSet, sync::Arc};
|
||||
use std::{
|
||||
collections::{HashMap, HashSet},
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
use async_trait::async_trait;
|
||||
use futures::{prelude::*, stream::BoxStream};
|
||||
use parking_lot::Mutex;
|
||||
|
||||
use parity_scale_codec::Encode;
|
||||
|
||||
use sc_network::{
|
||||
config::parse_addr, multiaddr::Multiaddr, types::ProtocolName, Event as NetworkEvent,
|
||||
IfDisconnected, NetworkEventStream, NetworkNotification, NetworkPeers, NetworkRequest,
|
||||
NetworkService, OutboundFailure, ReputationChange, RequestFailure,
|
||||
config::parse_addr, multiaddr::Multiaddr, types::ProtocolName, IfDisconnected, MessageSink,
|
||||
NetworkPeers, NetworkRequest, NetworkService, OutboundFailure, ReputationChange,
|
||||
RequestFailure,
|
||||
};
|
||||
|
||||
use polkadot_node_network_protocol::{
|
||||
peer_set::{
|
||||
CollationVersion, PeerSet, PeerSetProtocolNames, ProtocolVersion, ValidationVersion,
|
||||
},
|
||||
peer_set::{CollationVersion, PeerSet, ProtocolVersion, ValidationVersion},
|
||||
request_response::{OutgoingRequest, Recipient, ReqProtocolNames, Requests},
|
||||
v1 as protocol_v1, v2 as protocol_v2, vstaging as protocol_vstaging, PeerId,
|
||||
};
|
||||
@@ -44,104 +45,94 @@ const LOG_TARGET: &'static str = "parachain::network-bridge-net";
|
||||
// Helper function to send a validation v1 message to a list of peers.
|
||||
// Messages are always sent via the main protocol, even legacy protocol messages.
|
||||
pub(crate) fn send_validation_message_v1(
|
||||
net: &mut impl Network,
|
||||
peers: Vec<PeerId>,
|
||||
peerset_protocol_names: &PeerSetProtocolNames,
|
||||
message: WireMessage<protocol_v1::ValidationProtocol>,
|
||||
metrics: &Metrics,
|
||||
notification_sinks: &Arc<Mutex<HashMap<(PeerSet, PeerId), Box<dyn MessageSink>>>>,
|
||||
) {
|
||||
gum::trace!(target: LOG_TARGET, ?peers, ?message, "Sending validation v1 message to peers",);
|
||||
|
||||
send_message(
|
||||
net,
|
||||
peers,
|
||||
PeerSet::Validation,
|
||||
ValidationVersion::V1.into(),
|
||||
peerset_protocol_names,
|
||||
message,
|
||||
metrics,
|
||||
notification_sinks,
|
||||
);
|
||||
}
|
||||
|
||||
// Helper function to send a validation vstaging message to a list of peers.
|
||||
// Messages are always sent via the main protocol, even legacy protocol messages.
|
||||
pub(crate) fn send_validation_message_vstaging(
|
||||
net: &mut impl Network,
|
||||
peers: Vec<PeerId>,
|
||||
peerset_protocol_names: &PeerSetProtocolNames,
|
||||
message: WireMessage<protocol_vstaging::ValidationProtocol>,
|
||||
metrics: &Metrics,
|
||||
notification_sinks: &Arc<Mutex<HashMap<(PeerSet, PeerId), Box<dyn MessageSink>>>>,
|
||||
) {
|
||||
gum::trace!(target: LOG_TARGET, ?peers, ?message, "Sending validation vstaging message to peers",);
|
||||
|
||||
send_message(
|
||||
net,
|
||||
peers,
|
||||
PeerSet::Validation,
|
||||
ValidationVersion::VStaging.into(),
|
||||
peerset_protocol_names,
|
||||
message,
|
||||
metrics,
|
||||
notification_sinks,
|
||||
);
|
||||
}
|
||||
|
||||
// Helper function to send a validation v2 message to a list of peers.
|
||||
// Messages are always sent via the main protocol, even legacy protocol messages.
|
||||
pub(crate) fn send_validation_message_v2(
|
||||
net: &mut impl Network,
|
||||
peers: Vec<PeerId>,
|
||||
protocol_names: &PeerSetProtocolNames,
|
||||
message: WireMessage<protocol_v2::ValidationProtocol>,
|
||||
metrics: &Metrics,
|
||||
notification_sinks: &Arc<Mutex<HashMap<(PeerSet, PeerId), Box<dyn MessageSink>>>>,
|
||||
) {
|
||||
send_message(
|
||||
net,
|
||||
peers,
|
||||
PeerSet::Validation,
|
||||
ValidationVersion::V2.into(),
|
||||
protocol_names,
|
||||
message,
|
||||
metrics,
|
||||
notification_sinks,
|
||||
);
|
||||
}
|
||||
|
||||
// Helper function to send a collation v1 message to a list of peers.
|
||||
// Messages are always sent via the main protocol, even legacy protocol messages.
|
||||
pub(crate) fn send_collation_message_v1(
|
||||
net: &mut impl Network,
|
||||
peers: Vec<PeerId>,
|
||||
peerset_protocol_names: &PeerSetProtocolNames,
|
||||
message: WireMessage<protocol_v1::CollationProtocol>,
|
||||
metrics: &Metrics,
|
||||
notification_sinks: &Arc<Mutex<HashMap<(PeerSet, PeerId), Box<dyn MessageSink>>>>,
|
||||
) {
|
||||
send_message(
|
||||
net,
|
||||
peers,
|
||||
PeerSet::Collation,
|
||||
CollationVersion::V1.into(),
|
||||
peerset_protocol_names,
|
||||
message,
|
||||
metrics,
|
||||
notification_sinks,
|
||||
);
|
||||
}
|
||||
|
||||
// Helper function to send a collation v2 message to a list of peers.
|
||||
// Messages are always sent via the main protocol, even legacy protocol messages.
|
||||
pub(crate) fn send_collation_message_v2(
|
||||
net: &mut impl Network,
|
||||
peers: Vec<PeerId>,
|
||||
peerset_protocol_names: &PeerSetProtocolNames,
|
||||
message: WireMessage<protocol_v2::CollationProtocol>,
|
||||
metrics: &Metrics,
|
||||
notification_sinks: &Arc<Mutex<HashMap<(PeerSet, PeerId), Box<dyn MessageSink>>>>,
|
||||
) {
|
||||
send_message(
|
||||
net,
|
||||
peers,
|
||||
PeerSet::Collation,
|
||||
CollationVersion::V2.into(),
|
||||
peerset_protocol_names,
|
||||
message,
|
||||
metrics,
|
||||
notification_sinks,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -151,19 +142,19 @@ pub(crate) fn send_collation_message_v2(
|
||||
/// messages that are compatible with the passed peer set, as that is currently not enforced by
|
||||
/// this function. These are messages of type `WireMessage` parameterized on the matching type.
|
||||
fn send_message<M>(
|
||||
net: &mut impl Network,
|
||||
mut peers: Vec<PeerId>,
|
||||
peer_set: PeerSet,
|
||||
version: ProtocolVersion,
|
||||
protocol_names: &PeerSetProtocolNames,
|
||||
message: M,
|
||||
metrics: &super::Metrics,
|
||||
network_notification_sinks: &Arc<Mutex<HashMap<(PeerSet, PeerId), Box<dyn MessageSink>>>>,
|
||||
) where
|
||||
M: Encode + Clone,
|
||||
{
|
||||
if peers.is_empty() {
|
||||
return
|
||||
}
|
||||
|
||||
let message = {
|
||||
let encoded = message.encode();
|
||||
metrics.on_notification_sent(peer_set, version, encoded.len(), peers.len());
|
||||
@@ -171,13 +162,13 @@ fn send_message<M>(
|
||||
encoded
|
||||
};
|
||||
|
||||
// optimization: generate the protocol name once.
|
||||
let protocol_name = protocol_names.get_name(peer_set, version);
|
||||
let notification_sinks = network_notification_sinks.lock();
|
||||
|
||||
gum::trace!(
|
||||
target: LOG_TARGET,
|
||||
?peers,
|
||||
?peer_set,
|
||||
?version,
|
||||
?protocol_name,
|
||||
?message,
|
||||
"Sending message to peers",
|
||||
);
|
||||
@@ -185,29 +176,26 @@ fn send_message<M>(
|
||||
// optimization: avoid cloning the message for the last peer in the
|
||||
// list. The message payload can be quite large. If the underlying
|
||||
// network used `Bytes` this would not be necessary.
|
||||
//
|
||||
// peer may have gotten disconnect by the time `send_message()` is called
|
||||
// at which point the the sink is not available.
|
||||
let last_peer = peers.pop();
|
||||
|
||||
// We always send messages on the "main" name even when a negotiated
|
||||
// fallback is used. The libp2p implementation handles the fallback
|
||||
// under the hood.
|
||||
let protocol_name = protocol_names.get_main_name(peer_set);
|
||||
peers.into_iter().for_each(|peer| {
|
||||
net.write_notification(peer, protocol_name.clone(), message.clone());
|
||||
if let Some(sink) = notification_sinks.get(&(peer_set, peer)) {
|
||||
sink.send_sync_notification(message.clone());
|
||||
}
|
||||
});
|
||||
|
||||
if let Some(peer) = last_peer {
|
||||
net.write_notification(peer, protocol_name, message);
|
||||
if let Some(sink) = notification_sinks.get(&(peer_set, peer)) {
|
||||
sink.send_sync_notification(message.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An abstraction over networking for the purposes of this subsystem.
|
||||
#[async_trait]
|
||||
pub trait Network: Clone + Send + 'static {
|
||||
/// Get a stream of all events occurring on the network. This may include events unrelated
|
||||
/// to the Polkadot protocol - the user of this function should filter only for events related
|
||||
/// to the [`VALIDATION_PROTOCOL_NAME`](VALIDATION_PROTOCOL_NAME)
|
||||
/// or [`COLLATION_PROTOCOL_NAME`](COLLATION_PROTOCOL_NAME)
|
||||
fn event_stream(&mut self) -> BoxStream<'static, NetworkEvent>;
|
||||
|
||||
/// Ask the network to keep a substream open with these nodes and not disconnect from them
|
||||
/// until removed from the protocol's peer set.
|
||||
/// Note that `out_peers` setting has no effect on this.
|
||||
@@ -239,16 +227,12 @@ pub trait Network: Clone + Send + 'static {
|
||||
/// Disconnect a given peer from the protocol specified without harming reputation.
|
||||
fn disconnect_peer(&self, who: PeerId, protocol: ProtocolName);
|
||||
|
||||
/// Write a notification to a peer on the given protocol.
|
||||
fn write_notification(&self, who: PeerId, protocol: ProtocolName, message: Vec<u8>);
|
||||
/// Get peer role.
|
||||
fn peer_role(&self, who: PeerId, handshake: Vec<u8>) -> Option<sc_network::ObservedRole>;
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Network for Arc<NetworkService<Block, Hash>> {
|
||||
fn event_stream(&mut self) -> BoxStream<'static, NetworkEvent> {
|
||||
NetworkService::event_stream(self, "polkadot-network-bridge").boxed()
|
||||
}
|
||||
|
||||
async fn set_reserved_peers(
|
||||
&mut self,
|
||||
protocol: ProtocolName,
|
||||
@@ -273,10 +257,6 @@ impl Network for Arc<NetworkService<Block, Hash>> {
|
||||
NetworkService::disconnect_peer(&**self, who, protocol);
|
||||
}
|
||||
|
||||
fn write_notification(&self, who: PeerId, protocol: ProtocolName, message: Vec<u8>) {
|
||||
NetworkService::write_notification(&**self, who, protocol, message);
|
||||
}
|
||||
|
||||
async fn start_request<AD: AuthorityDiscovery>(
|
||||
&self,
|
||||
authority_discovery: &mut AD,
|
||||
@@ -348,6 +328,10 @@ impl Network for Arc<NetworkService<Block, Hash>> {
|
||||
if_disconnected,
|
||||
);
|
||||
}
|
||||
|
||||
fn peer_role(&self, who: PeerId, handshake: Vec<u8>) -> Option<sc_network::ObservedRole> {
|
||||
NetworkService::peer_role(self, who, handshake)
|
||||
}
|
||||
}
|
||||
|
||||
/// We assume one `peer_id` per `authority_id`.
|
||||
|
||||
Reference in New Issue
Block a user