Feature/host ip split (#654)
* Updated smart contract to work with future cosmwasm 0.14.0 update * Updated the rest of the codebase * Reordered imports * Missing imports * cargo fmt * More cargo fmt action * Introduced type alias for IdentityKey reference * Constant defined arguments for gateway and mixnode * Spliting host into explicit address and port(s) * Using more type restrictive IpAddr rather than String for listening address * Updated config templates * Tentative upgrade commands, probably to be further changed before release * Fixed mixnet contract test fixtures * Further missing test adjustments
This commit is contained in:
committed by
GitHub
parent
5ba20268dd
commit
b7f197d278
@@ -88,7 +88,7 @@ async fn register_with_gateway(
|
||||
) -> SharedKeys {
|
||||
let timeout = Duration::from_millis(1500);
|
||||
let mut gateway_client = GatewayClient::new_init(
|
||||
gateway.client_listener.clone(),
|
||||
gateway.clients_address(),
|
||||
gateway.identity_key,
|
||||
our_identity.clone(),
|
||||
timeout,
|
||||
@@ -215,7 +215,7 @@ pub fn execute(matches: &ArgMatches) {
|
||||
.with_gateway_id(gate_details.identity_key.to_base58_string());
|
||||
let shared_keys =
|
||||
register_with_gateway(&gate_details, key_manager.identity_keypair()).await;
|
||||
(shared_keys, gate_details.client_listener)
|
||||
(shared_keys, gate_details.clients_address())
|
||||
};
|
||||
|
||||
// TODO: is there perhaps a way to make it work without having to spawn entire runtime?
|
||||
|
||||
@@ -89,7 +89,7 @@ async fn register_with_gateway(
|
||||
) -> SharedKeys {
|
||||
let timeout = Duration::from_millis(1500);
|
||||
let mut gateway_client = GatewayClient::new_init(
|
||||
gateway.client_listener.clone(),
|
||||
gateway.clients_address(),
|
||||
gateway.identity_key,
|
||||
our_identity.clone(),
|
||||
timeout,
|
||||
@@ -217,7 +217,7 @@ pub fn execute(matches: &ArgMatches) {
|
||||
.with_gateway_id(gate_details.identity_key.to_base58_string());
|
||||
let shared_keys =
|
||||
register_with_gateway(&gate_details, key_manager.identity_keypair()).await;
|
||||
(shared_keys, gate_details.client_listener)
|
||||
(shared_keys, gate_details.clients_address())
|
||||
};
|
||||
|
||||
// TODO: is there perhaps a way to make it work without having to spawn entire runtime?
|
||||
|
||||
@@ -120,7 +120,7 @@ impl NymClient {
|
||||
let (ack_sender, ack_receiver) = mpsc::unbounded();
|
||||
|
||||
let mut gateway_client = GatewayClient::new(
|
||||
gateway.client_listener.clone(),
|
||||
gateway.clients_address(),
|
||||
Arc::clone(&client.identity),
|
||||
gateway.identity_key,
|
||||
None,
|
||||
|
||||
@@ -6,13 +6,12 @@ use cosmwasm_std::{Addr, Coin};
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt::Display;
|
||||
use std::io;
|
||||
use std::net::{SocketAddr, ToSocketAddrs};
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, JsonSchema)]
|
||||
pub struct Gateway {
|
||||
pub mix_host: String,
|
||||
pub clients_host: String,
|
||||
pub host: String,
|
||||
pub mix_port: u16,
|
||||
pub clients_port: u16,
|
||||
pub location: String,
|
||||
pub sphinx_key: SphinxKey,
|
||||
/// Base58 encoded ed25519 EdDSA public key of the gateway used to derive shared keys with clients
|
||||
@@ -22,29 +21,24 @@ pub struct Gateway {
|
||||
|
||||
impl Gateway {
|
||||
pub fn new(
|
||||
mix_host: String,
|
||||
clients_host: String,
|
||||
host: String,
|
||||
mix_port: u16,
|
||||
clients_port: u16,
|
||||
location: String,
|
||||
sphinx_key: SphinxKey,
|
||||
identity_key: IdentityKey,
|
||||
version: String,
|
||||
) -> Self {
|
||||
Gateway {
|
||||
mix_host,
|
||||
clients_host,
|
||||
host,
|
||||
mix_port,
|
||||
clients_port,
|
||||
location,
|
||||
sphinx_key,
|
||||
identity_key,
|
||||
version,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn try_resolve_hostname(&self) -> Result<SocketAddr, io::Error> {
|
||||
self.mix_host
|
||||
.to_socket_addrs()?
|
||||
.next()
|
||||
.ok_or_else(|| io::Error::new(io::ErrorKind::Other, "no valid socket address"))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, JsonSchema)]
|
||||
|
||||
@@ -6,12 +6,11 @@ use cosmwasm_std::{Addr, Coin};
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt::Display;
|
||||
use std::io;
|
||||
use std::net::{SocketAddr, ToSocketAddrs};
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, JsonSchema)]
|
||||
pub struct MixNode {
|
||||
pub host: String,
|
||||
pub mix_port: u16,
|
||||
pub layer: u64,
|
||||
pub location: String,
|
||||
pub sphinx_key: SphinxKey,
|
||||
@@ -23,6 +22,7 @@ pub struct MixNode {
|
||||
impl MixNode {
|
||||
pub fn new(
|
||||
host: String,
|
||||
mix_port: u16,
|
||||
layer: u64,
|
||||
location: String,
|
||||
sphinx_key: SphinxKey,
|
||||
@@ -31,6 +31,7 @@ impl MixNode {
|
||||
) -> Self {
|
||||
MixNode {
|
||||
host,
|
||||
mix_port,
|
||||
layer,
|
||||
location,
|
||||
sphinx_key,
|
||||
@@ -38,20 +39,8 @@ impl MixNode {
|
||||
version,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn try_resolve_hostname(&self) -> Result<SocketAddr, io::Error> {
|
||||
self.host
|
||||
.to_socket_addrs()?
|
||||
.next()
|
||||
.ok_or_else(|| io::Error::new(io::ErrorKind::Other, "no valid socket address"))
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
By the way, I've also been thinking of some potential changes in the contract we could introduce once we have to make an incompatible upgrade (say to cosmwasm 0.14+). Is there some place I could write them down so that we would not forget about them? Should I make a GitHub issue, a google doc or maybe put it on GitLab?
|
||||
|
||||
*/
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, JsonSchema)]
|
||||
pub struct MixNodeBond {
|
||||
// TODO:
|
||||
@@ -62,8 +51,6 @@ pub struct MixNodeBond {
|
||||
//
|
||||
// I would also modify the `MixNode` struct:
|
||||
// - remove `location` field
|
||||
// - repurpose `host` field to hold either ip or hostname (WITHOUT port information)
|
||||
// - introduce `mix_port` field
|
||||
// - introduce `rest_api_port` field
|
||||
// - [POTENTIALLY] introduce `verloc_port` field or keep it accessible via http api
|
||||
//
|
||||
|
||||
@@ -217,7 +217,8 @@ mod message_receiver {
|
||||
owner: "foomp1".to_string(),
|
||||
stake: 123,
|
||||
location: "unknown".to_string(),
|
||||
host: "10.20.30.40:1789".parse().unwrap(),
|
||||
host: "10.20.30.40".parse().unwrap(),
|
||||
mix_host: "10.20.30.40:1789".parse().unwrap(),
|
||||
identity_key: identity::PublicKey::from_base58_string(
|
||||
"3ebjp1Fb9hdcS1AR6AZihgeJiMHkB5jjJUsvqNnfQwU7",
|
||||
)
|
||||
@@ -237,7 +238,8 @@ mod message_receiver {
|
||||
owner: "foomp2".to_string(),
|
||||
stake: 123,
|
||||
location: "unknown".to_string(),
|
||||
host: "11.21.31.41:1789".parse().unwrap(),
|
||||
host: "11.21.31.41".parse().unwrap(),
|
||||
mix_host: "11.21.31.41:1789".parse().unwrap(),
|
||||
identity_key: identity::PublicKey::from_base58_string(
|
||||
"D6YaMzLSY7mANtSQRKXsmMZpqgqiVkeiagKM4V4oFPFr",
|
||||
)
|
||||
@@ -257,7 +259,8 @@ mod message_receiver {
|
||||
owner: "foomp3".to_string(),
|
||||
stake: 123,
|
||||
location: "unknown".to_string(),
|
||||
host: "12.22.32.42:1789".parse().unwrap(),
|
||||
host: "12.22.32.42".parse().unwrap(),
|
||||
mix_host: "12.22.32.42:1789".parse().unwrap(),
|
||||
identity_key: identity::PublicKey::from_base58_string(
|
||||
"GkWDysw4AjESv1KiAiVn7JzzCMJeksxNSXVfr1PpX8wD",
|
||||
)
|
||||
@@ -278,8 +281,9 @@ mod message_receiver {
|
||||
owner: "foomp4".to_string(),
|
||||
stake: 123,
|
||||
location: "unknown".to_string(),
|
||||
client_listener: "ws://1.2.3.4:9000".to_string(),
|
||||
mixnet_listener: "1.2.3.4:1789".parse().unwrap(),
|
||||
host: "1.2.3.4".parse().unwrap(),
|
||||
mix_host: "1.2.3.4:1789".parse().unwrap(),
|
||||
clients_port: 9000,
|
||||
identity_key: identity::PublicKey::from_base58_string(
|
||||
"FioFa8nMmPpQnYi7JyojoTuwGLeyNS8BF4ChPr29zUML",
|
||||
)
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use crate::filter;
|
||||
use crate::{filter, NetworkAddress};
|
||||
use crypto::asymmetric::{encryption, identity};
|
||||
use mixnet_contract::GatewayBond;
|
||||
use nymsphinx_addressing::nodes::{NodeIdentity, NymNodeRoutingAddress};
|
||||
@@ -84,8 +84,11 @@ pub struct Node {
|
||||
// on the network at a type, right?
|
||||
pub stake: u128,
|
||||
pub location: String,
|
||||
pub client_listener: String,
|
||||
pub mixnet_listener: SocketAddr,
|
||||
pub host: NetworkAddress,
|
||||
// we're keeping this as separate resolved field since we do not want to be resolving the potential
|
||||
// hostname every time we want to construct a path via this node
|
||||
pub mix_host: SocketAddr,
|
||||
pub clients_port: u16,
|
||||
pub identity_key: identity::PublicKey,
|
||||
pub sphinx_key: encryption::PublicKey, // TODO: or nymsphinx::PublicKey? both are x25519
|
||||
pub version: String,
|
||||
@@ -95,6 +98,10 @@ impl Node {
|
||||
pub fn identity(&self) -> &NodeIdentity {
|
||||
&self.identity_key
|
||||
}
|
||||
|
||||
pub fn clients_address(&self) -> String {
|
||||
format!("ws://{}:{}", self.host, self.clients_port)
|
||||
}
|
||||
}
|
||||
|
||||
impl filter::Versioned for Node {
|
||||
@@ -105,7 +112,7 @@ impl filter::Versioned for Node {
|
||||
|
||||
impl<'a> From<&'a Node> for SphinxNode {
|
||||
fn from(node: &'a Node) -> Self {
|
||||
let node_address_bytes = NymNodeRoutingAddress::from(node.mixnet_listener)
|
||||
let node_address_bytes = NymNodeRoutingAddress::from(node.mix_host)
|
||||
.try_into()
|
||||
.unwrap();
|
||||
|
||||
@@ -120,6 +127,17 @@ impl<'a> TryFrom<&'a GatewayBond> for Node {
|
||||
if bond.amount.len() > 1 {
|
||||
return Err(GatewayConversionError::InvalidStake);
|
||||
}
|
||||
|
||||
let host: NetworkAddress = bond.gateway.host.parse().map_err(|err| {
|
||||
GatewayConversionError::InvalidAddress(bond.gateway.host.clone(), err)
|
||||
})?;
|
||||
|
||||
// try to completely resolve the host in the mix situation to avoid doing it every
|
||||
// single time we want to construct a path
|
||||
let mix_host = host.to_socket_addrs(bond.gateway.mix_port).map_err(|err| {
|
||||
GatewayConversionError::InvalidAddress(bond.gateway.host.clone(), err)
|
||||
})?[0];
|
||||
|
||||
Ok(Node {
|
||||
owner: bond.owner.as_str().to_owned(),
|
||||
stake: bond
|
||||
@@ -128,10 +146,9 @@ impl<'a> TryFrom<&'a GatewayBond> for Node {
|
||||
.map(|stake| stake.amount.into())
|
||||
.unwrap_or(0),
|
||||
location: bond.gateway.location.clone(),
|
||||
client_listener: bond.gateway.clients_host.clone(),
|
||||
mixnet_listener: bond.gateway.try_resolve_hostname().map_err(|err| {
|
||||
GatewayConversionError::InvalidAddress(bond.gateway.mix_host.clone(), err)
|
||||
})?,
|
||||
host,
|
||||
mix_host,
|
||||
clients_port: bond.gateway.clients_port,
|
||||
identity_key: identity::PublicKey::from_base58_string(&bond.gateway.identity_key)?,
|
||||
sphinx_key: encryption::PublicKey::from_base58_string(&bond.gateway.sphinx_key)?,
|
||||
version: bond.gateway.version.clone(),
|
||||
|
||||
@@ -20,6 +20,10 @@ use nymsphinx_types::Node as SphinxNode;
|
||||
use rand::Rng;
|
||||
use std::collections::HashMap;
|
||||
use std::convert::TryInto;
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
use std::io;
|
||||
use std::net::{IpAddr, SocketAddr, ToSocketAddrs};
|
||||
use std::str::FromStr;
|
||||
|
||||
pub mod filter;
|
||||
pub mod gateway;
|
||||
@@ -35,6 +39,44 @@ pub enum NymTopologyError {
|
||||
NoMixesOnLayerAvailable(MixLayer),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum NetworkAddress {
|
||||
IpAddr(IpAddr),
|
||||
Hostname(String),
|
||||
}
|
||||
|
||||
impl NetworkAddress {
|
||||
pub fn to_socket_addrs(&self, port: u16) -> io::Result<Vec<SocketAddr>> {
|
||||
match self {
|
||||
NetworkAddress::IpAddr(addr) => Ok(vec![SocketAddr::new(*addr, port)]),
|
||||
NetworkAddress::Hostname(hostname) => {
|
||||
Ok((hostname.as_str(), port).to_socket_addrs()?.collect())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for NetworkAddress {
|
||||
type Err = std::io::Error;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
if let Ok(ip_addr) = s.parse() {
|
||||
Ok(NetworkAddress::IpAddr(ip_addr))
|
||||
} else {
|
||||
Ok(NetworkAddress::Hostname(s.to_string()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for NetworkAddress {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
NetworkAddress::IpAddr(ip_addr) => ip_addr.fmt(f),
|
||||
NetworkAddress::Hostname(hostname) => hostname.fmt(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub type MixLayer = u8;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@@ -248,7 +290,8 @@ mod converting_mixes_to_vec {
|
||||
owner: "N/A".to_string(),
|
||||
stake: 0,
|
||||
location: "London".to_string(),
|
||||
host: "3.3.3.3:1789".parse().unwrap(),
|
||||
host: "3.3.3.3".parse().unwrap(),
|
||||
mix_host: "3.3.3.3:1789".parse().unwrap(),
|
||||
identity_key: identity::PublicKey::from_base58_string(
|
||||
"3ebjp1Fb9hdcS1AR6AZihgeJiMHkB5jjJUsvqNnfQwU7",
|
||||
)
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use crate::filter;
|
||||
use crate::{filter, NetworkAddress};
|
||||
use crypto::asymmetric::{encryption, identity};
|
||||
use mixnet_contract::MixNodeBond;
|
||||
use nymsphinx_addressing::nodes::NymNodeRoutingAddress;
|
||||
@@ -84,7 +84,10 @@ pub struct Node {
|
||||
// on the network at a type, right?
|
||||
pub stake: u128,
|
||||
pub location: String,
|
||||
pub host: SocketAddr,
|
||||
pub host: NetworkAddress,
|
||||
// we're keeping this as separate resolved field since we do not want to be resolving the potential
|
||||
// hostname every time we want to construct a path via this node
|
||||
pub mix_host: SocketAddr,
|
||||
pub identity_key: identity::PublicKey,
|
||||
pub sphinx_key: encryption::PublicKey, // TODO: or nymsphinx::PublicKey? both are x25519
|
||||
pub layer: u64,
|
||||
@@ -99,7 +102,9 @@ impl filter::Versioned for Node {
|
||||
|
||||
impl<'a> From<&'a Node> for SphinxNode {
|
||||
fn from(node: &'a Node) -> Self {
|
||||
let node_address_bytes = NymNodeRoutingAddress::from(node.host).try_into().unwrap();
|
||||
let node_address_bytes = NymNodeRoutingAddress::from(node.mix_host)
|
||||
.try_into()
|
||||
.unwrap();
|
||||
|
||||
SphinxNode::new(node_address_bytes, (&node.sphinx_key).into())
|
||||
}
|
||||
@@ -112,6 +117,19 @@ impl<'a> TryFrom<&'a MixNodeBond> for Node {
|
||||
if bond.amount.len() > 1 {
|
||||
return Err(MixnodeConversionError::InvalidStake);
|
||||
}
|
||||
|
||||
let host: NetworkAddress = bond.mix_node.host.parse().map_err(|err| {
|
||||
MixnodeConversionError::InvalidAddress(bond.mix_node.host.clone(), err)
|
||||
})?;
|
||||
|
||||
// try to completely resolve the host in the mix situation to avoid doing it every
|
||||
// single time we want to construct a path
|
||||
let mix_host = host
|
||||
.to_socket_addrs(bond.mix_node.mix_port)
|
||||
.map_err(|err| {
|
||||
MixnodeConversionError::InvalidAddress(bond.mix_node.host.clone(), err)
|
||||
})?[0];
|
||||
|
||||
Ok(Node {
|
||||
owner: bond.owner.as_str().to_owned(),
|
||||
stake: bond
|
||||
@@ -120,9 +138,8 @@ impl<'a> TryFrom<&'a MixNodeBond> for Node {
|
||||
.map(|stake| stake.amount.into())
|
||||
.unwrap_or(0),
|
||||
location: bond.mix_node.location.clone(),
|
||||
host: bond.mix_node.try_resolve_hostname().map_err(|err| {
|
||||
MixnodeConversionError::InvalidAddress(bond.mix_node.host.clone(), err)
|
||||
})?,
|
||||
host,
|
||||
mix_host,
|
||||
identity_key: identity::PublicKey::from_base58_string(&bond.mix_node.identity_key)?,
|
||||
sphinx_key: encryption::PublicKey::from_base58_string(&bond.mix_node.sphinx_key)?,
|
||||
layer: bond.mix_node.layer,
|
||||
|
||||
@@ -107,6 +107,7 @@ pub mod helpers {
|
||||
pub fn mix_node_fixture() -> MixNode {
|
||||
MixNode::new(
|
||||
"mix.node.org".to_string(),
|
||||
1789,
|
||||
1,
|
||||
"Sweden".to_string(),
|
||||
"sphinx".to_string(),
|
||||
@@ -118,6 +119,7 @@ pub mod helpers {
|
||||
pub fn mixnode_bond_fixture() -> MixNodeBond {
|
||||
let mix_node = MixNode::new(
|
||||
"1.1.1.1".to_string(),
|
||||
1789,
|
||||
1,
|
||||
"London".to_string(),
|
||||
"1234".to_string(),
|
||||
@@ -129,8 +131,9 @@ pub mod helpers {
|
||||
|
||||
pub fn gateway_fixture() -> Gateway {
|
||||
Gateway::new(
|
||||
"1.1.1.1:1234".to_string(),
|
||||
"ws://1.1.1.1:1235".to_string(),
|
||||
"1.1.1.1".to_string(),
|
||||
1789,
|
||||
9000,
|
||||
"Sweden".to_string(),
|
||||
"sphinx".to_string(),
|
||||
"identity".to_string(),
|
||||
@@ -140,8 +143,9 @@ pub mod helpers {
|
||||
|
||||
pub fn gateway_bond_fixture() -> GatewayBond {
|
||||
let gateway = Gateway::new(
|
||||
"1.1.1.1:1234".to_string(),
|
||||
"ws://1.1.1.1:1235".to_string(),
|
||||
"1.1.1.1".to_string(),
|
||||
1789,
|
||||
9000,
|
||||
"London".to_string(),
|
||||
"sphinx".to_string(),
|
||||
"identity".to_string(),
|
||||
|
||||
@@ -1210,7 +1210,7 @@ pub mod tests {
|
||||
let msg = ExecuteMsg::BondGateway {
|
||||
gateway: Gateway {
|
||||
identity_key: "myAwesomeGateway".to_string(),
|
||||
mix_host: "1.1.1.1:1789".into(),
|
||||
host: "1.1.1.1".into(),
|
||||
..helpers::gateway_fixture()
|
||||
},
|
||||
};
|
||||
@@ -1221,7 +1221,7 @@ pub mod tests {
|
||||
let msg = ExecuteMsg::BondGateway {
|
||||
gateway: Gateway {
|
||||
identity_key: "myAwesomeGateway".to_string(),
|
||||
mix_host: "2.2.2.2:1789".into(),
|
||||
host: "2.2.2.2".into(),
|
||||
..helpers::gateway_fixture()
|
||||
},
|
||||
};
|
||||
@@ -1230,12 +1230,12 @@ pub mod tests {
|
||||
|
||||
// make sure the host information was updated
|
||||
assert_eq!(
|
||||
"2.2.2.2:1789".to_string(),
|
||||
"2.2.2.2".to_string(),
|
||||
gateways_read(deps.as_ref().storage)
|
||||
.load("myAwesomeGateway".as_bytes())
|
||||
.unwrap()
|
||||
.gateway
|
||||
.mix_host
|
||||
.host
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright 2020 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::commands::override_config;
|
||||
use crate::commands::*;
|
||||
use crate::config::persistence::pathfinder::GatewayPathfinder;
|
||||
use crate::config::Config;
|
||||
use clap::{App, Arg, ArgMatches};
|
||||
@@ -12,83 +12,58 @@ pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
|
||||
App::new("init")
|
||||
.about("Initialise the gateway")
|
||||
.arg(
|
||||
Arg::with_name("id")
|
||||
.long("id")
|
||||
Arg::with_name(ID_ARG_NAME)
|
||||
.long(ID_ARG_NAME)
|
||||
.help("Id of the gateway we want to create config for.")
|
||||
.takes_value(true)
|
||||
.required(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("mix-host")
|
||||
.long("mix-host")
|
||||
Arg::with_name(HOST_ARG_NAME)
|
||||
.long(HOST_ARG_NAME)
|
||||
.help("The custom host on which the gateway will be running for receiving sphinx packets")
|
||||
.takes_value(true)
|
||||
.required(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("mix-port")
|
||||
.long("mix-port")
|
||||
Arg::with_name(MIX_PORT_ARG_NAME)
|
||||
.long(MIX_PORT_ARG_NAME)
|
||||
.help("The port on which the gateway will be listening for sphinx packets")
|
||||
.takes_value(true)
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("clients-host")
|
||||
.long("clients-host")
|
||||
.help("The custom host on which the gateway will be running for receiving clients gateway-requests")
|
||||
.takes_value(true)
|
||||
.required(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("clients-port")
|
||||
.long("clients-port")
|
||||
Arg::with_name(CLIENTS_PORT_ARG_NAME)
|
||||
.long(CLIENTS_PORT_ARG_NAME)
|
||||
.help("The port on which the gateway will be listening for clients gateway-requests")
|
||||
.takes_value(true)
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("mix-announce-host")
|
||||
.long("mix-announce-host")
|
||||
Arg::with_name(ANNOUNCE_HOST_ARG_NAME)
|
||||
.long(ANNOUNCE_HOST_ARG_NAME)
|
||||
.help("The host that will be reported to the directory server")
|
||||
.takes_value(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("mix-announce-port")
|
||||
.long("mix-announce-port")
|
||||
.help("The port that will be reported to the directory server")
|
||||
.takes_value(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("clients-announce-host")
|
||||
.long("clients-announce-host")
|
||||
.help("The host that will be reported to the directory server")
|
||||
.takes_value(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("clients-announce-port")
|
||||
.long("clients-announce-port")
|
||||
.help("The port that will be reported to the directory server")
|
||||
.takes_value(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("inboxes")
|
||||
.long("inboxes")
|
||||
Arg::with_name(INBOXES_ARG_NAME)
|
||||
.long(INBOXES_ARG_NAME)
|
||||
.help("Directory with inboxes where all packets for the clients are stored")
|
||||
.takes_value(true)
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("clients-ledger")
|
||||
.long("clients-ledger")
|
||||
.help("Ledger directory containing registered clients")
|
||||
Arg::with_name(CLIENTS_LEDGER_ARG_NAME)
|
||||
.long(CLIENTS_LEDGER_ARG_NAME)
|
||||
.help("Ledger file containing registered clients")
|
||||
.takes_value(true)
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("validators")
|
||||
.long("validators")
|
||||
Arg::with_name(VALIDATORS_ARG_NAME)
|
||||
.long(VALIDATORS_ARG_NAME)
|
||||
.help("Comma separated list of rest endpoints of the validators")
|
||||
.takes_value(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("mixnet-contract")
|
||||
.long("mixnet-contract")
|
||||
Arg::with_name(CONTRACT_ARG_NAME)
|
||||
.long(CONTRACT_ARG_NAME)
|
||||
.help("Address of the validator contract managing the network")
|
||||
.takes_value(true),
|
||||
)
|
||||
@@ -131,21 +106,23 @@ fn show_bonding_info(config: &Config) {
|
||||
"\nTo bond your gateway you will [most likely] need to provide the following:
|
||||
Identity key: {}
|
||||
Sphinx key: {}
|
||||
Mix Host: {}
|
||||
Clients Host: {}
|
||||
Host: {}
|
||||
Mix Port: {}
|
||||
Clients Port: {}
|
||||
Location: [physical location of your node's server]
|
||||
Version: {}
|
||||
",
|
||||
identity_keypair.public_key().to_base58_string(),
|
||||
sphinx_keypair.public_key().to_base58_string(),
|
||||
config.get_mix_announce_address(),
|
||||
config.get_clients_announce_address(),
|
||||
config.get_announce_address(),
|
||||
config.get_mix_port(),
|
||||
config.get_clients_port(),
|
||||
config.get_version(),
|
||||
);
|
||||
}
|
||||
|
||||
pub fn execute(matches: &ArgMatches) {
|
||||
let id = matches.value_of("id").unwrap();
|
||||
let id = matches.value_of(ID_ARG_NAME).unwrap();
|
||||
println!("Initialising gateway {}...", id);
|
||||
|
||||
let already_init = if Config::default_config_file_path(id).exists() {
|
||||
|
||||
+29
-50
@@ -8,6 +8,16 @@ pub(crate) mod init;
|
||||
pub(crate) mod run;
|
||||
pub(crate) mod upgrade;
|
||||
|
||||
pub(crate) const ID_ARG_NAME: &str = "id";
|
||||
pub(crate) const HOST_ARG_NAME: &str = "host";
|
||||
pub(crate) const MIX_PORT_ARG_NAME: &str = "mix-port";
|
||||
pub(crate) const CLIENTS_PORT_ARG_NAME: &str = "clients-port";
|
||||
pub(crate) const VALIDATORS_ARG_NAME: &str = "validators";
|
||||
pub(crate) const CONTRACT_ARG_NAME: &str = "mixnet-contract";
|
||||
pub(crate) const ANNOUNCE_HOST_ARG_NAME: &str = "announce-host";
|
||||
pub(crate) const INBOXES_ARG_NAME: &str = "inboxes";
|
||||
pub(crate) const CLIENTS_LEDGER_ARG_NAME: &str = "clients-ledger";
|
||||
|
||||
fn parse_validators(raw: &str) -> Vec<String> {
|
||||
raw.split(',')
|
||||
.map(|raw_validator| raw_validator.trim().into())
|
||||
@@ -15,85 +25,54 @@ fn parse_validators(raw: &str) -> Vec<String> {
|
||||
}
|
||||
|
||||
pub(crate) fn override_config(mut config: Config, matches: &ArgMatches) -> Config {
|
||||
let mut was_mix_host_overridden = false;
|
||||
if let Some(mix_host) = matches.value_of("mix-host") {
|
||||
config = config.with_mix_listening_host(mix_host);
|
||||
was_mix_host_overridden = true;
|
||||
let mut was_host_overridden = false;
|
||||
if let Some(host) = matches.value_of(HOST_ARG_NAME) {
|
||||
config = config.with_listening_address(host);
|
||||
was_host_overridden = true;
|
||||
}
|
||||
|
||||
if let Some(mix_port) = matches.value_of("mix-port").map(|port| port.parse::<u16>()) {
|
||||
if let Some(mix_port) = matches
|
||||
.value_of(MIX_PORT_ARG_NAME)
|
||||
.map(|port| port.parse::<u16>())
|
||||
{
|
||||
if let Err(err) = mix_port {
|
||||
// if port was overridden, it must be parsable
|
||||
panic!("Invalid port value provided - {:?}", err);
|
||||
}
|
||||
config = config.with_mix_listening_port(mix_port.unwrap());
|
||||
}
|
||||
let mut was_clients_host_overridden = false;
|
||||
if let Some(clients_host) = matches.value_of("clients-host") {
|
||||
config = config.with_clients_listening_host(clients_host);
|
||||
was_clients_host_overridden = true;
|
||||
config = config.with_mix_port(mix_port.unwrap());
|
||||
}
|
||||
|
||||
if let Some(clients_port) = matches
|
||||
.value_of("clients-port")
|
||||
.value_of(CLIENTS_PORT_ARG_NAME)
|
||||
.map(|port| port.parse::<u16>())
|
||||
{
|
||||
if let Err(err) = clients_port {
|
||||
// if port was overridden, it must be parsable
|
||||
panic!("Invalid port value provided - {:?}", err);
|
||||
}
|
||||
config = config.with_clients_listening_port(clients_port.unwrap());
|
||||
config = config.with_clients_port(clients_port.unwrap());
|
||||
}
|
||||
|
||||
if let Some(mix_announce_host) = matches.value_of("mix-announce-host") {
|
||||
config = config.with_mix_announce_host(mix_announce_host);
|
||||
} else if was_mix_host_overridden {
|
||||
if let Some(announce_host) = matches.value_of(ANNOUNCE_HOST_ARG_NAME) {
|
||||
config = config.with_announce_address(announce_host);
|
||||
} else if was_host_overridden {
|
||||
// make sure our 'mix-announce-host' always defaults to 'mix-host'
|
||||
config = config.mix_announce_host_from_listening_host()
|
||||
config = config.announce_host_from_listening_host()
|
||||
}
|
||||
|
||||
if let Some(mix_announce_port) = matches
|
||||
.value_of("mix-announce-port")
|
||||
.map(|port| port.parse::<u16>())
|
||||
{
|
||||
if let Err(err) = mix_announce_port {
|
||||
// if port was overridden, it must be parsable
|
||||
panic!("Invalid port value provided - {:?}", err);
|
||||
}
|
||||
config = config.with_mix_announce_port(mix_announce_port.unwrap());
|
||||
}
|
||||
|
||||
if let Some(clients_announce_host) = matches.value_of("clients-announce-host") {
|
||||
config = config.with_clients_announce_host(clients_announce_host);
|
||||
} else if was_clients_host_overridden {
|
||||
// make sure our 'clients-announce-host' always defaults to 'clients-host'
|
||||
config = config.clients_announce_host_from_listening_host()
|
||||
}
|
||||
|
||||
if let Some(clients_announce_port) = matches
|
||||
.value_of("clients-announce-port")
|
||||
.map(|port| port.parse::<u16>())
|
||||
{
|
||||
if let Err(err) = clients_announce_port {
|
||||
// if port was overridden, it must be parsable
|
||||
panic!("Invalid port value provided - {:?}", err);
|
||||
}
|
||||
config = config.with_clients_announce_port(clients_announce_port.unwrap());
|
||||
}
|
||||
|
||||
if let Some(raw_validators) = matches.value_of("validators") {
|
||||
if let Some(raw_validators) = matches.value_of(VALIDATORS_ARG_NAME) {
|
||||
config = config.with_custom_validators(parse_validators(raw_validators));
|
||||
}
|
||||
|
||||
if let Some(contract_address) = matches.value_of("mixnet-contract") {
|
||||
if let Some(contract_address) = matches.value_of(CONTRACT_ARG_NAME) {
|
||||
config = config.with_custom_mixnet_contract(contract_address)
|
||||
}
|
||||
|
||||
if let Some(inboxes_dir) = matches.value_of("inboxes") {
|
||||
if let Some(inboxes_dir) = matches.value_of(INBOXES_ARG_NAME) {
|
||||
config = config.with_custom_clients_inboxes(inboxes_dir);
|
||||
}
|
||||
|
||||
if let Some(clients_ledger) = matches.value_of("clients-ledger") {
|
||||
if let Some(clients_ledger) = matches.value_of(CLIENTS_LEDGER_ARG_NAME) {
|
||||
config = config.with_custom_clients_ledger(clients_ledger);
|
||||
}
|
||||
|
||||
|
||||
+26
-71
@@ -1,7 +1,7 @@
|
||||
// Copyright 2020 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::commands::override_config;
|
||||
use crate::commands::*;
|
||||
use crate::config::persistence::pathfinder::GatewayPathfinder;
|
||||
use crate::config::Config;
|
||||
use crate::node::Gateway;
|
||||
@@ -15,88 +15,58 @@ pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
|
||||
App::new("run")
|
||||
.about("Starts the gateway")
|
||||
.arg(
|
||||
Arg::with_name("id")
|
||||
.long("id")
|
||||
Arg::with_name(ID_ARG_NAME)
|
||||
.long(ID_ARG_NAME)
|
||||
.help("Id of the gateway we want to run")
|
||||
.takes_value(true)
|
||||
.required(true),
|
||||
)
|
||||
// the rest of arguments are optional, they are used to override settings in config file
|
||||
.arg(
|
||||
Arg::with_name("config")
|
||||
.long("config")
|
||||
.help("Custom path to the nym gateway configuration file")
|
||||
.takes_value(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("mix-host")
|
||||
.long("mix-host")
|
||||
Arg::with_name(HOST_ARG_NAME)
|
||||
.long(HOST_ARG_NAME)
|
||||
.help("The custom host on which the gateway will be running for receiving sphinx packets")
|
||||
.takes_value(true)
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("mix-port")
|
||||
.long("mix-port")
|
||||
Arg::with_name(MIX_PORT_ARG_NAME)
|
||||
.long(MIX_PORT_ARG_NAME)
|
||||
.help("The port on which the gateway will be listening for sphinx packets")
|
||||
.takes_value(true)
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("clients-host")
|
||||
.long("clients-host")
|
||||
.help("The custom host on which the gateway will be running for receiving clients gateway-requests")
|
||||
.takes_value(true)
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("clients-port")
|
||||
.long("clients-port")
|
||||
Arg::with_name(CLIENTS_PORT_ARG_NAME)
|
||||
.long(CLIENTS_PORT_ARG_NAME)
|
||||
.help("The port on which the gateway will be listening for clients gateway-requests")
|
||||
.takes_value(true)
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("mix-announce-host")
|
||||
.long("mix-announce-host")
|
||||
Arg::with_name(ANNOUNCE_HOST_ARG_NAME)
|
||||
.long(ANNOUNCE_HOST_ARG_NAME)
|
||||
.help("The host that will be reported to the directory server")
|
||||
.takes_value(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("mix-announce-port")
|
||||
.long("mix-announce-port")
|
||||
.help("The port that will be reported to the directory server")
|
||||
.takes_value(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("clients-announce-host")
|
||||
.long("clients-announce-host")
|
||||
.help("The host that will be reported to the directory server")
|
||||
.takes_value(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("clients-announce-port")
|
||||
.long("clients-announce-port")
|
||||
.help("The port that will be reported to the directory server")
|
||||
.takes_value(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("inboxes")
|
||||
.long("inboxes")
|
||||
Arg::with_name(INBOXES_ARG_NAME)
|
||||
.long(INBOXES_ARG_NAME)
|
||||
.help("Directory with inboxes where all packets for the clients are stored")
|
||||
.takes_value(true)
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("clients-ledger")
|
||||
.long("clients-ledger")
|
||||
Arg::with_name(CLIENTS_LEDGER_ARG_NAME)
|
||||
.long(CLIENTS_LEDGER_ARG_NAME)
|
||||
.help("Ledger file containing registered clients")
|
||||
.takes_value(true)
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("validators")
|
||||
.long("validators")
|
||||
Arg::with_name(VALIDATORS_ARG_NAME)
|
||||
.long(VALIDATORS_ARG_NAME)
|
||||
.help("Comma separated list of rest endpoints of the validators")
|
||||
.takes_value(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("mixnet-contract")
|
||||
.long("mixnet-contract")
|
||||
Arg::with_name(CONTRACT_ARG_NAME)
|
||||
.long(CONTRACT_ARG_NAME)
|
||||
.help("Address of the validator contract managing the network")
|
||||
.takes_value(true),
|
||||
)
|
||||
@@ -163,7 +133,7 @@ fn version_check(cfg: &Config) -> bool {
|
||||
}
|
||||
|
||||
pub fn execute(matches: &ArgMatches) {
|
||||
let id = matches.value_of("id").unwrap();
|
||||
let id = matches.value_of(ID_ARG_NAME).unwrap();
|
||||
|
||||
println!("Starting gateway {}...", id);
|
||||
|
||||
@@ -186,14 +156,8 @@ pub fn execute(matches: &ArgMatches) {
|
||||
let sphinx_keypair = load_sphinx_keys(&pathfinder);
|
||||
let identity = load_identity_keys(&pathfinder);
|
||||
|
||||
let mix_listening_ip_string = config.get_mix_listening_address().ip().to_string();
|
||||
if special_addresses().contains(&mix_listening_ip_string.as_ref()) {
|
||||
show_binding_warning(mix_listening_ip_string);
|
||||
}
|
||||
|
||||
let clients_listening_ip_string = config.get_clients_listening_address().ip().to_string();
|
||||
if special_addresses().contains(&clients_listening_ip_string.as_ref()) {
|
||||
show_binding_warning(clients_listening_ip_string);
|
||||
if special_addresses().contains(&&*config.get_listening_address().to_string()) {
|
||||
show_binding_warning(config.get_listening_address().to_string());
|
||||
}
|
||||
|
||||
println!(
|
||||
@@ -202,21 +166,12 @@ pub fn execute(matches: &ArgMatches) {
|
||||
);
|
||||
|
||||
println!(
|
||||
"Listening for incoming sphinx packets on {}",
|
||||
config.get_mix_listening_address()
|
||||
"Listening for incoming packets on {}",
|
||||
config.get_listening_address()
|
||||
);
|
||||
println!(
|
||||
"Announcing the following socket address for sphinx packets: {}",
|
||||
config.get_mix_announce_address()
|
||||
);
|
||||
|
||||
println!(
|
||||
"Listening for incoming clients packets on {}",
|
||||
config.get_clients_listening_address()
|
||||
);
|
||||
println!(
|
||||
"Announcing the following socket address for clients packets: {}",
|
||||
config.get_clients_announce_address()
|
||||
"Announcing the following address: {}",
|
||||
config.get_announce_address()
|
||||
);
|
||||
|
||||
println!(
|
||||
|
||||
@@ -1,14 +1,22 @@
|
||||
// Copyright 2020 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::config::DEFAULT_MIXNET_CONTRACT_ADDRESS;
|
||||
use crate::config::{default_validator_rest_endpoints, Config, MISSING_VALUE};
|
||||
use clap::{App, Arg, ArgMatches};
|
||||
use config::NymConfig;
|
||||
use std::fmt::Display;
|
||||
use std::process;
|
||||
|
||||
use clap::{App, Arg, ArgMatches};
|
||||
|
||||
use config::NymConfig;
|
||||
use version_checker::{parse_version, Version};
|
||||
|
||||
use crate::config::DEFAULT_MIXNET_CONTRACT_ADDRESS;
|
||||
use crate::config::{default_validator_rest_endpoints, Config, MISSING_VALUE};
|
||||
|
||||
fn fail_upgrade<D1: Display, D2: Display>(from_version: D1, to_version: D2) -> ! {
|
||||
print_failed_upgrade(from_version, to_version);
|
||||
process::exit(1)
|
||||
}
|
||||
|
||||
fn print_start_upgrade<D1: Display, D2: Display>(from: D1, to: D2) {
|
||||
println!(
|
||||
"\n==================\nTrying to upgrade gateway from {} to {} ...",
|
||||
@@ -45,6 +53,16 @@ pub fn command_args<'a, 'b>() -> App<'a, 'b> {
|
||||
.help("REQUIRED FOR PRE-0.9.0 UPGRADES. Specifies current version of the configuration file to help to determine a valid upgrade path. Valid formats include '0.8.1', 'v0.8.1' or 'V0.8.1'")
|
||||
.takes_value(true)
|
||||
)
|
||||
.arg(Arg::with_name("listening-address")
|
||||
.long("listening-address")
|
||||
.help("REQUIRED FOR 0.Y.Z UPGRADE. Specifies the listening address of this gateway")
|
||||
.takes_value(true)
|
||||
)
|
||||
.arg(Arg::with_name("announce-address")
|
||||
.long("announce-address")
|
||||
.help("OPTIONAL FOR 0.Y.Z UPGRADE. Specifies the announce address of this gateway. If not provided, it will be set to the same value as listening address")
|
||||
.takes_value(true)
|
||||
)
|
||||
}
|
||||
|
||||
fn unsupported_upgrade(current_version: Version, config_version: Version) -> ! {
|
||||
@@ -169,8 +187,7 @@ fn minor_010_upgrade(
|
||||
|
||||
if config.get_validator_mixnet_contract_address() != MISSING_VALUE {
|
||||
eprintln!("existing config seems to have specified mixnet contract address which was only introduced in 0.10.0! Can't perform upgrade.");
|
||||
print_failed_upgrade(&config_version, &to_version);
|
||||
process::exit(1);
|
||||
fail_upgrade(&config_version, &to_version)
|
||||
}
|
||||
|
||||
println!(
|
||||
@@ -190,8 +207,7 @@ fn minor_010_upgrade(
|
||||
|
||||
upgraded_config.save_to_file(None).unwrap_or_else(|err| {
|
||||
eprintln!("failed to overwrite config file! - {:?}", err);
|
||||
print_failed_upgrade(&config_version, &to_version);
|
||||
process::exit(1);
|
||||
fail_upgrade(&config_version, &to_version)
|
||||
});
|
||||
|
||||
print_successful_upgrade(config_version, to_version);
|
||||
@@ -214,8 +230,58 @@ fn patch_010_upgrade(
|
||||
|
||||
upgraded_config.save_to_file(None).unwrap_or_else(|err| {
|
||||
eprintln!("failed to overwrite config file! - {:?}", err);
|
||||
print_failed_upgrade(&config_version, &to_version);
|
||||
process::exit(1);
|
||||
fail_upgrade(&config_version, &to_version)
|
||||
});
|
||||
|
||||
print_successful_upgrade(config_version, to_version);
|
||||
|
||||
upgraded_config
|
||||
}
|
||||
|
||||
// TODO: to be renamed once the release version is decided (so presumably either 0.10.2 or 0.11.0)
|
||||
fn undetermined_version_upgrade(
|
||||
config: Config,
|
||||
matches: &ArgMatches,
|
||||
config_version: &Version,
|
||||
package_version: &Version,
|
||||
) -> Config {
|
||||
// If we decide this version should be tagged with 0.11.0, then the following code will be used instead:
|
||||
// let to_version = if package_version.major == 0 && package_version.minor == 11 {
|
||||
// package_version.clone()
|
||||
// } else {
|
||||
// Version::new(0, 11, 0)
|
||||
// };
|
||||
let to_version = package_version;
|
||||
|
||||
print_start_upgrade(&config_version, &to_version);
|
||||
|
||||
// normally the proper approach would have been to keep old structs, parse file according to old structs
|
||||
// and move it to the new ones
|
||||
// however, considering that at this point of time we don't have many gateways and all
|
||||
// are run by us, this would be an unnecessary code complication and so just providing
|
||||
// addresses again during upgrade is I think a better approach.
|
||||
let listening_address = matches.value_of("listening-address").unwrap_or_else(|| {
|
||||
eprintln!(
|
||||
"trying to upgrade to {} without providing proper listening address!",
|
||||
to_version
|
||||
);
|
||||
fail_upgrade(&config_version, &to_version)
|
||||
});
|
||||
|
||||
let announce_address = if let Some(announce_addr) = matches.value_of("announce-address") {
|
||||
announce_addr.to_string()
|
||||
} else {
|
||||
listening_address.to_string()
|
||||
};
|
||||
|
||||
let upgraded_config = config
|
||||
.with_custom_version(to_version.to_string().as_ref())
|
||||
.with_listening_address(listening_address)
|
||||
.with_announce_address(announce_address);
|
||||
|
||||
upgraded_config.save_to_file(None).unwrap_or_else(|err| {
|
||||
eprintln!("failed to overwrite config file! - {:?}", err);
|
||||
fail_upgrade(&config_version, &to_version)
|
||||
});
|
||||
|
||||
print_successful_upgrade(config_version, to_version);
|
||||
@@ -235,7 +301,15 @@ fn do_upgrade(mut config: Config, matches: &ArgMatches, package_version: Version
|
||||
config = match config_version.major {
|
||||
0 => match config_version.minor {
|
||||
9 => minor_010_upgrade(config, matches, &config_version, &package_version),
|
||||
10 => patch_010_upgrade(config, matches, &config_version, &package_version),
|
||||
10 => match config_version.patch {
|
||||
0 => patch_010_upgrade(config, matches, &config_version, &package_version),
|
||||
_ => undetermined_version_upgrade(
|
||||
config,
|
||||
matches,
|
||||
&config_version,
|
||||
&package_version,
|
||||
),
|
||||
},
|
||||
_ => unsupported_upgrade(config_version, package_version),
|
||||
},
|
||||
_ => unsupported_upgrade(config_version, package_version),
|
||||
|
||||
+63
-207
@@ -3,11 +3,10 @@
|
||||
|
||||
use crate::config::template::config_template;
|
||||
use config::{deserialize_duration, deserialize_validators, NymConfig};
|
||||
use log::*;
|
||||
use log::error;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::net::{IpAddr, SocketAddr};
|
||||
use std::net::IpAddr;
|
||||
use std::path::PathBuf;
|
||||
use std::str::FromStr;
|
||||
use std::time::Duration;
|
||||
|
||||
pub mod persistence;
|
||||
@@ -21,7 +20,6 @@ const DEFAULT_CLIENT_LISTENING_PORT: u16 = 9000;
|
||||
pub(crate) const DEFAULT_VALIDATOR_REST_ENDPOINTS: &[&str] = &[
|
||||
"http://testnet-finney-validator.nymtech.net:1317",
|
||||
"http://testnet-finney-validator2.nymtech.net:1317",
|
||||
"http://mixnet.club:1317",
|
||||
];
|
||||
pub const DEFAULT_MIXNET_CONTRACT_ADDRESS: &str = "hal1k0jntykt7e4g3y88ltc60czgjuqdy4c9c6gv94";
|
||||
|
||||
@@ -53,13 +51,22 @@ pub fn missing_vec_string_value() -> Vec<String> {
|
||||
vec![missing_string_value()]
|
||||
}
|
||||
|
||||
fn bind_all_address() -> IpAddr {
|
||||
"0.0.0.0".parse().unwrap()
|
||||
}
|
||||
|
||||
fn default_mix_port() -> u16 {
|
||||
DEFAULT_MIX_LISTENING_PORT
|
||||
}
|
||||
|
||||
fn default_clients_port() -> u16 {
|
||||
DEFAULT_CLIENT_LISTENING_PORT
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct Config {
|
||||
gateway: Gateway,
|
||||
|
||||
mixnet_endpoint: MixnetEndpoint,
|
||||
|
||||
clients_endpoint: ClientsEndpoint,
|
||||
|
||||
#[serde(default)]
|
||||
@@ -155,167 +162,36 @@ impl Config {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_mix_listening_host<S: Into<String>>(mut self, host: S) -> Self {
|
||||
// see if the provided `host` is just an ip address or ip:port
|
||||
let host = host.into();
|
||||
|
||||
// is it ip:port?
|
||||
match SocketAddr::from_str(host.as_ref()) {
|
||||
Ok(socket_addr) => {
|
||||
self.mixnet_endpoint.listening_address = socket_addr;
|
||||
self
|
||||
}
|
||||
// try just for ip
|
||||
Err(_) => match IpAddr::from_str(host.as_ref()) {
|
||||
Ok(ip_addr) => {
|
||||
self.mixnet_endpoint.listening_address.set_ip(ip_addr);
|
||||
self
|
||||
}
|
||||
Err(_) => {
|
||||
error!(
|
||||
"failed to make any changes to config - invalid host {}",
|
||||
host
|
||||
);
|
||||
self
|
||||
}
|
||||
},
|
||||
pub fn with_listening_address<S: Into<String>>(mut self, listening_address: S) -> Self {
|
||||
let listening_address_string = listening_address.into();
|
||||
if let Ok(ip_addr) = listening_address_string.parse() {
|
||||
self.gateway.listening_address = ip_addr
|
||||
} else {
|
||||
error!(
|
||||
"failed to change listening address. the provided value ({}) was invalid",
|
||||
listening_address_string
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_mix_listening_port(mut self, port: u16) -> Self {
|
||||
self.mixnet_endpoint.listening_address.set_port(port);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_mix_announce_host<S: Into<String>>(mut self, host: S) -> Self {
|
||||
// this is slightly more complicated as we store announce information as String,
|
||||
// since it might not necessarily be a valid SocketAddr (say `nymtech.net:8080` is a valid
|
||||
// announce address, yet invalid SocketAddr`
|
||||
|
||||
// first let's see if we received host:port or just host part of an address
|
||||
let host = host.into();
|
||||
match host.split(':').count() {
|
||||
1 => {
|
||||
// we provided only 'host' part so we are going to reuse existing port
|
||||
self.mixnet_endpoint.announce_address =
|
||||
format!("{}:{}", host, self.mixnet_endpoint.listening_address.port());
|
||||
self
|
||||
}
|
||||
2 => {
|
||||
// we provided 'host:port' so just put the whole thing there
|
||||
self.mixnet_endpoint.announce_address = host;
|
||||
self
|
||||
}
|
||||
_ => {
|
||||
// we provided something completely invalid, so don't try to parse it
|
||||
error!(
|
||||
"failed to make any changes to config - invalid announce host {}",
|
||||
host
|
||||
);
|
||||
self
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mix_announce_host_from_listening_host(mut self) -> Self {
|
||||
self.mixnet_endpoint.announce_address = self.mixnet_endpoint.listening_address.to_string();
|
||||
pub fn with_announce_address<S: Into<String>>(mut self, announce_address: S) -> Self {
|
||||
self.gateway.announce_address = announce_address.into();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_mix_announce_port(mut self, port: u16) -> Self {
|
||||
let current_host: Vec<_> = self.mixnet_endpoint.announce_address.split(':').collect();
|
||||
debug_assert_eq!(current_host.len(), 2);
|
||||
self.mixnet_endpoint.announce_address = format!("{}:{}", current_host[0], port);
|
||||
pub fn with_mix_port(mut self, port: u16) -> Self {
|
||||
self.gateway.mix_port = port;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_clients_listening_host<S: Into<String>>(mut self, host: S) -> Self {
|
||||
// see if the provided `host` is just an ip address or ip:port
|
||||
let host = host.into();
|
||||
|
||||
// is it ip:port?
|
||||
match SocketAddr::from_str(host.as_ref()) {
|
||||
Ok(socket_addr) => {
|
||||
self.clients_endpoint.listening_address = socket_addr;
|
||||
self
|
||||
}
|
||||
// try just for ip
|
||||
Err(_) => match IpAddr::from_str(host.as_ref()) {
|
||||
Ok(ip_addr) => {
|
||||
self.clients_endpoint.listening_address.set_ip(ip_addr);
|
||||
self
|
||||
}
|
||||
Err(_) => {
|
||||
error!(
|
||||
"failed to make any changes to config - invalid host {}",
|
||||
host
|
||||
);
|
||||
self
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn clients_announce_host_from_listening_host(mut self) -> Self {
|
||||
self.clients_endpoint.announce_address = format!(
|
||||
"ws://{}",
|
||||
self.clients_endpoint.listening_address.to_string()
|
||||
);
|
||||
pub fn with_clients_port(mut self, port: u16) -> Self {
|
||||
self.gateway.clients_port = port;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_clients_listening_port(mut self, port: u16) -> Self {
|
||||
self.clients_endpoint.listening_address.set_port(port);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_clients_announce_host<S: Into<String>>(mut self, host: S) -> Self {
|
||||
// this is slightly more complicated as we store announce information as String,
|
||||
// since it might not necessarily be a valid SocketAddr (say `nymtech.net:8080` is a valid
|
||||
// announce address, yet invalid SocketAddr`
|
||||
|
||||
// first let's see if we received host:port or just host part of an address
|
||||
let host = host.into();
|
||||
match host.split(':').count() {
|
||||
1 => {
|
||||
// we provided only 'host' part so we are going to reuse existing port
|
||||
self.clients_endpoint.announce_address = format!(
|
||||
"{}:{}",
|
||||
host,
|
||||
self.clients_endpoint.listening_address.port()
|
||||
);
|
||||
// make sure it has 'ws' prefix (by extension it also includes 'wss')
|
||||
if !self.clients_endpoint.announce_address.starts_with("ws") {
|
||||
self.clients_endpoint.announce_address =
|
||||
format!("ws://{}", self.clients_endpoint.announce_address);
|
||||
}
|
||||
self
|
||||
}
|
||||
2 => {
|
||||
// we provided 'host:port' so just put the whole thing there
|
||||
self.clients_endpoint.announce_address = host;
|
||||
// make sure it has 'ws' prefix (by extension it also includes 'wss')
|
||||
if !self.clients_endpoint.announce_address.starts_with("ws") {
|
||||
self.clients_endpoint.announce_address =
|
||||
format!("ws://{}", self.clients_endpoint.announce_address);
|
||||
}
|
||||
self
|
||||
}
|
||||
_ => {
|
||||
// we provided something completely invalid, so don't try to parse it
|
||||
error!(
|
||||
"failed to make any changes to config - invalid announce host {}",
|
||||
host
|
||||
);
|
||||
self
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_clients_announce_port(mut self, port: u16) -> Self {
|
||||
let current_host: Vec<_> = self.clients_endpoint.announce_address.split(':').collect();
|
||||
debug_assert_eq!(current_host.len(), 2);
|
||||
self.clients_endpoint.announce_address = format!("{}:{}", current_host[0], port);
|
||||
pub fn announce_host_from_listening_host(mut self) -> Self {
|
||||
self.gateway.announce_address = self.gateway.listening_address.to_string();
|
||||
self
|
||||
}
|
||||
|
||||
@@ -363,20 +239,20 @@ impl Config {
|
||||
self.gateway.mixnet_contract_address.clone()
|
||||
}
|
||||
|
||||
pub fn get_mix_listening_address(&self) -> SocketAddr {
|
||||
self.mixnet_endpoint.listening_address
|
||||
pub fn get_listening_address(&self) -> IpAddr {
|
||||
self.gateway.listening_address
|
||||
}
|
||||
|
||||
pub fn get_mix_announce_address(&self) -> String {
|
||||
self.mixnet_endpoint.announce_address.clone()
|
||||
pub fn get_announce_address(&self) -> String {
|
||||
self.gateway.announce_address.clone()
|
||||
}
|
||||
|
||||
pub fn get_clients_listening_address(&self) -> SocketAddr {
|
||||
self.clients_endpoint.listening_address
|
||||
pub fn get_mix_port(&self) -> u16 {
|
||||
self.gateway.mix_port
|
||||
}
|
||||
|
||||
pub fn get_clients_announce_address(&self) -> String {
|
||||
self.clients_endpoint.announce_address.clone()
|
||||
pub fn get_clients_port(&self) -> u16 {
|
||||
self.gateway.clients_port
|
||||
}
|
||||
|
||||
pub fn get_clients_inboxes_dir(&self) -> PathBuf {
|
||||
@@ -429,6 +305,26 @@ pub struct Gateway {
|
||||
/// ID specifies the human readable ID of this particular gateway.
|
||||
id: String,
|
||||
|
||||
/// Address to which this mixnode will bind to and will be listening for packets.
|
||||
#[serde(default = "bind_all_address")]
|
||||
listening_address: IpAddr,
|
||||
|
||||
/// Optional address announced to the validator for the clients to connect to.
|
||||
/// It is useful, say, in NAT scenarios or wanting to more easily update actual IP address
|
||||
/// later on by using name resolvable with a DNS query, such as `nymtech.net`.
|
||||
#[serde(default = "missing_string_value")]
|
||||
announce_address: String,
|
||||
|
||||
/// Port used for listening for all mixnet traffic.
|
||||
/// (default: 1789)
|
||||
#[serde(default = "default_mix_port")]
|
||||
mix_port: u16,
|
||||
|
||||
/// Port used for listening for all client-related traffic.
|
||||
/// (default: 9000)
|
||||
#[serde(default = "default_clients_port")]
|
||||
clients_port: u16,
|
||||
|
||||
/// Path to file containing private identity key.
|
||||
private_identity_key_file: PathBuf,
|
||||
|
||||
@@ -481,6 +377,10 @@ impl Default for Gateway {
|
||||
Gateway {
|
||||
version: env!("CARGO_PKG_VERSION").to_string(),
|
||||
id: "".to_string(),
|
||||
listening_address: bind_all_address(),
|
||||
announce_address: "127.0.0.1".to_string(),
|
||||
mix_port: DEFAULT_MIX_LISTENING_PORT,
|
||||
clients_port: DEFAULT_CLIENT_LISTENING_PORT,
|
||||
private_identity_key_file: Default::default(),
|
||||
public_identity_key_file: Default::default(),
|
||||
private_sphinx_key_file: Default::default(),
|
||||
@@ -493,47 +393,7 @@ impl Default for Gateway {
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct MixnetEndpoint {
|
||||
/// Socket address to which this gateway will bind to
|
||||
/// and will be listening for sphinx packets coming from the mixnet.
|
||||
listening_address: SocketAddr,
|
||||
|
||||
/// Optional address announced to the directory server for the clients to connect to.
|
||||
/// It is useful, say, in NAT scenarios or wanting to more easily update actual IP address
|
||||
/// later on by using name resolvable with a DNS query, such as `nymtech.net:8080`.
|
||||
/// Additionally a custom port can be provided, so both `nymtech.net:8080` and `nymtech.net`
|
||||
/// are valid announce addresses, while the later will default to whatever port is used for
|
||||
/// `listening_address`.
|
||||
announce_address: String,
|
||||
}
|
||||
|
||||
impl Default for MixnetEndpoint {
|
||||
fn default() -> Self {
|
||||
MixnetEndpoint {
|
||||
listening_address: format!("0.0.0.0:{}", DEFAULT_MIX_LISTENING_PORT)
|
||||
.parse()
|
||||
.unwrap(),
|
||||
announce_address: format!("127.0.0.1:{}", DEFAULT_MIX_LISTENING_PORT),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct ClientsEndpoint {
|
||||
/// Socket address to which this gateway will bind to
|
||||
/// and will be listening for data packets coming from the clients.
|
||||
listening_address: SocketAddr,
|
||||
|
||||
/// Optional address announced to the directory server for the clients to connect to.
|
||||
/// It is useful, say, in NAT scenarios or wanting to more easily update actual IP address
|
||||
/// later on by using name resolvable with a DNS query, such as `nymtech.net:8080`.
|
||||
/// Additionally a custom port can be provided, so both `nymtech.net:8080` and `nymtech.net`
|
||||
/// are valid announce addresses, while the later will default to whatever port is used for
|
||||
/// `listening_address`.
|
||||
announce_address: String,
|
||||
|
||||
/// Path to the directory with clients inboxes containing messages stored for them.
|
||||
inboxes_directory: PathBuf,
|
||||
|
||||
@@ -555,10 +415,6 @@ impl ClientsEndpoint {
|
||||
impl Default for ClientsEndpoint {
|
||||
fn default() -> Self {
|
||||
ClientsEndpoint {
|
||||
listening_address: format!("0.0.0.0:{}", DEFAULT_CLIENT_LISTENING_PORT)
|
||||
.parse()
|
||||
.unwrap(),
|
||||
announce_address: format!("ws://127.0.0.1:{}", DEFAULT_CLIENT_LISTENING_PORT),
|
||||
inboxes_directory: Default::default(),
|
||||
ledger_path: Default::default(),
|
||||
}
|
||||
|
||||
@@ -19,6 +19,9 @@ version = '{{ gateway.version }}'
|
||||
# Human readable ID of this particular gateway.
|
||||
id = '{{ gateway.id }}'
|
||||
|
||||
# Socket address to which this gateway will bind to and will be listening for packets.
|
||||
listening_address = '{{ gateway.listening_address }}'
|
||||
|
||||
# Path to file containing private identity key.
|
||||
private_identity_key_file = '{{ gateway.private_identity_key_file }}'
|
||||
|
||||
@@ -31,7 +34,22 @@ private_sphinx_key_file = '{{ gateway.private_sphinx_key_file }}'
|
||||
# Path to file containing public sphinx key.
|
||||
public_sphinx_key_file = '{{ gateway.public_sphinx_key_file }}'
|
||||
|
||||
# Validator server to which the node will be reporting their presence data.
|
||||
##### additional gateway config options #####
|
||||
|
||||
# Optional address announced to the directory server for the clients to connect to.
|
||||
# It is useful, say, in NAT scenarios or wanting to more easily update actual IP address
|
||||
# later on by using name resolvable with a DNS query, such as `nymtech.net`.
|
||||
announce_address = '{{ gateway.announce_address }}'
|
||||
|
||||
# Port used for listening for all mixnet traffic.
|
||||
# (default: 1789)
|
||||
mix_port = {{ gateway.mix_port }}
|
||||
|
||||
# Port used for listening for all client websocket traffic.
|
||||
# (default: 9000)
|
||||
clients_port = {{ gateway.clients_port }}
|
||||
|
||||
# Validator server to which the node will be getting information about the network.
|
||||
validator_rest_urls = [
|
||||
{{#each gateway.validator_rest_urls }}
|
||||
'{{this}}',
|
||||
@@ -41,41 +59,15 @@ validator_rest_urls = [
|
||||
# Address of the validator contract managing the network.
|
||||
mixnet_contract_address = '{{ gateway.mixnet_contract_address }}'
|
||||
|
||||
##### advanced configuration options #####
|
||||
|
||||
# nym_home_directory specifies absolute path to the home nym gateway directory.
|
||||
# It is expected to use default value and hence .toml file should not redefine this field.
|
||||
nym_root_directory = '{{ gateway.nym_root_directory }}'
|
||||
|
||||
|
||||
##### Mixnet endpoint config options #####
|
||||
|
||||
[mixnet_endpoint]
|
||||
# Socket address to which this gateway will bind to
|
||||
# and will be listening for sphinx packets coming from the mixnet.
|
||||
listening_address = '{{ mixnet_endpoint.listening_address }}'
|
||||
|
||||
# Optional address announced to the directory server for the clients to connect to.
|
||||
# It is useful, say, in NAT scenarios or wanting to more easily update actual IP address
|
||||
# later on by using name resolvable with a DNS query, such as `nymtech.net:8080`.
|
||||
# Additionally a custom port can be provided, so both `nymtech.net:8080` and `nymtech.net`
|
||||
# are valid announce addresses, while the later will default to whatever port is used for
|
||||
# `listening_address`.
|
||||
announce_address = '{{ mixnet_endpoint.announce_address }}'
|
||||
|
||||
|
||||
#### Clients endpoint config options #####
|
||||
|
||||
[clients_endpoint]
|
||||
# Socket address to which this gateway will bind to
|
||||
# and will be listening for sphinx packets coming from the mixnet.
|
||||
listening_address = '{{ clients_endpoint.listening_address }}'
|
||||
|
||||
# Optional address announced to the directory server for the clients to connect to.
|
||||
# It is useful, say, in NAT scenarios or wanting to more easily update actual IP address
|
||||
# later on by using name resolvable with a DNS query, such as `nymtech.net:8080`.
|
||||
# Additionally a custom port can be provided, so both `nymtech.net:8080` and `nymtech.net`
|
||||
# are valid announce addresses, while the later will default to whatever port is used for
|
||||
# `listening_address`.
|
||||
announce_address = '{{ clients_endpoint.announce_address }}'
|
||||
|
||||
# Path to the directory with clients inboxes containing messages stored for them.
|
||||
inboxes_directory = '{{ clients_endpoint.inboxes_directory }}'
|
||||
|
||||
+16
-14
@@ -9,6 +9,7 @@ use crate::node::storage::{inboxes, ClientLedger};
|
||||
use crypto::asymmetric::{encryption, identity};
|
||||
use log::*;
|
||||
use mixnet_client::forwarder::{MixForwardingSender, PacketForwarder};
|
||||
use std::net::SocketAddr;
|
||||
use std::process;
|
||||
use std::sync::Arc;
|
||||
use tokio::runtime::Runtime;
|
||||
@@ -70,9 +71,12 @@ impl Gateway {
|
||||
ack_sender,
|
||||
);
|
||||
|
||||
let listener = mixnet_handling::Listener::new(self.config.get_mix_listening_address());
|
||||
let listening_address = SocketAddr::new(
|
||||
self.config.get_listening_address(),
|
||||
self.config.get_mix_port(),
|
||||
);
|
||||
|
||||
listener.start(connection_handler);
|
||||
mixnet_handling::Listener::new(listening_address).start(connection_handler);
|
||||
}
|
||||
|
||||
fn start_client_websocket_listener(
|
||||
@@ -82,11 +86,13 @@ impl Gateway {
|
||||
) {
|
||||
info!("Starting client [web]socket listener...");
|
||||
|
||||
websocket::Listener::new(
|
||||
self.config.get_clients_listening_address(),
|
||||
Arc::clone(&self.identity),
|
||||
)
|
||||
.start(clients_handler_sender, forwarding_channel);
|
||||
let listening_address = SocketAddr::new(
|
||||
self.config.get_listening_address(),
|
||||
self.config.get_clients_port(),
|
||||
);
|
||||
|
||||
websocket::Listener::new(listening_address, Arc::clone(&self.identity))
|
||||
.start(clients_handler_sender, forwarding_channel);
|
||||
}
|
||||
|
||||
fn start_packet_forwarder(&self) -> MixForwardingSender {
|
||||
@@ -127,9 +133,6 @@ impl Gateway {
|
||||
|
||||
// TODO: ask DH whether this function still makes sense in ^0.10
|
||||
async fn check_if_same_ip_gateway_exists(&self) -> Option<String> {
|
||||
let announced_mix_host = self.config.get_mix_announce_address();
|
||||
let announced_clients_host = self.config.get_clients_announce_address();
|
||||
|
||||
let validator_client_config = validator_client::Config::new(
|
||||
self.config.get_validator_rest_endpoints(),
|
||||
self.config.get_validator_mixnet_contract_address(),
|
||||
@@ -144,12 +147,11 @@ impl Gateway {
|
||||
}
|
||||
};
|
||||
|
||||
let our_host = self.config.get_announce_address();
|
||||
|
||||
existing_gateways
|
||||
.iter()
|
||||
.find(|node| {
|
||||
node.gateway.mix_host == announced_mix_host
|
||||
|| node.gateway.clients_host == announced_clients_host
|
||||
})
|
||||
.find(|node| node.gateway.host == our_host)
|
||||
.map(|node| node.gateway().identity_key.clone())
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use crate::commands::*;
|
||||
use crate::config::Config;
|
||||
use crate::node::node_description::NodeDescription;
|
||||
use clap::{App, Arg, ArgMatches};
|
||||
@@ -10,8 +11,8 @@ pub fn command_args<'a, 'b>() -> App<'a, 'b> {
|
||||
App::new("describe")
|
||||
.about("Describe your mixnode and tell people why they should delegate stake to you")
|
||||
.arg(
|
||||
Arg::with_name("id")
|
||||
.long("id")
|
||||
Arg::with_name(ID_ARG_NAME)
|
||||
.long(ID_ARG_NAME)
|
||||
.help("The id of the mixnode you want to describe")
|
||||
.takes_value(true)
|
||||
.required(true),
|
||||
@@ -21,7 +22,7 @@ pub fn command_args<'a, 'b>() -> App<'a, 'b> {
|
||||
pub fn execute(matches: &ArgMatches) {
|
||||
// figure out which node the user is describing
|
||||
let id = matches
|
||||
.value_of("id")
|
||||
.value_of(ID_ARG_NAME)
|
||||
.expect("Please provide the id of your mixnode");
|
||||
|
||||
// ensure that the mixnode has in fact been initialized
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright 2020 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::commands::override_config;
|
||||
use crate::commands::*;
|
||||
use crate::config::persistence::pathfinder::MixNodePathfinder;
|
||||
use crate::config::Config;
|
||||
use clap::{App, Arg, ArgMatches};
|
||||
@@ -15,61 +15,49 @@ pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
|
||||
App::new("init")
|
||||
.about("Initialise the mixnode")
|
||||
.arg(
|
||||
Arg::with_name("id")
|
||||
.long("id")
|
||||
Arg::with_name(ID_ARG_NAME)
|
||||
.long(ID_ARG_NAME)
|
||||
.help("Id of the nym-mixnode we want to create config for.")
|
||||
.takes_value(true)
|
||||
.required(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("layer")
|
||||
.long("layer")
|
||||
Arg::with_name(LAYER_ARG_NAME)
|
||||
.long(LAYER_ARG_NAME)
|
||||
.help("The mixnet layer of this particular node")
|
||||
.takes_value(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("host")
|
||||
.long("host")
|
||||
Arg::with_name(HOST_ARG_NAME)
|
||||
.long(HOST_ARG_NAME)
|
||||
.help("The host on which the mixnode will be running")
|
||||
.takes_value(true)
|
||||
.required(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("port")
|
||||
.long("port")
|
||||
Arg::with_name(MIX_PORT_ARG_NAME)
|
||||
.long(MIX_PORT_ARG_NAME)
|
||||
.help("The port on which the mixnode will be listening")
|
||||
.takes_value(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("announce-host")
|
||||
.long("announce-host")
|
||||
Arg::with_name(ANNOUNCE_HOST_ARG_NAME)
|
||||
.long(ANNOUNCE_HOST_ARG_NAME)
|
||||
.help("The custom host that will be reported to the directory server")
|
||||
.takes_value(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("announce-port")
|
||||
.long("announce-port")
|
||||
.help("The custom port that will be reported to the directory server")
|
||||
.takes_value(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("validators")
|
||||
.long("validators")
|
||||
Arg::with_name(VALIDATORS_ARG_NAME)
|
||||
.long(VALIDATORS_ARG_NAME)
|
||||
.help("Comma separated list of rest endpoints of the validators")
|
||||
.takes_value(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("mixnet-contract")
|
||||
.long("mixnet-contract")
|
||||
Arg::with_name(CONTRACT_ARG_NAME)
|
||||
.long(CONTRACT_ARG_NAME)
|
||||
.help("Address of the validator contract managing the network")
|
||||
.takes_value(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("metrics-server")
|
||||
.long("metrics-server")
|
||||
.help("Server to which the node is sending all metrics data")
|
||||
.takes_value(true),
|
||||
)
|
||||
}
|
||||
|
||||
async fn choose_layer(
|
||||
@@ -78,7 +66,10 @@ async fn choose_layer(
|
||||
mixnet_contract: String,
|
||||
) -> u64 {
|
||||
let max_layer = DEFAULT_NUM_MIX_HOPS;
|
||||
if let Some(layer) = matches.value_of("layer").map(|layer| layer.parse::<u64>()) {
|
||||
if let Some(layer) = matches
|
||||
.value_of(LAYER_ARG_NAME)
|
||||
.map(|layer| layer.parse::<u64>())
|
||||
{
|
||||
if let Err(err) = layer {
|
||||
// if layer was overridden, it must be parsable
|
||||
panic!("Invalid layer value provided - {:?}", err);
|
||||
@@ -139,7 +130,8 @@ fn show_bonding_info(config: &Config) {
|
||||
"\nTo bond your mixnode you will need to provide the following:
|
||||
Identity key: {}
|
||||
Sphinx key: {}
|
||||
Host: {}
|
||||
Address: {}
|
||||
Mix port: {}
|
||||
Layer: {}
|
||||
Location: [physical location of your node's server]
|
||||
Version: {}
|
||||
@@ -147,6 +139,7 @@ fn show_bonding_info(config: &Config) {
|
||||
identity_keypair.public_key().to_base58_string(),
|
||||
sphinx_keypair.public_key().to_base58_string(),
|
||||
config.get_announce_address(),
|
||||
config.get_mix_port(),
|
||||
config.get_layer(),
|
||||
config.get_version(),
|
||||
);
|
||||
@@ -157,7 +150,7 @@ pub fn execute(matches: &ArgMatches) {
|
||||
// and then removing runtime from mixnode itself in `run`
|
||||
let rt = Runtime::new().unwrap();
|
||||
rt.block_on(async {
|
||||
let id = matches.value_of("id").unwrap();
|
||||
let id = matches.value_of(ID_ARG_NAME).unwrap();
|
||||
println!("Initialising mixnode {}...", id);
|
||||
|
||||
let already_init = if Config::default_config_file_path(id).exists() {
|
||||
|
||||
+25
-22
@@ -11,6 +11,14 @@ pub(crate) mod run;
|
||||
pub(crate) mod sign;
|
||||
pub(crate) mod upgrade;
|
||||
|
||||
pub(crate) const ID_ARG_NAME: &str = "id";
|
||||
pub(crate) const HOST_ARG_NAME: &str = "host";
|
||||
pub(crate) const LAYER_ARG_NAME: &str = "layer";
|
||||
pub(crate) const MIX_PORT_ARG_NAME: &str = "mix-port";
|
||||
pub(crate) const VALIDATORS_ARG_NAME: &str = "validators";
|
||||
pub(crate) const CONTRACT_ARG_NAME: &str = "mixnet-contract";
|
||||
pub(crate) const ANNOUNCE_HOST_ARG_NAME: &str = "announce-host";
|
||||
|
||||
fn parse_validators(raw: &str) -> Vec<String> {
|
||||
raw.split(',')
|
||||
.map(|raw_validator| raw_validator.trim().into())
|
||||
@@ -20,12 +28,15 @@ fn parse_validators(raw: &str) -> Vec<String> {
|
||||
pub(crate) fn override_config(mut config: Config, matches: &ArgMatches) -> Config {
|
||||
let max_layer = DEFAULT_NUM_MIX_HOPS;
|
||||
let mut was_host_overridden = false;
|
||||
if let Some(host) = matches.value_of("host") {
|
||||
config = config.with_listening_host(host);
|
||||
if let Some(host) = matches.value_of(HOST_ARG_NAME) {
|
||||
config = config.with_listening_address(host);
|
||||
was_host_overridden = true;
|
||||
}
|
||||
|
||||
if let Some(layer) = matches.value_of("layer").map(|layer| layer.parse::<u64>()) {
|
||||
if let Some(layer) = matches
|
||||
.value_of(LAYER_ARG_NAME)
|
||||
.map(|layer| layer.parse::<u64>())
|
||||
{
|
||||
if let Err(err) = layer {
|
||||
// if layer was overridden, it must be parsable
|
||||
panic!("Invalid layer value provided - {:?}", err);
|
||||
@@ -36,38 +47,30 @@ pub(crate) fn override_config(mut config: Config, matches: &ArgMatches) -> Confi
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(port) = matches.value_of("port").map(|port| port.parse::<u16>()) {
|
||||
if let Some(port) = matches
|
||||
.value_of(MIX_PORT_ARG_NAME)
|
||||
.map(|port| port.parse::<u16>())
|
||||
{
|
||||
if let Err(err) = port {
|
||||
// if port was overridden, it must be parsable
|
||||
panic!("Invalid port value provided - {:?}", err);
|
||||
panic!("Invalid mix port value provided - {:?}", err);
|
||||
}
|
||||
config = config.with_listening_port(port.unwrap());
|
||||
config = config.with_mix_port(port.unwrap());
|
||||
}
|
||||
|
||||
if let Some(raw_validators) = matches.value_of("validators") {
|
||||
if let Some(raw_validators) = matches.value_of(VALIDATORS_ARG_NAME) {
|
||||
config = config.with_custom_validators(parse_validators(raw_validators));
|
||||
}
|
||||
|
||||
if let Some(contract_address) = matches.value_of("mixnet-contract") {
|
||||
if let Some(contract_address) = matches.value_of(CONTRACT_ARG_NAME) {
|
||||
config = config.with_custom_mixnet_contract(contract_address)
|
||||
}
|
||||
|
||||
if let Some(announce_host) = matches.value_of("announce-host") {
|
||||
config = config.with_announce_host(announce_host);
|
||||
if let Some(announce_host) = matches.value_of(ANNOUNCE_HOST_ARG_NAME) {
|
||||
config = config.with_announce_address(announce_host);
|
||||
} else if was_host_overridden {
|
||||
// make sure our 'announce-host' always defaults to 'host'
|
||||
config = config.announce_host_from_listening_host()
|
||||
}
|
||||
|
||||
if let Some(announce_port) = matches
|
||||
.value_of("announce-port")
|
||||
.map(|port| port.parse::<u16>())
|
||||
{
|
||||
if let Err(err) = announce_port {
|
||||
// if port was overridden, it must be parsable
|
||||
panic!("Invalid port value provided - {:?}", err);
|
||||
}
|
||||
config = config.with_announce_port(announce_port.unwrap());
|
||||
config = config.announce_address_from_listening_address()
|
||||
}
|
||||
|
||||
config
|
||||
|
||||
+22
-33
@@ -1,7 +1,7 @@
|
||||
// Copyright 2020 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::commands::override_config;
|
||||
use crate::commands::*;
|
||||
use crate::config::{persistence::pathfinder::MixNodePathfinder, Config};
|
||||
use crate::node::node_description::NodeDescription;
|
||||
use crate::node::MixNode;
|
||||
@@ -15,61 +15,49 @@ pub fn command_args<'a, 'b>() -> App<'a, 'b> {
|
||||
App::new("run")
|
||||
.about("Starts the mixnode")
|
||||
.arg(
|
||||
Arg::with_name("id")
|
||||
.long("id")
|
||||
Arg::with_name(ID_ARG_NAME)
|
||||
.long(ID_ARG_NAME)
|
||||
.help("Id of the nym-mixnode we want to run")
|
||||
.takes_value(true)
|
||||
.required(true),
|
||||
)
|
||||
// the rest of arguments are optional, they are used to override settings in config file
|
||||
.arg(
|
||||
Arg::with_name("layer")
|
||||
.long("layer")
|
||||
Arg::with_name(LAYER_ARG_NAME)
|
||||
.long(LAYER_ARG_NAME)
|
||||
.help("The mixnet layer of this particular node")
|
||||
.takes_value(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("host")
|
||||
.long("host")
|
||||
Arg::with_name(HOST_ARG_NAME)
|
||||
.long(HOST_ARG_NAME)
|
||||
.help("The custom host on which the mixnode will be running")
|
||||
.takes_value(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("port")
|
||||
.long("port")
|
||||
Arg::with_name(MIX_PORT_ARG_NAME)
|
||||
.long(MIX_PORT_ARG_NAME)
|
||||
.help("The port on which the mixnode will be listening")
|
||||
.takes_value(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("announce-host")
|
||||
.long("announce-host")
|
||||
Arg::with_name(ANNOUNCE_HOST_ARG_NAME)
|
||||
.long(ANNOUNCE_HOST_ARG_NAME)
|
||||
.help("The host that will be reported to the directory server")
|
||||
.takes_value(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("announce-port")
|
||||
.long("announce-port")
|
||||
.help("The port that will be reported to the directory server")
|
||||
.takes_value(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("validators")
|
||||
.long("validators")
|
||||
Arg::with_name(VALIDATORS_ARG_NAME)
|
||||
.long(VALIDATORS_ARG_NAME)
|
||||
.help("Comma separated list of rest endpoints of the validators")
|
||||
.takes_value(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("mixnet-contract")
|
||||
.long("mixnet-contract")
|
||||
Arg::with_name(CONTRACT_ARG_NAME)
|
||||
.long(CONTRACT_ARG_NAME)
|
||||
.help("Address of the validator contract managing the network")
|
||||
.takes_value(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("metrics-server")
|
||||
.long("metrics-server")
|
||||
.help("Server to which the node is sending all metrics data")
|
||||
.takes_value(true),
|
||||
)
|
||||
}
|
||||
|
||||
fn show_binding_warning(address: String) {
|
||||
@@ -125,7 +113,7 @@ fn version_check(cfg: &Config) -> bool {
|
||||
}
|
||||
|
||||
pub fn execute(matches: &ArgMatches) {
|
||||
let id = matches.value_of("id").unwrap();
|
||||
let id = matches.value_of(ID_ARG_NAME).unwrap();
|
||||
|
||||
println!("Starting mixnode {}...", id);
|
||||
|
||||
@@ -148,9 +136,8 @@ pub fn execute(matches: &ArgMatches) {
|
||||
let identity_keypair = load_identity_keys(&pathfinder);
|
||||
let sphinx_keypair = load_sphinx_keys(&pathfinder);
|
||||
|
||||
let listening_ip_string = config.get_listening_address().ip().to_string();
|
||||
if special_addresses().contains(&listening_ip_string.as_ref()) {
|
||||
show_binding_warning(listening_ip_string);
|
||||
if special_addresses().contains(&&*config.get_listening_address().to_string()) {
|
||||
show_binding_warning(config.get_listening_address().to_string());
|
||||
}
|
||||
|
||||
println!(
|
||||
@@ -162,7 +149,7 @@ pub fn execute(matches: &ArgMatches) {
|
||||
config.get_listening_address()
|
||||
);
|
||||
println!(
|
||||
"Announcing the following socket address: {}",
|
||||
"Announcing the following address: {}",
|
||||
config.get_announce_address()
|
||||
);
|
||||
|
||||
@@ -170,7 +157,8 @@ pub fn execute(matches: &ArgMatches) {
|
||||
"\nTo bond your mixnode, go to https://web-wallet-finney.nymtech.net/. You will need to provide the following:
|
||||
Identity key: {}
|
||||
Sphinx key: {}
|
||||
Host: {}
|
||||
Address: {}
|
||||
Mix port: {}
|
||||
Layer: {}
|
||||
Location: [physical location of your node's server]
|
||||
Version: {}
|
||||
@@ -178,6 +166,7 @@ pub fn execute(matches: &ArgMatches) {
|
||||
identity_keypair.public_key().to_base58_string(),
|
||||
sphinx_keypair.public_key().to_base58_string(),
|
||||
config.get_announce_address(),
|
||||
config.get_mix_port(),
|
||||
config.get_layer(),
|
||||
config.get_version(),
|
||||
);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use crate::commands::*;
|
||||
use crate::config::{persistence::pathfinder::MixNodePathfinder, Config};
|
||||
use clap::{App, Arg, ArgMatches};
|
||||
use colored::*;
|
||||
@@ -5,19 +6,21 @@ use config::NymConfig;
|
||||
use crypto::asymmetric::identity;
|
||||
use log::error;
|
||||
|
||||
const SIGN_TEXT_ARG_NAME: &str = "text";
|
||||
|
||||
pub fn command_args<'a, 'b>() -> App<'a, 'b> {
|
||||
App::new("sign")
|
||||
.about("Sign text to prove ownership of this mixnode")
|
||||
.arg(
|
||||
Arg::with_name("id")
|
||||
.long("id")
|
||||
Arg::with_name(ID_ARG_NAME)
|
||||
.long(ID_ARG_NAME)
|
||||
.help("The id of the mixnode you want to sign with")
|
||||
.takes_value(true)
|
||||
.required(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("text")
|
||||
.long("text")
|
||||
Arg::with_name(SIGN_TEXT_ARG_NAME)
|
||||
.long(SIGN_TEXT_ARG_NAME)
|
||||
.help("The text to sign")
|
||||
.takes_value(true)
|
||||
.required(true),
|
||||
@@ -34,8 +37,8 @@ fn load_identity_keys(pathfinder: &MixNodePathfinder) -> identity::KeyPair {
|
||||
}
|
||||
|
||||
pub fn execute(matches: &ArgMatches) {
|
||||
let id = matches.value_of("id").unwrap();
|
||||
let text = matches.value_of("text").unwrap();
|
||||
let id = matches.value_of(ID_ARG_NAME).unwrap();
|
||||
let text = matches.value_of(SIGN_TEXT_ARG_NAME).unwrap();
|
||||
|
||||
let config = match Config::load_from_file(id) {
|
||||
Ok(cfg) => cfg,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright 2020 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::commands::*;
|
||||
use crate::config::{
|
||||
default_validator_rest_endpoints, missing_string_value, Config,
|
||||
DEFAULT_MIXNET_CONTRACT_ADDRESS, MISSING_VALUE,
|
||||
@@ -9,10 +10,19 @@ use clap::{App, Arg, ArgMatches};
|
||||
use config::NymConfig;
|
||||
use crypto::asymmetric::identity;
|
||||
use std::fmt::Display;
|
||||
use std::net::SocketAddr;
|
||||
use std::path::PathBuf;
|
||||
use std::process;
|
||||
use std::str::FromStr;
|
||||
use version_checker::{parse_version, Version};
|
||||
|
||||
const CURRENT_VERSION_ARG_NAME: &str = "current-version";
|
||||
|
||||
fn fail_upgrade<D1: Display, D2: Display>(from_version: D1, to_version: D2) -> ! {
|
||||
print_failed_upgrade(from_version, to_version);
|
||||
process::exit(1)
|
||||
}
|
||||
|
||||
fn print_start_upgrade<D1: Display, D2: Display>(from: D1, to: D2) {
|
||||
println!(
|
||||
"\n==================\nTrying to upgrade mixnode from {} to {} ...",
|
||||
@@ -37,15 +47,15 @@ fn print_successful_upgrade<D1: Display, D2: Display>(from: D1, to: D2) {
|
||||
pub fn command_args<'a, 'b>() -> App<'a, 'b> {
|
||||
App::new("upgrade").about("Try to upgrade the mixnode")
|
||||
.arg(
|
||||
Arg::with_name("id")
|
||||
.long("id")
|
||||
Arg::with_name(ID_ARG_NAME)
|
||||
.long(ID_ARG_NAME)
|
||||
.help("Id of the nym-mixnode we want to upgrade")
|
||||
.takes_value(true)
|
||||
.required(true),
|
||||
)
|
||||
// the rest of arguments depend on the upgrade path
|
||||
.arg(Arg::with_name("current version")
|
||||
.long("current-version")
|
||||
.arg(Arg::with_name(CURRENT_VERSION_ARG_NAME)
|
||||
.long(CURRENT_VERSION_ARG_NAME)
|
||||
.help("REQUIRED FOR PRE-0.9.0 UPGRADES. Specifies current version of the configuration file to help to determine a valid upgrade path. Valid formats include '0.8.1', 'v0.8.1' or 'V0.8.1'")
|
||||
.takes_value(true)
|
||||
)
|
||||
@@ -123,28 +133,24 @@ fn pre_090_upgrade(from: &str, config: Config) -> Config {
|
||||
if from_version.major == 0 && from_version.minor < 8 {
|
||||
// technically this could be implemented, but is there any point in that?
|
||||
eprintln!("upgrading node from before v0.8.0 is not supported. Please run `init` with new binary instead");
|
||||
print_failed_upgrade(&from_version, &to_version);
|
||||
process::exit(1)
|
||||
fail_upgrade(&from_version, &to_version)
|
||||
}
|
||||
|
||||
if (from_version.major == 0 && from_version.minor >= 9) || from_version.major >= 1 {
|
||||
eprintln!("self reported version is higher than 0.9.0. Those releases should have already contained version numbers in config! Make sure you provided correct version");
|
||||
print_failed_upgrade(&from_version, &to_version);
|
||||
process::exit(1)
|
||||
fail_upgrade(&from_version, &to_version)
|
||||
}
|
||||
|
||||
if config.get_private_identity_key_file() != missing_string_value::<PathBuf>()
|
||||
|| config.get_public_identity_key_file() != missing_string_value::<PathBuf>()
|
||||
{
|
||||
eprintln!("existing config seems to have specified identity keys which were only introduced in 0.9.0! Can't perform upgrade.");
|
||||
print_failed_upgrade(&from_version, &to_version);
|
||||
process::exit(1);
|
||||
fail_upgrade(&from_version, &to_version)
|
||||
}
|
||||
|
||||
if config.get_validator_rest_endpoints()[0] != missing_string_value::<String>() {
|
||||
eprintln!("existing config seems to have specified new validator rest endpoint which was only introduced in 0.9.0! Can't perform upgrade.");
|
||||
print_failed_upgrade(&from_version, &to_version);
|
||||
process::exit(1);
|
||||
fail_upgrade(&from_version, &to_version)
|
||||
}
|
||||
|
||||
let mut upgraded_config = config
|
||||
@@ -175,8 +181,7 @@ fn pre_090_upgrade(from: &str, config: Config) -> Config {
|
||||
|
||||
upgraded_config.save_to_file(None).unwrap_or_else(|err| {
|
||||
eprintln!("failed to overwrite config file! - {:?}", err);
|
||||
print_failed_upgrade(&from_version, &to_version);
|
||||
process::exit(1);
|
||||
fail_upgrade(&from_version, &to_version)
|
||||
});
|
||||
|
||||
print_successful_upgrade(from_version, to_version);
|
||||
@@ -200,8 +205,7 @@ fn minor_010_upgrade(
|
||||
|
||||
if config.get_validator_mixnet_contract_address() != MISSING_VALUE {
|
||||
eprintln!("existing config seems to have specified mixnet contract address which was only introduced in 0.10.0! Can't perform upgrade.");
|
||||
print_failed_upgrade(&config_version, &to_version);
|
||||
process::exit(1);
|
||||
fail_upgrade(&config_version, to_version)
|
||||
}
|
||||
|
||||
println!(
|
||||
@@ -221,8 +225,7 @@ fn minor_010_upgrade(
|
||||
|
||||
upgraded_config.save_to_file(None).unwrap_or_else(|err| {
|
||||
eprintln!("failed to overwrite config file! - {:?}", err);
|
||||
print_failed_upgrade(&config_version, &to_version);
|
||||
process::exit(1);
|
||||
fail_upgrade(&config_version, &to_version)
|
||||
});
|
||||
|
||||
print_successful_upgrade(config_version, to_version);
|
||||
@@ -246,8 +249,56 @@ fn patch_010_upgrade(
|
||||
|
||||
upgraded_config.save_to_file(None).unwrap_or_else(|err| {
|
||||
eprintln!("failed to overwrite config file! - {:?}", err);
|
||||
print_failed_upgrade(&config_version, &to_version);
|
||||
process::exit(1);
|
||||
fail_upgrade(&config_version, to_version)
|
||||
});
|
||||
|
||||
print_successful_upgrade(config_version, to_version);
|
||||
|
||||
upgraded_config
|
||||
}
|
||||
|
||||
// TODO: to be renamed once the release version is decided (so presumably either 0.10.2 or 0.11.0)
|
||||
fn undetermined_version_upgrade(
|
||||
config: Config,
|
||||
_matches: &ArgMatches,
|
||||
config_version: &Version,
|
||||
package_version: &Version,
|
||||
) -> Config {
|
||||
// If we decide this version should be tagged with 0.11.0, then the following code will be used instead:
|
||||
// let to_version = if package_version.major == 0 && package_version.minor == 11 {
|
||||
// package_version.clone()
|
||||
// } else {
|
||||
// Version::new(0, 11, 0)
|
||||
// };
|
||||
let to_version = package_version;
|
||||
|
||||
print_start_upgrade(&config_version, &to_version);
|
||||
|
||||
let current_annnounce_addr = config.get_announce_address();
|
||||
// try to parse it as socket address directly
|
||||
let (announce_address, custom_mix_port) = match SocketAddr::from_str(¤t_annnounce_addr) {
|
||||
Ok(addr) => (addr.ip().to_string(), addr.port()),
|
||||
Err(_) => {
|
||||
let announce_split = current_annnounce_addr.split(':').collect::<Vec<_>>();
|
||||
if announce_split.len() != 2 {
|
||||
eprintln!("failed to correctly parse current announce host");
|
||||
fail_upgrade(&config_version, &to_version)
|
||||
}
|
||||
(
|
||||
announce_split[0].to_string(),
|
||||
announce_split[1].parse().unwrap(),
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
let upgraded_config = config
|
||||
.with_custom_version(to_version.to_string().as_ref())
|
||||
.with_announce_address(announce_address)
|
||||
.with_mix_port(custom_mix_port);
|
||||
|
||||
upgraded_config.save_to_file(None).unwrap_or_else(|err| {
|
||||
eprintln!("failed to overwrite config file! - {:?}", err);
|
||||
fail_upgrade(&config_version, to_version)
|
||||
});
|
||||
|
||||
print_successful_upgrade(config_version, to_version);
|
||||
@@ -267,7 +318,15 @@ fn do_upgrade(mut config: Config, matches: &ArgMatches, package_version: Version
|
||||
config = match config_version.major {
|
||||
0 => match config_version.minor {
|
||||
9 => minor_010_upgrade(config, matches, &config_version, &package_version),
|
||||
10 => patch_010_upgrade(config, matches, &config_version, &package_version),
|
||||
10 => match config_version.patch {
|
||||
0 => patch_010_upgrade(config, matches, &config_version, &package_version),
|
||||
_ => undetermined_version_upgrade(
|
||||
config,
|
||||
matches,
|
||||
&config_version,
|
||||
&package_version,
|
||||
),
|
||||
},
|
||||
_ => unsupported_upgrade(config_version, package_version),
|
||||
},
|
||||
_ => unsupported_upgrade(config_version, package_version),
|
||||
@@ -278,7 +337,7 @@ fn do_upgrade(mut config: Config, matches: &ArgMatches, package_version: Version
|
||||
pub fn execute(matches: &ArgMatches) {
|
||||
let package_version = parse_package_version();
|
||||
|
||||
let id = matches.value_of("id").unwrap();
|
||||
let id = matches.value_of(ID_ARG_NAME).unwrap();
|
||||
|
||||
let mut existing_config = Config::load_from_file(id).unwrap_or_else(|err| {
|
||||
eprintln!("failed to load existing config file! - {:?}", err);
|
||||
@@ -287,12 +346,15 @@ pub fn execute(matches: &ArgMatches) {
|
||||
|
||||
// versions fields were added in 0.9.0
|
||||
if existing_config.get_version() == missing_string_value::<String>() {
|
||||
let self_reported_version = matches.value_of("current version").unwrap_or_else(|| {
|
||||
eprintln!(
|
||||
let self_reported_version =
|
||||
matches
|
||||
.value_of(CURRENT_VERSION_ARG_NAME)
|
||||
.unwrap_or_else(|| {
|
||||
eprintln!(
|
||||
"trying to upgrade from pre v0.9.0 without providing current system version!"
|
||||
);
|
||||
process::exit(1)
|
||||
});
|
||||
process::exit(1)
|
||||
});
|
||||
|
||||
// upgrades up to 0.9.0
|
||||
existing_config = pre_090_upgrade(self_reported_version, existing_config);
|
||||
|
||||
+73
-91
@@ -3,8 +3,7 @@
|
||||
|
||||
use crate::config::template::config_template;
|
||||
use config::{deserialize_duration, deserialize_validators, NymConfig};
|
||||
use log::error;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde::{Deserialize, Deserializer, Serialize};
|
||||
use std::net::{IpAddr, SocketAddr};
|
||||
use std::path::PathBuf;
|
||||
use std::str::FromStr;
|
||||
@@ -16,11 +15,10 @@ mod template;
|
||||
pub(crate) const MISSING_VALUE: &str = "MISSING VALUE";
|
||||
|
||||
// 'MIXNODE'
|
||||
const DEFAULT_LISTENING_PORT: u16 = 1789;
|
||||
const DEFAULT_MIX_LISTENING_PORT: u16 = 1789;
|
||||
pub(crate) const DEFAULT_VALIDATOR_REST_ENDPOINTS: &[&str] = &[
|
||||
"http://testnet-finney-validator.nymtech.net:1317",
|
||||
"http://testnet-finney-validator2.nymtech.net:1317",
|
||||
"http://mixnet.club:1317",
|
||||
];
|
||||
pub const DEFAULT_MIXNET_CONTRACT_ADDRESS: &str = "hal1k0jntykt7e4g3y88ltc60czgjuqdy4c9c6gv94";
|
||||
|
||||
@@ -58,13 +56,37 @@ pub fn missing_vec_string_value() -> Vec<String> {
|
||||
vec![missing_string_value()]
|
||||
}
|
||||
|
||||
fn bind_all_address() -> IpAddr {
|
||||
"0.0.0.0".parse().unwrap()
|
||||
}
|
||||
|
||||
fn default_mix_port() -> u16 {
|
||||
DEFAULT_MIX_LISTENING_PORT
|
||||
}
|
||||
|
||||
// basically a migration helper that deserialises string representation of a maybe socket addr (like "1.1.1.1:1234")
|
||||
// into just the ipaddr (like "1.1.1.1")
|
||||
pub(super) fn de_ipaddr_from_maybe_str_socks_addr<'de, D>(
|
||||
deserializer: D,
|
||||
) -> Result<IpAddr, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
let s = String::deserialize(deserializer)?;
|
||||
if let Ok(socket_addr) = SocketAddr::from_str(&s) {
|
||||
Ok(socket_addr.ip())
|
||||
} else {
|
||||
IpAddr::from_str(&s).map_err(serde::de::Error::custom)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct Config {
|
||||
mixnode: MixNode,
|
||||
|
||||
#[serde(default)]
|
||||
rtt_measurement: RttMeasurement,
|
||||
verloc: Verloc,
|
||||
#[serde(default)]
|
||||
logging: Logging,
|
||||
#[serde(default)]
|
||||
@@ -152,80 +174,34 @@ impl Config {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_listening_host<S: Into<String>>(mut self, host: S) -> Self {
|
||||
// see if the provided `host` is just an ip address or ip:port
|
||||
let host = host.into();
|
||||
|
||||
// is it ip:port?
|
||||
match SocketAddr::from_str(host.as_ref()) {
|
||||
Ok(socket_addr) => {
|
||||
self.mixnode.listening_address = socket_addr;
|
||||
self
|
||||
}
|
||||
// try just for ip
|
||||
Err(_) => match IpAddr::from_str(host.as_ref()) {
|
||||
Ok(ip_addr) => {
|
||||
self.mixnode.listening_address.set_ip(ip_addr);
|
||||
self
|
||||
}
|
||||
Err(_) => {
|
||||
error!(
|
||||
"failed to make any changes to config - invalid host {}",
|
||||
host
|
||||
);
|
||||
self
|
||||
}
|
||||
},
|
||||
pub fn with_listening_address<S: Into<String>>(mut self, listening_address: S) -> Self {
|
||||
let listening_address_string = listening_address.into();
|
||||
if let Ok(ip_addr) = listening_address_string.parse() {
|
||||
self.mixnode.listening_address = ip_addr
|
||||
} else {
|
||||
error!(
|
||||
"failed to change listening address. the provided value ({}) was invalid",
|
||||
listening_address_string
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_listening_port(mut self, port: u16) -> Self {
|
||||
self.mixnode.listening_address.set_port(port);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_announce_host<S: Into<String>>(mut self, host: S) -> Self {
|
||||
// this is slightly more complicated as we store announce information as String,
|
||||
// since it might not necessarily be a valid SocketAddr (say `nymtech.net:8080` is a valid
|
||||
// announce address, yet invalid SocketAddr`
|
||||
|
||||
// first lets see if we received host:port or just host part of an address
|
||||
let host = host.into();
|
||||
match host.split(':').count() {
|
||||
1 => {
|
||||
// we provided only 'host' part so we are going to reuse existing port
|
||||
self.mixnode.announce_address =
|
||||
format!("{}:{}", host, self.mixnode.listening_address.port());
|
||||
self
|
||||
}
|
||||
2 => {
|
||||
// we provided 'host:port' so just put the whole thing there
|
||||
self.mixnode.announce_address = host;
|
||||
self
|
||||
}
|
||||
_ => {
|
||||
// we provided something completely invalid, so don't try to parse it
|
||||
error!(
|
||||
"failed to make any changes to config - invalid announce host {}",
|
||||
host
|
||||
);
|
||||
self
|
||||
}
|
||||
}
|
||||
pub fn with_announce_address<S: Into<String>>(mut self, announce_address: S) -> Self {
|
||||
self.mixnode.announce_address = announce_address.into();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn announce_host_from_listening_host(mut self) -> Self {
|
||||
pub fn with_mix_port(mut self, port: u16) -> Self {
|
||||
self.mixnode.mix_port = port;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn announce_address_from_listening_address(mut self) -> Self {
|
||||
self.mixnode.announce_address = self.mixnode.listening_address.to_string();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_announce_port(mut self, port: u16) -> Self {
|
||||
let current_host: Vec<_> = self.mixnode.announce_address.split(':').collect();
|
||||
debug_assert_eq!(current_host.len(), 2);
|
||||
self.mixnode.announce_address = format!("{}:{}", current_host[0], port);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_custom_version(mut self, version: &str) -> Self {
|
||||
self.mixnode.version = version.to_string();
|
||||
self
|
||||
@@ -272,7 +248,7 @@ impl Config {
|
||||
self.mixnode.layer
|
||||
}
|
||||
|
||||
pub fn get_listening_address(&self) -> SocketAddr {
|
||||
pub fn get_listening_address(&self) -> IpAddr {
|
||||
self.mixnode.listening_address
|
||||
}
|
||||
|
||||
@@ -280,6 +256,10 @@ impl Config {
|
||||
self.mixnode.announce_address.clone()
|
||||
}
|
||||
|
||||
pub fn get_mix_port(&self) -> u16 {
|
||||
self.mixnode.mix_port
|
||||
}
|
||||
|
||||
pub fn get_packet_forwarding_initial_backoff(&self) -> Duration {
|
||||
self.debug.packet_forwarding_initial_backoff
|
||||
}
|
||||
@@ -305,27 +285,27 @@ impl Config {
|
||||
}
|
||||
|
||||
pub fn get_measurement_packets_per_node(&self) -> usize {
|
||||
self.rtt_measurement.packets_per_node
|
||||
self.verloc.packets_per_node
|
||||
}
|
||||
pub fn get_measurement_packet_timeout(&self) -> Duration {
|
||||
self.rtt_measurement.packet_timeout
|
||||
self.verloc.packet_timeout
|
||||
}
|
||||
|
||||
pub fn get_measurement_connection_timeout(&self) -> Duration {
|
||||
self.rtt_measurement.connection_timeout
|
||||
self.verloc.connection_timeout
|
||||
}
|
||||
|
||||
pub fn get_measurement_delay_between_packets(&self) -> Duration {
|
||||
self.rtt_measurement.delay_between_packets
|
||||
self.verloc.delay_between_packets
|
||||
}
|
||||
pub fn get_measurement_tested_nodes_batch_size(&self) -> usize {
|
||||
self.rtt_measurement.tested_nodes_batch_size
|
||||
self.verloc.tested_nodes_batch_size
|
||||
}
|
||||
pub fn get_measurement_testing_interval(&self) -> Duration {
|
||||
self.rtt_measurement.testing_interval
|
||||
self.verloc.testing_interval
|
||||
}
|
||||
pub fn get_measurement_retry_timeout(&self) -> Duration {
|
||||
self.rtt_measurement.retry_timeout
|
||||
self.verloc.retry_timeout
|
||||
}
|
||||
|
||||
// upgrade-specific
|
||||
@@ -349,17 +329,20 @@ pub struct MixNode {
|
||||
/// Layer of this particular mixnode determining its position in the network.
|
||||
layer: u64,
|
||||
|
||||
/// Socket address to which this mixnode will bind to and will be listening for packets.
|
||||
listening_address: SocketAddr,
|
||||
/// Address to which this mixnode will bind to and will be listening for packets.
|
||||
#[serde(deserialize_with = "de_ipaddr_from_maybe_str_socks_addr")]
|
||||
listening_address: IpAddr,
|
||||
|
||||
/// Optional address announced to the validator for the clients to connect to.
|
||||
/// It is useful, say, in NAT scenarios or wanting to more easily update actual IP address
|
||||
/// later on by using name resolvable with a DNS query, such as `nymtech.net:8080`.
|
||||
/// Additionally a custom port can be provided, so both `nymtech.net:8080` and `nymtech.net`
|
||||
/// are valid announce addresses, while the later will default to whatever port is used for
|
||||
/// `listening_address`.
|
||||
/// later on by using name resolvable with a DNS query, such as `nymtech.net`.
|
||||
announce_address: String,
|
||||
|
||||
/// Port used for listening for all mixnet traffic.
|
||||
/// (default: 1789)
|
||||
#[serde(default = "default_mix_port")]
|
||||
mix_port: u16,
|
||||
|
||||
/// Path to file containing private identity key.
|
||||
#[serde(default = "missing_string_value")]
|
||||
private_identity_key_file: PathBuf,
|
||||
@@ -374,7 +357,7 @@ pub struct MixNode {
|
||||
/// Path to file containing public sphinx key.
|
||||
public_sphinx_key_file: PathBuf,
|
||||
|
||||
/// Validator server to which the node will be reporting their presence data.
|
||||
/// Validator server from which the node gets the view on the network.
|
||||
#[serde(
|
||||
deserialize_with = "deserialize_validators",
|
||||
default = "missing_vec_string_value",
|
||||
@@ -415,10 +398,9 @@ impl Default for MixNode {
|
||||
version: env!("CARGO_PKG_VERSION").to_string(),
|
||||
id: "".to_string(),
|
||||
layer: 0,
|
||||
listening_address: format!("0.0.0.0:{}", DEFAULT_LISTENING_PORT)
|
||||
.parse()
|
||||
.unwrap(),
|
||||
announce_address: format!("127.0.0.1:{}", DEFAULT_LISTENING_PORT),
|
||||
listening_address: bind_all_address(),
|
||||
announce_address: "127.0.0.1".to_string(),
|
||||
mix_port: DEFAULT_MIX_LISTENING_PORT,
|
||||
private_identity_key_file: Default::default(),
|
||||
public_identity_key_file: Default::default(),
|
||||
private_sphinx_key_file: Default::default(),
|
||||
@@ -442,7 +424,7 @@ impl Default for Logging {
|
||||
|
||||
#[derive(Debug, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct RttMeasurement {
|
||||
pub struct Verloc {
|
||||
/// Specifies number of echo packets sent to each node during a measurement run.
|
||||
packets_per_node: usize,
|
||||
|
||||
@@ -466,9 +448,9 @@ pub struct RttMeasurement {
|
||||
retry_timeout: Duration,
|
||||
}
|
||||
|
||||
impl Default for RttMeasurement {
|
||||
impl Default for Verloc {
|
||||
fn default() -> Self {
|
||||
RttMeasurement {
|
||||
Verloc {
|
||||
packets_per_node: DEFAULT_PACKETS_PER_NODE,
|
||||
connection_timeout: DEFAULT_CONNECTION_TIMEOUT,
|
||||
packet_timeout: DEFAULT_PACKET_TIMEOUT,
|
||||
|
||||
@@ -41,13 +41,14 @@ public_sphinx_key_file = '{{ mixnode.public_sphinx_key_file }}'
|
||||
|
||||
# Optional address announced to the directory server for the clients to connect to.
|
||||
# It is useful, say, in NAT scenarios or wanting to more easily update actual IP address
|
||||
# later on by using name resolvable with a DNS query, such as `nymtech.net:8080`.
|
||||
# Additionally a custom port can be provided, so both `nymtech.net:8080` and `nymtech.net`
|
||||
# are valid announce addresses, while the later will default to whatever port is used for
|
||||
# `listening_address`.
|
||||
# later on by using name resolvable with a DNS query, such as `nymtech.net`.
|
||||
announce_address = '{{ mixnode.announce_address }}'
|
||||
|
||||
# Validator server to which the node will be reporting their presence data.
|
||||
# Port used for listening for all mixnet traffic.
|
||||
# (default: 1789)
|
||||
mix_port = {{ mixnode.mix_port }}
|
||||
|
||||
# Validator server to which the node will be getting information about the network.
|
||||
validator_rest_urls = [
|
||||
{{#each mixnode.validator_rest_urls }}
|
||||
'{{this}}',
|
||||
|
||||
+12
-5
@@ -17,6 +17,7 @@ use crate::node::packet_delayforwarder::{DelayForwarder, PacketDelayForwardSende
|
||||
use crypto::asymmetric::{encryption, identity};
|
||||
use log::{error, info, warn};
|
||||
use mixnode_common::rtt_measurement::{self, AtomicVerlocResult, RttMeasurer};
|
||||
use std::net::SocketAddr;
|
||||
use std::process;
|
||||
use std::sync::Arc;
|
||||
use tokio::runtime::Runtime;
|
||||
@@ -61,7 +62,7 @@ impl MixNode {
|
||||
|
||||
let mut config = rocket::config::Config::release_default();
|
||||
// bind to the same address as we are using for mixnodes
|
||||
config.address = self.config.get_listening_address().ip();
|
||||
config.address = self.config.get_listening_address();
|
||||
|
||||
let verloc_state = VerlocState::new(atomic_verloc_result);
|
||||
let descriptor = self.descriptor.clone();
|
||||
@@ -106,9 +107,12 @@ impl MixNode {
|
||||
|
||||
let connection_handler = ConnectionHandler::new(packet_processor, delay_forwarding_channel);
|
||||
|
||||
let listener = Listener::new(self.config.get_listening_address());
|
||||
let listening_address = SocketAddr::new(
|
||||
self.config.get_listening_address(),
|
||||
self.config.get_mix_port(),
|
||||
);
|
||||
|
||||
listener.start(connection_handler);
|
||||
Listener::new(listening_address).start(connection_handler);
|
||||
}
|
||||
|
||||
fn start_packet_delay_forwarder(
|
||||
@@ -147,10 +151,11 @@ impl MixNode {
|
||||
|
||||
// use the same binding address with the HARDCODED port for time being (I don't like that approach personally)
|
||||
|
||||
let listening_address = rtt_measurement::replace_port(
|
||||
let listening_address = SocketAddr::new(
|
||||
self.config.get_listening_address(),
|
||||
rtt_measurement::DEFAULT_MEASUREMENT_PORT,
|
||||
);
|
||||
|
||||
let config = rtt_measurement::ConfigBuilder::new()
|
||||
.listening_address(listening_address)
|
||||
.packets_per_node(self.config.get_measurement_packets_per_node())
|
||||
@@ -186,9 +191,11 @@ impl MixNode {
|
||||
}
|
||||
};
|
||||
|
||||
let our_host = self.config.get_announce_address();
|
||||
|
||||
existing_nodes
|
||||
.iter()
|
||||
.find(|node| node.mix_node.host == self.config.get_announce_address())
|
||||
.find(|node| node.mix_node.host == our_host)
|
||||
.map(|node| node.mix_node.identity_key.clone())
|
||||
}
|
||||
|
||||
|
||||
@@ -408,7 +408,7 @@ impl PacketPreparer {
|
||||
gateway_packets.push(mix_packet.pop().unwrap());
|
||||
}
|
||||
packets.push(GatewayPackets::new(
|
||||
node.client_listener,
|
||||
node.clients_address(),
|
||||
node.identity_key,
|
||||
gateway_packets,
|
||||
))
|
||||
@@ -461,10 +461,7 @@ impl PacketPreparer {
|
||||
// we are not testing the gateway from our 'good' topology -> it's probably
|
||||
// situation similar to using 'good' qa-topology but testing testnet nodes.
|
||||
let main_gateway_packets = GatewayPackets::new(
|
||||
self.tested_network
|
||||
.main_v4_gateway()
|
||||
.client_listener
|
||||
.clone(),
|
||||
self.tested_network.main_v4_gateway().clients_address(),
|
||||
main_gateway_id,
|
||||
mix_packets,
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user