From 30165c10af0df927f68c0f05ec5a832a61830bd5 Mon Sep 17 00:00:00 2001 From: Lorexia Date: Thu, 2 Nov 2023 13:05:34 +0100 Subject: [PATCH 01/80] Update contract client page --- sdk/typescript/docs/pages/examples/nym-smart-contracts.mdx | 5 ----- 1 file changed, 5 deletions(-) diff --git a/sdk/typescript/docs/pages/examples/nym-smart-contracts.mdx b/sdk/typescript/docs/pages/examples/nym-smart-contracts.mdx index 0c9ffb73c1..f13b9601cb 100644 --- a/sdk/typescript/docs/pages/examples/nym-smart-contracts.mdx +++ b/sdk/typescript/docs/pages/examples/nym-smart-contracts.mdx @@ -18,11 +18,6 @@ Lists of the different available clients and methods from the `Contract Clients` | Vesting Client | Manages NYM token vesting functionality. | [Vesting](https://github.com/nymtech/nym/blob/develop/sdk/typescript/codegen/contract-clients/src/Vesting.client.ts) | -Depending on your app or project's architecture, this could be any of the ESM or CJS versions of the `Contract Clients`. - - This and the following examples will use the ESbuild bundler. - If you'd like to use another one, we will document different bundlers and polyfills in the [bundling](https://sdk.nymtech.net/bundling) page. - ##### Environment Setup Begin by creating a directory and configuring your application environment: From d073442cfeebcc5ce0c719984a552706c34f3a58 Mon Sep 17 00:00:00 2001 From: Lorexia Date: Thu, 2 Nov 2023 14:45:44 +0100 Subject: [PATCH 02/80] Correct typo in docs --- sdk/typescript/docs/pages/examples/nym-smart-contracts.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/typescript/docs/pages/examples/nym-smart-contracts.mdx b/sdk/typescript/docs/pages/examples/nym-smart-contracts.mdx index f13b9601cb..669d284611 100644 --- a/sdk/typescript/docs/pages/examples/nym-smart-contracts.mdx +++ b/sdk/typescript/docs/pages/examples/nym-smart-contracts.mdx @@ -9,7 +9,7 @@ Lists of the different available clients and methods from the `Contract Clients` | Client name | Functionality| Methods list | | :-------------: | :----------: | :----------: | | Coconut Bandwidth Client| Manages the depositing and release of funds. Tracks double spending. | [Coconut Bandwidth](https://github.com/nymtech/nym/blob/develop/sdk/typescript/codegen/contract-clients/src/CoconutBandwidth.client.ts) | -| Coconut DKG Client | Allows signers partcipating in issuing Coconut credentials to derive keys to be used. | [Coconut DKG](https://github.com/nymtech/nym/blob/develop/sdk/typescript/codegen/contract-clients/src/CoconutDkg.client.ts) | +| Coconut DKG Client | Allows signers participating in issuing Coconut credentials to derive keys to be used. | [Coconut DKG](https://github.com/nymtech/nym/blob/develop/sdk/typescript/codegen/contract-clients/src/CoconutDkg.client.ts) | | Cw3FlexMultisig Client | Used by the Coconut APIs to issue credentials. [This](https://github.com/CosmWasm/cw-plus/tree/main/contracts/cw3-flex-multisig) is a multisig contract that is backed by the cw4 (group) contract, which independently maintains the voter set. | [Cw3Flex Multisig](https://github.com/nymtech/nym/blob/develop/sdk/typescript/codegen/contract-clients/src/Cw3FlexMultisig.client.ts) | | Cw4Group Client | Used by the Coconut APIs to issue credentials. [Cw4 Group](https://github.com/CosmWasm/cw-plus/tree/main/contracts/cw4-group) stores a set of members along with an admin, and allows the admin to update the state. | [Cw4Group](https://github.com/nymtech/nym/blob/develop/sdk/typescript/codegen/contract-clients/src/Cw4Group.client.ts) | | Mixnet Client | Manages the network topology of the mixnet, tracking delegations and rewards. | [Mixnet](https://github.com/nymtech/nym/blob/develop/sdk/typescript/codegen/contract-clients/src/Mixnet.client.ts) | From c1f2bf4f27541c1b37a3945d19b17a71602def3b Mon Sep 17 00:00:00 2001 From: Lorexia Date: Fri, 3 Nov 2023 11:02:07 +0100 Subject: [PATCH 03/80] Update versioning and mixfetch docs --- sdk/typescript/docs/components/mixfetch.tsx | 25 +++++++++-------- .../docs/pages/examples/mix-fetch.mdx | 28 ++----------------- 2 files changed, 15 insertions(+), 38 deletions(-) diff --git a/sdk/typescript/docs/components/mixfetch.tsx b/sdk/typescript/docs/components/mixfetch.tsx index 564de818e4..871194f617 100644 --- a/sdk/typescript/docs/components/mixfetch.tsx +++ b/sdk/typescript/docs/components/mixfetch.tsx @@ -12,17 +12,17 @@ import type { SetupMixFetchOps } from '@nymproject/mix-fetch'; const defaultUrl = 'https://nymtech.net/favicon.svg'; const args = { mode: 'unsafe-ignore-cors' }; -const extra = { - hiddenGateways: [ - { - owner: 'n1kymvkx6vsq7pvn6hfurkpg06h3j4gxj4em7tlg', - host: 'gateway1.nymtech.net', - explicitIp: '213.219.38.119', - identityKey: 'E3mvZTHQCdBvhfr178Swx9g4QG3kkRUun7YnToLMcMbM', - sphinxKey: 'CYcrjoJ8GT7Dp54zViUyyRUfegeRCyPifWQZHRgMZrfX', - }, - ], -}; +// const extra = { +// hiddenGateways: [ +// { +// owner: 'n1kymvkx6vsq7pvn6hfurkpg06h3j4gxj4em7tlg', +// host: 'gateway1.nymtech.net', +// explicitIp: '213.219.38.119', +// identityKey: 'E3mvZTHQCdBvhfr178Swx9g4QG3kkRUun7YnToLMcMbM', +// sphinxKey: 'CYcrjoJ8GT7Dp54zViUyyRUfegeRCyPifWQZHRgMZrfX', +// }, +// ], +// }; const mixFetchOptions: SetupMixFetchOps = { preferredGateway: 'E3mvZTHQCdBvhfr178Swx9g4QG3kkRUun7YnToLMcMbM', // with WSS @@ -32,7 +32,8 @@ const mixFetchOptions: SetupMixFetchOps = { requestTimeoutMs: 60_000, }, forceTls: true, // force WSS - extra, // manually set the gateway details for WSS so certificates will work for hostname + // extra, // manually set the gateway details for WSS so certificates will work for hostname + extra: {}, }; export const MixFetch = () => { diff --git a/sdk/typescript/docs/pages/examples/mix-fetch.mdx b/sdk/typescript/docs/pages/examples/mix-fetch.mdx index 6d839864d2..ec0095e1d5 100644 --- a/sdk/typescript/docs/pages/examples/mix-fetch.mdx +++ b/sdk/typescript/docs/pages/examples/mix-fetch.mdx @@ -29,18 +29,6 @@ Read [this article](https://blog.nymtech.net/mixfetch-like-the-fetch-api-but-via // For mainnet import type { SetupMixFetchOps } from '@nymproject/mix-fetch'; -const extra = { - hiddenGateways: [ - { - owner: 'n1kymvkx6vsq7pvn6hfurkpg06h3j4gxj4em7tlg', - host: 'gateway1.nymtech.net', - explicitIp: '213.219.38.119', - identityKey: 'E3mvZTHQCdBvhfr178Swx9g4QG3kkRUun7YnToLMcMbM', - sphinxKey: 'CYcrjoJ8GT7Dp54zViUyyRUfegeRCyPifWQZHRgMZrfX', - }, - ], -}; - const mixFetchOptions: SetupMixFetchOps = { preferredGateway: 'E3mvZTHQCdBvhfr178Swx9g4QG3kkRUun7YnToLMcMbM', // with WSS preferredNetworkRequester: @@ -49,7 +37,7 @@ const mixFetchOptions: SetupMixFetchOps = { requestTimeoutMs: 60_000, }, forceTls: true, // force WSS - extra, // manually set the gateway details for WSS so certificates will work for hostname + extra: {}, }; ``` @@ -95,18 +83,6 @@ import "./App.css"; import { mixFetch, SetupMixFetchOps } from '@nymproject/mix-fetch-full-fat'; import React from 'react'; -const extra = { - hiddenGateways: [ - { - owner: 'n1kymvkx6vsq7pvn6hfurkpg06h3j4gxj4em7tlg', - host: 'gateway1.nymtech.net', - explicitIp: '213.219.38.119', - identityKey: 'E3mvZTHQCdBvhfr178Swx9g4QG3kkRUun7YnToLMcMbM', - sphinxKey: 'CYcrjoJ8GT7Dp54zViUyyRUfegeRCyPifWQZHRgMZrfX', - }, - ], -}; - const mixFetchOptions: SetupMixFetchOps = { preferredGateway: 'E3mvZTHQCdBvhfr178Swx9g4QG3kkRUun7YnToLMcMbM', // with WSS preferredNetworkRequester: @@ -115,7 +91,7 @@ const mixFetchOptions: SetupMixFetchOps = { requestTimeoutMs: 60_000, }, forceTls: true, // force WSS - extra + extra: {}, }; From a7f9cb7db0d9b8b45cd67ab3166d2e8d721abb2d Mon Sep 17 00:00:00 2001 From: Lorexia Date: Fri, 3 Nov 2023 12:48:55 +0100 Subject: [PATCH 04/80] mimxnet client examples updates --- .../docs/code-examples/mixfetch-example-code.mdx | 10 ++++++++-- sdk/typescript/docs/components/traffic.tsx | 1 + sdk/typescript/docs/pages/examples/mix-fetch.mdx | 4 ---- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/sdk/typescript/docs/code-examples/mixfetch-example-code.mdx b/sdk/typescript/docs/code-examples/mixfetch-example-code.mdx index 70ba77f9d1..780df512ed 100644 --- a/sdk/typescript/docs/code-examples/mixfetch-example-code.mdx +++ b/sdk/typescript/docs/code-examples/mixfetch-example-code.mdx @@ -8,16 +8,21 @@ import Box from '@mui/material/Box'; import { mixFetch } from '@nymproject/mix-fetch-full-fat'; import Stack from '@mui/material/Stack'; import Paper from '@mui/material/Paper'; +import type { SetupMixFetchOps } from '@nymproject/mix-fetch'; const defaultUrl = 'https://nymtech.net/favicon.svg'; const args = { mode: 'unsafe-ignore-cors' }; -const mixFetchOptions = { - preferredGateway: 'E3mvZTHQCdBvhfr178Swx9g4QG3kkRUun7YnToLMcMbM', + + +const mixFetchOptions: SetupMixFetchOps = { + preferredGateway: 'E3mvZTHQCdBvhfr178Swx9g4QG3kkRUun7YnToLMcMbM', // with WSS preferredNetworkRequester: 'GiRjFWrMxt58pEMuusm4yT3RxoMD1MMPrR9M2N4VWRJP.3CNZBPq4vg7v7qozjGjdPMXcvDmkbWPCgbGCjQVw9n6Z@2xU4CBE6QiiYt6EyBXSALwxkNvM7gqJfjHXaMkjiFmYW', mixFetchOverride: { requestTimeoutMs: 60_000, }, + forceTls: true, // force WSS + extra: {}, }; export const MixFetch = () => { @@ -77,4 +82,5 @@ export const MixFetch = () => { ); }; + ``` diff --git a/sdk/typescript/docs/components/traffic.tsx b/sdk/typescript/docs/components/traffic.tsx index 9205382d2d..344ce476a1 100644 --- a/sdk/typescript/docs/components/traffic.tsx +++ b/sdk/typescript/docs/components/traffic.tsx @@ -26,6 +26,7 @@ export const Traffic = () => { await client?.client.start({ clientId: crypto.randomUUID(), nymApiUrl, + preferredGatewayIdentityKey: 'E3mvZTHQCdBvhfr178Swx9g4QG3kkRUun7YnToLMcMbM', // force WSS }); // check when is connected and set the self address diff --git a/sdk/typescript/docs/pages/examples/mix-fetch.mdx b/sdk/typescript/docs/pages/examples/mix-fetch.mdx index ec0095e1d5..4f24271f04 100644 --- a/sdk/typescript/docs/pages/examples/mix-fetch.mdx +++ b/sdk/typescript/docs/pages/examples/mix-fetch.mdx @@ -72,10 +72,6 @@ import { mixFetch } from "@nymproject/mix-fetch-full-fat"; ##### Example: using the `mixFetch` client: - - Again, for this example, we will be using the `full-fat` version of the ESM SDK. - - `Get` and `Post` outputs will be observable from your console. ```ts From 4c2c738bbae363b3481c8de2ecf0f587fe3f9c05 Mon Sep 17 00:00:00 2001 From: Lorexia Date: Fri, 3 Nov 2023 14:04:24 +0100 Subject: [PATCH 05/80] Update versioning for sanity check --- sdk/typescript/docs/package.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sdk/typescript/docs/package.json b/sdk/typescript/docs/package.json index 0fcfab0d3d..f757878cfb 100644 --- a/sdk/typescript/docs/package.json +++ b/sdk/typescript/docs/package.json @@ -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.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", + "@nymproject/contract-clients": "1.2.1 || ^1", + "@nymproject/mix-fetch": "1.2.1 || ^1", + "@nymproject/mix-fetch-full-fat": "1.2.1 || ^1", + "@nymproject/sdk-full-fat": "1.2.1 || ^1", "chain-registry": "^1.19.0", "cosmjs-types": "^0.8.0", "next": "^13.4.19", From 5a96ef4ffe08dfc8b6b9bdf551a99c91d1a9c6b4 Mon Sep 17 00:00:00 2001 From: Lorexia Date: Tue, 7 Nov 2023 12:20:35 +0100 Subject: [PATCH 06/80] Update mixnet docs --- sdk/typescript/docs/pages/playground/traffic.mdx | 3 --- 1 file changed, 3 deletions(-) diff --git a/sdk/typescript/docs/pages/playground/traffic.mdx b/sdk/typescript/docs/pages/playground/traffic.mdx index 8435f3b2f0..6c845227e2 100644 --- a/sdk/typescript/docs/pages/playground/traffic.mdx +++ b/sdk/typescript/docs/pages/playground/traffic.mdx @@ -4,9 +4,6 @@ import { Traffic } from '../../components/traffic'; import Box from '@mui/material/Box'; import FormattedTrafficExampleCode from '../../code-examples/traffic-example-code.mdx'; - - Currently, due to SSL-related issues, the mixnet client is functional exclusively in local development environments. Unless you clone this repository or create your own build, you may encounter limitations when attempting to test this example. - Use this tool to experiment with the mixnet: send and receive messages! From 46d1ef789262a20f4f563a9f4880b6e0ed467c04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=20H=C3=A4ggblad?= Date: Thu, 9 Nov 2023 12:16:33 +0100 Subject: [PATCH 07/80] Disable poisson in ip-packet-router (#4123) --- Cargo.lock | 1 + gateway/src/commands/helpers.rs | 12 +++++- service-providers/ip-packet-router/Cargo.toml | 1 + .../ip-packet-router/src/config/mod.rs | 37 ++++++++++++++++++- 4 files changed, 48 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c167170d73..bf1c54e50b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6668,6 +6668,7 @@ dependencies = [ "tap", "thiserror", "tokio", + "url", ] [[package]] diff --git a/gateway/src/commands/helpers.rs b/gateway/src/commands/helpers.rs index 23ebd77afd..edaca0edb8 100644 --- a/gateway/src/commands/helpers.rs +++ b/gateway/src/commands/helpers.rs @@ -241,9 +241,17 @@ pub(crate) fn override_network_requester_config( } pub(crate) fn override_ip_packet_router_config( - cfg: nym_ip_packet_router::Config, - _opts: Option, + mut cfg: nym_ip_packet_router::Config, + opts: Option, ) -> nym_ip_packet_router::Config { + let Some(_opts) = opts else { return cfg }; + + // disable poisson rate in the BASE client if the IPR option is enabled + if cfg.ip_packet_router.disable_poisson_rate { + log::info!("Disabling poisson rate for ip packet router"); + cfg.set_no_poisson_process(); + } + cfg } diff --git a/service-providers/ip-packet-router/Cargo.toml b/service-providers/ip-packet-router/Cargo.toml index 3aa52688f4..1f8afecdd1 100644 --- a/service-providers/ip-packet-router/Cargo.toml +++ b/service-providers/ip-packet-router/Cargo.toml @@ -26,3 +26,4 @@ serde_json = { workspace = true } tap.workspace = true thiserror = { workspace = true } tokio = { workspace = true, features = ["rt-multi-thread", "net", "io-util"] } +url.workspace = true diff --git a/service-providers/ip-packet-router/src/config/mod.rs b/service-providers/ip-packet-router/src/config/mod.rs index 4b6b811bda..d8c9aac583 100644 --- a/service-providers/ip-packet-router/src/config/mod.rs +++ b/service-providers/ip-packet-router/src/config/mod.rs @@ -2,7 +2,8 @@ pub use nym_client_core::config::Config as BaseClientConfig; use nym_bin_common::logging::LoggingSettings; use nym_config::{ - must_get_home, save_formatted_config_to_file, NymConfigTemplate, DEFAULT_CONFIG_DIR, + defaults::mainnet, must_get_home, save_formatted_config_to_file, + serde_helpers::de_maybe_stringified, NymConfigTemplate, DEFAULT_CONFIG_DIR, DEFAULT_CONFIG_FILENAME, DEFAULT_DATA_DIR, NYM_DIR, }; use nym_service_providers_common::DEFAULT_SERVICE_PROVIDERS_DIR; @@ -11,6 +12,7 @@ use std::{ io, path::{Path, PathBuf}, }; +use url::Url; use crate::config::persistence::IpPacketRouterPaths; @@ -55,6 +57,9 @@ pub struct Config { #[serde(flatten)] pub base: BaseClientConfig, + #[serde(default)] + pub ip_packet_router: IpPacketRouter, + pub storage_paths: IpPacketRouterPaths, pub logging: LoggingSettings, @@ -70,6 +75,7 @@ impl Config { pub fn new>(id: S) -> Self { Config { base: BaseClientConfig::new(id.as_ref(), env!("CARGO_PKG_VERSION")), + ip_packet_router: Default::default(), storage_paths: IpPacketRouterPaths::new_base(default_data_directory(id.as_ref())), logging: Default::default(), } @@ -101,4 +107,33 @@ impl Config { // no other sections have explicit requirements (yet) self.base.validate() } + + #[doc(hidden)] + pub fn set_no_poisson_process(&mut self) { + self.base.set_no_poisson_process() + } +} + +#[derive(Debug, Clone, Deserialize, PartialEq, Serialize)] +#[serde(default, deny_unknown_fields)] +pub struct IpPacketRouter { + /// Disable Poisson sending rate. + pub disable_poisson_rate: bool, + + /// Specifies the url for an upstream source of the exit policy used by this node. + #[serde(deserialize_with = "de_maybe_stringified")] + pub upstream_exit_policy_url: Option, +} + +impl Default for IpPacketRouter { + fn default() -> Self { + IpPacketRouter { + disable_poisson_rate: true, + upstream_exit_policy_url: Some( + mainnet::EXIT_POLICY_URL + .parse() + .expect("invalid default exit policy URL"), + ), + } + } } From d38139be668064549ed3f597e7ebc7a71d3fb89a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bogdan-=C8=98tefan=20Neac=C5=9Fu?= Date: Thu, 9 Nov 2023 13:39:27 +0200 Subject: [PATCH 08/80] Add private ip assignment (#4089) * Add private ip assignment * Update wg IPs --- Cargo.lock | 11 ++++++++++ common/wireguard-types/src/registration.rs | 17 ++++++++++++++- gateway/Cargo.toml | 1 + gateway/src/config/old_config_v1_1_31.rs | 1 + gateway/src/error.rs | 6 ++++++ gateway/src/http/mod.rs | 7 +++++++ nym-node/Cargo.toml | 2 ++ nym-node/src/config/mod.rs | 6 ++++++ .../wireguard/client_registry.rs | 20 ++++++++++++++++-- .../client_interfaces/wireguard/mod.rs | 21 +++++++++++++++++++ 10 files changed, 89 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bf1c54e50b..4505e78707 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4282,6 +4282,15 @@ version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" +[[package]] +name = "ipnetwork" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8eca9f51da27bc908ef3dd85c21e1bbba794edaf94d7841e37356275b82d31e" +dependencies = [ + "serde", +] + [[package]] name = "ipnetwork" version = "0.18.0" @@ -6534,6 +6543,7 @@ dependencies = [ "futures", "humantime-serde", "hyper", + "ipnetwork 0.16.0", "lazy_static", "log", "nym-api-requests", @@ -6901,6 +6911,7 @@ dependencies = [ "fastrand 2.0.1", "hmac 0.12.1", "hyper", + "ipnetwork 0.16.0", "mime", "nym-config", "nym-crypto", diff --git a/common/wireguard-types/src/registration.rs b/common/wireguard-types/src/registration.rs index 1da614aaa0..0fa9536161 100644 --- a/common/wireguard-types/src/registration.rs +++ b/common/wireguard-types/src/registration.rs @@ -6,6 +6,7 @@ use crate::PeerPublicKey; use base64::{engine::general_purpose, Engine}; use dashmap::DashMap; use serde::{Deserialize, Serialize}; +use std::net::IpAddr; use std::{fmt, ops::Deref, str::FromStr}; #[cfg(feature = "verify")] @@ -17,11 +18,13 @@ use sha2::Sha256; pub type GatewayClientRegistry = DashMap; pub type PendingRegistrations = DashMap; +pub type PrivateIPs = DashMap; #[cfg(feature = "verify")] pub type HmacSha256 = Hmac; pub type Nonce = u64; +pub type Free = bool; #[derive(Serialize, Deserialize, Debug, Clone)] #[serde(tag = "type", rename_all = "camelCase")] @@ -72,6 +75,9 @@ pub struct GatewayClient { #[cfg_attr(feature = "openapi", schema(value_type = String, format = Byte))] pub pub_key: PeerPublicKey, + /// Assigned private IP + pub private_ip: IpAddr, + /// Sha256 hmac on the data (alongside the prior nonce) #[cfg_attr(feature = "openapi", schema(value_type = String, format = Byte))] pub mac: ClientMac, @@ -79,7 +85,12 @@ pub struct GatewayClient { impl GatewayClient { #[cfg(feature = "verify")] - pub fn new(local_secret: &PrivateKey, remote_public: PublicKey, nonce: u64) -> Self { + pub fn new( + local_secret: &PrivateKey, + remote_public: PublicKey, + private_ip: IpAddr, + nonce: u64, + ) -> Self { // convert from 1.0 x25519-dalek private key into 2.0 x25519-dalek #[allow(clippy::expect_used)] let static_secret = boringtun::x25519::StaticSecret::try_from(local_secret.to_bytes()) @@ -96,10 +107,12 @@ impl GatewayClient { .expect("x25519 shared secret is always 32 bytes long"); mac.update(local_public.as_bytes()); + mac.update(private_ip.to_string().as_bytes()); mac.update(&nonce.to_le_bytes()); GatewayClient { pub_key: PeerPublicKey::new(local_public), + private_ip, mac: ClientMac(mac.finalize().into_bytes().to_vec()), } } @@ -121,6 +134,7 @@ impl GatewayClient { .expect("x25519 shared secret is always 32 bytes long"); mac.update(self.pub_key.as_bytes()); + mac.update(self.private_ip.to_string().as_bytes()); mac.update(&nonce.to_le_bytes()); mac.verify_slice(&self.mac) @@ -209,6 +223,7 @@ mod tests { let client = GatewayClient::new( client_key_pair.private_key(), *gateway_key_pair.public_key(), + "10.0.0.42".parse().unwrap(), nonce, ); assert!(client.verify(gateway_key_pair.private_key(), nonce).is_ok()) diff --git a/gateway/Cargo.toml b/gateway/Cargo.toml index cec0929f6d..3ee6a13643 100644 --- a/gateway/Cargo.toml +++ b/gateway/Cargo.toml @@ -27,6 +27,7 @@ dirs = "4.0" dotenvy = { workspace = true } futures = { workspace = true } humantime-serde = "1.0.1" +ipnetwork = "0.16" lazy_static = "1.4.0" log = { workspace = true } once_cell = "1.7.2" diff --git a/gateway/src/config/old_config_v1_1_31.rs b/gateway/src/config/old_config_v1_1_31.rs index 6391b18115..04d76e6290 100644 --- a/gateway/src/config/old_config_v1_1_31.rs +++ b/gateway/src/config/old_config_v1_1_31.rs @@ -128,6 +128,7 @@ impl From for Config { enabled: value.wireguard.enabled, bind_address: value.wireguard.bind_address, announced_port: value.wireguard.announced_port, + private_network_prefix: Default::default(), storage_paths: nym_node::config::persistence::WireguardPaths { // no fields (yet) }, diff --git a/gateway/src/error.rs b/gateway/src/error.rs index 470e5421c4..4ae56f813c 100644 --- a/gateway/src/error.rs +++ b/gateway/src/error.rs @@ -134,6 +134,12 @@ pub(crate) enum GatewayError { // TODO: in the future this should work the other way, i.e. NymNode depending on Gateway errors #[error(transparent)] NymNodeError(#[from] nym_node::error::NymNodeError), + + #[error("there was an issue with wireguard IP network: {source}")] + IpNetworkError { + #[from] + source: ipnetwork::IpNetworkError, + }, } impl From for GatewayError { diff --git a/gateway/src/http/mod.rs b/gateway/src/http/mod.rs index d27b7873c6..401d1ccbf2 100644 --- a/gateway/src/http/mod.rs +++ b/gateway/src/http/mod.rs @@ -4,6 +4,7 @@ use crate::config::Config; use crate::error::GatewayError; use crate::node::helpers::load_public_key; +use ipnetwork::IpNetwork; use log::warn; use nym_bin_common::bin_info_owned; use nym_crypto::asymmetric::{encryption, identity}; @@ -16,6 +17,7 @@ use nym_node::http::router::WireguardAppState; use nym_node::wireguard::types::GatewayClientRegistry; use nym_sphinx::addressing::clients::Recipient; use nym_task::TaskClient; +use std::net::{IpAddr, Ipv4Addr}; use std::sync::Arc; fn load_gateway_details( @@ -223,12 +225,17 @@ impl<'a> HttpApiBuilder<'a> { } } + let wireguard_private_network = IpNetwork::new( + IpAddr::from(Ipv4Addr::new(10, 1, 0, 0)), + self.gateway_config.wireguard.private_network_prefix, + )?; let wg_state = self.client_registry.map(|client_registry| { WireguardAppState::new( self.sphinx_keypair, client_registry, Default::default(), self.gateway_config.wireguard.bind_address.port(), + wireguard_private_network, ) }); diff --git a/nym-node/Cargo.toml b/nym-node/Cargo.toml index 7b70ae86e0..ded34c9d48 100644 --- a/nym-node/Cargo.toml +++ b/nym-node/Cargo.toml @@ -14,6 +14,8 @@ license.workspace = true anyhow = { workspace = true } bytes = "1.5.0" colored = "2" +ipnetwork = "0.16" +rand = "0.7.3" serde = { workspace = true, features = ["derive"] } serde_yaml = "0.9.25" serde_json = { workspace = true } diff --git a/nym-node/src/config/mod.rs b/nym-node/src/config/mod.rs index ad4a9a8823..c6a6610d4b 100644 --- a/nym-node/src/config/mod.rs +++ b/nym-node/src/config/mod.rs @@ -12,6 +12,7 @@ pub mod persistence; mod serde_helpers; pub const DEFAULT_WIREGUARD_PORT: u16 = WG_PORT; +pub const DEFAULT_WIREGUARD_PREFIX: u8 = 16; pub const DEFAULT_HTTP_PORT: u16 = DEFAULT_NYM_NODE_HTTP_PORT; // TODO: this is very much a WIP. we need proper ssl certificate support here @@ -75,6 +76,10 @@ pub struct Wireguard { /// Useful in the instances where the node is behind a proxy. pub announced_port: u16, + /// The prefix denoting the maximum number of the clients that can be connected via Wireguard. + /// The maximum value for IPv4 is 32 and for IPv6 is 128 + pub private_network_prefix: u8, + /// Paths for wireguard keys, client registries, etc. pub storage_paths: persistence::WireguardPaths, } @@ -88,6 +93,7 @@ impl Default for Wireguard { DEFAULT_WIREGUARD_PORT, ), announced_port: DEFAULT_WIREGUARD_PORT, + private_network_prefix: DEFAULT_WIREGUARD_PREFIX, storage_paths: persistence::WireguardPaths {}, } } diff --git a/nym-node/src/http/router/api/v1/gateway/client_interfaces/wireguard/client_registry.rs b/nym-node/src/http/router/api/v1/gateway/client_interfaces/wireguard/client_registry.rs index 850443e325..dacc42afaf 100644 --- a/nym-node/src/http/router/api/v1/gateway/client_interfaces/wireguard/client_registry.rs +++ b/nym-node/src/http/router/api/v1/gateway/client_interfaces/wireguard/client_registry.rs @@ -14,6 +14,7 @@ use nym_crypto::asymmetric::encryption::PublicKey; use nym_node_requests::api::v1::gateway::client_interfaces::wireguard::models::{ ClientMessage, ClientRegistrationResponse, GatewayClient, InitMessage, Nonce, PeerPublicKey, }; +use rand::{prelude::IteratorRandom, thread_rng}; async fn process_final_message( client: GatewayClient, @@ -91,8 +92,23 @@ pub(crate) async fn register_client( let remote_public = PublicKey::from_bytes(init.pub_key().as_bytes()) .map_err(|_| RequestError::new_status(StatusCode::BAD_REQUEST))?; let nonce = process_init_message(init, state).await; - let gateway_data = - GatewayClient::new(state.dh_keypair.private_key(), remote_public, nonce); + let mut private_ip_ref = state + .free_private_network_ips + .iter_mut() + .filter(|r| **r) + .choose(&mut thread_rng()) + .ok_or(RequestError::new( + "No more space in the network", + StatusCode::SERVICE_UNAVAILABLE, + ))?; + // mark it as used, even though it's not final + *private_ip_ref = false; + let gateway_data = GatewayClient::new( + state.dh_keypair.private_key(), + remote_public, + *private_ip_ref.key(), + nonce, + ); let response = ClientRegistrationResponse::PendingRegistration { nonce, gateway_data, diff --git a/nym-node/src/http/router/api/v1/gateway/client_interfaces/wireguard/mod.rs b/nym-node/src/http/router/api/v1/gateway/client_interfaces/wireguard/mod.rs index 37348be94e..622b12935d 100644 --- a/nym-node/src/http/router/api/v1/gateway/client_interfaces/wireguard/mod.rs +++ b/nym-node/src/http/router/api/v1/gateway/client_interfaces/wireguard/mod.rs @@ -7,8 +7,10 @@ use crate::http::api::v1::gateway::client_interfaces::wireguard::client_registry use crate::wireguard::types::{GatewayClientRegistry, PendingRegistrations}; use axum::routing::{get, post}; use axum::Router; +use ipnetwork::IpNetwork; use nym_crypto::asymmetric::encryption; use nym_node_requests::routes::api::v1::gateway::client_interfaces::wireguard; +use nym_wireguard_types::registration::PrivateIPs; use std::sync::Arc; pub(crate) mod client_registry; @@ -26,6 +28,7 @@ impl WireguardAppState { client_registry: Arc, registration_in_progress: Arc, binding_port: u16, + private_ip_network: IpNetwork, ) -> Self { WireguardAppState { inner: Some(WireguardAppStateInner { @@ -33,6 +36,9 @@ impl WireguardAppState { client_registry, registration_in_progress, binding_port, + free_private_network_ips: Arc::new( + private_ip_network.iter().map(|ip| (ip, true)).collect(), + ), }), } } @@ -77,6 +83,7 @@ pub(crate) struct WireguardAppStateInner { client_registry: Arc, registration_in_progress: Arc, binding_port: u16, + free_private_network_ips: Arc, } pub(crate) fn routes(initial_state: WireguardAppState) -> Router { @@ -98,6 +105,7 @@ mod test { use axum::http::StatusCode; use dashmap::DashMap; use hmac::Mac; + use ipnetwork::IpNetwork; use nym_crypto::asymmetric::encryption; use nym_node_requests::api::v1::gateway::client_interfaces::wireguard::models::{ ClientMac, ClientMessage, ClientRegistrationResponse, GatewayClient, InitMessage, @@ -105,6 +113,8 @@ mod test { }; use nym_node_requests::routes::api::v1::gateway::client_interfaces::wireguard; use nym_wireguard_types::registration::HmacSha256; + use std::net::IpAddr; + use std::str::FromStr; use std::sync::Arc; use tower::Service; use tower::ServiceExt; @@ -136,6 +146,14 @@ mod test { let registration_in_progress = Arc::new(DashMap::new()); let client_registry = Arc::new(DashMap::new()); + let free_private_network_ips = Arc::new( + IpNetwork::from_str("10.1.0.0/24") + .unwrap() + .iter() + .map(|ip| (ip, true)) + .collect(), + ); + let client_private_ip = IpAddr::from_str("10.1.0.42").unwrap(); let state = WireguardAppState { inner: Some(WireguardAppStateInner { @@ -143,6 +161,7 @@ mod test { dh_keypair: Arc::new(gateway_key_pair), registration_in_progress: Arc::clone(®istration_in_progress), binding_port: 8080, + free_private_network_ips, }), }; @@ -186,11 +205,13 @@ mod test { let mut mac = HmacSha256::new_from_slice(client_dh.as_bytes()).unwrap(); mac.update(client_static_public.as_bytes()); + mac.update(client_private_ip.to_string().as_bytes()); mac.update(&nonce.to_le_bytes()); let mac = mac.finalize().into_bytes(); let finalized_message = ClientMessage::Final(GatewayClient { pub_key: PeerPublicKey::new(client_static_public), + private_ip: client_private_ip, mac: ClientMac::new(mac.as_slice().to_vec()), }); From f6e5892de7644c12f89fabfaaf72117cb56b4174 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Thu, 9 Nov 2023 14:01:30 +0100 Subject: [PATCH 09/80] initialise electrum guide --- documentation/dev-portal/src/tutorials/electrum.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 documentation/dev-portal/src/tutorials/electrum.md diff --git a/documentation/dev-portal/src/tutorials/electrum.md b/documentation/dev-portal/src/tutorials/electrum.md new file mode 100644 index 0000000000..0cc7f2488b --- /dev/null +++ b/documentation/dev-portal/src/tutorials/electrum.md @@ -0,0 +1 @@ +# Electrum NymConnect Integration From f8666cec45d433af7aa35a3ed879c12cd3741c33 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Thu, 9 Nov 2023 14:13:34 +0100 Subject: [PATCH 10/80] add NC install steps --- .../dev-portal/src/tutorials/electrum.md | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/documentation/dev-portal/src/tutorials/electrum.md b/documentation/dev-portal/src/tutorials/electrum.md index 0cc7f2488b..6f43bc37e9 100644 --- a/documentation/dev-portal/src/tutorials/electrum.md +++ b/documentation/dev-portal/src/tutorials/electrum.md @@ -1 +1,36 @@ # Electrum NymConnect Integration + +Electrum is one of the most favorite Bitcoin wallet for desktop users and it is used as backend wallet for several crypto aplications in smart phones. Electrum was among the first integrations of Nym. This easy setup allows users to enhance privacy when managing the flagship of blochain cryptocurencies Bitcoin. + +## How can I use Bitcoin over the Nym mixnet? + +> Any syntax in `<>` brackets is a user’s unique variable. Exchange with a corresponding name without the `<>` brackets. + +### NymConnect Installation + +NymConnect application is for everyone who does not want to install and run `nym-socks5-client`. NymConnect is plug-and-play, fast and easy use. Electrum Bitcoin wallet, Monero wallet (desktop and CLI) and Matrix (Element app) connects through NymConnect automatically to the Mixnet. + +1. [Download](https://nymtech.net/download/nymconnect) NymConnect +2. On Linux and Mac, make executable by opening terminal in the same directory and run: + +```sh +chmod +x ./nym-connect_.AppImage +``` + +3. Start the application +4. Click on `Connect` button to initialise the connection with the Mixnet +5. Anytime you'll need to setup Host and Port in your applications, click on `IP` and `Port` to copy the values to clipboard +6. In case you have problems such as `Gateway Issues`, try to reconnect or restart the application + +### Electrum Bitcoin wallet via NymConnect + + +To download Electrum visit the [official webpage](https://electrum.org/#download). To connect to the Mixnet follow these steps: + +7. Start and connect [NymConnect](./hcpp23-serinko.html#nymconnect-installation) (or [`nym-socks5-client`](./hcpp23-serinko.html#building-nym-platform)) +2. Start your Electrum Bitcoin wallet +3. Go to: *Tools* -> *Network* -> *Proxy* +4. Set *Use proxy* to ✅, choose `SOCKS5` from the drop-down and add the values from your NymConnect application +5. Now your Electrum Bitcoin wallet runs through the Mixnet and it will be connected only if your NymConnect or `nym-socks5-client` are connected. + +![Electrum Bitcoin wallet setup](../images/electrum_tutorial/electrum.gif) From 90bfeb3dd243203c7c8082e848ca1f16881350d5 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Thu, 9 Nov 2023 14:15:25 +0100 Subject: [PATCH 11/80] add electrum to SUMMARY.md --- documentation/dev-portal/src/SUMMARY.md | 1 + 1 file changed, 1 insertion(+) diff --git a/documentation/dev-portal/src/SUMMARY.md b/documentation/dev-portal/src/SUMMARY.md index cd930be17a..51576a6d70 100644 --- a/documentation/dev-portal/src/SUMMARY.md +++ b/documentation/dev-portal/src/SUMMARY.md @@ -21,6 +21,7 @@ - [NymConnect X Monero](tutorials/monero.md) - [NymConnect X Matrix](tutorials/matrix.md) - [NymConnect X Telegram](tutorials/telegram.md) +- [NymConnect X Electrum](tutorials/electrum.md) # Code Examples From 7ea415c0823ecfcd795c57c02fdbe3c294c79602 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Thu, 9 Nov 2023 14:21:17 +0100 Subject: [PATCH 12/80] finish electrum guide --- documentation/dev-portal/src/tutorials/electrum.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/documentation/dev-portal/src/tutorials/electrum.md b/documentation/dev-portal/src/tutorials/electrum.md index 6f43bc37e9..b16edef822 100644 --- a/documentation/dev-portal/src/tutorials/electrum.md +++ b/documentation/dev-portal/src/tutorials/electrum.md @@ -1,6 +1,6 @@ # Electrum NymConnect Integration -Electrum is one of the most favorite Bitcoin wallet for desktop users and it is used as backend wallet for several crypto aplications in smart phones. Electrum was among the first integrations of Nym. This easy setup allows users to enhance privacy when managing the flagship of blochain cryptocurencies Bitcoin. +Electrum is one of the most favorite Bitcoin wallet for desktop users and it is used as a backend wallet for various crypto aplications in smart phones. Electrum was among the first integrations of Nym. This easy setup allows users to enhance privacy when managing the flagship of blochain cryptocurencies Bitcoin. ## How can I use Bitcoin over the Nym mixnet? @@ -27,7 +27,7 @@ chmod +x ./nym-connect_.AppImage To download Electrum visit the [official webpage](https://electrum.org/#download). To connect to the Mixnet follow these steps: -7. Start and connect [NymConnect](./hcpp23-serinko.html#nymconnect-installation) (or [`nym-socks5-client`](./hcpp23-serinko.html#building-nym-platform)) +7. Start and connect [NymConnect](./electrum.md#nymconnect-installation) (or [`nym-socks5-client`](https://nymtech.net/docs/clients/socks5-client.html)) 2. Start your Electrum Bitcoin wallet 3. Go to: *Tools* -> *Network* -> *Proxy* 4. Set *Use proxy* to ✅, choose `SOCKS5` from the drop-down and add the values from your NymConnect application From f5e16cda5e1a1962f70586a115f77d13f03f5545 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Thu, 9 Nov 2023 14:22:50 +0100 Subject: [PATCH 13/80] initialise firo guide --- documentation/dev-portal/src/tutorials/firo.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 documentation/dev-portal/src/tutorials/firo.md diff --git a/documentation/dev-portal/src/tutorials/firo.md b/documentation/dev-portal/src/tutorials/firo.md new file mode 100644 index 0000000000..a203bf59f0 --- /dev/null +++ b/documentation/dev-portal/src/tutorials/firo.md @@ -0,0 +1 @@ +# Firo-Electrum NymConnect Integration From 2389d7e62f9743452d63c58a9dc2b861614191cd Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Thu, 9 Nov 2023 14:23:40 +0100 Subject: [PATCH 14/80] add firo to SUMMARY.md --- documentation/dev-portal/src/SUMMARY.md | 1 + 1 file changed, 1 insertion(+) diff --git a/documentation/dev-portal/src/SUMMARY.md b/documentation/dev-portal/src/SUMMARY.md index 51576a6d70..a4e5dbce11 100644 --- a/documentation/dev-portal/src/SUMMARY.md +++ b/documentation/dev-portal/src/SUMMARY.md @@ -22,6 +22,7 @@ - [NymConnect X Matrix](tutorials/matrix.md) - [NymConnect X Telegram](tutorials/telegram.md) - [NymConnect X Electrum](tutorials/electrum.md) +- [NymConnect X Firo wallet](tutorials/firo.md) # Code Examples From c4b227f66e59bf9f859443c594c785ab19cba856 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Thu, 9 Nov 2023 14:31:50 +0100 Subject: [PATCH 15/80] create firo setup screenshot --- .../src/images/firo_tutorial/firo.png | Bin 0 -> 103415 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 documentation/dev-portal/src/images/firo_tutorial/firo.png diff --git a/documentation/dev-portal/src/images/firo_tutorial/firo.png b/documentation/dev-portal/src/images/firo_tutorial/firo.png new file mode 100644 index 0000000000000000000000000000000000000000..ed1d7a078969abb4e66a7c00adcd23be0005b35c GIT binary patch literal 103415 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

~#?kVE}!^WAFV<6AVu`yqAW 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 literal 0 HcmV?d00001 From abef9c9768e2746b0b990dfd733f48a75bf78f09 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Thu, 9 Nov 2023 14:34:28 +0100 Subject: [PATCH 16/80] add firo wallet setup --- .../dev-portal/src/tutorials/firo.md | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/documentation/dev-portal/src/tutorials/firo.md b/documentation/dev-portal/src/tutorials/firo.md index a203bf59f0..a7f595a003 100644 --- a/documentation/dev-portal/src/tutorials/firo.md +++ b/documentation/dev-portal/src/tutorials/firo.md @@ -1 +1,36 @@ # Firo-Electrum NymConnect Integration + + + +## How can I use Firo over the Nym mixnet? + +> Any syntax in `<>` brackets is a user’s unique variable. Exchange with a corresponding name without the `<>` brackets. + +### NymConnect Installation + +NymConnect application is for everyone who does not want to install and run `nym-socks5-client`. NymConnect is plug-and-play, fast and easy use. Electrum Bitcoin wallet, Monero wallet (desktop and CLI) and Matrix (Element app) connects through NymConnect automatically to the Mixnet. + +1. [Download](https://nymtech.net/download/nymconnect) NymConnect +2. On Linux and Mac, make executable by opening terminal in the same directory and run: + +```sh +chmod +x ./nym-connect_.AppImage +``` + +3. Start the application +4. Click on `Connect` button to initialise the connection with the Mixnet +5. Anytime you'll need to setup Host and Port in your applications, click on `IP` and `Port` to copy the values to clipboard +6. In case you have problems such as `Gateway Issues`, try to reconnect or restart the application + +### Firo Electrum wallet via NymConnect + + +To download Firo Electrum wallet visit the [Firo's repository](https://github.com/firoorg/firo) or [Github release page](https://github.com/firoorg/electrum-firo/releases/tag/4.1.5.2). To connect to the Mixnet follow these steps: + +7. Start and connect [NymConnect](./firo.md#nymconnect-installation) (or [`nym-socks5-client`](https://nymtech.net/docs/clients/socks5-client.html)) +2. Start your Firo Electrum wallet +3. Go to: *Tools* -> *Network* -> *Proxy* +4. Set *Use proxy* to ✅, choose `SOCKS5` from the drop-down and add the values from your NymConnect application +5. Now your Firo Electrum wallet runs through the Mixnet and it will be connected only if your NymConnect or `nym-socks5-client` are connected. + +![Firo Electrum wallet setup](../images/firo_tutorial/firo.png) From f1b0a60b34baa8348808ffdf46be63276c0214be Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Thu, 9 Nov 2023 14:37:32 +0100 Subject: [PATCH 17/80] syntax edit --- documentation/dev-portal/src/tutorials/electrum.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/dev-portal/src/tutorials/electrum.md b/documentation/dev-portal/src/tutorials/electrum.md index b16edef822..e929ea2578 100644 --- a/documentation/dev-portal/src/tutorials/electrum.md +++ b/documentation/dev-portal/src/tutorials/electrum.md @@ -1,4 +1,4 @@ -# Electrum NymConnect Integration +# Electrum Wallet NymConnect Integration Electrum is one of the most favorite Bitcoin wallet for desktop users and it is used as a backend wallet for various crypto aplications in smart phones. Electrum was among the first integrations of Nym. This easy setup allows users to enhance privacy when managing the flagship of blochain cryptocurencies Bitcoin. From c34d89165c927456c3f310da8bd8cfcaf602c353 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Thu, 9 Nov 2023 14:37:44 +0100 Subject: [PATCH 18/80] syntax edit --- documentation/dev-portal/src/tutorials/firo.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/dev-portal/src/tutorials/firo.md b/documentation/dev-portal/src/tutorials/firo.md index a7f595a003..e92e3ee5b6 100644 --- a/documentation/dev-portal/src/tutorials/firo.md +++ b/documentation/dev-portal/src/tutorials/firo.md @@ -1,4 +1,4 @@ -# Firo-Electrum NymConnect Integration +# Firo-Electrum Wallet NymConnect Integration From 4a84274055a182d792778832f2fe5ca7336798b4 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Thu, 9 Nov 2023 14:43:27 +0100 Subject: [PATCH 19/80] rename gateway to Gateway --- .../operators/src/nodes/gateway-setup.md | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/documentation/operators/src/nodes/gateway-setup.md b/documentation/operators/src/nodes/gateway-setup.md index 93ca3e7735..d6d2b32a8d 100644 --- a/documentation/operators/src/nodes/gateway-setup.md +++ b/documentation/operators/src/nodes/gateway-setup.md @@ -102,7 +102,7 @@ To setup Exit Gateway functionality with our new [exit policy](https://nymtech.n ./nym-gateway setup-network-requester --enabled true --with-exit-policy true --id ``` -Say we have a gateway with `` as `new-gateway`, originally initialised and ran without the Exit Gateway functionality. To change the setup, run: +Say we have a Gateway with `` as `new-gateway`, originally initialised and ran without the Exit Gateway functionality. To change the setup, run: ``` @@ -124,7 +124,7 @@ In case there are any unexpected problems, you can also change it manually by ed enabled = true ``` -Save, exit and restart your gateway. Now you are an operator of post-smooshed Exit gateway. +Save, exit and restart your Gateway. Now you are an operator of post-smooshed Exit Gateway. #### Enable Nym exit policy to an existing Gateway with Network requester functionality @@ -134,7 +134,7 @@ Open the config file stored at `.nym/gateways//config/network_requester_conf ```sh use_deprecated_allow_list = false ``` -Save, exit and restart your gateway. Now you are an operator of post-smooshed Exit gateway. +Save, exit and restart your Gateway. Now you are an operator of post-smooshed Exit gateway. ```admonish info All information about network requester part of your Exit Gateway is in `/home/user/.nym/gateways//config/network_requester_config.toml`. @@ -161,7 +161,7 @@ To check available configuration options use: ``` ~~~ -The following command returns a gateway on your current IP with the `` of `simple-gateway`: +The following command returns a Gateway on your current IP with the `` of `simple-gateway`: ``` ./nym-gateway init --id simple-gateway --host $(curl -4 https://ifconfig.me) @@ -176,15 +176,15 @@ The following command returns a gateway on your current IP with the `` of `s The `$(curl -4 https://ifconfig.me)` command above returns your IP automatically using an external service. Alternatively, you can enter your IP manually if you wish. If you do this, remember to enter your IP **without** any port information. -### Bonding your gateway +### Bonding your Gateway ```admonish info -Before you bond and re-run your Gateway, please make sure the [firewall configuration](./maintenance.md#configure-your-firewall) is setup so your gateway can be reached from the outside. You can also setup WSS on your Gateway, the steps are on the [Maintenance page](./maintenance.md#configure-your-firewall) below. +Before you bond and re-run your Gateway, please make sure the [firewall configuration](./maintenance.md#configure-your-firewall) is setup so your Gateway can be reached from the outside. You can also setup WSS on your Gateway, the steps are on the [Maintenance page](./maintenance.md#configure-your-firewall) below. ``` #### Via the Desktop wallet -You can bond your gateway via the Desktop wallet. +You can bond your Gateway via the Desktop wallet. 1. Open your wallet, and head to the `Bonding` page, then select the node type `Gateway` and input your node details. Press `Next`. @@ -229,20 +229,21 @@ It will look something like this: ![Paste Signature](../images/wallet-screenshots/wallet-gateway-sign.png) -* Your gateway is now bonded. +* Your Gateway is now bonded. > You are asked to `sign` a transaction on bonding so that the Mixnet smart contract is able to map your Nym address to your node. This allows us to create a nonce for each account and defend against replay attacks. #### Via the CLI (power users) If you want to bond your mix node via the CLI, then check out the [relevant section in the Nym CLI](https://nymtech.net/docs/tools/nym-cli.html#bond-a-mix-node) docs. -### Running your gateway -The `run` command starts the gateway: +### Running your Gateway + +The `run` command starts the Gateway: ``` ./nym-gateway run --id ``` ## Maintenance -For gateway upgrade, firewall setup, port configuration, API endpoints, VPS suggestions, automation and more, see the [maintenance page](./maintenance.md) +For Gateway upgrade, firewall setup, port configuration, API endpoints, VPS suggestions, automation, WSS setup and more, see the [maintenance page](./maintenance.md) From 2960a4c48e82bf787b9b81f0fc6c5a790d402497 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Thu, 9 Nov 2023 14:50:28 +0100 Subject: [PATCH 20/80] add --listening-address and --public-ips --- documentation/operators/src/nodes/gateway-setup.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/documentation/operators/src/nodes/gateway-setup.md b/documentation/operators/src/nodes/gateway-setup.md index d6d2b32a8d..73ffc84528 100644 --- a/documentation/operators/src/nodes/gateway-setup.md +++ b/documentation/operators/src/nodes/gateway-setup.md @@ -60,12 +60,14 @@ Before you start an Exit Gateway, read our [Operators Legal Forum](../legal/exit There has been an ongoing development with dynamic upgrades. Follow the status of the Project Smoosh [changes](../faq/smoosh-faq.md#what-are-the-changes) and the progression state of exit policy [implementation](../faq/smoosh-faq.html#how-will-the-exit-policy-be-implemented) to be up to date with the current design. ``` +**Note:** Due to the development towards Exit Gateway functionality the `--host` flag has been replaced with `--listening-address`, this is the IP address which is used for receiving sphinx packets and listening to client data. Another flag `--public-ips` is required; it’s a comma separated list of IP’s that are announced to the `nym-api`, it is usually the address which is used for bonding. + ### Initialising Exit Gateway An operator can initialise the Exit Gateway functionality by adding Network requester with the new exit policy option: ``` -./nym-gateway init --id --host $(curl -4 https://ifconfig.me) --with-network-requester --with-exit-policy true +./nym-gateway init --id --listening-address 0.0.0.0 --public-ips "$(curl -4 https://ifconfig.me)" --with-network-requester --with-exit-policy true ``` If we follow the previous example with `` chosen `superexitgateway`, adding the `--with-network-requester` and `--with-exit-policy` flags, the outcome will be: From 7d12b91bbdef636c22d0a7ae199ec31b01f0ce02 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Thu, 9 Nov 2023 14:52:51 +0100 Subject: [PATCH 21/80] remove --host flag --- documentation/operators/src/nodes/gateway-setup.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/documentation/operators/src/nodes/gateway-setup.md b/documentation/operators/src/nodes/gateway-setup.md index 73ffc84528..fbf817834d 100644 --- a/documentation/operators/src/nodes/gateway-setup.md +++ b/documentation/operators/src/nodes/gateway-setup.md @@ -74,7 +74,7 @@ If we follow the previous example with `` chosen `superexitgateway`, adding ~~~admonish example collapsible=true title="Console output" ``` - + ``` ~~~ @@ -114,7 +114,7 @@ Say we have a Gateway with `` as `new-gateway`, originally initialised and r ~~~admonish example collapsible=true title="Console output" ``` - + ``` ~~~ @@ -166,12 +166,12 @@ To check available configuration options use: The following command returns a Gateway on your current IP with the `` of `simple-gateway`: ``` -./nym-gateway init --id simple-gateway --host $(curl -4 https://ifconfig.me) +./nym-gateway init --id simple-gateway --listening-address 0.0.0.0 --public-ips "$(curl -4 https://ifconfig.me)" ``` ~~~admonish example collapsible=true title="Console output" ``` - + ``` ~~~ From 41f9b9b34056e60382ef3815b1bd45b640b49475 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Thu, 9 Nov 2023 14:56:15 +0100 Subject: [PATCH 22/80] rename gateway to Gateway --- documentation/operators/src/nodes/maintenance.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/documentation/operators/src/nodes/maintenance.md b/documentation/operators/src/nodes/maintenance.md index 5a08724d61..c0016cf752 100644 --- a/documentation/operators/src/nodes/maintenance.md +++ b/documentation/operators/src/nodes/maintenance.md @@ -16,7 +16,7 @@ For example `./target/debug/nym-network-requester --no-banner build-info --outpu ## Upgrading your node -> The process is the similar for mix node, gateway and network requester. In the following steps we use a placeholder `` in the commands, please change it for the type of node you want to upgrade. Any particularities for the given type of node are included. +> The process is the similar for Mix node, Gateway and Network requester. In the following steps we use a placeholder `` in the commands, please change it for the type of node you want to upgrade. Any particularities for the given type of node are included. Upgrading your node is a two-step process: * Updating the binary and `~/.nym///config/config.toml` on your VPS @@ -29,7 +29,7 @@ Follow these steps to upgrade your mix node binary and update its config file: * re-run `init` with the same values as you used initially. **This will just update the config file, it will not overwrite existing keys**. * restart your mix node process with the new binary. -> In case of a network requester this is all all, the following step is only for mix nodes and gateways. +> In case of a network requester this is all all, the following step is only for Mix nodes and Gateways. ### Step 2: Updating your node information in the smart contract Follow these steps to update the information about your `` which is publicly available from the [Nym API](https://validator.nymtech.net/api/swagger/index.html) and information displayed on the [mixnet explorer](https://explorer.nymtech.net). @@ -184,13 +184,13 @@ exit 0 ``` -Although your gateway is Now ready to use its `wss_port`, your server may not be ready - the following commands will allow you to set up a properly configured firewall using `ufw`: +Although your Gateway is Now ready to use its `wss_port`, your server may not be ready - the following commands will allow you to set up a properly configured firewall using `ufw`: ```sh ufw allow 9001/tcp ``` -Lastly don't forget to restart your Gateway, now the API will render the WSS details for this gateway: +Lastly don't forget to restart your Gateway, now the API will render the WSS details for this Gateway: ### WSS on a new Gateway @@ -203,7 +203,7 @@ Another flag `--public-ips` is required; it's a comma separated list of IP’s t If the operator wishes to run WSS, an optional `--hostname` flag is also required, that can be something like `mainnet-gateway2.nymtech.net`. Make sure to enable all necessary [ports](maintenance.md#configure-your-firewall) on the Gateway. -The gateway will then be accessible on something like: *http://85.159.211.99:8080/api/v1/swagger/index.html* +The Gateway will then be accessible on something like: *http://85.159.211.99:8080/api/v1/swagger/index.html* Are you seeing something like: *this node attempted to announce an invalid public address: 0.0.0.0.*? @@ -236,7 +236,7 @@ sudo ufw status Finally open your `` p2p port, as well as ports for ssh and ports for verloc and measurement pings: ```sh -# for mix node, gateway and network requester +# for Mix node, Gateway and Network requester sudo ufw allow 1789,1790,8000,9000,9001,22/tcp # In case of reverse proxy for the Gateway swagger page add: @@ -436,7 +436,7 @@ systemctl daemon-reload # to pickup the new unit file # for mix node systemctl enable nym-mixnode.service -# for gateway +# for Gateway systemctl enable nym-gateway.service ``` @@ -446,7 +446,7 @@ Start your node: # for mix node service nym-mixnode start -# for gateway +# for Gateway service nym-gateway start ``` From c656b3968b77f3a5a5da0e29fcccdf2735db7a4b Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Thu, 9 Nov 2023 17:03:10 +0100 Subject: [PATCH 23/80] add firo intro --- documentation/dev-portal/src/tutorials/firo.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/dev-portal/src/tutorials/firo.md b/documentation/dev-portal/src/tutorials/firo.md index e92e3ee5b6..4cad23bb8f 100644 --- a/documentation/dev-portal/src/tutorials/firo.md +++ b/documentation/dev-portal/src/tutorials/firo.md @@ -1,6 +1,6 @@ # Firo-Electrum Wallet NymConnect Integration - +[Firo](https://github.com/firoorg/firo#firo) (formely Zcoin) is a privacy focuse zk-proofs based cryptocurency. Now users can enjoy Firo with network privacy by Nym as Firo's fork of Electrum wallet was integrated to work behind the Mixnet. Read more about Firo on their [official webpage](https://firo.org/). ## How can I use Firo over the Nym mixnet? From e3f3c5620d6e338944174ecab5812c802d6036c5 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Thu, 9 Nov 2023 17:06:26 +0100 Subject: [PATCH 24/80] spell check --- documentation/dev-portal/src/tutorials/firo.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/documentation/dev-portal/src/tutorials/firo.md b/documentation/dev-portal/src/tutorials/firo.md index 4cad23bb8f..2e0c24ade0 100644 --- a/documentation/dev-portal/src/tutorials/firo.md +++ b/documentation/dev-portal/src/tutorials/firo.md @@ -1,8 +1,8 @@ # Firo-Electrum Wallet NymConnect Integration -[Firo](https://github.com/firoorg/firo#firo) (formely Zcoin) is a privacy focuse zk-proofs based cryptocurency. Now users can enjoy Firo with network privacy by Nym as Firo's fork of Electrum wallet was integrated to work behind the Mixnet. Read more about Firo on their [official webpage](https://firo.org/). +[Firo](https://github.com/firoorg/firo#firo) (formerly Zcoin) is a privacy focused, zk-proofs based cryptocurency. Now users can enjoy Firo with network privacy by Nym as Firo's fork of Electrum wallet was integrated to work behind the Mixnet. Read more about Firo on their [official webpage](https://firo.org/). -## How can I use Firo over the Nym mixnet? +## How can I use Firo over the Nym Mixnet? > Any syntax in `<>` brackets is a user’s unique variable. Exchange with a corresponding name without the `<>` brackets. From 61296b58e90ebf96b8dd57fbacdaa72ad93069ce Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Thu, 9 Nov 2023 17:15:34 +0100 Subject: [PATCH 25/80] unify naming convention mixnode to Mix node --- .../operators/src/nodes/maintenance.md | 48 +++++++++---------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/documentation/operators/src/nodes/maintenance.md b/documentation/operators/src/nodes/maintenance.md index c0016cf752..caa9c24d3e 100644 --- a/documentation/operators/src/nodes/maintenance.md +++ b/documentation/operators/src/nodes/maintenance.md @@ -23,11 +23,11 @@ Upgrading your node is a two-step process: * Updating the node information in the [mixnet smart contract](https://nymtech.net/docs/nyx/mixnet-contract.html). **This is the information that is present on the [mixnet explorer](https://explorer.nymtech.net)**. ### Step 1: Upgrading your binary -Follow these steps to upgrade your mix node binary and update its config file: -* pause your mix node process. +Follow these steps to upgrade your Mix node binary and update its config file: +* pause your Mix node process. * replace the existing binary with the newest binary (which you can either [compile yourself](https://nymtech.net/docs/binaries/building-nym.html) or grab from our [releases page](https://github.com/nymtech/nym/releases)). * re-run `init` with the same values as you used initially. **This will just update the config file, it will not overwrite existing keys**. -* restart your mix node process with the new binary. +* restart your Mix node process with the new binary. > In case of a network requester this is all all, the following step is only for Mix nodes and Gateways. @@ -257,7 +257,7 @@ For more information about your node's port configuration, check the [port refer ### Automating your node with nohup, tmux and systemd -Although it’s not totally necessary, it's useful to have the mix node automatically start at system boot time. +Although it’s not totally necessary, it's useful to have the Mix node automatically start at system boot time. #### nohup @@ -287,7 +287,7 @@ In case it didn't work for your distribution, see how to build `tmux` from [vers **Running tmux** -No when you installed tmux on your VPS, let's run a mix node on tmux, which allows you to detach your terminal and let your `` run on its own on the VPS. +No when you installed tmux on your VPS, let's run a Mix node on tmux, which allows you to detach your terminal and let your `` run on its own on the VPS. * Pause your `` * Start tmux with the command @@ -310,7 +310,7 @@ tmux attach-session Here's a systemd service file to do that: -##### For mix node +##### For Mix node ```ini [Unit] @@ -433,7 +433,7 @@ systemctl daemon-reload # to pickup the new unit file ``` ```sh -# for mix node +# for Mix node systemctl enable nym-mixnode.service # for Gateway @@ -443,7 +443,7 @@ systemctl enable nym-gateway.service Start your node: ```sh -# for mix node +# for Mix node service nym-mixnode start # for Gateway @@ -477,7 +477,7 @@ This lets your operating system know it's ok to reload the service configuration Linux machines limit how many open files a user is allowed to have. This is called a `ulimit`. -`ulimit` is 1024 by default on most systems. It needs to be set higher, because mix nodes make and receive a lot of connections to other nodes. +`ulimit` is 1024 by default on most systems. It needs to be set higher, because Mix nodes make and receive a lot of connections to other nodes. If you see errors such as: @@ -491,7 +491,7 @@ This means that the operating system is preventing network connections from bein > Replace `` variable with `nym-mixnode`, `nym-gateway` or `nym-network-requester` according the node you running on your machine. -The ulimit setup is relevant for maintenance of nym mix node only. +The ulimit setup is relevant for maintenance of nym Mix node only. Query the `ulimit` of your `` with: @@ -543,7 +543,7 @@ Make sure the limit has changed to 65535. #### Set the ulimit on `non-systemd` based distributions -In case you chose tmux option for mix node automatization, see your `ulimit` list by running: +In case you chose tmux option for Mix node automatization, see your `ulimit` list by running: ```sh ulimit -a @@ -568,13 +568,13 @@ username hard nofile 4096 username soft nofile 4096 ``` -Then reboot your server and restart your mix node. +Then reboot your server and restart your Mix node. ## Moving a node In case of a need to move a node from one machine to another and avoiding to lose the delegation, here are few steps how to do it. -The following examples transfers a mix node (in case of other nodes, change the `mixnodes` in the command for the `` of your desire. +The following examples transfers a Mix node (in case of other nodes, change the `mixnodes` in the command for the `` of your desire. * Pause your node process. @@ -587,7 +587,7 @@ Assuming both machines are remote VPS. # in case none of the nym configs was created previously mkdir ~/.nym -#in case no nym mix node was initialized previously +#in case no nym Mix node was initialized previously mkdir ~/.nym/mixnodes ``` * Move the node data (keys) and config file to the new machine by opening a local terminal (as that one's ssh key is authorized in both of the machines) and running: @@ -614,16 +614,16 @@ ens4: flags=4163 mtu 1460 The `ens4` interface has the IP `10.126.5.7`. But this isn't the public IP of the machine, it's the IP of the machine on Google's internal network. Google uses virtual routing, so the public IP of this machine is something else, maybe `36.68.243.18`. -`./nym-mixnode init --host 10.126.5.7`, initalises the mix node, but no packets will be routed because `10.126.5.7` is not on the public internet. +`./nym-mixnode init --host 10.126.5.7`, initalises the Mix node, but no packets will be routed because `10.126.5.7` is not on the public internet. -Trying `nym-mixnode init --host 36.68.243.18`, you'll get back a startup error saying `AddrNotAvailable`. This is because the mix node doesn't know how to bind to a host that's not in the output of `ifconfig`. +Trying `nym-mixnode init --host 36.68.243.18`, you'll get back a startup error saying `AddrNotAvailable`. This is because the Mix node doesn't know how to bind to a host that's not in the output of `ifconfig`. The right thing to do in this situation is to init with a command: ```sh ./nym-mixnode init --host 10.126.5.7 --announce-host 36.68.243.18 ``` -This will bind the mix node to the available host `10.126.5.7`, but announce the mix node's public IP to the directory server as `36.68.243.18`. It's up to you as a node operator to ensure that your public and private IPs match up properly. +This will bind the Mix node to the available host `10.126.5.7`, but announce the Mix node's public IP to the directory server as `36.68.243.18`. It's up to you as a node operator to ensure that your public and private IPs match up properly. To find the right IP configuration, contact your VPS provider for support. @@ -632,11 +632,11 @@ Numerous API endpoints are documented on the Nym API (previously 'Validator API' ### Mix node Reward Estimation API endpoint -The Reward Estimation API endpoint allows mix node operators to estimate the rewards they could earn for running a Nym mix node with a specific `MIX_ID`. +The Reward Estimation API endpoint allows Mix node operators to estimate the rewards they could earn for running a Nym Mix node with a specific `MIX_ID`. > The `` can be found in the "Mix ID" column of the [Network Explorer](https://explorer.nymtech.net/network-components/mixnodes/active). -The endpoint is a particularly common for mix node operators as it can provide an estimate of potential earnings based on factors such as the amount of traffic routed through the mix node, the quality of the mix node's performance, and the overall demand for mixnodes in the network. This information can be useful for mix node operators in deciding whether or not to run a mix node and in optimizing its operations for maximum profitability. +The endpoint is a particularly common for Mix node operators as it can provide an estimate of potential earnings based on factors such as the amount of traffic routed through the Mix node, the quality of the Mix node's performance, and the overall demand for Mixnodes in the network. This information can be useful for Mix node operators in deciding whether or not to run a Mix node and in optimizing its operations for maximum profitability. Using this API endpoint returns information about the Reward Estimation: @@ -657,15 +657,15 @@ Query Response: > The unit of value is measured in `uNYM`. -- `estimated_total_node_reward` - An estimate of the total amount of rewards that a particular mix node can expect to receive during the current epoch. This value is calculated by the Nym Validator based on a number of factors, including the current state of the network, the number of mix nodes currently active in the network, and the amount of network traffic being processed by the mix node. +- `estimated_total_node_reward` - An estimate of the total amount of rewards that a particular Mix node can expect to receive during the current epoch. This value is calculated by the Nym Validator based on a number of factors, including the current state of the network, the number of Mix nodes currently active in the network, and the amount of network traffic being processed by the Mix node. -- `estimated_operator_reward` - An estimate of the amount of rewards that a particular mix node operator can expect to receive. This value is calculated by the Nym Validator based on a number of factors, including the amount of traffic being processed by the mix node, the quality of service provided by the mix node, and the operator's stake in the network. +- `estimated_operator_reward` - An estimate of the amount of rewards that a particular Mix node operator can expect to receive. This value is calculated by the Nym Validator based on a number of factors, including the amount of traffic being processed by the Mix node, the quality of service provided by the Mix node, and the operator's stake in the network. -- `estimated_delegators_reward` - An estimate of the amount of rewards that mix node delegators can expect to receive individually. This value is calculated by the Nym Validator based on a number of factors, including the amount of traffic being processed by the mix node, the quality of service provided by the mix node, and the delegator's stake in the network. +- `estimated_delegators_reward` - An estimate of the amount of rewards that Mix node delegators can expect to receive individually. This value is calculated by the Nym Validator based on a number of factors, including the amount of traffic being processed by the Mix node, the quality of service provided by the Mix node, and the delegator's stake in the network. -- `estimated_node_profit` - An estimate of the profit that a particular mix node operator can expect to earn. This value is calculated by subtracting the mix node operator's `operating_costs` from their `estimated_operator_reward` for the current epoch. +- `estimated_node_profit` - An estimate of the profit that a particular Mix node operator can expect to earn. This value is calculated by subtracting the Mix node operator's `operating_costs` from their `estimated_operator_reward` for the current epoch. -- `estimated_operator_cost` - An estimate of the total cost that a particular mix node operator can expect to incur for their participation. This value is calculated by the Nym Validator based on a number of factors, including the cost of running a mix node, such as server hosting fees, and other expenses associated with operating the mix node. +- `estimated_operator_cost` - An estimate of the total cost that a particular Mix node operator can expect to incur for their participation. This value is calculated by the Nym Validator based on a number of factors, including the cost of running a Mix node, such as server hosting fees, and other expenses associated with operating the Mix node. ### Validator: Installing and configuring nginx for HTTPS #### Setup From a2ede72798f5b51630d307122b4ebd2da8263a68 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Thu, 9 Nov 2023 17:16:55 +0100 Subject: [PATCH 26/80] unify naming convention network requester to Network requester --- documentation/operators/src/nodes/maintenance.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/documentation/operators/src/nodes/maintenance.md b/documentation/operators/src/nodes/maintenance.md index caa9c24d3e..79efbcca22 100644 --- a/documentation/operators/src/nodes/maintenance.md +++ b/documentation/operators/src/nodes/maintenance.md @@ -29,7 +29,7 @@ Follow these steps to upgrade your Mix node binary and update its config file: * re-run `init` with the same values as you used initially. **This will just update the config file, it will not overwrite existing keys**. * restart your Mix node process with the new binary. -> In case of a network requester this is all all, the following step is only for Mix nodes and Gateways. +> In case of a Network requester this is all all, the following step is only for Mix nodes and Gateways. ### Step 2: Updating your node information in the smart contract Follow these steps to update the information about your `` which is publicly available from the [Nym API](https://validator.nymtech.net/api/swagger/index.html) and information displayed on the [mixnet explorer](https://explorer.nymtech.net). @@ -53,9 +53,9 @@ If you want to bond your `` via the CLI, then check out the [relevant sect In the previous version of the network-requester, users were required to run a nym-client along side it to function. As of `v1.1.10`, the network-requester now has a nym client embedded into the binary, so it can run standalone. -If you are running an existing network requester registered with nym-connect, upgrading requires you move your old keys over to the new network requester configuration. We suggest following these instructions carefully to ensure a smooth transition. +If you are running an existing Network requester registered with nym-connect, upgrading requires you move your old keys over to the new Network requester configuration. We suggest following these instructions carefully to ensure a smooth transition. -Initiate the new network requester: +Initiate the new Network requester: ```sh nym-network-requester init --id @@ -496,7 +496,7 @@ The ulimit setup is relevant for maintenance of nym Mix node only. Query the `ulimit` of your `` with: ```sh -# for nym-mixnode, nym-gateway and nym-network requester: +# for nym-mixnode, nym-gateway and nym-network-requester: grep -i "open files" /proc/$(ps -A -o pid,cmd|grep | grep -v grep |head -n 1 | awk '{print $1}')/limits # for nyx validator: @@ -533,7 +533,7 @@ echo "DefaultLimitNOFILE=65535" >> /etc/systemd/system.conf Reboot your machine and restart your node. When it comes back, use: ```sh -# for nym-mixnode, nym-gateway and nym-network requester: +# for nym-mixnode, nym-gateway and nym-network-requester: cat /proc/$(pidof )/limits | grep "Max open files" # for validator From 09124dafac841fed42eb92d98a2dcd298f578956 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Thu, 9 Nov 2023 17:20:20 +0100 Subject: [PATCH 27/80] unify naming convention network requester to Network requester --- .../src/nodes/network-requester-setup.md | 40 +++++++++---------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/documentation/operators/src/nodes/network-requester-setup.md b/documentation/operators/src/nodes/network-requester-setup.md index 9945bf0d0f..6788dc51e6 100644 --- a/documentation/operators/src/nodes/network-requester-setup.md +++ b/documentation/operators/src/nodes/network-requester-setup.md @@ -1,6 +1,6 @@ # Network Requesters -> The Nym network requester was built in the [building nym](../binaries/building-nym.md) section. If you haven't yet built Nym and want to run the code, go there first. +> Nym Network requester was built in the [building nym](../binaries/building-nym.md) section. If you haven't yet built Nym and want to run the code, go there first. ```admonish info As a result of [Project Smoosh](../faq/smoosh-faq.md), the current version of `nym-gateway` binary also contains `nym-network-requester` functionality which can be enabled [by the operator](./gateway-setup.md#initialising-gateway-with-network-requester). This combination is a basis of Nym exit gateway node - an essential piece in our new setup. Please read more in our [Project Smoosh FAQ](../faq/smoosh-faq.md) and [Exit Gateways Page](../legal/exit-gateway.md). We recommend operators begin to shift their setups to this new combined node, instead of operating two separate binaries. @@ -15,15 +15,15 @@ As a result of [Project Smoosh](../faq/smoosh-faq.md), the current version of `n ## Preliminary steps -Make sure you do the preparation listed in the [preliminary steps page](../preliminary-steps.md) before setting up your network requester. +Make sure you do the preparation listed in the [preliminary steps page](../preliminary-steps.md) before setting up your Network requester. ## Network Requester Whitelist -If you have access to a server, you can run the network requester, which allows Nym users to send outbound requests from their local machine through the mixnet to a server, which then makes the request on their behalf, shielding them (and their metadata) from clearnet, untrusted and unknown infrastructure, such as email or message client servers. +If you have access to a server, you can run the Network requester, which allows Nym users to send outbound requests from their local machine through the mixnet to a server, which then makes the request on their behalf, shielding them (and their metadata) from clearnet, untrusted and unknown infrastructure, such as email or message client servers. By default the network requester is **not** an open proxy (although it can be used as one). It uses a file called `allowed.list` (located in `~/.nym/service-providers/network-requester//`) as a whitelist for outbound requests. -**Note:** If you run network requester as a part of the exit gateway (suggested setup) the `allowed.list` will be stored in `~/.nym/gateways//data/network-requester-data/allowed.list`. +**Note:** If you run Network requester as a part of the exit gateway (suggested setup) the `allowed.list` will be stored in `~/.nym/gateways//data/network-requester-data/allowed.list`. Any request to a URL which is not on this list will be blocked. @@ -31,7 +31,7 @@ On startup, if this file is not present, the requester will grab the default whi This default whitelist is useful for knowing that the majority of Network requesters are able to support certain apps 'out of the box'. -**Operators of a network requester are of course free to edit this file and add the URLs of services they wish to support to it!** You can find instructions below on adding your own URLs or IPs to this list. +**Operators of a Network requester are of course free to edit this file and add the URLs of services they wish to support to it!** You can find instructions below on adding your own URLs or IPs to this list. The domains and IPs on the default whitelist can be broken down by application as follows: @@ -116,7 +116,7 @@ You can find a list of Network requesters running the default whitelist in the [ ## Viewing command help ```admonish info -If you run your network requester as a part of your exit gateway according to the suggested setup, please skip this part of the page and read about [exit gateway setup](./gateway-setup.md#initialising-gateway-with-network-requester) instead. +If you run your Network requester as a part of your exit gateway according to the suggested setup, please skip this part of the page and read about [exit gateway setup](./gateway-setup.md#initialising-gateway-with-network-requester) instead. ``` To begin, move to `/target/release` directory from which you run the node commands: @@ -141,9 +141,9 @@ You can check the required parameters for available commands by running: > Adding `--no-banner` startup flag will prevent Nym banner being printed even if run in tty environment. -## Initializing and running your network requester +## Initializing and running your Network requester -The network-requester needs to be initialized before it can be run. This is required for the embedded nym-client to connect successfully to the mixnet. We want to specify an `` using the `--id` command and give it a value of your choice. The following command will achieve that: +The Network requester needs to be initialized before it can be run. This is required for the embedded nym-client to connect successfully to the mixnet. We want to specify an `` using the `--id` command and give it a value of your choice. The following command will achieve that: ``` ./nym-network-requester init --id @@ -164,11 +164,11 @@ Now that we have initialized our network-requester, we can start it with the fol ./nym-network-requester run --id ``` -## Using your network requester +## Using your Network requester -The next thing to do is use your requester, share its address with friends (or whoever you want to help privacy-enhance their app traffic). Is this safe to do? If it was an open proxy, this would be unsafe, because any Nym user could make network requests to any system on the internet. +The next thing to do is use your requester, share its address with friends (or whoever you want to help privacy-enhance their app traffic). Is this safe to do? If it was an open proxy, this would be unsafe, because any Nym user could make Network requests to any system on the internet. -To make things a bit less stressful for administrators, the Network Requester drops all incoming requests by default. In order for it to make requests, you need to add specific domains to the `allowed.list` file at `$HOME/.nym/service-providers/network-requester/allowed.list` or if network requester is ran as a part of [exit gateway](./gateway-setup.md#initialising-gateway-with-network-requester), the `allowed.list` will be stored in `~/.nym/gateways//data/network-requester-data/allowed.list` +To make things a bit less stressful for administrators, the Network Requester drops all incoming requests by default. In order for it to make requests, you need to add specific domains to the `allowed.list` file at `$HOME/.nym/service-providers/network-requester/allowed.list` or if Network requester is ran as a part of [exit gateway](./gateway-setup.md#initialising-gateway-with-network-requester), the `allowed.list` will be stored in `~/.nym/gateways//data/network-requester-data/allowed.list` ### Global vs local allow lists Your Network Requester will check for a domain against 2 lists before allowing traffic through for a particular domain or IP. @@ -177,15 +177,15 @@ Your Network Requester will check for a domain against 2 lists before allowing t * The second is the local `allowed.list` file. -### Supporting custom domains with your network requester +### Supporting custom domains with your Network requester It is easy to add new domains and services to your network requester - simply find out which endpoints (both URLs and raw IP addresses are supported) you need to whitelist, and then add these endpoints to your `allowed.list`. > In order to keep things more organised, you can now use comments in the `allow.list` like the example at the top of this page. -How to go about this? Have a look in your nym-network-requester config directory: +How to go about this? Have a look in your `nym-network-requester` config directory: ``` -# network requester binary +# nym-network-requester binary ls -lt $HOME/.nym/service-providers/network-requester/*/data | grep "list" # exit gateway binary @@ -194,17 +194,17 @@ ls -lt $HOME/.nym/gateways/*/data/network-requester-data | grep "list" # returns: allowed.list unknown.list ``` -We already know that `allowed.list` is what lets requests go through. All unknown requests are logged to `unknown.list`. If you want to try using a new client type, just start the new application, point it at your local [socks client](https://nymtech.net/docs/clients/socks5-client.html) (configured to use your remote `nym-network-requester`), and keep copying URLs from `unknown.list` into `allowed.list` (it may take multiple tries until you get all of them, depending on the complexity of the application). Make sure to delete the copied ones in `unknown.list` and restart your exit gateway or standalone network requester. +We already know that `allowed.list` is what lets requests go through. All unknown requests are logged to `unknown.list`. If you want to try using a new client type, just start the new application, point it at your local [socks client](https://nymtech.net/docs/clients/socks5-client.html) (configured to use your remote `nym-network-requester`), and keep copying URLs from `unknown.list` into `allowed.list` (it may take multiple tries until you get all of them, depending on the complexity of the application). Make sure to delete the copied ones in `unknown.list` and restart your exit gateway or standalone Network requester. > If you are adding custom domains, please note that whilst they may appear in the logs of your network-requester as something like `api-0.core.keybaseapi.com:443`, you **only need** to include the main domain name, in this instance `keybaseapi.com` ### Running an open proxy -If you *really* want to run an open proxy, perhaps for testing purposes for your own use or among a small group of trusted friends, it is possible to do so. You can disable network checks by passing the flag `--open-proxy` flag when you run it. If you run in this configuration, you do so at your own risk. +If you *really* want to run an open proxy, perhaps for testing purposes for your own use or among a small group of trusted friends, it is possible to do so. You can disable Network checks by passing the flag `--open-proxy` flag when you run it. If you run in this configuration, you do so at your own risk. -## Testing your network requester -1. Make sure `nymtech.net` is in your `allowed.list` (remember to restart your network requester). +## Testing your Network requester +1. Make sure `nymtech.net` is in your `allowed.list` (remember to restart your Network requester). -2. Ensure that your network-requester is initialized and running. +2. Ensure that your `nym-network-requester` is initialized and running. 3. In another terminal window, run the following: @@ -220,5 +220,5 @@ This command should return the following: ## Maintenance -For network requester upgrade (including an upgrade from `= v1.1.10`), firewall setup, port configuration, API endpoints, VPS suggestions, automation and more, see the [maintenance page](./maintenance.md). +For Network requester upgrade (including an upgrade from `= v1.1.10`), firewall setup, port configuration, API endpoints, VPS suggestions, automation and more, see the [maintenance page](./maintenance.md). From d09503edf4f2e6031c6c474883d8e5832456a3c2 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Thu, 9 Nov 2023 17:22:09 +0100 Subject: [PATCH 28/80] unify naming convention gateway to Gateway --- .../operators/src/nodes/network-requester-setup.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/documentation/operators/src/nodes/network-requester-setup.md b/documentation/operators/src/nodes/network-requester-setup.md index 6788dc51e6..4a90ea0f88 100644 --- a/documentation/operators/src/nodes/network-requester-setup.md +++ b/documentation/operators/src/nodes/network-requester-setup.md @@ -3,7 +3,7 @@ > Nym Network requester was built in the [building nym](../binaries/building-nym.md) section. If you haven't yet built Nym and want to run the code, go there first. ```admonish info -As a result of [Project Smoosh](../faq/smoosh-faq.md), the current version of `nym-gateway` binary also contains `nym-network-requester` functionality which can be enabled [by the operator](./gateway-setup.md#initialising-gateway-with-network-requester). This combination is a basis of Nym exit gateway node - an essential piece in our new setup. Please read more in our [Project Smoosh FAQ](../faq/smoosh-faq.md) and [Exit Gateways Page](../legal/exit-gateway.md). We recommend operators begin to shift their setups to this new combined node, instead of operating two separate binaries. +As a result of [Project Smoosh](../faq/smoosh-faq.md), the current version of `nym-gateway` binary also contains `nym-network-requester` functionality which can be enabled [by the operator](./gateway-setup.md#initialising-gateway-with-network-requester). This combination is a basis of Nym Exit Gateway node - an essential piece in our new setup. Please read more in our [Project Smoosh FAQ](../faq/smoosh-faq.md) and [Exit Gateways Page](../legal/exit-gateway.md). We recommend operators begin to shift their setups to this new combined node, instead of operating two separate binaries. ``` > Any syntax in `<>` brackets is a user's unique variable. Exchange with a corresponding name without the `<>` brackets. @@ -23,7 +23,7 @@ If you have access to a server, you can run the Network requester, which allows By default the network requester is **not** an open proxy (although it can be used as one). It uses a file called `allowed.list` (located in `~/.nym/service-providers/network-requester//`) as a whitelist for outbound requests. -**Note:** If you run Network requester as a part of the exit gateway (suggested setup) the `allowed.list` will be stored in `~/.nym/gateways//data/network-requester-data/allowed.list`. +**Note:** If you run Network requester as a part of the Exit Gateway (suggested setup) the `allowed.list` will be stored in `~/.nym/gateways//data/network-requester-data/allowed.list`. Any request to a URL which is not on this list will be blocked. @@ -116,7 +116,7 @@ You can find a list of Network requesters running the default whitelist in the [ ## Viewing command help ```admonish info -If you run your Network requester as a part of your exit gateway according to the suggested setup, please skip this part of the page and read about [exit gateway setup](./gateway-setup.md#initialising-gateway-with-network-requester) instead. +If you run your Network requester as a part of your Exit Gateway according to the suggested setup, please skip this part of the page and read about [Exit Gateway setup](./gateway-setup.md#initialising-gateway-with-network-requester) instead. ``` To begin, move to `/target/release` directory from which you run the node commands: @@ -168,7 +168,7 @@ Now that we have initialized our network-requester, we can start it with the fol The next thing to do is use your requester, share its address with friends (or whoever you want to help privacy-enhance their app traffic). Is this safe to do? If it was an open proxy, this would be unsafe, because any Nym user could make Network requests to any system on the internet. -To make things a bit less stressful for administrators, the Network Requester drops all incoming requests by default. In order for it to make requests, you need to add specific domains to the `allowed.list` file at `$HOME/.nym/service-providers/network-requester/allowed.list` or if Network requester is ran as a part of [exit gateway](./gateway-setup.md#initialising-gateway-with-network-requester), the `allowed.list` will be stored in `~/.nym/gateways//data/network-requester-data/allowed.list` +To make things a bit less stressful for administrators, the Network Requester drops all incoming requests by default. In order for it to make requests, you need to add specific domains to the `allowed.list` file at `$HOME/.nym/service-providers/network-requester/allowed.list` or if Network requester is ran as a part of [Exit Gateway](./gateway-setup.md#initialising-gateway-with-network-requester), the `allowed.list` will be stored in `~/.nym/gateways//data/network-requester-data/allowed.list` ### Global vs local allow lists Your Network Requester will check for a domain against 2 lists before allowing traffic through for a particular domain or IP. @@ -188,13 +188,13 @@ How to go about this? Have a look in your `nym-network-requester` config directo # nym-network-requester binary ls -lt $HOME/.nym/service-providers/network-requester/*/data | grep "list" -# exit gateway binary +# nym-gateway binary ls -lt $HOME/.nym/gateways/*/data/network-requester-data | grep "list" # returns: allowed.list unknown.list ``` -We already know that `allowed.list` is what lets requests go through. All unknown requests are logged to `unknown.list`. If you want to try using a new client type, just start the new application, point it at your local [socks client](https://nymtech.net/docs/clients/socks5-client.html) (configured to use your remote `nym-network-requester`), and keep copying URLs from `unknown.list` into `allowed.list` (it may take multiple tries until you get all of them, depending on the complexity of the application). Make sure to delete the copied ones in `unknown.list` and restart your exit gateway or standalone Network requester. +We already know that `allowed.list` is what lets requests go through. All unknown requests are logged to `unknown.list`. If you want to try using a new client type, just start the new application, point it at your local [socks client](https://nymtech.net/docs/clients/socks5-client.html) (configured to use your remote `nym-network-requester`), and keep copying URLs from `unknown.list` into `allowed.list` (it may take multiple tries until you get all of them, depending on the complexity of the application). Make sure to delete the copied ones in `unknown.list` and restart your Exit Gateway or standalone Network requester. > If you are adding custom domains, please note that whilst they may appear in the logs of your network-requester as something like `api-0.core.keybaseapi.com:443`, you **only need** to include the main domain name, in this instance `keybaseapi.com` From 9113658a423ff7de855670666ff1c6bc93a9b246 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Thu, 9 Nov 2023 17:34:00 +0100 Subject: [PATCH 29/80] unify naming convention --- documentation/operators/src/nodes/network-requester-setup.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/documentation/operators/src/nodes/network-requester-setup.md b/documentation/operators/src/nodes/network-requester-setup.md index 4a90ea0f88..d98a937f93 100644 --- a/documentation/operators/src/nodes/network-requester-setup.md +++ b/documentation/operators/src/nodes/network-requester-setup.md @@ -19,7 +19,7 @@ Make sure you do the preparation listed in the [preliminary steps page](../preli ## Network Requester Whitelist -If you have access to a server, you can run the Network requester, which allows Nym users to send outbound requests from their local machine through the mixnet to a server, which then makes the request on their behalf, shielding them (and their metadata) from clearnet, untrusted and unknown infrastructure, such as email or message client servers. +If you have access to a server, you can run the Network requester, which allows Nym users to send outbound requests from their local machine through the Mixnet to a server, which then makes the request on their behalf, shielding them (and their metadata) from clearnet, untrusted and unknown infrastructure, such as email or message client servers. By default the network requester is **not** an open proxy (although it can be used as one). It uses a file called `allowed.list` (located in `~/.nym/service-providers/network-requester//`) as a whitelist for outbound requests. @@ -143,7 +143,7 @@ You can check the required parameters for available commands by running: ## Initializing and running your Network requester -The Network requester needs to be initialized before it can be run. This is required for the embedded nym-client to connect successfully to the mixnet. We want to specify an `` using the `--id` command and give it a value of your choice. The following command will achieve that: +The Network requester needs to be initialized before it can be run. This is required for the embedded nym-client to connect successfully to the Mixnet. We want to specify an `` using the `--id` command and give it a value of your choice. The following command will achieve that: ``` ./nym-network-requester init --id From 6088c835a3af512b19da99668ee59ac772172c65 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Thu, 9 Nov 2023 17:53:51 +0100 Subject: [PATCH 30/80] unify naming convention mixnode to Mix node --- .../operators/src/nodes/troubleshooting.md | 42 +++++++++---------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/documentation/operators/src/nodes/troubleshooting.md b/documentation/operators/src/nodes/troubleshooting.md index 7e2f37503d..4385851ae2 100644 --- a/documentation/operators/src/nodes/troubleshooting.md +++ b/documentation/operators/src/nodes/troubleshooting.md @@ -78,7 +78,7 @@ Additional details can be obtained via various methods after you connect to your ##### Socket statistics with `ss` ``` -sudo ss -s -t | grep 1789 # if you have specified a different port in your mix node config, change accordingly +sudo ss -s -t | grep 1789 # if you have specified a different port in your Mix node config, change accordingly ``` This command should return a lot of data containing `ESTAB`. This command should work on every unix based system. @@ -90,7 +90,7 @@ This command should return a lot of data containing `ESTAB`. This command should lsof -v # install if not installed sudo apt install lsof -# run against mix node port +# run against nym-mix-node node port sudo lsof -i TCP:1789 # if you have specified a different port in your mixnode config, change accordingly ``` @@ -110,7 +110,7 @@ nym-mixno 103349 root 57u IPv6 1333229976 0t0 TCP [2a03:b0c0:3:d0::ff3: sudo journalctl -u nym-mixnode -o cat | grep "Since startup mixed" ``` -If you have created `nym-mixnode.service` file (i.e. you are running your mix node via `systemd`) then this command shows you how many packets have you mixed so far, and should return a list of messages like this: +If you have created `nym-mixnode.service` file (i.e. you are running your Mix node via `systemd`) then this command shows you how many packets have you mixed so far, and should return a list of messages like this: ``` 2021-05-18T12:35:24.057Z INFO nym_mixnode::node::metrics > Since startup mixed 233639 packets! @@ -140,7 +140,7 @@ For example `./target/debug/nym-network-requester --no-banner build-info --outpu nmap -p 1789 -Pn ``` -If your mix node is configured properly it should output something like this: +If your Mix node is configured properly it should output something like this: ``` bob@desktop:~$ nmap -p 1789 95.296.134.220 -Pn @@ -164,7 +164,7 @@ You can query gateways by replacing `mixnodes` with `gateways` in the above comm #### Check with Network API -We currently have an API set up returning our metrics tests of the network. There are two endpoints to ping for information about your mix node, `report` and `history`. Find more information about this in the [Mixnodes metrics documentation](./maintenance.md#metrics--api-endpoints). +We currently have an API set up returning our metrics tests of the network. There are two endpoints to ping for information about your Mix node, `report` and `history`. Find more information about this in the [Mixnodes metrics documentation](./maintenance.md#metrics--api-endpoints). ### Why is my node not mixing any packets? @@ -172,24 +172,24 @@ If you are still unable to see your node on the dashboard, or your node is decla - The firewall on your host machine is not configured properly. Checkout the [instructions](./maintenance.md#configure-your-firewall). - You provided incorrect information when bonding your node. -- You are running your mix node from a VPS without IPv6 support. -- You did not use the `--announce-host` flag while running the mix node from your local machine behind NAT. -- You did not configure your router firewall while running the mix node from your local machine behind NAT, or you are lacking IPv6 support. +- You are running your Mix node from a VPS without IPv6 support. +- You did not use the `--announce-host` flag while running the Mix node from your local machine behind NAT. +- You did not configure your router firewall while running the Mix node from your local machine behind NAT, or you are lacking IPv6 support. - Your mix node is not running at all, it has either exited / panicked or you closed the session without making the node persistent. Check out the [instructions](./maintenance.md#automating-your-node-with-tmux-and-systemd). ```admonish caution -Your mix node **must speak both IPv4 and IPv6** in order to cooperate with other nodes and route traffic. This is a common reason behind many errors we are seeing among node operators, so check with your provider that your VPS is able to do this! +Your Mix node **must speak both IPv4 and IPv6** in order to cooperate with other nodes and route traffic. This is a common reason behind many errors we are seeing among node operators, so check with your provider that your VPS is able to do this! ``` #### Incorrect bonding information -Check that you have provided the correct information when bonding your mix node in the web wallet interface. When in doubt, un-bond and then re-bond your node! +Check that you have provided the correct information when bonding your Mix node in the web wallet interface. When in doubt, un-bond and then re-bond your node! -> All delegated stake will be lost when un-bonding! However the mix node must be operational in the first place for the delegation to have any effect. +> All delegated stake will be lost when un-bonding! However the Mix node must be operational in the first place for the delegation to have any effect. #### Missing `announce-host` flag -On certain cloud providers such as AWS and Google Cloud, you need to do some additional configuration of your firewall and use `--host` with your **local ip** and `--announce-host` with the **public ip** of your mix node host. +On certain cloud providers such as AWS and Google Cloud, you need to do some additional configuration of your firewall and use `--host` with your **local ip** and `--announce-host` with the **public ip** of your Mix node host. If the difference between the two is unclear, contact the help desk of your VPS provider. @@ -222,15 +222,15 @@ bob@nym:~$ hostname -I ### Running on a local machine behind NAT with no fixed IP address -Your ISP has to be IPv6 ready if you want to run a mix node on your local machine. Sadly, in 2020, most of them are not and you won't get an IPv6 address by default from your ISP. Usually it is an extra paid service or they simply don't offer it. +Your ISP has to be IPv6 ready if you want to run a Mix node on your local machine. Sadly, in 2020, most of them are not and you won't get an IPv6 address by default from your ISP. Usually it is an extra paid service or they simply don't offer it. Before you begin, check if you have IPv6 [here](https://test-ipv6.cz/) or by running command explained in the [section above](./troubleshooting.md#no-ipv6-connectivity). If not, then don't waste your time to run a node which won't ever be able to mix any packet due to this limitation. Call your ISP and ask for IPv6, there is a plenty of it for everyone! -If all goes well and you have IPv6 available, then you will need to `init` the mix node with an extra flag, `--announce-host`. You will also need to edit your `config.toml` file each time your IPv4 address changes, that could be a few days or a few weeks. Check the your IPv4 in the [section above](./troubleshooting.md#no-ipv6-connectivity). +If all goes well and you have IPv6 available, then you will need to `init` the Mix node with an extra flag, `--announce-host`. You will also need to edit your `config.toml` file each time your IPv4 address changes, that could be a few days or a few weeks. Check the your IPv4 in the [section above](./troubleshooting.md#no-ipv6-connectivity). Additional configuration on your router might also be needed to allow traffic in and out to port 1789 and IPv6 support. -Here is a sample of the `init` command example to create the mix node config. +Here is a sample of the `init` command example to create the Mix node config. ``` ./nym-mixnode init --id --host 0.0.0.0 --announce-host 85.160.12.13 @@ -244,7 +244,7 @@ Make sure you check if your node is really mixing. We are aiming to improve the ### Accidentally killing your node process on exiting session -When you close your current terminal session, you need to make sure you don't kill the mix node process! There are multiple ways on how to make it persistent even after exiting your ssh session, the easiest solution is to use `tmux` or `nohup`, and the more elegant solution is to run the node with `systemd`. Read the automation manual [here](./maintenance.md#automating-your-node-with-tmux-and-systemd). +When you close your current terminal session, you need to make sure you don't kill the Mix node process! There are multiple ways on how to make it persistent even after exiting your ssh session, the easiest solution is to use `tmux` or `nohup`, and the more elegant solution is to run the node with `systemd`. Read the automation manual [here](./maintenance.md#automating-your-node-with-tmux-and-systemd). ### Common errors and warnings @@ -266,14 +266,14 @@ Then you need to `--announce-host ` and `--host ` on startu Yes! Here is what you will need to do: -Assuming you would like to use port `1337` for your mix node, you need to open the new port (and close the old one): +Assuming you would like to use port `1337` for your Mix node, you need to open the new port (and close the old one): ``` sudo ufw allow 1337 sudo ufw deny 1789 ``` -And then edit the mix node's config. +And then edit the Mix node's config. > If you want to change the port for an already running node, you need to stop the process before editing your config file. @@ -287,11 +287,11 @@ nano ~/.nym/mixnodes/alice-node/config/config.toml You will need to edit two parts of the file. `announce_address` and `listening_address` in the config.toml file. Simply replace `:1789` (the default port) with `:1337` (your new port) after your IP address. -Finally, restart your node. You should see if the mix node is using the port you have changed in the config.toml file right after you run the node. +Finally, restart your node. You should see if the Mix node is using the port you have changed in the config.toml file right after you run the node. -### What is `verloc` and do I have to configure my mix node to implement it? +### What is `verloc` and do I have to configure my Mix node to implement it? -`verloc` is short for _verifiable location_. Mixnodes and gateways now measure speed-of-light distances to each other, in an attempt to verify how far apart they are. In later releases, this will allow us to algorithmically verify node locations in a non-fake-able and trustworthy manner. +`verloc` is short for _verifiable location_. Mixnodes and Gateways now measure speed-of-light distances to each other, in an attempt to verify how far apart they are. In later releases, this will allow us to algorithmically verify node locations in a non-fake-able and trustworthy manner. You don't have to do any additional configuration for your node to implement this, it is a passive process that runs in the background of the mixnet from version `0.10.1` onward. From b06d6ff4126e2e542d0100b4c5b75cc4dd89fe1e Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Thu, 9 Nov 2023 17:57:51 +0100 Subject: [PATCH 31/80] unify naming convention gateway to Gateway --- documentation/operators/src/nodes/troubleshooting.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/documentation/operators/src/nodes/troubleshooting.md b/documentation/operators/src/nodes/troubleshooting.md index 4385851ae2..8ea39dfdf4 100644 --- a/documentation/operators/src/nodes/troubleshooting.md +++ b/documentation/operators/src/nodes/troubleshooting.md @@ -159,7 +159,7 @@ curl --location --request GET 'https://validator.nymtech.net/api/v1/mixnodes/' Will return a list all nodes currently online. -You can query gateways by replacing `mixnodes` with `gateways` in the above command, and can query for the mixnodes and gateways on the Sandbox testnet by replacing `validator` with `sandbox-validator`. +You can query Gateways by replacing `nym-mixnodes` with `nym-gateways` in the above command, and can query for the Mix nodes and Gateways on the Sandbox testnet by replacing `validator` with `sandbox-validator`. #### Check with Network API @@ -301,11 +301,11 @@ You don't have to do any additional configuration for your node to implement thi Check your [firewall](./maintenance.md#configure-your-firewall) is active and if the necessary ports are open / allowed. -### My exit gateway "is still not online..." +### My exit Gateway "is still not online..." -The Nyx chain epoch takes up to 60 min. To prevent the gateway getting blacklisted, it's important to run it right after the bonding process to return positive response our API testing it's routing score. +The Nyx chain epoch takes up to 60 min. To prevent the Gateway getting blacklisted, it's important to run it before and during the bonding process. In case it already got blacklisted run it for at several hours. During this time your node is tested by `nym-api` and every positive response picks up your Gateway's routing score. -You may want to disconnect the network requester and let it run as a gatewy alone for some time to regain better routing score and then areturn to the full [exit gateway finctionality](./gateway-setup.md#initialising-gateway-with-network-requester). +You may want to disconnect the Network requester and let it run as a Gateway alone for some time to regain better routing score and then return to the full [Exit Gateway finctionality](./gateway-setup.md#initialising-gateway-with-network-requester). ## Validators From 3620cc9df0a1985b88524756843632119942488c Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Thu, 9 Nov 2023 18:08:00 +0100 Subject: [PATCH 32/80] unify naming convention gateway to Gateway --- documentation/operators/src/legal/exit-gateway.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/documentation/operators/src/legal/exit-gateway.md b/documentation/operators/src/legal/exit-gateway.md index 4cac80d7de..0b68fbe394 100644 --- a/documentation/operators/src/legal/exit-gateway.md +++ b/documentation/operators/src/legal/exit-gateway.md @@ -40,7 +40,7 @@ Nym core team cannot provide comprehensive legal advice across all jurisdictions To offer a better and more private everyday experience for its users, Nym would like them to use any online services they please, without limiting its access to a few messaging apps or crypto wallets. -To achieve this, operators running exit gateways would have to “open” their nodes to a wider range of online services, in a similar fashion to Tor exit relays following this [Exit policy](https://nymtech.net/.wellknown/network-requester/exit-policy.txt). +To achieve this, operators running Exit Gateways would have to “open” their nodes to a wider range of online services, in a similar fashion to Tor exit relays following this [Exit policy](https://nymtech.net/.wellknown/network-requester/exit-policy.txt). ## Pros and cons of the initiative @@ -64,7 +64,7 @@ The new setup: Running nodes supporting traffic of any online service (with safe | Operational | | - Higher operational overhead, such as dealing with DMCA / abuse complaints, managing the VPS provider questions, or helping the community to maintain the denylist
- Administrative overhead if running nodes as a company or an entity | | Legal | | - Ideally requires to check legal environment with local privacy association or lawyer | Financial | - Higher revenue potential for operators due to the increase in network usage | - If not running VPS with an unlimited bandwidth plan, higher costs due to higher network usage | -## Exit gateways: New setup +## Exit Gateways: New setup In our previous technical setup, network requesters acted as a proxy, and only made requests that match an allow list. That was a default IP based list of allowed domains stored at Nym page in a centralised fashion possibly re-defined by any Network requester operator. @@ -72,15 +72,15 @@ This restricts the hosts that the NymConnect app can connect to and has the effe The principal change in the new configuration is to make this short allow list more permissive. Nym's [Exit policy](https://nymtech.net/.wellknown/network-requester/exit-policy.txt) will restrict the hosts to which Nym Mixnet and Nym VPN users are permitted to connect. This will be done in an effort to protect the operators, as Gateways will act both as SOCKS5 Network Requesters, and exit nodes for IP traffic from Nym Mixnet VPN and VPN clients (both wrapped in the same app). -As of now we the gateways will be defaulted to a combination of [Tor Null ‘deny’ list](https://tornull.org/) (note: Not affiliated with Tor) - reproduction permitted under Creative Commons Attribution 3.0 United States License which is IP-based, e.g., `ExitPolicy reject 5.188.10.0/23:*` and [Tor reduced policy](https://tornull.org/tor-reduced-reduced-exit-policy.php). Whether we will stick with this list, do modifications or compile another one is still a subject of discussion. In all cases, this policy will remain the same for all the nodes, without any option to modify it by Nym node operators to secure stable and reliable service for the end users. +As of now we the Gateways will be defaulted to a combination of [Tor Null ‘deny’ list](https://tornull.org/) (note: Not affiliated with Tor) - reproduction permitted under Creative Commons Attribution 3.0 United States License which is IP-based, e.g., `ExitPolicy reject 5.188.10.0/23:*` and [Tor reduced policy](https://tornull.org/tor-reduced-reduced-exit-policy.php). Whether we will stick with this list, do modifications or compile another one is still a subject of discussion. In all cases, this policy will remain the same for all the nodes, without any option to modify it by Nym node operators to secure stable and reliable service for the end users. -For exit relays on ports 80 and 443, the gateways will exhibit an HTML page resembling the one proposed by [Tor](https://gitlab.torproject.org/tpo/core/tor/-/raw/HEAD/contrib/operator-tools/tor-exit-notice.html). By doing so, the operator will be able to disclose details regarding their gateway, including the currently configured exit policy, all without the need for direct correspondence with regulatory or law enforcement agencies. It also makes the behaviour of exit gateways transparent and even computable (a possible feature would be to offer a machine readable form of the notice in JSON or YAML). +For exit relays on ports 80 and 443, the Gateways will exhibit an HTML page resembling the one proposed by [Tor](https://gitlab.torproject.org/tpo/core/tor/-/raw/HEAD/contrib/operator-tools/tor-exit-notice.html). By doing so, the operator will be able to disclose details regarding their Gateway, including the currently configured exit policy, all without the need for direct correspondence with regulatory or law enforcement agencies. It also makes the behavior of Exit Gateways transparent and even computable (a possible feature would be to offer a machine readable form of the notice in JSON or YAML). We also recommend operators to check the technical advice from [Tor](https://community.torproject.org/relay/setup/exit/). ## Tor legal advice -Giving the legal similarity between Nym exit gateways and Tor exit relays, it is helpful to have a look in [Tor community Exit Guidelines](https://community.torproject.org/relay/community-resources/tor-exit-guidelines/). This chapter is an exert of tor page. +Giving the legal similarity between Nym Exit Gateways and Tor exit relays, it is helpful to have a look in [Tor community Exit Guidelines](https://community.torproject.org/relay/community-resources/tor-exit-guidelines/). This chapter is an exert of tor page. Note that Tor states: > This FAQ is for informational purposes only and does not constitute legal advice. @@ -88,7 +88,7 @@ Note that Tor states: *Check legal advice prior to running an exit relay* * Understand the risks associated with running an exit relay; E.g., know legal paragraphs relevant in the country of operations: - - US [DMCA 512](https://www.law.cornell.edu/uscode/text/17/512); see [EFF's Legal FAQ for TOr Operators](https://community.torproject.org/relay/community-resources/eff-tor-legal-faq) (a very good and relevant read for other countries as well) + - US [DMCA 512](https://www.law.cornell.edu/uscode/text/17/512); see [EFF's Legal FAQ for Tor Operators](https://community.torproject.org/relay/community-resources/eff-tor-legal-faq) (a very good and relevant read for other countries as well) - Germany’s [TeleMedienGesetz 8](http://www.gesetze-im-internet.de/tmg/__8.html) and [15](http://www.gesetze-im-internet.de/tmg/__15.html) - Netherlands: [Artikel 6:196c BW](http://wetten.overheid.nl/BWBR0005289/Boek6/Titel3/Afdeling4A/Artikel196c/) - Austria: [E-Commerce-Gesetz 13](http://www.ris.bka.gv.at/Dokument.wxe?Abfrage=Bundesnormen&Dokumentnummer=NOR40025809) From dd04d4ea461da0859bd4e6c2b5065026476c0468 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Thu, 9 Nov 2023 18:08:34 +0100 Subject: [PATCH 33/80] unify naming convention --- documentation/operators/src/legal/exit-gateway.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/documentation/operators/src/legal/exit-gateway.md b/documentation/operators/src/legal/exit-gateway.md index 0b68fbe394..19c0e88f4e 100644 --- a/documentation/operators/src/legal/exit-gateway.md +++ b/documentation/operators/src/legal/exit-gateway.md @@ -17,9 +17,9 @@ Nym core team cannot provide comprehensive legal advice across all jurisdictions ## Summary -* This document outlines a plan to change Nym Gateways from operating with an ‘allow’ to a ‘deny’ list to enable broader uptake and usage of the Nym mixnet. It provides operators with an overview of the plan, pros and cons, legal as well as technical advice. +* This document outlines a plan to change Nym Gateways from operating with an ‘allow’ to a ‘deny’ list to enable broader uptake and usage of the Nym Mixnet. It provides operators with an overview of the plan, pros and cons, legal as well as technical advice. -* Nym is committed to ensuring privacy for all users, regardless of their location and for the broadest possible range of online services. In order to achieve this aim, the Nym mixnet needs to increase its usability across a broad range of apps and services. +* Nym is committed to ensuring privacy for all users, regardless of their location and for the broadest possible range of online services. In order to achieve this aim, the Nym Mixnet needs to increase its usability across a broad range of apps and services. * Currently, Nym Gateway nodes only enable access to apps and services that are on an ‘allow’ list that is maintained by the core team. From 1d292d4688fdb60c30f6853d0a68184e755fc8cd Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Thu, 9 Nov 2023 18:09:09 +0100 Subject: [PATCH 34/80] unify naming convention --- documentation/operators/src/legal/exit-gateway.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/documentation/operators/src/legal/exit-gateway.md b/documentation/operators/src/legal/exit-gateway.md index 19c0e88f4e..c60fc8dcea 100644 --- a/documentation/operators/src/legal/exit-gateway.md +++ b/documentation/operators/src/legal/exit-gateway.md @@ -23,7 +23,7 @@ Nym core team cannot provide comprehensive legal advice across all jurisdictions * Currently, Nym Gateway nodes only enable access to apps and services that are on an ‘allow’ list that is maintained by the core team. -* To decentralise and enable privacy for a broader range of services, this initiative will have to transition from the current ‘allow’ list to a ‘deny’ list - [Exit policy](https://nymtech.net/.wellknown/network-requester/exit-policy.txt). In accordance with the [Tor Null 'deny' list](https://tornull.org/) and [Tor reduced policy](https://tornull.org/tor-reduced-reduced-exit-policy.php), which are two established safeguards. +* To decentralise and enable privacy for a broader range of services, this initiative will have to transition from the current ‘allow’ list to a ‘deny’ list - [exit policy](https://nymtech.net/.wellknown/network-requester/exit-policy.txt). In accordance with the [Tor Null 'deny' list](https://tornull.org/) and [Tor reduced policy](https://tornull.org/tor-reduced-reduced-exit-policy.php), which are two established safeguards. * This will enhance the usage and appeal of Nym products for end users. As a result, increased usage will ultimately lead to higher revenues for Nym operators. @@ -40,7 +40,7 @@ Nym core team cannot provide comprehensive legal advice across all jurisdictions To offer a better and more private everyday experience for its users, Nym would like them to use any online services they please, without limiting its access to a few messaging apps or crypto wallets. -To achieve this, operators running Exit Gateways would have to “open” their nodes to a wider range of online services, in a similar fashion to Tor exit relays following this [Exit policy](https://nymtech.net/.wellknown/network-requester/exit-policy.txt). +To achieve this, operators running Exit Gateways would have to “open” their nodes to a wider range of online services, in a similar fashion to Tor exit relays following this [exit policy](https://nymtech.net/.wellknown/network-requester/exit-policy.txt). ## Pros and cons of the initiative @@ -70,7 +70,7 @@ In our previous technical setup, network requesters acted as a proxy, and only m This restricts the hosts that the NymConnect app can connect to and has the effect of selectively supporting messaging services (e.g. Telegram, Matrix) or crypto wallets (e.g. Electrum or Monero). Operators of network requesters can have confidence that the infrastructure they run only connects to a limited set of public internet hosts. -The principal change in the new configuration is to make this short allow list more permissive. Nym's [Exit policy](https://nymtech.net/.wellknown/network-requester/exit-policy.txt) will restrict the hosts to which Nym Mixnet and Nym VPN users are permitted to connect. This will be done in an effort to protect the operators, as Gateways will act both as SOCKS5 Network Requesters, and exit nodes for IP traffic from Nym Mixnet VPN and VPN clients (both wrapped in the same app). +The principal change in the new configuration is to make this short allow list more permissive. Nym's [exit policy](https://nymtech.net/.wellknown/network-requester/exit-policy.txt) will restrict the hosts to which Nym Mixnet and Nym VPN users are permitted to connect. This will be done in an effort to protect the operators, as Gateways will act both as SOCKS5 Network Requesters, and exit nodes for IP traffic from Nym Mixnet VPN and VPN clients (both wrapped in the same app). As of now we the Gateways will be defaulted to a combination of [Tor Null ‘deny’ list](https://tornull.org/) (note: Not affiliated with Tor) - reproduction permitted under Creative Commons Attribution 3.0 United States License which is IP-based, e.g., `ExitPolicy reject 5.188.10.0/23:*` and [Tor reduced policy](https://tornull.org/tor-reduced-reduced-exit-policy.php). Whether we will stick with this list, do modifications or compile another one is still a subject of discussion. In all cases, this policy will remain the same for all the nodes, without any option to modify it by Nym node operators to secure stable and reliable service for the end users. From 7ffe4dd1d8e537c9de8e65192d2ef769eb813503 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Thu, 9 Nov 2023 18:12:23 +0100 Subject: [PATCH 35/80] unify naming convention gateway to Gateway --- documentation/operators/src/faq/smoosh-faq.md | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/documentation/operators/src/faq/smoosh-faq.md b/documentation/operators/src/faq/smoosh-faq.md index 5c8705eb60..90648437ac 100644 --- a/documentation/operators/src/faq/smoosh-faq.md +++ b/documentation/operators/src/faq/smoosh-faq.md @@ -14,7 +14,7 @@ If any questions are not answered or it's not clear for you in which stage proje As we shared in our blog post article [*What does it take to build the wolds most powerful VPN*](https://blog.nymtech.net/what-does-it-take-to-build-the-worlds-most-powerful-vpn-d351a76ec4e6), project Smoosh is: -> A nick-name by CTO Dave Hrycyszyn and Chief Scientist Claudia Diaz for the work they are currently doing to “smoosh” Nym nodes so that the same operator can serve alternately as mix node, gateway or VPN node. This requires careful calibration of the Nym token economics, for example, only nodes with the highest reputation for good quality service will be in the VPN set and have the chance to earn higher rewards. +> A nick-name by CTO Dave Hrycyszyn and Chief Scientist Claudia Diaz for the work they are currently doing to “smoosh” Nym nodes so that the same operator can serve alternately as mix node, Gateway or VPN node. This requires careful calibration of the Nym token economics, for example, only nodes with the highest reputation for good quality service will be in the VPN set and have the chance to earn higher rewards. > By simplifying the components, adding VPN features and supporting new node operators, the aim is to widen the geographical coverage of nodes and have significant redundancy, meaning plenty of operators to be able to meet demand. This requires strong token economic incentives as well as training and support for new node operators. ## Technical Questions @@ -23,9 +23,9 @@ As we shared in our blog post article [*What does it take to build the wolds mos Project smoosh will have three steps: -1. Combine the `gateway` and `network-requester` into one binary ✅ -2. Create [Exit Gateway](../legal/exit-gateway.md): Take the gateway binary including network requester combined in \#1 and switch from [`allowed.list`](https://nymtech.net/.wellknown/network-requester/standard-allowed-list.txt) to a new [exit policy](https://nymtech.net/.wellknown/network-requester/exit-policy.txt) ✅ -3. Combine all the nodes in the Nym Mixnet into one binary, that is `mixnode`, `gateway` (entry and exit) and `network-requester`. +1. Combine the `nym-gateway` and `nym-network-requester` into one binary ✅ +2. Create [Exit Gateway](../legal/exit-gateway.md): Take the `nym-gateway` binary including `nym-network-requester` combined in \#1 and switch from [`allowed.list`](https://nymtech.net/.wellknown/network-requester/standard-allowed-list.txt) to a new [exit policy](https://nymtech.net/.wellknown/network-requester/exit-policy.txt) ✅ +3. Combine all the nodes in the Nym Mixnet into one binary, that is `nym-mixnode`, `nym-gateway` (entry and exit) and `nym-network-requester`. These three steps will be staggered over time - period of several months, and will be implemented one by one with enough time to take in feedback and fix bugs in between. Generally, the software will be the same, just instead of multiple binaries, there will be one Nym Mixnet node binary. Delegations will remain on as they are now, per our token economics (staking, saturation etc) @@ -34,13 +34,13 @@ Generally, the software will be the same, just instead of multiple binaries, the We are exploring two potential methods for implementing binary functionality in practice and will provide information in advance. The options are: -1. Make a selection button (command/argument/flag) for operators to choose whether they want their node to provide all or just some of the functions nodes have in the Nym Mixnet. Nodes functioning as exit gateways (in that epoch) will then have bigger rewards due to their larger risk exposure and overhead work with the setup. +1. Make a selection button (command/argument/flag) for operators to choose whether they want their node to provide all or just some of the functions nodes have in the Nym Mixnet. Nodes functioning as Exit Gateways (in that epoch) will then have bigger rewards due to their larger risk exposure and overhead work with the setup. -2. All nodes will be required to have the exit gateway functionality. All nodes are rewarded the same as now, and the difference is that a node sometimes (some epochs) may be performing as exit gateway sometimes as mix node or entry gateway adjusted according the network demand by an algorithm. +2. All nodes will be required to have the Exit Gateway functionality. All nodes are rewarded the same as now, and the difference is that a node sometimes (some epochs) may be performing as Exit Gateway sometimes as mix node or Entry Gateway adjusted according the network demand by an algorithm. -### Where can I read more about the exit gateway setup? +### Where can I read more about the exit Gateway setup? -We created an [entire page](../legal/exit-gateway.md) about the technical and legal questions around exit gateway. +We created an [entire page](../legal/exit-gateway.md) about the technical and legal questions around Exit Gateway. ### What is the change from allow list to deny list? @@ -78,9 +78,9 @@ The token economics will stay the same as they are, same goes for the reward alg This depends on [design](./smoosh-faq.md#what-does-it-mean-for-nym-nodes-operators) chosen. In case of \#1, it will look like this: -As each operator can choose what roles their nodes provide, the nodes which work as open gateways will have higher rewards because they are the most important to keep up and stable. Besides that the operators of gateways may be exposed to more complication and possible legal risks. +As each operator can choose what roles their nodes provide, the nodes which work as open Gateways will have higher rewards because they are the most important to keep up and stable. Besides that the operators of Gateways may be exposed to more complication and possible legal risks. -The nodes which are initialized to run as mix nodes and gateways will be chosen to be on top of the active set before the ones working only as a mix node. +The nodes which are initialized to run as mix nodes and Gateways will be chosen to be on top of the active set before the ones working only as a mix node. I case we go with \#2, all nodes active in the epoch will be rewarded proportionally according their work. @@ -88,21 +88,21 @@ In either way, Nym will share all the specifics beforehand. ### How will be the staking and inflation after project Smoosh? -Nym will run tests to count how much payment comes from the users of the Mixnet and if that covers the reward payments. If not, we may need to keep inflation on to secure incentives for high quality gateways in the early stage of the transition. +Nym will run tests to count how much payment comes from the users of the Mixnet and if that covers the reward payments. If not, we may need to keep inflation on to secure incentives for high quality Gateways in the early stage of the transition. -### When project smooth will be launched, it would be the mixmining pool that will pay for the gateway rewards based on amount of traffic routed ? +### When project smooth will be launched, it would be the mixmining pool that will pay for the Gateway rewards based on amount of traffic routed ? -Yes, the same pool. Nym's aim is to do minimal modifications. The only real modification on the smart contract side will be to get into top X of 'active set' operators will need to have open gateway function enabled. +Yes, the same pool. Nym's aim is to do minimal modifications. The only real modification on the smart contract side will be to get into top X of 'active set' operators will need to have open Gateway function enabled. ### What does this mean for the current delegators? -From an operator standpoint, it shall just be a standard Nym upgrade, a new option to run the gateway software on your node. Delegators should not have to re-delegate. +From an operator standpoint, it shall just be a standard Nym upgrade, a new option to run the Gateway software on your node. Delegators should not have to re-delegate. ## Legal Questions ### Are there any legal concerns for the operators? -So far the general line is that running a gateway is not illegal (unless you are in Iran, China, and a few other places) and due to encryption/mixing less risky than running a normal VPN node. For mix nodes, it's very safe as they have "no idea" what packets they are mixing. +So far the general line is that running a Gateway is not illegal (unless you are in Iran, China, and a few other places) and due to encryption/mixing less risky than running a normal VPN node. For mix nodes, it's very safe as they have "no idea" what packets they are mixing. There are several legal questions and analysis to be made for different jurisdictions. To be able to share resources and findings between the operators themselves we created a [Community Legal Forum](../legal/exit-gateway.md). From 5395eebaefc32db1da2b68cc472f4bca5e8790f1 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Thu, 9 Nov 2023 18:13:18 +0100 Subject: [PATCH 36/80] unify naming convention mixnode to Mix node --- documentation/operators/src/faq/smoosh-faq.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/documentation/operators/src/faq/smoosh-faq.md b/documentation/operators/src/faq/smoosh-faq.md index 90648437ac..68e06ed3d1 100644 --- a/documentation/operators/src/faq/smoosh-faq.md +++ b/documentation/operators/src/faq/smoosh-faq.md @@ -14,7 +14,7 @@ If any questions are not answered or it's not clear for you in which stage proje As we shared in our blog post article [*What does it take to build the wolds most powerful VPN*](https://blog.nymtech.net/what-does-it-take-to-build-the-worlds-most-powerful-vpn-d351a76ec4e6), project Smoosh is: -> A nick-name by CTO Dave Hrycyszyn and Chief Scientist Claudia Diaz for the work they are currently doing to “smoosh” Nym nodes so that the same operator can serve alternately as mix node, Gateway or VPN node. This requires careful calibration of the Nym token economics, for example, only nodes with the highest reputation for good quality service will be in the VPN set and have the chance to earn higher rewards. +> A nick-name by CTO Dave Hrycyszyn and Chief Scientist Claudia Diaz for the work they are currently doing to “smoosh” Nym nodes so that the same operator can serve alternately as Mix node, Gateway or VPN node. This requires careful calibration of the Nym token economics, for example, only nodes with the highest reputation for good quality service will be in the VPN set and have the chance to earn higher rewards. > By simplifying the components, adding VPN features and supporting new node operators, the aim is to widen the geographical coverage of nodes and have significant redundancy, meaning plenty of operators to be able to meet demand. This requires strong token economic incentives as well as training and support for new node operators. ## Technical Questions @@ -36,7 +36,7 @@ We are exploring two potential methods for implementing binary functionality in 1. Make a selection button (command/argument/flag) for operators to choose whether they want their node to provide all or just some of the functions nodes have in the Nym Mixnet. Nodes functioning as Exit Gateways (in that epoch) will then have bigger rewards due to their larger risk exposure and overhead work with the setup. -2. All nodes will be required to have the Exit Gateway functionality. All nodes are rewarded the same as now, and the difference is that a node sometimes (some epochs) may be performing as Exit Gateway sometimes as mix node or Entry Gateway adjusted according the network demand by an algorithm. +2. All nodes will be required to have the Exit Gateway functionality. All nodes are rewarded the same as now, and the difference is that a node sometimes (some epochs) may be performing as Exit Gateway sometimes as Mix node or Entry Gateway adjusted according the network demand by an algorithm. ### Where can I read more about the exit Gateway setup? @@ -56,7 +56,7 @@ The progression of exit policy on Gateways will have three steps: Keep in mind this only relates to changes happening on Gateway and Network Requester side. Whether this will be optional or mandatory depends on the chosen [design](./smoosh-faq.md#what-does-it-mean-for-nym-nodes-operators). -### Can I run a mix node only? +### Can I run a Mix node only? It depends which [design](./smoosh-faq.md#what-does-it-mean-for-nym-nodes-operators) will ultimately be used. In case of the first - yes. In case of the second option, all the nodes will be setup with Exit Gateway functionality turned on. @@ -80,7 +80,7 @@ This depends on [design](./smoosh-faq.md#what-does-it-mean-for-nym-nodes-operato As each operator can choose what roles their nodes provide, the nodes which work as open Gateways will have higher rewards because they are the most important to keep up and stable. Besides that the operators of Gateways may be exposed to more complication and possible legal risks. -The nodes which are initialized to run as mix nodes and Gateways will be chosen to be on top of the active set before the ones working only as a mix node. +The nodes which are initialized to run as Mix nodes and Gateways will be chosen to be on top of the active set before the ones working only as a Mix node. I case we go with \#2, all nodes active in the epoch will be rewarded proportionally according their work. @@ -102,7 +102,7 @@ From an operator standpoint, it shall just be a standard Nym upgrade, a new opti ### Are there any legal concerns for the operators? -So far the general line is that running a Gateway is not illegal (unless you are in Iran, China, and a few other places) and due to encryption/mixing less risky than running a normal VPN node. For mix nodes, it's very safe as they have "no idea" what packets they are mixing. +So far the general line is that running a Gateway is not illegal (unless you are in Iran, China, and a few other places) and due to encryption/mixing less risky than running a normal VPN node. For Mix nodes, it's very safe as they have "no idea" what packets they are mixing. There are several legal questions and analysis to be made for different jurisdictions. To be able to share resources and findings between the operators themselves we created a [Community Legal Forum](../legal/exit-gateway.md). From f623a9967c3fa3ec7ef69397e7b362062c286abe Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Thu, 9 Nov 2023 18:13:54 +0100 Subject: [PATCH 37/80] unify naming convention network requester to Network requester --- documentation/operators/src/faq/smoosh-faq.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/operators/src/faq/smoosh-faq.md b/documentation/operators/src/faq/smoosh-faq.md index 68e06ed3d1..1d072249d5 100644 --- a/documentation/operators/src/faq/smoosh-faq.md +++ b/documentation/operators/src/faq/smoosh-faq.md @@ -68,7 +68,7 @@ For any specifics on Nym token economics and Nym Mixnet reward system, please re ### 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 `nym-network-requester` binary. 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? From 11e01335c2afcdc0de691c703abc805a942dbc31 Mon Sep 17 00:00:00 2001 From: Zane Schepke Date: Sun, 12 Nov 2023 13:48:07 -0500 Subject: [PATCH 38/80] Update tauri.conf.json --- nym-vpn/ui/src-tauri/tauri.conf.json | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/nym-vpn/ui/src-tauri/tauri.conf.json b/nym-vpn/ui/src-tauri/tauri.conf.json index d3983c24e4..a1983b2f27 100644 --- a/nym-vpn/ui/src-tauri/tauri.conf.json +++ b/nym-vpn/ui/src-tauri/tauri.conf.json @@ -11,6 +11,14 @@ "version": "0.0.0" }, "tauri": { + "updater": { + "active": true, + "endpoints": [ + "https://releases.myapp.com/{{target}}/{{arch}}/{{current_version}}" + ], + "dialog": true, + "pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IDUxMjFCMDhFOTczQzE5MjUKUldRbEdUeVhqckFoVVljRDZNZkRQZzIyYTBSZUVmSk1SVUlaTC9OeTk0NDFYUVl1blhWV2VTQi8K" + }, "allowlist": { "all": false, "shell": { From 58e0330f4f9d61630c48f031f659686f0b9652bc Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Mon, 13 Nov 2023 11:29:16 +0100 Subject: [PATCH 39/80] mix node to Mix Node --- .../operators/src/faq/mixnodes-faq.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/documentation/operators/src/faq/mixnodes-faq.md b/documentation/operators/src/faq/mixnodes-faq.md index 38c62154b5..7b67c2d859 100644 --- a/documentation/operators/src/faq/mixnodes-faq.md +++ b/documentation/operators/src/faq/mixnodes-faq.md @@ -1,20 +1,20 @@ # Frequently Asked Questions -## Mixnet nodes +## Nym Nodes -### What determines the rewards when running a mix node? +### What determines the rewards when running a Mix Node? -The stake required for a mix node to achieve maximum rewards is called mix node saturation point. This is calculated from the staking supply (all circulating supply + part of unlocked tokens). The target level of staking is to have 50% of the staking supply locked in mix nodes. +The stake required for a Mix Node to achieve maximum rewards is called Mix Node saturation point. This is calculated from the staking supply (all circulating supply + part of unlocked tokens). The target level of staking is to have 50% of the staking supply locked in Mix Nodes. The node stake saturation point, which we denote by Nsat, is given by the stake supply, target level of staking divided by the number of rewarded (active) nodes. -This design ensures the nodes aim to have a same size of stake (reputation) which can be done by delegation staking, as well as it ensures that there is a decentralization of staking as any higher level of staked tokens per node results in worse rewards. On the contrary, the more mix nodes are active, the lower is Nsat. The equilibrium is reached when the staked tokens are delegated equally across the active mix-nodes and that's our basis for this incentive system. +This design ensures the nodes aim to have a same size of stake (reputation) which can be done by delegation staking, as well as it ensures that there is a decentralization of staking as any higher level of staked tokens per node results in worse rewards. On the contrary, the more Mix Nodes are active, the lower is Nsat. The equilibrium is reached when the staked tokens are delegated equally across the active mix-nodes and that's our basis for this incentive system. -For more detailed calculation, read our blog post [Nym Token Economics update](https://blog.nymtech.net/nym-token-economics-update-fedff0ed5267). More info on staking can be found [here](https://blog.nymtech.net/staking-in-nym-introducing-mainnet-mixmining-f9bb1cbc7c36). And [here](https://blog.nymtech.net/want-to-stake-in-nym-here-is-how-to-choose-a-mix-node-to-delegate-nym-to-c3b862add165) is more info on how to choose a mix node for delegation. And finally an [update](https://blog.nymtech.net/quarterly-token-economic-parameter-update-b2862948710f) on token economics from July 2023. +For more detailed calculation, read our blog post [Nym Token Economics update](https://blog.nymtech.net/nym-token-economics-update-fedff0ed5267). More info on staking can be found [here](https://blog.nymtech.net/staking-in-nym-introducing-mainnet-mixmining-f9bb1cbc7c36). And [here](https://blog.nymtech.net/want-to-stake-in-nym-here-is-how-to-choose-a-mix-node-to-delegate-nym-to-c3b862add165) is more info on how to choose a Mix Node for delegation. And finally an [update](https://blog.nymtech.net/quarterly-token-economic-parameter-update-b2862948710f) on token economics from July 2023. ### Which VPS providers would you recommend? -Consider in which jurisdiction you reside and where do you want to run a mix node. Do you want to pay by crypto or not and what are the other important particularities for your case? We always recommend operators to try to choose smaller and decentralised VPS providers over the most known ones controlling a majority of the internet. We receive some good feedback on these: Linode, Ghandi, Flokinet and Exoscale. Do your own research and share with the community. +Consider in which jurisdiction you reside and where do you want to run a Mix Node. Do you want to pay by crypto or not and what are the other important particularities for your case? We always recommend operators to try to choose smaller and decentralised VPS providers over the most known ones controlling a majority of the internet. We receive some good feedback on these: Linode, Ghandi, Flokinet and Exoscale. Do your own research and share with the community. @@ -22,17 +22,17 @@ Consider in which jurisdiction you reside and where do you want to run a mix nod The sizes are shown in the configs [here](https://github.com/nymtech/nym/blob/1ba6444e722e7757f1175a296bed6e31e25b8db8/common/nymsphinx/params/src/packet_sizes.rs#L12) (default is the one clients use, the others are for research purposes, not to be used in production as this would fragment the anonymity set). More info can be found [here](https://github.com/nymtech/nym/blob/4844ac953a12b29fa27688609ec193f1d560c996/common/nymsphinx/anonymous-replies/src/reply_surb.rs#L80). -### Why a mix node and a gateway cannot be bond to the same wallet? +### Why a Mix Node and a gateway cannot be bond to the same wallet? Because of the way the smart contract works we keep it one-node one-address at the moment. ### Which nodes are the most needed to be setup to strengthen Nym infrastructure and which ones bring rewards? -Right now only mix nodes are rewarded. We're working on gateway and service payments. Gateways are the weak link right now due mostly to lack of incentivisation. Services like Network Requesters are obviously the most necessary for people to start using the platform, and we're working on smart contracts to allow for people to start advertising them the same way they do mix nodes. +Right now only Mix Nodes are rewarded. We're working on gateway and service payments. Gateways are the weak link right now due mostly to lack of incentivisation. Services like Network Requesters are obviously the most necessary for people to start using the platform, and we're working on smart contracts to allow for people to start advertising them the same way they do Mix Nodes. ### Are mixnodes whitelisted? -Nope, anyone can run a mix node. Purely reliant on the node's reputation (self stake + delegations) & routing score. +Nope, anyone can run a Mix Node. Purely reliant on the node's reputation (self stake + delegations) & routing score. ## Validators and tokens From 83eb0cbf54ecb7630f2a41381c06c247d3fedb87 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Mon, 13 Nov 2023 11:29:35 +0100 Subject: [PATCH 40/80] mix node to Mix Node --- documentation/operators/src/faq/mixnodes-faq.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/operators/src/faq/mixnodes-faq.md b/documentation/operators/src/faq/mixnodes-faq.md index 7b67c2d859..62659806dc 100644 --- a/documentation/operators/src/faq/mixnodes-faq.md +++ b/documentation/operators/src/faq/mixnodes-faq.md @@ -30,7 +30,7 @@ Because of the way the smart contract works we keep it one-node one-address at t Right now only Mix Nodes are rewarded. We're working on gateway and service payments. Gateways are the weak link right now due mostly to lack of incentivisation. Services like Network Requesters are obviously the most necessary for people to start using the platform, and we're working on smart contracts to allow for people to start advertising them the same way they do Mix Nodes. -### Are mixnodes whitelisted? +### Are Mix Nodes whitelisted? Nope, anyone can run a Mix Node. Purely reliant on the node's reputation (self stake + delegations) & routing score. From 532fea38d5f65723a3909b3dd465eb52c8f9d1c0 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Mon, 13 Nov 2023 11:30:22 +0100 Subject: [PATCH 41/80] edit gateway to Gateway --- documentation/operators/src/faq/mixnodes-faq.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/documentation/operators/src/faq/mixnodes-faq.md b/documentation/operators/src/faq/mixnodes-faq.md index 62659806dc..bd1b3fa413 100644 --- a/documentation/operators/src/faq/mixnodes-faq.md +++ b/documentation/operators/src/faq/mixnodes-faq.md @@ -22,13 +22,13 @@ Consider in which jurisdiction you reside and where do you want to run a Mix Nod The sizes are shown in the configs [here](https://github.com/nymtech/nym/blob/1ba6444e722e7757f1175a296bed6e31e25b8db8/common/nymsphinx/params/src/packet_sizes.rs#L12) (default is the one clients use, the others are for research purposes, not to be used in production as this would fragment the anonymity set). More info can be found [here](https://github.com/nymtech/nym/blob/4844ac953a12b29fa27688609ec193f1d560c996/common/nymsphinx/anonymous-replies/src/reply_surb.rs#L80). -### Why a Mix Node and a gateway cannot be bond to the same wallet? +### Why a Mix Node and a Gateway cannot be bond to the same wallet? Because of the way the smart contract works we keep it one-node one-address at the moment. ### Which nodes are the most needed to be setup to strengthen Nym infrastructure and which ones bring rewards? -Right now only Mix Nodes are rewarded. We're working on gateway and service payments. Gateways are the weak link right now due mostly to lack of incentivisation. Services like Network Requesters are obviously the most necessary for people to start using the platform, and we're working on smart contracts to allow for people to start advertising them the same way they do Mix Nodes. +Right now only Mix Nodes are rewarded. We're working on Gateway and service payments. Gateways are the weak link right now due mostly to lack of incentivisation. Services like Network Requesters are obviously the most necessary for people to start using the platform, and we're working on smart contracts to allow for people to start advertising them the same way they do Mix Nodes. ### Are Mix Nodes whitelisted? From f0864adfe6e09dfb74c689564591436d4aa64a20 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Mon, 13 Nov 2023 11:31:18 +0100 Subject: [PATCH 42/80] mix node to Mix Node --- documentation/operators/src/faq/smoosh-faq.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/documentation/operators/src/faq/smoosh-faq.md b/documentation/operators/src/faq/smoosh-faq.md index 1d072249d5..18a5bfe268 100644 --- a/documentation/operators/src/faq/smoosh-faq.md +++ b/documentation/operators/src/faq/smoosh-faq.md @@ -56,7 +56,7 @@ The progression of exit policy on Gateways will have three steps: Keep in mind this only relates to changes happening on Gateway and Network Requester side. Whether this will be optional or mandatory depends on the chosen [design](./smoosh-faq.md#what-does-it-mean-for-nym-nodes-operators). -### Can I run a Mix node only? +### Can I run a Mix Node only? It depends which [design](./smoosh-faq.md#what-does-it-mean-for-nym-nodes-operators) will ultimately be used. In case of the first - yes. In case of the second option, all the nodes will be setup with Exit Gateway functionality turned on. @@ -80,7 +80,7 @@ This depends on [design](./smoosh-faq.md#what-does-it-mean-for-nym-nodes-operato As each operator can choose what roles their nodes provide, the nodes which work as open Gateways will have higher rewards because they are the most important to keep up and stable. Besides that the operators of Gateways may be exposed to more complication and possible legal risks. -The nodes which are initialized to run as Mix nodes and Gateways will be chosen to be on top of the active set before the ones working only as a Mix node. +The nodes which are initialized to run as Mix Nodes and Gateways will be chosen to be on top of the active set before the ones working only as a Mix Node. I case we go with \#2, all nodes active in the epoch will be rewarded proportionally according their work. @@ -102,7 +102,7 @@ From an operator standpoint, it shall just be a standard Nym upgrade, a new opti ### Are there any legal concerns for the operators? -So far the general line is that running a Gateway is not illegal (unless you are in Iran, China, and a few other places) and due to encryption/mixing less risky than running a normal VPN node. For Mix nodes, it's very safe as they have "no idea" what packets they are mixing. +So far the general line is that running a Gateway is not illegal (unless you are in Iran, China, and a few other places) and due to encryption/mixing less risky than running a normal VPN node. For Mix Nodes, it's very safe as they have "no idea" what packets they are mixing. There are several legal questions and analysis to be made for different jurisdictions. To be able to share resources and findings between the operators themselves we created a [Community Legal Forum](../legal/exit-gateway.md). From 9f5c225cf97c8ea40ae923af6683613cbe984965 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Mon, 13 Nov 2023 11:32:16 +0100 Subject: [PATCH 43/80] edit Network requester to Network Requester --- documentation/operators/src/faq/smoosh-faq.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/operators/src/faq/smoosh-faq.md b/documentation/operators/src/faq/smoosh-faq.md index 18a5bfe268..5d131f4320 100644 --- a/documentation/operators/src/faq/smoosh-faq.md +++ b/documentation/operators/src/faq/smoosh-faq.md @@ -50,7 +50,7 @@ The operators running Gateways would have to “open” their nodes to a wider r The progression of exit policy on Gateways will have three steps: -1. By default the [exit policy](https://nymtech.net/.wellknown/network-requester/exit-policy.txt) filtering will be disabled and the current [`allowed.list`](https://nymtech.net/.wellknown/network-requester/standard-allowed-list.txt) filtering is going to continue be used. This is to prevent operators getting surprised by upgrading their Gateways (or Network requesters) and suddenly be widely open to the internet. To enable the new exit policy, operators must use `--with-exit-policy` flag or modify the `config.toml` file. ✅ +1. By default the [exit policy](https://nymtech.net/.wellknown/network-requester/exit-policy.txt) filtering will be disabled and the current [`allowed.list`](https://nymtech.net/.wellknown/network-requester/standard-allowed-list.txt) filtering is going to continue be used. This is to prevent operators getting surprised by upgrading their Gateways (or Network Requesters) and suddenly be widely open to the internet. To enable the new exit policy, operators must use `--with-exit-policy` flag or modify the `config.toml` file. ✅ 2. Relatively soon the exit policy will be part of the Gateway setup by default. To disable this exit policy, operators must use `--disable-exit-policy` flag. 3. Further down the line, it will be the only option. Then the `allowed.list` will be completely removed. From b5bb3f36bffd87211636a6d2710668750ce5e479 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Mon, 13 Nov 2023 11:46:08 +0100 Subject: [PATCH 44/80] add steps prior to bond --- documentation/operators/src/nodes/mix-node-setup.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/documentation/operators/src/nodes/mix-node-setup.md b/documentation/operators/src/nodes/mix-node-setup.md index 15a5a21ef0..ee8c946701 100644 --- a/documentation/operators/src/nodes/mix-node-setup.md +++ b/documentation/operators/src/nodes/mix-node-setup.md @@ -108,6 +108,13 @@ During the `init` process you will have the option to change the `http_api`, `ve From `v1.1.3`, if you unbond your mix node that means you are leaving the mixnet and you will lose all your delegations (permanently). You can join again with the same identity key, however, you will start with **no delegations**. ``` +To initialise, run and bond your Mix Node are the minimum steps to do in order for your Mix Node to work. However we recommend to do a few more steps before bonding. These steps will make it easier for you as a node operator on a long run as well as for others to possibly delegate Nym tokens to your Mix Node. These steps are: + +- [Describe your Mix Node](./mix-node-setup.md#node-description-optional) +- [Configure your firewall](./maintenance.md#configure-your-firewall) +- [Automate your Mix Node](./maintenance.md#vps-setup-and-automation) +- Set the [ulimit](./maintenance.md#set-the-ulimit-via-systemd-service-file) In case you haven't automated with [systemd](./maintenance.md#set-the-ulimit-on-non-systemd-based-distributions) + #### Bond via the Desktop wallet (recommended) You can bond your mix node via the Desktop wallet. @@ -116,7 +123,7 @@ You can bond your mix node via the Desktop wallet. * Enter the `Amount`, `Operating cost` and `Profit margin` and press `Next`. -* You will be asked to run a the `sign` command with your `gateway` - copy and paste the long signature as the value of `--contract-msg` and run it. +* You will be asked to run a the `sign` command with your `mixnode` - copy and paste the long signature as the value of `--contract-msg` and run it. ``` ./nym-mixnode sign --id --contract-msg From aa65b96ef27bfd15acac1bb739f8ac344455ac15 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Mon, 13 Nov 2023 11:52:18 +0100 Subject: [PATCH 45/80] reorder Mix Node setup steps --- .../operators/src/nodes/mix-node-setup.md | 69 ++++++++++--------- 1 file changed, 35 insertions(+), 34 deletions(-) diff --git a/documentation/operators/src/nodes/mix-node-setup.md b/documentation/operators/src/nodes/mix-node-setup.md index ee8c946701..e98cfee6b2 100644 --- a/documentation/operators/src/nodes/mix-node-setup.md +++ b/documentation/operators/src/nodes/mix-node-setup.md @@ -102,7 +102,37 @@ Mix Port: 1789, Verloc port: 1790, Http Port: 8000 During the `init` process you will have the option to change the `http_api`, `verloc` and `mixnode` ports from their default settings. If you wish to change these in the future you can edit their values in the `config.toml` file created by the initialization process, which is located at `~/.nym/mixnodes//`. -### Bonding your mix node +## Node Description (optional) + +In order to easily identify your node via human-readable information later on, you can `describe` your mix node with the following command: + +``` +./nym-mixnode describe --id +``` +Node description is a short text that describes your node. It is displayed in the `./nym-mixnode list` command and in the `./nym-mixnode node-details --id ` command. It also shows up in the node explorer to let people know what your node is about and link to your website. + +You can set your node description, by creating a file called `description.toml` and put it in the same directory as your `config.toml` file (`~/.nym/mixnodes//description.toml`). The file should look like this example: + +```toml +name = "Winston Smith" +description = "I am the Sphinx" +link = "https://nymtech.net" +location = "Giza, Egypt" +``` + +> Remember to restart your `nym-mix-node` process in order for the new description to be propagated. + +## Running your mix node + +Run your Mix Node with: + +``` +./nym-mixnode run --id +``` + +Have a look at the saved configuration files in `$HOME/.nym/mixnodes/` to see more configuration options. + +## Bonding your mix node ```admonish caution From `v1.1.3`, if you unbond your mix node that means you are leaving the mixnet and you will lose all your delegations (permanently). You can join again with the same identity key, however, you will start with **no delegations**. @@ -115,7 +145,7 @@ To initialise, run and bond your Mix Node are the minimum steps to do in order f - [Automate your Mix Node](./maintenance.md#vps-setup-and-automation) - Set the [ulimit](./maintenance.md#set-the-ulimit-via-systemd-service-file) In case you haven't automated with [systemd](./maintenance.md#set-the-ulimit-on-non-systemd-based-distributions) -#### Bond via the Desktop wallet (recommended) +### Bond via the Desktop wallet (recommended) You can bond your mix node via the Desktop wallet. @@ -163,44 +193,15 @@ It will look something like this: * Your node will now be bonded and ready to mix at the beginning of the next epoch (at most 1 hour). -> You are asked to `sign` a transaction on bonding so that the mixnet smart contract is able to map your nym address to your node. This allows us to create a nonce for each account and defend against replay attacks. - -#### Bond via the CLI (power users) -If you want to bond your mix node via the CLI, then check out the [relevant section in the Nym CLI](https://nymtech.net/docs/tools/nym-cli.html#bond-a-mix-node) docs. - -### Running your mix node - -Now you've bonded your mix node, run it with: - -``` -./nym-mixnode run --id -``` +> You are asked to `sign` a transaction on bonding so that the Mixnet smart contract is able to map your nym address to your node. This allows us to create a nonce for each account and defend against replay attacks. If everything worked, you'll see your node running on the either the [Sandbox testnet network explorer](https://sandbox-explorer.nymtech.net) or the [mainnet network explorer](https://explorer.nymtech.net), depending on which network you're running. Note that your node's public identity key is displayed during startup, you can use it to identify your node in the list. -Have a look at the saved configuration files in `$HOME/.nym/mixnodes/` to see more configuration options. +### Bond via the CLI (power users) +If you want to bond your mix node via the CLI, then check out the [relevant section in the Nym CLI](https://nymtech.net/docs/tools/nym-cli.html#bond-a-mix-node) docs. -## Node Description (optional) - -In order to easily identify your node via human-readable information later on in the development of the testnet when delegated staking is implemented, you can `describe` your mix node with the following command: - -``` -./nym-mixnode describe --id -``` -Node description is a short text that describes your node. It is displayed in the `./nym-mixnode list` command and in the `./nym-mixnode node-details --id ` command. It also shows up in the node explorer to let people know what your node is about and link to your website. - -You can set your node description, by creating a file called `description.toml` and put it in the same directory as your `config.toml` file (`~/.nym/mixnodes//description.toml`). The file should look like this example: - -```toml -name = "Winston Smith" -description = "I am the Sphinx" -link = "https://nymtech.net" -location = "Giza, Egypt" -``` - -> Remember to restart your mix node process in order for the new description to be propagated. ## Node Families From 2934d24e5398852b7dcb470ea511e021f95ff1ac Mon Sep 17 00:00:00 2001 From: Pierre Dommerc Date: Mon, 13 Nov 2023 12:33:58 +0100 Subject: [PATCH 46/80] feat(vpn-ui): scaffold rust backend (#4073) * scaffold app * feat: local storage for app data & config --- nym-vpn/ui/README.md | 35 ++++++++ nym-vpn/ui/package.json | 2 +- nym-vpn/ui/src-tauri/.gitignore | 3 +- nym-vpn/ui/src-tauri/Cargo.lock | 78 ++++++++++++++--- nym-vpn/ui/src-tauri/Cargo.toml | 11 ++- .../ui/src-tauri/src/commands/connection.rs | 61 ++++++++++++++ nym-vpn/ui/src-tauri/src/commands/mod.rs | 11 +++ nym-vpn/ui/src-tauri/src/commands/settings.rs | 32 +++++++ nym-vpn/ui/src-tauri/src/error.rs | 12 +++ nym-vpn/ui/src-tauri/src/fs/cache.rs | 6 ++ nym-vpn/ui/src-tauri/src/fs/config.rs | 6 ++ nym-vpn/ui/src-tauri/src/fs/data.rs | 13 +++ nym-vpn/ui/src-tauri/src/fs/log.rs | 6 ++ nym-vpn/ui/src-tauri/src/fs/mod.rs | 4 + nym-vpn/ui/src-tauri/src/fs/storage.rs | 84 +++++++++++++++++++ nym-vpn/ui/src-tauri/src/main.rs | 63 ++++++++++++-- nym-vpn/ui/src-tauri/src/states/app.rs | 44 ++++++++++ nym-vpn/ui/src-tauri/src/states/mod.rs | 11 +++ nym-vpn/ui/src-tauri/tauri.conf.json | 6 +- 19 files changed, 463 insertions(+), 25 deletions(-) create mode 100644 nym-vpn/ui/src-tauri/src/commands/connection.rs create mode 100644 nym-vpn/ui/src-tauri/src/commands/mod.rs create mode 100644 nym-vpn/ui/src-tauri/src/commands/settings.rs create mode 100644 nym-vpn/ui/src-tauri/src/error.rs create mode 100644 nym-vpn/ui/src-tauri/src/fs/cache.rs create mode 100644 nym-vpn/ui/src-tauri/src/fs/config.rs create mode 100644 nym-vpn/ui/src-tauri/src/fs/data.rs create mode 100644 nym-vpn/ui/src-tauri/src/fs/log.rs create mode 100644 nym-vpn/ui/src-tauri/src/fs/mod.rs create mode 100644 nym-vpn/ui/src-tauri/src/fs/storage.rs create mode 100644 nym-vpn/ui/src-tauri/src/states/app.rs create mode 100644 nym-vpn/ui/src-tauri/src/states/mod.rs diff --git a/nym-vpn/ui/README.md b/nym-vpn/ui/README.md index a1fe5876a6..b4c3e351e1 100644 --- a/nym-vpn/ui/README.md +++ b/nym-vpn/ui/README.md @@ -25,6 +25,25 @@ yarn yarn dev:app ``` +or + +``` +cd src-tauri +cargo tauri dev +``` + +#### Logging + +Rust logging (standard output) is controlled by the `RUST_LOG` +env variable + +Example: + +``` +cd src-tauri +RUST_LOG=trace cargo tauri dev +``` + ## Dev in the browser For convenience and better development experience, we can run the @@ -43,6 +62,22 @@ When creating new tauri command, be sure to add the corresponding mock definition into `nym-vpn/ui/src/dev/tauri-cmd-mocks/` and update `nym-vpn/ui/src/dev/setup.ts` accordingly. +## Type bindings + +[ts-rs](https://github.com/Aleph-Alpha/ts-rs) can be used to generate +TS type definitions from Rust types + +To generate bindings, first +[annotate](https://github.com/Aleph-Alpha/ts-rs/blob/main/example/src/lib.rs) +Rust types, then run + +``` +cd src-tauri +cargo test +``` + +Generated TS types will be located in `src-tauri/bindings/` + ## Build To build as a **shared library** diff --git a/nym-vpn/ui/package.json b/nym-vpn/ui/package.json index 2570661bcc..4be6c83b4e 100644 --- a/nym-vpn/ui/package.json +++ b/nym-vpn/ui/package.json @@ -5,7 +5,7 @@ "type": "module", "scripts": { "dev": "vite", - "dev:app": "WEBKIT_DISABLE_COMPOSITING_MODE=1 tauri dev", + "dev:app": "RUST_LOG=nymvpn_ui=trace tauri dev", "dev:browser": "vite --mode dev-browser", "build": "tsc && vite build", "build:app": "yarn build && cd src-tauri && cargo build --release --lib --features custom-protocol", diff --git a/nym-vpn/ui/src-tauri/.gitignore b/nym-vpn/ui/src-tauri/.gitignore index f4dfb82b2c..a324855cc5 100644 --- a/nym-vpn/ui/src-tauri/.gitignore +++ b/nym-vpn/ui/src-tauri/.gitignore @@ -1,4 +1,3 @@ -# Generated by Cargo -# will have compiled files and executables /target/ +/bindings/ diff --git a/nym-vpn/ui/src-tauri/Cargo.lock b/nym-vpn/ui/src-tauri/Cargo.lock index 4e4061f1a5..58d65c1337 100644 --- a/nym-vpn/ui/src-tauri/Cargo.lock +++ b/nym-vpn/ui/src-tauri/Cargo.lock @@ -2,6 +2,12 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "Inflector" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" + [[package]] name = "addr2line" version = "0.21.0" @@ -294,8 +300,10 @@ checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" dependencies = [ "android-tzdata", "iana-time-zone", + "js-sys", "num-traits", "serde", + "wasm-bindgen", "windows-targets", ] @@ -570,6 +578,12 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" +[[package]] +name = "dotenvy" +version = "0.15.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" + [[package]] name = "dtoa" version = "1.0.9" @@ -599,7 +613,7 @@ checksum = "f54cc3e827ee1c3812239a9a41dede7b4d7d5d5464faa32d71bd7cba28ce2cb2" dependencies = [ "cc", "rustc_version", - "toml 0.8.2", + "toml 0.8.5", "vswhom", "winreg", ] @@ -1651,10 +1665,19 @@ dependencies = [ name = "nymvpn-ui" version = "0.0.0" dependencies = [ + "anyhow", + "dotenvy", + "once_cell", "serde", "serde_json", "tauri", "tauri-build", + "thiserror", + "tokio", + "toml 0.8.5", + "tracing", + "tracing-subscriber", + "ts-rs", ] [[package]] @@ -2323,9 +2346,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96426c9936fd7a0124915f9185ea1d20aa9445cc9821142f0a73bc9207a2e186" +checksum = "12022b835073e5b11e90a14f86838ceb1c8fb0325b72416845c487ac0fa95e80" dependencies = [ "serde", ] @@ -2557,7 +2580,7 @@ dependencies = [ "cfg-expr 0.15.5", "heck 0.4.1", "pkg-config", - "toml 0.8.2", + "toml 0.8.5", "version-compare 0.1.1", ] @@ -2847,6 +2870,15 @@ dependencies = [ "utf-8", ] +[[package]] +name = "termcolor" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6093bad37da69aab9d123a8091e4be0aa4a03e4d601ec641c327398315f62b64" +dependencies = [ + "winapi-util", +] + [[package]] name = "thin-slice" version = "0.1.1" @@ -2962,21 +2994,21 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.2" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "185d8ab0dfbb35cf1399a6344d8484209c088f75f8f68230da55d48d95d43e3d" +checksum = "3efaf127c78d5339cc547cce4e4d973bd5e4f56e949a06d091c082ebeef2f800" dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit 0.20.2", + "toml_edit 0.20.5", ] [[package]] name = "toml_datetime" -version = "0.6.3" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" +checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" dependencies = [ "serde", ] @@ -2996,9 +3028,9 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.20.2" +version = "0.20.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" +checksum = "782bf6c2ddf761c1e7855405e8975472acf76f7f36d0d4328bd3b7a2fae12a85" dependencies = [ "indexmap 2.0.2", "serde", @@ -3077,6 +3109,30 @@ dependencies = [ "serde_json", ] +[[package]] +name = "ts-rs" +version = "7.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1ff1f8c90369bc172200013ac17ae86e7b5def580687df4e6127883454ff2b0" +dependencies = [ + "chrono", + "thiserror", + "ts-rs-macros", +] + +[[package]] +name = "ts-rs-macros" +version = "7.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6f41cc0aeb7a4a55730188e147d3795a7349b501f8334697fd37629b896cdc2" +dependencies = [ + "Inflector", + "proc-macro2", + "quote", + "syn 2.0.38", + "termcolor", +] + [[package]] name = "typenum" version = "1.17.0" diff --git a/nym-vpn/ui/src-tauri/Cargo.toml b/nym-vpn/ui/src-tauri/Cargo.toml index 93b390a573..b7eab97c9f 100644 --- a/nym-vpn/ui/src-tauri/Cargo.toml +++ b/nym-vpn/ui/src-tauri/Cargo.toml @@ -14,9 +14,18 @@ crate-type = ["cdylib"] tauri-build = { version = "1.5", features = [] } [dependencies] -tauri = { version = "1.5", features = ["shell-open"] } +tauri = { version = "1.5.2", features = ["shell-open"] } +tokio = { version = "1.33", features = ["rt", "sync", "time", "fs"] } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" +tracing = "0.1" +tracing-subscriber = { version = "0.3.1", features = ["tracing-log", "env-filter"] } +anyhow = "1.0" +dotenvy = "0.15.7" +thiserror = "1.0" +ts-rs = { version = "7.0.0", features = ["chrono-impl"] } +once_cell = "1.18.0" +toml = "0.8.5" [features] # this feature is used for production builds or when `devPath` points to the filesystem diff --git a/nym-vpn/ui/src-tauri/src/commands/connection.rs b/nym-vpn/ui/src-tauri/src/commands/connection.rs new file mode 100644 index 0000000000..9f44794ac0 --- /dev/null +++ b/nym-vpn/ui/src-tauri/src/commands/connection.rs @@ -0,0 +1,61 @@ +use std::time::Duration; + +use tauri::State; +use tokio::time::sleep; +use tracing::{debug, instrument, trace}; + +use crate::{ + error::CommandError, + states::{app::ConnectionState, SharedAppState}, +}; + +#[instrument] +#[tauri::command] +pub async fn get_connection_state( + state: State<'_, SharedAppState>, +) -> Result { + debug!("get_connection_state"); + let app_state = state.lock().await; + Ok(app_state.state) +} + +#[tauri::command] +pub async fn connect(state: State<'_, SharedAppState>) -> Result { + debug!("connect"); + let mut app_state = state.lock().await; + let ConnectionState::Disconnected = app_state.state else { + return Err(CommandError::CallerError(format!( + "cannot connect from state {:?}", + app_state.state + ))); + }; + + // TODO fake some delay to establish connection + let app_state_cloned = state.inner().clone(); + let task = tokio::spawn(async move { + sleep(Duration::from_secs(2)).await; + trace!("connected"); + app_state_cloned.lock().await.state = ConnectionState::Connected; + }); + + let _ = task.await; + + app_state.state = ConnectionState::Connecting; + Ok(app_state.state) +} + +#[instrument] +#[tauri::command] +pub async fn disconnect(state: State<'_, SharedAppState>) -> Result { + debug!("disconnect"); + let mut app_state = state.lock().await; + let ConnectionState::Connected = app_state.state else { + return Err(CommandError::CallerError(format!( + "cannot disconnect from state {:?}", + app_state.state + ))); + }; + + app_state.state = ConnectionState::Disconnecting; + Ok(app_state.state) +} diff --git a/nym-vpn/ui/src-tauri/src/commands/mod.rs b/nym-vpn/ui/src-tauri/src/commands/mod.rs new file mode 100644 index 0000000000..c28bd8ce47 --- /dev/null +++ b/nym-vpn/ui/src-tauri/src/commands/mod.rs @@ -0,0 +1,11 @@ +use tracing::{debug, instrument}; + +pub mod connection; +pub mod settings; + +#[instrument] +#[tauri::command] +pub fn greet(name: &str) -> String { + debug!("greet"); + format!("Hello, {}! You've been greeted from Rust!", name) +} diff --git a/nym-vpn/ui/src-tauri/src/commands/settings.rs b/nym-vpn/ui/src-tauri/src/commands/settings.rs new file mode 100644 index 0000000000..ee9701ea9e --- /dev/null +++ b/nym-vpn/ui/src-tauri/src/commands/settings.rs @@ -0,0 +1,32 @@ +use tauri::State; +use tracing::{debug, instrument}; + +use crate::{error::CommandError, fs::data::AppData, states::SharedAppData}; + +#[instrument] +#[tauri::command] +pub async fn save_user_settings(state: State<'_, SharedAppData>) -> Result<(), CommandError> { + debug!("save_user_settings"); + let app_data = state.lock().await; + app_data + .write() + .map_err(|e| CommandError::InternalError(e.to_string()))?; + + Ok(()) +} + +#[instrument] +#[tauri::command] +pub async fn set_user_settings( + state: State<'_, SharedAppData>, + settings: AppData, +) -> Result<(), CommandError> { + debug!("set_user_settings"); + let mut app_data = state.lock().await; + app_data.data = settings; + app_data + .write() + .map_err(|e| CommandError::InternalError(e.to_string()))?; + + Ok(()) +} diff --git a/nym-vpn/ui/src-tauri/src/error.rs b/nym-vpn/ui/src-tauri/src/error.rs new file mode 100644 index 0000000000..34f57b66b2 --- /dev/null +++ b/nym-vpn/ui/src-tauri/src/error.rs @@ -0,0 +1,12 @@ +use serde::{Deserialize, Serialize}; +use thiserror::Error; + +#[derive(Error, Debug, Serialize, Deserialize)] +pub enum CommandError { + #[error("internal error: `{0}`")] + InternalError(String), + #[error("caller error: `{0}`")] + CallerError(String), + #[error("unknown error")] + Unknown, +} diff --git a/nym-vpn/ui/src-tauri/src/fs/cache.rs b/nym-vpn/ui/src-tauri/src/fs/cache.rs new file mode 100644 index 0000000000..64bc676b0f --- /dev/null +++ b/nym-vpn/ui/src-tauri/src/fs/cache.rs @@ -0,0 +1,6 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Default, Serialize, Deserialize, Debug, Clone)] +pub struct AppCache { + // TODO +} diff --git a/nym-vpn/ui/src-tauri/src/fs/config.rs b/nym-vpn/ui/src-tauri/src/fs/config.rs new file mode 100644 index 0000000000..3755d701a8 --- /dev/null +++ b/nym-vpn/ui/src-tauri/src/fs/config.rs @@ -0,0 +1,6 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Default, Serialize, Deserialize, Debug, Clone)] +pub struct AppConfig { + // TODO +} diff --git a/nym-vpn/ui/src-tauri/src/fs/data.rs b/nym-vpn/ui/src-tauri/src/fs/data.rs new file mode 100644 index 0000000000..cbc177b281 --- /dev/null +++ b/nym-vpn/ui/src-tauri/src/fs/data.rs @@ -0,0 +1,13 @@ +use serde::{Deserialize, Serialize}; + +use crate::states::app::{NodeConfig, PrivacyMode}; + +#[derive(Default, Serialize, Deserialize, Debug, Clone)] +pub struct AppData { + pub monitoring: Option, + pub autoconnect: Option, + pub killswitch: Option, + pub privacy_mode: Option, + pub entry_node: Option, + pub exit_node: Option, +} diff --git a/nym-vpn/ui/src-tauri/src/fs/log.rs b/nym-vpn/ui/src-tauri/src/fs/log.rs new file mode 100644 index 0000000000..7401d4e653 --- /dev/null +++ b/nym-vpn/ui/src-tauri/src/fs/log.rs @@ -0,0 +1,6 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Default, Serialize, Deserialize, Debug, Clone)] +pub struct AppLog { + // TODO +} diff --git a/nym-vpn/ui/src-tauri/src/fs/mod.rs b/nym-vpn/ui/src-tauri/src/fs/mod.rs new file mode 100644 index 0000000000..429f48cc99 --- /dev/null +++ b/nym-vpn/ui/src-tauri/src/fs/mod.rs @@ -0,0 +1,4 @@ +pub mod config; +pub mod data; +pub mod log; +pub mod storage; diff --git a/nym-vpn/ui/src-tauri/src/fs/storage.rs b/nym-vpn/ui/src-tauri/src/fs/storage.rs new file mode 100644 index 0000000000..70a2e6287b --- /dev/null +++ b/nym-vpn/ui/src-tauri/src/fs/storage.rs @@ -0,0 +1,84 @@ +use anyhow::{anyhow, Context, Result}; +use serde::{de::DeserializeOwned, Serialize}; +use std::{fmt, fs, path::PathBuf, str}; +use tauri::api::path::data_dir; +use tracing::{debug, error, instrument}; + +#[derive(Debug, Clone)] +pub struct AppStorage +where + T: Serialize + DeserializeOwned + Default + fmt::Debug, +{ + pub data: T, + pub dir_path: PathBuf, + pub filename: String, + pub full_path: PathBuf, +} + +fn create_directory_path(path: &PathBuf) -> Result<()> { + let mut data_dir = data_dir().ok_or(anyhow!( + "Failed to retrieve data directory {:?}", + path.display() + ))?; + data_dir.push(path); + + fs::create_dir_all(&data_dir).context(format!( + "Failed to create data directory {}", + data_dir.display() + )) +} + +impl AppStorage +where + T: Serialize + DeserializeOwned + Default + fmt::Debug, +{ + pub fn new(dir_path: PathBuf, filename: &str, data: Option) -> Self { + let mut full_path = dir_path.clone(); + full_path.push(filename); + + Self { + data: data.unwrap_or_default(), + dir_path, + filename: filename.to_owned(), + full_path, + } + } + + #[instrument] + pub fn read(&self) -> Result { + // create the full directory path if it is missing + create_directory_path(&self.dir_path)?; + + debug!("reading stored data from {}", self.full_path.display()); + let content = fs::read(&self.full_path).context(format!( + "Failed to read data from {}", + self.full_path.display() + ))?; + + toml::from_str::(str::from_utf8(&content)?).map_err(|e| { + error!("{e}"); + anyhow!("{e}") + }) + } + + #[instrument] + pub fn write(&self) -> Result<()> { + // create the full directory path if it is missing + create_directory_path(&self.dir_path)?; + + debug!("writing data to {}", self.full_path.display()); + let toml = toml::to_string(&self.data)?; + fs::write(&self.full_path, toml)?; + Ok(()) + } + + #[instrument] + pub fn clear(&self) -> Result<()> { + // create the full directory path if it is missing + create_directory_path(&self.dir_path)?; + + debug!("clearing data {}", self.full_path.display()); + fs::write(&self.full_path, vec![])?; + Ok(()) + } +} diff --git a/nym-vpn/ui/src-tauri/src/main.rs b/nym-vpn/ui/src-tauri/src/main.rs index 523550d3b7..b690e8e804 100644 --- a/nym-vpn/ui/src-tauri/src/main.rs +++ b/nym-vpn/ui/src-tauri/src/main.rs @@ -1,15 +1,64 @@ // Prevents additional console window on Windows in release, DO NOT REMOVE!! #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] -// Learn more about Tauri commands at https://tauri.app/v1/guides/features/command -#[tauri::command] -fn greet(name: &str) -> String { - format!("Hello, {}! You've been greeted from Rust!", name) -} +use std::sync::Arc; + +use anyhow::anyhow; +use anyhow::Result; +use tauri::api::path::{config_dir, data_dir}; +use tokio::sync::Mutex; +use tracing::info; + +mod commands; +mod error; +mod fs; +mod states; + +use commands::*; +use states::app::AppState; + +use crate::fs::config::AppConfig; +use crate::fs::data::AppData; +use crate::fs::storage::AppStorage; + +const APP_DIR: &str = "nymvpn"; +const APP_DATA_FILE: &str = "app-data.toml"; +const APP_CONFIG_FILE: &str = "config.toml"; + +fn main() -> Result<()> { + dotenvy::dotenv()?; + + // uses RUST_LOG value for logging level + // eg. RUST_LOG=tauri=debug,nymvpn_ui=trace + tracing_subscriber::fmt::init(); + + let mut app_data_path = data_dir().ok_or(anyhow!("Failed to retrieve data directory"))?; + app_data_path.push(APP_DIR); + let app_data_store = AppStorage::::new(app_data_path, APP_DATA_FILE, None); + + let mut app_config_path = config_dir().ok_or(anyhow!("Failed to retrieve config directory"))?; + app_config_path.push(APP_DIR); + let app_config_store = AppStorage::::new(app_config_path, APP_CONFIG_FILE, None); + + info!("Starting tauri app"); -fn main() { tauri::Builder::default() - .invoke_handler(tauri::generate_handler![greet]) + .manage(Arc::new(Mutex::new(AppState::default()))) + .manage(Arc::new(Mutex::new(app_data_store))) + .manage(Arc::new(Mutex::new(app_config_store))) + .setup(|_app| { + info!("app setup"); + Ok(()) + }) + .invoke_handler(tauri::generate_handler![ + greet, + connection::get_connection_state, + connection::connect, + connection::disconnect, + settings::save_user_settings, + settings::set_user_settings, + ]) .run(tauri::generate_context!()) .expect("error while running tauri application"); + Ok(()) } diff --git a/nym-vpn/ui/src-tauri/src/states/app.rs b/nym-vpn/ui/src-tauri/src/states/app.rs new file mode 100644 index 0000000000..6354409d92 --- /dev/null +++ b/nym-vpn/ui/src-tauri/src/states/app.rs @@ -0,0 +1,44 @@ +use serde::{Deserialize, Serialize}; +use ts_rs::TS; + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct NodeConfig { + pub id: String, + pub country: String, +} + +#[derive(Default, Debug, Clone, Copy, Serialize, Deserialize, TS)] +#[ts(export)] +pub enum ConnectionState { + Connected, + #[default] + Disconnected, + Connecting, + Disconnecting, + Error, +} + +#[derive(Default, Debug, Serialize, Deserialize, TS, Clone)] +#[ts(export)] +pub enum PrivacyMode { + High, + Medium, + #[default] + Low, +} + +#[derive(Debug, Serialize, Deserialize, TS)] +#[ts(export)] +pub struct TunnelConfig { + pub id: String, + pub name: String, +} + +#[derive(Debug, Default)] +pub struct AppState { + pub state: ConnectionState, + pub privacy_mode: PrivacyMode, + pub entry_node: Option, + pub exit_node: Option, + pub tunnel: Option, +} diff --git a/nym-vpn/ui/src-tauri/src/states/mod.rs b/nym-vpn/ui/src-tauri/src/states/mod.rs new file mode 100644 index 0000000000..b02b90be7b --- /dev/null +++ b/nym-vpn/ui/src-tauri/src/states/mod.rs @@ -0,0 +1,11 @@ +use std::sync::Arc; + +use tokio::sync::Mutex; + +use crate::fs::{config::AppConfig, data::AppData, storage::AppStorage}; + +pub mod app; + +pub type SharedAppState = Arc>; +pub type SharedAppData = Arc>>; +pub type SharedAppConfig = Arc>>; diff --git a/nym-vpn/ui/src-tauri/tauri.conf.json b/nym-vpn/ui/src-tauri/tauri.conf.json index a1983b2f27..059b30d70d 100644 --- a/nym-vpn/ui/src-tauri/tauri.conf.json +++ b/nym-vpn/ui/src-tauri/tauri.conf.json @@ -29,7 +29,7 @@ "bundle": { "active": true, "targets": "all", - "identifier": "com.tauri.dev", + "identifier": "net.nymtech.vpn", "icon": [ "icons/32x32.png", "icons/128x128.png", @@ -46,8 +46,8 @@ "fullscreen": false, "resizable": true, "title": "NymVPN", - "width": 800, - "height": 600 + "width": 200, + "height": 200 } ] } From d6a9f4c5492879bb527f9834d6667ffe2b376fd0 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Mon, 13 Nov 2023 12:34:57 +0100 Subject: [PATCH 47/80] syntax edit --- .../operators/src/nodes/mix-node-setup.md | 32 +++---------------- 1 file changed, 5 insertions(+), 27 deletions(-) diff --git a/documentation/operators/src/nodes/mix-node-setup.md b/documentation/operators/src/nodes/mix-node-setup.md index e98cfee6b2..f9dd3b3d19 100644 --- a/documentation/operators/src/nodes/mix-node-setup.md +++ b/documentation/operators/src/nodes/mix-node-setup.md @@ -59,42 +59,20 @@ To check available configuration options for initializing your node use: ~~~admonish example collapsible=true title="Console output" ``` - + ``` ~~~ -Initalise your mix node with the following command, replacing the value of `--id` with the moniker you wish to give your mix node. Your `--host` must be publicly routable on the internet in order to mix packets, and can be either an Ipv4 or IPv6 address. The `$(curl -4 https://ifconfig.me)` command returns your IP automatically using an external service. If you enter your IP address manually, enter it **without** any port information. +Initialise your mix node with the following command, replacing the value of `--id` with the moniker you wish to give your mix node. Your `--host` must be publicly routable on the internet in order to mix packets, and can be either an Ipv4 or IPv6 address. The `$(curl -4 https://ifconfig.me)` command returns your IP automatically using an external service. If you enter your IP address manually, enter it **without** any port information. ``` -./nym-mixnode init --id --host $(curl -4 https://ifconfig.me) +./nym-mixnode init --id --host $(curl -4 https://ifconfig.me) ``` +If `` was `my-node`, the output shall look like like this: - ~~~admonish example collapsible=true title="Console output" ``` -.nym-mixnode init --id --host $(curl -4 https://ifconfig.me) --wallet-address - - -Initialising mixnode ... -Saved mixnet identity and sphinx keypairs - 2023-06-04T08:20:32.862Z INFO nym_config > Configuration file will be saved to "/home//.nym/mixnodes//config/config.toml" -Saved configuration file to "/home//.nym/mixnodes//config/config.toml" -Mixnode configuration completed. - - _ __ _ _ _ __ ___ - | '_ \| | | | '_ \ _ \ - | | | | |_| | | | | | | - |_| |_|\__, |_| |_| |_| - |___/ - - (nym-mixnode - version v1.1.29) - - -Identity Key: DhmUYedPZvhP9MMwXdNpPaqCxxTQgjAg78s2nqtTTiNF","version":"v1.1.29"},"cost_params -Sphinx Key: CfZSy1jRfrfiVi9JYexjFWPqWkKoY72t7NdpWaq37K8Z -Host: 62.240.134.189 (bind address: 62.240.134.189) -Version: v1.1.29 -Mix Port: 1789, Verloc port: 1790, Http Port: 8000 + ``` ~~~ From e936ba1d26cde3ede5cd57c3476156f384cdca4b Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Mon, 13 Nov 2023 12:39:54 +0100 Subject: [PATCH 48/80] edit Mix node to Mix Node --- .../operators/src/nodes/mix-node-setup.md | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/documentation/operators/src/nodes/mix-node-setup.md b/documentation/operators/src/nodes/mix-node-setup.md index f9dd3b3d19..0644d44452 100644 --- a/documentation/operators/src/nodes/mix-node-setup.md +++ b/documentation/operators/src/nodes/mix-node-setup.md @@ -1,6 +1,6 @@ # Mix Nodes -> The Nym mix node binary was built in the [building nym](../binaries/building-nym.md) section. If you haven't yet built Nym and want to run the code, go there first. +> The Nym Mix Node binary was built in the [building nym](../binaries/building-nym.md) section. If you haven't yet built Nym and want to run the code, go there first. > Any syntax in `<>` brackets is a user's unique variable. Exchange with a corresponding name without the `<>` brackets. @@ -13,11 +13,11 @@ The `nym-mix node` binary is currently one point version ahead of the rest of th ## Preliminary steps -Make sure you do the preparation listed in the [preliminary steps page](../preliminary-steps.md) before setting up your mix node. +Make sure you do the preparation listed in the [preliminary steps page](../preliminary-steps.md) before setting up your Mix Node. ## Mix node setup -Now that you have built the [codebase](../binaries/building-nym.md), set up your [wallet](https://nymtech.net/docs/wallet/desktop-wallet.html), and have a VPS with the `nym-mix node` binary, you can set up your mix node with the instructions below. +Now that you have built the [codebase](../binaries/building-nym.md), set up your [wallet](https://nymtech.net/docs/wallet/desktop-wallet.html), and have a VPS with the `nym-mix node` binary, you can set up your Mix Node with the instructions below. To begin, move to `/target/release` directory from which you run the node commands: @@ -49,7 +49,7 @@ You can also check the various arguments required for individual commands with: > Adding `--no-banner` startup flag will prevent Nym banner being printed even if run in tty environment. -### Initialising your mix node +### Initialising your Mix Node To check available configuration options for initializing your node use: @@ -63,7 +63,7 @@ To check available configuration options for initializing your node use: ``` ~~~ -Initialise your mix node with the following command, replacing the value of `--id` with the moniker you wish to give your mix node. Your `--host` must be publicly routable on the internet in order to mix packets, and can be either an Ipv4 or IPv6 address. The `$(curl -4 https://ifconfig.me)` command returns your IP automatically using an external service. If you enter your IP address manually, enter it **without** any port information. +Initialise your Mix Node with the following command, replacing the value of `--id` with the moniker you wish to give your Mix Node. Your `--host` must be publicly routable on the internet in order to mix packets, and can be either an Ipv4 or IPv6 address. The `$(curl -4 https://ifconfig.me)` command returns your IP automatically using an external service. If you enter your IP address manually, enter it **without** any port information. ``` ./nym-mixnode init --id --host $(curl -4 https://ifconfig.me) @@ -76,13 +76,13 @@ If `` was `my-node`, the output shall look like like this: ``` ~~~ -> The `init` command will refuse to destroy existing mix node keys. +> The `init` command will refuse to destroy existing Mix Node keys. During the `init` process you will have the option to change the `http_api`, `verloc` and `mixnode` ports from their default settings. If you wish to change these in the future you can edit their values in the `config.toml` file created by the initialization process, which is located at `~/.nym/mixnodes//`. ## Node Description (optional) -In order to easily identify your node via human-readable information later on, you can `describe` your mix node with the following command: +In order to easily identify your node via human-readable information later on, you can `describe` your Mix Node with the following command: ``` ./nym-mixnode describe --id @@ -100,7 +100,7 @@ location = "Giza, Egypt" > Remember to restart your `nym-mix-node` process in order for the new description to be propagated. -## Running your mix node +## Running your Mix Node Run your Mix Node with: @@ -110,10 +110,10 @@ Run your Mix Node with: Have a look at the saved configuration files in `$HOME/.nym/mixnodes/` to see more configuration options. -## Bonding your mix node +## Bonding your Mix Node ```admonish caution -From `v1.1.3`, if you unbond your mix node that means you are leaving the mixnet and you will lose all your delegations (permanently). You can join again with the same identity key, however, you will start with **no delegations**. +From `v1.1.3`, if you unbond your Mix Node that means you are leaving the mixnet and you will lose all your delegations (permanently). You can join again with the same identity key, however, you will start with **no delegations**. ``` To initialise, run and bond your Mix Node are the minimum steps to do in order for your Mix Node to work. However we recommend to do a few more steps before bonding. These steps will make it easier for you as a node operator on a long run as well as for others to possibly delegate Nym tokens to your Mix Node. These steps are: @@ -125,7 +125,7 @@ To initialise, run and bond your Mix Node are the minimum steps to do in order f ### Bond via the Desktop wallet (recommended) -You can bond your mix node via the Desktop wallet. +You can bond your Mix Node via the Desktop wallet. * Open your wallet, and head to the `Bond` page, then select the node type `Mixnode` and input your node details. Press `Next`. @@ -178,16 +178,16 @@ If everything worked, you'll see your node running on the either the [Sandbox te Note that your node's public identity key is displayed during startup, you can use it to identify your node in the list. ### Bond via the CLI (power users) -If you want to bond your mix node via the CLI, then check out the [relevant section in the Nym CLI](https://nymtech.net/docs/tools/nym-cli.html#bond-a-mix-node) docs. +If you want to bond your Mix Node via the CLI, then check out the [relevant section in the Nym CLI](https://nymtech.net/docs/tools/nym-cli.html#bond-a-mix-node) docs. ## Node Families -Node family involves setting up a group of mix nodes that work together to provide greater privacy and security for network communications. This is achieved by having the nodes in the family share information and routes, creating a decentralized network that makes it difficult for third parties to monitor or track communication traffic. +Node family involves setting up a group of Mix Nodes that work together to provide greater privacy and security for network communications. This is achieved by having the nodes in the family share information and routes, creating a decentralized network that makes it difficult for third parties to monitor or track communication traffic. ### Create a Node Family -To create a Node family, you will need to install and configure multiple mix nodes, and then use the CLI to link them together into a family. Once your Node family is up and running, you can use it to route your network traffic through a series of nodes, obscuring the original source and destination of the communication. +To create a Node family, you will need to install and configure multiple Mix Nodes, and then use the CLI to link them together into a family. Once your Node family is up and running, you can use it to route your network traffic through a series of nodes, obscuring the original source and destination of the communication. You can use either `nym-cli` which can be downloaded from the [release page](https://github.com/nymtech/nym/releases) or compiling `nyxd`. @@ -273,7 +273,7 @@ Using `nyxd`: ## Checking that your node is mixing correctly ### Network explorers -Once you've started your mix node and it connects to the validator, your node will automatically show up in the 'Mix nodes' section of either the Nym Network Explorers: +Once you've started your Mix Node and it connects to the validator, your node will automatically show up in the 'Mix Nodes' section of either the Nym Network Explorers: - [Mainnet](https://explorer.nymtech.net/overview) - [Sandbox testnet](https://sandbox-explorer.nymtech.net/) @@ -291,5 +291,5 @@ For more details see [Troubleshooting FAQ](../nodes/troubleshooting.md) ## Maintenance -For mix node upgrade, firewall setup, port configuration, API endpoints, VPS suggestions, automation and more, see the [maintenance page](./maintenance.md) +For Mix Node upgrade, firewall setup, port configuration, API endpoints, VPS suggestions, automation and more, see the [maintenance page](./maintenance.md) From 2edd704e39cb4e1ece4426207f5b83ecb5894fb4 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Mon, 13 Nov 2023 12:45:54 +0100 Subject: [PATCH 49/80] edit Mix node to Mix Node --- .../operators/src/nodes/troubleshooting.md | 44 +++++++++---------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/documentation/operators/src/nodes/troubleshooting.md b/documentation/operators/src/nodes/troubleshooting.md index 8ea39dfdf4..357e7fe0f9 100644 --- a/documentation/operators/src/nodes/troubleshooting.md +++ b/documentation/operators/src/nodes/troubleshooting.md @@ -78,7 +78,7 @@ Additional details can be obtained via various methods after you connect to your ##### Socket statistics with `ss` ``` -sudo ss -s -t | grep 1789 # if you have specified a different port in your Mix node config, change accordingly +sudo ss -s -t | grep 1789 # if you have specified a different port in your Mix Node config, change accordingly ``` This command should return a lot of data containing `ESTAB`. This command should work on every unix based system. @@ -110,7 +110,7 @@ nym-mixno 103349 root 57u IPv6 1333229976 0t0 TCP [2a03:b0c0:3:d0::ff3: sudo journalctl -u nym-mixnode -o cat | grep "Since startup mixed" ``` -If you have created `nym-mixnode.service` file (i.e. you are running your Mix node via `systemd`) then this command shows you how many packets have you mixed so far, and should return a list of messages like this: +If you have created `nym-mixnode.service` file (i.e. you are running your Mix Node via `systemd`) then this command shows you how many packets have you mixed so far, and should return a list of messages like this: ``` 2021-05-18T12:35:24.057Z INFO nym_mixnode::node::metrics > Since startup mixed 233639 packets! @@ -140,7 +140,7 @@ For example `./target/debug/nym-network-requester --no-banner build-info --outpu nmap -p 1789 -Pn ``` -If your Mix node is configured properly it should output something like this: +If your Mix Node is configured properly it should output something like this: ``` bob@desktop:~$ nmap -p 1789 95.296.134.220 -Pn @@ -159,12 +159,12 @@ curl --location --request GET 'https://validator.nymtech.net/api/v1/mixnodes/' Will return a list all nodes currently online. -You can query Gateways by replacing `nym-mixnodes` with `nym-gateways` in the above command, and can query for the Mix nodes and Gateways on the Sandbox testnet by replacing `validator` with `sandbox-validator`. +You can query Gateways by replacing `nym-mixnodes` with `nym-gateways` in the above command, and can query for the Mix Nodes and Gateways on the Sandbox testnet by replacing `validator` with `sandbox-validator`. #### Check with Network API -We currently have an API set up returning our metrics tests of the network. There are two endpoints to ping for information about your Mix node, `report` and `history`. Find more information about this in the [Mixnodes metrics documentation](./maintenance.md#metrics--api-endpoints). +We currently have an API set up returning our metrics tests of the network. There are two endpoints to ping for information about your Mix Node, `report` and `history`. Find more information about this in the [Mixnodes metrics documentation](./maintenance.md#metrics--api-endpoints). ### Why is my node not mixing any packets? @@ -172,24 +172,24 @@ If you are still unable to see your node on the dashboard, or your node is decla - The firewall on your host machine is not configured properly. Checkout the [instructions](./maintenance.md#configure-your-firewall). - You provided incorrect information when bonding your node. -- You are running your Mix node from a VPS without IPv6 support. -- You did not use the `--announce-host` flag while running the Mix node from your local machine behind NAT. -- You did not configure your router firewall while running the Mix node from your local machine behind NAT, or you are lacking IPv6 support. -- Your mix node is not running at all, it has either exited / panicked or you closed the session without making the node persistent. Check out the [instructions](./maintenance.md#automating-your-node-with-tmux-and-systemd). +- You are running your Mix Node from a VPS without IPv6 support. +- You did not use the `--announce-host` flag while running the Mix Node from your local machine behind NAT. +- You did not configure your router firewall while running the Mix Node from your local machine behind NAT, or you are lacking IPv6 support. +- Your Mix Node is not running at all, it has either exited / panicked or you closed the session without making the node persistent. Check out the [instructions](./maintenance.md#automating-your-node-with-tmux-and-systemd). ```admonish caution -Your Mix node **must speak both IPv4 and IPv6** in order to cooperate with other nodes and route traffic. This is a common reason behind many errors we are seeing among node operators, so check with your provider that your VPS is able to do this! +Your Mix Node **must speak both IPv4 and IPv6** in order to cooperate with other nodes and route traffic. This is a common reason behind many errors we are seeing among node operators, so check with your provider that your VPS is able to do this! ``` #### Incorrect bonding information -Check that you have provided the correct information when bonding your Mix node in the web wallet interface. When in doubt, un-bond and then re-bond your node! +Check that you have provided the correct information when bonding your Mix Node in the web wallet interface. When in doubt, un-bond and then re-bond your node! -> All delegated stake will be lost when un-bonding! However the Mix node must be operational in the first place for the delegation to have any effect. +> All delegated stake will be lost when un-bonding! However the Mix Node must be operational in the first place for the delegation to have any effect. #### Missing `announce-host` flag -On certain cloud providers such as AWS and Google Cloud, you need to do some additional configuration of your firewall and use `--host` with your **local ip** and `--announce-host` with the **public ip** of your Mix node host. +On certain cloud providers such as AWS and Google Cloud, you need to do some additional configuration of your firewall and use `--host` with your **local ip** and `--announce-host` with the **public ip** of your Mix Node host. If the difference between the two is unclear, contact the help desk of your VPS provider. @@ -222,15 +222,15 @@ bob@nym:~$ hostname -I ### Running on a local machine behind NAT with no fixed IP address -Your ISP has to be IPv6 ready if you want to run a Mix node on your local machine. Sadly, in 2020, most of them are not and you won't get an IPv6 address by default from your ISP. Usually it is an extra paid service or they simply don't offer it. +Your ISP has to be IPv6 ready if you want to run a Mix Node on your local machine. Sadly, in 2020, most of them are not and you won't get an IPv6 address by default from your ISP. Usually it is an extra paid service or they simply don't offer it. Before you begin, check if you have IPv6 [here](https://test-ipv6.cz/) or by running command explained in the [section above](./troubleshooting.md#no-ipv6-connectivity). If not, then don't waste your time to run a node which won't ever be able to mix any packet due to this limitation. Call your ISP and ask for IPv6, there is a plenty of it for everyone! -If all goes well and you have IPv6 available, then you will need to `init` the Mix node with an extra flag, `--announce-host`. You will also need to edit your `config.toml` file each time your IPv4 address changes, that could be a few days or a few weeks. Check the your IPv4 in the [section above](./troubleshooting.md#no-ipv6-connectivity). +If all goes well and you have IPv6 available, then you will need to `init` the Mix Node with an extra flag, `--announce-host`. You will also need to edit your `config.toml` file each time your IPv4 address changes, that could be a few days or a few weeks. Check the your IPv4 in the [section above](./troubleshooting.md#no-ipv6-connectivity). Additional configuration on your router might also be needed to allow traffic in and out to port 1789 and IPv6 support. -Here is a sample of the `init` command example to create the Mix node config. +Here is a sample of the `init` command example to create the Mix Node config. ``` ./nym-mixnode init --id --host 0.0.0.0 --announce-host 85.160.12.13 @@ -244,7 +244,7 @@ Make sure you check if your node is really mixing. We are aiming to improve the ### Accidentally killing your node process on exiting session -When you close your current terminal session, you need to make sure you don't kill the Mix node process! There are multiple ways on how to make it persistent even after exiting your ssh session, the easiest solution is to use `tmux` or `nohup`, and the more elegant solution is to run the node with `systemd`. Read the automation manual [here](./maintenance.md#automating-your-node-with-tmux-and-systemd). +When you close your current terminal session, you need to make sure you don't kill the Mix Node process! There are multiple ways on how to make it persistent even after exiting your ssh session, the easiest solution is to use `tmux` or `nohup`, and the more elegant solution is to run the node with `systemd`. Read the automation manual [here](./maintenance.md#automating-your-node-with-tmux-and-systemd). ### Common errors and warnings @@ -266,14 +266,14 @@ Then you need to `--announce-host ` and `--host ` on startu Yes! Here is what you will need to do: -Assuming you would like to use port `1337` for your Mix node, you need to open the new port (and close the old one): +Assuming you would like to use port `1337` for your Mix Node, you need to open the new port (and close the old one): ``` sudo ufw allow 1337 sudo ufw deny 1789 ``` -And then edit the Mix node's config. +And then edit the Mix Node's config. > If you want to change the port for an already running node, you need to stop the process before editing your config file. @@ -287,11 +287,11 @@ nano ~/.nym/mixnodes/alice-node/config/config.toml You will need to edit two parts of the file. `announce_address` and `listening_address` in the config.toml file. Simply replace `:1789` (the default port) with `:1337` (your new port) after your IP address. -Finally, restart your node. You should see if the Mix node is using the port you have changed in the config.toml file right after you run the node. +Finally, restart your node. You should see if the Mix Node is using the port you have changed in the config.toml file right after you run the node. -### What is `verloc` and do I have to configure my Mix node to implement it? +### What is `verloc` and do I have to configure my Mix Node to implement it? -`verloc` is short for _verifiable location_. Mixnodes and Gateways now measure speed-of-light distances to each other, in an attempt to verify how far apart they are. In later releases, this will allow us to algorithmically verify node locations in a non-fake-able and trustworthy manner. +`verloc` is short for _verifiable location_. Mix Nodes and Gateways now measure speed-of-light distances to each other, in an attempt to verify how far apart they are. In later releases, this will allow us to algorithmically verify node locations in a non-fake-able and trustworthy manner. You don't have to do any additional configuration for your node to implement this, it is a passive process that runs in the background of the mixnet from version `0.10.1` onward. From 0dd1f3ac2b2c1e7e07ca096733e722229104c599 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Mon, 13 Nov 2023 12:47:26 +0100 Subject: [PATCH 50/80] edit Network requester to Network Requester --- documentation/operators/src/nodes/troubleshooting.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/documentation/operators/src/nodes/troubleshooting.md b/documentation/operators/src/nodes/troubleshooting.md index 357e7fe0f9..16a4d8d9fa 100644 --- a/documentation/operators/src/nodes/troubleshooting.md +++ b/documentation/operators/src/nodes/troubleshooting.md @@ -295,7 +295,7 @@ Finally, restart your node. You should see if the Mix Node is using the port you You don't have to do any additional configuration for your node to implement this, it is a passive process that runs in the background of the mixnet from version `0.10.1` onward. -## Gateways & Network requesters +## Gateways & Network Requesters ### My gateway seems to be running but appears offline @@ -305,7 +305,7 @@ Check your [firewall](./maintenance.md#configure-your-firewall) is active and if The Nyx chain epoch takes up to 60 min. To prevent the Gateway getting blacklisted, it's important to run it before and during the bonding process. In case it already got blacklisted run it for at several hours. During this time your node is tested by `nym-api` and every positive response picks up your Gateway's routing score. -You may want to disconnect the Network requester and let it run as a Gateway alone for some time to regain better routing score and then return to the full [Exit Gateway finctionality](./gateway-setup.md#initialising-gateway-with-network-requester). +You may want to disconnect the Network Requester and let it run as a Gateway alone for some time to regain better routing score and then return to the full [Exit Gateway finctionality](./gateway-setup.md#initialising-gateway-with-network-requester). ## Validators From 2a3d898da1429f106a90a859c5f0de12bcaa8df4 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Mon, 13 Nov 2023 12:48:07 +0100 Subject: [PATCH 51/80] edit gateway to Gateway --- documentation/operators/src/nodes/troubleshooting.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/operators/src/nodes/troubleshooting.md b/documentation/operators/src/nodes/troubleshooting.md index 16a4d8d9fa..fc201639c4 100644 --- a/documentation/operators/src/nodes/troubleshooting.md +++ b/documentation/operators/src/nodes/troubleshooting.md @@ -297,7 +297,7 @@ You don't have to do any additional configuration for your node to implement thi ## Gateways & Network Requesters -### My gateway seems to be running but appears offline +### My Gateway seems to be running but appears offline Check your [firewall](./maintenance.md#configure-your-firewall) is active and if the necessary ports are open / allowed. From 8029136251f9a2b7babdf5656c0a8b721cacf233 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Mon, 13 Nov 2023 12:50:10 +0100 Subject: [PATCH 52/80] edit Network requester to Network Requester --- .../src/nodes/network-requester-setup.md | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/documentation/operators/src/nodes/network-requester-setup.md b/documentation/operators/src/nodes/network-requester-setup.md index d98a937f93..2cd3732418 100644 --- a/documentation/operators/src/nodes/network-requester-setup.md +++ b/documentation/operators/src/nodes/network-requester-setup.md @@ -1,6 +1,6 @@ # Network Requesters -> Nym Network requester was built in the [building nym](../binaries/building-nym.md) section. If you haven't yet built Nym and want to run the code, go there first. +> Nym Network Requester was built in the [building nym](../binaries/building-nym.md) section. If you haven't yet built Nym and want to run the code, go there first. ```admonish info As a result of [Project Smoosh](../faq/smoosh-faq.md), the current version of `nym-gateway` binary also contains `nym-network-requester` functionality which can be enabled [by the operator](./gateway-setup.md#initialising-gateway-with-network-requester). This combination is a basis of Nym Exit Gateway node - an essential piece in our new setup. Please read more in our [Project Smoosh FAQ](../faq/smoosh-faq.md) and [Exit Gateways Page](../legal/exit-gateway.md). We recommend operators begin to shift their setups to this new combined node, instead of operating two separate binaries. @@ -15,23 +15,23 @@ As a result of [Project Smoosh](../faq/smoosh-faq.md), the current version of `n ## Preliminary steps -Make sure you do the preparation listed in the [preliminary steps page](../preliminary-steps.md) before setting up your Network requester. +Make sure you do the preparation listed in the [preliminary steps page](../preliminary-steps.md) before setting up your Network Requester. ## Network Requester Whitelist -If you have access to a server, you can run the Network requester, which allows Nym users to send outbound requests from their local machine through the Mixnet to a server, which then makes the request on their behalf, shielding them (and their metadata) from clearnet, untrusted and unknown infrastructure, such as email or message client servers. +If you have access to a server, you can run the Network Requester, which allows Nym users to send outbound requests from their local machine through the Mixnet to a server, which then makes the request on their behalf, shielding them (and their metadata) from clearnet, untrusted and unknown infrastructure, such as email or message client servers. -By default the network requester is **not** an open proxy (although it can be used as one). It uses a file called `allowed.list` (located in `~/.nym/service-providers/network-requester//`) as a whitelist for outbound requests. +By default the Network Requester is **not** an open proxy (although it can be used as one). It uses a file called `allowed.list` (located in `~/.nym/service-providers/network-requester//`) as a whitelist for outbound requests. -**Note:** If you run Network requester as a part of the Exit Gateway (suggested setup) the `allowed.list` will be stored in `~/.nym/gateways//data/network-requester-data/allowed.list`. +**Note:** If you run Network Requester as a part of the Exit Gateway (suggested setup) the `allowed.list` will be stored in `~/.nym/gateways//data/network-requester-data/allowed.list`. Any request to a URL which is not on this list will be blocked. On startup, if this file is not present, the requester will grab the default whitelist from [Nym's default list](https://nymtech.net/.wellknown/network-requester/standard-allowed-list.txt) automatically. -This default whitelist is useful for knowing that the majority of Network requesters are able to support certain apps 'out of the box'. +This default whitelist is useful for knowing that the majority of Network Requesters are able to support certain apps 'out of the box'. -**Operators of a Network requester are of course free to edit this file and add the URLs of services they wish to support to it!** You can find instructions below on adding your own URLs or IPs to this list. +**Operators of a Network Requester are of course free to edit this file and add the URLs of services they wish to support to it!** You can find instructions below on adding your own URLs or IPs to this list. The domains and IPs on the default whitelist can be broken down by application as follows: @@ -109,14 +109,14 @@ alephium.org ## Network Requester Directory -You can find a list of Network requesters running the default whitelist in the [explorer](https://explorer.nymtech.net/network-components/service-providers). This list comprises of the NRs running as infrastructure for NymConnect. +You can find a list of Network Requesters running the default whitelist in the [explorer](https://explorer.nymtech.net/network-components/service-providers). This list comprises of the NRs running as infrastructure for NymConnect. > We are currently working on a smart-contract based solution more in line with how Mix nodes and Gateways announce themselves to the network. ## Viewing command help ```admonish info -If you run your Network requester as a part of your Exit Gateway according to the suggested setup, please skip this part of the page and read about [Exit Gateway setup](./gateway-setup.md#initialising-gateway-with-network-requester) instead. +If you run your Network Requester as a part of your Exit Gateway according to the suggested setup, please skip this part of the page and read about [Exit Gateway setup](./gateway-setup.md#initialising-gateway-with-network-requester) instead. ``` To begin, move to `/target/release` directory from which you run the node commands: @@ -141,9 +141,9 @@ You can check the required parameters for available commands by running: > Adding `--no-banner` startup flag will prevent Nym banner being printed even if run in tty environment. -## Initializing and running your Network requester +## Initializing and running your Network Requester -The Network requester needs to be initialized before it can be run. This is required for the embedded nym-client to connect successfully to the Mixnet. We want to specify an `` using the `--id` command and give it a value of your choice. The following command will achieve that: +The Network Requester needs to be initialized before it can be run. This is required for the embedded nym-client to connect successfully to the Mixnet. We want to specify an `` using the `--id` command and give it a value of your choice. The following command will achieve that: ``` ./nym-network-requester init --id @@ -164,11 +164,11 @@ Now that we have initialized our network-requester, we can start it with the fol ./nym-network-requester run --id ``` -## Using your Network requester +## Using your Network Requester The next thing to do is use your requester, share its address with friends (or whoever you want to help privacy-enhance their app traffic). Is this safe to do? If it was an open proxy, this would be unsafe, because any Nym user could make Network requests to any system on the internet. -To make things a bit less stressful for administrators, the Network Requester drops all incoming requests by default. In order for it to make requests, you need to add specific domains to the `allowed.list` file at `$HOME/.nym/service-providers/network-requester/allowed.list` or if Network requester is ran as a part of [Exit Gateway](./gateway-setup.md#initialising-gateway-with-network-requester), the `allowed.list` will be stored in `~/.nym/gateways//data/network-requester-data/allowed.list` +To make things a bit less stressful for administrators, the Network Requester drops all incoming requests by default. In order for it to make requests, you need to add specific domains to the `allowed.list` file at `$HOME/.nym/service-providers/network-requester/allowed.list` or if Network Requester is ran as a part of [Exit Gateway](./gateway-setup.md#initialising-gateway-with-network-requester), the `allowed.list` will be stored in `~/.nym/gateways//data/network-requester-data/allowed.list` ### Global vs local allow lists Your Network Requester will check for a domain against 2 lists before allowing traffic through for a particular domain or IP. @@ -177,8 +177,8 @@ Your Network Requester will check for a domain against 2 lists before allowing t * The second is the local `allowed.list` file. -### Supporting custom domains with your Network requester -It is easy to add new domains and services to your network requester - simply find out which endpoints (both URLs and raw IP addresses are supported) you need to whitelist, and then add these endpoints to your `allowed.list`. +### Supporting custom domains with your Network Requester +It is easy to add new domains and services to your Network Requester - simply find out which endpoints (both URLs and raw IP addresses are supported) you need to whitelist, and then add these endpoints to your `allowed.list`. > In order to keep things more organised, you can now use comments in the `allow.list` like the example at the top of this page. @@ -194,15 +194,15 @@ ls -lt $HOME/.nym/gateways/*/data/network-requester-data | grep "list" # returns: allowed.list unknown.list ``` -We already know that `allowed.list` is what lets requests go through. All unknown requests are logged to `unknown.list`. If you want to try using a new client type, just start the new application, point it at your local [socks client](https://nymtech.net/docs/clients/socks5-client.html) (configured to use your remote `nym-network-requester`), and keep copying URLs from `unknown.list` into `allowed.list` (it may take multiple tries until you get all of them, depending on the complexity of the application). Make sure to delete the copied ones in `unknown.list` and restart your Exit Gateway or standalone Network requester. +We already know that `allowed.list` is what lets requests go through. All unknown requests are logged to `unknown.list`. If you want to try using a new client type, just start the new application, point it at your local [socks client](https://nymtech.net/docs/clients/socks5-client.html) (configured to use your remote `nym-network-requester`), and keep copying URLs from `unknown.list` into `allowed.list` (it may take multiple tries until you get all of them, depending on the complexity of the application). Make sure to delete the copied ones in `unknown.list` and restart your Exit Gateway or standalone Network Requester. > If you are adding custom domains, please note that whilst they may appear in the logs of your network-requester as something like `api-0.core.keybaseapi.com:443`, you **only need** to include the main domain name, in this instance `keybaseapi.com` ### Running an open proxy If you *really* want to run an open proxy, perhaps for testing purposes for your own use or among a small group of trusted friends, it is possible to do so. You can disable Network checks by passing the flag `--open-proxy` flag when you run it. If you run in this configuration, you do so at your own risk. -## Testing your Network requester -1. Make sure `nymtech.net` is in your `allowed.list` (remember to restart your Network requester). +## Testing your Network Requester +1. Make sure `nymtech.net` is in your `allowed.list` (remember to restart your Network Requester). 2. Ensure that your `nym-network-requester` is initialized and running. @@ -220,5 +220,5 @@ This command should return the following: ## Maintenance -For Network requester upgrade (including an upgrade from `= v1.1.10`), firewall setup, port configuration, API endpoints, VPS suggestions, automation and more, see the [maintenance page](./maintenance.md). +For Network Requester upgrade (including an upgrade from `= v1.1.10`), firewall setup, port configuration, API endpoints, VPS suggestions, automation and more, see the [maintenance page](./maintenance.md). From 4c7a30a16d4f33fdbe44c7d0f391a2ad198c94f5 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Mon, 13 Nov 2023 12:50:35 +0100 Subject: [PATCH 53/80] edit Mix node to Mix Node --- documentation/operators/src/nodes/network-requester-setup.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/operators/src/nodes/network-requester-setup.md b/documentation/operators/src/nodes/network-requester-setup.md index 2cd3732418..fa5528c7d6 100644 --- a/documentation/operators/src/nodes/network-requester-setup.md +++ b/documentation/operators/src/nodes/network-requester-setup.md @@ -111,7 +111,7 @@ alephium.org You can find a list of Network Requesters running the default whitelist in the [explorer](https://explorer.nymtech.net/network-components/service-providers). This list comprises of the NRs running as infrastructure for NymConnect. -> We are currently working on a smart-contract based solution more in line with how Mix nodes and Gateways announce themselves to the network. +> We are currently working on a smart-contract based solution more in line with how Mix Nodes and Gateways announce themselves to the network. ## Viewing command help From 9f57ea4309901da976563768df580911e61084ac Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Mon, 13 Nov 2023 12:54:59 +0100 Subject: [PATCH 54/80] edit Mix node to Mix Node --- .../operators/src/nodes/maintenance.md | 60 +++++++++---------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/documentation/operators/src/nodes/maintenance.md b/documentation/operators/src/nodes/maintenance.md index 79efbcca22..21765d2a5c 100644 --- a/documentation/operators/src/nodes/maintenance.md +++ b/documentation/operators/src/nodes/maintenance.md @@ -16,20 +16,20 @@ For example `./target/debug/nym-network-requester --no-banner build-info --outpu ## Upgrading your node -> The process is the similar for Mix node, Gateway and Network requester. In the following steps we use a placeholder `` in the commands, please change it for the type of node you want to upgrade. Any particularities for the given type of node are included. +> The process is the similar for Mix Node, Gateway and Network requester. In the following steps we use a placeholder `` in the commands, please change it for the type of node you want to upgrade. Any particularities for the given type of node are included. Upgrading your node is a two-step process: * Updating the binary and `~/.nym///config/config.toml` on your VPS * Updating the node information in the [mixnet smart contract](https://nymtech.net/docs/nyx/mixnet-contract.html). **This is the information that is present on the [mixnet explorer](https://explorer.nymtech.net)**. ### Step 1: Upgrading your binary -Follow these steps to upgrade your Mix node binary and update its config file: -* pause your Mix node process. +Follow these steps to upgrade your Mix Node binary and update its config file: +* pause your Mix Node process. * replace the existing binary with the newest binary (which you can either [compile yourself](https://nymtech.net/docs/binaries/building-nym.html) or grab from our [releases page](https://github.com/nymtech/nym/releases)). * re-run `init` with the same values as you used initially. **This will just update the config file, it will not overwrite existing keys**. -* restart your Mix node process with the new binary. +* restart your Mix Node process with the new binary. -> In case of a Network requester this is all all, the following step is only for Mix nodes and Gateways. +> In case of a Network requester this is all all, the following step is only for Mix Nodes and Gateways. ### Step 2: Updating your node information in the smart contract Follow these steps to update the information about your `` which is publicly available from the [Nym API](https://validator.nymtech.net/api/swagger/index.html) and information displayed on the [mixnet explorer](https://explorer.nymtech.net). @@ -236,7 +236,7 @@ sudo ufw status Finally open your `` p2p port, as well as ports for ssh and ports for verloc and measurement pings: ```sh -# for Mix node, Gateway and Network requester +# for Mix Node, Gateway and Network requester sudo ufw allow 1789,1790,8000,9000,9001,22/tcp # In case of reverse proxy for the Gateway swagger page add: @@ -257,7 +257,7 @@ For more information about your node's port configuration, check the [port refer ### Automating your node with nohup, tmux and systemd -Although it’s not totally necessary, it's useful to have the Mix node automatically start at system boot time. +Although it’s not totally necessary, it's useful to have the Mix Node automatically start at system boot time. #### nohup @@ -287,7 +287,7 @@ In case it didn't work for your distribution, see how to build `tmux` from [vers **Running tmux** -No when you installed tmux on your VPS, let's run a Mix node on tmux, which allows you to detach your terminal and let your `` run on its own on the VPS. +No when you installed tmux on your VPS, let's run a Mix Node on tmux, which allows you to detach your terminal and let your `` run on its own on the VPS. * Pause your `` * Start tmux with the command @@ -310,7 +310,7 @@ tmux attach-session Here's a systemd service file to do that: -##### For Mix node +##### For Mix Node ```ini [Unit] @@ -433,7 +433,7 @@ systemctl daemon-reload # to pickup the new unit file ``` ```sh -# for Mix node +# for Mix Node systemctl enable nym-mixnode.service # for Gateway @@ -443,7 +443,7 @@ systemctl enable nym-gateway.service Start your node: ```sh -# for Mix node +# for Mix Node service nym-mixnode start # for Gateway @@ -477,7 +477,7 @@ This lets your operating system know it's ok to reload the service configuration Linux machines limit how many open files a user is allowed to have. This is called a `ulimit`. -`ulimit` is 1024 by default on most systems. It needs to be set higher, because Mix nodes make and receive a lot of connections to other nodes. +`ulimit` is 1024 by default on most systems. It needs to be set higher, because Mix Nodes make and receive a lot of connections to other nodes. If you see errors such as: @@ -491,7 +491,7 @@ This means that the operating system is preventing network connections from bein > Replace `` variable with `nym-mixnode`, `nym-gateway` or `nym-network-requester` according the node you running on your machine. -The ulimit setup is relevant for maintenance of nym Mix node only. +The ulimit setup is relevant for maintenance of Nym Mix Node only. Query the `ulimit` of your `` with: @@ -543,7 +543,7 @@ Make sure the limit has changed to 65535. #### Set the ulimit on `non-systemd` based distributions -In case you chose tmux option for Mix node automatization, see your `ulimit` list by running: +In case you chose tmux option for Mix Node automation, see your `ulimit` list by running: ```sh ulimit -a @@ -568,13 +568,13 @@ username hard nofile 4096 username soft nofile 4096 ``` -Then reboot your server and restart your Mix node. +Then reboot your server and restart your Mix Node. ## Moving a node In case of a need to move a node from one machine to another and avoiding to lose the delegation, here are few steps how to do it. -The following examples transfers a Mix node (in case of other nodes, change the `mixnodes` in the command for the `` of your desire. +The following examples transfers a Mix Node (in case of other nodes, change the `mixnodes` in the command for the `` of your desire. * Pause your node process. @@ -587,7 +587,7 @@ Assuming both machines are remote VPS. # in case none of the nym configs was created previously mkdir ~/.nym -#in case no nym Mix node was initialized previously +#in case no nym Mix Node was initialized previously mkdir ~/.nym/mixnodes ``` * Move the node data (keys) and config file to the new machine by opening a local terminal (as that one's ssh key is authorized in both of the machines) and running: @@ -614,29 +614,29 @@ ens4: flags=4163 mtu 1460 The `ens4` interface has the IP `10.126.5.7`. But this isn't the public IP of the machine, it's the IP of the machine on Google's internal network. Google uses virtual routing, so the public IP of this machine is something else, maybe `36.68.243.18`. -`./nym-mixnode init --host 10.126.5.7`, initalises the Mix node, but no packets will be routed because `10.126.5.7` is not on the public internet. +`./nym-mixnode init --host 10.126.5.7`, initalises the Mix Node, but no packets will be routed because `10.126.5.7` is not on the public internet. -Trying `nym-mixnode init --host 36.68.243.18`, you'll get back a startup error saying `AddrNotAvailable`. This is because the Mix node doesn't know how to bind to a host that's not in the output of `ifconfig`. +Trying `nym-mixnode init --host 36.68.243.18`, you'll get back a startup error saying `AddrNotAvailable`. This is because the Mix Node doesn't know how to bind to a host that's not in the output of `ifconfig`. The right thing to do in this situation is to init with a command: ```sh ./nym-mixnode init --host 10.126.5.7 --announce-host 36.68.243.18 ``` -This will bind the Mix node to the available host `10.126.5.7`, but announce the Mix node's public IP to the directory server as `36.68.243.18`. It's up to you as a node operator to ensure that your public and private IPs match up properly. +This will bind the Mix Node to the available host `10.126.5.7`, but announce the Mix Node's public IP to the directory server as `36.68.243.18`. It's up to you as a node operator to ensure that your public and private IPs match up properly. To find the right IP configuration, contact your VPS provider for support. ## Nym API (previously 'Validator API') endpoints Numerous API endpoints are documented on the Nym API (previously 'Validator API')'s [Swagger Documentation](https://validator.nymtech.net/api/swagger/index.html). There you can also try out various requests from your browser, and download the response from the API. Swagger will also show you what commands it is running, so that you can run these from an app or from your CLI if you prefer. -### Mix node Reward Estimation API endpoint +### Mix Node Reward Estimation API endpoint -The Reward Estimation API endpoint allows Mix node operators to estimate the rewards they could earn for running a Nym Mix node with a specific `MIX_ID`. +The Reward Estimation API endpoint allows Mix Node operators to estimate the rewards they could earn for running a Nym Mix Node with a specific `MIX_ID`. > The `` can be found in the "Mix ID" column of the [Network Explorer](https://explorer.nymtech.net/network-components/mixnodes/active). -The endpoint is a particularly common for Mix node operators as it can provide an estimate of potential earnings based on factors such as the amount of traffic routed through the Mix node, the quality of the Mix node's performance, and the overall demand for Mixnodes in the network. This information can be useful for Mix node operators in deciding whether or not to run a Mix node and in optimizing its operations for maximum profitability. +The endpoint is a particularly common for Mix Node operators as it can provide an estimate of potential earnings based on factors such as the amount of traffic routed through the Mix Node, the quality of the Mix Node's performance, and the overall demand for Mix Nodes in the network. This information can be useful for Mix Node operators in deciding whether or not to run a Mix Node and in optimizing its operations for maximum profitability. Using this API endpoint returns information about the Reward Estimation: @@ -657,15 +657,15 @@ Query Response: > The unit of value is measured in `uNYM`. -- `estimated_total_node_reward` - An estimate of the total amount of rewards that a particular Mix node can expect to receive during the current epoch. This value is calculated by the Nym Validator based on a number of factors, including the current state of the network, the number of Mix nodes currently active in the network, and the amount of network traffic being processed by the Mix node. +- `estimated_total_node_reward` - An estimate of the total amount of rewards that a particular Mix Node can expect to receive during the current epoch. This value is calculated by the Nym Validator based on a number of factors, including the current state of the network, the number of Mix Nodes currently active in the network, and the amount of network traffic being processed by the Mix Node. -- `estimated_operator_reward` - An estimate of the amount of rewards that a particular Mix node operator can expect to receive. This value is calculated by the Nym Validator based on a number of factors, including the amount of traffic being processed by the Mix node, the quality of service provided by the Mix node, and the operator's stake in the network. +- `estimated_operator_reward` - An estimate of the amount of rewards that a particular Mix Node operator can expect to receive. This value is calculated by the Nym Validator based on a number of factors, including the amount of traffic being processed by the Mix Node, the quality of service provided by the Mix Node, and the operator's stake in the network. -- `estimated_delegators_reward` - An estimate of the amount of rewards that Mix node delegators can expect to receive individually. This value is calculated by the Nym Validator based on a number of factors, including the amount of traffic being processed by the Mix node, the quality of service provided by the Mix node, and the delegator's stake in the network. +- `estimated_delegators_reward` - An estimate of the amount of rewards that Mix Node delegators can expect to receive individually. This value is calculated by the Nym Validator based on a number of factors, including the amount of traffic being processed by the Mix Node, the quality of service provided by the Mix Node, and the delegator's stake in the network. -- `estimated_node_profit` - An estimate of the profit that a particular Mix node operator can expect to earn. This value is calculated by subtracting the Mix node operator's `operating_costs` from their `estimated_operator_reward` for the current epoch. +- `estimated_node_profit` - An estimate of the profit that a particular Mix node operator can expect to earn. This value is calculated by subtracting the Mix Node operator's `operating_costs` from their `estimated_operator_reward` for the current epoch. -- `estimated_operator_cost` - An estimate of the total cost that a particular Mix node operator can expect to incur for their participation. This value is calculated by the Nym Validator based on a number of factors, including the cost of running a Mix node, such as server hosting fees, and other expenses associated with operating the Mix node. +- `estimated_operator_cost` - An estimate of the total cost that a particular Mix Node operator can expect to incur for their participation. This value is calculated by the Nym Validator based on a number of factors, including the cost of running a Mix Node, such as server hosting fees, and other expenses associated with operating the Mix Node. ### Validator: Installing and configuring nginx for HTTPS #### Setup @@ -785,7 +785,7 @@ go_memstats_gc_sys_bytes 1.3884192e+07 ## Ports All ``-specific port configuration can be found in `$HOME/.nym///config/config.toml`. If you do edit any port configs, remember to restart your client and node processes. -### Mix node port reference +### Mix Node port reference | Default port | Use | | ------------ | ------------------------- | | `1789` | Listen for Mixnet traffic | @@ -800,7 +800,7 @@ All ``-specific port configuration can be found in `$HOME/.nym// Date: Mon, 13 Nov 2023 12:55:54 +0100 Subject: [PATCH 55/80] edit Network requester to Network Requester --- documentation/operators/src/nodes/maintenance.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/documentation/operators/src/nodes/maintenance.md b/documentation/operators/src/nodes/maintenance.md index 21765d2a5c..406a04da63 100644 --- a/documentation/operators/src/nodes/maintenance.md +++ b/documentation/operators/src/nodes/maintenance.md @@ -16,7 +16,7 @@ For example `./target/debug/nym-network-requester --no-banner build-info --outpu ## Upgrading your node -> The process is the similar for Mix Node, Gateway and Network requester. In the following steps we use a placeholder `` in the commands, please change it for the type of node you want to upgrade. Any particularities for the given type of node are included. +> The process is the similar for Mix Node, Gateway and Network Requester. In the following steps we use a placeholder `` in the commands, please change it for the type of node you want to upgrade. Any particularities for the given type of node are included. Upgrading your node is a two-step process: * Updating the binary and `~/.nym///config/config.toml` on your VPS @@ -29,7 +29,7 @@ Follow these steps to upgrade your Mix Node binary and update its config file: * re-run `init` with the same values as you used initially. **This will just update the config file, it will not overwrite existing keys**. * restart your Mix Node process with the new binary. -> In case of a Network requester this is all all, the following step is only for Mix Nodes and Gateways. +> In case of a Network Requester this is all all, the following step is only for Mix Nodes and Gateways. ### Step 2: Updating your node information in the smart contract Follow these steps to update the information about your `` which is publicly available from the [Nym API](https://validator.nymtech.net/api/swagger/index.html) and information displayed on the [mixnet explorer](https://explorer.nymtech.net). @@ -53,9 +53,9 @@ If you want to bond your `` via the CLI, then check out the [relevant sect In the previous version of the network-requester, users were required to run a nym-client along side it to function. As of `v1.1.10`, the network-requester now has a nym client embedded into the binary, so it can run standalone. -If you are running an existing Network requester registered with nym-connect, upgrading requires you move your old keys over to the new Network requester configuration. We suggest following these instructions carefully to ensure a smooth transition. +If you are running an existing Network Requester registered with nym-connect, upgrading requires you move your old keys over to the new Network Requester configuration. We suggest following these instructions carefully to ensure a smooth transition. -Initiate the new Network requester: +Initiate the new Network Requester: ```sh nym-network-requester init --id @@ -236,7 +236,7 @@ sudo ufw status Finally open your `` p2p port, as well as ports for ssh and ports for verloc and measurement pings: ```sh -# for Mix Node, Gateway and Network requester +# for Mix Node, Gateway and Network Requester sudo ufw allow 1789,1790,8000,9000,9001,22/tcp # In case of reverse proxy for the Gateway swagger page add: @@ -354,7 +354,7 @@ WantedBy=multi-user.target * Put the above file onto your system at `/etc/systemd/system/nym-gateway.service`. -##### For Network requester +##### For Network Requester ```ini [Unit] From 946ced541c749e7c388a27adf29eea6758966627 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Mon, 13 Nov 2023 12:57:03 +0100 Subject: [PATCH 56/80] edit Mix node to Mix Node --- documentation/operators/src/nodes/gateway-setup.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/operators/src/nodes/gateway-setup.md b/documentation/operators/src/nodes/gateway-setup.md index fbf817834d..bf7c6aea94 100644 --- a/documentation/operators/src/nodes/gateway-setup.md +++ b/documentation/operators/src/nodes/gateway-setup.md @@ -236,7 +236,7 @@ It will look something like this: > You are asked to `sign` a transaction on bonding so that the Mixnet smart contract is able to map your Nym address to your node. This allows us to create a nonce for each account and defend against replay attacks. #### Via the CLI (power users) -If you want to bond your mix node via the CLI, then check out the [relevant section in the Nym CLI](https://nymtech.net/docs/tools/nym-cli.html#bond-a-mix-node) docs. +If you want to bond your Mix Node via the CLI, then check out the [relevant section in the Nym CLI](https://nymtech.net/docs/tools/nym-cli.html#bond-a-mix-node) docs. ### Running your Gateway From caa18f166164c705256880f8b65fbe2c7cd79a4f Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Mon, 13 Nov 2023 12:58:35 +0100 Subject: [PATCH 57/80] edit Network requester to Network Requester --- .../operators/src/nodes/gateway-setup.md | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/documentation/operators/src/nodes/gateway-setup.md b/documentation/operators/src/nodes/gateway-setup.md index bf7c6aea94..85dd254e2e 100644 --- a/documentation/operators/src/nodes/gateway-setup.md +++ b/documentation/operators/src/nodes/gateway-setup.md @@ -50,7 +50,7 @@ You can also check the various arguments required for individual commands with: ## Initialising your Gateway -As Nym developers build towards [Exit Gateway](../legal/exit-gateway.md) functionality, operators can now run their `nym-gateway` binary with in-build Network requester and include the our new [exit policy](https://nymtech.net/.wellknown/network-requester/exit-policy.txt). Considering the plan to [*smoosh*](../faq/smoosh-faq.md) all the nodes into one binary and have wide opened Exit Gateways, we recommend this setup, instead of operating two separate binaries. +As Nym developers build towards [Exit Gateway](../legal/exit-gateway.md) functionality, operators can now run their `nym-gateway` binary with in-build Network Requester and include the our new [exit policy](https://nymtech.net/.wellknown/network-requester/exit-policy.txt). Considering the plan to [*smoosh*](../faq/smoosh-faq.md) all the nodes into one binary and have wide opened Exit Gateways, we recommend this setup, instead of operating two separate binaries. ```admonish warning Before you start an Exit Gateway, read our [Operators Legal Forum](../legal/exit-gateway.md) page and [*Project Smoosh FAQ*](../faq/smoosh-faq.md). @@ -64,7 +64,7 @@ There has been an ongoing development with dynamic upgrades. Follow the status o ### Initialising Exit Gateway -An operator can initialise the Exit Gateway functionality by adding Network requester with the new exit policy option: +An operator can initialise the Exit Gateway functionality by adding Network Requester with the new exit policy option: ``` ./nym-gateway init --id --listening-address 0.0.0.0 --public-ips "$(curl -4 https://ifconfig.me)" --with-network-requester --with-exit-policy true @@ -82,9 +82,9 @@ You can see that the printed information besides *identity* and *sphinx keys* al Additionally -#### Add Network requester to an existing Gateway +#### Add Network Requester to an existing Gateway -If you already [upgraded](./maintenance.md#upgrading-your-node) your Gateway to the [latest version](./gateway-setup.md#current-version) and initialised without a Network requester, you can easily change its functionality to Exit Gateway with a command `setup-network-requester`. +If you already [upgraded](./maintenance.md#upgrading-your-node) your Gateway to the [latest version](./gateway-setup.md#current-version) and initialised without a Network Requester, you can easily change its functionality to Exit Gateway with a command `setup-network-requester`. See the options: @@ -122,13 +122,13 @@ In case there are any unexpected problems, you can also change it manually by ed ``` [network_requester] -# Specifies whether network requester service is enabled in this process. +# Specifies whether Network Requester service is enabled in this process. enabled = true ``` Save, exit and restart your Gateway. Now you are an operator of post-smooshed Exit Gateway. -#### Enable Nym exit policy to an existing Gateway with Network requester functionality +#### Enable Nym exit policy to an existing Gateway with Network Requester functionality In case you already added Network Requester functionality to your Gateway as described above but haven't enabled the [exit policy](https://nymtech.net/.wellknown/network-requester/exit-policy.txt) there is an easy tweak to do so and turn your node into [Nym Exit Gateway](../faq/smoosh-faq.md#what-are-the-changes). @@ -139,15 +139,15 @@ use_deprecated_allow_list = false Save, exit and restart your Gateway. Now you are an operator of post-smooshed Exit gateway. ```admonish info -All information about network requester part of your Exit Gateway is in `/home/user/.nym/gateways//config/network_requester_config.toml`. +All information about Network Requester part of your Exit Gateway is in `/home/user/.nym/gateways//config/network_requester_config.toml`. ``` -For now you can run Gateway without Network requester or with and without the new exit policy. This will soon change as we inform in our [Project Smoosh FAQ](../faq/smoosh-faq.html#how-will-the-exit-policy-be-implemented). +For now you can run Gateway without Network Requester or with and without the new exit policy. This will soon change as we inform in our [Project Smoosh FAQ](../faq/smoosh-faq.html#how-will-the-exit-policy-be-implemented). -To read more about the configuration like whitelisted outbound requesters in `allowed.list` and other useful information, see the page [*Network requester whitelist*](network-requester-setup.md#using-your-network-requester). +To read more about the configuration like whitelisted outbound requesters in `allowed.list` and other useful information, see the page [*Network Requester whitelist*](network-requester-setup.md#using-your-network-requester). -#### Initialising Gateway without Network requester +#### Initialising Gateway without Network Requester In case you don't want to run your Gateway with the Exit Gateway functionality, you still can run a simple Gateway. From 0041b4a7a71406e410e6566e6eeca8b36b6e478a Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Mon, 13 Nov 2023 13:00:11 +0100 Subject: [PATCH 58/80] edit Mix node to Mix Node --- documentation/operators/src/nodes/setup-guides.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/operators/src/nodes/setup-guides.md b/documentation/operators/src/nodes/setup-guides.md index ca86dd99f4..52fdbf2ee8 100644 --- a/documentation/operators/src/nodes/setup-guides.md +++ b/documentation/operators/src/nodes/setup-guides.md @@ -3,7 +3,7 @@ To setup any type of Nym's node, start with building [Nym's platform](../binaries/building-nym.md) on the machine (VPS) where you want to run the node. Nodes will need to be bond to Nym's wallet, setup one [here](https://nymtech.net/docs/wallet/desktop-wallet.html). This section contains setup guides for the following node types: -* [Mix node](./mix-node-setup.md) +* [Mix Node](./mix-node-setup.md) * [Gateway](./gateway-setup.md) * [Network Requester](./network-requester-setup.md) * [Validator](./validator-setup.md) From 0cd01393071a282f36a1b8161bdbb2747e884d7a Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Mon, 13 Nov 2023 13:02:04 +0100 Subject: [PATCH 59/80] edit Network requester to Network Requester --- documentation/operators/src/legal/exit-gateway.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/documentation/operators/src/legal/exit-gateway.md b/documentation/operators/src/legal/exit-gateway.md index c60fc8dcea..4cbc66bc5e 100644 --- a/documentation/operators/src/legal/exit-gateway.md +++ b/documentation/operators/src/legal/exit-gateway.md @@ -66,9 +66,9 @@ The new setup: Running nodes supporting traffic of any online service (with safe ## Exit Gateways: New setup -In our previous technical setup, network requesters acted as a proxy, and only made requests that match an allow list. That was a default IP based list of allowed domains stored at Nym page in a centralised fashion possibly re-defined by any Network requester operator. +In our previous technical setup, network Requesters acted as a proxy, and only made requests that match an allow list. That was a default IP based list of allowed domains stored at Nym page in a centralised fashion possibly re-defined by any Network Requester operator. -This restricts the hosts that the NymConnect app can connect to and has the effect of selectively supporting messaging services (e.g. Telegram, Matrix) or crypto wallets (e.g. Electrum or Monero). Operators of network requesters can have confidence that the infrastructure they run only connects to a limited set of public internet hosts. +This restricts the hosts that the NymConnect app can connect to and has the effect of selectively supporting messaging services (e.g. Telegram, Matrix) or crypto wallets (e.g. Electrum or Monero). Operators of Network Requesters can have confidence that the infrastructure they run only connects to a limited set of public internet hosts. The principal change in the new configuration is to make this short allow list more permissive. Nym's [exit policy](https://nymtech.net/.wellknown/network-requester/exit-policy.txt) will restrict the hosts to which Nym Mixnet and Nym VPN users are permitted to connect. This will be done in an effort to protect the operators, as Gateways will act both as SOCKS5 Network Requesters, and exit nodes for IP traffic from Nym Mixnet VPN and VPN clients (both wrapped in the same app). From 8ca2ef28e6a1c770c2e4aa7da5d0effc16ec7dd3 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Mon, 13 Nov 2023 13:53:32 +0100 Subject: [PATCH 60/80] edit node upgrade steps and add auto scripts --- .../operators/src/nodes/maintenance.md | 24 ++++++++++++++----- 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/documentation/operators/src/nodes/maintenance.md b/documentation/operators/src/nodes/maintenance.md index 406a04da63..38bf303da5 100644 --- a/documentation/operators/src/nodes/maintenance.md +++ b/documentation/operators/src/nodes/maintenance.md @@ -23,13 +23,25 @@ Upgrading your node is a two-step process: * Updating the node information in the [mixnet smart contract](https://nymtech.net/docs/nyx/mixnet-contract.html). **This is the information that is present on the [mixnet explorer](https://explorer.nymtech.net)**. ### Step 1: Upgrading your binary -Follow these steps to upgrade your Mix Node binary and update its config file: -* pause your Mix Node process. -* replace the existing binary with the newest binary (which you can either [compile yourself](https://nymtech.net/docs/binaries/building-nym.html) or grab from our [releases page](https://github.com/nymtech/nym/releases)). -* re-run `init` with the same values as you used initially. **This will just update the config file, it will not overwrite existing keys**. -* restart your Mix Node process with the new binary. +Follow these steps to upgrade your Node binary and update its config file: +* Pause your node process. + - if you see the terminal window with your node, press `ctrl + c` + - if you run it as `systemd` service, run: `systemctl stop nym-.service` +* Replace the existing `` binary with the newest binary (which you can either [compile yourself](https://nymtech.net/docs/binaries/building-nym.html) or grab from our [releases page](https://github.com/nymtech/nym/releases)). +* Re-run `init` with the same values as you used initially for your `` ([Mix Node](./mix-node-setup.md#initialising-your-mix-node), [Gateway](./gateway-setup.md#initialising-your-gateway)) . **This will just update the config file, it will not overwrite existing keys**. +* Restart your node process with the new binary. + - if you automatized (recommended) run: +```sh +systemctl daemon-reload # to pickup the new unit file +systemctl start nym-.service +journalctl -f -u .service # to monitor log of you node +``` + - if you haven't automatized, just run your `` ([Mix Node](./mix-node-setup.md#running-your-mix-node), [Gateway](./gateway-setup.md#running-your-gateway)) -> In case of a Network Requester this is all all, the following step is only for Mix Nodes and Gateways. + +If these steps are too difficult and you prefer to just run a script, you can use [ExploreNYM script](https://github.com/ExploreNYM/bash-tool) or one done by [Nym developers](https://gist.github.com/tommyv1987/4dca7cc175b70742c9ecb3d072eb8539). + +> In case of a Network Requester this is all, the following step is only for Mix Nodes and Gateways. ### Step 2: Updating your node information in the smart contract Follow these steps to update the information about your `` which is publicly available from the [Nym API](https://validator.nymtech.net/api/swagger/index.html) and information displayed on the [mixnet explorer](https://explorer.nymtech.net). From 0e312f66ead6f563d54fa3f4b4569b60c69e7690 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Mon, 13 Nov 2023 14:46:26 +0100 Subject: [PATCH 61/80] make node upgrade steps more explicit --- documentation/operators/src/nodes/maintenance.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/documentation/operators/src/nodes/maintenance.md b/documentation/operators/src/nodes/maintenance.md index 38bf303da5..7668080295 100644 --- a/documentation/operators/src/nodes/maintenance.md +++ b/documentation/operators/src/nodes/maintenance.md @@ -36,7 +36,7 @@ systemctl daemon-reload # to pickup the new unit file systemctl start nym-.service journalctl -f -u .service # to monitor log of you node ``` - - if you haven't automatized, just run your `` ([Mix Node](./mix-node-setup.md#running-your-mix-node), [Gateway](./gateway-setup.md#running-your-gateway)) + - if your node is not automitized, just `run` your `` with `./nym- run --id `. Here are exact guidelines for [Mix Node](./mix-node-setup.md#running-your-mix-node) and [Gateway](./gateway-setup.md#running-your-gateway). If these steps are too difficult and you prefer to just run a script, you can use [ExploreNYM script](https://github.com/ExploreNYM/bash-tool) or one done by [Nym developers](https://gist.github.com/tommyv1987/4dca7cc175b70742c9ecb3d072eb8539). @@ -44,11 +44,11 @@ If these steps are too difficult and you prefer to just run a script, you can us > In case of a Network Requester this is all, the following step is only for Mix Nodes and Gateways. ### Step 2: Updating your node information in the smart contract -Follow these steps to update the information about your `` which is publicly available from the [Nym API](https://validator.nymtech.net/api/swagger/index.html) and information displayed on the [mixnet explorer](https://explorer.nymtech.net). +Follow these steps to update the information about your `` which is publicly available from the [`nym-api`](https://validator.nymtech.net/api/swagger/index.html) and information displayed on the [Mixnet explorer](https://explorer.nymtech.net). You can either do this graphically via the Desktop Wallet, or the CLI. -### Updating node information via the Desktop Wallet +### Updating node information via the Desktop Wallet (recommended) * Navigate to the `Bonding` page and click the `Node Settings` link in the top right corner: ![Bonding page](../images/wallet-screenshots/bonding.png) From 5a9920edb8485f489ccaeb789f9fc3c0fca55d5f Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Mon, 13 Nov 2023 14:48:41 +0100 Subject: [PATCH 62/80] simplify bonding sequence --- .../operators/src/nodes/gateway-setup.md | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/documentation/operators/src/nodes/gateway-setup.md b/documentation/operators/src/nodes/gateway-setup.md index 85dd254e2e..bf4767a03d 100644 --- a/documentation/operators/src/nodes/gateway-setup.md +++ b/documentation/operators/src/nodes/gateway-setup.md @@ -177,14 +177,21 @@ The following command returns a Gateway on your current IP with the `` of `s The `$(curl -4 https://ifconfig.me)` command above returns your IP automatically using an external service. Alternatively, you can enter your IP manually if you wish. If you do this, remember to enter your IP **without** any port information. +## Running your Gateway -### Bonding your Gateway +The `run` command starts the Gateway: + +``` +./nym-gateway run --id + + +## Bonding your Gateway ```admonish info Before you bond and re-run your Gateway, please make sure the [firewall configuration](./maintenance.md#configure-your-firewall) is setup so your Gateway can be reached from the outside. You can also setup WSS on your Gateway, the steps are on the [Maintenance page](./maintenance.md#configure-your-firewall) below. ``` -#### Via the Desktop wallet +### Via the Desktop wallet (recommended) You can bond your Gateway via the Desktop wallet. @@ -235,15 +242,9 @@ It will look something like this: > You are asked to `sign` a transaction on bonding so that the Mixnet smart contract is able to map your Nym address to your node. This allows us to create a nonce for each account and defend against replay attacks. -#### Via the CLI (power users) +### Via the CLI (power users) If you want to bond your Mix Node via the CLI, then check out the [relevant section in the Nym CLI](https://nymtech.net/docs/tools/nym-cli.html#bond-a-mix-node) docs. -### Running your Gateway - -The `run` command starts the Gateway: - -``` -./nym-gateway run --id ``` ## Maintenance From 564cbadc6e6a76742c6a8f0455fa7cfcca4fec21 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Mon, 13 Nov 2023 14:58:31 +0100 Subject: [PATCH 63/80] edit gateway bonding --- documentation/operators/src/nodes/gateway-setup.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/documentation/operators/src/nodes/gateway-setup.md b/documentation/operators/src/nodes/gateway-setup.md index bf4767a03d..2a6d5565d1 100644 --- a/documentation/operators/src/nodes/gateway-setup.md +++ b/documentation/operators/src/nodes/gateway-setup.md @@ -188,24 +188,24 @@ The `run` command starts the Gateway: ## Bonding your Gateway ```admonish info -Before you bond and re-run your Gateway, please make sure the [firewall configuration](./maintenance.md#configure-your-firewall) is setup so your Gateway can be reached from the outside. You can also setup WSS on your Gateway, the steps are on the [Maintenance page](./maintenance.md#configure-your-firewall) below. +Before you bond your Gateway, please make sure the [firewall configuration](./maintenance.md#configure-your-firewall) is setup so your Gateway can be reached from the outside. You can also setup [WSS on your Gateway](./maintenance.md#run-web-secure-socket-wss-on-gateway) and [automate](./maintenance.md#vps-setup-and-automation) your Gateway to simplify the operation overhead. We highly recommend to run ny of these steps before bonding to prevent disruption of your Gateway's routing score later on. ``` ### Via the Desktop wallet (recommended) -You can bond your Gateway via the Desktop wallet. +You can bond your Gateway via the Desktop wallet. Make sure your Gateway is running and follow the steps below: 1. Open your wallet, and head to the `Bonding` page, then select the node type `Gateway` and input your node details. Press `Next`. 2. Enter the `Amount`, `Operating cost` and press `Next`. -3. You will be asked to run a the `sign` command with your `gateway` - copy and paste the long signature as the value of `--contract-msg` and run it. +3. You will be asked to run a the `sign` command with your `gateway` - copy and paste the long signature `` and paste it as a value of `--contract-msg` in the following command: ``` ./nym-gateway sign --id --contract-msg ``` -It will look something like this: +It will look something like this (as `` we used `supergateway`: ~~~admonish example collapsible=true title="Console output" ``` @@ -218,7 +218,7 @@ It will look something like this: |_| |_|\__, |_| |_| |_| |___/ - (nym-gateway - version v1.1.31) + (nym-gateway - version v1.1.) >>> attempting to sign 2Mf8xYytgEeyJke9LA7TjhHoGQWNBEfgHZtTyy2krFJfGHSiqy7FLgTnauSkQepCZTqKN5Yfi34JQCuog9k6FGA2EjsdpNGAWHZiuUGDipyJ6UksNKRxnFKhYW7ri4MRduyZwbR98y5fQMLAwHne1Tjm9cXYCn8McfigNt77WAYwBk5bRRKmC34BJMmWcAxphcLES2v9RdSR68tkHSpy2C8STfdmAQs3tZg8bJS5Qa8pQdqx14TnfQAPLk3QYCynfUJvgcQTrg29aqCasceGRpKdQ3Tbn81MLXAGAs7JLBbiMEAhCezAr2kEN8kET1q54zXtKz6znTPgeTZoSbP8rzf4k2JKHZYWrHYF9JriXepuZTnyxAKAxvGFPBk8Z6KAQi33NRQkwd7MPyttatHna6kG9x7knffV6ebGzgRBf7NV27LurH8x4L1uUXwm1v1UYCA1WSBQ9Pp2JW69k5v5v7G9gBy8RUcZnMbeL26Qqb8WkuGcmuHhaFfoqSfV7PRHPpPT4M8uRqUyR4bjUtSJJM1yh6QSeZk9BEazzoJqPeYeGoiFDZ3LMj2jesbJweQR4caaYuRczK92UGSSqu9zBKmE45a @@ -243,7 +243,7 @@ It will look something like this: > You are asked to `sign` a transaction on bonding so that the Mixnet smart contract is able to map your Nym address to your node. This allows us to create a nonce for each account and defend against replay attacks. ### Via the CLI (power users) -If you want to bond your Mix Node via the CLI, then check out the [relevant section in the Nym CLI](https://nymtech.net/docs/tools/nym-cli.html#bond-a-mix-node) docs. +If you want to bond your Gateway via the CLI, then check out the [relevant section in the Nym CLI](https://nymtech.net/docs/tools/nym-cli.html#bond-a-mix-node) docs. ``` ## Maintenance From 2ddd34f343bf1713dafa0a1fcf2c7d6e483a312e Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Mon, 13 Nov 2023 15:00:19 +0100 Subject: [PATCH 64/80] edit syntax --- documentation/operators/src/nodes/gateway-setup.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/documentation/operators/src/nodes/gateway-setup.md b/documentation/operators/src/nodes/gateway-setup.md index 2a6d5565d1..1c1fd3414c 100644 --- a/documentation/operators/src/nodes/gateway-setup.md +++ b/documentation/operators/src/nodes/gateway-setup.md @@ -183,6 +183,7 @@ The `run` command starts the Gateway: ``` ./nym-gateway run --id +``` ## Bonding your Gateway @@ -243,9 +244,9 @@ It will look something like this (as `` we used `supergateway`: > You are asked to `sign` a transaction on bonding so that the Mixnet smart contract is able to map your Nym address to your node. This allows us to create a nonce for each account and defend against replay attacks. ### Via the CLI (power users) + If you want to bond your Gateway via the CLI, then check out the [relevant section in the Nym CLI](https://nymtech.net/docs/tools/nym-cli.html#bond-a-mix-node) docs. -``` ## Maintenance For Gateway upgrade, firewall setup, port configuration, API endpoints, VPS suggestions, automation, WSS setup and more, see the [maintenance page](./maintenance.md) From 5b2e4158bd327f09f7d54c2271eb9ca7756a6f4d Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Mon, 13 Nov 2023 15:37:36 +0100 Subject: [PATCH 65/80] change version variable --- documentation/dev-portal/src/tutorials/electrum.md | 2 +- documentation/dev-portal/src/tutorials/firo.md | 2 +- documentation/dev-portal/src/tutorials/telegram.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/documentation/dev-portal/src/tutorials/electrum.md b/documentation/dev-portal/src/tutorials/electrum.md index e929ea2578..bc5e9b0022 100644 --- a/documentation/dev-portal/src/tutorials/electrum.md +++ b/documentation/dev-portal/src/tutorials/electrum.md @@ -14,7 +14,7 @@ NymConnect application is for everyone who does not want to install and run `nym 2. On Linux and Mac, make executable by opening terminal in the same directory and run: ```sh -chmod +x ./nym-connect_.AppImage +chmod +x ./nym-connect_ ``` 3. Start the application diff --git a/documentation/dev-portal/src/tutorials/firo.md b/documentation/dev-portal/src/tutorials/firo.md index 2e0c24ade0..594bf8f5aa 100644 --- a/documentation/dev-portal/src/tutorials/firo.md +++ b/documentation/dev-portal/src/tutorials/firo.md @@ -14,7 +14,7 @@ NymConnect application is for everyone who does not want to install and run `nym 2. On Linux and Mac, make executable by opening terminal in the same directory and run: ```sh -chmod +x ./nym-connect_.AppImage +chmod +x ./nym-connect_ ``` 3. Start the application diff --git a/documentation/dev-portal/src/tutorials/telegram.md b/documentation/dev-portal/src/tutorials/telegram.md index 731dc0d163..adfd22adc5 100644 --- a/documentation/dev-portal/src/tutorials/telegram.md +++ b/documentation/dev-portal/src/tutorials/telegram.md @@ -16,7 +16,7 @@ Here’s how to configure Telegram with NymConnect: For more releases, check out [Github](https://github.com/nymtech/nym/tags). NymConnect is available for Linux, Windows, and MacOS. On Linux make sure NymConnect is executable. Opening a terminal in the same directory and run: ```sh - chmod +x ./.AppImage + chmod +x ./ ``` 2. **Start NymConnect** Telegram is added to NymConnect by default. From 3715860a47b34bb8ede2fb90baafbbaaff1a893e Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Mon, 13 Nov 2023 15:43:38 +0100 Subject: [PATCH 66/80] add donwload binary steps --- .../src/binaries/pre-built-binaries.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/documentation/operators/src/binaries/pre-built-binaries.md b/documentation/operators/src/binaries/pre-built-binaries.md index 269c26276c..780b13e37f 100644 --- a/documentation/operators/src/binaries/pre-built-binaries.md +++ b/documentation/operators/src/binaries/pre-built-binaries.md @@ -4,3 +4,21 @@ The [Github releases page](https://github.com/nymtech/nym/releases) has pre-buil If the pre-built binaries don't work or are unavailable for your system, you will need to build the platform yourself. +## Setup Binaries + +> Any syntax in `<>` brackets is a user’s unique variable. Exchange with a corresponding name without the `<>` brackets. + +### Download Binary + +1. Open [Github releases page](https://github.com/nymtech/nym/releases) and right click on the binary you want +2. Select `Copy Link` +3. Open your VPS terminal in a directory where you want to download Nym binaries. +4. Download binary by running `wget ` where `` shall be in your clipboard from point \# 2. + +## Make Executable + +5. Run: +```sh +chmod +x +``` + From 4cb0231acf07353e7a4544de2041a56604a35ef8 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Mon, 13 Nov 2023 15:47:27 +0100 Subject: [PATCH 67/80] add run binary steps --- .../operators/src/binaries/pre-built-binaries.md | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/documentation/operators/src/binaries/pre-built-binaries.md b/documentation/operators/src/binaries/pre-built-binaries.md index 780b13e37f..2112670418 100644 --- a/documentation/operators/src/binaries/pre-built-binaries.md +++ b/documentation/operators/src/binaries/pre-built-binaries.md @@ -15,10 +15,19 @@ If the pre-built binaries don't work or are unavailable for your system, you wil 3. Open your VPS terminal in a directory where you want to download Nym binaries. 4. Download binary by running `wget ` where `` shall be in your clipboard from point \# 2. -## Make Executable +### Make Executable -5. Run: +5. Run command: ```sh chmod +x ``` +### Run Binary +Now you can use your binary, initialise and run your Nym Node. Follow the guide according to the type of your binary. + +**Node setup and usage guides:** + +* [Mix nodes](./nodes/mix-node-setup.md) +* [Gateways](./nodes/gateway-setup.md) +* [Network requesters](./nodes/network-requester-setup.md) +* [Validators](./nodes/validator-setup.md) From 8336bb000904a47e51d98e89d9118b66f1b17040 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Mon, 13 Nov 2023 15:48:14 +0100 Subject: [PATCH 68/80] comment a reduntand page --- documentation/operators/src/SUMMARY.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/operators/src/SUMMARY.md b/documentation/operators/src/SUMMARY.md index 5d1a7049bb..5300c117df 100644 --- a/documentation/operators/src/SUMMARY.md +++ b/documentation/operators/src/SUMMARY.md @@ -5,7 +5,7 @@ # Binaries - [Pre-built Binaries](binaries/pre-built-binaries.md) - - [Binary Initialisation and Configuration](binaries/init-and-config.md) + - [Building from Source](binaries/building-nym.md) From c7b3999dcf60fcd609d48fed3f2a96423dcfb201 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Mon, 13 Nov 2023 15:51:42 +0100 Subject: [PATCH 69/80] add command example --- documentation/operators/src/binaries/pre-built-binaries.md | 1 + 1 file changed, 1 insertion(+) diff --git a/documentation/operators/src/binaries/pre-built-binaries.md b/documentation/operators/src/binaries/pre-built-binaries.md index 2112670418..1e7a6c768f 100644 --- a/documentation/operators/src/binaries/pre-built-binaries.md +++ b/documentation/operators/src/binaries/pre-built-binaries.md @@ -20,6 +20,7 @@ If the pre-built binaries don't work or are unavailable for your system, you wil 5. Run command: ```sh chmod +x +# for example: chmod +x nym-mixnode ``` ### Run Binary From 3d82f84e1da068d40bc6b60aa6e26e088f42cd9d Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Mon, 13 Nov 2023 15:52:16 +0100 Subject: [PATCH 70/80] correct link path --- .../operators/src/binaries/pre-built-binaries.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/documentation/operators/src/binaries/pre-built-binaries.md b/documentation/operators/src/binaries/pre-built-binaries.md index 1e7a6c768f..1256df3d19 100644 --- a/documentation/operators/src/binaries/pre-built-binaries.md +++ b/documentation/operators/src/binaries/pre-built-binaries.md @@ -28,7 +28,7 @@ Now you can use your binary, initialise and run your Nym Node. Follow the guide **Node setup and usage guides:** -* [Mix nodes](./nodes/mix-node-setup.md) -* [Gateways](./nodes/gateway-setup.md) -* [Network requesters](./nodes/network-requester-setup.md) -* [Validators](./nodes/validator-setup.md) +* [Mix nodes](../nodes/mix-node-setup.md) +* [Gateways](../nodes/gateway-setup.md) +* [Network requesters](../nodes/network-requester-setup.md) +* [Validators](../nodes/validator-setup.md) From 05eb05643fe4c5ca7242886988c4084b6e28f2d9 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Mon, 13 Nov 2023 15:53:54 +0100 Subject: [PATCH 71/80] correct link path --- documentation/operators/src/introduction.md | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/documentation/operators/src/introduction.md b/documentation/operators/src/introduction.md index 27d9ab63db..e12497a791 100644 --- a/documentation/operators/src/introduction.md +++ b/documentation/operators/src/introduction.md @@ -9,18 +9,17 @@ If you want to dive deeper into Nym's architecture, clients, nodes, and SDK exam ## Popular pages **Binary Information** -* [Building Nym](./binaries/building-nym.md) -* [Pre-built Binaries](./binaries/pre-built-binaries.md) -* [Init & Configuration](./binaries/init-and-config.md) +* [Building Nym](binaries/building-nym.md) +* [Pre-built Binaries](binaries/pre-built-binaries.md) **Node setup and usage guides:** -* [Mix nodes](./nodes/mix-node-setup.md) -* [Gateways](./nodes/gateway-setup.md) -* [Network requesters](./nodes/network-requester-setup.md) -* [Validators](./nodes/validator-setup.md) +* [Mix nodes](nodes/mix-node-setup.md) +* [Gateways](nodes/gateway-setup.md) +* [Network requesters](nodes/network-requester-setup.md) +* [Validators](nodes/validator-setup.md) **Maintenance, troubleshooting and FAQ** -* [Maintenance](./nodes/maintenance.md) -* [Troubleshooting](./nodes/troubleshooting.md) -* [FAQ](./faq/mixnodes-faq.md) +* [Maintenance](nodes/maintenance.md) +* [Troubleshooting](nodes/troubleshooting.md) +* [FAQ](faq/mixnodes-faq.md) From 457d1e86154bebc5c3cd703ef6e0103c486b5e45 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Mon, 13 Nov 2023 17:33:21 +0100 Subject: [PATCH 72/80] syntax edit --- documentation/operators/src/nodes/network-requester-setup.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/operators/src/nodes/network-requester-setup.md b/documentation/operators/src/nodes/network-requester-setup.md index fa5528c7d6..90bd37d3fe 100644 --- a/documentation/operators/src/nodes/network-requester-setup.md +++ b/documentation/operators/src/nodes/network-requester-setup.md @@ -166,7 +166,7 @@ Now that we have initialized our network-requester, we can start it with the fol ## Using your Network Requester -The next thing to do is use your requester, share its address with friends (or whoever you want to help privacy-enhance their app traffic). Is this safe to do? If it was an open proxy, this would be unsafe, because any Nym user could make Network requests to any system on the internet. +The next thing to do is use your requester, share its address with friends (or whoever you want to help privacy-enhance their app traffic). Is this safe to do? If it was an open proxy, this would be unsafe, because any Nym user could make network requests to any system on the internet. To make things a bit less stressful for administrators, the Network Requester drops all incoming requests by default. In order for it to make requests, you need to add specific domains to the `allowed.list` file at `$HOME/.nym/service-providers/network-requester/allowed.list` or if Network Requester is ran as a part of [Exit Gateway](./gateway-setup.md#initialising-gateway-with-network-requester), the `allowed.list` will be stored in `~/.nym/gateways//data/network-requester-data/allowed.list` From a1c9b9b4bb8d4dda0dc6c47ce91c24f3ad88a0f9 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Mon, 13 Nov 2023 17:33:54 +0100 Subject: [PATCH 73/80] syntax edit --- documentation/operators/src/nodes/gateway-setup.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/operators/src/nodes/gateway-setup.md b/documentation/operators/src/nodes/gateway-setup.md index 1c1fd3414c..4ecf649cf4 100644 --- a/documentation/operators/src/nodes/gateway-setup.md +++ b/documentation/operators/src/nodes/gateway-setup.md @@ -206,7 +206,7 @@ You can bond your Gateway via the Desktop wallet. Make sure your Gateway is runn ./nym-gateway sign --id --contract-msg ``` -It will look something like this (as `` we used `supergateway`: +It will look something like this (as `` we used `supergateway`): ~~~admonish example collapsible=true title="Console output" ``` From 435a60aee9eea5fae921ffa85099794540d8e1e9 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Mon, 13 Nov 2023 17:34:55 +0100 Subject: [PATCH 74/80] syntax edit --- documentation/operators/src/nodes/gateway-setup.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/operators/src/nodes/gateway-setup.md b/documentation/operators/src/nodes/gateway-setup.md index 4ecf649cf4..76aeae2aa9 100644 --- a/documentation/operators/src/nodes/gateway-setup.md +++ b/documentation/operators/src/nodes/gateway-setup.md @@ -50,7 +50,7 @@ You can also check the various arguments required for individual commands with: ## Initialising your Gateway -As Nym developers build towards [Exit Gateway](../legal/exit-gateway.md) functionality, operators can now run their `nym-gateway` binary with in-build Network Requester and include the our new [exit policy](https://nymtech.net/.wellknown/network-requester/exit-policy.txt). Considering the plan to [*smoosh*](../faq/smoosh-faq.md) all the nodes into one binary and have wide opened Exit Gateways, we recommend this setup, instead of operating two separate binaries. +As Nym developers build towards [Exit Gateway](../legal/exit-gateway.md) functionality, operators can now run their `nym-gateway` binary with inbuilt Network Requester and include the our new [exit policy](https://nymtech.net/.wellknown/network-requester/exit-policy.txt). Considering the plan to [*smoosh*](../faq/smoosh-faq.md) all the nodes into one binary and have wide opened Exit Gateways, we recommend this setup, instead of operating two separate binaries. ```admonish warning Before you start an Exit Gateway, read our [Operators Legal Forum](../legal/exit-gateway.md) page and [*Project Smoosh FAQ*](../faq/smoosh-faq.md). From 354c529cea36e21d083e41e0e39789d03b603fcf Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Mon, 13 Nov 2023 17:35:33 +0100 Subject: [PATCH 75/80] syntax edit --- documentation/operators/src/legal/exit-gateway.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/operators/src/legal/exit-gateway.md b/documentation/operators/src/legal/exit-gateway.md index 4cbc66bc5e..e1605f9045 100644 --- a/documentation/operators/src/legal/exit-gateway.md +++ b/documentation/operators/src/legal/exit-gateway.md @@ -80,7 +80,7 @@ We also recommend operators to check the technical advice from [Tor](https://com ## Tor legal advice -Giving the legal similarity between Nym Exit Gateways and Tor exit relays, it is helpful to have a look in [Tor community Exit Guidelines](https://community.torproject.org/relay/community-resources/tor-exit-guidelines/). This chapter is an exert of tor page. +Giving the legal similarity between Nym Exit Gateways and Tor Exit Relays, it is helpful to have a look in [Tor community Exit Guidelines](https://community.torproject.org/relay/community-resources/tor-exit-guidelines/). This chapter is an exert of tor page. Note that Tor states: > This FAQ is for informational purposes only and does not constitute legal advice. From 59d43e1acdcfd55bc9bc7dbab695f96a6cc3abf8 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Mon, 13 Nov 2023 17:36:33 +0100 Subject: [PATCH 76/80] spell check --- documentation/operators/src/legal/exit-gateway.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/operators/src/legal/exit-gateway.md b/documentation/operators/src/legal/exit-gateway.md index e1605f9045..8d0ac54682 100644 --- a/documentation/operators/src/legal/exit-gateway.md +++ b/documentation/operators/src/legal/exit-gateway.md @@ -66,7 +66,7 @@ The new setup: Running nodes supporting traffic of any online service (with safe ## Exit Gateways: New setup -In our previous technical setup, network Requesters acted as a proxy, and only made requests that match an allow list. That was a default IP based list of allowed domains stored at Nym page in a centralised fashion possibly re-defined by any Network Requester operator. +In our previous technical setup, Network Requesters acted as a proxy, and only made requests that match an allow list. That was a default IP based list of allowed domains stored at Nym page in a centralised fashion possibly re-defined by any Network Requester operator. This restricts the hosts that the NymConnect app can connect to and has the effect of selectively supporting messaging services (e.g. Telegram, Matrix) or crypto wallets (e.g. Electrum or Monero). Operators of Network Requesters can have confidence that the infrastructure they run only connects to a limited set of public internet hosts. From a2fd78963cbc2846643ec647ad15bf352941ca6f Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Mon, 13 Nov 2023 17:39:03 +0100 Subject: [PATCH 77/80] spell check --- documentation/operators/src/faq/smoosh-faq.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/documentation/operators/src/faq/smoosh-faq.md b/documentation/operators/src/faq/smoosh-faq.md index 5d131f4320..cb58eb5bc4 100644 --- a/documentation/operators/src/faq/smoosh-faq.md +++ b/documentation/operators/src/faq/smoosh-faq.md @@ -14,7 +14,7 @@ If any questions are not answered or it's not clear for you in which stage proje As we shared in our blog post article [*What does it take to build the wolds most powerful VPN*](https://blog.nymtech.net/what-does-it-take-to-build-the-worlds-most-powerful-vpn-d351a76ec4e6), project Smoosh is: -> A nick-name by CTO Dave Hrycyszyn and Chief Scientist Claudia Diaz for the work they are currently doing to “smoosh” Nym nodes so that the same operator can serve alternately as Mix node, Gateway or VPN node. This requires careful calibration of the Nym token economics, for example, only nodes with the highest reputation for good quality service will be in the VPN set and have the chance to earn higher rewards. +> A nick-name by CTO Dave Hrycyszyn and Chief Scientist Claudia Diaz for the work they are currently doing to “smoosh” Nym Nodes so that the same operator can serve alternately as Mix Node, Gateway or VPN node. This requires careful calibration of the Nym token economics, for example, only nodes with the highest reputation for good quality service will be in the VPN set and have the chance to earn higher rewards. > By simplifying the components, adding VPN features and supporting new node operators, the aim is to widen the geographical coverage of nodes and have significant redundancy, meaning plenty of operators to be able to meet demand. This requires strong token economic incentives as well as training and support for new node operators. ## Technical Questions @@ -38,7 +38,7 @@ We are exploring two potential methods for implementing binary functionality in 2. All nodes will be required to have the Exit Gateway functionality. All nodes are rewarded the same as now, and the difference is that a node sometimes (some epochs) may be performing as Exit Gateway sometimes as Mix node or Entry Gateway adjusted according the network demand by an algorithm. -### Where can I read more about the exit Gateway setup? +### Where can I read more about the Exit Gateway setup? We created an [entire page](../legal/exit-gateway.md) about the technical and legal questions around Exit Gateway. From 8d51cd1afdd338f7d55e01ec61d67e473cb7ad91 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Mon, 13 Nov 2023 17:40:30 +0100 Subject: [PATCH 78/80] spell check --- documentation/operators/src/faq/mixnodes-faq.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/operators/src/faq/mixnodes-faq.md b/documentation/operators/src/faq/mixnodes-faq.md index bd1b3fa413..c6b81bb3f0 100644 --- a/documentation/operators/src/faq/mixnodes-faq.md +++ b/documentation/operators/src/faq/mixnodes-faq.md @@ -22,7 +22,7 @@ Consider in which jurisdiction you reside and where do you want to run a Mix Nod The sizes are shown in the configs [here](https://github.com/nymtech/nym/blob/1ba6444e722e7757f1175a296bed6e31e25b8db8/common/nymsphinx/params/src/packet_sizes.rs#L12) (default is the one clients use, the others are for research purposes, not to be used in production as this would fragment the anonymity set). More info can be found [here](https://github.com/nymtech/nym/blob/4844ac953a12b29fa27688609ec193f1d560c996/common/nymsphinx/anonymous-replies/src/reply_surb.rs#L80). -### Why a Mix Node and a Gateway cannot be bond to the same wallet? +### Why a Mix Node and a Gateway cannot be bonded with the same wallet? Because of the way the smart contract works we keep it one-node one-address at the moment. From 05e349cf37f42bdff16c9381d4fddf6d1b657c98 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Mon, 13 Nov 2023 17:44:33 +0100 Subject: [PATCH 79/80] spell check --- documentation/dev-portal/src/tutorials/firo.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/dev-portal/src/tutorials/firo.md b/documentation/dev-portal/src/tutorials/firo.md index 594bf8f5aa..056a4f10f6 100644 --- a/documentation/dev-portal/src/tutorials/firo.md +++ b/documentation/dev-portal/src/tutorials/firo.md @@ -1,6 +1,6 @@ # Firo-Electrum Wallet NymConnect Integration -[Firo](https://github.com/firoorg/firo#firo) (formerly Zcoin) is a privacy focused, zk-proofs based cryptocurency. Now users can enjoy Firo with network privacy by Nym as Firo's fork of Electrum wallet was integrated to work behind the Mixnet. Read more about Firo on their [official webpage](https://firo.org/). +[Firo](https://github.com/firoorg/firo#firo) (formerly Zcoin) is a privacy focused, zk-proof based cryptocurrency. Now users can enjoy Firo with network privacy by Nym as Firo's fork of Electrum wallet was integrated to work behind the Mixnet. Read more about Firo on their [official webpage](https://firo.org/). ## How can I use Firo over the Nym Mixnet? From ee99843b51942c2544f03f0a94abd9f34d79b6d2 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Mon, 13 Nov 2023 18:46:56 +0100 Subject: [PATCH 80/80] correction point ordering - PR finished --- documentation/dev-portal/src/tutorials/firo.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/documentation/dev-portal/src/tutorials/firo.md b/documentation/dev-portal/src/tutorials/firo.md index 056a4f10f6..db09a87d79 100644 --- a/documentation/dev-portal/src/tutorials/firo.md +++ b/documentation/dev-portal/src/tutorials/firo.md @@ -28,9 +28,9 @@ chmod +x ./nym-connect_ To download Firo Electrum wallet visit the [Firo's repository](https://github.com/firoorg/firo) or [Github release page](https://github.com/firoorg/electrum-firo/releases/tag/4.1.5.2). To connect to the Mixnet follow these steps: 7. Start and connect [NymConnect](./firo.md#nymconnect-installation) (or [`nym-socks5-client`](https://nymtech.net/docs/clients/socks5-client.html)) -2. Start your Firo Electrum wallet -3. Go to: *Tools* -> *Network* -> *Proxy* -4. Set *Use proxy* to ✅, choose `SOCKS5` from the drop-down and add the values from your NymConnect application -5. Now your Firo Electrum wallet runs through the Mixnet and it will be connected only if your NymConnect or `nym-socks5-client` are connected. +8. Start your Firo Electrum wallet +9. Go to: *Tools* -> *Network* -> *Proxy* +10. Set *Use proxy* to ✅, choose `SOCKS5` from the drop-down and add the values from your NymConnect application +11. Now your Firo Electrum wallet runs through the Mixnet and it will be connected only if your NymConnect or `nym-socks5-client` are connected. ![Firo Electrum wallet setup](../images/firo_tutorial/firo.png)