@@ -25,7 +25,7 @@ use crate::{
2525 start_rpc_servers, BuildGenesisBlock , GenesisBlockBuilder , RpcHandlers , SpawnTaskHandle ,
2626 TaskManager , TransactionPoolAdapter ,
2727} ;
28- use futures:: { select, FutureExt , StreamExt } ;
28+ use futures:: { channel :: oneshot , select, FutureExt , StreamExt } ;
2929use jsonrpsee:: RpcModule ;
3030use log:: info;
3131use prometheus_endpoint:: Registry ;
@@ -845,6 +845,7 @@ pub fn build_network<Block, Net, TxPool, IQ, Client>(
845845 Arc < dyn sc_network:: service:: traits:: NetworkService > ,
846846 TracingUnboundedSender < sc_rpc:: system:: Request < Block > > ,
847847 sc_network_transactions:: TransactionsHandlerController < <Block as BlockT >:: Hash > ,
848+ NetworkStarter ,
848849 Arc < SyncingService < Block > > ,
849850 ) ,
850851 Error ,
@@ -1006,6 +1007,7 @@ pub fn build_network_advanced<Block, Net, TxPool, IQ, Client>(
10061007 Arc < dyn sc_network:: service:: traits:: NetworkService > ,
10071008 TracingUnboundedSender < sc_rpc:: system:: Request < Block > > ,
10081009 sc_network_transactions:: TransactionsHandlerController < <Block as BlockT >:: Hash > ,
1010+ NetworkStarter ,
10091011 Arc < SyncingService < Block > > ,
10101012 ) ,
10111013 Error ,
@@ -1146,16 +1148,49 @@ where
11461148 announce_block,
11471149 ) ;
11481150
1151+ // TODO: Normally, one is supposed to pass a list of notifications protocols supported by the
1152+ // node through the `NetworkConfiguration` struct. But because this function doesn't know in
1153+ // advance which components, such as GrandPa or Polkadot, will be plugged on top of the
1154+ // service, it is unfortunately not possible to do so without some deep refactoring. To
1155+ // bypass this problem, the `NetworkService` provides a `register_notifications_protocol`
1156+ // method that can be called even after the network has been initialized. However, we want to
1157+ // avoid the situation where `register_notifications_protocol` is called *after* the network
1158+ // actually connects to other peers. For this reason, we delay the process of the network
1159+ // future until the user calls `NetworkStarter::start_network`.
1160+ //
1161+ // This entire hack should eventually be removed in favour of passing the list of protocols
1162+ // through the configuration.
1163+ //
1164+ // See also https://github.com/paritytech/substrate/issues/6827
1165+ let ( network_start_tx, network_start_rx) = oneshot:: channel ( ) ;
1166+
11491167 // The network worker is responsible for gathering all network messages and processing
11501168 // them. This is quite a heavy task, and at the time of the writing of this comment it
11511169 // frequently happens that this future takes several seconds or in some situations
11521170 // even more than a minute until it has processed its entire queue. This is clearly an
11531171 // issue, and ideally we would like to fix the network future to take as little time as
11541172 // possible, but we also take the extra harm-prevention measure to execute the networking
11551173 // future using `spawn_blocking`.
1156- spawn_handle. spawn_blocking ( "network-worker" , Some ( "networking" ) , future) ;
1174+ spawn_handle. spawn_blocking ( "network-worker" , Some ( "networking" ) , async move {
1175+ if network_start_rx. await . is_err ( ) {
1176+ log:: warn!(
1177+ "The NetworkStart returned as part of `build_network` has been silently dropped"
1178+ ) ;
1179+ // This `return` might seem unnecessary, but we don't want to make it look like
1180+ // everything is working as normal even though the user is clearly misusing the API.
1181+ return
1182+ }
1183+
1184+ future. await
1185+ } ) ;
11571186
1158- Ok ( ( network, system_rpc_tx, tx_handler_controller, sync_service. clone ( ) ) )
1187+ Ok ( (
1188+ network,
1189+ system_rpc_tx,
1190+ tx_handler_controller,
1191+ NetworkStarter ( network_start_tx) ,
1192+ sync_service. clone ( ) ,
1193+ ) )
11591194}
11601195
11611196/// Configuration for [`build_default_syncing_engine`].
@@ -1384,3 +1419,21 @@ where
13841419 warp_sync_protocol_name,
13851420 ) ?) )
13861421}
1422+
1423+ /// Object used to start the network.
1424+ #[ must_use]
1425+ pub struct NetworkStarter ( oneshot:: Sender < ( ) > ) ;
1426+
1427+ impl NetworkStarter {
1428+ /// Create a new NetworkStarter
1429+ pub fn new ( sender : oneshot:: Sender < ( ) > ) -> Self {
1430+ NetworkStarter ( sender)
1431+ }
1432+
1433+ /// Start the network. Call this after all sub-components have been initialized.
1434+ ///
1435+ /// > **Note**: If you don't call this function, the networking will not work.
1436+ pub fn start_network ( self ) {
1437+ let _ = self . 0 . send ( ( ) ) ;
1438+ }
1439+ }
0 commit comments