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:
Aaro Altonen
2023-11-28 20:18:52 +02:00
committed by GitHub
parent ec3a61ed86
commit e71c484d5b
102 changed files with 5694 additions and 2603 deletions
+67 -23
View File
@@ -23,10 +23,11 @@
pub use crate::{
discovery::DEFAULT_KADEMLIA_REPLICATION_FACTOR,
protocol::NotificationsSink,
protocol::{notification_service, NotificationsSink, ProtocolHandlePair},
request_responses::{
IncomingRequest, OutgoingResponse, ProtocolConfig as RequestResponseConfig,
},
service::traits::NotificationService,
types::ProtocolName,
};
@@ -47,7 +48,6 @@ pub use sc_network_common::{
ExHashT,
};
use sc_utils::mpsc::TracingUnboundedSender;
use sp_runtime::traits::Block as BlockT;
use std::{
@@ -454,14 +454,14 @@ impl Default for SetConfig {
///
/// > **Note**: As new fields might be added in the future, please consider using the `new` method
/// > and modifiers instead of creating this struct manually.
#[derive(Clone, Debug)]
#[derive(Debug)]
pub struct NonDefaultSetConfig {
/// Name of the notifications protocols of this set. A substream on this set will be
/// considered established once this protocol is open.
///
/// > **Note**: This field isn't present for the default set, as this is handled internally
/// > by the networking code.
pub notifications_protocol: ProtocolName,
protocol_name: ProtocolName,
/// If the remote reports that it doesn't support the protocol indicated in the
/// `notifications_protocol` field, then each of these fallback names will be tried one by
@@ -469,37 +469,84 @@ pub struct NonDefaultSetConfig {
///
/// If a fallback is used, it will be reported in
/// `sc_network::protocol::event::Event::NotificationStreamOpened::negotiated_fallback`
pub fallback_names: Vec<ProtocolName>,
fallback_names: Vec<ProtocolName>,
/// Handshake of the protocol
///
/// NOTE: Currently custom handshakes are not fully supported. See issue #5685 for more
/// details. This field is temporarily used to allow moving the hardcoded block announcement
/// protocol out of `protocol.rs`.
pub handshake: Option<NotificationHandshake>,
handshake: Option<NotificationHandshake>,
/// Maximum allowed size of single notifications.
pub max_notification_size: u64,
max_notification_size: u64,
/// Base configuration.
pub set_config: SetConfig,
set_config: SetConfig,
/// Notification handle.
///
/// Notification handle is created during `NonDefaultSetConfig` creation and its other half,
/// `Box<dyn NotificationService>` is given to the protocol created the config and
/// `ProtocolHandle` is given to `Notifications` when it initializes itself. This handle allows
/// `Notifications ` to communicate with the protocol directly without relaying events through
/// `sc-network.`
protocol_handle_pair: ProtocolHandlePair,
}
impl NonDefaultSetConfig {
/// Creates a new [`NonDefaultSetConfig`]. Zero slots and accepts only reserved nodes.
pub fn new(notifications_protocol: ProtocolName, max_notification_size: u64) -> Self {
Self {
notifications_protocol,
max_notification_size,
fallback_names: Vec::new(),
handshake: None,
set_config: SetConfig {
in_peers: 0,
out_peers: 0,
reserved_nodes: Vec::new(),
non_reserved_mode: NonReservedPeerMode::Deny,
/// Also returns an object which allows the protocol to communicate with `Notifications`.
pub fn new(
protocol_name: ProtocolName,
fallback_names: Vec<ProtocolName>,
max_notification_size: u64,
handshake: Option<NotificationHandshake>,
set_config: SetConfig,
) -> (Self, Box<dyn NotificationService>) {
let (protocol_handle_pair, notification_service) =
notification_service(protocol_name.clone());
(
Self {
protocol_name,
max_notification_size,
fallback_names,
handshake,
set_config,
protocol_handle_pair,
},
}
notification_service,
)
}
/// Get reference to protocol name.
pub fn protocol_name(&self) -> &ProtocolName {
&self.protocol_name
}
/// Get reference to fallback protocol names.
pub fn fallback_names(&self) -> impl Iterator<Item = &ProtocolName> {
self.fallback_names.iter()
}
/// Get reference to handshake.
pub fn handshake(&self) -> &Option<NotificationHandshake> {
&self.handshake
}
/// Get maximum notification size.
pub fn max_notification_size(&self) -> u64 {
self.max_notification_size
}
/// Get reference to `SetConfig`.
pub fn set_config(&self) -> &SetConfig {
&self.set_config
}
/// Take `ProtocolHandlePair` from `NonDefaultSetConfig`
pub fn take_protocol_handle(self) -> ProtocolHandlePair {
self.protocol_handle_pair
}
/// Modifies the configuration to allow non-reserved nodes.
@@ -703,9 +750,6 @@ pub struct Params<Block: BlockT> {
/// Block announce protocol configuration
pub block_announce_config: NonDefaultSetConfig,
/// TX channel for direct communication with `SyncingEngine` and `Protocol`.
pub tx: TracingUnboundedSender<crate::event::SyncEvent<Block>>,
}
/// Full network configuration.