Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8cd9b99d72 | |||
| f7093cdc5a |
Generated
+1
@@ -7593,6 +7593,7 @@ dependencies = [
|
||||
"tap",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
"tokio-tun",
|
||||
]
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
use clap::{Args, Subcommand};
|
||||
|
||||
pub mod update_config;
|
||||
pub mod update_cost_params;
|
||||
pub mod vesting_update_config;
|
||||
|
||||
#[derive(Debug, Args)]
|
||||
@@ -21,5 +20,7 @@ pub enum MixnetOperatorsMixnodeSettingsCommands {
|
||||
/// Update mixnode configuration for a mixnode bonded with locked tokens
|
||||
VestingUpdateConfig(vesting_update_config::Args),
|
||||
/// Update mixnode cost parameters
|
||||
UpdateCostParameters(update_cost_params::Args),
|
||||
UpdateCostParameters,
|
||||
/// Update mixnode cost parameters for a mixnode bonded with locked tokens
|
||||
VestingUpdateCostParameters,
|
||||
}
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::context::SigningClient;
|
||||
use clap::Parser;
|
||||
use cosmwasm_std::Uint128;
|
||||
use log::info;
|
||||
use nym_mixnet_contract_common::{MixNodeCostParams, Percent};
|
||||
use nym_validator_client::nyxd::contract_traits::MixnetSigningClient;
|
||||
use nym_validator_client::nyxd::CosmWasmCoin;
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
pub struct Args {
|
||||
#[clap(
|
||||
long,
|
||||
help = "input your profit margin as follows; (so it would be 10, rather than 0.1)"
|
||||
)]
|
||||
pub profit_margin_percent: Option<u8>,
|
||||
|
||||
#[clap(
|
||||
long,
|
||||
help = "operating cost in current DENOMINATION (so it would be 'unym', rather than 'nym')"
|
||||
)]
|
||||
pub interval_operating_cost: Option<u128>,
|
||||
}
|
||||
|
||||
pub async fn update_cost_params(args: Args, client: SigningClient) {
|
||||
let denom = client.current_chain_details().mix_denom.base.as_str();
|
||||
|
||||
let cost_params = MixNodeCostParams {
|
||||
profit_margin_percent: Percent::from_percentage_value(
|
||||
args.profit_margin_percent.unwrap_or(10) as u64,
|
||||
)
|
||||
.unwrap(),
|
||||
interval_operating_cost: CosmWasmCoin {
|
||||
denom: denom.into(),
|
||||
amount: Uint128::new(args.interval_operating_cost.unwrap_or(40_000_000)),
|
||||
},
|
||||
};
|
||||
|
||||
info!("Starting mixnode params updating!");
|
||||
let res = client
|
||||
.update_mixnode_cost_params(cost_params, None)
|
||||
.await
|
||||
.expect("failed to update cost params");
|
||||
|
||||
info!("Cost params result: {:?}", res)
|
||||
}
|
||||
@@ -25,20 +25,12 @@ pub const DEFAULT_CONFIG_FILENAME: &str = "config.toml";
|
||||
|
||||
#[cfg(feature = "dirs")]
|
||||
pub fn must_get_home() -> PathBuf {
|
||||
if let Some(home_dir) = std::env::var_os("NYM_HOME_DIR") {
|
||||
home_dir.into()
|
||||
} else {
|
||||
dirs::home_dir().expect("Failed to evaluate $HOME value")
|
||||
}
|
||||
dirs::home_dir().expect("Failed to evaluate $HOME value")
|
||||
}
|
||||
|
||||
#[cfg(feature = "dirs")]
|
||||
pub fn may_get_home() -> Option<PathBuf> {
|
||||
if let Some(home_dir) = std::env::var_os("NYM_HOME_DIR") {
|
||||
Some(home_dir.into())
|
||||
} else {
|
||||
dirs::home_dir()
|
||||
}
|
||||
dirs::home_dir()
|
||||
}
|
||||
|
||||
pub trait NymConfigTemplate: Serialize {
|
||||
|
||||
@@ -32,6 +32,7 @@ serde = { workspace = true, features = ["derive"] }
|
||||
tap.workspace = true
|
||||
thiserror.workspace = true
|
||||
tokio = { workspace = true, features = ["rt-multi-thread", "net", "io-util"] }
|
||||
tokio-stream = { version = "0.1.11" }
|
||||
|
||||
[target.'cfg(target_os = "linux")'.dependencies]
|
||||
tokio-tun = "0.9.0"
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
use std::net::SocketAddr;
|
||||
use std::{net::SocketAddr, time::Duration};
|
||||
|
||||
use boringtun::x25519;
|
||||
use dashmap::{
|
||||
mapref::one::{Ref, RefMut},
|
||||
DashMap,
|
||||
};
|
||||
use tokio::sync::mpsc::{self};
|
||||
use tokio::{
|
||||
sync::mpsc::{self},
|
||||
time::{error::Elapsed, timeout},
|
||||
};
|
||||
|
||||
use crate::event::Event;
|
||||
|
||||
@@ -14,9 +17,26 @@ use crate::event::Event;
|
||||
pub struct PeerEventSender(mpsc::Sender<Event>);
|
||||
pub(crate) struct PeerEventReceiver(mpsc::Receiver<Event>);
|
||||
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
pub enum PeerEventSenderError {
|
||||
#[error("timeout")]
|
||||
Timeout {
|
||||
#[from]
|
||||
source: Elapsed,
|
||||
},
|
||||
|
||||
#[error("send failed: {source}")]
|
||||
SendError {
|
||||
#[from]
|
||||
source: mpsc::error::SendError<Event>,
|
||||
},
|
||||
}
|
||||
|
||||
impl PeerEventSender {
|
||||
pub(crate) async fn send(&self, event: Event) -> Result<(), mpsc::error::SendError<Event>> {
|
||||
self.0.send(event).await
|
||||
pub(crate) async fn send(&self, event: Event) -> Result<(), PeerEventSenderError> {
|
||||
timeout(Duration::from_millis(1000), self.0.send(event))
|
||||
.await?
|
||||
.map_err(|err| err.into())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,21 +2,61 @@ use std::{
|
||||
collections::HashMap,
|
||||
net::{IpAddr, Ipv4Addr},
|
||||
sync::Arc,
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use etherparse::{InternetSlice, SlicedPacket};
|
||||
use tap::TapFallible;
|
||||
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
||||
use tokio::{
|
||||
io::{AsyncReadExt, AsyncWriteExt},
|
||||
time::timeout,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
active_peers::PeerEventSenderError,
|
||||
event::Event,
|
||||
tun_task_channel::{
|
||||
tun_task_channel, tun_task_response_channel, TunTaskPayload, TunTaskResponseRx,
|
||||
TunTaskResponseTx, TunTaskRx, TunTaskTx,
|
||||
TunTaskResponseSendError, TunTaskResponseTx, TunTaskRx, TunTaskTx,
|
||||
},
|
||||
udp_listener::PeersByIp,
|
||||
};
|
||||
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
pub enum TunDeviceError {
|
||||
#[error("iface: timeout writing to tun device, dropping packet")]
|
||||
TunWriteTimeout,
|
||||
|
||||
#[error("iface: failed forwarding packet to peer: {source}")]
|
||||
ForwardToPeerFailed {
|
||||
#[from]
|
||||
source: PeerEventSenderError,
|
||||
},
|
||||
|
||||
#[error("iface: failed to forward responding packet with tag: {source}")]
|
||||
ForwardNatResponseFailed {
|
||||
#[from]
|
||||
source: TunTaskResponseSendError,
|
||||
},
|
||||
|
||||
#[error("iface: error writing to tun device: {source}")]
|
||||
TunWriteError { source: std::io::Error },
|
||||
|
||||
#[error("unable to parse destination address from packet")]
|
||||
UnableToParseDstAdddress,
|
||||
|
||||
#[error("unable to parse source address from packet")]
|
||||
UnableToParseSrcAddress {
|
||||
#[from]
|
||||
source: etherparse::ReadError,
|
||||
},
|
||||
|
||||
#[error("unable to parse source address from packet: ip header missing")]
|
||||
UnableToParseSrcAddressIpHeaderMissing,
|
||||
|
||||
#[error("unable to lock peer mutex")]
|
||||
FailedToLockPeer,
|
||||
}
|
||||
|
||||
fn setup_tokio_tun_device(name: &str, address: Ipv4Addr, netmask: Ipv4Addr) -> tokio_tun::Tun {
|
||||
log::info!("Creating TUN device with: address={address}, netmask={netmask}");
|
||||
// Read MTU size from env variable NYM_MTU_SIZE, else default to 1420.
|
||||
@@ -38,10 +78,10 @@ fn setup_tokio_tun_device(name: &str, address: Ipv4Addr, netmask: Ipv4Addr) -> t
|
||||
|
||||
pub struct TunDevice {
|
||||
// The TUN device that we read/write to, to send/receive packets
|
||||
tun: tokio_tun::Tun,
|
||||
tun: Option<tokio_tun::Tun>,
|
||||
|
||||
// Incoming data that we should send
|
||||
tun_task_rx: TunTaskRx,
|
||||
tun_task_rx: Option<TunTaskRx>,
|
||||
|
||||
// And when we get replies, this is where we should send it
|
||||
tun_task_response_tx: TunTaskResponseTx,
|
||||
@@ -74,6 +114,14 @@ pub struct AllowedIpsInner {
|
||||
peers_by_ip: Arc<tokio::sync::Mutex<PeersByIp>>,
|
||||
}
|
||||
|
||||
impl AllowedIpsInner {
|
||||
async fn lock(&self) -> Result<tokio::sync::MutexGuard<PeersByIp>, TunDeviceError> {
|
||||
timeout(Duration::from_millis(200), self.peers_by_ip.as_ref().lock())
|
||||
.await
|
||||
.map_err(|_| TunDeviceError::FailedToLockPeer)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct NatInner {
|
||||
nat_table: HashMap<IpAddr, u64>,
|
||||
}
|
||||
@@ -104,9 +152,9 @@ impl TunDevice {
|
||||
let (tun_task_response_tx, tun_task_response_rx) = tun_task_response_channel();
|
||||
|
||||
let tun_device = TunDevice {
|
||||
tun_task_rx,
|
||||
tun_task_rx: Some(tun_task_rx),
|
||||
tun_task_response_tx,
|
||||
tun,
|
||||
tun: Some(tun),
|
||||
routing_mode,
|
||||
};
|
||||
|
||||
@@ -114,47 +162,35 @@ impl TunDevice {
|
||||
}
|
||||
|
||||
// Send outbound packets out on the wild internet
|
||||
async fn handle_tun_write(&mut self, data: TunTaskPayload) {
|
||||
let (tag, packet) = data;
|
||||
let Some(dst_addr) = boringtun::noise::Tunn::dst_address(&packet) else {
|
||||
log::error!("Unable to parse dst_address in packet that was supposed to be written to tun device");
|
||||
return;
|
||||
};
|
||||
let Some(src_addr) = parse_src_address(&packet) else {
|
||||
log::error!("Unable to parse src_address in packet that was supposed to be written to tun device");
|
||||
return;
|
||||
};
|
||||
log::info!(
|
||||
"iface: write Packet({src_addr} -> {dst_addr}, {} bytes)",
|
||||
packet.len()
|
||||
);
|
||||
async fn handle_tun_write(&mut self, data: TunTaskPayload) -> Result<(), TunDeviceError> {
|
||||
{
|
||||
let (tag, ref packet) = data;
|
||||
let dst_addr = boringtun::noise::Tunn::dst_address(packet)
|
||||
.ok_or_else(|| TunDeviceError::UnableToParseDstAdddress)?;
|
||||
|
||||
// TODO: expire old entries
|
||||
if let RoutingMode::Nat(nat_table) = &mut self.routing_mode {
|
||||
nat_table.nat_table.insert(src_addr, tag);
|
||||
let src_addr = parse_src_address(packet)?;
|
||||
log::info!(
|
||||
"iface: write Packet({src_addr} -> {dst_addr}, {} bytes)",
|
||||
packet.len()
|
||||
);
|
||||
|
||||
// TODO: expire old entries
|
||||
if let RoutingMode::Nat(nat_table) = &mut self.routing_mode {
|
||||
nat_table.nat_table.insert(src_addr, tag);
|
||||
}
|
||||
}
|
||||
|
||||
tokio::time::timeout(
|
||||
std::time::Duration::from_millis(1000),
|
||||
self.tun.write_all(&packet),
|
||||
)
|
||||
.await
|
||||
.tap_err(|err| {
|
||||
log::error!("iface: write error: {err}");
|
||||
})
|
||||
.ok();
|
||||
// timeout(Duration::from_millis(1000), self.tun.write_all(&data.1))
|
||||
// .await
|
||||
// .map_err(|_| TunDeviceError::TunWriteTimeout)?
|
||||
// .map_err(|err| TunDeviceError::TunWriteError { source: err })
|
||||
}
|
||||
|
||||
// Receive reponse packets from the wild internet
|
||||
async fn handle_tun_read(&self, packet: &[u8]) {
|
||||
let Some(dst_addr) = boringtun::noise::Tunn::dst_address(packet) else {
|
||||
log::error!("Unable to parse dst_address in packet that was read from tun device");
|
||||
return;
|
||||
};
|
||||
let Some(src_addr) = parse_src_address(packet) else {
|
||||
log::error!("Unable to parse src_address in packet that was read from tun device");
|
||||
return;
|
||||
};
|
||||
async fn handle_tun_read(&self, packet: &[u8]) -> Result<(), TunDeviceError> {
|
||||
let dst_addr = boringtun::noise::Tunn::dst_address(packet)
|
||||
.ok_or(TunDeviceError::UnableToParseDstAdddress)?;
|
||||
let src_addr = parse_src_address(packet)?;
|
||||
log::info!(
|
||||
"iface: read Packet({src_addr} -> {dst_addr}, {} bytes)",
|
||||
packet.len(),
|
||||
@@ -165,64 +201,72 @@ impl TunDevice {
|
||||
match self.routing_mode {
|
||||
// This is how wireguard does it, by consulting the AllowedIPs table.
|
||||
RoutingMode::AllowedIps(ref peers_by_ip) => {
|
||||
let Ok(peers) = tokio::time::timeout(
|
||||
std::time::Duration::from_millis(1000),
|
||||
peers_by_ip.peers_by_ip.as_ref().lock(),
|
||||
)
|
||||
.await
|
||||
else {
|
||||
log::error!("Failed to lock peer");
|
||||
return;
|
||||
};
|
||||
|
||||
let peers = peers_by_ip.lock().await?;
|
||||
if let Some(peer_tx) = peers.longest_match(dst_addr).map(|(_, tx)| tx) {
|
||||
log::info!("Forward packet to wg tunnel");
|
||||
tokio::time::timeout(
|
||||
std::time::Duration::from_millis(1000),
|
||||
peer_tx.send(Event::Ip(packet.to_vec().into())),
|
||||
)
|
||||
.await
|
||||
.tap_err(|err| log::error!("Failed to forward packet to wg tunnel: {err}"))
|
||||
.ok();
|
||||
return;
|
||||
return peer_tx
|
||||
.send(Event::Ip(packet.to_vec().into()))
|
||||
.await
|
||||
.map_err(|err| err.into());
|
||||
}
|
||||
}
|
||||
|
||||
// But we can also do it by consulting the NAT table.
|
||||
RoutingMode::Nat(ref nat_table) => {
|
||||
if let Some(tag) = nat_table.nat_table.get(&dst_addr) {
|
||||
log::info!("Forward packet with tag: {tag}");
|
||||
tokio::time::timeout(
|
||||
std::time::Duration::from_millis(1000),
|
||||
self.tun_task_response_tx.send((*tag, packet.to_vec())),
|
||||
)
|
||||
.await
|
||||
.tap_err(|err| log::error!("Failed to foward packet with tag: {err}"))
|
||||
.ok();
|
||||
return;
|
||||
log::info!("Forward packet with NAT tag: {tag}");
|
||||
return self
|
||||
.tun_task_response_tx
|
||||
.send((*tag, packet.to_vec()))
|
||||
.await
|
||||
.map_err(|err| err.into());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log::info!("No peer found, packet dropped");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn run(mut self) {
|
||||
let mut buf = [0u8; 65535];
|
||||
|
||||
let tun_task_rx_stream =
|
||||
tokio_stream::wrappers::ReceiverStream::new(self.tun_task_rx.take().unwrap().0);
|
||||
use futures::StreamExt;
|
||||
let tun_task_rx_stream = tun_task_rx_stream.map(|data| {
|
||||
//{
|
||||
// let (tag, ref packet) = data;
|
||||
// let dst_addr = boringtun::noise::Tunn::dst_address(packet).unwrap();
|
||||
// // .ok_or_else(|| TunDeviceError::UnableToParseDstAdddress)?;
|
||||
|
||||
// let src_addr = parse_src_address(packet).unwrap();
|
||||
// log::info!(
|
||||
// "iface: write Packet({src_addr} -> {dst_addr}, {} bytes)",
|
||||
// packet.len()
|
||||
// );
|
||||
|
||||
// // TODO: expire old entries
|
||||
// // if let RoutingMode::Nat(nat_table) = &mut self.routing_mode {
|
||||
// // nat_table.nat_table.insert(src_addr, tag);
|
||||
// // }
|
||||
//}
|
||||
// data.1
|
||||
4
|
||||
});
|
||||
|
||||
let (mut tun_read, tun_write) = tokio::io::split(self.tun);
|
||||
|
||||
loop {
|
||||
tokio::select! {
|
||||
// Reading from the TUN device
|
||||
len = self.tun.read(&mut buf) => match len {
|
||||
// len = self.tun.read(&mut buf) => match len {
|
||||
len = tun_read.read(&mut buf) => match len {
|
||||
Ok(len) => {
|
||||
let packet = &buf[..len];
|
||||
tokio::time::timeout(
|
||||
std::time::Duration::from_millis(1000),
|
||||
self.handle_tun_read(packet)
|
||||
)
|
||||
.await
|
||||
.tap_err(|_err| log::error!("Failed: handle_tun_read timeout"))
|
||||
.ok();
|
||||
if let Err(err) = self.handle_tun_read(packet).await {
|
||||
log::error!("iface: handle_tun_read failed: {err}")
|
||||
}
|
||||
},
|
||||
Err(err) => {
|
||||
log::info!("iface: read error: {err}");
|
||||
@@ -230,15 +274,14 @@ impl TunDevice {
|
||||
}
|
||||
},
|
||||
// Writing to the TUN device
|
||||
Some(data) = self.tun_task_rx.recv() => {
|
||||
tokio::time::timeout(
|
||||
std::time::Duration::from_millis(1000),
|
||||
self.handle_tun_write(data)
|
||||
)
|
||||
.await
|
||||
.tap_err(|_err| log::error!("Failed: handle_tun_write timeout"))
|
||||
.ok();
|
||||
}
|
||||
//Some(data) = self.tun_task_rx.recv() => {
|
||||
// if let Err(err) = self.handle_tun_write(data).await {
|
||||
// log::error!("ifcae: handle_tun_write failed: {err}");
|
||||
// }
|
||||
//}
|
||||
// res = self.tun.send_all(&mut tun_task_rx_stream) => {
|
||||
// log::error!("finished");
|
||||
// }
|
||||
}
|
||||
}
|
||||
// log::info!("TUN device shutting down");
|
||||
@@ -249,12 +292,11 @@ impl TunDevice {
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_src_address(packet: &[u8]) -> Option<IpAddr> {
|
||||
let headers = SlicedPacket::from_ip(packet)
|
||||
.tap_err(|err| log::error!("Unable to parse IP packet: {err:?}"))
|
||||
.ok()?;
|
||||
Some(match headers.ip? {
|
||||
InternetSlice::Ipv4(ip, _) => ip.source_addr().into(),
|
||||
InternetSlice::Ipv6(ip, _) => ip.source_addr().into(),
|
||||
})
|
||||
fn parse_src_address(packet: &[u8]) -> Result<IpAddr, TunDeviceError> {
|
||||
let headers = SlicedPacket::from_ip(packet)?;
|
||||
match headers.ip {
|
||||
Some(InternetSlice::Ipv4(ip, _)) => Ok(ip.source_addr().into()),
|
||||
Some(InternetSlice::Ipv6(ip, _)) => Ok(ip.source_addr().into()),
|
||||
None => Err(TunDeviceError::UnableToParseSrcAddressIpHeaderMissing),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,17 @@
|
||||
use tokio::sync::mpsc;
|
||||
use std::time::Duration;
|
||||
|
||||
use tokio::{
|
||||
sync::mpsc::{self, error::SendError},
|
||||
time::{error::Elapsed, timeout},
|
||||
};
|
||||
|
||||
pub(crate) type TunTaskPayload = (u64, Vec<u8>);
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct TunTaskTx(mpsc::Sender<TunTaskPayload>);
|
||||
pub(crate) struct TunTaskRx(mpsc::Receiver<TunTaskPayload>);
|
||||
pub(crate) struct TunTaskRx(pub(crate) mpsc::Receiver<TunTaskPayload>);
|
||||
|
||||
pub(crate) struct TunTaskRxStream(pub(crate) tokio_stream::wrappers::ReceiverStream<TunTaskPayload>);
|
||||
|
||||
impl TunTaskTx {
|
||||
pub async fn send(
|
||||
@@ -30,12 +37,20 @@ pub(crate) fn tun_task_channel() -> (TunTaskTx, TunTaskRx) {
|
||||
pub(crate) struct TunTaskResponseTx(mpsc::Sender<TunTaskPayload>);
|
||||
pub struct TunTaskResponseRx(mpsc::Receiver<TunTaskPayload>);
|
||||
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
pub enum TunTaskResponseSendError {
|
||||
#[error("failed to send: timeout")]
|
||||
Timeout(#[from] Elapsed),
|
||||
|
||||
#[error("failed to send: {0}")]
|
||||
SendError(#[from] SendError<TunTaskPayload>),
|
||||
}
|
||||
|
||||
impl TunTaskResponseTx {
|
||||
pub(crate) async fn send(
|
||||
&self,
|
||||
data: TunTaskPayload,
|
||||
) -> Result<(), tokio::sync::mpsc::error::SendError<TunTaskPayload>> {
|
||||
self.0.send(data).await
|
||||
pub(crate) async fn send(&self, data: TunTaskPayload) -> Result<(), TunTaskResponseSendError> {
|
||||
timeout(Duration::from_millis(1000), self.0.send(data))
|
||||
.await?
|
||||
.map_err(|err| err.into())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -81,8 +81,3 @@ cpucycles = [
|
||||
"opentelemetry",
|
||||
"nym-bin-common/tracing",
|
||||
]
|
||||
|
||||
[package.metadata.deb]
|
||||
name = "nym-mixnode"
|
||||
maintainer-scripts = "debian"
|
||||
systemd-units = { enable = false }
|
||||
|
||||
@@ -14,27 +14,3 @@ A Rust mixnode implementation.
|
||||
* `nym-mixnode run --layer 1 --host x.x.x.x` will start the mixnode in layer 1 and bind to the specified host IP address. Coordinate with other people in your network to find out which layer needs coverage.
|
||||
|
||||
By default, the Nym Mixnode will start on port 1789. If desired, you can change the port using the `--port` option.
|
||||
|
||||
## Build debian package
|
||||
|
||||
```bash
|
||||
# cargo install cargo-deb
|
||||
|
||||
# Build package
|
||||
cargo deb -p nym-mixnode
|
||||
|
||||
# Install
|
||||
|
||||
# This will init the mixnode to `/etc/nym` as `nym` user, and create a systemd service
|
||||
sudo dpkg -i target/debian/<PACKAGE>
|
||||
|
||||
# Run
|
||||
sudo systemctl start nym-mixnode
|
||||
|
||||
# Check status
|
||||
sudo systemctl status nym-mixnode
|
||||
|
||||
# Logs
|
||||
journalctl -f -u nym-mixnode
|
||||
|
||||
```
|
||||
@@ -1,6 +0,0 @@
|
||||
#DEBHELPER#
|
||||
|
||||
useradd nym
|
||||
mkdir -p /etc/nym
|
||||
chown -R nym /etc/nym
|
||||
su nym -c 'NYM_HOME_DIR=/etc/nym nym-mixnode init --host 0.0.0.0 --id nym-mixnode'
|
||||
@@ -1,11 +0,0 @@
|
||||
[Unit]
|
||||
Description=Nym Mixnode
|
||||
After=network-online.target
|
||||
|
||||
[Service]
|
||||
ExecStart=/usr/bin/nym-mixnode run --id nym-mixnode
|
||||
User=nym
|
||||
Environment="NYM_HOME_DIR=/etc/nym"
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -13,7 +13,7 @@ This is the application UI layer for the next NymVPN clients.
|
||||
Some system libraries are required depending on the host platform.
|
||||
Follow the instructions for your specific OS [here](https://tauri.app/v1/guides/getting-started/prerequisites)
|
||||
|
||||
To install:
|
||||
To install run
|
||||
|
||||
```
|
||||
yarn
|
||||
|
||||
@@ -16,8 +16,6 @@ in combination with their own configuration. If you are trying to access somethi
|
||||
3. If you are using `mixFetch` in a web app with HTTPS you will need to use a gateway that has Secure Websockets to
|
||||
avoid getting a [mixed content](https://developer.mozilla.org/en-US/docs/Web/Security/Mixed_content) error.
|
||||
|
||||
4. For now, mixfetch doesn't work with SURBS, altough this may change in the future.
|
||||
|
||||
|
||||
Read [this article](https://blog.nymtech.net/mixfetch-like-the-fetch-api-but-via-the-mixnet-82acfd435c62) to learn more about mixFetch.
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ pub(crate) trait ReleasePackage: Sized {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn update_nym_dependencies(&mut self, _: &HashSet<String>, _: bool) -> anyhow::Result<()> {
|
||||
fn update_nym_dependencies(&mut self, _: &HashSet<String>) -> anyhow::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -57,29 +57,28 @@ pub(crate) trait VersionBumpExt: Sized {
|
||||
fn try_remove_prerelease(&self) -> anyhow::Result<Self>;
|
||||
}
|
||||
|
||||
pub(crate) fn try_bump_raw_prerelease(raw: &str) -> anyhow::Result<Prerelease> {
|
||||
// ugh that's disgusting
|
||||
let (rc_prefix, pre_version) = raw
|
||||
.split_once('.')
|
||||
.context("the prerelease version does not contain a valid rc.X suffix")?;
|
||||
|
||||
let parsed_version: u32 = pre_version.parse()?;
|
||||
let updated_version = parsed_version + 1;
|
||||
|
||||
Ok(format!("{rc_prefix}.{updated_version}").parse()?)
|
||||
}
|
||||
|
||||
impl VersionBumpExt for Version {
|
||||
fn try_bump_prerelease(&self) -> anyhow::Result<Self> {
|
||||
if self.pre.is_empty() {
|
||||
bail!("the current version ({self}) does not have pre-release data set - are you sure you followed the release process correctly?")
|
||||
}
|
||||
|
||||
// ugh that's disgusting
|
||||
let (rc_prefix, pre_version) = self
|
||||
.pre
|
||||
.as_str()
|
||||
.split_once('.')
|
||||
.context("the prerelease version does not contain a valid rc.X suffix")?;
|
||||
|
||||
let parsed_version: u32 = pre_version.parse()?;
|
||||
let updated_version = parsed_version + 1;
|
||||
|
||||
let pre = format!("{rc_prefix}.{updated_version}").parse()?;
|
||||
Ok(Version {
|
||||
major: self.major,
|
||||
minor: self.minor,
|
||||
patch: self.patch,
|
||||
pre: try_bump_raw_prerelease(self.pre.as_str())?,
|
||||
pre,
|
||||
build: self.build.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::helpers::try_bump_raw_prerelease;
|
||||
use crate::json_types::DepsSet;
|
||||
use crate::{json_types, ReleasePackage};
|
||||
use anyhow::{bail, Context};
|
||||
@@ -15,18 +14,10 @@ pub struct PackageJson {
|
||||
inner: json_types::Package,
|
||||
}
|
||||
|
||||
fn update_dependencies(
|
||||
deps: &mut DepsSet,
|
||||
names: &HashSet<String>,
|
||||
pre_release: bool,
|
||||
) -> anyhow::Result<()> {
|
||||
fn update_dependencies(deps: &mut DepsSet, names: &HashSet<String>) -> anyhow::Result<()> {
|
||||
for (package, version) in deps.iter_mut() {
|
||||
if names.contains(package) {
|
||||
let updated = if pre_release {
|
||||
try_bump_prerelease_version_req(version)?
|
||||
} else {
|
||||
try_bump_minor_version_req(version)?
|
||||
};
|
||||
let updated = try_bump_minor_version_req(version)?;
|
||||
|
||||
println!("\t\t>>> updating '{package}' from {version} to {updated}");
|
||||
*version = updated
|
||||
@@ -61,25 +52,21 @@ impl ReleasePackage for PackageJson {
|
||||
self.inner.version = version.to_string()
|
||||
}
|
||||
|
||||
fn update_nym_dependencies(
|
||||
&mut self,
|
||||
names: &HashSet<String>,
|
||||
pre_release: bool,
|
||||
) -> anyhow::Result<()> {
|
||||
fn update_nym_dependencies(&mut self, names: &HashSet<String>) -> anyhow::Result<()> {
|
||||
println!("\t>>> updating @nymproject dependencies...");
|
||||
update_dependencies(&mut self.inner.dependencies, names, pre_release)?;
|
||||
update_dependencies(&mut self.inner.dependencies, names)?;
|
||||
|
||||
println!("\t>>> updating @nymproject peerDependencies...");
|
||||
update_dependencies(&mut self.inner.peer_dependencies, names, pre_release)?;
|
||||
update_dependencies(&mut self.inner.peer_dependencies, names)?;
|
||||
|
||||
println!("\t>>> updating @nymproject devDependencies...");
|
||||
update_dependencies(&mut self.inner.dev_dependencies, names, pre_release)?;
|
||||
update_dependencies(&mut self.inner.dev_dependencies, names)?;
|
||||
|
||||
println!("\t>>> updating @nymproject optionalDependencies...");
|
||||
update_dependencies(&mut self.inner.optional_dependencies, names, pre_release)?;
|
||||
update_dependencies(&mut self.inner.optional_dependencies, names)?;
|
||||
|
||||
println!("\t>>> updating @nymproject bundledDependencies...");
|
||||
update_dependencies(&mut self.inner.bundled_dependencies, names, pre_release)?;
|
||||
update_dependencies(&mut self.inner.bundled_dependencies, names)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -114,9 +101,9 @@ pub(crate) fn find_package_path(dir: &Path) -> anyhow::Result<PathBuf> {
|
||||
|
||||
// expected structure: `>=X.Y.Z-rc.W || ^X`
|
||||
fn try_bump_minor_version_req(raw_req: &str) -> anyhow::Result<String> {
|
||||
let (req, major) = raw_req.split_once("||").context(format!(
|
||||
"'{raw_req}' is not a valid semver version requirement - we expect '`>=X.Y.Z-rc.W || ^X`'"
|
||||
))?;
|
||||
let (req, major) = raw_req
|
||||
.split_once("||")
|
||||
.context("invalid version requirement")?;
|
||||
let parsed_req = VersionReq::parse(req)?;
|
||||
let parsed_major = VersionReq::parse(major)?;
|
||||
if parsed_req.comparators.len() != 1 {
|
||||
@@ -136,30 +123,6 @@ fn try_bump_minor_version_req(raw_req: &str) -> anyhow::Result<String> {
|
||||
Ok(format!("{updated} || {parsed_major}"))
|
||||
}
|
||||
|
||||
// expected structure: `>=X.Y.Z-rc.W || ^X`
|
||||
fn try_bump_prerelease_version_req(raw_req: &str) -> anyhow::Result<String> {
|
||||
let (req, major) = raw_req.split_once("||").context(format!(
|
||||
"'{raw_req}' is not a valid semver version requirement - we expect '`>=X.Y.Z-rc.W || ^X`'"
|
||||
))?;
|
||||
let parsed_req = VersionReq::parse(req)?;
|
||||
let parsed_major = VersionReq::parse(major)?;
|
||||
if parsed_req.comparators.len() != 1 {
|
||||
bail!("wrong number of version requirements present in {parsed_req}")
|
||||
}
|
||||
|
||||
let updated = VersionReq {
|
||||
comparators: vec![Comparator {
|
||||
op: parsed_req.comparators[0].op,
|
||||
major: parsed_req.comparators[0].major,
|
||||
minor: parsed_req.comparators[0].minor,
|
||||
patch: parsed_req.comparators[0].patch,
|
||||
pre: try_bump_raw_prerelease(parsed_req.comparators[0].pre.as_str())?,
|
||||
}],
|
||||
};
|
||||
|
||||
Ok(format!("{updated} || {parsed_major}"))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
@@ -5,7 +5,7 @@ use crate::cargo::CargoPackage;
|
||||
use crate::helpers::ReleasePackage;
|
||||
use crate::json::PackageJson;
|
||||
use clap::{Parser, Subcommand};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::collections::HashSet;
|
||||
use std::env;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
@@ -18,48 +18,6 @@ fn default_root() -> PathBuf {
|
||||
env::current_dir().unwrap()
|
||||
}
|
||||
|
||||
struct Summary {
|
||||
cargo_results: HashMap<String, anyhow::Result<()>>,
|
||||
|
||||
json_results: HashMap<String, anyhow::Result<()>>,
|
||||
}
|
||||
|
||||
impl Summary {
|
||||
fn new(
|
||||
cargo_results: HashMap<String, anyhow::Result<()>>,
|
||||
json_results: HashMap<String, anyhow::Result<()>>,
|
||||
) -> Self {
|
||||
Summary {
|
||||
cargo_results,
|
||||
json_results,
|
||||
}
|
||||
}
|
||||
|
||||
fn print(&self) {
|
||||
let cargo_ok = self.cargo_results.values().filter(|p| p.is_ok()).count();
|
||||
let json_ok = self.json_results.values().filter(|p| p.is_ok()).count();
|
||||
|
||||
println!("SUMMARY");
|
||||
println!("inspected {} cargo packages", self.cargo_results.len());
|
||||
println!("updated {cargo_ok} cargo packages");
|
||||
for (package, res) in &self.cargo_results {
|
||||
if let Err(err) = res {
|
||||
println!(
|
||||
"\t>>> ❌ FAILURE: cargo package '{package}' failed to get updated: {err}"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
println!("inspected {} json packages", self.json_results.len());
|
||||
println!("updated {json_ok} json packages");
|
||||
for (package, res) in &self.json_results {
|
||||
if let Err(err) = res {
|
||||
println!("\t>>> ❌ FAILURE: json package '{package}' failed to get updated: {err}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
struct Args {
|
||||
#[arg(default_value=default_root().into_os_string())]
|
||||
@@ -78,13 +36,12 @@ enum Commands {
|
||||
/// It will also update the `@nymproject/...` dependencies from `">=X.Y.Z-rc.0 || ^X"` to `">=X.Y.(Z+1)-rc.0 || ^X"`
|
||||
BumpVersion {
|
||||
#[arg(long)]
|
||||
/// If enabled, the packages will only have their rc version bumped and the dependencies
|
||||
/// will get updated from `">=X.Y.Z-rc.W || ^X"` to `">=X.Y.Z-rc.(W+1) || ^X"`
|
||||
/// If enabled, the packages will only have their rc version bumped and the dependencies won't get updated at all
|
||||
pre_release: bool,
|
||||
},
|
||||
}
|
||||
|
||||
fn remove_suffix<Pkg: ReleasePackage>(root: &Path, path: impl AsRef<Path>) -> anyhow::Result<()> {
|
||||
fn remove_suffix<Pkg: ReleasePackage>(root: &Path, path: impl AsRef<Path>) {
|
||||
let path = root.join(path);
|
||||
println!(
|
||||
">>> [{}] UPDATING PACKAGE {}: ",
|
||||
@@ -94,10 +51,8 @@ fn remove_suffix<Pkg: ReleasePackage>(root: &Path, path: impl AsRef<Path>) -> an
|
||||
|
||||
if let Err(err) = { remove_suffix_inner::<Pkg>(path) } {
|
||||
println!("\t>>> ❌ FAILURE: {err}");
|
||||
Err(err)
|
||||
} else {
|
||||
println!("\t>>> ✅ SUCCESS");
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,7 +70,7 @@ fn bump_version<Pkg: ReleasePackage>(
|
||||
path: impl AsRef<Path>,
|
||||
dependencies_to_update: &HashSet<String>,
|
||||
pre_release: bool,
|
||||
) -> anyhow::Result<()> {
|
||||
) {
|
||||
let path = root.join(path);
|
||||
println!(
|
||||
">>> [{}] UPDATING PACKAGE {}: ",
|
||||
@@ -124,10 +79,8 @@ fn bump_version<Pkg: ReleasePackage>(
|
||||
);
|
||||
if let Err(err) = { bump_version_inner::<Pkg>(path, dependencies_to_update, pre_release) } {
|
||||
println!("\t>>> ❌ FAILURE: {err}");
|
||||
Err(err)
|
||||
} else {
|
||||
println!("\t>>> ✅ SUCCESS");
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,7 +93,9 @@ fn bump_version_inner<Pkg: ReleasePackage>(
|
||||
let mut package = Pkg::open(path)?;
|
||||
package.bump_version(pre_release)?;
|
||||
|
||||
package.update_nym_dependencies(dependencies_to_update, pre_release)?;
|
||||
if !pre_release {
|
||||
package.update_nym_dependencies(dependencies_to_update)?;
|
||||
}
|
||||
|
||||
println!("\t>>> saving the package file...");
|
||||
package.save_changes()
|
||||
@@ -177,46 +132,34 @@ impl InternalPackages {
|
||||
self.internal_js_dependencies.insert(name.into());
|
||||
}
|
||||
|
||||
pub fn remove_suffix(&self) -> Summary {
|
||||
let mut cargo_results = HashMap::new();
|
||||
pub fn remove_suffix(&self) {
|
||||
for cargo_package in &self.cargo {
|
||||
let res = remove_suffix::<CargoPackage>(&self.root, cargo_package);
|
||||
cargo_results.insert(cargo_package.clone(), res);
|
||||
remove_suffix::<CargoPackage>(&self.root, cargo_package);
|
||||
}
|
||||
|
||||
let mut json_results = HashMap::new();
|
||||
for package_json in &self.json {
|
||||
let res = remove_suffix::<PackageJson>(&self.root, package_json);
|
||||
json_results.insert(package_json.clone(), res);
|
||||
remove_suffix::<PackageJson>(&self.root, package_json);
|
||||
}
|
||||
|
||||
Summary::new(cargo_results, json_results)
|
||||
}
|
||||
|
||||
pub fn bump_version(&self, pre_release: bool) -> Summary {
|
||||
let mut cargo_results = HashMap::new();
|
||||
pub fn bump_version(&self, pre_release: bool) {
|
||||
for cargo_package in &self.cargo {
|
||||
let res = bump_version::<CargoPackage>(
|
||||
bump_version::<CargoPackage>(
|
||||
&self.root,
|
||||
cargo_package,
|
||||
&Default::default(),
|
||||
pre_release,
|
||||
);
|
||||
cargo_results.insert(cargo_package.clone(), res);
|
||||
}
|
||||
|
||||
let mut json_results = HashMap::new();
|
||||
for package_json in &self.json {
|
||||
let res = bump_version::<PackageJson>(
|
||||
bump_version::<PackageJson>(
|
||||
&self.root,
|
||||
package_json,
|
||||
&self.internal_js_dependencies,
|
||||
pre_release,
|
||||
);
|
||||
json_results.insert(package_json.clone(), res);
|
||||
}
|
||||
|
||||
Summary::new(cargo_results, json_results)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -283,12 +226,10 @@ fn main() -> anyhow::Result<()> {
|
||||
let args = Args::parse();
|
||||
let packages = initialise_internal_packages(args.root);
|
||||
|
||||
let summary = match args.command {
|
||||
match args.command {
|
||||
Commands::RemoveSuffix => packages.remove_suffix(),
|
||||
Commands::BumpVersion { pre_release } => packages.bump_version(pre_release),
|
||||
};
|
||||
|
||||
summary.print();
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -13,9 +13,6 @@ pub(crate) async fn execute(
|
||||
nym_cli_commands::validator::mixnet::operators::mixnode::settings::MixnetOperatorsMixnodeSettingsCommands::UpdateConfig(args) => {
|
||||
nym_cli_commands::validator::mixnet::operators::mixnode::settings::update_config::update_config(args, create_signing_client(global_args, network_details)?).await
|
||||
}
|
||||
nym_cli_commands::validator::mixnet::operators::mixnode::settings::MixnetOperatorsMixnodeSettingsCommands::UpdateCostParameters(args) => {
|
||||
nym_cli_commands::validator::mixnet::operators::mixnode::settings::update_cost_params::update_cost_params(args, create_signing_client(global_args, network_details)?).await
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
Ok(())
|
||||
|
||||
Reference in New Issue
Block a user