Use the default port for configured listen addresses with no port (#2043)

* Allow use listen address in config without port

* update comments

* remove not used alias

* use Network::default_port

* Move tests and use toml instead json

* change error message

* Make match more readable

Co-authored-by: teor <teor@riseup.net>
This commit is contained in:
Kirill Fomichev 2021-04-22 02:14:29 +03:00 committed by GitHub
parent 96b3c94dbc
commit afac2c2846
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 101 additions and 10 deletions

1
Cargo.lock generated
View File

@ -4382,6 +4382,7 @@ dependencies = [
"thiserror",
"tokio 0.3.6",
"tokio-util 0.5.1",
"toml",
"tower",
"tracing",
"tracing-error",

View File

@ -38,5 +38,6 @@ zebra-chain = { path = "../zebra-chain" }
[dev-dependencies]
proptest = "0.10"
proptest-derive = "0.3"
toml = "0.5"
zebra-test = { path = "../zebra-test/" }

View File

@ -1,4 +1,11 @@
use std::{collections::HashSet, net::SocketAddr, string::String, time::Duration};
use std::{
collections::HashSet,
net::{IpAddr, SocketAddr},
string::String,
time::Duration,
};
use serde::{de, Deserialize, Deserializer};
use zebra_chain::parameters::Network;
@ -9,11 +16,15 @@ use crate::BoxError;
const MAX_SINGLE_PEER_RETRIES: usize = 2;
/// Configuration for networking code.
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(deny_unknown_fields, default)]
#[derive(Clone, Debug, Serialize)]
pub struct Config {
/// The address on which this node should listen for connections.
///
/// Can be `address:port` or just `address`. If there is no configured
/// port, Zebra will use the default port for the configured `network`.
/// `address` can be an IP address or a DNS name. DNS names are
/// only resolved once, when Zebra starts up.
///
/// Zebra will also advertise this address to other nodes. Advertising a
/// different external IP address is currently not supported, see #1890
/// for details.
@ -44,7 +55,6 @@ pub struct Config {
/// - regularly, every time `crawl_new_peer_interval` elapses, and
/// - if the peer set is busy, and there aren't any peer addresses for the
/// next connection attempt.
#[serde(alias = "new_peer_interval")]
pub crawl_new_peer_interval: Duration,
}
@ -176,3 +186,61 @@ impl Default for Config {
}
}
}
impl<'de> Deserialize<'de> for Config {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
#[derive(Deserialize)]
#[serde(deny_unknown_fields, default)]
struct DConfig {
listen_addr: String,
network: Network,
initial_mainnet_peers: HashSet<String>,
initial_testnet_peers: HashSet<String>,
peerset_initial_target_size: usize,
#[serde(alias = "new_peer_interval")]
crawl_new_peer_interval: Duration,
}
impl Default for DConfig {
fn default() -> Self {
let config = Config::default();
Self {
listen_addr: config.listen_addr.to_string(),
network: config.network,
initial_mainnet_peers: config.initial_mainnet_peers,
initial_testnet_peers: config.initial_testnet_peers,
peerset_initial_target_size: config.peerset_initial_target_size,
crawl_new_peer_interval: config.crawl_new_peer_interval,
}
}
}
let config = DConfig::deserialize(deserializer)?;
// TODO: perform listener DNS lookups asynchronously with a timeout (#1631)
let listen_addr = match config.listen_addr.parse::<SocketAddr>() {
Ok(socket) => Ok(socket),
Err(_) => match config.listen_addr.parse::<IpAddr>() {
Ok(ip) => Ok(SocketAddr::new(ip, config.network.default_port())),
Err(err) => Err(de::Error::custom(format!(
"{}; Hint: addresses can be a IPv4, IPv6 (with brackets), or a DNS name, the port is optional",
err
))),
},
}?;
Ok(Config {
listen_addr,
network: config.network,
initial_mainnet_peers: config.initial_mainnet_peers,
initial_testnet_peers: config.initial_testnet_peers,
peerset_initial_target_size: config.peerset_initial_target_size,
crawl_new_peer_interval: config.crawl_new_peer_interval,
})
}
}
#[cfg(test)]
mod tests;

View File

@ -0,0 +1,22 @@
use super::Config;
#[test]
fn parse_config_listen_addr() {
let fixtures = vec![
("listen_addr = '0.0.0.0'", "0.0.0.0:8233"),
("listen_addr = '0.0.0.0:9999'", "0.0.0.0:9999"),
(
"listen_addr = '0.0.0.0'\nnetwork = 'Testnet'",
"0.0.0.0:18233",
),
(
"listen_addr = '0.0.0.0:8233'\nnetwork = 'Testnet'",
"0.0.0.0:8233",
),
];
for (config, value) in fixtures {
let config: Config = toml::from_str(config).unwrap();
assert_eq!(config.listen_addr.to_string(), value);
}
}

View File

@ -121,13 +121,12 @@ where
// 1. Incoming peer connections, via a listener.
// Warn if we're configured using the wrong network port.
// TODO: use the right port if the port is unspecified
// split the address and port configs?
let (wrong_net, wrong_net_port) = match config.network {
Network::Mainnet => (Network::Testnet, 18233),
Network::Testnet => (Network::Mainnet, 8233),
use Network::*;
let wrong_net = match config.network {
Mainnet => Testnet,
Testnet => Mainnet,
};
if config.listen_addr.port() == wrong_net_port {
if config.listen_addr.port() == wrong_net.default_port() {
warn!(
"We are configured with port {} for {:?}, but that port is the default port for {:?}",
config.listen_addr.port(),