diff --git a/substrate/cli/src/cli.yml b/substrate/cli/src/cli.yml index e6b8e395d2a36..437d100d245bd 100644 --- a/substrate/cli/src/cli.yml +++ b/substrate/cli/src/cli.yml @@ -41,10 +41,16 @@ args: long: dev help: Run in development mode; implies --chain=dev --validator --key Alice takes_value: false + - listen-addr: + long: listen-addr + value_name: LISTEN_ADDR + help: Listen on this multiaddress + takes_value: true + multiple: true - port: long: port value_name: PORT - help: Specify p2p protocol TCP port + help: Specify p2p protocol TCP port. Only used if --listen-addr is not specified. takes_value: true - rpc-external: long: rpc-external diff --git a/substrate/cli/src/lib.rs b/substrate/cli/src/lib.rs index f2dee51e454a9..7e5b756af662e 100644 --- a/substrate/cli/src/lib.rs +++ b/substrate/cli/src/lib.rs @@ -287,15 +287,25 @@ where config.network.non_reserved_mode = NonReservedPeerMode::Deny; } - let port = match matches.value_of("port") { - Some(port) => port.parse().map_err(|_| "Invalid p2p port value specified.")?, - None => 30333, - }; + config.network.listen_addresses = Vec::new(); + for addr in matches.values_of("listen-addr").unwrap_or_default() { + let addr = addr.parse().map_err(|_| "Invalid listen multiaddress")?; + config.network.listen_addresses.push(addr); + } + if config.network.listen_addresses.is_empty() { + let port = match matches.value_of("port") { + Some(port) => port.parse().map_err(|_| "Invalid p2p port value specified.")?, + None => 30333, + }; + config.network.listen_addresses = vec![ + iter::once(AddrComponent::IP4(Ipv4Addr::new(0, 0, 0, 0))) + .chain(iter::once(AddrComponent::TCP(port))) + .collect() + ]; + } + + config.network.public_addresses = Vec::new(); - config.network.listen_address = iter::once(AddrComponent::IP4(Ipv4Addr::new(0, 0, 0, 0))) - .chain(iter::once(AddrComponent::TCP(port))) - .collect(); - config.network.public_address = None; config.network.client_version = config.client_id(); config.network.use_secret = match matches.value_of("node-key").map(|s| s.parse()) { Some(Ok(secret)) => Some(secret), diff --git a/substrate/network-libp2p/src/service.rs b/substrate/network-libp2p/src/service.rs index 61aa0495154cc..220e094b127c4 100644 --- a/substrate/network-libp2p/src/service.rs +++ b/substrate/network-libp2p/src/service.rs @@ -109,9 +109,10 @@ impl NetworkService { let local_peer_id = network_state.local_public_key().clone() .into_peer_id(); - let mut listen_addr = config.listen_address.clone(); - listen_addr.append(AddrComponent::P2P(local_peer_id.clone().into_bytes())); - info!(target: "sub-libp2p", "Local node address is: {}", listen_addr); + for mut addr in config.listen_addresses.iter().cloned() { + addr.append(AddrComponent::P2P(local_peer_id.clone().into_bytes())); + info!(target: "sub-libp2p", "Local node address is: {}", addr); + } let kad_system = KadSystem::without_init(KadSystemConfig { parallelism: 3, @@ -129,10 +130,7 @@ impl NetworkService { let (close_tx, close_rx) = oneshot::channel(); let (timeouts_register_tx, timeouts_register_rx) = mpsc::unbounded(); - let mut listened_addrs = Vec::new(); - if let Some(ref addr) = config.public_address { - listened_addrs.push(addr.clone()); - } + let listened_addrs = config.public_addresses.clone(); let shared = Arc::new(Shared { network_state, @@ -445,17 +443,18 @@ fn init_thread( ) }; - // Listen on multiaddress. - match swarm_controller.listen_on(shared.config.listen_address.clone()) { - Ok(new_addr) => { - debug!(target: "sub-libp2p", "Libp2p listening on {}", new_addr); - *shared.original_listened_addr.write() = Some(new_addr.clone()); - }, - Err(_) => { - warn!(target: "sub-libp2p", "Can't listen on {}, protocol not supported", - shared.config.listen_address); - return Err(ErrorKind::BadProtocol.into()) - }, + // Listen on multiaddresses. + for addr in &shared.config.listen_addresses { + match swarm_controller.listen_on(addr.clone()) { + Ok(new_addr) => { + debug!(target: "sub-libp2p", "Libp2p listening on {}", new_addr); + *shared.original_listened_addr.write() = Some(new_addr.clone()); + }, + Err(_) => { + warn!(target: "sub-libp2p", "Can't listen on {}, protocol not supported", addr); + return Err(ErrorKind::BadProtocol.into()) + }, + } } // Explicitely connect to _all_ the boostrap nodes as a temporary measure. diff --git a/substrate/network-libp2p/src/traits.rs b/substrate/network-libp2p/src/traits.rs index 3f625e4ae23d4..de18f083c559d 100644 --- a/substrate/network-libp2p/src/traits.rs +++ b/substrate/network-libp2p/src/traits.rs @@ -104,10 +104,10 @@ pub struct NetworkConfiguration { pub config_path: Option, /// Directory path to store network-specific configuration. None means nothing will be saved pub net_config_path: Option, - /// IP address to listen for incoming connections. Listen to all connections by default - pub listen_address: Multiaddr, - /// IP address to advertise. Detected automatically if none. - pub public_address: Option, + /// Multiaddresses to listen for incoming connections. + pub listen_addresses: Vec, + /// Multiaddresses to advertise. Detected automatically if empty. + pub public_addresses: Vec, /// List of initial node addresses pub boot_nodes: Vec, /// Use provided node key instead of default @@ -136,10 +136,12 @@ impl NetworkConfiguration { NetworkConfiguration { config_path: None, net_config_path: None, - listen_address: iter::once(AddrComponent::IP4(Ipv4Addr::new(0, 0, 0, 0))) - .chain(iter::once(AddrComponent::TCP(30333))) - .collect(), - public_address: None, + listen_addresses: vec![ + iter::once(AddrComponent::IP4(Ipv4Addr::new(0, 0, 0, 0))) + .chain(iter::once(AddrComponent::TCP(30333))) + .collect() + ], + public_addresses: Vec::new(), boot_nodes: Vec::new(), use_secret: None, min_peers: 25, @@ -153,9 +155,11 @@ impl NetworkConfiguration { /// Create new default configuration for localhost-only connection with random port (useful for testing) pub fn new_local() -> NetworkConfiguration { let mut config = NetworkConfiguration::new(); - config.listen_address = iter::once(AddrComponent::IP4(Ipv4Addr::new(127, 0, 0, 1))) - .chain(iter::once(AddrComponent::TCP(0))) - .collect(); + config.listen_addresses = vec![ + iter::once(AddrComponent::IP4(Ipv4Addr::new(127, 0, 0, 1))) + .chain(iter::once(AddrComponent::TCP(0))) + .collect() + ]; config } }