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
+40 -46
View File
@@ -44,16 +44,16 @@ async fn sync_peers_works() {
sp_tracing::try_init_simple();
let mut net = TestNet::new(3);
futures::future::poll_fn::<(), _>(|cx| {
net.poll(cx);
for peer in 0..3 {
if net.peer(peer).num_peers() != 2 {
return Poll::Pending
}
}
Poll::Ready(())
})
.await;
while net.peer(0).num_peers().await != 2 &&
net.peer(1).num_peers().await != 2 &&
net.peer(2).num_peers().await != 2
{
futures::future::poll_fn::<(), _>(|cx| {
net.poll(cx);
Poll::Ready(())
})
.await;
}
}
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
@@ -412,15 +412,13 @@ async fn can_sync_small_non_best_forks() {
assert!(net.peer(1).client().header(small_hash).unwrap().is_none());
// poll until the two nodes connect, otherwise announcing the block will not work
futures::future::poll_fn::<(), _>(|cx| {
net.poll(cx);
if net.peer(0).num_peers() == 0 || net.peer(1).num_peers() == 0 {
Poll::Pending
} else {
while net.peer(0).num_peers().await == 0 || net.peer(1).num_peers().await == 0 {
futures::future::poll_fn::<(), _>(|cx| {
net.poll(cx);
Poll::Ready(())
}
})
.await;
})
.await;
}
// synchronization: 0 synced to longer chain and 1 didn't sync to small chain.
@@ -465,6 +463,7 @@ async fn can_sync_forks_ahead_of_the_best_chain() {
net.peer(1).push_blocks(1, false);
net.run_until_connected().await;
// Peer 0 is on 2-block fork which is announced with is_best=false
let fork_hash = net
.peer(0)
@@ -516,15 +515,13 @@ async fn can_sync_explicit_forks() {
assert!(net.peer(1).client().header(small_hash).unwrap().is_none());
// poll until the two nodes connect, otherwise announcing the block will not work
futures::future::poll_fn::<(), _>(|cx| {
net.poll(cx);
if net.peer(0).num_peers() == 0 || net.peer(1).num_peers() == 0 {
Poll::Pending
} else {
while net.peer(0).num_peers().await == 0 || net.peer(1).num_peers().await == 0 {
futures::future::poll_fn::<(), _>(|cx| {
net.poll(cx);
Poll::Ready(())
}
})
.await;
})
.await;
}
// synchronization: 0 synced to longer chain and 1 didn't sync to small chain.
@@ -613,15 +610,14 @@ async fn full_sync_requires_block_body() {
net.peer(0).push_headers(1);
// Wait for nodes to connect
futures::future::poll_fn::<(), _>(|cx| {
net.poll(cx);
if net.peer(0).num_peers() == 0 || net.peer(1).num_peers() == 0 {
Poll::Pending
} else {
while net.peer(0).num_peers().await == 0 || net.peer(1).num_peers().await == 0 {
futures::future::poll_fn::<(), _>(|cx| {
net.poll(cx);
Poll::Ready(())
}
})
.await;
})
.await;
}
net.run_until_idle().await;
assert_eq!(net.peer(1).client.info().best_number, 0);
}
@@ -917,18 +913,16 @@ async fn block_announce_data_is_propagated() {
});
// Wait until peer 1 is connected to both nodes.
futures::future::poll_fn::<(), _>(|cx| {
net.poll(cx);
if net.peer(1).num_peers() == 2 &&
net.peer(0).num_peers() == 1 &&
net.peer(2).num_peers() == 1
{
while net.peer(1).num_peers().await != 2 ||
net.peer(0).num_peers().await != 1 ||
net.peer(2).num_peers().await != 1
{
futures::future::poll_fn::<(), _>(|cx| {
net.poll(cx);
Poll::Ready(())
} else {
Poll::Pending
}
})
.await;
})
.await;
}
let block_hash = net
.peer(0)
@@ -1010,7 +1004,7 @@ async fn multiple_requests_are_accepted_as_long_as_they_are_not_fulfilled() {
tokio::time::sleep(tokio::time::Duration::from_secs(10)).await;
net.peer(0).push_blocks(1, false);
net.run_until_sync().await;
assert_eq!(1, net.peer(0).num_peers());
assert_eq!(1, net.peer(0).num_peers().await);
}
let hashof10 = hashes[9];