merge develop

This commit is contained in:
fmtabbara
2023-10-16 15:34:08 +01:00
78 changed files with 1295 additions and 2508 deletions
+4 -3
View File
@@ -3,11 +3,12 @@ name: ci-build-ts
on:
push:
paths:
- 'ts-packages/**'
- "ts-packages/**"
- "sdk/typescript/**"
jobs:
build:
runs-on: custom-runner-linux
runs-on: ubuntu-20.04-16-core
steps:
- uses: actions/checkout@v2
- name: Install rsync
@@ -20,7 +21,7 @@ jobs:
- name: Setup yarn
run: npm install -g yarn
- name: Build
run: yarn && yarn build && yarn build:ci
run: yarn && yarn build && yarn build:ci:storybook
- name: Deploy branch to CI www (storybook)
continue-on-error: true
uses: easingthemes/ssh-deploy@main
+2 -2
View File
@@ -28,11 +28,11 @@ jobs:
command: build
args: --workspace --release --all
- name: Install mdbook
run: (test -x $HOME/.cargo/bin/mdbook || cargo install --vers "^0.4.33" mdbook)
run: (test -x $HOME/.cargo/bin/mdbook || cargo install --vers "^0.4.35" mdbook)
- name: Install mdbook plugins
run: |
cargo install --vers "=0.2.2" mdbook-variables && cargo install \
--vers "^1.8.0" mdbook-admonish && cargo install --vers \
--vers "^1.8.0" mdbook-admonish install && cargo install --vers \
"^0.1.2" mdbook-last-changed && cargo install --vers "^0.1.2" mdbook-theme \
&& cargo install --vers "^0.7.7" mdbook-linkcheck
- name: Build all projects in documentation/ & move to ~/dist/docs/
+4 -2
View File
@@ -22,7 +22,7 @@ on:
jobs:
build:
runs-on: custom-runner-linux
runs-on: ubuntu-20.04-16-core
steps:
- uses: actions/checkout@v2
- uses: rlespinasse/github-slug-action@v3.x
@@ -39,6 +39,8 @@ jobs:
toolchain: stable
- name: Install wasm-pack
run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
- name: Install wasm-opt
run: cargo install wasm-opt
- name: Set up Go
uses: actions/setup-go@v4
@@ -49,7 +51,7 @@ jobs:
run: yarn
- name: Build packages
run: yarn build:ci:sdk
run: yarn build:ci
- name: Lint
run: yarn lint
@@ -14,7 +14,7 @@ jobs:
strategy:
fail-fast: false
matrix:
platform: [macos-latest]
platform: [macos-12-large]
runs-on: ${{ matrix.platform }}
outputs:
@@ -14,7 +14,7 @@ jobs:
strategy:
fail-fast: false
matrix:
platform: [macos-latest]
platform: [macos-12-large]
runs-on: ${{ matrix.platform }}
outputs:
+4 -1
View File
@@ -4,7 +4,7 @@ on:
jobs:
publish:
runs-on: [custom-ubuntu-20.04]
runs-on: ubuntu-20.04-16-core
steps:
- uses: actions/checkout@v2
@@ -25,6 +25,9 @@ jobs:
- name: Install wasm-pack
run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
- name: Install wasm-opt
run: cargo install wasm-opt
- name: Install dependencies
run: yarn
Generated
+632 -589
View File
File diff suppressed because it is too large Load Diff
@@ -74,7 +74,7 @@ impl PartiallyDelegated {
fn route_socket_messages(
ws_msgs: Vec<Message>,
packet_router: &mut PacketRouter,
packet_router: &PacketRouter,
shared_key: &SharedKeys,
) -> Result<(), GatewayClientError> {
let plaintexts = Self::recover_received_plaintexts(ws_msgs, shared_key);
@@ -97,7 +97,6 @@ impl PartiallyDelegated {
let mixnet_receiver_future = async move {
let mut notify_receiver = notify_receiver;
let mut chunk_stream = (&mut stream).ready_chunks(8);
let mut packet_router = packet_router;
let ret_err = loop {
tokio::select! {
@@ -115,7 +114,7 @@ impl PartiallyDelegated {
Ok(msgs) => msgs
};
if let Err(err) = Self::route_socket_messages(ws_msgs, &mut packet_router, shared_key.as_ref()) {
if let Err(err) = Self::route_socket_messages(ws_msgs, &packet_router, shared_key.as_ref()) {
log::warn!("Route socket messages failed: {err}");
}
}
@@ -42,7 +42,9 @@ pub trait GatewayPacketRouter {
}
n if n
== PacketSize::OutfoxRegularPacket.plaintext_size() - outfox_ack_overhead =>
== PacketSize::OutfoxRegularPacket
.plaintext_size()
.saturating_sub(outfox_ack_overhead) =>
{
trace!("received regular outfox packet");
received_messages.push(received_packet);
@@ -86,4 +86,5 @@ required-features = ["http-client"]
default = ["http-client"]
http-client = ["cosmrs/rpc", "openssl"]
generate-ts = []
contract-testing = ["nym-mixnet-contract-common/contract-testing"]
@@ -683,13 +683,14 @@ pub trait MixnetSigningClient {
.await
}
#[cfg(feature = "nym_mixnet_contract_common/contract-testing")]
#[cfg(feature = "contract-testing")]
async fn testing_resolve_all_pending_events(
&self,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract(
fee,
MixnetExecuteMsg::TestingResolveAllPendingEvents {},
MixnetExecuteMsg::TestingResolveAllPendingEvents { limit: None },
vec![],
)
.await
@@ -928,8 +929,8 @@ mod tests {
.withdraw_delegator_reward_on_behalf(owner.parse().unwrap(), mix_id, None)
.ignore(),
#[cfg(feature = "nym_mixnet_contract_common/contract-testing")]
MixnetExecuteMsg::TestingResolveAllPendingEvents {} => {
#[cfg(feature = "contract-testing")]
MixnetExecuteMsg::TestingResolveAllPendingEvents { .. } => {
client.testing_resolve_all_pending_events(None).ignore()
}
};
+15 -9
View File
@@ -3,25 +3,31 @@ use std::fmt::{Display, Formatter};
use bytes::Bytes;
#[allow(unused)]
#[derive(Debug, Clone)]
#[derive(Debug)]
pub enum Event {
/// IP packet received from the WireGuard tunnel that should be passed through to the corresponding virtual device/internet.
/// Original implementation also has protocol here since it understands it, but we'll have to infer it downstream
WgPacket(Bytes),
/// IP packet received from the WireGuard tunnel that should be passed through to the
/// corresponding virtual device/internet.
Wg(Bytes),
/// IP packet received from the WireGuard tunnel that was verified as part of the handshake.
WgVerified(Bytes),
/// IP packet to be sent through the WireGuard tunnel as crafted by the virtual device.
IpPacket(Bytes),
Ip(Bytes),
}
impl Display for Event {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Event::WgPacket(data) => {
Event::Wg(data) => {
let size = data.len();
write!(f, "WgPacket{{ size={size} }}")
write!(f, "Wg{{ size={size} }}")
}
Event::IpPacket(data) => {
Event::WgVerified(data) => {
let size = data.len();
write!(f, "IpPacket{{ size={size} }}")
write!(f, "WgVerified{{ size={size} }}")
}
Event::Ip(data) => {
let size = data.len();
write!(f, "Ip{{ size={size} }}")
}
}
}
+10 -3
View File
@@ -1,9 +1,13 @@
#![cfg_attr(not(target_os = "linux"), allow(dead_code))]
// #![warn(clippy::pedantic)]
// #![warn(clippy::expect_used)]
// #![warn(clippy::unwrap_used)]
mod error;
mod event;
mod network_table;
mod platform;
mod registered_peers;
mod setup;
mod udp_listener;
mod wg_tunnel;
@@ -21,21 +25,24 @@ impl TunTaskTx {
}
}
/// Start wireguard UDP listener and TUN device
///
/// # Errors
///
/// This function will return an error if either the UDP listener of the TUN device fails to start.
#[cfg(target_os = "linux")]
pub async fn start_wireguard(
task_client: nym_task::TaskClient,
) -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
use std::sync::Arc;
// The set of active tunnels indexed by the peer's address
let active_peers = Arc::new(udp_listener::ActivePeers::new());
let peers_by_ip = Arc::new(std::sync::Mutex::new(network_table::NetworkTable::new()));
// Start the tun device that is used to relay traffic outbound
let tun_task_tx = tun_device::start_tun_device(peers_by_ip.clone());
// Start the UDP listener that clients connect to
udp_listener::start_udp_listener(tun_task_tx, active_peers, peers_by_ip, task_client).await?;
udp_listener::start_udp_listener(tun_task_tx, peers_by_ip, task_client).await?;
Ok(())
}
@@ -30,7 +30,7 @@ fn setup_tokio_tun_device(name: &str, address: Ipv4Addr, netmask: Ipv4Addr) -> t
pub(crate) fn start_tun_device(peers_by_ip: Arc<std::sync::Mutex<PeersByIp>>) -> TunTaskTx {
let tun = setup_tokio_tun_device(
format!("{}%d", TUN_BASE_NAME).as_str(),
format!("{TUN_BASE_NAME}%d").as_str(),
TUN_DEVICE_ADDRESS.parse().unwrap(),
TUN_DEVICE_NETMASK.parse().unwrap(),
);
@@ -63,7 +63,7 @@ pub(crate) fn start_tun_device(peers_by_ip: Arc<std::sync::Mutex<PeersByIp>>) ->
if let Some(peer_tx) = peers_by_ip.lock().unwrap().longest_match(dst_addr).map(|(_, tx)| tx) {
log::info!("Forward packet to wg tunnel");
peer_tx
.send(Event::IpPacket(packet.to_vec().into()))
.send(Event::Ip(packet.to_vec().into()))
.tap_err(|err| log::error!("{err}"))
.unwrap();
} else {
+56
View File
@@ -0,0 +1,56 @@
use std::{collections::HashMap, sync::Arc};
use boringtun::x25519;
use ip_network::IpNetwork;
pub(crate) type PeerIdx = u32;
#[derive(Debug)]
pub(crate) struct RegisteredPeer {
pub(crate) public_key: x25519::PublicKey,
pub(crate) index: PeerIdx,
pub(crate) allowed_ips: IpNetwork,
// endpoint: SocketAddr,
}
#[derive(Debug, Default)]
pub(crate) struct RegisteredPeers {
peers: HashMap<x25519::PublicKey, Arc<tokio::sync::Mutex<RegisteredPeer>>>,
peers_by_idx: HashMap<PeerIdx, Arc<tokio::sync::Mutex<RegisteredPeer>>>,
}
impl RegisteredPeers {
pub(crate) async fn insert(
&mut self,
public_key: x25519::PublicKey,
peer: Arc<tokio::sync::Mutex<RegisteredPeer>>,
) {
let peer_idx = { peer.lock().await.index };
self.peers.insert(public_key, Arc::clone(&peer));
self.peers_by_idx.insert(peer_idx, peer);
}
#[allow(unused)]
pub(crate) async fn remove(&mut self, public_key: &x25519::PublicKey) {
if let Some(peer) = self.peers.remove(public_key) {
let peer_idx = peer.lock().await.index;
if self.peers_by_idx.remove(&peer_idx).is_none() {
log::error!("Removed registered peer but no registered index was found");
}
}
}
pub(crate) fn get_by_key(
&self,
public_key: &x25519::PublicKey,
) -> Option<&Arc<tokio::sync::Mutex<RegisteredPeer>>> {
self.peers.get(public_key)
}
pub(crate) fn get_by_idx(
&self,
peer_idx: PeerIdx,
) -> Option<&Arc<tokio::sync::Mutex<RegisteredPeer>>> {
self.peers_by_idx.get(&peer_idx)
}
}
+1 -1
View File
@@ -50,7 +50,7 @@ pub fn peer_static_public_key() -> x25519::PublicKey {
let peer_static_public_bytes: [u8; 32] = decode_base64_key(PEER);
let peer_static_public = x25519::PublicKey::try_from(peer_static_public_bytes).unwrap();
info!(
"peer public key: {}",
"Adding wg peer public key: {}",
general_purpose::STANDARD.encode(peer_static_public)
);
peer_static_public
+128 -33
View File
@@ -1,5 +1,9 @@
use std::{net::SocketAddr, sync::Arc};
use std::{net::SocketAddr, sync::Arc, time::Duration};
use boringtun::{
noise::{self, handshake::parse_handshake_anon, rate_limiter::RateLimiter, TunnResult},
x25519,
};
use dashmap::DashMap;
use futures::StreamExt;
use log::error;
@@ -13,49 +17,80 @@ use tokio::{
use crate::{
event::Event,
network_table::NetworkTable,
registered_peers::{RegisteredPeer, RegisteredPeers},
setup::{self, WG_ADDRESS, WG_PORT},
TunTaskTx,
};
const MAX_PACKET: usize = 65535;
pub(crate) type ActivePeers = DashMap<SocketAddr, mpsc::UnboundedSender<Event>>;
// Registered peers
pub(crate) type PeersByIp = NetworkTable<mpsc::UnboundedSender<Event>>;
// Active peers
pub(crate) type ActivePeers = DashMap<x25519::PublicKey, mpsc::UnboundedSender<Event>>;
pub(crate) type PeersByAddr = DashMap<SocketAddr, mpsc::UnboundedSender<Event>>;
async fn add_test_peer(registered_peers: &mut RegisteredPeers) {
let peer_static_public = setup::peer_static_public_key();
let peer_index = 0;
let peer_allowed_ips = setup::peer_allowed_ips();
let test_peer = Arc::new(tokio::sync::Mutex::new(RegisteredPeer {
public_key: peer_static_public,
index: peer_index,
allowed_ips: peer_allowed_ips,
}));
registered_peers.insert(peer_static_public, test_peer).await;
}
pub(crate) async fn start_udp_listener(
tun_task_tx: TunTaskTx,
active_peers: Arc<ActivePeers>,
peers_by_ip: Arc<std::sync::Mutex<PeersByIp>>,
mut task_client: TaskClient,
) -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
let wg_address = SocketAddr::new(WG_ADDRESS.parse().unwrap(), WG_PORT);
log::info!("Starting wireguard UDP listener on {wg_address}");
let udp_socket = Arc::new(UdpSocket::bind(wg_address).await?);
let udp = Arc::new(UdpSocket::bind(wg_address).await?);
// Setup some static keys for development
// Setup our own keys
let static_private = setup::server_static_private_key();
let peer_static_public = setup::peer_static_public_key();
let peer_allowed_ips = setup::peer_allowed_ips();
let static_public = x25519::PublicKey::from(&static_private);
let handshake_max_rate = 100u64;
let rate_limiter = RateLimiter::new(&static_public, handshake_max_rate);
// Create a test peer for dev
let mut registered_peers = RegisteredPeers::default();
add_test_peer(&mut registered_peers).await;
tokio::spawn(async move {
// The set of active tunnels indexed by the peer's address
let active_peers = Arc::new(ActivePeers::new());
let active_peers_by_addr = PeersByAddr::new();
// Each tunnel is run in its own task, and the task handle is stored here so we can remove
// it from `active_peers` when the tunnel is closed
let mut active_peers_task_handles = futures::stream::FuturesUnordered::new();
let mut buf = [0u8; MAX_PACKET];
let mut dst_buf = [0u8; MAX_PACKET];
while !task_client.is_shutdown() {
tokio::select! {
_ = task_client.recv() => {
() = task_client.recv() => {
log::trace!("WireGuard UDP listener: received shutdown");
break;
}
// Reset the rate limiter every 1 sec
() = tokio::time::sleep(Duration::from_secs(1)) => {
rate_limiter.reset_count();
},
// Handle tunnel closing
Some(addr) = active_peers_task_handles.next() => {
match addr {
Ok(addr) => {
log::info!("Removing peer: {addr:?}");
active_peers.remove(&addr);
// TODO: remove from peers_by_ip
Some(public_key) = active_peers_task_handles.next() => {
match public_key {
Ok(public_key) => {
log::info!("Removing peer: {public_key:?}");
active_peers.remove(&public_key);
log::warn!("TODO: remove from peers_by_ip?");
log::warn!("TODO: remove from peers_by_addr");
}
Err(err) => {
error!("WireGuard UDP listener: error receiving shutdown from peer: {err}");
@@ -63,40 +98,100 @@ pub(crate) async fn start_udp_listener(
}
},
// Handle incoming packets
Ok((len, addr)) = udp_socket.recv_from(&mut buf) => {
Ok((len, addr)) = udp.recv_from(&mut buf) => {
log::trace!("udp: received {} bytes from {}", len, addr);
if let Some(peer_tx) = active_peers.get_mut(&addr) {
// If this addr has already been encountered, send directly to tunnel
// TODO: optimization opportunity to instead create a connected UDP socket
// inside the wg tunnel, where you can recv the data directly.
if let Some(peer_tx) = active_peers_by_addr.get(&addr) {
log::info!("udp: received {len} bytes from {addr} from known peer");
peer_tx.send(Event::WgPacket(buf[..len].to_vec().into()))
peer_tx
.send(Event::Wg(buf[..len].to_vec().into()))
.tap_err(|e| log::error!("{e}"))
.ok();
continue;
}
// Verify the incoming packet
let verified_packet = match rate_limiter.verify_packet(Some(addr.ip()), &buf[..len], &mut dst_buf) {
Ok(packet) => packet,
Err(TunnResult::WriteToNetwork(cookie)) => {
log::info!("Send back cookie to: {addr}");
udp.send_to(cookie, addr).await.tap_err(|e| log::error!("{e}")).ok();
continue;
}
Err(err) => {
log::warn!("{err:?}");
continue;
}
};
// Check if this is a registered peer, if not, just skip
let registered_peer = {
let reg_peer = match verified_packet {
noise::Packet::HandshakeInit(ref packet) => {
let Ok(handshake) = parse_handshake_anon(&static_private, &static_public, packet) else {
log::warn!("Handshake failed: {addr}");
continue;
};
registered_peers.get_by_key(&x25519::PublicKey::from(handshake.peer_static_public))
},
noise::Packet::HandshakeResponse(packet) => {
let peer_idx = packet.receiver_idx >> 8;
registered_peers.get_by_idx(peer_idx)
},
noise::Packet::PacketCookieReply(packet) => {
let peer_idx = packet.receiver_idx >> 8;
registered_peers.get_by_idx(peer_idx)
},
noise::Packet::PacketData(packet) => {
let peer_idx = packet.receiver_idx >> 8;
registered_peers.get_by_idx(peer_idx)
},
};
match reg_peer {
Some(reg_peer) => reg_peer.lock().await,
None => {
log::warn!("Peer not registered: {addr}");
continue;
}
}
};
// Look up if the peer is already connected
if let Some(peer_tx) = active_peers.get_mut(&registered_peer.public_key) {
// We found the peer as connected, even though the addr was not known
log::info!("udp: received {len} bytes from {addr} which is a known peer with unknown addr");
peer_tx.send(Event::WgVerified(buf[..len].to_vec().into()))
.tap_err(|err| log::error!("{err}"))
.unwrap();
.ok();
} else {
// If it isn't, start a new tunnel
log::info!("udp: received {len} bytes from {addr} from unknown peer, starting tunnel");
// TODO: this is a temporary solution for development since this
// assumes we know the peer_static_public this corresponds to.
// TODO: rework this before production! This is likely not secure!
log::warn!("Assuming peer_static_public is known");
log::warn!("SECURITY: Rework me to do proper handshake before creating the tunnel!");
// NOTE: we are NOT passing in the existing rate_limiter. Re-visit this
// choice later.
log::warn!("Creating new rate limiter, consider re-using?");
let (join_handle, peer_tx) = crate::wg_tunnel::start_wg_tunnel(
addr,
udp_socket.clone(),
udp.clone(),
static_private.clone(),
peer_static_public,
peer_allowed_ips,
registered_peer.public_key,
registered_peer.index,
registered_peer.allowed_ips,
tun_task_tx.clone(),
);
peers_by_ip.lock().unwrap().insert(peer_allowed_ips, peer_tx.clone());
peers_by_ip.lock().unwrap().insert(registered_peer.allowed_ips, peer_tx.clone());
active_peers_by_addr.insert(addr, peer_tx.clone());
peer_tx.send(Event::WgPacket(buf[..len].to_vec().into()))
.tap_err(|err| log::error!("{err}"))
.unwrap();
peer_tx.send(Event::Wg(buf[..len].to_vec().into()))
.tap_err(|e| log::error!("{e}"))
.ok();
// WIP(JON): active peers should probably be keyed by peer_static_public
// instead. Does this current setup lead to any issues?
log::info!("Adding peer: {addr}");
active_peers.insert(addr, peer_tx);
active_peers.insert(registered_peer.public_key, peer_tx);
active_peers_task_handles.push(join_handle);
}
},
+34 -14
View File
@@ -2,7 +2,7 @@ use std::{net::SocketAddr, sync::Arc, time::Duration};
use async_recursion::async_recursion;
use boringtun::{
noise::{errors::WireGuardError, Tunn, TunnResult},
noise::{errors::WireGuardError, rate_limiter::RateLimiter, Tunn, TunnResult},
x25519,
};
use bytes::Bytes;
@@ -14,7 +14,11 @@ use tokio::{
time::timeout,
};
use crate::{error::WgError, event::Event, network_table::NetworkTable, TunTaskTx};
use crate::{
error::WgError, event::Event, network_table::NetworkTable, registered_peers::PeerIdx, TunTaskTx,
};
const HANDSHAKE_MAX_RATE: u64 = 10;
const MAX_PACKET: usize = 65535;
@@ -55,7 +59,9 @@ impl WireGuardTunnel {
endpoint: SocketAddr,
static_private: x25519::StaticSecret,
peer_static_public: x25519::PublicKey,
index: PeerIdx,
peer_allowed_ips: ip_network::IpNetwork,
// rate_limiter: Option<RateLimiter>,
tunnel_tx: TunTaskTx,
) -> (Self, mpsc::UnboundedSender<Event>) {
let local_addr = udp.local_addr().unwrap();
@@ -64,8 +70,12 @@ impl WireGuardTunnel {
let preshared_key = None;
let persistent_keepalive = None;
let index = 0;
let rate_limiter = None;
let static_public = x25519::PublicKey::from(&static_private);
let rate_limiter = Some(Arc::new(RateLimiter::new(
&static_public,
HANDSHAKE_MAX_RATE,
)));
let wg_tunnel = Arc::new(tokio::sync::Mutex::new(
Tunn::new(
@@ -117,12 +127,17 @@ impl WireGuardTunnel {
Some(packet) => {
info!("event loop: {packet}");
match packet {
Event::WgPacket(data) => {
Event::Wg(data) => {
let _ = self.consume_wg(&data)
.await
.tap_err(|err| error!("WireGuard tunnel: consume_wg error: {err}"));
},
Event::IpPacket(data) => self.consume_eth(&data).await,
Event::WgVerified(data) => {
let _ = self.consume_verified_wg(&data)
.await
.tap_err(|err| error!("WireGuard tunnel: consume_verified_wg error: {err}"));
}
Event::Ip(data) => self.consume_eth(&data).await,
}
},
None => {
@@ -130,7 +145,7 @@ impl WireGuardTunnel {
break;
},
},
_ = tokio::time::sleep(Duration::from_millis(250)) => {
() = tokio::time::sleep(Duration::from_millis(250)) => {
let _ = self.update_wg_timers()
.await
.map_err(|err| error!("WireGuard tunnel: update_wg_timers error: {err}"));
@@ -182,8 +197,6 @@ impl WireGuardTunnel {
}
}
TunnResult::WriteToTunnelV4(packet, addr) => {
// TODO: once the flow is redone, we should add updating the endpoint dynamically
// self.set_endpoint(addr);
if self.allowed_ips.longest_match(addr).is_some() {
self.tun_task_tx.send(packet.to_vec()).unwrap();
} else {
@@ -191,8 +204,6 @@ impl WireGuardTunnel {
}
}
TunnResult::WriteToTunnelV6(packet, addr) => {
// TODO: once the flow is redone, we should add updating the endpoint dynamically
// self.set_endpoint(addr);
if self.allowed_ips.longest_match(addr).is_some() {
self.tun_task_tx.send(packet.to_vec()).unwrap();
} else {
@@ -209,6 +220,13 @@ impl WireGuardTunnel {
Ok(())
}
async fn consume_verified_wg(&mut self, data: &[u8]) -> Result<(), WgError> {
// Potentially we could take some shortcuts here in the name of performance, but currently
// I don't see that the needed functions in boringtun is exposed in the public API.
// TODO: make sure we don't put double pressure on the rate limiter!
self.consume_wg(data).await
}
async fn consume_eth(&self, data: &Bytes) {
info!("consume_eth: raw packet size: {}", data.len());
let encapsulated_packet = self.encapsulate_packet(data).await;
@@ -269,7 +287,7 @@ impl WireGuardTunnel {
return;
};
peer.format_handshake_initiation(&mut buf[..], false);
self.handle_routine_tun_result(result).await
self.handle_routine_tun_result(result).await;
}
TunnResult::Err(err) => {
error!("Failed to prepare routine packet for WireGuard endpoint: {err:?}");
@@ -287,10 +305,11 @@ pub(crate) fn start_wg_tunnel(
udp: Arc<UdpSocket>,
static_private: x25519::StaticSecret,
peer_static_public: x25519::PublicKey,
peer_index: PeerIdx,
peer_allowed_ips: ip_network::IpNetwork,
tunnel_tx: TunTaskTx,
) -> (
tokio::task::JoinHandle<SocketAddr>,
tokio::task::JoinHandle<x25519::PublicKey>,
mpsc::UnboundedSender<Event>,
) {
let (mut tunnel, peer_tx) = WireGuardTunnel::new(
@@ -298,12 +317,13 @@ pub(crate) fn start_wg_tunnel(
endpoint,
static_private,
peer_static_public,
peer_index,
peer_allowed_ips,
tunnel_tx,
);
let join_handle = tokio::spawn(async move {
tunnel.spin_off().await;
endpoint
peer_static_public
});
(join_handle, peer_tx)
}
@@ -17,8 +17,7 @@ This is a *reference page*, to see the entire presentation join Max's talk at [H
## SDKs
* [Rust SDK](https://nymtech.net/docs/sdk/rust.html)
* [Typescript SDK](https://nymtech.net/docs/sdk/typescript.html)
* [Interactive Typescript SDK docs](https://sdk.nymtech.net)
* [Typescript SDK](https://sdk.nymtech.net/)
### Rust examples
+5 -1
View File
@@ -2,4 +2,8 @@
Welcome to the Nym Developer Portal, containing quickstart resources, user manuals, integration information, and tutorials outlining to start building privacy enhanced apps.
For more in-depth information about nodes, network traffic flows, clients, coconut etc check out the [docs](https://nymtech.net/docs). If you are looking for information and setup guides for the various pieces of Nym mixnet infrastructure (mix nodes, gateways and network requesters) and Nyx blockchain validators see the **new [Operators Guides](https://nymtech.net/operators)** book.
For more in-depth information about nodes, network traffic flows, clients, coconut etc check out the [docs](https://nymtech.net/docs).
If you are looking for information and setup guides for the various pieces of Nym mixnet infrastructure (mix nodes, gateways and network requesters) and Nyx blockchain validators see the **new [Operators Guides](https://nymtech.net/operators)** book.
If you're looking for TypeScript/JavaScript related information such as SDKs to build your own tools, step-by-step tutorials, live playgrounds and more, make sure to check out the **new [TS SDK Handbook](https://sdk.nymtech.net/)** !
@@ -1,3 +1,3 @@
# Typescript
Tutorial code in this section is built to interact with a standalone Nym client. You can read about interacting with standalone clients [here](https://nymtech.net/docs/clients/websocket-client.html#connecting-to-the-local-websocket), although it is usually preferable to use the [Typescript SDK](https://nymtech.net/docs/sdk/typescript.html).
Tutorial code in this section is built to interact with a standalone Nym client. You can read about interacting with standalone clients [here](https://nymtech.net/docs/clients/websocket-client.html#connecting-to-the-local-websocket), although it is usually preferable to use the [Typescript SDK](https://sdk.nymtech.net/).
+4 -2
View File
@@ -2,9 +2,11 @@
This is Nym's technical documentation, containing information and setup guides about the various pieces of Nym software such as different mixnet infrastructure nodes, application clients, and existing applications like the desktop wallet and mixnet explorer.
If you are new to Nym and want to learn about the mixnet, explore kickstart options and demos, learn how to integrate with the network, and follow developer tutorials check out the [Developer Portal](https://nymtech.net/developers/) where you can find also our [FAQ section](https://nymtech.net/developers/faq/general-faq.md).
If you are looking for information and setup guides for the various pieces of Nym mixnet infrastructure (mix nodes, gateways and network requesters) and Nyx blockchain validators see the **new [Operators Guides](https://nymtech.net/operators)** book.
If you are new to Nym and want to learn about the mixnet, explore kickstart options and demos, learn how to integrate with the network, and follow developer tutorials check out the [Developer Portal](https://nymtech.net/developers/) where you can find also our [FAQ section](https://nymtech.net/developers/faq/general-faq.md).
If you're specically looking for TypeScript/JavaScript related information such as SDKs to build your own tools, step-by-step tutorials, live playgrounds and more - make sure to check out the **new [TS SDK Handbook](https://sdk.nymtech.net/)** !
## Popular pages
**Network Architecture:**
@@ -12,7 +14,7 @@ If you are new to Nym and want to learn about the mixnet, explore kickstart opti
* [Mixnet Traffic Flow](./architecture/traffic-flow.md)
**SDK examples:**
* [Typescript SDK](./sdk/typescript.md)
* [Typescript SDK](https://sdk.nymtech.net/)
* [Rust SDK](./sdk/rust.md)
**Nyx**
+1 -63
View File
@@ -1,66 +1,4 @@
# Typescript SDK
The Typescript SDK allows developers to start building browser-based mixnet applications quickly, by simply importing the SDK into their code via NPM as they would any other Typescript library.
You can find the source code [here](https://github.com/nymtech/nym/tree/master/sdk) and the library on NPM [here](https://www.npmjs.com/package/@nymproject/sdk).
Currently developers can use the SDK to do the following **entirely in the browser**:
* Create a client
* Listen for incoming messages and reply to them
* Encrypt text and binary-encoded messages as Sphinx packets and send these through the mixnet
> We will be fleshing out further mixnet-related features in the coming weeks with functionality such as importing/exporting keypairs for developing apps with a retained identity over time.
In the future the SDK will be made up of several components, each of which will allow developers to interact with different parts of Nym's infrastructure.
| Component | Functionality | Released |
| --------- | ------------------------------------------------------------------------------ | -------- |
| Mixnet | Create clients & keypairs, subscribe to Mixnet events, send & receive messages | ✔️ |
| Coconut | Create & verify Coconut credentials | ❌ |
| Validator | Sign & broadcast Nyx blockchain transactions, query the blockchain | ❌ |
### How it works
The SDK can be thought of as a 'wrapper' around the compiled [WebAssembly client](https://github.com/nymtech/nym/tree/master/clients/webassembly) code: it runs the client (a Wasm blob) in a web worker. This allows us to keep the work done by the client - such as the heavy lifting of creating and multiply-encrypting Sphinx packets - in a seperate thread from our UI, enabling you to build reactive frontends without worrying about the work done under the hood by the client eating your processing power.
The SDK exposes an interface that allows developers to interact with the Wasm blob inside the webworker from frontend code.
### Framework Support
Currently, the SDK **only** works with frameworks that use either `Webpack` or `Parcel` as bundlers. If you want to use the SDK with a framework that isn't on this list, such as Angular, or NodeJS, **here be dragons!** These frameworks will probably use a different bundler and you will probably run into problems.
| Bundler | Supported |
| ------- | --------- |
| Webpack | ✔️ |
| Packer | ✔️ |
Support for environments with different bundlers will be added in subsequent releases.
| Environment | Supported |
| ---------------- | --------- |
| Browser | ✔️ |
| Headless NodeJS | ❌ |
| Electron Desktop | ❌ |
### Using the SDK
There are multiple example projects in [`nym/sdk/typescript/examples/`](https://github.com/nymtech/nym/tree/master/sdk/typescript/examples/), each for a different frontend framework.
#### Vanilla HTML
The best place to start if you just want to quickly get a basic frontend up and running with which to experiment is `examples/plain-html`:
```typescript
{{#include ../../../../sdk/typescript/examples/shared/index.ts}}
```
As you can see, all that is required to create an ephemeral keypair and connect to the mixnet is creating a client and then subscribing to the mixnet events coming down the websocket, and adding logic to deal with them.
#### Parcel
If you don't want to use `Webpack` as your app bundler, we have an example with `Parcel` located at [`examples/parcel/`](https://github.com/nymtech/nym/tree/master/sdk/typescript/examples/chat-app/parcel).
#### Create React App
For React developers we have an example which is a basic React app scaffold with the additional logic for creating a client and subscribing to mixnet events in [`examples/react-webpack-with-theme-example/`](https://github.com/nymtech/nym/tree/master/sdk/typescript/examples/chat-app/react-webpack-with-theme-example).
### Developers: think about what you're sending (and importing)!
Think about what information your app sends. That goes for whatever you put into your Sphinx packet messages as well as what your app's environment may leak.
Whenever you write client PEApps using HTML/JavaScript, we recommend that you **do not load external resources from CDNs**. Webapp developers do this all the time, to save load time for common resources, or just for convenience. But when you're writing privacy apps it's better not to make these kinds of requests. **Pack everything locally**.
If you use only local resources within your Electron app or your browser extensions, explicitly encoding request data in a Sphinx packet does protect you from the normal leakage that gets sent in a browser HTTP request. [There's a lot of stuff that leaks when you make an HTTP request from a browser window](https://panopticlick.eff.org/). Luckily, all that metadata and request leakage doesn't happen in Nym, because you're choosing very explicitly what to encode into Sphinx packets, instead of sending a whole browser environment by default.
> If you'd like to learn more, build apps or integrate Nym components using the TS SDK, please visit the **dedicated [TS SDK Handbook](https://sdk.nymtech.net/)** !
+2 -2
View File
@@ -42,7 +42,7 @@ turn-off = true
[preprocessor.admonish]
command = "mdbook-admonish"
assets_version = "2.0.0" # do not edit: managed by `mdbook-admonish install`
assets_version = "3.0.0" # do not edit: managed by `mdbook-admonish install`
# variables preprocessor: import variables into files
# https://gitlab.com/tglman/mdbook-variables/
@@ -83,7 +83,7 @@ curly-quotes = true
# mathjax-support = false # useful if we want to pull equations in
copy-fonts = true
no-section-label = false
additional-css = ["theme/pagetoc.css", "././mdbook-admonish.css","./custom.css"]
additional-css = ["theme/pagetoc.css", "././mdbook-admonish.css","./custom.css", "./mdbook-admonish.css"]
additional-js = ["theme/pagetoc.js"]
git-repository-url = "https://github.com/nymtech/nym"
git-repository-icon = "fa-github"
+81 -92
View File
@@ -1,31 +1,18 @@
@charset "UTF-8";
:root {
--md-admonition-icon--note:
url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M20.71 7.04c.39-.39.39-1.04 0-1.41l-2.34-2.34c-.37-.39-1.02-.39-1.41 0l-1.84 1.83 3.75 3.75M3 17.25V21h3.75L17.81 9.93l-3.75-3.75L3 17.25z'/></svg>");
--md-admonition-icon--abstract:
url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M17 9H7V7h10m0 6H7v-2h10m-3 6H7v-2h7M12 3a1 1 0 0 1 1 1 1 1 0 0 1-1 1 1 1 0 0 1-1-1 1 1 0 0 1 1-1m7 0h-4.18C14.4 1.84 13.3 1 12 1c-1.3 0-2.4.84-2.82 2H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V5a2 2 0 0 0-2-2z'/></svg>");
--md-admonition-icon--info:
url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M13 9h-2V7h2m0 10h-2v-6h2m-1-9A10 10 0 0 0 2 12a10 10 0 0 0 10 10 10 10 0 0 0 10-10A10 10 0 0 0 12 2z'/></svg>");
--md-admonition-icon--tip:
url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M17.66 11.2c-.23-.3-.51-.56-.77-.82-.67-.6-1.43-1.03-2.07-1.66C13.33 7.26 13 4.85 13.95 3c-.95.23-1.78.75-2.49 1.32-2.59 2.08-3.61 5.75-2.39 8.9.04.1.08.2.08.33 0 .22-.15.42-.35.5-.23.1-.47.04-.66-.12a.58.58 0 0 1-.14-.17c-1.13-1.43-1.31-3.48-.55-5.12C5.78 10 4.87 12.3 5 14.47c.06.5.12 1 .29 1.5.14.6.41 1.2.71 1.73 1.08 1.73 2.95 2.97 4.96 3.22 2.14.27 4.43-.12 6.07-1.6 1.83-1.66 2.47-4.32 1.53-6.6l-.13-.26c-.21-.46-.77-1.26-.77-1.26m-3.16 6.3c-.28.24-.74.5-1.1.6-1.12.4-2.24-.16-2.9-.82 1.19-.28 1.9-1.16 2.11-2.05.17-.8-.15-1.46-.28-2.23-.12-.74-.1-1.37.17-2.06.19.38.39.76.63 1.06.77 1 1.98 1.44 2.24 2.8.04.14.06.28.06.43.03.82-.33 1.72-.93 2.27z'/></svg>");
--md-admonition-icon--success:
url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='m9 20.42-6.21-6.21 2.83-2.83L9 14.77l9.88-9.89 2.83 2.83L9 20.42z'/></svg>");
--md-admonition-icon--question:
url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='m15.07 11.25-.9.92C13.45 12.89 13 13.5 13 15h-2v-.5c0-1.11.45-2.11 1.17-2.83l1.24-1.26c.37-.36.59-.86.59-1.41a2 2 0 0 0-2-2 2 2 0 0 0-2 2H8a4 4 0 0 1 4-4 4 4 0 0 1 4 4 3.2 3.2 0 0 1-.93 2.25M13 19h-2v-2h2M12 2A10 10 0 0 0 2 12a10 10 0 0 0 10 10 10 10 0 0 0 10-10c0-5.53-4.5-10-10-10z'/></svg>");
--md-admonition-icon--warning:
url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M13 14h-2V9h2m0 9h-2v-2h2M1 21h22L12 2 1 21z'/></svg>");
--md-admonition-icon--failure:
url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M20 6.91 17.09 4 12 9.09 6.91 4 4 6.91 9.09 12 4 17.09 6.91 20 12 14.91 17.09 20 20 17.09 14.91 12 20 6.91z'/></svg>");
--md-admonition-icon--danger:
url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M11 15H6l7-14v8h5l-7 14v-8z'/></svg>");
--md-admonition-icon--bug:
url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M14 12h-4v-2h4m0 6h-4v-2h4m6-6h-2.81a5.985 5.985 0 0 0-1.82-1.96L17 4.41 15.59 3l-2.17 2.17a6.002 6.002 0 0 0-2.83 0L8.41 3 7 4.41l1.62 1.63C7.88 6.55 7.26 7.22 6.81 8H4v2h2.09c-.05.33-.09.66-.09 1v1H4v2h2v1c0 .34.04.67.09 1H4v2h2.81c1.04 1.79 2.97 3 5.19 3s4.15-1.21 5.19-3H20v-2h-2.09c.05-.33.09-.66.09-1v-1h2v-2h-2v-1c0-.34-.04-.67-.09-1H20V8z'/></svg>");
--md-admonition-icon--example:
url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M7 13v-2h14v2H7m0 6v-2h14v2H7M7 7V5h14v2H7M3 8V5H2V4h2v4H3m-1 9v-1h3v4H2v-1h2v-.5H3v-1h1V17H2m2.25-7a.75.75 0 0 1 .75.75c0 .2-.08.39-.21.52L3.12 13H5v1H2v-.92L4 11H2v-1h2.25z'/></svg>");
--md-admonition-icon--quote:
url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M14 17h3l2-4V7h-6v6h3M6 17h3l2-4V7H5v6h3l-2 4z'/></svg>");
--md-details-icon:
url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M8.59 16.58 13.17 12 8.59 7.41 10 6l6 6-6 6-1.41-1.42Z'/></svg>");
--md-admonition-icon--admonish-note: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M20.71 7.04c.39-.39.39-1.04 0-1.41l-2.34-2.34c-.37-.39-1.02-.39-1.41 0l-1.84 1.83 3.75 3.75M3 17.25V21h3.75L17.81 9.93l-3.75-3.75L3 17.25z'/></svg>");
--md-admonition-icon--admonish-abstract: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M17 9H7V7h10m0 6H7v-2h10m-3 6H7v-2h7M12 3a1 1 0 0 1 1 1 1 1 0 0 1-1 1 1 1 0 0 1-1-1 1 1 0 0 1 1-1m7 0h-4.18C14.4 1.84 13.3 1 12 1c-1.3 0-2.4.84-2.82 2H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V5a2 2 0 0 0-2-2z'/></svg>");
--md-admonition-icon--admonish-info: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M13 9h-2V7h2m0 10h-2v-6h2m-1-9A10 10 0 0 0 2 12a10 10 0 0 0 10 10 10 10 0 0 0 10-10A10 10 0 0 0 12 2z'/></svg>");
--md-admonition-icon--admonish-tip: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M17.66 11.2c-.23-.3-.51-.56-.77-.82-.67-.6-1.43-1.03-2.07-1.66C13.33 7.26 13 4.85 13.95 3c-.95.23-1.78.75-2.49 1.32-2.59 2.08-3.61 5.75-2.39 8.9.04.1.08.2.08.33 0 .22-.15.42-.35.5-.23.1-.47.04-.66-.12a.58.58 0 0 1-.14-.17c-1.13-1.43-1.31-3.48-.55-5.12C5.78 10 4.87 12.3 5 14.47c.06.5.12 1 .29 1.5.14.6.41 1.2.71 1.73 1.08 1.73 2.95 2.97 4.96 3.22 2.14.27 4.43-.12 6.07-1.6 1.83-1.66 2.47-4.32 1.53-6.6l-.13-.26c-.21-.46-.77-1.26-.77-1.26m-3.16 6.3c-.28.24-.74.5-1.1.6-1.12.4-2.24-.16-2.9-.82 1.19-.28 1.9-1.16 2.11-2.05.17-.8-.15-1.46-.28-2.23-.12-.74-.1-1.37.17-2.06.19.38.39.76.63 1.06.77 1 1.98 1.44 2.24 2.8.04.14.06.28.06.43.03.82-.33 1.72-.93 2.27z'/></svg>");
--md-admonition-icon--admonish-success: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='m9 20.42-6.21-6.21 2.83-2.83L9 14.77l9.88-9.89 2.83 2.83L9 20.42z'/></svg>");
--md-admonition-icon--admonish-question: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='m15.07 11.25-.9.92C13.45 12.89 13 13.5 13 15h-2v-.5c0-1.11.45-2.11 1.17-2.83l1.24-1.26c.37-.36.59-.86.59-1.41a2 2 0 0 0-2-2 2 2 0 0 0-2 2H8a4 4 0 0 1 4-4 4 4 0 0 1 4 4 3.2 3.2 0 0 1-.93 2.25M13 19h-2v-2h2M12 2A10 10 0 0 0 2 12a10 10 0 0 0 10 10 10 10 0 0 0 10-10c0-5.53-4.5-10-10-10z'/></svg>");
--md-admonition-icon--admonish-warning: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M13 14h-2V9h2m0 9h-2v-2h2M1 21h22L12 2 1 21z'/></svg>");
--md-admonition-icon--admonish-failure: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M20 6.91 17.09 4 12 9.09 6.91 4 4 6.91 9.09 12 4 17.09 6.91 20 12 14.91 17.09 20 20 17.09 14.91 12 20 6.91z'/></svg>");
--md-admonition-icon--admonish-danger: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M11 15H6l7-14v8h5l-7 14v-8z'/></svg>");
--md-admonition-icon--admonish-bug: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M14 12h-4v-2h4m0 6h-4v-2h4m6-6h-2.81a5.985 5.985 0 0 0-1.82-1.96L17 4.41 15.59 3l-2.17 2.17a6.002 6.002 0 0 0-2.83 0L8.41 3 7 4.41l1.62 1.63C7.88 6.55 7.26 7.22 6.81 8H4v2h2.09c-.05.33-.09.66-.09 1v1H4v2h2v1c0 .34.04.67.09 1H4v2h2.81c1.04 1.79 2.97 3 5.19 3s4.15-1.21 5.19-3H20v-2h-2.09c.05-.33.09-.66.09-1v-1h2v-2h-2v-1c0-.34-.04-.67-.09-1H20V8z'/></svg>");
--md-admonition-icon--admonish-example: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M7 13v-2h14v2H7m0 6v-2h14v2H7M7 7V5h14v2H7M3 8V5H2V4h2v4H3m-1 9v-1h3v4H2v-1h2v-.5H3v-1h1V17H2m2.25-7a.75.75 0 0 1 .75.75c0 .2-.08.39-.21.52L3.12 13H5v1H2v-.92L4 11H2v-1h2.25z'/></svg>");
--md-admonition-icon--admonish-quote: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M14 17h3l2-4V7h-6v6h3M6 17h3l2-4V7H5v6h3l-2 4z'/></svg>");
--md-details-icon: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M8.59 16.58 13.17 12 8.59 7.41 10 6l6 6-6 6-1.41-1.42Z'/></svg>");
}
:is(.admonition) {
@@ -75,8 +62,9 @@ a.admonition-anchor-link::before {
content: "§";
}
:is(.admonition-title, summary) {
:is(.admonition-title, summary.admonition-title) {
position: relative;
min-height: 4rem;
margin-block: 0;
margin-inline: -1.6rem -1.2rem;
padding-block: 0.8rem;
@@ -85,13 +73,13 @@ a.admonition-anchor-link::before {
background-color: rgba(68, 138, 255, 0.1);
display: flex;
}
:is(.admonition-title, summary) p {
:is(.admonition-title, summary.admonition-title) p {
margin: 0;
}
html :is(.admonition-title, summary):last-child {
html :is(.admonition-title, summary.admonition-title):last-child {
margin-bottom: 0;
}
:is(.admonition-title, summary)::before {
:is(.admonition-title, summary.admonition-title)::before {
position: absolute;
top: 0.625em;
inset-inline-start: 1.6rem;
@@ -106,7 +94,7 @@ html :is(.admonition-title, summary):last-child {
-webkit-mask-size: contain;
content: "";
}
:is(.admonition-title, summary):hover a.admonition-anchor-link {
:is(.admonition-title, summary.admonition-title):hover a.admonition-anchor-link {
display: initial;
}
@@ -131,204 +119,204 @@ details[open].admonition > summary.admonition-title::after {
transform: rotate(90deg);
}
:is(.admonition):is(.note) {
:is(.admonition):is(.admonish-note) {
border-color: #448aff;
}
:is(.note) > :is(.admonition-title, summary) {
:is(.admonish-note) > :is(.admonition-title, summary.admonition-title) {
background-color: rgba(68, 138, 255, 0.1);
}
:is(.note) > :is(.admonition-title, summary)::before {
:is(.admonish-note) > :is(.admonition-title, summary.admonition-title)::before {
background-color: #448aff;
mask-image: var(--md-admonition-icon--note);
-webkit-mask-image: var(--md-admonition-icon--note);
mask-image: var(--md-admonition-icon--admonish-note);
-webkit-mask-image: var(--md-admonition-icon--admonish-note);
mask-repeat: no-repeat;
-webkit-mask-repeat: no-repeat;
mask-size: contain;
-webkit-mask-repeat: no-repeat;
}
:is(.admonition):is(.abstract, .summary, .tldr) {
:is(.admonition):is(.admonish-abstract, .admonish-summary, .admonish-tldr) {
border-color: #00b0ff;
}
:is(.abstract, .summary, .tldr) > :is(.admonition-title, summary) {
:is(.admonish-abstract, .admonish-summary, .admonish-tldr) > :is(.admonition-title, summary.admonition-title) {
background-color: rgba(0, 176, 255, 0.1);
}
:is(.abstract, .summary, .tldr) > :is(.admonition-title, summary)::before {
:is(.admonish-abstract, .admonish-summary, .admonish-tldr) > :is(.admonition-title, summary.admonition-title)::before {
background-color: #00b0ff;
mask-image: var(--md-admonition-icon--abstract);
-webkit-mask-image: var(--md-admonition-icon--abstract);
mask-image: var(--md-admonition-icon--admonish-abstract);
-webkit-mask-image: var(--md-admonition-icon--admonish-abstract);
mask-repeat: no-repeat;
-webkit-mask-repeat: no-repeat;
mask-size: contain;
-webkit-mask-repeat: no-repeat;
}
:is(.admonition):is(.info, .todo) {
:is(.admonition):is(.admonish-info, .admonish-todo) {
border-color: #00b8d4;
}
:is(.info, .todo) > :is(.admonition-title, summary) {
:is(.admonish-info, .admonish-todo) > :is(.admonition-title, summary.admonition-title) {
background-color: rgba(0, 184, 212, 0.1);
}
:is(.info, .todo) > :is(.admonition-title, summary)::before {
:is(.admonish-info, .admonish-todo) > :is(.admonition-title, summary.admonition-title)::before {
background-color: #00b8d4;
mask-image: var(--md-admonition-icon--info);
-webkit-mask-image: var(--md-admonition-icon--info);
mask-image: var(--md-admonition-icon--admonish-info);
-webkit-mask-image: var(--md-admonition-icon--admonish-info);
mask-repeat: no-repeat;
-webkit-mask-repeat: no-repeat;
mask-size: contain;
-webkit-mask-repeat: no-repeat;
}
:is(.admonition):is(.tip, .hint, .important) {
:is(.admonition):is(.admonish-tip, .admonish-hint, .admonish-important) {
border-color: #00bfa5;
}
:is(.tip, .hint, .important) > :is(.admonition-title, summary) {
:is(.admonish-tip, .admonish-hint, .admonish-important) > :is(.admonition-title, summary.admonition-title) {
background-color: rgba(0, 191, 165, 0.1);
}
:is(.tip, .hint, .important) > :is(.admonition-title, summary)::before {
:is(.admonish-tip, .admonish-hint, .admonish-important) > :is(.admonition-title, summary.admonition-title)::before {
background-color: #00bfa5;
mask-image: var(--md-admonition-icon--tip);
-webkit-mask-image: var(--md-admonition-icon--tip);
mask-image: var(--md-admonition-icon--admonish-tip);
-webkit-mask-image: var(--md-admonition-icon--admonish-tip);
mask-repeat: no-repeat;
-webkit-mask-repeat: no-repeat;
mask-size: contain;
-webkit-mask-repeat: no-repeat;
}
:is(.admonition):is(.success, .check, .done) {
:is(.admonition):is(.admonish-success, .admonish-check, .admonish-done) {
border-color: #00c853;
}
:is(.success, .check, .done) > :is(.admonition-title, summary) {
:is(.admonish-success, .admonish-check, .admonish-done) > :is(.admonition-title, summary.admonition-title) {
background-color: rgba(0, 200, 83, 0.1);
}
:is(.success, .check, .done) > :is(.admonition-title, summary)::before {
:is(.admonish-success, .admonish-check, .admonish-done) > :is(.admonition-title, summary.admonition-title)::before {
background-color: #00c853;
mask-image: var(--md-admonition-icon--success);
-webkit-mask-image: var(--md-admonition-icon--success);
mask-image: var(--md-admonition-icon--admonish-success);
-webkit-mask-image: var(--md-admonition-icon--admonish-success);
mask-repeat: no-repeat;
-webkit-mask-repeat: no-repeat;
mask-size: contain;
-webkit-mask-repeat: no-repeat;
}
:is(.admonition):is(.question, .help, .faq) {
:is(.admonition):is(.admonish-question, .admonish-help, .admonish-faq) {
border-color: #64dd17;
}
:is(.question, .help, .faq) > :is(.admonition-title, summary) {
:is(.admonish-question, .admonish-help, .admonish-faq) > :is(.admonition-title, summary.admonition-title) {
background-color: rgba(100, 221, 23, 0.1);
}
:is(.question, .help, .faq) > :is(.admonition-title, summary)::before {
:is(.admonish-question, .admonish-help, .admonish-faq) > :is(.admonition-title, summary.admonition-title)::before {
background-color: #64dd17;
mask-image: var(--md-admonition-icon--question);
-webkit-mask-image: var(--md-admonition-icon--question);
mask-image: var(--md-admonition-icon--admonish-question);
-webkit-mask-image: var(--md-admonition-icon--admonish-question);
mask-repeat: no-repeat;
-webkit-mask-repeat: no-repeat;
mask-size: contain;
-webkit-mask-repeat: no-repeat;
}
:is(.admonition):is(.warning, .caution, .attention) {
:is(.admonition):is(.admonish-warning, .admonish-caution, .admonish-attention) {
border-color: #ff9100;
}
:is(.warning, .caution, .attention) > :is(.admonition-title, summary) {
:is(.admonish-warning, .admonish-caution, .admonish-attention) > :is(.admonition-title, summary.admonition-title) {
background-color: rgba(255, 145, 0, 0.1);
}
:is(.warning, .caution, .attention) > :is(.admonition-title, summary)::before {
:is(.admonish-warning, .admonish-caution, .admonish-attention) > :is(.admonition-title, summary.admonition-title)::before {
background-color: #ff9100;
mask-image: var(--md-admonition-icon--warning);
-webkit-mask-image: var(--md-admonition-icon--warning);
mask-image: var(--md-admonition-icon--admonish-warning);
-webkit-mask-image: var(--md-admonition-icon--admonish-warning);
mask-repeat: no-repeat;
-webkit-mask-repeat: no-repeat;
mask-size: contain;
-webkit-mask-repeat: no-repeat;
}
:is(.admonition):is(.failure, .fail, .missing) {
:is(.admonition):is(.admonish-failure, .admonish-fail, .admonish-missing) {
border-color: #ff5252;
}
:is(.failure, .fail, .missing) > :is(.admonition-title, summary) {
:is(.admonish-failure, .admonish-fail, .admonish-missing) > :is(.admonition-title, summary.admonition-title) {
background-color: rgba(255, 82, 82, 0.1);
}
:is(.failure, .fail, .missing) > :is(.admonition-title, summary)::before {
:is(.admonish-failure, .admonish-fail, .admonish-missing) > :is(.admonition-title, summary.admonition-title)::before {
background-color: #ff5252;
mask-image: var(--md-admonition-icon--failure);
-webkit-mask-image: var(--md-admonition-icon--failure);
mask-image: var(--md-admonition-icon--admonish-failure);
-webkit-mask-image: var(--md-admonition-icon--admonish-failure);
mask-repeat: no-repeat;
-webkit-mask-repeat: no-repeat;
mask-size: contain;
-webkit-mask-repeat: no-repeat;
}
:is(.admonition):is(.danger, .error) {
:is(.admonition):is(.admonish-danger, .admonish-error) {
border-color: #ff1744;
}
:is(.danger, .error) > :is(.admonition-title, summary) {
:is(.admonish-danger, .admonish-error) > :is(.admonition-title, summary.admonition-title) {
background-color: rgba(255, 23, 68, 0.1);
}
:is(.danger, .error) > :is(.admonition-title, summary)::before {
:is(.admonish-danger, .admonish-error) > :is(.admonition-title, summary.admonition-title)::before {
background-color: #ff1744;
mask-image: var(--md-admonition-icon--danger);
-webkit-mask-image: var(--md-admonition-icon--danger);
mask-image: var(--md-admonition-icon--admonish-danger);
-webkit-mask-image: var(--md-admonition-icon--admonish-danger);
mask-repeat: no-repeat;
-webkit-mask-repeat: no-repeat;
mask-size: contain;
-webkit-mask-repeat: no-repeat;
}
:is(.admonition):is(.bug) {
:is(.admonition):is(.admonish-bug) {
border-color: #f50057;
}
:is(.bug) > :is(.admonition-title, summary) {
:is(.admonish-bug) > :is(.admonition-title, summary.admonition-title) {
background-color: rgba(245, 0, 87, 0.1);
}
:is(.bug) > :is(.admonition-title, summary)::before {
:is(.admonish-bug) > :is(.admonition-title, summary.admonition-title)::before {
background-color: #f50057;
mask-image: var(--md-admonition-icon--bug);
-webkit-mask-image: var(--md-admonition-icon--bug);
mask-image: var(--md-admonition-icon--admonish-bug);
-webkit-mask-image: var(--md-admonition-icon--admonish-bug);
mask-repeat: no-repeat;
-webkit-mask-repeat: no-repeat;
mask-size: contain;
-webkit-mask-repeat: no-repeat;
}
:is(.admonition):is(.example) {
:is(.admonition):is(.admonish-example) {
border-color: #7c4dff;
}
:is(.example) > :is(.admonition-title, summary) {
:is(.admonish-example) > :is(.admonition-title, summary.admonition-title) {
background-color: rgba(124, 77, 255, 0.1);
}
:is(.example) > :is(.admonition-title, summary)::before {
:is(.admonish-example) > :is(.admonition-title, summary.admonition-title)::before {
background-color: #7c4dff;
mask-image: var(--md-admonition-icon--example);
-webkit-mask-image: var(--md-admonition-icon--example);
mask-image: var(--md-admonition-icon--admonish-example);
-webkit-mask-image: var(--md-admonition-icon--admonish-example);
mask-repeat: no-repeat;
-webkit-mask-repeat: no-repeat;
mask-size: contain;
-webkit-mask-repeat: no-repeat;
}
:is(.admonition):is(.quote, .cite) {
:is(.admonition):is(.admonish-quote, .admonish-cite) {
border-color: #9e9e9e;
}
:is(.quote, .cite) > :is(.admonition-title, summary) {
:is(.admonish-quote, .admonish-cite) > :is(.admonition-title, summary.admonition-title) {
background-color: rgba(158, 158, 158, 0.1);
}
:is(.quote, .cite) > :is(.admonition-title, summary)::before {
:is(.admonish-quote, .admonish-cite) > :is(.admonition-title, summary.admonition-title)::before {
background-color: #9e9e9e;
mask-image: var(--md-admonition-icon--quote);
-webkit-mask-image: var(--md-admonition-icon--quote);
mask-image: var(--md-admonition-icon--admonish-quote);
-webkit-mask-image: var(--md-admonition-icon--admonish-quote);
mask-repeat: no-repeat;
-webkit-mask-repeat: no-repeat;
mask-size: contain;
@@ -339,7 +327,8 @@ details[open].admonition > summary.admonition-title::after {
background-color: var(--sidebar-bg);
}
.ayu :is(.admonition), .coal :is(.admonition) {
.ayu :is(.admonition),
.coal :is(.admonition) {
background-color: var(--theme-hover);
}
@@ -2,9 +2,10 @@
> We aim on purpose to make minimal changes to reward scheme and software. We're just 'smooshing' together stuff we already debugged and know works.
> -- Harry Halpin, Nym CEO
<p>
<p></p>
This page refer to the changes which are planned to take place over Q3 and Q4 2023. As this is a transition period in the beginning (Q3 2023) the [Mix Nodes FAQ page](./mixnodes-faq.md) holds more answers to the current setup as project Smoosh refers to the eventual setup. As project Smoosh gets progressively implemented the answers on this page will become to be more relevant to the current state and eventually this FAQ page will be merged with the still relevant parts of the main Mix Nodes FAQ page.
</p>
If any questions are not answered or it's not clear for you in which stage project Smoosh is right now, please reach out in Node Operators [Matrix room](https://matrix.to/#/#operators:nymtech.chat).
## Overview
@@ -40,7 +41,7 @@ Yes, to run a mix node only is an option. However it will be less rewarded as no
### What are the incentives for the node operator?
In the original setup there were no incentives to run a `network-requester`. After the transition all the users will buy multiple tickets of zkNyms credentials and use those as [anonymous e-cash](https://arxiv.org/abs/2303.08221) to pay for their data traffic (`[Nym API](https://github.com/nymtech/nym/tree/master/nym-api)` will do the do cryptographical checks to prevent double-spending). All collected fees get distributed to all active nodes proportionally to their work by the end of each epoch.
In the original setup there were no incentives to run a `network-requester`. After the transition all the users will buy multiple tickets of zkNyms credentials and use those as [anonymous e-cash](https://arxiv.org/abs/2303.08221) to pay for their data traffic ([`Nym API`](https://github.com/nymtech/nym/tree/master/nym-api) will do the do cryptographical checks to prevent double-spending). All collected fees get distributed to all active nodes proportionally to their work by the end of each epoch.
### How does this change the token economics?
+1 -1
View File
@@ -101,7 +101,7 @@ impl ApiCmdProcessor {
}
fn ephemera_config<A: Application>(
ephemera: &mut Ephemera<A>,
ephemera: &Ephemera<A>,
reply: Sender<api::Result<ApiEphemeraConfig>>,
) {
let node_info = ephemera.node_info.clone();
+3 -3
View File
@@ -191,10 +191,10 @@ impl<A: Application> EphemeraStarterWithApplication<A> {
let block_manager = self.init_block_manager(&mut storage)?;
let (mut shutdown_manager, shutdown_handle) = ShutdownManager::init();
let (shutdown_manager, shutdown_handle) = ShutdownManager::init();
let mut service_data = ServiceInfo::default();
let services = self.init_services(&mut service_data, &mut shutdown_manager, provider)?;
let services = self.init_services(&mut service_data, &shutdown_manager, provider)?;
Ok(EphemeraStarterWithProvider {
with_application: self,
@@ -237,7 +237,7 @@ impl<A: Application> EphemeraStarterWithApplication<A> {
>(
&mut self,
service_data: &mut ServiceInfo,
shutdown_manager: &mut ShutdownManager,
shutdown_manager: &ShutdownManager,
provider: P,
) -> anyhow::Result<Vec<BoxFuture<'static, anyhow::Result<()>>>> {
let services = vec![
+4 -4
View File
@@ -1,5 +1,5 @@
import { GatewayResponse, GatewayBond, GatewayReportResponse } from '../typeDefs/explorer-api';
import { toPercentIntegerString } from '../utils';
import { toPercentInteger } from '../utils';
export type GatewayRowType = {
id: string;
@@ -9,7 +9,7 @@ export type GatewayRowType = {
host: string;
location: string;
version: string;
node_performance: string;
node_performance: number;
};
export type GatewayEnrichedRowType = GatewayRowType & {
@@ -30,7 +30,7 @@ export function gatewayToGridRow(arrayOfGateways: GatewayResponse): GatewayRowTy
bond: gw.pledge_amount.amount || 0,
host: gw.gateway.host || '',
version: gw.gateway.version || '',
node_performance: toPercentIntegerString(gw.node_performance.last_24h),
node_performance: toPercentInteger(gw.node_performance.last_24h),
}));
}
@@ -47,6 +47,6 @@ export function gatewayEnrichedToGridRow(gateway: GatewayBond, report: GatewayRe
mixPort: gateway.gateway.mix_port || 0,
routingScore: `${report.most_recent}%`,
avgUptime: `${report.last_day || report.last_hour}%`,
node_performance: toPercentIntegerString(gateway.node_performance.most_recent),
node_performance: toPercentInteger(gateway.node_performance.most_recent),
};
}
+9 -9
View File
@@ -1,6 +1,6 @@
/* eslint-disable camelcase */
import { MixNodeResponse, MixNodeResponseItem, MixnodeStatus, NodePerformance } from '../../typeDefs/explorer-api';
import { toPercentIntegerString } from '../../utils';
import { MixNodeResponse, MixNodeResponseItem, MixnodeStatus } from '../../typeDefs/explorer-api';
import { toPercentInteger, toPercentIntegerString } from '../../utils';
import { unymToNym } from '../../utils/currency';
export type MixnodeRowType = {
@@ -15,11 +15,11 @@ export type MixnodeRowType = {
pledge_amount: number;
host: string;
layer: string;
profit_percentage: string;
profit_percentage: number;
avg_uptime: string;
stake_saturation: React.ReactNode;
operating_cost: string;
node_performance: NodePerformance['most_recent'];
operating_cost: number;
node_performance: number;
blacklisted: boolean;
};
@@ -32,7 +32,7 @@ export function mixNodeResponseItemToMixnodeRowType(item: MixNodeResponseItem):
const delegations = Number(item.total_delegation.amount) || 0;
const totalBond = pledge + delegations;
const selfPercentage = ((pledge * 100) / totalBond).toFixed(2);
const profitPercentage = toPercentIntegerString(item.profit_margin_percent) || 0;
const profitPercentage = toPercentInteger(item.profit_margin_percent) || 0;
const uncappedSaturation = typeof item.uncapped_saturation === 'number' ? item.uncapped_saturation * 100 : 0;
return {
@@ -47,11 +47,11 @@ export function mixNodeResponseItemToMixnodeRowType(item: MixNodeResponseItem):
pledge_amount: pledge,
host: item?.mix_node?.host || '',
layer: item?.layer || '',
profit_percentage: `${profitPercentage}%`,
profit_percentage: profitPercentage,
avg_uptime: `${toPercentIntegerString(item.node_performance.last_24h)}%`,
stake_saturation: Number(uncappedSaturation.toFixed(2)),
operating_cost: `${unymToNym(item.operating_cost?.amount, 6)} NYM`,
node_performance: `${toPercentIntegerString(item.node_performance.most_recent)}%`,
operating_cost: Number(unymToNym(item.operating_cost?.amount, 6)) || 0,
node_performance: toPercentInteger(item.node_performance.most_recent),
blacklisted: item.blacklisted,
};
}
+3 -3
View File
@@ -210,7 +210,7 @@ export const PageMixnodes: FCWithChildren = () => {
component={RRDLink}
to={`/network-components/mixnode/${params.row.mix_id}`}
>
{params.value}
{params.value}%
</MuiLink>
),
},
@@ -233,7 +233,7 @@ export const PageMixnodes: FCWithChildren = () => {
component={RRDLink}
to={`/network-components/mixnode/${params.row.mix_id}`}
>
{params.value}
{params.value} NYM
</MuiLink>
),
},
@@ -256,7 +256,7 @@ export const PageMixnodes: FCWithChildren = () => {
component={RRDLink}
to={`/network-components/mixnode/${params.row.mix_id}`}
>
{params.value}
{params.value}%
</MuiLink>
),
},
+1
View File
@@ -55,6 +55,7 @@ export const splice = (start: number, deleteCount: number, address?: string): st
* @returns A stringified integer
*/
export const toPercentIntegerString = (value: string) => Math.round(Number(value) * 100).toString();
export const toPercentInteger = (value: string) => Math.round(Number(value) * 100);
export const textColour = (value: EconomicsRowsType, field: string, theme: Theme) => {
const progressBarValue = value?.progressBarValue || 0;
@@ -1,5 +1,4 @@
use std::{
collections::HashMap,
fmt,
hash::{Hash, Hasher},
net::SocketAddr,
@@ -8,6 +7,7 @@ use std::{
};
use base64::{engine::general_purpose, Engine};
use dashmap::DashMap;
use hmac::{Hmac, Mac};
use nym_crypto::asymmetric::encryption::PrivateKey;
use serde::{Deserialize, Serialize};
@@ -178,4 +178,4 @@ impl<'de> Deserialize<'de> for ClientPublicKey {
}
}
pub(crate) type ClientRegistry = HashMap<SocketAddr, Client>;
pub(crate) type ClientRegistry = DashMap<SocketAddr, Client>;
+15 -16
View File
@@ -14,8 +14,7 @@ use crate::node::http::ApiState;
async fn process_final_message(client: Client, state: Arc<ApiState>) -> StatusCode {
let preshared_nonce = {
let in_progress_ro = state.registration_in_progress.read().await;
if let Some(nonce) = in_progress_ro.get(client.pub_key()) {
if let Some(nonce) = state.registration_in_progress.get(client.pub_key()) {
*nonce
} else {
return StatusCode::BAD_REQUEST;
@@ -27,12 +26,10 @@ async fn process_final_message(client: Client, state: Arc<ApiState>) -> StatusCo
.is_ok()
{
{
let mut in_progress_rw = state.registration_in_progress.write().await;
in_progress_rw.remove(client.pub_key());
state.registration_in_progress.remove(client.pub_key());
}
{
let mut registry_rw = state.client_registry.write().await;
registry_rw.insert(client.socket(), client);
state.client_registry.insert(client.socket(), client);
}
return StatusCode::OK;
}
@@ -42,8 +39,9 @@ async fn process_final_message(client: Client, state: Arc<ApiState>) -> StatusCo
async fn process_init_message(init_message: InitMessage, state: Arc<ApiState>) -> u64 {
let nonce: u64 = fastrand::u64(..);
let mut registry_rw = state.registration_in_progress.write().await;
registry_rw.insert(init_message.pub_key().clone(), nonce);
state
.registration_in_progress
.insert(init_message.pub_key().clone(), nonce);
nonce
}
@@ -67,12 +65,12 @@ pub(crate) async fn register_client(
pub(crate) async fn get_all_clients(
State(state): State<Arc<ApiState>>,
) -> (StatusCode, Json<Vec<ClientPublicKey>>) {
let registry_ro = state.client_registry.read().await;
(
StatusCode::OK,
Json(
registry_ro
.values()
state
.client_registry
.iter()
.map(|c| c.pub_key().clone())
.collect::<Vec<ClientPublicKey>>(),
),
@@ -87,12 +85,13 @@ pub(crate) async fn get_client(
Ok(pub_key) => pub_key,
Err(_) => return (StatusCode::BAD_REQUEST, Json(vec![])),
};
let registry_ro = state.client_registry.read().await;
let clients = registry_ro
let clients = state
.client_registry
.iter()
.filter_map(|(_, c)| {
if c.pub_key() == &pub_key {
Some(c.clone())
.filter_map(|r| {
let client = r.value();
if client.pub_key() == &pub_key {
Some(client.clone())
} else {
None
}
+15 -16
View File
@@ -1,12 +1,12 @@
use std::{collections::HashMap, sync::Arc};
use std::sync::Arc;
use axum::{
routing::{get, post},
Router,
};
use dashmap::DashMap;
use log::info;
use nym_crypto::asymmetric::encryption;
use tokio::sync::RwLock;
mod api;
use api::v1::client_registry::*;
@@ -16,9 +16,9 @@ use super::client_handling::client_registration::{ClientPublicKey, ClientRegistr
const ROUTE_PREFIX: &str = "/api/v1/gateway/client-interfaces/wireguard";
pub struct ApiState {
client_registry: Arc<RwLock<ClientRegistry>>,
client_registry: Arc<ClientRegistry>,
sphinx_key_pair: Arc<encryption::KeyPair>,
registration_in_progress: Arc<RwLock<HashMap<ClientPublicKey, u64>>>,
registration_in_progress: Arc<DashMap<ClientPublicKey, u64>>,
}
fn router_with_state(state: Arc<ApiState>) -> Router {
@@ -33,7 +33,7 @@ fn router_with_state(state: Arc<ApiState>) -> Router {
}
pub(crate) async fn start_http_api(
client_registry: Arc<RwLock<ClientRegistry>>,
client_registry: Arc<ClientRegistry>,
sphinx_key_pair: Arc<encryption::KeyPair>,
) {
// Port should be 80 post smoosh
@@ -46,7 +46,7 @@ pub(crate) async fn start_http_api(
let state = Arc::new(ApiState {
client_registry,
sphinx_key_pair,
registration_in_progress: Arc::new(RwLock::new(HashMap::new())),
registration_in_progress: Arc::new(DashMap::new()),
});
let routes = router_with_state(state);
@@ -62,17 +62,17 @@ pub(crate) async fn start_http_api(
mod test {
use std::net::SocketAddr;
use std::str::FromStr;
use std::{collections::HashMap, sync::Arc};
use std::sync::Arc;
use axum::body::Body;
use axum::http::Request;
use axum::http::StatusCode;
use dashmap::DashMap;
use hmac::Mac;
use tower::Service;
use tower::ServiceExt;
use nym_crypto::asymmetric::encryption;
use tokio::sync::RwLock;
use x25519_dalek::{PublicKey, StaticSecret};
use crate::node::client_handling::client_registration::{
@@ -105,8 +105,8 @@ mod test {
let client_dh = client_static_private.diffie_hellman(&gateway_static_public);
let registration_in_progress = Arc::new(RwLock::new(HashMap::new()));
let client_registry = Arc::new(RwLock::new(HashMap::new()));
let registration_in_progress = Arc::new(DashMap::new());
let client_registry = Arc::new(DashMap::new());
let state = Arc::new(ApiState {
client_registry: Arc::clone(&client_registry),
@@ -136,7 +136,7 @@ mod test {
.unwrap();
assert_eq!(response.status(), StatusCode::OK);
assert!(!registration_in_progress.read().await.is_empty());
assert!(!registration_in_progress.is_empty());
let nonce: Option<u64> =
serde_json::from_slice(&hyper::body::to_bytes(response.into_body()).await.unwrap())
@@ -171,7 +171,7 @@ mod test {
.unwrap();
assert_eq!(response.status(), StatusCode::OK);
assert!(!client_registry.read().await.is_empty());
assert!(!client_registry.is_empty());
let clients_request = Request::builder()
.method("GET")
@@ -194,11 +194,10 @@ mod test {
assert!(!clients.is_empty());
let ro_clients = client_registry.read().await.clone();
assert_eq!(
ro_clients
.values()
.map(|c| c.pub_key().clone())
client_registry
.iter()
.map(|c| c.value().pub_key().clone())
.collect::<Vec<ClientPublicKey>>(),
clients
)
+4 -5
View File
@@ -18,6 +18,7 @@ use crate::node::mixnet_handling::receiver::connection_handler::ConnectionHandle
use crate::node::statistics::collector::GatewayStatisticsCollector;
use crate::node::storage::Storage;
use anyhow::bail;
use dashmap::DashMap;
use futures::channel::{mpsc, oneshot};
use log::*;
use nym_crypto::asymmetric::{encryption, identity};
@@ -29,12 +30,10 @@ use nym_task::{TaskClient, TaskManager};
use nym_validator_client::{nyxd, DirectSigningHttpRpcNyxdClient};
use rand::seq::SliceRandom;
use rand::thread_rng;
use std::collections::HashMap;
use std::error::Error;
use std::net::SocketAddr;
use std::path::PathBuf;
use std::sync::Arc;
use tokio::sync::RwLock;
pub(crate) mod client_handling;
pub(crate) mod helpers;
@@ -91,7 +90,7 @@ pub(crate) struct Gateway<St = PersistentStorage> {
sphinx_keypair: Arc<encryption::KeyPair>,
storage: St,
client_registry: Arc<RwLock<ClientRegistry>>,
client_registry: Arc<ClientRegistry>,
}
impl<St> Gateway<St> {
@@ -107,7 +106,7 @@ impl<St> Gateway<St> {
sphinx_keypair: Arc::new(helpers::load_sphinx_keys(&config)?),
config,
network_requester_opts,
client_registry: Arc::new(RwLock::new(HashMap::new())),
client_registry: Arc::new(DashMap::new()),
})
}
@@ -125,7 +124,7 @@ impl<St> Gateway<St> {
identity_keypair: Arc::new(identity_keypair),
sphinx_keypair: Arc::new(sphinx_keypair),
storage,
client_registry: Arc::new(RwLock::new(HashMap::new())),
client_registry: Arc::new(DashMap::new()),
}
}
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "extension-storage"
version = "1.2.0-rc.10"
version = "1.2.0"
edition = "2021"
license = "Apache-2.0"
repository = "https://github.com/nymtech/nym"
+6
View File
@@ -2,6 +2,12 @@
## [Unreleased]
## [v1.2.9] (2023-10-10)
- Wallet: Introduce edit account name ([#3895])
[#3895]: https://github.com/nymtech/nym/pull/3895
## [v1.2.8] (2023-08-23)
- [hotfix]: don't assign invalid fields when crossing the JS boundary ([#3805])
+1 -1
View File
@@ -3512,7 +3512,7 @@ dependencies = [
[[package]]
name = "nym_wallet"
version = "1.2.8"
version = "1.2.9"
dependencies = [
"async-trait",
"base64 0.13.1",
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@nymproject/nym-wallet-app",
"version": "1.2.8",
"version": "1.2.9",
"main": "index.js",
"license": "MIT",
"scripts": {
@@ -123,4 +123,4 @@
"webpack-favicons": "^1.3.8",
"webpack-merge": "^5.8.0"
}
}
}
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "nym_wallet"
version = "1.2.8"
version = "1.2.9"
description = "Nym Native Wallet"
authors = ["Nym Technologies SA"]
license = ""
+1 -1
View File
@@ -1,7 +1,7 @@
{
"package": {
"productName": "nym-wallet",
"version": "1.2.8"
"version": "1.2.9"
},
"build": {
"distDir": "../dist",
+1 -8
View File
@@ -125,7 +125,6 @@ export type TBondingContext = {
updateBondAmount: (data: TUpdateBondArgs, tokenPool: TokenPool) => Promise<TransactionExecuteResult | undefined>;
redeemRewards: (fee?: FeeDetails) => Promise<TransactionExecuteResult | undefined>;
updateMixnode: (pm: string, fee?: FeeDetails) => Promise<TransactionExecuteResult | undefined>;
checkOwnership: () => Promise<void>;
generateMixnodeMsgPayload: (data: TBondMixnodeSignatureArgs) => Promise<string | undefined>;
generateGatewayMsgPayload: (data: TBondGatewaySignatureArgs) => Promise<string | undefined>;
isVestingAccount: boolean;
@@ -152,9 +151,6 @@ export const BondingContext = createContext<TBondingContext>({
updateMixnode: async () => {
throw new Error('Not implemented');
},
checkOwnership(): Promise<void> {
throw new Error('Not implemented');
},
generateMixnodeMsgPayload: async () => {
throw new Error('Not implemented');
},
@@ -171,7 +167,7 @@ export const BondingContextProvider: FCWithChildren = ({ children }): JSX.Elemen
const [isVestingAccount, setIsVestingAccount] = useState(false);
const { userBalance, clientDetails } = useContext(AppContext);
const { ownership, isLoading: isOwnershipLoading, checkOwnership } = useCheckOwnership();
const { ownership, isLoading: isOwnershipLoading } = useCheckOwnership();
useEffect(() => {
userBalance.fetchBalance();
@@ -342,8 +338,6 @@ export const BondingContextProvider: FCWithChildren = ({ children }): JSX.Elemen
setIsLoading(true);
setError(undefined);
await checkOwnership();
if (ownership.hasOwnership && ownership.nodeType === EnumNodeType.mixnode && clientDetails) {
try {
const data = await getMixnodeBondDetails();
@@ -617,7 +611,6 @@ export const BondingContextProvider: FCWithChildren = ({ children }): JSX.Elemen
refresh,
redeemRewards,
updateBondAmount,
checkOwnership,
generateMixnodeMsgPayload,
generateGatewayMsgPayload,
isVestingAccount,
+2 -3
View File
@@ -4,7 +4,7 @@ import { AppContext } from '../context/main';
import { checkGatewayOwnership, checkMixnodeOwnership, getVestingPledgeInfo } from '../requests';
import { EnumNodeType, TNodeOwnership } from '../types';
const initial = {
const initial: TNodeOwnership = {
hasOwnership: false,
nodeType: undefined,
vestingPledge: undefined,
@@ -18,8 +18,7 @@ export const useCheckOwnership = () => {
const [error, setError] = useState<string>();
const checkOwnership = useCallback(async () => {
const status = initial as TNodeOwnership;
const status = { ...initial };
try {
const [ownsMixnode, ownsGateway] = await Promise.all([checkMixnodeOwnership(), checkGatewayOwnership()]);
+3 -12
View File
@@ -34,17 +34,8 @@ const Bonding = () => {
const navigate = useNavigate();
const {
bondedNode,
bondMixnode,
bondGateway,
redeemRewards,
isLoading,
checkOwnership,
updateBondAmount,
error,
refresh,
} = useBondingContext();
const { bondedNode, bondMixnode, bondGateway, redeemRewards, isLoading, updateBondAmount, error, refresh } =
useBondingContext();
useEffect(() => {
if (bondedNode && isMixnode(bondedNode) && bondedNode.uncappedStakeSaturation) {
@@ -54,7 +45,7 @@ const Bonding = () => {
const handleCloseModal = async () => {
setShowModal(undefined);
await checkOwnership();
refresh();
};
const handleError = (err: string) => {
+15 -10
View File
@@ -6,7 +6,10 @@
"workspaces": [
"dist/wasm/**",
"dist/node/**",
"sdk/typescript/packages/**",
"dist/ts/**",
"sdk/typescript/packages/mui-theme",
"sdk/typescript/packages/react-components",
"sdk/typescript/packages/validator-client",
"ts-packages/*",
"nym-wallet",
"nym-connect/**",
@@ -16,22 +19,22 @@
],
"scripts": {
"nuke": "npx rimraf **/node_modules node_modules",
"scrub": "npx rimraf **/dist dist",
"clean": "lerna run clean",
"build:ci:sdk": "run-s build:types build:packages build:wasm build:sdk:ci",
"build:sdk:ci": "lerna run --scope '{@nymproject/sdk,@nymproject/node-tester,@nymproject/sdk-react,@nymproject/mix-fetch}' build:dev --stream",
"build": "run-s build:types build:packages",
"build:wasm": "make sdk-wasm-build",
"build:sdk": "make sdk-typescript-build",
"build:types": "lerna run --scope @nymproject/types build --stream",
"build:packages": "run-s build:packages:theme build:packages:react",
"build:packages:theme": "lerna run --scope @nymproject/mui-theme build",
"build:packages:react": "lerna run --scope @nymproject/react build",
"build:react-example": "lerna run --scope @nymproject/react-webpack-with-theme-example build --stream",
"build:playground": "lerna run --scope @nymproject/react storybook:build --stream",
"build:ci": "yarn build && run-p build:react-example build:playground && yarn build:ci:collect-artifacts",
"build:ci:collect-artifacts": "mkdir -p ts-packages/dist && mv ts-packages/react-components/storybook-static ts-packages/dist/storybook && mv ts-packages/react-webpack-with-theme-example/dist ts-packages/dist/example",
"build:ci:storybook": "yarn build && yarn dev:on && run-p build:react-example build:playground && yarn build:ci:storybook:collect-artifacts",
"build:ci:storybook:collect-artifacts": "mkdir -p ts-packages/dist && mv sdk/typescript/packages/react-components/storybook-static ts-packages/dist/storybook && mv sdk/typescript/examples/react/mui-theme/dist ts-packages/dist/example",
"prebuild:ci": "yarn dev:on && yarn",
"build:ci": "run-s build:types build:packages build:wasm build:ci:sdk",
"postbuild:ci": "yarn dev:off",
"build:ci:sdk": "lerna run --scope '{@nymproject/sdk,@nymproject/node-tester,@nymproject/sdk-react,@nymproject/mix-fetch}' build:dev --stream",
"docs:prod:build": "run-s docs:prod:build:ws",
"docs:prod:build:ws": "lerna run docs:prod:build --stream",
"sdk:build": "./sdk/typescript/scripts/build-prod-sdk.sh",
@@ -40,7 +43,9 @@
"lint:fix": "lerna run lint:fix --stream",
"tsc": "lerna run tsc --stream",
"types:lint:fix": "lerna run lint:fix --scope @nymproject/types --scope @nymproject/nym-wallet-app",
"audit:fix": "npm_config_yes=true npx yarn-audit-fix -- --dry-run"
"audit:fix": "npm_config_yes=true npx yarn-audit-fix -- --dry-run",
"dev:on": "node sdk/typescript/scripts/dev-mode-add.mjs",
"dev:off": "node sdk/typescript/scripts/dev-mode-remove.mjs"
},
"devDependencies": {
"lerna": "^7.3.0",
@@ -48,4 +53,4 @@
"@npmcli/node-gyp": "^3.0.0",
"node-gyp": "^9.3.1"
}
}
}
@@ -45,7 +45,6 @@ use libp2p::ping::Success;
use libp2p::swarm::{keep_alive, NetworkBehaviour, SwarmEvent};
use libp2p::{identity, ping, Multiaddr, PeerId};
use log::{debug, info, LevelFilter};
use nym_sdk::mixnet::MixnetClient;
use std::error::Error;
use std::time::Duration;
@@ -70,7 +69,7 @@ async fn main() -> Result<(), Box<dyn Error>> {
use libp2p::swarm::SwarmBuilder;
use rust_libp2p_nym::transport::NymTransport;
let client = MixnetClient::connect_new().await.unwrap();
let client = nym_sdk::mixnet::MixnetClient::connect_new().await.unwrap();
let transport = NymTransport::new(client, local_key.clone()).await?;
SwarmBuilder::with_tokio_executor(
@@ -80,6 +80,7 @@ pub struct NymTransport {
impl NymTransport {
/// New transport.
#[allow(unused)]
pub async fn new(client: MixnetClient, keypair: Keypair) -> Result<Self, Error> {
Self::new_maybe_with_notify_inbound(client, keypair, None, None).await
}
@@ -1,6 +1,6 @@
{
"name": "@nymproject/contract-clients",
"version": "1.2.0-rc.10",
"version": "1.2.0",
"description": "A client for all Nym smart contracts",
"license": "Apache-2.0",
"author": "Nym Technologies SA",
+6 -6
View File
@@ -1,6 +1,6 @@
{
"name": "@nymproject/ts-sdk-docs",
"version": "1.2.0-rc.10",
"version": "1.2.0",
"description": "Nym Typescript SDK Docs",
"license": "Apache-2.0",
"author": "Nym Technologies SA",
@@ -28,10 +28,10 @@
"@mui/icons-material": "^5.14.9",
"@mui/lab": "^5.0.0-alpha.145",
"@mui/material": "^5.14.8",
"@nymproject/contract-clients": "^1.2.0-rc.9",
"@nymproject/mix-fetch": "^1.2.0-rc.9",
"@nymproject/mix-fetch-full-fat": "^1.2.0-rc.9",
"@nymproject/sdk-full-fat": "^1.2.0-rc.9",
"@nymproject/contract-clients": ">=1.2.0-rc.10 || ^1",
"@nymproject/mix-fetch": ">=1.2.0-rc.10 || ^1",
"@nymproject/mix-fetch-full-fat": ">=1.2.0-rc.10 || ^1",
"@nymproject/sdk-full-fat": ">=1.2.0-rc.10 || ^1",
"chain-registry": "^1.19.0",
"cosmjs-types": "^0.8.0",
"next": "^13.4.19",
@@ -51,4 +51,4 @@
"typescript": "^4.9.3"
},
"private": false
}
}
@@ -6,7 +6,7 @@
"source": "src/index.html",
"browserslist": "> 0.5%, last 2 versions, not dead",
"dependencies": {
"@nymproject/sdk": "1.2.0-rc.1"
"@nymproject/sdk": ">=1.2.0-rc.10 || ^1"
},
"devDependencies": {
"@types/jest": "^27.0.1",
@@ -4,7 +4,7 @@
"version": "1.0.0",
"license": "Apache-2.0",
"dependencies": {
"@nymproject/sdk": "1.2.0-rc.1"
"@nymproject/sdk": ">=1.2.0-rc.10 || ^1"
},
"devDependencies": {
"@babel/core": "^7.15.0",
@@ -9,7 +9,7 @@
"@mui/material": "^5.0.1",
"@mui/styles": "^5.0.1",
"react-mui-dropzone": "^4.0.6",
"@nymproject/sdk": "1.2.0-rc.1",
"@nymproject/sdk": ">=1.2.0-rc.10 || ^1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-dropzone": "^14.2.3",
@@ -15,6 +15,6 @@
"webpack-cli": "^5.1.4"
},
"dependencies": {
"@nymproject/sdk": "1.2.0-rc.1"
"@nymproject/sdk": ">=1.2.0-rc.10 || ^1"
}
}
@@ -15,6 +15,6 @@
"build": "yarn webpack"
},
"dependencies": {
"@nymproject/sdk": "1.2.0-rc.1"
"@nymproject/sdk": ">=1.2.0-rc.10 || ^1"
}
}
@@ -5,7 +5,7 @@
"source": "src/index.html",
"dependencies": {
"parcel": "^2.9.3",
"@nymproject/mix-fetch": ">=1.2.0-rc.7 || ^1"
"@nymproject/mix-fetch": ">=1.2.0-rc.10 || ^1"
},
"scripts": {
"start": "parcel --no-cache",
@@ -6,7 +6,7 @@
"source": "src/index.html",
"browserslist": "> 0.5%, last 2 versions, not dead",
"dependencies": {
"@nymproject/sdk": "1.2.0-rc.1"
"@nymproject/sdk": ">=1.2.0-rc.10 || ^1"
},
"devDependencies": {
"@types/jest": "^27.0.1",
@@ -4,7 +4,7 @@
"version": "1.0.0",
"license": "Apache-2.0",
"dependencies": {
"@nymproject/sdk": "1.2.0-rc.1"
"@nymproject/sdk": ">=1.2.0-rc.10 || ^1"
},
"devDependencies": {
"@babel/core": "^7.15.0",
@@ -8,7 +8,7 @@
"@emotion/styled": "^11.11.0",
"@mui/icons-material": "^5.14.0",
"@mui/material": "^5.14.0",
"@nymproject/sdk": "1.2.0-rc.1",
"@nymproject/sdk": ">=1.2.0-rc.10 || ^1",
"parcel": "^2.9.3",
"react": "^18.2.0",
"react-dom": "^18.2.0"
@@ -1,5 +1,5 @@
{
"extends": "../tsconfig.json",
"extends": "../../../tsconfig.json",
"compilerOptions": {
"jsx": "react-jsx",
"outDir": "./dist"
@@ -1,5 +1,5 @@
{
"extends": "../tsconfig.json",
"extends": "../../../tsconfig.json",
"compilerOptions": {
"jsx": "react-jsx",
"outDir": "./dist",
@@ -3,7 +3,7 @@
"version": "1.0.0",
"license": "Apache-2.0",
"dependencies": {
"@nymproject/mix-fetch": ">=1.2.0-rc.7 || ^1"
"@nymproject/mix-fetch": ">=1.2.0-rc.10 || ^1"
},
"devDependencies": {
"@babel/core": "^7.22.10",
@@ -4,7 +4,7 @@
"license": "Apache-2.0",
"source": "../src/index.html",
"dependencies": {
"@nymproject/mix-fetch": ">=1.2.0-rc.7 || ^1"
"@nymproject/mix-fetch": ">=1.2.0-rc.10 || ^1"
},
"scripts": {
"start": "npx parcel --no-cache",
@@ -1,6 +1,6 @@
{
"name": "@nymproject/mix-fetch",
"version": "1.2.0-rc.10",
"version": "1.2.0",
"description": "This package is a drop-in replacement for `fetch` to send HTTP requests over the Nym Mixnet.",
"license": "Apache-2.0",
"author": "Nym Technologies SA",
@@ -33,7 +33,7 @@
"tsc": "tsc --noEmit true"
},
"dependencies": {
"@nymproject/mix-fetch-wasm": ">=1.2.0-rc.7 || 1",
"@nymproject/mix-fetch-wasm": ">=1.2.0-rc.10 || ^1",
"comlink": "^4.3.1"
},
"devDependencies": {
@@ -81,4 +81,4 @@
"private": false,
"type": "module",
"types": "./dist/esm/index.d.ts"
}
}
@@ -1,6 +1,6 @@
{
"name": "@nymproject/node-tester",
"version": "1.2.0-rc.10",
"version": "1.2.0",
"description": "This package provides a tester that can send test packets to mixnode that is part of the Nym Mixnet.",
"license": "Apache-2.0",
"author": "Nym Technologies SA",
@@ -25,7 +25,7 @@
"tsc": "tsc --noEmit true"
},
"dependencies": {
"@nymproject/nym-node-tester-wasm": ">=1.2.0-rc.7 || ^1",
"@nymproject/nym-node-tester-wasm": ">=1.2.0-rc.10 || ^1",
"comlink": "^4.3.1"
},
"devDependencies": {
@@ -71,4 +71,4 @@
"private": false,
"type": "module",
"types": "./dist/esm/index.d.ts"
}
}
@@ -1,6 +1,6 @@
{
"name": "@nymproject/sdk-react",
"version": "1.2.0-rc.10",
"version": "1.2.0",
"license": "Apache-2.0",
"author": "Nym Technologies SA",
"files": [
@@ -20,7 +20,7 @@
"tsc": "tsc --noEmit true"
},
"dependencies": {
"@nymproject/sdk": ">=1.2.0-rc.7 || ^1"
"@nymproject/sdk": ">=1.2.0-rc.10 || ^1"
},
"devDependencies": {
"@babel/core": "^7.17.5",
@@ -67,4 +67,4 @@
"private": false,
"type": "module",
"types": "./dist/index.d.ts"
}
}
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@nymproject/sdk",
"version": "1.2.0-rc.10",
"version": "1.2.0",
"license": "Apache-2.0",
"author": "Nym Technologies SA",
"files": [
@@ -30,7 +30,7 @@
"tsc": "tsc --noEmit true"
},
"dependencies": {
"@nymproject/nym-client-wasm": ">=1.2.0-rc.7 || ^1",
"@nymproject/nym-client-wasm": ">=1.2.0-rc.10 || ^1",
"comlink": "^4.3.1"
},
"devDependencies": {
@@ -80,4 +80,4 @@
"private": false,
"type": "module",
"types": "./dist/esm/index.d.ts"
}
}
@@ -1,6 +1,6 @@
{
"name": "@nymproject/nym-validator-client",
"version": "1.2.0-rc.10",
"version": "1.2.0",
"description": "A TypeScript client for interacting with smart contracts in Nym validators",
"license": "Apache-2.0",
"author": "Nym Technologies SA (https://nymtech.net)",
+12
View File
@@ -0,0 +1,12 @@
import fs from 'fs';
const packageJson = JSON.parse(fs.readFileSync('package.json').toString());
const devWorkspace = ['sdk/typescript/packages/**', 'sdk/typescript/examples/**'];
if (!packageJson.workspaces.includes(devWorkspace)) {
// add
packageJson.workspaces.push(...devWorkspace);
// write out modified file
fs.writeFileSync('package.json', JSON.stringify(packageJson, null, 2));
}
@@ -0,0 +1,11 @@
import fs from 'fs';
const packageJson = JSON.parse(fs.readFileSync('package.json').toString());
const devWorkspace = ['sdk/typescript/packages/**', 'sdk/typescript/examples/**'];
// remove
packageJson.workspaces = packageJson.workspaces.filter((w) => !devWorkspace.includes(w));
// write out modified file
fs.writeFileSync('package.json', JSON.stringify(packageJson, null, 2));
@@ -34,7 +34,7 @@ use nym_socks5_requests::{
};
use nym_sphinx::addressing::clients::Recipient;
use nym_sphinx::anonymous_replies::requests::AnonymousSenderTag;
use nym_sphinx::params::PacketSize;
use nym_sphinx::params::{PacketSize, PacketType};
use nym_sphinx::receiver::ReconstructedMessage;
use nym_statistics_common::collector::StatisticsSender;
use nym_task::connections::LaneQueueLengths;
@@ -321,6 +321,7 @@ impl NRServiceProviderBuilder {
let stats_collector_clone = stats_collector.clone();
let mixnet_client_sender = mixnet_client.split_sender();
let self_address = *mixnet_client.nym_address();
let packet_type = self.config.base.debug.traffic.packet_type;
// start the listener for mix messages
tokio::spawn(async move {
@@ -328,6 +329,7 @@ impl NRServiceProviderBuilder {
mixnet_client_sender,
mix_input_receiver,
stats_collector_clone,
packet_type,
)
.await;
});
@@ -420,6 +422,7 @@ impl NRServiceProvider {
mixnet_client_sender: nym_sdk::mixnet::MixnetClientSender,
mut mix_input_reader: MixProxyReader<MixnetMessage>,
stats_collector: Option<ServiceStatisticsCollector>,
packet_type: PacketType,
) {
loop {
tokio::select! {
@@ -440,7 +443,7 @@ impl NRServiceProvider {
}
}
let response_message = msg.into_input_message();
let response_message = msg.into_input_message(packet_type);
mixnet_client_sender.send(response_message).await.unwrap();
} else {
log::error!("Exiting: channel closed!");
@@ -11,6 +11,7 @@ use nym_socks5_requests::{
};
use nym_sphinx::addressing::clients::Recipient;
use nym_sphinx::anonymous_replies::requests::AnonymousSenderTag;
use nym_sphinx::params::PacketType;
use nym_task::connections::TransmissionLane;
use std::fmt::{Debug, Formatter};
@@ -148,8 +149,9 @@ impl MixnetMessage {
self.data.len()
}
pub(crate) fn into_input_message(self) -> InputMessage {
self.address.send_back_to(self.data, self.connection_id)
pub(crate) fn into_input_message(self, packet_type: PacketType) -> InputMessage {
self.address
.send_back_to(self.data, self.connection_id, packet_type)
}
}
@@ -175,17 +177,28 @@ impl MixnetAddress {
None
}
pub(super) fn send_back_to(self, message: Vec<u8>, connection_id: u64) -> InputMessage {
pub(super) fn send_back_to(
self,
message: Vec<u8>,
connection_id: u64,
packet_type: PacketType,
) -> InputMessage {
match self {
MixnetAddress::Known(recipient) => InputMessage::Regular {
recipient: *recipient,
data: message,
lane: TransmissionLane::ConnectionId(connection_id),
MixnetAddress::Known(recipient) => InputMessage::MessageWrapper {
message: Box::new(InputMessage::Regular {
recipient: *recipient,
data: message,
lane: TransmissionLane::ConnectionId(connection_id),
}),
packet_type,
},
MixnetAddress::Anonymous(sender_tag) => InputMessage::Reply {
recipient_tag: sender_tag,
data: message,
lane: TransmissionLane::ConnectionId(connection_id),
MixnetAddress::Anonymous(sender_tag) => InputMessage::MessageWrapper {
message: Box::new(InputMessage::Reply {
recipient_tag: sender_tag,
data: message,
lane: TransmissionLane::ConnectionId(connection_id),
}),
packet_type,
},
}
}
+14 -5
View File
@@ -174,15 +174,24 @@ fn initialise_internal_packages<P: AsRef<Path>>(root: P) -> InternalPackages {
packages.register_cargo("nym-browser-extension/storage");
// js packages that will have their package.json modified
packages.register_json("nym-wallet");
packages.register_json("sdk/typescript/docs");
packages.register_json("sdk/typescript/examples/chat-app/parcel");
packages.register_json("sdk/typescript/examples/chat-app/plain-html");
packages.register_json("sdk/typescript/examples/chat-app/react-webpack-with-theme-example");
packages.register_json("sdk/typescript/examples/chrome-extension");
packages.register_json("sdk/typescript/examples/firefox-extension");
packages.register_json("sdk/typescript/examples/mix-fetch/browser");
packages.register_json("sdk/typescript/examples/node-tester/parcel");
packages.register_json("sdk/typescript/examples/node-tester/plain-html");
packages.register_json("sdk/typescript/examples/node-tester/react");
packages.register_json("sdk/typescript/packages/mix-fetch");
packages.register_json("sdk/typescript/packages/mui-theme");
packages.register_json("sdk/typescript/packages/mix-fetch/internal-dev");
packages.register_json("sdk/typescript/packages/mix-fetch/internal-dev/parcel");
packages.register_json("sdk/typescript/packages/node-tester");
packages.register_json("sdk/typescript/packages/react-components");
packages.register_json("sdk/typescript/packages/nodejs-client");
packages.register_json("sdk/typescript/packages/sdk");
packages.register_json("sdk/typescript/packages/sdk-react");
packages.register_json("sdk/typescript/packages/validator-client");
packages.register_json("sdk/typescript/codegen/contract-clients");
packages.register_json("sdk/typescript/docs");
// dependencies that will have their versions adjusted in the above packages
packages.register_known_js_dependency("@nymproject/mix-fetch");
+1 -1
View File
@@ -1,7 +1,7 @@
[package]
name = "nym-client-wasm"
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jedrzej Stuczynski <andrew@nymtech.net>"]
version = "1.2.0-rc.10"
version = "1.2.0"
edition = "2021"
keywords = ["nym", "sphinx", "wasm", "webassembly", "privacy", "client"]
license = "Apache-2.0"
+1 -1
View File
@@ -1,7 +1,7 @@
[package]
name = "nym-wasm-sdk"
authors = ["Jedrzej Stuczynski <andrew@nymtech.net>"]
version = "1.2.0-rc.10"
version = "1.2.0"
edition = "2021"
keywords = ["nym", "sphinx", "wasm", "webassembly", "privacy"]
license = "Apache-2.0"
+1 -1
View File
@@ -1,7 +1,7 @@
[package]
name = "mix-fetch-wasm"
authors = ["Jedrzej Stuczynski <andrew@nymtech.net>"]
version = "1.2.0-rc.10"
version = "1.2.0"
edition = "2021"
keywords = ["nym", "fetch", "wasm", "webassembly", "privacy"]
license = "Apache-2.0"
+1 -1
View File
@@ -1,7 +1,7 @@
[package]
name = "nym-node-tester-wasm"
authors = ["Jedrzej Stuczynski <andrew@nymtech.net>"]
version = "1.2.0-rc.10"
version = "1.2.0"
edition = "2021"
keywords = ["nym", "sphinx", "webassembly", "privacy", "tester"]
license = "Apache-2.0"
+96 -1518
View File
File diff suppressed because it is too large Load Diff