diff --git a/substrate/client/cli/src/params/network_params.rs b/substrate/client/cli/src/params/network_params.rs index 130325a7f9..0b53616b9e 100644 --- a/substrate/client/cli/src/params/network_params.rs +++ b/substrate/client/cli/src/params/network_params.rs @@ -175,6 +175,7 @@ impl NetworkParams { max_parallel_downloads: self.max_parallel_downloads, allow_non_globals_in_dht, kademlia_disjoint_query_paths: self.kademlia_disjoint_query_paths, + yamux_window_size: None, } } } diff --git a/substrate/client/network/src/config.rs b/substrate/client/network/src/config.rs index aee07e7464..6ba31272da 100644 --- a/substrate/client/network/src/config.rs +++ b/substrate/client/network/src/config.rs @@ -401,6 +401,27 @@ pub struct NetworkConfiguration { /// Require iterative Kademlia DHT queries to use disjoint paths for increased resiliency in the /// presence of potentially adversarial nodes. pub kademlia_disjoint_query_paths: bool, + + /// Size of Yamux window receive window of all substreams. `None` for the default (256kiB). + /// Any value inferior to 256kiB is invalid. + /// + /// # Context + /// + /// By design, notifications substreams on top of Yamux connections only allow up to `N` bytes + /// to be transferred at a time, where `N` is the Yamux receive window size configurable here. + /// This means, in practice, that every `N` bytes must be acknowledged by the receiver before + /// the sender can send more data. The maximum bandwidth of each notifications substream is + /// therefore `N / round_trip_time`. + /// + /// It is recommended to leave this to `None`, and use a request-response protocol instead if + /// a large amount of data must be transferred. The reason why the value is configurable is + /// that some Substrate users mis-use notification protocols to send large amounts of data. + /// As such, this option isn't designed to stay and will likely get removed in the future. + /// + /// Note that configuring a value here isn't a modification of the Yamux protocol, but rather + /// a modification of the way the implementation works. Different nodes with different + /// configured values remain compatible with each other. + pub yamux_window_size: Option, } impl NetworkConfiguration { @@ -430,6 +451,7 @@ impl NetworkConfiguration { max_parallel_downloads: 5, allow_non_globals_in_dht: false, kademlia_disjoint_query_paths: false, + yamux_window_size: None, } } diff --git a/substrate/client/network/src/service.rs b/substrate/client/network/src/service.rs index 00ca0fb0bb..fec444846a 100644 --- a/substrate/client/network/src/service.rs +++ b/substrate/client/network/src/service.rs @@ -311,7 +311,13 @@ impl NetworkWorker { TransportConfig::Normal { wasm_external_transport, .. } => (false, wasm_external_transport) }; - transport::build_transport(local_identity, config_mem, config_wasm) + + transport::build_transport( + local_identity, + config_mem, + config_wasm, + params.network_config.yamux_window_size + ) }; let mut builder = SwarmBuilder::new(transport, behaviour, local_peer_id.clone()) .connection_limits(ConnectionLimits::default() diff --git a/substrate/client/network/src/transport.rs b/substrate/client/network/src/transport.rs index 4d9d4fbde2..6896e59856 100644 --- a/substrate/client/network/src/transport.rs +++ b/substrate/client/network/src/transport.rs @@ -35,12 +35,16 @@ pub use self::bandwidth::BandwidthSinks; /// If `memory_only` is true, then only communication within the same process are allowed. Only /// addresses with the format `/memory/...` are allowed. /// +/// `yamux_window_size` consists in the size of the Yamux windows. `None` to leave the default +/// (256kiB). +/// /// Returns a `BandwidthSinks` object that allows querying the average bandwidth produced by all /// the connections spawned with this transport. pub fn build_transport( keypair: identity::Keypair, memory_only: bool, wasm_external_transport: Option, + yamux_window_size: Option, ) -> (Boxed<(PeerId, StreamMuxerBox)>, Arc) { // Build the base layer of the transport. let transport = if let Some(t) = wasm_external_transport { @@ -98,6 +102,10 @@ pub fn build_transport( // buffered data has been consumed. yamux_config.set_window_update_mode(libp2p::yamux::WindowUpdateMode::on_read()); + if let Some(yamux_window_size) = yamux_window_size { + yamux_config.set_receive_window_size(yamux_window_size); + } + core::upgrade::SelectUpgrade::new(yamux_config, mplex_config) };