Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d1a8dd45f4 |
@@ -79,6 +79,7 @@ jobs:
|
||||
target/release/nym-socks5-client
|
||||
target/release/nym-api
|
||||
target/release/nym-network-requester
|
||||
target/release/nym-data-observatory
|
||||
target/release/nym-cli
|
||||
target/release/nymvisor
|
||||
target/release/nym-node
|
||||
@@ -96,6 +97,7 @@ jobs:
|
||||
cp target/release/nym-socks5-client $OUTPUT_DIR
|
||||
cp target/release/nym-api $OUTPUT_DIR
|
||||
cp target/release/nym-network-requester $OUTPUT_DIR
|
||||
cp target/release/nym-data-observatory $OUTPUT_DIR
|
||||
cp target/release/nymvisor $OUTPUT_DIR
|
||||
cp target/release/nym-node $OUTPUT_DIR
|
||||
cp target/release/nym-cli $OUTPUT_DIR
|
||||
|
||||
@@ -8,18 +8,17 @@ on:
|
||||
- 'explorer-api/**'
|
||||
- 'gateway/**'
|
||||
- 'integrations/**'
|
||||
- 'mixnode/**'
|
||||
- 'nym-api/**'
|
||||
- 'nym-credential-proxy/**'
|
||||
- 'nym-data-observatory/**'
|
||||
- 'nym-network-monitor/**'
|
||||
- 'nym-node/**'
|
||||
- 'nym-node-status-api/**'
|
||||
- 'nym-outfox/**'
|
||||
- 'nym-validator-rewarder/**'
|
||||
- 'nyx-chain-watcher/**'
|
||||
- 'sdk/ffi/**'
|
||||
- 'sdk/lib/**'
|
||||
- 'sdk/rust/**'
|
||||
- 'service-providers/**'
|
||||
- 'nym-browser-extension/storage/**'
|
||||
- 'tools/**'
|
||||
- 'wasm/**'
|
||||
- 'Cargo.toml'
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
name: ci-sdk-wasm
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
pull_request:
|
||||
paths:
|
||||
- 'wasm/**'
|
||||
|
||||
Generated
+101
-364
File diff suppressed because it is too large
Load Diff
+36
-34
@@ -53,8 +53,8 @@ members = [
|
||||
"common/execute",
|
||||
"common/exit-policy",
|
||||
"common/gateway-requests",
|
||||
"common/gateway-stats-storage",
|
||||
"common/gateway-storage",
|
||||
"common/gateway-stats-storage",
|
||||
"common/http-api-client",
|
||||
"common/http-api-common",
|
||||
"common/inclusion-probability",
|
||||
@@ -93,7 +93,6 @@ members = [
|
||||
"common/topology",
|
||||
"common/tun",
|
||||
"common/types",
|
||||
"common/verloc",
|
||||
"common/wasm/client-core",
|
||||
"common/wasm/storage",
|
||||
"common/wasm/utils",
|
||||
@@ -105,22 +104,6 @@ members = [
|
||||
"explorer-api/explorer-client",
|
||||
"gateway",
|
||||
"integrations/bity",
|
||||
"nym-api",
|
||||
"nym-api/nym-api-requests",
|
||||
"nym-browser-extension/storage",
|
||||
"nym-credential-proxy/nym-credential-proxy",
|
||||
"nym-credential-proxy/nym-credential-proxy-requests",
|
||||
"nym-credential-proxy/vpn-api-lib-wasm",
|
||||
"nym-network-monitor",
|
||||
"nym-node",
|
||||
"nym-node-status-api/nym-node-status-agent",
|
||||
"nym-node-status-api/nym-node-status-api",
|
||||
"nym-node-status-api/nym-node-status-client",
|
||||
"nym-node/nym-node-metrics",
|
||||
"nym-node/nym-node-requests",
|
||||
"nym-outfox",
|
||||
"nym-validator-rewarder",
|
||||
"nyx-chain-watcher",
|
||||
"sdk/ffi/cpp",
|
||||
"sdk/ffi/go",
|
||||
"sdk/ffi/shared",
|
||||
@@ -129,16 +112,26 @@ members = [
|
||||
"service-providers/common",
|
||||
"service-providers/ip-packet-router",
|
||||
"service-providers/network-requester",
|
||||
"nym-api",
|
||||
"nym-api/nym-api-requests",
|
||||
"nym-browser-extension/storage",
|
||||
"nym-credential-proxy/nym-credential-proxy",
|
||||
"nym-credential-proxy/nym-credential-proxy-requests",
|
||||
"nym-credential-proxy/vpn-api-lib-wasm",
|
||||
"nym-network-monitor",
|
||||
"nyx-chain-watcher",
|
||||
"nym-node",
|
||||
"nym-node/nym-node-requests",
|
||||
"nym-node/nym-node-metrics",
|
||||
"nym-node-status-api/nym-node-status-agent",
|
||||
"nym-node-status-api/nym-node-status-api",
|
||||
"nym-node-status-api/nym-node-status-client",
|
||||
"nym-outfox",
|
||||
"nym-validator-rewarder",
|
||||
"tools/echo-server",
|
||||
"tools/echo-server",
|
||||
"tools/internal/contract-state-importer/importer-cli",
|
||||
"tools/internal/contract-state-importer/importer-contract",
|
||||
"tools/internal/mixnet-connectivity-check",
|
||||
# "tools/internal/sdk-version-bump",
|
||||
"tools/internal/ssl-inject",
|
||||
# "tools/internal/sdk-version-bump",
|
||||
"tools/internal/testnet-manager",
|
||||
"tools/internal/testnet-manager",
|
||||
"tools/internal/testnet-manager/dkg-bypass-contract",
|
||||
"tools/internal/testnet-manager/dkg-bypass-contract",
|
||||
"tools/nym-cli",
|
||||
"tools/nym-id-cli",
|
||||
@@ -150,6 +143,13 @@ members = [
|
||||
"wasm/mix-fetch",
|
||||
"wasm/node-tester",
|
||||
"wasm/zknym-lib",
|
||||
"tools/echo-server",
|
||||
"tools/internal/contract-state-importer/importer-cli",
|
||||
"tools/internal/contract-state-importer/importer-contract",
|
||||
"tools/internal/testnet-manager",
|
||||
"tools/internal/testnet-manager/dkg-bypass-contract",
|
||||
"common/verloc",
|
||||
"tools/internal/mixnet-connectivity-check",
|
||||
]
|
||||
|
||||
default-members = [
|
||||
@@ -173,6 +173,7 @@ exclude = [
|
||||
"explorer",
|
||||
"contracts",
|
||||
"nym-wallet",
|
||||
"nym-vpn/ui/src-tauri",
|
||||
"cpu-cycles",
|
||||
]
|
||||
|
||||
@@ -193,7 +194,6 @@ aes-gcm = "0.10.1"
|
||||
aes-gcm-siv = "0.11.1"
|
||||
aead = "0.5.2"
|
||||
anyhow = "1.0.95"
|
||||
arc-swap = "1.7.1"
|
||||
argon2 = "0.5.0"
|
||||
async-trait = "0.1.85"
|
||||
axum-client-ip = "0.6.1"
|
||||
@@ -254,7 +254,6 @@ handlebars = "3.5.5"
|
||||
headers = "0.4.0"
|
||||
hex = "0.4.3"
|
||||
hex-literal = "0.3.3"
|
||||
hickory-resolver = "0.24.2"
|
||||
hkdf = "0.12.3"
|
||||
hmac = "0.12.1"
|
||||
http = "1"
|
||||
@@ -325,7 +324,7 @@ strum = "0.26"
|
||||
strum_macros = "0.26"
|
||||
subtle-encoding = "0.5"
|
||||
syn = "1"
|
||||
sysinfo = "0.33.0"
|
||||
sysinfo = "0.30.13"
|
||||
tap = "1.0.1"
|
||||
tar = "0.4.43"
|
||||
tempfile = "3.15"
|
||||
@@ -387,17 +386,20 @@ cw-controllers = { version = "=1.1.0" }
|
||||
# cosmrs-related
|
||||
bip32 = { version = "0.5.2", default-features = false }
|
||||
|
||||
|
||||
cosmrs = { version = "0.21.0" }
|
||||
tendermint = "0.40.0"
|
||||
tendermint-rpc = "0.40.0"
|
||||
prost = { version = "0.13", default-features = false }
|
||||
# temporarily using a fork again (yay.) because we need staking and slashing support (which are already on main but not released)
|
||||
# plus response message parsing (which is, as of the time of writing this message, waiting to get merged)
|
||||
#cosmrs = { path = "../cosmos-rust-fork/cosmos-rust/cosmrs" }
|
||||
cosmrs = { git = "https://github.com/cosmos/cosmos-rust", rev = "4b1332e6d8258ac845cef71589c8d362a669675a" } # unfortuntely we need a fork by yours truly to get the staking support
|
||||
tendermint = "0.37.0" # same version as used by cosmrs
|
||||
tendermint-rpc = "0.37.0" # same version as used by cosmrs
|
||||
prost = { version = "0.12", default-features = false }
|
||||
|
||||
# wasm-related dependencies
|
||||
gloo-utils = "0.2.0"
|
||||
gloo-net = "0.6.0"
|
||||
|
||||
indexed_db_futures = "0.6.0"
|
||||
# TODO: migrate to 0.6+
|
||||
indexed_db_futures = "0.4.2"
|
||||
js-sys = "0.3.76"
|
||||
serde-wasm-bindgen = "0.6.5"
|
||||
tsify = "0.4.5"
|
||||
|
||||
@@ -13,7 +13,7 @@ The platform is composed of multiple Rust crates. Top-level executable binary cr
|
||||
* `nym-client` - an executable which you can build into your own applications. Use it for interacting with Nym nodes.
|
||||
* `nym-socks5-client` - a Socks5 proxy you can run on your machine and use with existing applications.
|
||||
* `nym-explorer` - a (projected) block explorer and (existing) mixnet viewer.
|
||||
* `nym-wallet` - a desktop wallet implemented using the [Tauri](https://tauri.app)) framework.
|
||||
* `nym-wallet` - a desktop wallet implemented using the [Tauri](https://tauri.studio/en/docs/about/intro) framework.
|
||||
* `nym-cli` - a tool for interacting with the network from the CLI.
|
||||
<!-- coming soon
|
||||
* `nym-network-monitor` - sends packets through the full system to check that they are working as expected, and stores node uptime histories as the basis of a rewards system ("mixmining" or "proof-of-mixing").
|
||||
@@ -66,4 +66,4 @@ As a general approach, licensing is as follows this pattern:
|
||||
- libraries and components are Apache 2.0 or MIT
|
||||
- documentation is Apache 2.0 or CC0-1.0
|
||||
|
||||
Nym Node Operators and Validators Terms and Conditions can be found [here](https://nym.com/operators-validators-terms).
|
||||
Nym Node Operators and Validators Temrs and Conditions can be found [here](https://nym.com/terms-and-conditions/operators/v1.0.0).
|
||||
|
||||
@@ -553,6 +553,7 @@ pub struct Topology {
|
||||
|
||||
/// Specifies whether this client should attempt to retrieve all available network nodes
|
||||
/// as opposed to just active mixnodes/gateways.
|
||||
/// Useless without `ignore_epoch_roles = true`
|
||||
pub use_extended_topology: bool,
|
||||
|
||||
/// Specifies whether this client should ignore the current epoch role of the target egress node
|
||||
|
||||
@@ -15,7 +15,6 @@ pub mod error;
|
||||
mod manager;
|
||||
mod models;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct OnDiskGatewaysDetails {
|
||||
manager: StorageManager,
|
||||
}
|
||||
|
||||
@@ -20,12 +20,12 @@ pub enum InMemStorageError {
|
||||
MalformedGateway(#[from] BadGateway),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
#[derive(Debug, Default)]
|
||||
pub struct InMemGatewaysDetails {
|
||||
inner: Arc<RwLock<InMemStorageInner>>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
#[derive(Debug, Default)]
|
||||
struct InMemStorageInner {
|
||||
active_gateway: Option<String>,
|
||||
gateways: HashMap<String, GatewayRegistration>,
|
||||
|
||||
@@ -115,7 +115,7 @@ where
|
||||
hardcoded_topology.entry_capable_nodes().cloned().collect()
|
||||
} else {
|
||||
let mut rng = rand::thread_rng();
|
||||
crate::init::helpers::gateways_for_init(
|
||||
crate::init::helpers::current_gateways(
|
||||
&mut rng,
|
||||
&core.client.nym_api_urls,
|
||||
user_agent,
|
||||
|
||||
@@ -170,7 +170,7 @@ where
|
||||
hardcoded_topology.entry_capable_nodes().cloned().collect()
|
||||
} else {
|
||||
let mut rng = rand::thread_rng();
|
||||
crate::init::helpers::gateways_for_init(
|
||||
crate::init::helpers::current_gateways(
|
||||
&mut rng,
|
||||
&core.client.nym_api_urls,
|
||||
user_agent,
|
||||
|
||||
@@ -63,7 +63,7 @@ pub trait MixnetClientStorage {
|
||||
fn gateway_details_store(&self) -> &Self::GatewaysDetailsStore;
|
||||
}
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
#[derive(Default)]
|
||||
pub struct Ephemeral {
|
||||
key_store: InMemEphemeralKeys,
|
||||
reply_store: reply_storage::Empty,
|
||||
@@ -114,7 +114,6 @@ impl MixnetClientStorage for Ephemeral {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
#[cfg(all(
|
||||
not(target_arch = "wasm32"),
|
||||
feature = "fs-surb-storage",
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
use crate::client::key_manager::ClientKeys;
|
||||
use async_trait::async_trait;
|
||||
use std::error::Error;
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::Mutex;
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
@@ -65,7 +64,6 @@ pub enum OnDiskKeysError {
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
pub struct OnDiskKeys {
|
||||
paths: ClientKeysPaths,
|
||||
@@ -195,9 +193,9 @@ impl KeyStore for OnDiskKeys {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
#[derive(Default)]
|
||||
pub struct InMemEphemeralKeys {
|
||||
keys: Arc<Mutex<Option<ClientKeys>>>,
|
||||
keys: Mutex<Option<ClientKeys>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
|
||||
@@ -86,7 +86,7 @@ impl<'a, G: ConnectableGateway> GatewayWithLatency<'a, G> {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn gateways_for_init<R: Rng>(
|
||||
pub async fn current_gateways<R: Rng>(
|
||||
rng: &mut R,
|
||||
nym_apis: &[Url],
|
||||
user_agent: Option<UserAgent>,
|
||||
@@ -108,11 +108,8 @@ pub async fn gateways_for_init<R: Rng>(
|
||||
|
||||
log::trace!("Gateways: {:#?}", gateways);
|
||||
|
||||
// filter out gateways below minimum performance and ones that could operate as a mixnode
|
||||
// (we don't want instability)
|
||||
let valid_gateways = gateways
|
||||
.iter()
|
||||
.filter(|g| !g.supported_roles.mixnode)
|
||||
.filter(|g| g.performance.round_to_integer() >= minimum_performance)
|
||||
.filter_map(|gateway| gateway.try_into().ok())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
@@ -22,7 +22,7 @@ mod error;
|
||||
mod manager;
|
||||
mod models;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Debug)]
|
||||
pub struct Backend {
|
||||
temporary_old_path: Option<PathBuf>,
|
||||
database_path: PathBuf,
|
||||
|
||||
@@ -19,7 +19,7 @@ pub mod fs_backend;
|
||||
#[error("no information provided")]
|
||||
pub struct UndefinedError;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Debug)]
|
||||
pub struct Empty {
|
||||
// we need to keep 'basic' metadata here to "load" the CombinedReplyStorage
|
||||
pub min_surb_threshold: usize,
|
||||
|
||||
@@ -19,9 +19,8 @@ use nym_api_requests::ecash::{
|
||||
PartialExpirationDateSignatureResponse, VerificationKeyResponse,
|
||||
};
|
||||
use nym_api_requests::models::{
|
||||
ApiHealthResponse, GatewayBondAnnotated, GatewayCoreStatusResponse,
|
||||
HistoricalPerformanceResponse, MixnodeCoreStatusResponse, MixnodeStatusResponse,
|
||||
NymNodeDescription, RewardEstimationResponse, StakeSaturationResponse,
|
||||
ApiHealthResponse, GatewayBondAnnotated, GatewayCoreStatusResponse, MixnodeCoreStatusResponse,
|
||||
MixnodeStatusResponse, NymNodeDescription, RewardEstimationResponse, StakeSaturationResponse,
|
||||
};
|
||||
use nym_api_requests::models::{LegacyDescribedGateway, MixNodeBondAnnotated};
|
||||
use nym_api_requests::nym_nodes::SkimmedNode;
|
||||
@@ -265,31 +264,6 @@ impl<C, S> Client<C, S> {
|
||||
Ok(self.nym_api.get_gateways_detailed_unfiltered().await?)
|
||||
}
|
||||
|
||||
pub async fn get_full_node_performance_history(
|
||||
&self,
|
||||
node_id: NodeId,
|
||||
) -> Result<Vec<HistoricalPerformanceResponse>, ValidatorClientError> {
|
||||
// TODO: deal with paging in macro or some helper function or something, because it's the same pattern everywhere
|
||||
let mut page = 0;
|
||||
let mut history = Vec::new();
|
||||
|
||||
loop {
|
||||
let mut res = self
|
||||
.nym_api
|
||||
.get_node_performance_history(node_id, Some(page), None)
|
||||
.await?;
|
||||
|
||||
history.append(&mut res.history.data);
|
||||
if history.len() < res.history.pagination.total {
|
||||
page += 1
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(history)
|
||||
}
|
||||
|
||||
// TODO: combine with NymApiClient...
|
||||
pub async fn get_all_cached_described_nodes(
|
||||
&self,
|
||||
|
||||
@@ -13,7 +13,7 @@ use nym_api_requests::ecash::models::{
|
||||
use nym_api_requests::ecash::VerificationKeyResponse;
|
||||
use nym_api_requests::models::{
|
||||
AnnotationResponse, ApiHealthResponse, LegacyDescribedMixNode, NodePerformanceResponse,
|
||||
NodeRefreshBody, NymNodeDescription, PerformanceHistoryResponse, RewardedSetResponse,
|
||||
NodeRefreshBody, NymNodeDescription, RewardedSetResponse,
|
||||
};
|
||||
use nym_api_requests::nym_nodes::PaginatedCachedNodesResponse;
|
||||
use nym_api_requests::pagination::PaginatedResponse;
|
||||
@@ -163,35 +163,6 @@ pub trait NymApiClientExt: ApiClient {
|
||||
.await
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "debug", skip_all)]
|
||||
async fn get_node_performance_history(
|
||||
&self,
|
||||
node_id: NodeId,
|
||||
page: Option<u32>,
|
||||
per_page: Option<u32>,
|
||||
) -> Result<PerformanceHistoryResponse, NymAPIError> {
|
||||
let mut params = Vec::new();
|
||||
|
||||
if let Some(page) = page {
|
||||
params.push(("page", page.to_string()))
|
||||
}
|
||||
|
||||
if let Some(per_page) = per_page {
|
||||
params.push(("per_page", per_page.to_string()))
|
||||
}
|
||||
|
||||
self.get_json(
|
||||
&[
|
||||
routes::API_VERSION,
|
||||
routes::NYM_NODES_ROUTES,
|
||||
routes::NYM_NODES_PERFORMANCE_HISTORY,
|
||||
&*node_id.to_string(),
|
||||
],
|
||||
¶ms,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "debug", skip_all)]
|
||||
async fn get_nodes_described(
|
||||
&self,
|
||||
@@ -208,15 +179,8 @@ pub trait NymApiClientExt: ApiClient {
|
||||
params.push(("per_page", per_page.to_string()))
|
||||
}
|
||||
|
||||
self.get_json(
|
||||
&[
|
||||
routes::API_VERSION,
|
||||
routes::NYM_NODES_ROUTES,
|
||||
routes::NYM_NODES_DESCRIBED,
|
||||
],
|
||||
¶ms,
|
||||
)
|
||||
.await
|
||||
self.get_json(&[routes::API_VERSION, "nym-nodes", "described"], ¶ms)
|
||||
.await
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "debug", skip_all)]
|
||||
@@ -235,15 +199,8 @@ pub trait NymApiClientExt: ApiClient {
|
||||
params.push(("per_page", per_page.to_string()))
|
||||
}
|
||||
|
||||
self.get_json(
|
||||
&[
|
||||
routes::API_VERSION,
|
||||
routes::NYM_NODES_ROUTES,
|
||||
routes::NYM_NODES_BONDED,
|
||||
],
|
||||
¶ms,
|
||||
)
|
||||
.await
|
||||
self.get_json(&[routes::API_VERSION, "nym-nodes", "bonded"], ¶ms)
|
||||
.await
|
||||
}
|
||||
|
||||
#[deprecated]
|
||||
@@ -253,7 +210,7 @@ pub trait NymApiClientExt: ApiClient {
|
||||
&[
|
||||
routes::API_VERSION,
|
||||
"unstable",
|
||||
routes::NYM_NODES_ROUTES,
|
||||
"nym-nodes",
|
||||
"mixnodes",
|
||||
"skimmed",
|
||||
],
|
||||
@@ -269,7 +226,7 @@ pub trait NymApiClientExt: ApiClient {
|
||||
&[
|
||||
routes::API_VERSION,
|
||||
"unstable",
|
||||
routes::NYM_NODES_ROUTES,
|
||||
"nym-nodes",
|
||||
"gateways",
|
||||
"skimmed",
|
||||
],
|
||||
@@ -281,11 +238,7 @@ pub trait NymApiClientExt: ApiClient {
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
async fn get_rewarded_set(&self) -> Result<RewardedSetResponse, NymAPIError> {
|
||||
self.get_json(
|
||||
&[
|
||||
routes::API_VERSION,
|
||||
routes::NYM_NODES_ROUTES,
|
||||
routes::NYM_NODES_REWARDED_SET,
|
||||
],
|
||||
&[routes::API_VERSION, "nym-nodes", "rewarded-set"],
|
||||
NO_PARAMS,
|
||||
)
|
||||
.await
|
||||
@@ -318,7 +271,7 @@ pub trait NymApiClientExt: ApiClient {
|
||||
&[
|
||||
routes::API_VERSION,
|
||||
"unstable",
|
||||
routes::NYM_NODES_ROUTES,
|
||||
"nym-nodes",
|
||||
"skimmed",
|
||||
"entry-gateways",
|
||||
"all",
|
||||
@@ -355,7 +308,7 @@ pub trait NymApiClientExt: ApiClient {
|
||||
&[
|
||||
routes::API_VERSION,
|
||||
"unstable",
|
||||
routes::NYM_NODES_ROUTES,
|
||||
"nym-nodes",
|
||||
"skimmed",
|
||||
"mixnodes",
|
||||
"active",
|
||||
@@ -392,7 +345,7 @@ pub trait NymApiClientExt: ApiClient {
|
||||
&[
|
||||
routes::API_VERSION,
|
||||
"unstable",
|
||||
routes::NYM_NODES_ROUTES,
|
||||
"nym-nodes",
|
||||
"skimmed",
|
||||
"mixnodes",
|
||||
"all",
|
||||
@@ -424,12 +377,7 @@ pub trait NymApiClientExt: ApiClient {
|
||||
}
|
||||
|
||||
self.get_json(
|
||||
&[
|
||||
routes::API_VERSION,
|
||||
"unstable",
|
||||
routes::NYM_NODES_ROUTES,
|
||||
"skimmed",
|
||||
],
|
||||
&[routes::API_VERSION, "unstable", "nym-nodes", "skimmed"],
|
||||
¶ms,
|
||||
)
|
||||
.await
|
||||
@@ -738,8 +686,8 @@ pub trait NymApiClientExt: ApiClient {
|
||||
self.get_json(
|
||||
&[
|
||||
routes::API_VERSION,
|
||||
routes::NYM_NODES_ROUTES,
|
||||
routes::NYM_NODES_PERFORMANCE,
|
||||
"nym-nodes",
|
||||
"performance",
|
||||
&node_id.to_string(),
|
||||
],
|
||||
NO_PARAMS,
|
||||
@@ -754,8 +702,8 @@ pub trait NymApiClientExt: ApiClient {
|
||||
self.get_json(
|
||||
&[
|
||||
routes::API_VERSION,
|
||||
routes::NYM_NODES_ROUTES,
|
||||
routes::NYM_NODES_ANNOTATION,
|
||||
"nym-nodes",
|
||||
"annotation",
|
||||
&node_id.to_string(),
|
||||
],
|
||||
NO_PARAMS,
|
||||
@@ -979,11 +927,7 @@ pub trait NymApiClientExt: ApiClient {
|
||||
request: &NodeRefreshBody,
|
||||
) -> Result<(), NymAPIError> {
|
||||
self.post_json(
|
||||
&[
|
||||
routes::API_VERSION,
|
||||
routes::NYM_NODES_ROUTES,
|
||||
routes::NYM_NODES_REFRESH_DESCRIBED,
|
||||
],
|
||||
&[routes::API_VERSION, "nym-nodes", "refresh-described"],
|
||||
NO_PARAMS,
|
||||
request,
|
||||
)
|
||||
|
||||
@@ -34,19 +34,6 @@ pub mod ecash {
|
||||
pub const EPOCH_ID_PARAM: &str = "epoch_id";
|
||||
}
|
||||
|
||||
pub const NYM_NODES_ROUTES: &str = "nym-nodes";
|
||||
|
||||
pub use nym_nodes::*;
|
||||
pub mod nym_nodes {
|
||||
pub const NYM_NODES_PERFORMANCE_HISTORY: &str = "performance-history";
|
||||
pub const NYM_NODES_PERFORMANCE: &str = "performance";
|
||||
pub const NYM_NODES_ANNOTATION: &str = "annotation";
|
||||
pub const NYM_NODES_DESCRIBED: &str = "described";
|
||||
pub const NYM_NODES_BONDED: &str = "bonded";
|
||||
pub const NYM_NODES_REWARDED_SET: &str = "rewarded-set";
|
||||
pub const NYM_NODES_REFRESH_DESCRIBED: &str = "refresh-described";
|
||||
}
|
||||
|
||||
pub const STATUS_ROUTES: &str = "status";
|
||||
pub const API_STATUS_ROUTES: &str = "api-status";
|
||||
pub const HEALTH: &str = "health";
|
||||
|
||||
-31
@@ -153,20 +153,13 @@ pub trait CosmWasmClient: TendermintRpcClient {
|
||||
let req = QueryAllBalancesRequest {
|
||||
address: address.to_string(),
|
||||
pagination,
|
||||
resolve_denom: false,
|
||||
};
|
||||
|
||||
let mut res = self
|
||||
.make_abci_query::<_, QueryAllBalancesResponse>(path.clone(), req)
|
||||
.await?;
|
||||
|
||||
let early_break = res.balances.is_empty();
|
||||
raw_balances.append(&mut res.balances);
|
||||
|
||||
if early_break {
|
||||
break;
|
||||
}
|
||||
|
||||
if let Some(next_key) = next_page_key(res.pagination) {
|
||||
pagination = Some(create_pagination(next_key))
|
||||
} else {
|
||||
@@ -194,13 +187,7 @@ pub trait CosmWasmClient: TendermintRpcClient {
|
||||
.make_abci_query::<_, QueryTotalSupplyResponse>(path.clone(), req)
|
||||
.await?;
|
||||
|
||||
let early_break = res.supply.is_empty();
|
||||
supply.append(&mut res.supply);
|
||||
|
||||
if early_break {
|
||||
break;
|
||||
}
|
||||
|
||||
if let Some(next_key) = next_page_key(res.pagination) {
|
||||
pagination = Some(create_pagination(next_key))
|
||||
} else {
|
||||
@@ -341,13 +328,7 @@ pub trait CosmWasmClient: TendermintRpcClient {
|
||||
.make_abci_query::<_, QueryCodesResponse>(path.clone(), req)
|
||||
.await?;
|
||||
|
||||
let early_break = res.code_infos.is_empty();
|
||||
raw_codes.append(&mut res.code_infos);
|
||||
|
||||
if early_break {
|
||||
break;
|
||||
}
|
||||
|
||||
if let Some(next_key) = next_page_key(res.pagination) {
|
||||
pagination = Some(create_pagination(next_key))
|
||||
} else {
|
||||
@@ -392,13 +373,7 @@ pub trait CosmWasmClient: TendermintRpcClient {
|
||||
.make_abci_query::<_, QueryContractsByCodeResponse>(path.clone(), req)
|
||||
.await?;
|
||||
|
||||
let early_break = res.contracts.is_empty();
|
||||
raw_contracts.append(&mut res.contracts);
|
||||
|
||||
if early_break {
|
||||
break;
|
||||
}
|
||||
|
||||
if let Some(next_key) = next_page_key(res.pagination) {
|
||||
pagination = Some(create_pagination(next_key))
|
||||
} else {
|
||||
@@ -454,13 +429,7 @@ pub trait CosmWasmClient: TendermintRpcClient {
|
||||
.make_abci_query::<_, QueryContractHistoryResponse>(path.clone(), req)
|
||||
.await?;
|
||||
|
||||
let early_break = res.entries.is_empty();
|
||||
raw_entries.append(&mut res.entries);
|
||||
|
||||
if early_break {
|
||||
break;
|
||||
}
|
||||
|
||||
if let Some(next_key) = next_page_key(res.pagination) {
|
||||
pagination = Some(create_pagination(next_key))
|
||||
} else {
|
||||
|
||||
@@ -4,11 +4,9 @@
|
||||
use crate::rpc::TendermintRpcClient;
|
||||
use async_trait::async_trait;
|
||||
use base64::Engine;
|
||||
use cosmrs::tendermint;
|
||||
use cosmrs::tendermint::{block::Height, evidence::Evidence, Hash};
|
||||
use reqwest::header::HeaderMap;
|
||||
use reqwest::{header, RequestBuilder};
|
||||
use tendermint_rpc::dialect::{v0_34, v0_37, v0_38, LatestDialect};
|
||||
use tendermint_rpc::{
|
||||
client::CompatMode,
|
||||
dialect::{self, Dialect},
|
||||
@@ -23,21 +21,8 @@ macro_rules! perform_with_compat {
|
||||
($self:expr, $request:expr) => {{
|
||||
let request = $request;
|
||||
match $self.compat {
|
||||
CompatMode::V0_38 => {
|
||||
$self
|
||||
.perform_request_with_dialect(request, dialect::v0_38::Dialect)
|
||||
.await
|
||||
}
|
||||
CompatMode::V0_37 => {
|
||||
$self
|
||||
.perform_request_with_dialect(request, dialect::v0_37::Dialect)
|
||||
.await
|
||||
}
|
||||
CompatMode::V0_34 => {
|
||||
$self
|
||||
.perform_request_with_dialect(request, dialect::v0_34::Dialect)
|
||||
.await
|
||||
}
|
||||
CompatMode::V0_37 => $self.perform_v0_37(request).await,
|
||||
CompatMode::V0_34 => $self.perform_v0_34(request).await,
|
||||
}
|
||||
}};
|
||||
}
|
||||
@@ -85,11 +70,7 @@ impl ReqwestRpcClient {
|
||||
.headers(headers)
|
||||
}
|
||||
|
||||
async fn perform_request_with_dialect<R, S>(
|
||||
&self,
|
||||
request: R,
|
||||
_dialect: S,
|
||||
) -> Result<R::Output, Error>
|
||||
async fn perform_request<R, S>(&self, request: R) -> Result<R::Output, Error>
|
||||
where
|
||||
R: SimpleRequest<S>,
|
||||
S: Dialect,
|
||||
@@ -100,25 +81,26 @@ impl ReqwestRpcClient {
|
||||
.send()
|
||||
.await
|
||||
.map_err(TendermintRpcErrorMap::into_rpc_err)?;
|
||||
let response_status = response.status();
|
||||
let bytes = response
|
||||
.bytes()
|
||||
.await
|
||||
.map_err(TendermintRpcErrorMap::into_rpc_err)?;
|
||||
|
||||
// Successful JSON-RPC requests are expected to return a 200 OK HTTP status.
|
||||
// Otherwise, this means that the HTTP request failed as a whole,
|
||||
// as opposed to the JSON-RPC request returning an error,
|
||||
// and we cannot expect the response body to be a valid JSON-RPC response.
|
||||
if response_status != reqwest::StatusCode::OK {
|
||||
// hehe, that's so nasty but we have to somehow convert between different versions of the same lib
|
||||
return Err(Error::http_request_failed(
|
||||
response_status.as_u16().try_into().unwrap(),
|
||||
));
|
||||
}
|
||||
|
||||
R::Response::from_string(bytes).map(Into::into)
|
||||
}
|
||||
|
||||
async fn perform_v0_34<R>(&self, request: R) -> Result<R::Output, Error>
|
||||
where
|
||||
R: SimpleRequest<dialect::v0_34::Dialect>,
|
||||
{
|
||||
self.perform_request(request).await
|
||||
}
|
||||
|
||||
async fn perform_v0_37<R>(&self, request: R) -> Result<R::Output, Error>
|
||||
where
|
||||
R: SimpleRequest<dialect::v0_37::Dialect>,
|
||||
{
|
||||
self.perform_request(request).await
|
||||
}
|
||||
}
|
||||
|
||||
trait TendermintRpcErrorMap {
|
||||
@@ -138,50 +120,18 @@ impl TendermintRpcClient for ReqwestRpcClient {
|
||||
where
|
||||
R: SimpleRequest,
|
||||
{
|
||||
self.perform_request_with_dialect(request, LatestDialect)
|
||||
.await
|
||||
self.perform_request(request).await
|
||||
}
|
||||
|
||||
async fn block<H>(&self, height: H) -> Result<endpoint::block::Response, Error>
|
||||
async fn block_results<H>(&self, height: H) -> Result<block_results::Response, Error>
|
||||
where
|
||||
H: Into<Height> + Send,
|
||||
{
|
||||
perform_with_compat!(self, endpoint::block::Request::new(height.into()))
|
||||
perform_with_compat!(self, block_results::Request::new(height.into()))
|
||||
}
|
||||
|
||||
async fn block_by_hash(
|
||||
&self,
|
||||
hash: tendermint::Hash,
|
||||
) -> Result<endpoint::block_by_hash::Response, Error> {
|
||||
perform_with_compat!(self, endpoint::block_by_hash::Request::new(hash))
|
||||
}
|
||||
|
||||
async fn latest_block(&self) -> Result<endpoint::block::Response, Error> {
|
||||
perform_with_compat!(self, endpoint::block::Request::default())
|
||||
}
|
||||
|
||||
async fn block_results<H>(&self, height: H) -> Result<endpoint::block_results::Response, Error>
|
||||
where
|
||||
H: Into<Height> + Send,
|
||||
{
|
||||
perform_with_compat!(self, endpoint::block_results::Request::new(height.into()))
|
||||
}
|
||||
|
||||
async fn latest_block_results(&self) -> Result<endpoint::block_results::Response, Error> {
|
||||
perform_with_compat!(self, endpoint::block_results::Request::default())
|
||||
}
|
||||
|
||||
async fn block_search(
|
||||
&self,
|
||||
query: Query,
|
||||
page: u32,
|
||||
per_page: u8,
|
||||
order: Order,
|
||||
) -> Result<endpoint::block_search::Response, Error> {
|
||||
perform_with_compat!(
|
||||
self,
|
||||
endpoint::block_search::Request::new(query, page, per_page, order)
|
||||
)
|
||||
async fn latest_block_results(&self) -> Result<block_results::Response, Error> {
|
||||
perform_with_compat!(self, block_results::Request::default())
|
||||
}
|
||||
|
||||
async fn header<H>(&self, height: H) -> Result<endpoint::header::Response, Error>
|
||||
@@ -190,26 +140,11 @@ impl TendermintRpcClient for ReqwestRpcClient {
|
||||
{
|
||||
let height = height.into();
|
||||
match self.compat {
|
||||
CompatMode::V0_38 => {
|
||||
self.perform_request_with_dialect(
|
||||
endpoint::header::Request::new(height),
|
||||
v0_38::Dialect,
|
||||
)
|
||||
.await
|
||||
}
|
||||
CompatMode::V0_37 => {
|
||||
self.perform_request_with_dialect(
|
||||
endpoint::header::Request::new(height),
|
||||
v0_37::Dialect,
|
||||
)
|
||||
.await
|
||||
}
|
||||
CompatMode::V0_37 => self.perform(endpoint::header::Request::new(height)).await,
|
||||
CompatMode::V0_34 => {
|
||||
// Back-fill with a request to /block endpoint and
|
||||
// taking just the header from the response.
|
||||
let resp = self
|
||||
.perform_request_with_dialect(block::Request::new(height), v0_34::Dialect)
|
||||
.await?;
|
||||
let resp = self.perform_v0_34(block::Request::new(height)).await?;
|
||||
Ok(resp.into())
|
||||
}
|
||||
}
|
||||
@@ -217,25 +152,12 @@ impl TendermintRpcClient for ReqwestRpcClient {
|
||||
|
||||
async fn header_by_hash(&self, hash: Hash) -> Result<header_by_hash::Response, Error> {
|
||||
match self.compat {
|
||||
CompatMode::V0_38 => {
|
||||
self.perform_request_with_dialect(
|
||||
header_by_hash::Request::new(hash),
|
||||
v0_38::Dialect,
|
||||
)
|
||||
.await
|
||||
}
|
||||
CompatMode::V0_37 => {
|
||||
self.perform_request_with_dialect(
|
||||
header_by_hash::Request::new(hash),
|
||||
v0_37::Dialect,
|
||||
)
|
||||
.await
|
||||
}
|
||||
CompatMode::V0_37 => self.perform(header_by_hash::Request::new(hash)).await,
|
||||
CompatMode::V0_34 => {
|
||||
// Back-fill with a request to /block_by_hash endpoint and
|
||||
// taking just the header from the response.
|
||||
let resp = self
|
||||
.perform_request_with_dialect(block_by_hash::Request::new(hash), v0_34::Dialect)
|
||||
.perform_v0_34(block_by_hash::Request::new(hash))
|
||||
.await?;
|
||||
Ok(resp.into())
|
||||
}
|
||||
@@ -245,18 +167,8 @@ impl TendermintRpcClient for ReqwestRpcClient {
|
||||
/// `/broadcast_evidence`: broadcast an evidence.
|
||||
async fn broadcast_evidence(&self, e: Evidence) -> Result<evidence::Response, Error> {
|
||||
match self.compat {
|
||||
CompatMode::V0_38 => {
|
||||
self.perform_request_with_dialect(evidence::Request::new(e), v0_38::Dialect)
|
||||
.await
|
||||
}
|
||||
CompatMode::V0_37 => {
|
||||
self.perform_request_with_dialect(evidence::Request::new(e), v0_37::Dialect)
|
||||
.await
|
||||
}
|
||||
CompatMode::V0_34 => {
|
||||
self.perform_request_with_dialect(evidence::Request::new(e), v0_34::Dialect)
|
||||
.await
|
||||
}
|
||||
CompatMode::V0_37 => self.perform(evidence::Request::new(e)).await,
|
||||
CompatMode::V0_34 => self.perform_v0_34(evidence::Request::new(e)).await,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -113,10 +113,6 @@ impl Role {
|
||||
pub fn is_standby(&self) -> bool {
|
||||
matches!(self, Role::Standby)
|
||||
}
|
||||
|
||||
pub fn is_mixnode(&self) -> bool {
|
||||
matches!(self, Role::Layer1 | Role::Layer2 | Role::Layer3)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Role {
|
||||
|
||||
@@ -19,7 +19,7 @@ use std::error::Error;
|
||||
// `SELECT total_tickets, used_tickets FROM ecash_ticketbook WHERE expiration_date >= ?`, today_date
|
||||
// then for each calculate the diff total_tickets - used_tickets and multiply the result by the size of the ticket
|
||||
#[async_trait]
|
||||
pub trait Storage: Clone + Send + Sync {
|
||||
pub trait Storage: Send + Sync {
|
||||
type StorageError: Error;
|
||||
|
||||
async fn close(&self);
|
||||
|
||||
@@ -15,7 +15,6 @@ async-trait = { workspace = true }
|
||||
reqwest = { workspace = true, features = ["json"] }
|
||||
http.workspace = true
|
||||
url = { workspace = true }
|
||||
once_cell = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
@@ -23,13 +22,7 @@ tracing = { workspace = true }
|
||||
|
||||
nym-bin-common = { path = "../bin-common" }
|
||||
|
||||
[target."cfg(not(target_arch = \"wasm32\"))".dependencies]
|
||||
hickory-resolver = { workspace = true, features = ["dns-over-https-rustls", "webpki-roots"] }
|
||||
|
||||
# for request timeout until https://github.com/seanmonstar/reqwest/issues/1135 is fixed
|
||||
[target."cfg(target_arch = \"wasm32\")".dependencies.wasmtimer]
|
||||
workspace = true
|
||||
features = ["tokio"]
|
||||
|
||||
[dev-dependencies]
|
||||
tokio = { workspace = true, features=["rt", "macros"] }
|
||||
|
||||
@@ -1,177 +0,0 @@
|
||||
//! DNS resolver configuration for internal lookups.
|
||||
//!
|
||||
//! The resolver itself is the set combination of the google, cloudflare, and quad9 endpoints
|
||||
//! supporting DoH and DoT.
|
||||
//!
|
||||
//! This resolver implements a fallback mechanism where, should the DNS-over-TLS resolution fail, a
|
||||
//! followup resolution will be done using the hosts configured default (e.g. `/etc/resolve.conf` on
|
||||
//! linux).
|
||||
//!
|
||||
//! Requires the `dns-over-https-rustls`, `webpki-roots` feature for the
|
||||
//! `hickory-resolver` crate
|
||||
#![deny(missing_docs)]
|
||||
|
||||
use crate::ClientBuilder;
|
||||
|
||||
use std::{net::SocketAddr, sync::Arc};
|
||||
|
||||
use hickory_resolver::lookup_ip::LookupIp;
|
||||
use hickory_resolver::{
|
||||
config::{LookupIpStrategy, NameServerConfigGroup, ResolverConfig, ResolverOpts},
|
||||
error::ResolveError,
|
||||
lookup_ip::LookupIpIntoIter,
|
||||
TokioAsyncResolver,
|
||||
};
|
||||
use once_cell::sync::OnceCell;
|
||||
use reqwest::dns::{Addrs, Name, Resolve, Resolving};
|
||||
use tracing::warn;
|
||||
|
||||
impl ClientBuilder {
|
||||
/// Override the DNS resolver implementation used by the underlying http client.
|
||||
pub fn dns_resolver<R: Resolve + 'static>(mut self, resolver: Arc<R>) -> Self {
|
||||
self.reqwest_client_builder = self.reqwest_client_builder.dns_resolver(resolver);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
struct SocketAddrs {
|
||||
iter: LookupIpIntoIter,
|
||||
}
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
#[error("hickory-dns resolver error: {hickory_error}")]
|
||||
pub struct HickoryDnsError {
|
||||
#[from]
|
||||
hickory_error: ResolveError,
|
||||
}
|
||||
|
||||
/// Wrapper around an `AsyncResolver`, which implements the `Resolve` trait.
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct HickoryDnsResolver {
|
||||
/// Since we might not have been called in the context of a
|
||||
/// Tokio Runtime in initialization, so we must delay the actual
|
||||
/// construction of the resolver.
|
||||
state: Arc<OnceCell<TokioAsyncResolver>>,
|
||||
fallback: Arc<OnceCell<TokioAsyncResolver>>,
|
||||
}
|
||||
|
||||
impl Resolve for HickoryDnsResolver {
|
||||
fn resolve(&self, name: Name) -> Resolving {
|
||||
let resolver = self.state.clone();
|
||||
let fallback = self.fallback.clone();
|
||||
Box::pin(async move {
|
||||
let resolver = resolver.get_or_try_init(new_resolver)?;
|
||||
|
||||
// try the primary DNS resolver that we set up (DoH or DoT or whatever)
|
||||
let lookup = match resolver.lookup_ip(name.as_str()).await {
|
||||
Ok(res) => res,
|
||||
Err(e) => {
|
||||
// on failure use the fall back system configured DNS resolver
|
||||
warn!("primary DNS failed w/ error {e}: using system fallback");
|
||||
let resolver = fallback.get_or_try_init(new_resolver_system)?;
|
||||
resolver.lookup_ip(name.as_str()).await?
|
||||
}
|
||||
};
|
||||
|
||||
let addrs: Addrs = Box::new(SocketAddrs {
|
||||
iter: lookup.into_iter(),
|
||||
});
|
||||
Ok(addrs)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterator for SocketAddrs {
|
||||
type Item = SocketAddr;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
self.iter.next().map(|ip_addr| SocketAddr::new(ip_addr, 0))
|
||||
}
|
||||
}
|
||||
|
||||
impl HickoryDnsResolver {
|
||||
/// Attempt to resolve a domain name to a set of ['IpAddr']s
|
||||
pub async fn resolve_str(&self, name: &str) -> Result<LookupIp, HickoryDnsError> {
|
||||
let resolver = self.state.get_or_try_init(new_resolver)?;
|
||||
|
||||
// try the primary DNS resolver that we set up (DoH or DoT or whatever)
|
||||
let lookup = match resolver.lookup_ip(name).await {
|
||||
Ok(res) => res,
|
||||
Err(e) => {
|
||||
// on failure use the fall back system configured DNS resolver
|
||||
warn!("primary DNS failed w/ error {e}: using system fallback");
|
||||
let resolver = self.fallback.get_or_try_init(new_resolver_system)?;
|
||||
resolver.lookup_ip(name).await?
|
||||
}
|
||||
};
|
||||
|
||||
Ok(lookup)
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a new resolver with a custom DoT based configuration. The options are overridden to look
|
||||
/// up for both IPv4 and IPv6 addresses to work with "happy eyeballs" algorithm.
|
||||
fn new_resolver() -> Result<TokioAsyncResolver, HickoryDnsError> {
|
||||
let mut name_servers = NameServerConfigGroup::google_tls();
|
||||
name_servers.merge(NameServerConfigGroup::google_https());
|
||||
// name_servers.merge(NameServerConfigGroup::google_h3());
|
||||
name_servers.merge(NameServerConfigGroup::quad9_tls());
|
||||
name_servers.merge(NameServerConfigGroup::quad9_https());
|
||||
name_servers.merge(NameServerConfigGroup::cloudflare_tls());
|
||||
name_servers.merge(NameServerConfigGroup::cloudflare_https());
|
||||
|
||||
let config = ResolverConfig::from_parts(None, Vec::new(), name_servers);
|
||||
|
||||
let mut opts = ResolverOpts::default();
|
||||
opts.ip_strategy = LookupIpStrategy::Ipv4AndIpv6;
|
||||
// Would like to enable this when 0.25 stabilizes
|
||||
// opts.server_ordering_strategy = ServerOrderingStrategy::RoundRobin;
|
||||
|
||||
Ok(TokioAsyncResolver::tokio(config, opts))
|
||||
}
|
||||
|
||||
/// Create a new resolver with the default configuration, which reads from the system DNS config
|
||||
/// (i.e. `/etc/resolve.conf` in unix). The options are overridden to look up for both IPv4 and IPv6
|
||||
/// addresses to work with "happy eyeballs" algorithm.
|
||||
fn new_resolver_system() -> Result<TokioAsyncResolver, HickoryDnsError> {
|
||||
let (config, mut opts) = hickory_resolver::system_conf::read_system_conf()?;
|
||||
opts.ip_strategy = LookupIpStrategy::Ipv4AndIpv6;
|
||||
Ok(TokioAsyncResolver::tokio(config, opts))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[tokio::test]
|
||||
async fn reqwest_hickory_doh() {
|
||||
let resolver = HickoryDnsResolver::default();
|
||||
let client = reqwest::ClientBuilder::new()
|
||||
.dns_resolver(resolver.into())
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
let resp = client
|
||||
.get("http://ifconfig.me:80")
|
||||
.send()
|
||||
.await
|
||||
.unwrap()
|
||||
.bytes()
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert!(!resp.is_empty());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn dns_lookup() -> Result<(), HickoryDnsError> {
|
||||
let resolver = HickoryDnsResolver::default();
|
||||
|
||||
let domain = "ifconfig.me";
|
||||
let addrs = resolver.resolve_str(domain).await?;
|
||||
|
||||
assert!(addrs.into_iter().next().is_some());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -6,23 +6,17 @@ use reqwest::header::HeaderValue;
|
||||
use reqwest::{RequestBuilder, Response, StatusCode};
|
||||
use serde::de::DeserializeOwned;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt::Display;
|
||||
use std::time::Duration;
|
||||
use thiserror::Error;
|
||||
use tracing::{instrument, warn};
|
||||
use url::Url;
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
use std::sync::Arc;
|
||||
use std::{fmt::Display, time::Duration};
|
||||
|
||||
pub use reqwest::IntoUrl;
|
||||
|
||||
mod user_agent;
|
||||
pub use user_agent::UserAgent;
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
mod dns;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
pub use dns::HickoryDnsResolver;
|
||||
mod user_agent;
|
||||
|
||||
// The timeout is relatively high as we are often making requests over the mixnet, where latency is
|
||||
// high and chatty protocols take a while to complete.
|
||||
@@ -92,18 +86,11 @@ impl ClientBuilder {
|
||||
// TODO: or should we maybe default to https?
|
||||
Self::new(alt)
|
||||
} else {
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
let reqwest_client_builder = reqwest::ClientBuilder::new();
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
let reqwest_client_builder =
|
||||
reqwest::ClientBuilder::new().dns_resolver(Arc::new(HickoryDnsResolver::default()));
|
||||
|
||||
Ok(ClientBuilder {
|
||||
url: url.into_url()?,
|
||||
timeout: None,
|
||||
custom_user_agent: false,
|
||||
reqwest_client_builder,
|
||||
reqwest_client_builder: reqwest::ClientBuilder::new(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ impl Default for ClientStatsReport {
|
||||
pub struct OsInformation {
|
||||
pub(crate) os_type: String,
|
||||
pub(crate) os_version: Option<String>,
|
||||
pub(crate) os_arch: String,
|
||||
pub(crate) os_arch: Option<String>,
|
||||
}
|
||||
|
||||
impl OsInformation {
|
||||
|
||||
@@ -401,17 +401,20 @@ impl NymTopology {
|
||||
});
|
||||
};
|
||||
|
||||
// a 'valid' egress is one that is currently **not** acting as a mixnode
|
||||
// a 'valid' egress is one assigned to either entry role (i.e. entry for another client)
|
||||
// or exit role (as a service provider)
|
||||
if !ignore_epoch_roles {
|
||||
if let Some(role) = self.rewarded_set.role(node.node_id) {
|
||||
if role.is_mixnode() {
|
||||
return Err(NymTopologyError::InvalidEgressRole {
|
||||
node_identity: Box::new(node_identity),
|
||||
});
|
||||
}
|
||||
let Some(role) = self.rewarded_set.role(node.node_id) else {
|
||||
return Err(NymTopologyError::InvalidEgressRole {
|
||||
node_identity: Box::new(node_identity),
|
||||
});
|
||||
};
|
||||
if !matches!(role, Role::EntryGateway | Role::ExitGateway) {
|
||||
return Err(NymTopologyError::InvalidEgressRole {
|
||||
node_identity: Box::new(node_identity),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Ok(node)
|
||||
}
|
||||
|
||||
|
||||
@@ -390,6 +390,7 @@ pub struct TopologyWasm {
|
||||
|
||||
/// Specifies whether this client should attempt to retrieve all available network nodes
|
||||
/// as opposed to just active mixnodes/gateways.
|
||||
/// Useless without `ignore_epoch_roles = true`
|
||||
pub use_extended_topology: bool,
|
||||
|
||||
/// Specifies whether this client should ignore the current epoch role of the target egress node
|
||||
|
||||
@@ -274,6 +274,7 @@ pub struct TopologyWasmOverride {
|
||||
|
||||
/// Specifies whether this client should attempt to retrieve all available network nodes
|
||||
/// as opposed to just active mixnodes/gateways.
|
||||
/// Useless without `ignore_epoch_roles = true`
|
||||
#[tsify(optional)]
|
||||
pub use_extended_topology: Option<bool>,
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ use nym_client_core::client::base_client::storage::GatewaysDetailsStore;
|
||||
use nym_client_core::client::replies::reply_storage::browser_backend;
|
||||
use nym_client_core::config;
|
||||
use nym_client_core::error::ClientCoreError;
|
||||
use nym_client_core::init::helpers::gateways_for_init;
|
||||
use nym_client_core::init::helpers::current_gateways;
|
||||
use nym_client_core::init::types::GatewaySelectionSpecification;
|
||||
use nym_client_core::init::{
|
||||
self, setup_gateway,
|
||||
@@ -134,7 +134,7 @@ pub async fn setup_gateway_from_api(
|
||||
minimum_performance: u8,
|
||||
) -> Result<InitialisationResult, WasmCoreError> {
|
||||
let mut rng = thread_rng();
|
||||
let gateways = gateways_for_init(&mut rng, nym_apis, None, minimum_performance).await?;
|
||||
let gateways = current_gateways(&mut rng, nym_apis, None, minimum_performance).await?;
|
||||
setup_gateway_wasm(client_store, force_tls, chosen_gateway, gateways).await
|
||||
}
|
||||
|
||||
@@ -144,7 +144,7 @@ pub async fn current_gateways_wasm(
|
||||
minimum_performance: u8,
|
||||
) -> Result<Vec<RoutingNode>, ClientCoreError> {
|
||||
let mut rng = thread_rng();
|
||||
gateways_for_init(&mut rng, nym_apis, user_agent, minimum_performance).await
|
||||
current_gateways(&mut rng, nym_apis, user_agent, minimum_performance).await
|
||||
}
|
||||
|
||||
pub async fn setup_from_topology(
|
||||
|
||||
@@ -4,15 +4,13 @@
|
||||
use crate::error::WasmCoreError;
|
||||
use crate::storage::wasm_client_traits::{v1, v2, WasmClientStorage};
|
||||
use async_trait::async_trait;
|
||||
use js_sys::Promise;
|
||||
use js_sys::{Array, Promise};
|
||||
use serde::de::DeserializeOwned;
|
||||
use serde::Serialize;
|
||||
use wasm_bindgen::prelude::*;
|
||||
use wasm_bindgen_futures::future_to_promise;
|
||||
use wasm_storage::traits::BaseWasmStorage;
|
||||
use wasm_storage::{
|
||||
Build, Database, RawDbResult, TryFromJs, TryToJs, VersionChangeEvent, WasmStorage,
|
||||
};
|
||||
use wasm_storage::{IdbVersionChangeEvent, WasmStorage};
|
||||
use wasm_utils::error::{simple_js_error, PromisableResult};
|
||||
use zeroize::Zeroizing;
|
||||
|
||||
@@ -46,29 +44,28 @@ impl ClientStorage {
|
||||
// special care must be taken on JS side to ensure it's correctly used there.
|
||||
let passphrase = Zeroizing::new(passphrase);
|
||||
|
||||
let migrate_fn = Some(|evt: VersionChangeEvent, db: Database| -> RawDbResult<()> {
|
||||
let migrate_fn = Some(|evt: &IdbVersionChangeEvent| -> Result<(), JsValue> {
|
||||
// Even if the web-sys bindings expose the version as a f64, the IndexedDB API
|
||||
// works with an unsigned integer.
|
||||
// See <https://github.com/rustwasm/wasm-bindgen/issues/1149>
|
||||
let old_version = evt.old_version() as u32;
|
||||
let db = evt.db();
|
||||
|
||||
if old_version < 1 {
|
||||
// migrating to version 2
|
||||
|
||||
db.create_object_store(v1::KEYS_STORE).build()?;
|
||||
db.create_object_store(v1::CORE_STORE).build()?;
|
||||
db.create_object_store(v1::KEYS_STORE)?;
|
||||
db.create_object_store(v1::CORE_STORE)?;
|
||||
|
||||
db.create_object_store(v2::GATEWAY_REGISTRATIONS_ACTIVE_GATEWAY_STORE)
|
||||
.build()?;
|
||||
db.create_object_store(v2::GATEWAY_REGISTRATIONS_REGISTERED_GATEWAYS_STORE)
|
||||
.build()?;
|
||||
db.create_object_store(v2::GATEWAY_REGISTRATIONS_ACTIVE_GATEWAY_STORE)?;
|
||||
db.create_object_store(v2::GATEWAY_REGISTRATIONS_REGISTERED_GATEWAYS_STORE)?;
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// version 1 -> unimplemented migration
|
||||
if old_version < 2 {
|
||||
return Err(simple_js_error("this client is incompatible with existing storage. please initialise it again.").into());
|
||||
return Err(simple_js_error("this client is incompatible with existing storage. please initialise it again."));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -115,7 +112,7 @@ impl BaseWasmStorage for ClientStorage {
|
||||
async fn read_value<T, K>(&self, store: &str, key: K) -> Result<Option<T>, Self::StorageError>
|
||||
where
|
||||
T: DeserializeOwned,
|
||||
K: TryToJs,
|
||||
K: JsCast,
|
||||
{
|
||||
Ok(self.inner.read_value(store, key).await?)
|
||||
}
|
||||
@@ -128,33 +125,33 @@ impl BaseWasmStorage for ClientStorage {
|
||||
) -> Result<(), Self::StorageError>
|
||||
where
|
||||
T: Serialize,
|
||||
K: TryToJs + TryFromJs,
|
||||
K: JsCast,
|
||||
{
|
||||
Ok(self.inner.store_value(store, key, value).await?)
|
||||
}
|
||||
|
||||
async fn remove_value<K>(&self, store: &str, key: K) -> Result<(), Self::StorageError>
|
||||
where
|
||||
K: TryToJs,
|
||||
K: JsCast,
|
||||
{
|
||||
Ok(self.inner.remove_value(store, key).await?)
|
||||
}
|
||||
|
||||
async fn has_value<K>(&self, store: &str, key: K) -> Result<bool, Self::StorageError>
|
||||
where
|
||||
K: TryToJs,
|
||||
K: JsCast,
|
||||
{
|
||||
Ok(self.inner.has_value(store, key).await?)
|
||||
}
|
||||
|
||||
async fn key_count<K>(&self, store: &str, key: K) -> Result<u32, Self::StorageError>
|
||||
where
|
||||
K: TryToJs,
|
||||
K: JsCast,
|
||||
{
|
||||
Ok(self.inner.key_count(store, key).await?)
|
||||
}
|
||||
|
||||
async fn get_all_keys(&self, store: &str) -> Result<Vec<JsValue>, Self::StorageError> {
|
||||
async fn get_all_keys(&self, store: &str) -> Result<Array, Self::StorageError> {
|
||||
Ok(self.inner.get_all_keys(store).await?)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -286,8 +286,8 @@ pub trait WasmClientStorage: BaseWasmStorage {
|
||||
.await
|
||||
.map_err(Into::into)
|
||||
.map(|arr| {
|
||||
arr.iter()
|
||||
.cloned()
|
||||
arr.to_vec()
|
||||
.into_iter()
|
||||
.filter_map(|key| key.as_string())
|
||||
.collect()
|
||||
})
|
||||
|
||||
@@ -9,7 +9,7 @@ license.workspace = true
|
||||
|
||||
[dependencies]
|
||||
async-trait = { workspace = true }
|
||||
getrandom = { workspace = true, features = ["js"] }
|
||||
futures = { workspace = true }
|
||||
js-sys = { workspace = true }
|
||||
wasm-bindgen = { workspace = true }
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use indexed_db_futures::web_sys::DomException;
|
||||
use serde_wasm_bindgen::Error;
|
||||
use thiserror::Error;
|
||||
use wasm_bindgen::JsValue;
|
||||
@@ -11,11 +12,15 @@ pub enum StorageError {
|
||||
#[error("{0}")]
|
||||
Json(String),
|
||||
|
||||
#[error("storage failure: {message}")]
|
||||
InternalStorageFailure { message: String },
|
||||
|
||||
#[error("failed to open the db file: {message}")]
|
||||
DbOpenFailure { message: String },
|
||||
#[error("DomException {name} ({code}): {message}")]
|
||||
DomException {
|
||||
/// DomException code
|
||||
code: u16,
|
||||
/// Specific name of the DomException
|
||||
name: String,
|
||||
/// Message given to the DomException
|
||||
message: String,
|
||||
},
|
||||
|
||||
#[error("FATAL ERROR: storage key is somehow present {count} times in the table!")]
|
||||
DuplicateKey { count: u32 },
|
||||
@@ -41,18 +46,12 @@ impl From<StorageError> for JsValue {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<indexed_db_futures::error::Error> for StorageError {
|
||||
fn from(value: indexed_db_futures::error::Error) -> Self {
|
||||
StorageError::InternalStorageFailure {
|
||||
message: value.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<indexed_db_futures::error::OpenDbError> for StorageError {
|
||||
fn from(value: indexed_db_futures::error::OpenDbError) -> Self {
|
||||
StorageError::DbOpenFailure {
|
||||
message: value.to_string(),
|
||||
impl From<DomException> for StorageError {
|
||||
fn from(value: DomException) -> StorageError {
|
||||
StorageError::DomException {
|
||||
name: value.name(),
|
||||
message: value.message(),
|
||||
code: value.code(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
// Copyright 2023-2025 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::cipher_export::StoredExportedStoreCipher;
|
||||
use crate::error::StorageError;
|
||||
use indexed_db_futures::transaction::TransactionMode;
|
||||
use nym_store_cipher::{
|
||||
Aes256Gcm, Algorithm, EncryptedData, KdfInfo, KeySizeUser, Params, StoreCipher, Unsigned,
|
||||
Version,
|
||||
@@ -14,10 +13,7 @@ use std::future::IntoFuture;
|
||||
use wasm_bindgen::JsValue;
|
||||
use wasm_utils::console_log;
|
||||
|
||||
pub use indexed_db_futures::database::{Database, VersionChangeEvent};
|
||||
pub use indexed_db_futures::prelude::*;
|
||||
pub use indexed_db_futures::primitive::{TryFromJs, TryToJs};
|
||||
pub use indexed_db_futures::Result as RawDbResult;
|
||||
|
||||
mod cipher_export;
|
||||
pub mod error;
|
||||
@@ -58,29 +54,31 @@ impl WasmStorage {
|
||||
passphrase: Option<&[u8]>,
|
||||
) -> Result<Self, StorageError>
|
||||
where
|
||||
F: Fn(VersionChangeEvent, Database) -> RawDbResult<()> + 'static,
|
||||
F: Fn(&IdbVersionChangeEvent) -> Result<(), JsValue> + 'static,
|
||||
{
|
||||
let mut db_req: OpenDbRequest = IdbDatabase::open_u32(db_name, version)?;
|
||||
|
||||
// we must always ensure the cipher table is present
|
||||
let db = Database::open(db_name)
|
||||
.with_version(version)
|
||||
.with_on_upgrade_needed(move |event, db| {
|
||||
db_req.set_on_upgrade_needed(Some(
|
||||
move |evt: &IdbVersionChangeEvent| -> Result<(), JsValue> {
|
||||
// Even if the web-sys bindings expose the version as a f64, the IndexedDB API
|
||||
// works with an unsigned integer.
|
||||
// See <https://github.com/rustwasm/wasm-bindgen/issues/1149>
|
||||
let old_version = event.old_version() as u32;
|
||||
let old_version = evt.old_version() as u32;
|
||||
|
||||
if old_version < 1 {
|
||||
db.create_object_store(CIPHER_INFO_STORE).build()?;
|
||||
evt.db().create_object_store(CIPHER_INFO_STORE)?;
|
||||
}
|
||||
|
||||
if let Some(migrate) = migrate_fn.as_ref() {
|
||||
migrate(event, db)
|
||||
migrate(evt)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
})
|
||||
.await?;
|
||||
},
|
||||
));
|
||||
|
||||
let db: IdbDatabase = db_req.into_future().await?;
|
||||
let inner = IdbWrapper(db);
|
||||
let store_cipher = inner.setup_store_cipher(passphrase).await?;
|
||||
|
||||
@@ -96,12 +94,13 @@ impl WasmStorage {
|
||||
}
|
||||
|
||||
pub async fn remove(db_name: &str) -> Result<(), StorageError> {
|
||||
Database::delete_by_name(db_name)?.into_future().await?;
|
||||
IdbDatabase::delete_by_name(db_name)?.into_future().await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn exists(db_name: &str) -> Result<bool, StorageError> {
|
||||
let db = Database::open(db_name).await?;
|
||||
let db_req: OpenDbRequest = IdbDatabase::open(db_name)?;
|
||||
let db: IdbDatabase = db_req.into_future().await?;
|
||||
|
||||
// if the db was already created before, at the very least cipher info store should exist,
|
||||
// thus the iterator should return at least one value
|
||||
@@ -140,7 +139,7 @@ impl WasmStorage {
|
||||
pub async fn read_value<T, K>(&self, store: &str, key: K) -> Result<Option<T>, StorageError>
|
||||
where
|
||||
T: DeserializeOwned,
|
||||
K: TryToJs,
|
||||
K: wasm_bindgen::JsCast,
|
||||
{
|
||||
self.inner
|
||||
.read_value_raw(store, key)
|
||||
@@ -157,7 +156,7 @@ impl WasmStorage {
|
||||
) -> Result<(), StorageError>
|
||||
where
|
||||
T: Serialize,
|
||||
K: TryToJs + TryFromJs,
|
||||
K: wasm_bindgen::JsCast,
|
||||
{
|
||||
self.inner
|
||||
.store_value_raw(store, key, &self.serialize_value(&value)?)
|
||||
@@ -166,14 +165,14 @@ impl WasmStorage {
|
||||
|
||||
pub async fn remove_value<K>(&self, store: &str, key: K) -> Result<(), StorageError>
|
||||
where
|
||||
K: TryToJs,
|
||||
K: wasm_bindgen::JsCast,
|
||||
{
|
||||
self.inner.remove_value_raw(store, key).await
|
||||
}
|
||||
|
||||
pub async fn has_value<K>(&self, store: &str, key: K) -> Result<bool, StorageError>
|
||||
where
|
||||
K: TryToJs,
|
||||
K: wasm_bindgen::JsCast,
|
||||
{
|
||||
match self.key_count(store, key).await? {
|
||||
0 => Ok(false),
|
||||
@@ -184,98 +183,82 @@ impl WasmStorage {
|
||||
|
||||
pub async fn key_count<K>(&self, store: &str, key: K) -> Result<u32, StorageError>
|
||||
where
|
||||
K: TryToJs,
|
||||
K: wasm_bindgen::JsCast,
|
||||
{
|
||||
self.inner.get_key_count(store, key).await
|
||||
}
|
||||
|
||||
pub async fn get_all_keys(&self, store: &str) -> Result<Vec<JsValue>, StorageError> {
|
||||
pub async fn get_all_keys(&self, store: &str) -> Result<js_sys::Array, StorageError> {
|
||||
self.inner.get_all_keys(store).await
|
||||
}
|
||||
}
|
||||
|
||||
struct IdbWrapper(Database);
|
||||
struct IdbWrapper(IdbDatabase);
|
||||
|
||||
impl IdbWrapper {
|
||||
async fn read_value_raw<K>(&self, store: &str, key: K) -> Result<Option<JsValue>, StorageError>
|
||||
where
|
||||
K: TryToJs,
|
||||
K: wasm_bindgen::JsCast,
|
||||
{
|
||||
self.0
|
||||
.transaction(store)
|
||||
.with_mode(TransactionMode::Readonly)
|
||||
.build()?
|
||||
.transaction_on_one_with_mode(store, IdbTransactionMode::Readonly)?
|
||||
.object_store(store)?
|
||||
.get(&key)
|
||||
.primitive()?
|
||||
.get(&key)?
|
||||
.await
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
async fn store_value_raw<K, T>(
|
||||
async fn store_value_raw<K>(
|
||||
&self,
|
||||
store: &str,
|
||||
key: K,
|
||||
value: &T,
|
||||
value: &JsValue,
|
||||
) -> Result<(), StorageError>
|
||||
where
|
||||
K: TryToJs + TryFromJs,
|
||||
T: TryToJs,
|
||||
K: wasm_bindgen::JsCast,
|
||||
{
|
||||
let tx = self
|
||||
.0
|
||||
.transaction(store)
|
||||
.with_mode(TransactionMode::Readwrite)
|
||||
.build()?;
|
||||
|
||||
let store = tx.object_store(store)?;
|
||||
store.put(value).with_key(key).primitive()?.await?;
|
||||
|
||||
tx.commit().await.map_err(Into::into)
|
||||
self.0
|
||||
.transaction_on_one_with_mode(store, IdbTransactionMode::Readwrite)?
|
||||
.object_store(store)?
|
||||
.put_key_val_owned(key, value)?
|
||||
.into_future()
|
||||
.await
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
async fn remove_value_raw<K>(&self, store: &str, key: K) -> Result<(), StorageError>
|
||||
where
|
||||
K: TryToJs,
|
||||
{
|
||||
let tx = self
|
||||
.0
|
||||
.transaction(store)
|
||||
.with_mode(TransactionMode::Readwrite)
|
||||
.build()?;
|
||||
|
||||
let store = tx.object_store(store)?;
|
||||
store.delete(key).primitive()?.await?;
|
||||
|
||||
tx.commit().await.map_err(Into::into)
|
||||
}
|
||||
|
||||
async fn get_key_count<K>(&self, store: &str, key: K) -> Result<u32, StorageError>
|
||||
where
|
||||
K: TryToJs,
|
||||
K: wasm_bindgen::JsCast,
|
||||
{
|
||||
self.0
|
||||
.transaction(store)
|
||||
.with_mode(TransactionMode::Readonly)
|
||||
.build()?
|
||||
.transaction_on_one_with_mode(store, IdbTransactionMode::Readwrite)?
|
||||
.object_store(store)?
|
||||
.count()
|
||||
.with_query(key)
|
||||
.primitive()?
|
||||
.delete_owned(key)?
|
||||
.into_future()
|
||||
.await
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
async fn get_all_keys(&self, store: &str) -> Result<Vec<JsValue>, StorageError> {
|
||||
async fn get_key_count<K>(&self, store: &str, key: K) -> Result<u32, StorageError>
|
||||
where
|
||||
K: wasm_bindgen::JsCast,
|
||||
{
|
||||
self.0
|
||||
.transaction(store)
|
||||
.with_mode(TransactionMode::Readonly)
|
||||
.build()?
|
||||
.transaction_on_one_with_mode(store, IdbTransactionMode::Readwrite)?
|
||||
.object_store(store)?
|
||||
.get_all_keys()
|
||||
.primitive()?
|
||||
.await?
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
.count_with_key_owned(key)?
|
||||
.into_future()
|
||||
.await
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
async fn get_all_keys(&self, store: &str) -> Result<js_sys::Array, StorageError> {
|
||||
self.0
|
||||
.transaction_on_one_with_mode(store, IdbTransactionMode::Readonly)?
|
||||
.object_store(store)?
|
||||
.get_all_keys()?
|
||||
.into_future()
|
||||
.await
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
|
||||
@@ -3,11 +3,10 @@
|
||||
|
||||
use crate::WasmStorage;
|
||||
use async_trait::async_trait;
|
||||
use indexed_db_futures::primitive::{TryFromJs, TryToJs};
|
||||
use js_sys::Array;
|
||||
use serde::de::DeserializeOwned;
|
||||
use serde::Serialize;
|
||||
use std::error::Error;
|
||||
use wasm_bindgen::JsValue;
|
||||
|
||||
#[async_trait(?Send)]
|
||||
pub trait BaseWasmStorage {
|
||||
@@ -18,7 +17,7 @@ pub trait BaseWasmStorage {
|
||||
async fn read_value<T, K>(&self, store: &str, key: K) -> Result<Option<T>, Self::StorageError>
|
||||
where
|
||||
T: DeserializeOwned,
|
||||
K: TryToJs;
|
||||
K: wasm_bindgen::JsCast;
|
||||
|
||||
async fn store_value<T, K>(
|
||||
&self,
|
||||
@@ -28,21 +27,21 @@ pub trait BaseWasmStorage {
|
||||
) -> Result<(), Self::StorageError>
|
||||
where
|
||||
T: Serialize,
|
||||
K: TryToJs + TryFromJs;
|
||||
K: wasm_bindgen::JsCast;
|
||||
|
||||
async fn remove_value<K>(&self, store: &str, key: K) -> Result<(), Self::StorageError>
|
||||
where
|
||||
K: TryToJs;
|
||||
K: wasm_bindgen::JsCast;
|
||||
|
||||
async fn has_value<K>(&self, store: &str, key: K) -> Result<bool, Self::StorageError>
|
||||
where
|
||||
K: TryToJs;
|
||||
K: wasm_bindgen::JsCast;
|
||||
|
||||
async fn key_count<K>(&self, store: &str, key: K) -> Result<u32, Self::StorageError>
|
||||
where
|
||||
K: TryToJs;
|
||||
K: wasm_bindgen::JsCast;
|
||||
|
||||
async fn get_all_keys(&self, store: &str) -> Result<Vec<JsValue>, Self::StorageError>;
|
||||
async fn get_all_keys(&self, store: &str) -> Result<js_sys::Array, Self::StorageError>;
|
||||
}
|
||||
|
||||
#[async_trait(?Send)]
|
||||
@@ -56,7 +55,7 @@ impl BaseWasmStorage for WasmStorage {
|
||||
async fn read_value<T, K>(&self, store: &str, key: K) -> Result<Option<T>, Self::StorageError>
|
||||
where
|
||||
T: DeserializeOwned,
|
||||
K: TryToJs,
|
||||
K: wasm_bindgen::JsCast,
|
||||
{
|
||||
self.read_value(store, key).await
|
||||
}
|
||||
@@ -69,33 +68,33 @@ impl BaseWasmStorage for WasmStorage {
|
||||
) -> Result<(), Self::StorageError>
|
||||
where
|
||||
T: Serialize,
|
||||
K: TryToJs + TryFromJs,
|
||||
K: wasm_bindgen::JsCast,
|
||||
{
|
||||
self.store_value(store, key, value).await
|
||||
}
|
||||
|
||||
async fn remove_value<K>(&self, store: &str, key: K) -> Result<(), Self::StorageError>
|
||||
where
|
||||
K: TryToJs,
|
||||
K: wasm_bindgen::JsCast,
|
||||
{
|
||||
self.remove_value(store, key).await
|
||||
}
|
||||
|
||||
async fn has_value<K>(&self, store: &str, key: K) -> Result<bool, Self::StorageError>
|
||||
where
|
||||
K: TryToJs,
|
||||
K: wasm_bindgen::JsCast,
|
||||
{
|
||||
self.has_value(store, key).await
|
||||
}
|
||||
|
||||
async fn key_count<K>(&self, store: &str, key: K) -> Result<u32, Self::StorageError>
|
||||
where
|
||||
K: TryToJs,
|
||||
K: wasm_bindgen::JsCast,
|
||||
{
|
||||
self.key_count(store, key).await
|
||||
}
|
||||
|
||||
async fn get_all_keys(&self, store: &str) -> Result<Vec<JsValue>, Self::StorageError> {
|
||||
async fn get_all_keys(&self, store: &str) -> Result<Array, Self::StorageError> {
|
||||
self.get_all_keys(store).await
|
||||
}
|
||||
}
|
||||
|
||||
@@ -325,7 +325,7 @@ impl PeerController {
|
||||
log::error!("Can't read wireguard kernel data");
|
||||
continue;
|
||||
};
|
||||
self.update_metrics(&host).await;
|
||||
self.update_metrics(&host);
|
||||
|
||||
*self.host_information.write().await = host;
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import Stack from '@mui/material/Stack';
|
||||
import Paper from '@mui/material/Paper';
|
||||
import type { SetupMixFetchOps } from '@nymproject/mix-fetch';
|
||||
|
||||
const defaultUrl = 'https://nym.com/favicon.svg';
|
||||
const defaultUrl = 'https://nymtech.net/favicon.svg';
|
||||
const args = { mode: 'unsafe-ignore-cors' };
|
||||
|
||||
const mixFetchOptions: SetupMixFetchOps = {
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
import { Callout } from 'nextra/components';
|
||||
|
||||
### Terms & Conditions
|
||||
|
||||
<Callout type="info" emoji="ℹ️">
|
||||
From `nym-node` version `1.1.3` onward is required to accept [**Operators Terms & Conditions**](https://nymtech.net/terms-and-conditions/operators/v1.0.0) in order to be part of the active set. Make sure to read them before you add the flag.
|
||||
</Callout>
|
||||
|
||||
There has been a long ongoing discussion whether and how to apply Terms and Conditions for Nym network operators, with an aim to stay aligned with the philosophy of Free Software and provide legal defense for both node operators and Nym developers. To understand better the reasoning behind this decision, you can listen to the first [Nym Operator Town Hall](https://www.youtube.com/live/7hwb8bAZIuc?si=3mQ2ed7AyUA1SsCp&t=915) introducing the T&Cs or to [Operator AMA with CEO Harry Halpin](https://www.youtube.com/watch?v=yIN-zYQw0I0) from June 4th, 2024, explaining pros and cons of T&Cs implementation.
|
||||
+1
-1
@@ -1 +1 @@
|
||||
44.332
|
||||
44.811
|
||||
|
||||
@@ -1 +1 @@
|
||||
Thursday, January 23rd 2025, 10:41:32 UTC
|
||||
Wednesday, January 8th 2025, 15:01:28 UTC
|
||||
|
||||
@@ -1,21 +1,26 @@
|
||||
**ISP**,**Locations**,**Public IPv6**,**Crypto Payments**,**Comments**,**Last Updated**
|
||||
[Flokinet](https://flokinet.is),"Netherlands, Iceland, Romania,France","Yes, needs a ticket and custom setup","yes, including XMR",Very slow customer support,05/2024
|
||||
[BitLaunch](https://bitlaunch.io),"Canada, USA, UK",No,Yes,Expensive. Digial Ocean through BitLanch has IPv6,05/2024
|
||||
[Hostinger](https://hostinger.com),"France, Lithuania, India, USA, Brazil","Yes, out of the box",Yes,Crypto payments must be done per each server monthly or annually.,05/2024
|
||||
[Linode](https://linode.com),"USA, Canada, Japan, India, Indonesia, Sweden, Netherlands, Germany, Brazil, France, UK, Australia, Italy",Yes out of the box,"No, only through [BitLAunch](https://bitlaunch.io)","IPv6 sometimes need to be re-added in Networking tab, no reboot needed",05/2024
|
||||
[Cherry Servers](https://www.cherryservers.com),"Lithuania, Netherlands, USA, Singapore",No,Yes,Issued IP doesn’t match the location offered by the provider.,05/2024
|
||||
[Njalla](https://nja.la),Sweden,Yes,Yes,"Privacy vandguards! The biggest VPS 45 is 3 cores only, but it works better than many “larger” servers on the market.",05/2024
|
||||
[HostSailor](https://hostsailor.com),USA,"Yes, based on ticket",Yes,The IPv6 setup needs custom research and is not documented,05/2024
|
||||
[Misaka](https://www.misaka.io/),South Africa,"Yes, native support",No,Very Expensive,05/2024
|
||||
[IsHosting](https://ishosting.com/en),"Brazil, Netherlands","Yes, based on ticket",Yes,Expensive,05/2024
|
||||
[AlexHost](https://alexhost.com),"Moldova, Bulgaria, Sweden, Netherlands","Yes, on by default",Yes,"They allow TOR Bridges, Relays. Exit nodes are only allowed on dedicated servers (prices start from 26 EUR)",07/2024
|
||||
[iHostArt](https://ihostart.com),Romania,"Yes, on by default",Yes,"Super permissive provider. They do allow Tor Exit/Relay/Bridge. Pro-free speech etc. Recently, IPv6 geolocation was set to North Korea, so be aware.",07/2024
|
||||
[Incognet](https://incognet.io),Netherlands and USA,"Yes, on by default",Yes,They allow Tor exit nodes but you must adhere to their rules https://incognet.io/tor-exits,07/2024
|
||||
[vSys Host](https://vsys.host),"Ukraine, Netherlands, USA","Yes, on by default",Yes,"Pretty permissive provider registered in Ukraine. Should allow Relay/Exit nodes but nothing in T&C, so better double check.",07/2024
|
||||
[LiteServer](https://liteserver.nl),Netherlands,"Yes, on by default",Yes,Very reliable Dutch provider. They do allow Relay nodes but for Exit nodes you need to contact them. Always check T&C https://liteserver.nl/legal,07/2024
|
||||
[TerraHost](https://terrahost.no),Norway,"Yes, on by default",Yes,Very reliable Norwegian provider. Only allow exit nodes on Dedicated servers subject to certain caveats (you must open a ticket). Always check T&C https://terrahost.no/avtalebetingelser,07/2024
|
||||
[Mevspace](https://mevspace.com),Poland,"Yes, on by default",Yes,"Flexible Polish providers with 3 DCs in Poland. They do allow Tor Exit nodes but you may need a dedicated server for this. Make sure you open a ticket to check. As of today's date, they have 48h for 1 EUR tariff",07/2024
|
||||
[Hostiko](https://hostiko.com.ua),"Ukraine, Germany","Yes, on by default",Yes,"Ukrainian provider. They allow Exit nodes on Germany boxes but limit the bandwidth, you also have to restrict certain ports like 25 and 587. Make sure you open a ticket.",07/2024
|
||||
[Hostslick](https://hostslick.com),"Netherlands, Germany","Yes, on by default",Yes,Good amount of bandwidth for the price. Make sure you open the ticket if you want to run Exit node,07/2024
|
||||
[RDP](https://rdp.sh),"Netherlands, USA, Poland","Yes, on by default",Yes,"German provider. Exit nodes are allowed, policy is here https://rdp.sh/docs/faq/tor ports 25,465,587 must be closed. Make sure you open a ticket before running an exit node.",07/2024
|
||||
[PQ.Hosting](https://bill.pq.hosting),"Netherlands, USA, UK, Moldova, France","Yes, for a small fee",Yes,Support claims that they allow everything. So far Nym nodes never had any problems,01/2025
|
||||
[Flokinet](https://flokinet.is),"Netherlands, Iceland, Romania,France","Yes, needs a ticket and custom setup","yes, including XMR","Very slow customer support","05/2024"
|
||||
[BitLaunch](https://bitlaunch.io),"Canada, USA, UK","No","Yes","Expensive. Digial Ocean through BitLanch has IPv6","05/2024"
|
||||
[Hostinger](https://hostinger.com),"France, Lithuania, India, USA, Brazil","Yes, out of the box","Yes","Crypto payments must be done per each server monthly or annually.","05/2024"
|
||||
[Linode](https://linode.com),"USA, Canada, Japan, India, Indonesia, Sweden, Netherlands, Germany, Brazil, France, UK, Australia, Italy","Yes out of the box","No, only through [BitLAunch](https://bitlaunch.io)","IPv6 sometimes need to be re-added in Networking tab, no reboot needed","05/2024"
|
||||
[Cherry Servers](https://www.cherryservers.com),"Lithuania, Netherlands, USA, Singapore","No","Yes","Issued IP doesn’t match the location offered by the provider.","05/2024"
|
||||
[Njalla](https://nja.la),"Sweden","Yes","Yes","Privacy vandguards! The biggest VPS 45 is 3 cores only, but it works better than many “larger” servers on the market.","05/2024"
|
||||
[HostSailor](https://hostsailor.com),"USA","Yes, based on ticket","Yes","The IPv6 setup needs custom research and is not documented","05/2024"
|
||||
[Misaka](https://www.misaka.io/),"South Africa","Yes, native support","No","Very Expensive","05/2024"
|
||||
[IsHosting](https://ishosting.com/en),"Brazil, Netherlands","Yes, based on ticket","Yes","Expensive","05/2024"
|
||||
[AlexHost](https://alexhost.com),"Moldova, Bulgaria, Sweden, Netherlands","Yes, on by default","Yes","They allow TOR Bridges, Relays. Exit nodes are only allowed on dedicated servers (prices start from 26 EUR)","07/2024"
|
||||
[iHostArt](https://ihostart.com),"Romania","Yes, on by default","Yes","Super permissive provider. They do allow Tor Exit/Relay/Bridge. Pro-free speech etc. Recently, IPv6 geolocation was set to North Korea, so be aware.","07/2024"
|
||||
[Incognet](https://incognet.io),"Netherlands and USA","Yes, on by default","Yes","They allow Tor exit nodes but you must adhere to their rules https://incognet.io/tor-exits","07/2024"
|
||||
[vSys Host](https://vsys.host),"Ukraine, Netherlands, USA","Yes, on by default","Yes","Pretty permissive provider registered in Ukraine. Should allow Relay/Exit nodes but nothing in T&C, so better double check.","07/2024"
|
||||
[LiteServer](https://liteserver.nl),"Netherlands","Yes, on by default","Yes","Very reliable Dutch provider. They do allow Relay nodes but for Exit nodes you need to contact them. Always check T&C https://liteserver.nl/legal","07/2024"
|
||||
[TerraHost](https://terrahost.no),"Norway","Yes, on by default","Yes","Very reliable Norwegian provider. Only allow exit nodes on Dedicated servers subject to certain caveats (you must open a ticket). Always check T&C https://terrahost.no/avtalebetingelser","07/2024"
|
||||
[Mevspace](https://mevspace.com),"Poland","Yes, on by default","Yes","Flexible Polish providers with 3 DCs in Poland. They do allow Tor Exit nodes but you may need a dedicated server for this. Make sure you open a ticket to check. As of today's date, they have 48h for 1 EUR tariff","07/2024"
|
||||
[Hostiko](https://hostiko.com.ua),"Ukraine, Germany","Yes, on by default","Yes","Ukrainian provider. They allow Exit nodes on Germany boxes but limit the bandwidth, you also have to restrict certain ports like 25 and 587. Make sure you open a ticket.","07/2024"
|
||||
[Hostslick](https://hostslick.com),"Netherlands, Germany","Yes, on by default","Yes","Good amount of bandwidth for the price. Make sure you open the ticket if you want to run Exit node","07/2024"
|
||||
[RDP](https://rdp.sh),"Netherlands, USA, Poland","Yes, on by default","Yes","German provider. Exit nodes are allowed, policy is here https://rdp.sh/docs/faq/tor ports 25,465,587 must be closed. Make sure you open a ticket before running an exit node.","07/2024"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@@ -497,6 +497,13 @@ const config = {
|
||||
permanent: true,
|
||||
basePath: false,
|
||||
},
|
||||
{
|
||||
source: "/operators/testing/node-api-check.html",
|
||||
destination:
|
||||
"/docs/operators/nodes/performance-and-testing/node-api-check",
|
||||
permanent: true,
|
||||
basePath: false,
|
||||
},
|
||||
{
|
||||
source: "/operators/testing/prometheus-grafana.html",
|
||||
destination:
|
||||
@@ -656,6 +663,13 @@ const config = {
|
||||
permanent: true,
|
||||
basePath: false,
|
||||
},
|
||||
{
|
||||
source: "/docs/operators/testing/node-api-check",
|
||||
destination:
|
||||
"/docs/operators/nodes/performance-and-testing/node-api-check",
|
||||
permanent: true,
|
||||
basePath: false,
|
||||
},
|
||||
{
|
||||
source: "/docs/operators/nodes/proxy-configuration",
|
||||
destination:
|
||||
|
||||
@@ -3,6 +3,6 @@
|
||||
|
||||
The Explorer API is the backend for the [Mixnet Explorer](https://explorer.nymtech.net/).
|
||||
|
||||
**This will soon be deprecated in favour of the [Node Status API](ns-api.mdx).**
|
||||
**This will soon be deprecated in favour of the [Node Status API](../ns-api).**
|
||||
|
||||
The code for this service can be found [in our monorepo](https://github.com/nymtech/nym/tree/develop/explorer).
|
||||
|
||||
@@ -16,7 +16,7 @@ You can check that your binaries are properly compiled with:
|
||||
You can check the necessary parameters for the available commands by running:
|
||||
|
||||
```
|
||||
./nym-socks5-client <COMMAND> --help
|
||||
./nym-client <COMMAND> --help
|
||||
```
|
||||
|
||||
## Initialising a new client instance
|
||||
|
||||
@@ -2,3 +2,6 @@
|
||||
The Rust SDK allows developers building applications in Rust to import and interact with Nym clients as they would any other dependency, instead of running the client as a separate process on their machine.
|
||||
|
||||
Check the [development status](./rust/development-status) page to see the various modules that make up the SDK, and the [FFI](./rust/ffi) page for Go/C++ developers.
|
||||
|
||||
### Generate Crate Docs
|
||||
In order to generate the crate docs run `cargo doc --open` from `nym/sdk/rust/nym-sdk/`
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
The `nym-cli` binary can be built by running `cargo build --release` in the `nym/tools/nym-cli` directory.
|
||||
|
||||
## Usage
|
||||
See the [commands](commands.mdx) page for an overview of all command options.
|
||||
See the [commands](./nym-cli/commands.mdx) page for an overview of all command options.
|
||||
|
||||
## Staking on someone's behalf (for custodians)
|
||||
|
||||
|
||||
@@ -1,11 +1,5 @@
|
||||
import { Callout } from 'nextra/components'
|
||||
|
||||
# Cosmos Kit
|
||||
|
||||
<Callout type="warning">
|
||||
The Typescript SDK is currently undergoing maintenance: a network upgrade elsewhere has temporarily caused a problem. These docs are likely to change after we upgrade the SDK.
|
||||
</Callout>
|
||||
|
||||
The wonderful people of Cosmology have made some [fantastic components](https://cosmoskit.com/) that can be used with
|
||||
Nym. These include:
|
||||
|
||||
@@ -23,7 +17,7 @@ npm create vite@latest
|
||||
During the environment setup, choose React and subsequently opt for Typescript if you want your application to function smoothly following this tutorial. Next, navigate to your application directory and run the following commands:
|
||||
```bash
|
||||
cd < YOUR_APP >
|
||||
npm i
|
||||
npm i
|
||||
npm run dev
|
||||
```
|
||||
|
||||
@@ -63,7 +57,7 @@ export default defineConfig({
|
||||
Your components have to be wrapped into a [ChainProvider](https://docs.cosmoskit.com/chain-provider),
|
||||
in order to use the `useChain('nyx')` hook. The nyx chain is provided in the 'chain-registry' NPM package by default.
|
||||
|
||||
Now, go to the `src` folder and open your `App.tsx` file to replace all the code with the following, which will allow you to connect and disconnect a Ledger or Keplr wallet to Nyx:
|
||||
Now, go to the `src` folder and open your `App.tsx` file to replace all the code with the following, which will allow you to connect and disconnect a Ledger or Keplr wallet to Nyx:
|
||||
|
||||
```ts
|
||||
import "./App.css";
|
||||
@@ -74,7 +68,7 @@ import { wallets as ledger } from '@cosmos-kit/ledger';
|
||||
import { wallets as keplr } from '@cosmos-kit/keplr';
|
||||
import { AminoMsg, makeSignDoc } from '@cosmjs/amino';
|
||||
import { MsgSend } from 'cosmjs-types/cosmos/bank/v1beta1/tx';
|
||||
|
||||
|
||||
export const getDoc = (address: string) => {
|
||||
const chainId = 'nyx';
|
||||
const msg: AminoMsg = {
|
||||
@@ -95,28 +89,28 @@ export const getDoc = (address: string) => {
|
||||
const doc = makeSignDoc([msg], fee, chainId, memo, accountNumber, sequence);
|
||||
return doc
|
||||
};
|
||||
|
||||
|
||||
function MyComponent() {
|
||||
const {wallet, address, connect, disconnect, getOfflineSignerAmino } =
|
||||
useChain('nyx');
|
||||
|
||||
|
||||
React.useEffect(() => {
|
||||
connect();
|
||||
disconnect();
|
||||
}, []);
|
||||
|
||||
|
||||
const sign = async () => {
|
||||
if (!address) return
|
||||
const doc = getDoc(address);
|
||||
return getOfflineSignerAmino().signAmino(address, doc);
|
||||
};
|
||||
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div>
|
||||
<div>
|
||||
{wallet &&
|
||||
<div>
|
||||
<div>Connected to {wallet?.prettyName} </div>
|
||||
{wallet &&
|
||||
<div>
|
||||
<div>Connected to {wallet?.prettyName} </div>
|
||||
<div>Address: <code>{address}</code></div>
|
||||
</div>}
|
||||
</div>
|
||||
@@ -132,7 +126,7 @@ function MyComponent() {
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
export default function App() {
|
||||
const assetsFixedUp = React.useMemo(() => {
|
||||
const nyx = assets.find((a) => a.chain_name === 'nyx');
|
||||
@@ -145,7 +139,7 @@ export default function App() {
|
||||
}
|
||||
return assets;
|
||||
}, [assets]);
|
||||
|
||||
|
||||
return (
|
||||
<ChainProvider
|
||||
chains={[chains.find((c) => c.chain_id === 'nyx')!]}
|
||||
@@ -155,10 +149,10 @@ export default function App() {
|
||||
preferredSignType: () => 'amino',
|
||||
}}
|
||||
>
|
||||
|
||||
|
||||
<MyComponent/>
|
||||
</ChainProvider>
|
||||
|
||||
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
import { Callout } from 'nextra/components';
|
||||
|
||||
# `mixFetch`
|
||||
<Callout type="warning">
|
||||
The Typescript SDK is currently undergoing maintenance: a network upgrade elsewhere has temporarily caused a problem. These docs are likely to change after we upgrade the SDK.
|
||||
</Callout>
|
||||
|
||||
An easy way to secure parts or all of your web app is to replace calls to [`fetch`](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch) with `mixFetch`:
|
||||
|
||||
MixFetch works the same as vanilla `fetch` as it's a proxied wrapper around the original function.
|
||||
@@ -17,6 +15,8 @@ Sounds great, are there any catches? Well, there are a few (for now):
|
||||
|
||||
- For now, `mixFetch` cannot deal with concurrent requests with the same base URL.
|
||||
|
||||
Read [this article](https://blog.nym.com/mixfetch-like-the-fetch-api-but-via-the-mixnet-82acfd435c62) to learn more.
|
||||
|
||||
<Callout type="info" emoji="ℹ️">
|
||||
Right now Gateways are not required to run a Secure Websocket (WSS) listener, so only a subset of nodes running in Gateway mode have configured their nodes to do so.
|
||||
|
||||
@@ -35,9 +35,9 @@ curl -X 'GET' \
|
||||
import type { SetupMixFetchOps } from '@nymproject/mix-fetch';
|
||||
|
||||
const mixFetchOptions: SetupMixFetchOps = {
|
||||
preferredGateway: '23A7CSaBSA2L67PWuFTPXUnYrCdyVcB7ATYsjUsfdftb', // with WSS
|
||||
preferredGateway: '6Gb7ftQdKveMjPyrxDXeAtfYAX7Zg5mVZHtnRC5MmZ1B', // with WSS
|
||||
preferredNetworkRequester:
|
||||
'HuNL1pFprNSKW6jdqppibXP5KNKCNJxDh7ivpYcoULN9.C62NahRTUf6kqpNtDVHXoVriQr6yyaU5LtxdgpbsGrtA@23A7CSaBSA2L67PWuFTPXUnYrCdyVcB7ATYsjUsfdftb',
|
||||
'8rRGWy54oC8drFL9DepMegBt2DLrsqQwCoHMXt9nsnTo.2XjCPVbb4FpQ9hNRcXwb9mTzEAVVk1zf1tcch3wdtNEA@6Gb7ftQdKveMjPyrxDXeAtfYAX7Zg5mVZHtnRC5MmZ1B',
|
||||
mixFetchOverride: {
|
||||
requestTimeoutMs: 60_000,
|
||||
},
|
||||
@@ -90,9 +90,9 @@ import { mixFetch, SetupMixFetchOps } from '@nymproject/mix-fetch-full-fat';
|
||||
import React from 'react';
|
||||
|
||||
const mixFetchOptions: SetupMixFetchOps = {
|
||||
preferredGateway: '23A7CSaBSA2L67PWuFTPXUnYrCdyVcB7ATYsjUsfdftb', // with WSS
|
||||
preferredGateway: '6Gb7ftQdKveMjPyrxDXeAtfYAX7Zg5mVZHtnRC5MmZ1B', // with WSS
|
||||
preferredNetworkRequester:
|
||||
'HuNL1pFprNSKW6jdqppibXP5KNKCNJxDh7ivpYcoULN9.C62NahRTUf6kqpNtDVHXoVriQr6yyaU5LtxdgpbsGrtA@23A7CSaBSA2L67PWuFTPXUnYrCdyVcB7ATYsjUsfdftb',
|
||||
'8rRGWy54oC8drFL9DepMegBt2DLrsqQwCoHMXt9nsnTo.2XjCPVbb4FpQ9hNRcXwb9mTzEAVVk1zf1tcch3wdtNEA@6Gb7ftQdKveMjPyrxDXeAtfYAX7Zg5mVZHtnRC5MmZ1B',
|
||||
mixFetchOverride: {
|
||||
requestTimeoutMs: 60_000,
|
||||
},
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
import { Callout } from 'nextra/components'
|
||||
|
||||
# Mixnet Client
|
||||
<Callout type="warning">
|
||||
The Typescript SDK is currently undergoing maintenance: a network upgrade elsewhere has temporarily caused a problem. These docs are likely to change after we upgrade the SDK.
|
||||
</Callout>
|
||||
|
||||
As you know by now, in order to send or receive messages over the mixnet, you'll need to use the [`SDK Client`](https://www.npmjs.com/package/@nymproject/sdk), which will allow you to create apps that can use the Nym mixnet and Coconut credentials.
|
||||
|
||||
This client is message based - it can only send a one-way message to another client's address.
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
import { Callout } from 'nextra/components'
|
||||
|
||||
# Nym Smart Contract Clients
|
||||
<Callout type="warning">
|
||||
The Typescript SDK is currently undergoing maintenance: a network upgrade elsewhere has temporarily caused a problem. These docs are likely to change after we upgrade the SDK.
|
||||
</Callout>
|
||||
|
||||
As previously mentioned, to query or execute on any of the Nym contracts, you'll need to use one of the [`Contract Clients`](https://www.npmjs.com/package/@nymproject/contract-clients), which contains read-only query and signing clients for all of Nym's smart contracts.
|
||||
|
||||
##### Contract Clients list
|
||||
@@ -31,14 +29,14 @@ npm create vite@latest
|
||||
During the environment setup, choose React and subsequently opt for Typescript if you want your application to function smoothly following this tutorial. Next, navigate to your application directory and run the following commands:
|
||||
```bash
|
||||
cd < YOUR_APP >
|
||||
npm i
|
||||
npm i
|
||||
npm run dev
|
||||
```
|
||||
|
||||
##### Installation
|
||||
Install the packages and their dependencies if you don't already have them:
|
||||
```bash
|
||||
npm install @nymproject/contract-clients @cosmjs/cosmwasm-stargate
|
||||
npm install @nymproject/contract-clients @cosmjs/cosmwasm-stargate
|
||||
```
|
||||
|
||||
## Query clients
|
||||
@@ -145,7 +143,7 @@ import { SigningCosmWasmClient } from "@cosmjs/cosmwasm-stargate";
|
||||
import { DirectSecp256k1HdWallet } from "@cosmjs/proto-signing";
|
||||
import { GasPrice } from "@cosmjs/stargate";
|
||||
import { settings } from "./settings";
|
||||
|
||||
|
||||
export default function Exec() {
|
||||
let signer: DirectSecp256k1HdWallet;
|
||||
let signerMixnetClient: any;
|
||||
@@ -155,7 +153,7 @@ export default function Exec() {
|
||||
let nodeAddress: string;
|
||||
let amountToSend: string;
|
||||
let delegations: any;
|
||||
|
||||
|
||||
async function ExecuteOnNyx() {
|
||||
// Cosmos client
|
||||
signer = await DirectSecp256k1HdWallet.fromMnemonic(settings.mnemonic, {
|
||||
@@ -170,7 +168,7 @@ export default function Exec() {
|
||||
);
|
||||
// Save globally
|
||||
cosmWasmSigningClient = cosmWasmClient;
|
||||
|
||||
|
||||
// Nym client
|
||||
const mixnetClient = new contracts.Mixnet.MixnetClient(
|
||||
cosmWasmSigningClient,
|
||||
@@ -179,9 +177,9 @@ export default function Exec() {
|
||||
);
|
||||
// Save globally
|
||||
signerMixnetClient = mixnetClient;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Get delegations
|
||||
const getDelegations = async () => {
|
||||
if (!signerMixnetClient) {
|
||||
@@ -192,7 +190,7 @@ export default function Exec() {
|
||||
});
|
||||
delegations = delegationsObject;
|
||||
};
|
||||
|
||||
|
||||
// Make delegation
|
||||
const doDelegation = async () => {
|
||||
if (!signerMixnetClient) {
|
||||
@@ -206,7 +204,7 @@ export default function Exec() {
|
||||
);
|
||||
console.log(res);
|
||||
};
|
||||
|
||||
|
||||
// Undelegate all
|
||||
const doUndelegateAll = async () => {
|
||||
for (const delegation of delegations.delegations) {
|
||||
@@ -216,7 +214,7 @@ export default function Exec() {
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Sending tokens
|
||||
const doSendTokens = async () => {
|
||||
const memo = "test sending tokens";
|
||||
@@ -229,10 +227,10 @@ export default function Exec() {
|
||||
);
|
||||
console.log(res);
|
||||
};
|
||||
|
||||
|
||||
ExecuteOnNyx();
|
||||
setTimeout(() => getDelegations(), 1000);
|
||||
|
||||
|
||||
return (
|
||||
<div>
|
||||
<p>Exec</p>
|
||||
|
||||
@@ -1,15 +1,10 @@
|
||||
import "@interchain-ui/react/styles"
|
||||
import { CosmosKit } from "../../../../components/cosmos-kit";
|
||||
import { Callout } from 'nextra/components'
|
||||
import FormattedCosmoskitExampleCode from '../../../../code-examples/sdk/typescript/cosmoskit-example-code.mdx';
|
||||
|
||||
# Cosmos Kit
|
||||
|
||||
import { Callout } from 'nextra/components'
|
||||
|
||||
<Callout type="warning">
|
||||
The Typescript SDK is currently undergoing maintenance: a network upgrade elsewhere has temporarily caused a problem. These docs are likely to change after we upgrade the SDK.
|
||||
</Callout>
|
||||
|
||||
Below is an example that uses [CosmosKit](https://cosmoskit.com/) to connect and sign a fake transaction with your [Keplr wallet](https://www.keplr.app/) or
|
||||
[Ledger hardware wallet](https://www.ledger.com/) to this page:
|
||||
|
||||
|
||||
@@ -5,10 +5,6 @@ import Box from '@mui/material/Box';
|
||||
import FormattedMixFetchExampleCode from '../../../../code-examples/sdk/typescript/mixfetch-example-code.mdx';
|
||||
import { Callout } from 'nextra/components'
|
||||
|
||||
<Callout type="warning">
|
||||
The Typescript SDK is currently undergoing maintenance: a network upgrade elsewhere has temporarily caused a problem. These docs are likely to change after we upgrade the SDK.
|
||||
</Callout>
|
||||
|
||||
<Callout type="info" emoji="ℹ️">
|
||||
Right now Gateways are not required to run a Secure Websocket (WSS) listener, so only a subset of nodes running in Gateway mode have configured their nodes to do so.
|
||||
|
||||
|
||||
@@ -3,11 +3,6 @@
|
||||
import { Mixnodes } from '../../../../components/mixnodes';
|
||||
import Box from '@mui/material/Box';
|
||||
import FormattedExampleCode from '../../../../code-examples/sdk/typescript/mixnodes-example-code.mdx';
|
||||
import { Callout } from 'nextra/components'
|
||||
|
||||
<Callout type="warning">
|
||||
The Typescript SDK is currently undergoing maintenance: a network upgrade elsewhere has temporarily caused a problem. These docs are likely to change after we upgrade the SDK.
|
||||
</Callout>
|
||||
|
||||
The Nym Mixnet contract keeps a directory of all mixnodes that can be used to mix traffic.
|
||||
|
||||
|
||||
@@ -4,9 +4,6 @@ import { Traffic } from '../../../../components/traffic';
|
||||
import Box from '@mui/material/Box';
|
||||
import FormattedTrafficExampleCode from '../../../../code-examples/sdk/typescript/traffic-example-code.mdx';
|
||||
|
||||
<Callout type="warning">
|
||||
The Typescript SDK is currently undergoing maintenance: a network upgrade elsewhere has temporarily caused a problem. These docs are likely to change after we upgrade the SDK.
|
||||
</Callout>
|
||||
|
||||
Use this tool to experiment with the mixnet: send and receive messages!
|
||||
|
||||
|
||||
@@ -10,13 +10,6 @@ import FormattedWalletConnectCode from '../../../../code-examples/sdk/typescript
|
||||
import FormattedWalletSendTokensCode from '../../../../code-examples/sdk/typescript/wallet-sendTokens-code.mdx';
|
||||
import FormattedWalletDelegationsCode from '../../../../code-examples/sdk/typescript/wallet-delegations-code.mdx';
|
||||
|
||||
|
||||
import { Callout } from 'nextra/components'
|
||||
|
||||
<Callout type="warning">
|
||||
The Typescript SDK is currently undergoing maintenance: a network upgrade elsewhere has temporarily caused a problem. These docs are likely to change after we upgrade the SDK.
|
||||
</Callout>
|
||||
|
||||
Here's a small wallet example using testnet for you to test out!
|
||||
|
||||
<WalletContextProvider>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# Network Components
|
||||
|
||||
Core components:
|
||||
* A **Mixnet**, which mixes Sphinx packet traffic so that it cannot be determined who is communicating with whom. Our mixnet is based on a modified version of the [**Loopix** design](concepts/loopix). This is made up of [Nym nodes](architecture/mixnet#nodes) runnning on servers around the world maintained by a decentralised group of Operators.
|
||||
* Various [**Nym clients**](architecture/mixnet#nym-clients) which manage sending and receiving Sphinx packets, encrypting/decrypting traffic, and providing [cover traffic](./concepts/cover-traffic) to hide 'real' traffic timing.
|
||||
* A **Mixnet**, which mixes Sphinx packet traffic so that it cannot be determined who is communicating with whom. Our mixnet is based on a modified version of the [**Loopix** design](concepts/loopix). This is made up of [Nym nodes](architecture/mixnet/nodes) runnning on servers around the world maintained by a decentralised group of Operators.
|
||||
* Various [**Nym clients**](architecture/mixnet/clients) which manage sending and receiving Sphinx packets, encrypting/decrypting traffic, and providing [cover traffic](./concepts/cover-traffic) to hide 'real' traffic timing.
|
||||
* A CosmWasm-enabled blockchain called [**Nyx**](architecture/nyx), the home of the various smart contracts used by the mixnet. A subset of Nyx Validators run [NymAPI](./architecture/nyx#nymapi) instances, taking part in also producing and verifying [zk-nym credentials](cryptography/zk-nym).
|
||||
|
||||

|
||||
|
||||
@@ -66,7 +66,7 @@ The Vesting contract has multiple functions:
|
||||
* Interacting with the Mixnet using vesting (i.e. non-transferable) tokens, allowing users to delegate their unvested tokens.
|
||||
|
||||
### Multisig Contract
|
||||
The multisig contract used by the [NymAPI Quroum](../cryptography/zk-nym/zk-nym-overview) - a subset of the Nyx Validator set taking on the additional work of generating and validating zk-nyms - to execute certain actions in the [zk-nym](../cryptography/zk-nym) contract.
|
||||
The multisig contract used by the [NymAPI Quroum](../cryptography/zk-nym/zk-nym-overview) - a subset of the Nyx Validator set taking on the additional work of generating and validating zk-nyms - to execute certain actions in the [zk-nym](./ecash.md) contract.
|
||||
|
||||
It is essentially an instance of the [canonical](https://github.com/CosmWasm/cw-plus/tree/main/contracts) `cw3-flex-multisig` using the `cw4-group` contract, with one minor change to restrict the addresses allowed to submit proposals.
|
||||
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import { Steps } from 'nextra/components';
|
||||
import { Steps } from 'nextra/components'
|
||||
import { VarInfo } from 'components/variable-info.tsx';
|
||||
import { Tabs } from 'nextra/components';
|
||||
import { MyTab } from 'components/generic-tabs.tsx';
|
||||
|
||||
# Pre-built Binaries
|
||||
|
||||
@@ -20,62 +18,20 @@ If the pre-built binaries don't work or are unavailable for your system, you wil
|
||||
- Download from your terminal using `curl` or `wget` tool:
|
||||
```sh
|
||||
# using curl
|
||||
curl -L <LINK> -o <PATH>
|
||||
curl -L <LINK> -o <PATH>/nym-node
|
||||
|
||||
# using wget
|
||||
wget <LINK>
|
||||
```
|
||||
In case you want to download binary to your current working directory, drop `<PATH>` from the command
|
||||
|
||||
###### 2. Verify the binary `sha256sum` hash
|
||||
In case you want to download binary to your current working directory, drop `<PATH>` from the command
|
||||
|
||||
<div>
|
||||
<Tabs items={[
|
||||
<strong>Manual check</strong>,
|
||||
<strong>One-liner</strong>,
|
||||
]} defaultIndex="0">
|
||||
<MyTab>
|
||||
To see your binary `sha256sum` hash, run:
|
||||
```sh
|
||||
sha256sum <BINARY>
|
||||
```
|
||||
```sh
|
||||
# for example
|
||||
# sha256sum ./nym-wallet_1.2.15_amd64.AppImage
|
||||
# or
|
||||
# sha256sum ./nym-node
|
||||
```
|
||||
- Download [`hashes.json`](https://github.com/nymtech/nym/releases) file from the same same *Assets* drop down like your binary
|
||||
- Open it with your text editor or print its content with `cat hashes.json`
|
||||
- Check it if your binary `sha256sum` output is in `hashes.json` by using the `sha256sum` and searching for it or using `grep` command:
|
||||
```
|
||||
grep -i <SHA_HASH>
|
||||
```
|
||||
</MyTab>
|
||||
<MyTab>
|
||||
- Download [`hashes.json`](https://github.com/nymtech/nym/releases) file from the same same *Assets* drop down like your binary
|
||||
- Run this command, substituting `<BINARY>` with your the one you want to check:
|
||||
```sh
|
||||
sha256sum <BINARY> | awk '{print $1}' | grep -qF "$(jq -r '.assets | to_entries | .[].value.sha256' hashes.json)" && echo "Hash matches an asset in the JSON file." || echo "Hash does not match any asset in the JSON file."
|
||||
```
|
||||
```sh
|
||||
# for example
|
||||
# sha256sum ./nym-node | awk '{print $1}' | grep -qF "$(jq -r '.assets | to_entries | .[].value.sha256' hashes.json)" && echo "Hash matches an asset in the JSON file." || echo "Hash does not match any asset in the JSON file."
|
||||
```
|
||||
</MyTab>
|
||||
</Tabs>
|
||||
</div>
|
||||
|
||||
- If your have to extract the binary (it would look like like `<BINARY>.tar.gz`) do it:
|
||||
```sh
|
||||
tar -xvzf <BINARY>.tar.gz
|
||||
```
|
||||
|
||||
###### 3. Make the binary executable
|
||||
###### 2. Make the binary executable
|
||||
- Open terminal in the same directory and run:
|
||||
```sh
|
||||
chmod u+x <BINARY>
|
||||
# for example: chmod u+x nym-node
|
||||
chmod +x <BINARY>
|
||||
# for example: chmod +x nym-mixnode
|
||||
```
|
||||
|
||||
</Steps>
|
||||
|
||||
@@ -5,6 +5,8 @@ import { VarInfo } from 'components/variable-info.tsx';
|
||||
import { AccordionTemplate } from 'components/accordion-template.tsx';
|
||||
import { Steps } from 'nextra/components';
|
||||
|
||||
|
||||
|
||||
export const TestingSteps = () => (
|
||||
<div>
|
||||
Testing steps performed
|
||||
@@ -30,251 +32,15 @@ export const TunnelManagerCommands = () => (
|
||||
);
|
||||
|
||||
|
||||
|
||||
# Changelog
|
||||
|
||||
This page displays a full list of all the changes during our release cycle from `v2024.3-eclipse` onward. Operators can find here the newest updates together with links to relevant documentation. The list is sorted so that the newest changes appear first.
|
||||
|
||||
**Note:** Any information published on this page was up to date at the time of writing. We do *not* maintain changelog retrospectively.
|
||||
**Note:** Any information shared on this page was up to date at the time of writing. We do *not* maintain changelog retrospectively.
|
||||
|
||||
<VarInfo />
|
||||
|
||||
## `v2025.1-reeses`
|
||||
|
||||
- [Release Binaries](https://github.com/nymtech/nym/releases/tag/nym-binaries-v2025.1-reeses)
|
||||
- [`nym-node`](nodes/nym-node.mdx) version `1.3.1`
|
||||
|
||||
```
|
||||
nym-node
|
||||
Binary Name: nym-node
|
||||
Build Timestamp: 2025-01-16T11:54:17.079662337Z
|
||||
Build Version: 1.3.1
|
||||
Commit SHA: 5ab164d229f85bd2dd27ec6e38292c281df2f678
|
||||
Commit Date: 2025-01-16T12:51:53.000000000+01:00
|
||||
Commit Branch: HEAD
|
||||
rustc Version: 1.84.0
|
||||
rustc Channel: stable
|
||||
cargo Profile: release
|
||||
```
|
||||
|
||||
### Operators Updates & Tools
|
||||
|
||||
<Callout type="info">
|
||||
From `nym-node v1.3.0` operators can choose multiple functionalities for their `nym-node` binary (flagged as `--mode`).
|
||||
|
||||
**However, the clients are yet to be developed to be able to make a proper selection for multi-mode nodes and therefore we ask operators to sign only one functionality to `--mode` option at a time. Please chose out of: `mixnode` or `entry-gateway` or `exit-gateway`.**
|
||||
|
||||
We are developing a design where operators can enable multiple modes, and let the Nym API to position the node according the network's needs in the beginning of each epoch.
|
||||
</Callout>
|
||||
|
||||
- [Node functionality info updated](nodes/nym-node/setup#functionality-mode)
|
||||
- [Fund your `nym-node` inbuilt Nyx account](nodes/nym-node/bonding#fund-nym-node-client-nyx-account) to prepare for gateway ticket rewarding
|
||||
- `config.toml` changes:
|
||||
- Replaced `mode` with `modes` to allow setting the node to run with say, `entry` + `mixnode` roles simultaneously
|
||||
- Added `maximum_forward_packet_delay` to `mixnet.debug` section
|
||||
- Moved `verloc` section from `mixnode.verloc` to top level
|
||||
- Removed `mixnode` section
|
||||
- Removed `entry_gateway` section to `gateway_tasks`
|
||||
- Moved `authenticator` section from `gateway_tasks` (`entry_gateway`) to `service_providers` (`exit_gateway`)
|
||||
- Renamed `exit_gateway` section to `service_providers`
|
||||
- Moved top level `authenticator` section to `service_providers` so that it'd live alongside NR and IPR
|
||||
- Added general `debug` section
|
||||
- Added `metrics` section
|
||||
- All documentation migrated to a new URL [nym.com/docs](https://nym.com/docs) alongside the rebranding of Nym organisation.
|
||||
- Updated [network architecture diagrams](https://nym.com/docs/network/architecture)
|
||||
- New blow-by-blow mixnet [traffic flow](https://nym.com/docs/network/architecture) section
|
||||
- [Winter Nym Squad League started](https://forum.nym.com/t/nym-squad-league-farewell-fall-welcome-winter/977)
|
||||
- From this release onward (New Year) Operators Updates & Tools will be on top of each release changelog followed by features, cryptography and bugfix parts.
|
||||
- All 2024 release notes were moved to the bottom section called [Archived changelog](#archived-changelog)
|
||||
|
||||
### Features
|
||||
|
||||
- [build(deps): bump micromatch from `4.0.4` to `4.0.8` in `/testnet-faucet`](https://github.com/nymtech/nym/pull/4813): Bumps [micromatch](https://github.com/micromatch/micromatch) from `4.0.4` to `4.0.8`.
|
||||
- [Move NS client to separate package under NS API](https://github.com/nymtech/nym/pull/5171):
|
||||
- Moving NS API client code to separate package outside NS Agent makes the code cleaner & more modular
|
||||
- NS agent now imports NS API client that it uses
|
||||
- No functionality change in NS API or NS agent
|
||||
- [Introduced initial internal commands for nym-cli: ecash key and request generation](https://github.com/nymtech/nym/pull/5174)
|
||||
- [NS API - Gateway stats scraping](https://github.com/nymtech/nym/pull/5180): This PR adds a metrics scraper that fetches metrics from the `metrics/sessions` endpoint on gateway. The entries are stored and served on the API for one year
|
||||
- [Remove explorer dependency](https://github.com/nymtech/nym/pull/5190)
|
||||
- [Hopefully final steps of the smoosh™️](https://github.com/nymtech/nym/pull/5201): this PR is a bit more extensive than initially planned because of all the spaghetti that had to be untangled to make it all happen. The general idea is that now it's possible to run your node simultaneously in multiple modes. for example `mixnode` + `entry` or `entry` + `exit`, etc. The modes do the following:
|
||||
- `mixnode`: allows the node to handle **forward** sphinx packets
|
||||
- `entry-gateway`: allows the node to accepts websocket connections from incoming clients and to handle **final hop** sphinx packets
|
||||
- `exit-gateway`: allows the node to handle **final hop** sphinx packets as well as starts NR and IPR service providers
|
||||
Furthermore, if node runs with `wireguard` enabled, it will start local `authenticator` service provider which will also implicitly enable final hop packet handling regardless of the underlying mode. There are also various of other smaller (and bigger) changes:
|
||||
- Upon receiving a forward packet, its delay is now clamped so that one could not dos the node by asking it to delay it for, for example, a year
|
||||
- As mentioned above, node can now run in multiple modes at the same time,
|
||||
- `/metrics/mixing` endpoint got deprecated (it still provides the same information, however) and might be removed in future release
|
||||
- Introduced `/metrics/packet-stats` endpoint that provides more extensive information about packets received/sent
|
||||
- It is now possible to control whether the node should log its statistics to console
|
||||
- The console logs are also updated with the current packet rates
|
||||
- All nodes now run the "verloc" protocol and measure every other node on the network
|
||||
- Metrics got revamped and unified:
|
||||
- All running metrics are stored in a single `NymNodeMetrics` struct
|
||||
- There exists a `MetricsAggregator` that listens to any metrics events that might require additional processing
|
||||
- Any new metrics event types can be easily added by registering a new handler via `register_handler`. the type must implement `MetricsHandler` trait and use unique variant of `MetricsEvent` enum. for example `GatewaySessionStatsHandler`. It is, however, possible to have opaque handlers, such as the already implemented `LegacyMixingStatsUpdater` and `MixnetMetricsCleaner`
|
||||
- Everything in `mixnode` directory has been removed because there was nothing really left there. The mixing socket listener was unified in `nym-node` and similarly `verloc` was also moved there
|
||||
- `gateway` directory was similarly reduced in size. Now it also creates appropriate tasks as opposed to the whole gateway process. eventually it might also be further stripped, but today is not that day.
|
||||
- Removed the generic parameter on the `GatewayStorage` to simplify all the generics down the stack. it wasn't used anyway
|
||||
|
||||
CLI:
|
||||
- Added `--modes` argument to specify all node modes with a single command (or `env` variable). for example: `--modes="mixnode,entry"`. Can't be used alongside `--modes`
|
||||
- Extended `--mode` argument to allow specifying it multiple times, for example: `--mode mixnode --mode entry`. can't be used alongside `--mode`
|
||||
|
||||
Config changes:
|
||||
- Replaced `mode` with `modes` to allow setting the node to run with say, `entry` + `mixnode` roles simultaneously
|
||||
- Added `maximum_forward_packet_delay` to `mixnet.debug` section
|
||||
- Moved `verloc` section from `mixnode.verloc` to top level
|
||||
- Removed `mixnode` section
|
||||
- Removed `entry_gateway` section to `gateway_tasks`
|
||||
- Moved `authenticator` section from `gateway_tasks` (`entry_gateway`) to `service_providers` (`exit_gateway`)
|
||||
- Renamed `exit_gateway` section to `service_providers`
|
||||
- Moved top level `authenticator` section to `service_providers` so that it'd live alongside NR and IPR
|
||||
- Added general `debug` section
|
||||
- Added `metrics` section
|
||||
- [Better date serialization](https://github.com/nymtech/nym/pull/5207): Proper date serialization for NS API session stats
|
||||
- [Restore Location fields](https://github.com/nymtech/nym/pull/5208): restore `latitude` and `longitude` fields
|
||||
- [Derive serialize for UserAgent](https://github.com/nymtech/nym/pull/5210)
|
||||
- [Change sqlite journal mode to WAL](https://github.com/nymtech/nym/pull/5213)
|
||||
- [Shipping raw metrics to PG](https://github.com/nymtech/nym/pull/5216)
|
||||
- [Extend raw ws fd for gateway client](https://github.com/nymtech/nym/pull/5218)
|
||||
- [Add fd callback to client core](https://github.com/nymtech/nym/pull/5230)
|
||||
- [TicketType derive Hash and Eq](https://github.com/nymtech/nym/pull/5233): It's useful to keep `TicketType` in maps, which require `Hash`. Also derive `Eq` since it's useful.
|
||||
- [Extend swagger docs](https://github.com/nymtech/nym/pull/5235)
|
||||
- [Add FromStr impl for UserAgent](https://github.com/nymtech/nym/pull/5236): Add `FromStr` implementation for `UserAgent` to make it easier to pass in custom user agent in vpn clients as a CLI argument.
|
||||
- [Remove unneeded async function annotation](https://github.com/nymtech/nym/pull/5246)
|
||||
- [Add control messages to `GatewayTransciver`](https://github.com/nymtech/nym/pull/5247)
|
||||
<AccordionTemplate name={<TestingSteps/>}>
|
||||
**Review and Testing: Forget Me Implementation**
|
||||
|
||||
- Validated the encryption and delivery of `ForgetMe` control messages to the gateway
|
||||
|
||||
**Testing: MixTrafficController Integration**
|
||||
|
||||
- Verified that the `MixTrafficController` invokes `ForgetMe` logic correctly during shutdown
|
||||
- Tested behaviour for gateway transceiver failures while sending control messages
|
||||
|
||||
**Testing: Gateway Storage Updates**
|
||||
- Confirmed successful deletion of client data (e.g., inbox messages, bandwidth allocations) from persistent storage
|
||||
</AccordionTemplate>
|
||||
|
||||
- [Add conversion unit tests for auth msg](https://github.com/nymtech/nym/pull/5251)
|
||||
- [Update TS bindings](https://github.com/nymtech/nym/pull/5255)
|
||||
- [Removed legacy socks5 listener](https://github.com/nymtech/nym/pull/5259)
|
||||
- [Add PATCH support to `nym-http-api-client`](https://github.com/nymtech/nym/pull/5260): Add `PATCH` support to `nym-http-api-client` crate
|
||||
- [Wireguard metrics](https://github.com/nymtech/nym/pull/5278): With this PR on each peer controller update the following global metrics information are also updated:
|
||||
- total bytes tx
|
||||
- total bytes rx
|
||||
- current active peers
|
||||
- total peers registered
|
||||
- The former two are exposed with REST endpoints `/api/v1/metrics/wireguard-stats`, while the rest will be accessible via prometheus (soon ™️ ). The wireguard stats are also logged to the console (assuming they're non-zero)
|
||||
- [Add close to credential storage](https://github.com/nymtech/nym/pull/5283): Add close method to credential storage
|
||||
<AccordionTemplate name={<TestingSteps/>}>
|
||||
1. **Review File: `common/credential-storage/src/backends/sqlite.rs`**
|
||||
- Verified addition of `close` method for the SQLite backend
|
||||
|
||||
2. **Review File: `common/credential-storage/src/ephemeral_storage.rs`**
|
||||
- Confirmed addition of `close` method for ephemeral storage with no action required
|
||||
|
||||
3. **Review File: `common/credential-storage/src/persistent_storage/mod.rs`**
|
||||
- Ensured `close` method integration for persistent storage
|
||||
|
||||
4. **Review File: `common/credential-storage/src/storage.rs`**
|
||||
- Verified updates to the `Storage` trait to include `close` and `cleanup_expired` methods
|
||||
</AccordionTemplate>
|
||||
|
||||
- [Cherry picked \#5286](https://github.com/nymtech/nym/pull/5287)
|
||||
<AccordionTemplate name={<TestingSteps/>}>
|
||||
1. **Review File: `common/network-defaults/src/constants.rs`**
|
||||
- Confirmed updated `mixnet_vpn` constants were added.
|
||||
|
||||
2. **Review File: `service-providers/ip-packet-router/src/constants.rs`**
|
||||
- Checked replacement of legacy `TUN_*` constants with new `mixnet_vpn` constants.
|
||||
- Validated alignment of routing traffic configurations.
|
||||
|
||||
3. **Review File: `service-providers/ip-packet-router/src/ip_packet_router.rs`**
|
||||
- Ensured new `nym_network_defaults::constants::mixnet_vpn` constants replaced old references.
|
||||
- Verified `TunDeviceConfig` consistency.
|
||||
|
||||
4. **Review File: `service-providers/ip-packet-router/src/util/generate_new_ip.rs`**
|
||||
- Confirmed substitution of `TUN_DEVICE_*` constants with `NYM_TUN_DEVICE_*` constants.
|
||||
- Tested functionality for generating random IPs within subnet.
|
||||
</AccordionTemplate>
|
||||
|
||||
- [Expand `nym-node` prometheus metrics](https://github.com/nymtech/nym/pull/5298): This PR undusts the `/api/v1/metrics/prometheus` and introduces the following **37** new data points:
|
||||
<AccordionTemplate name="New data points">
|
||||
- mixnet:
|
||||
- ingress:
|
||||
- `nym_node_mixnet_ingress_forward_hop_packets_received`
|
||||
- `nym_node_mixnet_ingress_final_hop_packets_received`
|
||||
- `nym_node_mixnet_ingress_malformed_packets_received`
|
||||
- `nym_node_mixnet_ingress_excessive_delay_packets`
|
||||
- `nym_node_mixnet_ingress_forward_hop_packets_dropped`
|
||||
- `nym_node_mixnet_ingress_final_hop_packets_dropped`
|
||||
|
||||
- `nym_node_mixnet_ingress_forward_hop_packets_received_rate`
|
||||
- `nym_node_mixnet_ingress_final_hop_packets_received_rate`
|
||||
- `nym_node_mixnet_ingress_malformed_packets_received_rate`
|
||||
- `nym_node_mixnet_ingress_excessive_delay_packets_rate`
|
||||
- `nym_node_mixnet_ingress_forward_hop_packets_dropped_rate`
|
||||
- `nym_node_mixnet_ingress_final_hop_packets_dropped_rate`
|
||||
|
||||
- egress:
|
||||
- `nym_node_mixnet_egress_stored_on_disk_final_hop_packets`
|
||||
- `nym_node_mixnet_egress_forward_hop_packets_sent`
|
||||
- `nym_node_mixnet_egress_ack_packets_sent`
|
||||
- `nym_node_mixnet_egress_forward_hop_packets_dropped`
|
||||
|
||||
- `nym_node_mixnet_egress_forward_hop_packets_sent_rate`
|
||||
- `nym_node_mixnet_egress_ack_packets_sent_rate`
|
||||
- `nym_node_mixnet_egress_forward_hop_packets_dropped_rate`
|
||||
|
||||
- client sessions
|
||||
- `nym_node_entry_client_sessions_unique_users`
|
||||
- `nym_node_entry_client_sessions_sessions_started`
|
||||
- `nym_node_entry_client_sessions_finished_sessions`
|
||||
- `nym_node_entry_client_sessions_durations_{TYP}` (histogram), for example `nym_node_entry_client_sessions_durations_vpn`
|
||||
|
||||
- wireguard:
|
||||
- `nym_node_wireguard_bytes_rx`
|
||||
- `nym_node_wireguard_bytes_tx`
|
||||
- `nym_node_wireguard_bytes_total_peers`
|
||||
- `nym_node_wireguard_bytes_active_peers`
|
||||
|
||||
- `nym_node_wireguard_bytes_rx_rate`
|
||||
- `nym_node_wireguard_bytes_tx_rate`
|
||||
|
||||
|
||||
- network
|
||||
- `nym_node_network_active_ingress_mixnet_connections`
|
||||
- `nym_node_network_active_ingress_web_socket_connections`
|
||||
- `nym_node_network_active_egress_mixnet_connections`
|
||||
|
||||
- process
|
||||
- `nym_node_process_forward_hop_packets_being_delayed`
|
||||
- `nym_node_process_packet_forwarder_queue_size`
|
||||
- `nym_node_process_topology_query_resolution_latency` (histogram)
|
||||
- `nym_node_process_final_hop_packets_pending_delivery`
|
||||
- `nym_node_process_forward_hop_packets_pending_delivery`
|
||||
</AccordionTemplate>
|
||||
|
||||
- [Amend 250gb limit](https://github.com/nymtech/nym/pull/5313): Change bandwidth cap to 250gb
|
||||
- [Warn users if node is run in exit mode only](https://github.com/nymtech/nym/pull/5320): Throws a warning if node is run in "exit" mode only as by default, this will **NOT** enable entry capabilities, i.e. opening the websocket. thus making it ineligible for rewarded set selection (and rewards)
|
||||
- [Reduce log severity for number of packets being delayed](https://github.com/nymtech/nym/pull/5321)
|
||||
- [Apply 1.84 linter suggestions](https://github.com/nymtech/nym/pull/5330)
|
||||
- [Readjusted --mode behaviour to fix the regression](https://github.com/nymtech/nym/pull/5331)
|
||||
- [Legacy alert](https://github.com/nymtech/nym/pull/5346): alert moved into `nav` components
|
||||
|
||||
|
||||
### Bugfix
|
||||
|
||||
- [Fix overflow](https://github.com/nymtech/nym/pull/5184)
|
||||
- [Fix overflow again](https://github.com/nymtech/nym/pull/5204)
|
||||
- [Make sure to update timestamp of last batch verification to prevent double redemption](https://github.com/nymtech/nym/pull/5239)
|
||||
- [Make sure to apply gateway score filtering when choosing initial node](https://github.com/nymtech/nym/pull/5256)
|
||||
- [Fixed client session histogram buckets](https://github.com/nymtech/nym/pull/5316)
|
||||
- [Contract version assignment](https://github.com/nymtech/nym/pull/5318): This PR fixes updates to current nym-node version as well as introduces migration to fix the existing state of the mainnet contract
|
||||
- [Make sure refresh data key matches bond info](https://github.com/nymtech/nym/pull/5329): This is to forbid operators from reusing the same underlying identity key for multiple nodes by overwriting the describe data. the reported key has to always match what the node has bonded with (and the contract enforces uniqueness)
|
||||
|
||||
## Archived Changelog
|
||||
|
||||
To allow reading through older changelogs, we store them below sorted by years.
|
||||
@@ -525,7 +291,7 @@ cargo Profile: release
|
||||
|
||||
- `nym-node` has now implemented [IPv6 support for wireguard](https://github.com/nymtech/nym/pull/5059)
|
||||
|
||||
- [`network_tunnel_manager.sh` updated](https://raw.githubusercontent.com/nymtech/nym/refs/heads/develop/scripts/network_tunnel_manager.sh): run the commands below to make sure
|
||||
- [`network_tunnel_manager.sh` updated](network): run the commands below to make sure
|
||||
|
||||
<br />
|
||||
|
||||
@@ -659,7 +425,7 @@ systemctl daemon-reload && service nym-node restart
|
||||
|
||||
- Since `v2024.13-magura`, operators do not update their node version in the wallet. [Manual upgrading steps](nodes/maintenance/manual-upgrade.mdx) has been updated accordingly.
|
||||
|
||||
- CLI tool `node_api_check.py`, helping operators to collect all API values about their nodes locally, is not up to date with the API changes introduced with `v2024.13-magura` release version. Please treat it as unstable before we fix it.
|
||||
- CLI tool [`node_api_check.py`](nodes/performance-and-testing/node-api-check.mdx), helping operators to collect all API values about their nodes locally, is not up to date with the API changes introduced with `v2024.13-magura` release version. Please treat it as unstable before we fix it.
|
||||
|
||||
#### Error Log
|
||||
|
||||
@@ -967,7 +733,7 @@ Confirm that the deployment workflows work through manual testing
|
||||
### Operators Updates & Tooling
|
||||
|
||||
<Callout type="warning" emoji="⚠️">
|
||||
**Every operator has to make sure that their nodes self-described endpoint works, otherwise the node will be un-routable and thus won't get any rewards!**
|
||||
**Every operator has to make sure that their nodes [self-described endpoint works](nodes/performance-and-testing/node-api-check#basic-api-usage), otherwise the node will be un-routable and thus won't get any rewards!**
|
||||
</Callout>
|
||||
|
||||
- **New technical documentation:** All Nym documentation starts from a new entry page [nymtech.net/docs](https://nymtech.net/docs/operators/introduction). To run locally or propose collaboration, start in our [repository](https://github.com/nymtech/nym/tree/develop/documentation)
|
||||
@@ -1165,7 +931,7 @@ Some endpoints got purposely deprecated without any equivalent reimplemented sin
|
||||
##### Mixnet Contract
|
||||
|
||||
<Callout type="warning" emoji="">
|
||||
**Every operator has to make sure that their nodes self-described endpoint works, otherwise the node will be un-routable and thus won't get any rewards!**
|
||||
**Every operator has to make sure that their nodes [self-described endpoint works](nodes/performance-and-testing/node-api-check#basic-api-usage), otherwise the node will be un-routable and thus won't get any rewards!**
|
||||
</Callout>
|
||||
|
||||
###### High Level Changes
|
||||
@@ -1979,7 +1745,7 @@ done
|
||||
- Vesting contract functionalities have been purged, users can only remove tokens from vesting
|
||||
- Migrating from `mixnode` or `gateway` smart contracts to a new unifying `nym-node` smart contract will be available soon using Nym desktop wallet, just like you are used to for bonding and node settings. After this migration all `nym-nodes` will be able to receive delegation and rewards. We will share a step by step guide once this migration will be deployed. No action needed now.
|
||||
|
||||
- Nym API Check CLI is upgraded according to the latest API endpoints, output is cleaner and more concise.
|
||||
- [Nym API Check CLI](testing/node-api-check.md) is upgraded according to the latest API endpoints, output is cleaner and more concise.
|
||||
|
||||
|
||||
#### Operators Tasks
|
||||
@@ -2868,7 +2634,7 @@ warning: /home/alice/src/nym/nym/common/dkg/Cargo.toml: `default-features` is ig
|
||||
- Flow [chart](release-cycle.md#release-flow)
|
||||
- [Sandbox testnet](sandbox.md) guide: teaching Nym node operators how to run their nodes in Nym Sandbox testnet environment.
|
||||
- [Terms & Conditions flag](nodes/setup.md#terms--conditions)
|
||||
- Node API Check CLI
|
||||
- [Node API Check CLI](testing/node-api-check.md)
|
||||
- [Pruning VPS `syslog` scripts](troubleshooting/vps-isp.md#pruning-logs)
|
||||
- [Black-xit: Exiting the blacklist](troubleshooting/nodes.md#my-gateway-is-blacklisted)
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
## Nym Network
|
||||
|
||||
To see different stats about Nym Network live, we recommend you to visit [Nym Harbourmaster](https://harbourmaster.nymtech.net) and dynamic [Nym token page](https://nymtech.net/about/token).
|
||||
To see different stats about Nym Network live, we recommend you to visit [Nym Harbourmaster](https://harbourmaster.nymtech.net) and dynamic [Nym token page](https://nymtech.net/about/token.
|
||||
|
||||
### Is there an explorer for Nym Mixnet?
|
||||
|
||||
@@ -12,7 +12,7 @@ Yes, there are..
|
||||
|
||||
* [Nym Explorer](https://explorer.nymtech.net/)
|
||||
* [Sandbox testnet](https://sandbox-explorer.nymtech.net/)
|
||||
* [Nym Harbourmaster](https://harbourmaster.nymtech.net)
|
||||
* [Nym Harbourmaster](https://harbourmaster.nymtech.net)
|
||||
|
||||
**Built by community**
|
||||
|
||||
@@ -43,3 +43,5 @@ At this point the most crucial component needed are [Exit Gateways](../nodes/nym
|
||||
### Are Nym Nodes whitelisted?
|
||||
|
||||
Nope, anyone can run a Nym Node. whether your node is chosen to mix is purely reliant on the node's performance and reputation (self stake + delegations).
|
||||
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@ import { Callout } from 'nextra/components';
|
||||
import { Steps } from 'nextra/components';
|
||||
import { Tabs } from 'nextra/components';
|
||||
import NymNodeSpecs from 'components/operators/snippets/nym-node-specs.mdx';
|
||||
import TermsConditions from 'components/operators/snippets/tc-info.mdx';
|
||||
|
||||
# Nym Nodes Operator Guides
|
||||
|
||||
@@ -26,25 +25,21 @@ Reserve 45-120 minutes for the initial setup and configuration (depends on your
|
||||
|
||||
Outdated nodes are never selected for routing/mixing packets, resulting in not receiving any rewards. You can read more on our [Tokenomics page](tokenomics/mixnet-rewards.mdx) to understand the selection and rewards logic.
|
||||
|
||||
<TermsConditions />
|
||||
|
||||
Accepting T&Cs is done via a flag `--accept-operator-terms-and-conditions` added explicitly to `nym-node run` command every time. Detailed info and proper syntax is provided on the [setup page](nodes/nym-node/setup#terms--conditions).
|
||||
|
||||
## Steps for Nym Node Operators
|
||||
|
||||
This is a summary of all needed steps for node operators to setup and configure a `nym-node` and register it to Nym Network:
|
||||
|
||||
|
||||
1. **Start with [Preliminary Steps](nodes/preliminary-steps.mdx), preparing:**
|
||||
- [VPS](nodes/preliminary-steps/vps-setup.mdx)
|
||||
- [Nym wallet](nodes/preliminary-steps/wallet-preparation)
|
||||
1. **Start with [Preliminary Steps](preliminary-steps.mdx), preparing:**
|
||||
- [VPS](preliminary-steps/vps-setup.mdx)
|
||||
- [Nym wallet](preliminary-steps/wallet-preparation/mdx)
|
||||
|
||||
2. **[Setup](nodes/nym-node/setup.mdx) the node**
|
||||
2. **[Setup](nym-node/setup.mdx) the node**
|
||||
|
||||
3. **[Configure](nodes/nym-node/configuration.mdx) the node and (optionally) automation, Wireguard, WSS, reverse proxy ...**
|
||||
3. **[Configure](nym-node/configuration.mdx) the node and (optionally) automation, Wireguard, WSS, reverse proxy ...**
|
||||
|
||||
4. **[Run](nodes/nym-node/setup.mdx#initialise--run) the node or [the service](nodes/nym-node/configuration.md#systemd)**
|
||||
4. **[Run](nym-node/setup.mdx#initialise--run) the node or [the service](nym-node/configuration.md#systemd)**
|
||||
|
||||
5. **[Bond](nodes/nym-node/bonding.mdx) the node to the Nym API, using Nym wallet**
|
||||
5. **[Bond](nym-node/bonding.mdx) the node to the Nym API, using Nym wallet**
|
||||
|
||||
Make sure to follow the steps thoroughly, in case you find any point difficult don't hesitate to ask in our [Operators channel](https://matrix.to/#/#operators:nymtech.chat).
|
||||
|
||||
@@ -101,31 +101,23 @@ For more information about your node's port configuration, check the [port refer
|
||||
|
||||
Anything can happen to the server on which your node is running. To back up your `nym-node` keys and configuration protects the operators against the negative impact of unexpected events. To restart your node on another server, two essential pieces are needed:
|
||||
|
||||
1. **Node keys to initialise the same node on a new VPS**
|
||||
2. **Access to the bonding Nyx account (wallet seeds) to update host on the Mixnet smart contract**
|
||||
1. Node keys to initialise the same node on a new VPS
|
||||
2. Access to the bonding Nym account (wallet seeds) to edit the IP on smart contract
|
||||
|
||||
Optionally, it can be useful to have a backup your configuration directories to setup [reverse proxy and WSS](nym-node/configuration/proxy-configuration.mdx) quickly as well.
|
||||
|
||||
Assuming that everyone access their wallets from local machine and does *not* store their seeds on VPS, point \#2 should be a given.
|
||||
Assuming that everyone access their wallets from local machine and does *not* store their seeds on VPS, point 2. should be a given.
|
||||
To backup your `nym-node` keys and configuration in the easiest way possible, copy the entire config directory `.nym` from your VPS to your local desktop, using a special copy command `scp`:
|
||||
|
||||
<Callout type="warning" emoji="⚠️">
|
||||
Never store your mnemonic seed anywhere online nor do *not* share it with anyone!
|
||||
</Callout>
|
||||
|
||||
To backup your `nym-node` keys and configuration in the easiest way possible, copy the entire config directory `.nym` from your VPS to your local machine, using a special copy command `scp`:
|
||||
|
||||
<Steps>
|
||||
|
||||
###### 1. Create a local directory where you want to store your backup
|
||||
###### 1. Create a directory where you want to store your backup
|
||||
```sh
|
||||
mkdir -pv <PATH_TO_TARGET_DIRECTORY>
|
||||
```
|
||||
|
||||
```sh
|
||||
# for example
|
||||
# mkdir -pv $HOME/backup/my_nym_node/.nym
|
||||
```
|
||||
|
||||
###### 2. Copy configuration folder `.nym` from your VPS to your newly created backup directory
|
||||
|
||||
```sh
|
||||
@@ -138,96 +130,37 @@ The `scp` command should print logs, an operator can see directly whether it was
|
||||
|
||||
</Steps>
|
||||
|
||||
Now you have everything needed to restore your `nym-node` on another server. If you are in a need of doing so, follow the steps in [*Restoring a node*](#restoring-a-node) chapter below.
|
||||
|
||||
### Backup proxy configuration
|
||||
|
||||
If you run your node behind a [reverse proxy and WSS](nym-node/configuration/proxy-configuration.mdx) (suggested for all Exit Gateways), you may find it useful to backup configuration directories for that as well. It's done by following the same logic, using `scp` command for remote copy:
|
||||
|
||||
<Callout>
|
||||
Given that servers hosting a `nym-node` are expected to be a single purpose machines, we assume in this guide, that there are no other `<HOSTNAME>` sub-directories in `/var/www` and `/etc/nginx/sites-available` then the ones relevant to `nym-node`. In case you prefer to only backup configuration for a particular hostname, just append your `<HOSTNAME>` to the path in the commands below.
|
||||
</ Callout>
|
||||
|
||||
<Steps>
|
||||
|
||||
###### 1. Create local sub-directories where you want to store your backup
|
||||
|
||||
```sh
|
||||
mkdir -pv <PATH_TO_TARGET_DIRECTORY>
|
||||
mkdir -pv <PATH_TO_TARGET_DIRECTORY>
|
||||
```
|
||||
|
||||
```sh
|
||||
# for example
|
||||
# mkdir -pv $HOME/backup/my_nym_node/var/www
|
||||
# mkdir -pv $HOME/backup/my_nym_node/etc/nginx/sites-available
|
||||
```
|
||||
|
||||
###### 1. Backup `/var/www` directory
|
||||
|
||||
```sh
|
||||
scp -r <SOURCE_USER_NAME>@<SOURCE_HOST_ADDRESS>:/var/www <PATH_TO_TARGET_DIRECTORY>
|
||||
```
|
||||
|
||||
###### 2. Backup `/etc/nginx/sites-available` directory
|
||||
|
||||
```sh
|
||||
scp -r <SOURCE_USER_NAME>@<SOURCE_HOST_ADDRESS>:/etc/nginx/sites-available <PATH_TO_TARGET_DIRECTORY>
|
||||
```
|
||||
|
||||
###### 3. Verify the success of the backup
|
||||
|
||||
The `scp` command should print logs, an operator can see directly whether it was successful or if it encountered any error. However, double check that all your needed configuration is in the backup target directory.
|
||||
|
||||
</Steps>
|
||||
|
||||
<Callout type="info">
|
||||
To copy files from the root directory (paths starting with `/`), you need root permissions on the remote machine. If your server is not running as the root user, the `scp` command won't work directly, as using the `sudo` prefix would apply to your local machine instead of the remote server.
|
||||
|
||||
To resolve this, you need to SSH into the remote server first, and there use the `sudo cp -r <SOURCE_PATH> <TARGET_PATH>` command to copy the necessary directories to a location outside the root directory. After that, you can run `scp` with the correct source path to transfer the files.
|
||||
</Callout>
|
||||
|
||||
## Restoring a node
|
||||
|
||||
In case your VPS was terminated and you have a [backup](#backup-a-node) of your node keys and access to your [bonding](nym-node/bonding) wallet, you can easily restore your node on another server without losing your delegation.
|
||||
In case your VPS shut down and you have a [backup](#backup-a-node) of your node keys and access to your bonding wallet, you can easily restore your node on another server without losing your delegation.
|
||||
|
||||
<Steps>
|
||||
|
||||
###### 1. Prepare new VPS
|
||||
|
||||
SSH into your new VPS and start with:
|
||||
- On VPS: Do all [preliminary steps](preliminary-steps.mdx) needed to run a `nym-node`.
|
||||
|
||||
- Do all [preliminary steps](preliminary-steps.mdx) needed to run a `nym-node`.
|
||||
|
||||
- Create a `.nym/nym-nodes` configuration folder:
|
||||
- On VPS: Create a `.nym/nym-nodes` configuration folder:
|
||||
```sh
|
||||
mkdir -pv ~/.nym/nym-nodes
|
||||
```
|
||||
|
||||
###### 2. Restore your node configuration
|
||||
|
||||
Copy the folder with your node configuration and keys from your local machine to the newly created folder on your VPS using `scp` command. Make sure to grab the entire `nym-node` configuration folder, which is called after your local `nym-node` identifier (`<ID>`), the `-r` (recursive) flag will take care of all sub-directories and their content:
|
||||
|
||||
From machine where your node is backed up (usually local desktop): Copy the folder with your node keys and configuration to the newly created folder on your VPS using `scp` command. Make sure to grab the entire `nym-node` configuration folder, which is called after your local `nym-node` identifier (`<ID>`), the `-r` (recursive) flag will take care of all sub-directories and their content:
|
||||
```sh
|
||||
scp -r <PATH_TO_LOCAL_NODE_CONFIGURATION_FOLDER> <VPS_USER_NAME>@<VPS_HOST_ADDRESS>:~/.nym/nym-nodes/
|
||||
```
|
||||
```sh
|
||||
# for example:
|
||||
scp -r $HOME/backup/my_nym_node/.nym/nym-nodes/default-nym-node root@my-nym-node:~/.nym/nym-nodes/
|
||||
```
|
||||
|
||||
###### 3. Verify the success of the backup
|
||||
|
||||
The `scp` command should print logs, an operator can see directly whether it was successful or if it encountered any error. However, double check that all your needed configuration is in the target directory `.nym/nym-nodes` on your VPS.
|
||||
|
||||
|
||||
###### 4. Configure your node on the new VPS
|
||||
###### 3. Configure your node on the new VPS
|
||||
|
||||
* Edit `~/.nym/nym-nodes/<ID>/config/config.toml` config with the new listening address IP - it's the one under the header `[host]`, called `public_ips = [<PUBLIC_IPS>,]` and add your new location (field `location = <LOCATION>`, formats like: 'Jamaica', or two-letter alpha2 (e.g. 'JM'), three-letter alpha3 (e.g. 'JAM') or three-digit numeric-3 (e.g. '388') can be provided). You can see your IP by running a command `echo "$(curl -4 https://ifconfig.me)"`.
|
||||
|
||||
* SSH to your VPS
|
||||
* Run a command `echo "$(curl -4 https://ifconfig.me)"` to see your public IPv4
|
||||
* Edit config file located at `~/.nym/nym-nodes/<ID>/config/config.toml` correct IP - it's the field under the header `[host]`, called `public_ips = [<PUBLIC_IPS>,]`
|
||||
* Add your new location field `location = <LOCATION>`, (formats like: 'Jamaica', or two-letter alpha2 (e.g. 'JM'), three-letter alpha3 (e.g. 'JAM') or three-digit numeric-3 (e.g. '388') can be provided).
|
||||
* Try to run the node and see if everything works.
|
||||
|
||||
* Setup the [systemd](nym-node/configuration.mdx#systemd) automation (don't forget to add the [terms and conditions flag](nym-node/setup.mdx#terms--conditions)) to `ExecStart` command, reload the daemon and run the service.
|
||||
|
||||
###### 4. Change the node smart contract info via the wallet interface
|
||||
@@ -236,63 +169,6 @@ Open Nym Wallet, go to *Bonding*, open *Settings* and change *Host* value to the
|
||||
|
||||
</Steps>
|
||||
|
||||
Everything should work now. If not, have a look through the `config.toml` file and ensure that there are no details from the past VPS, things like WSS port, landing page asset etc. If you had a configuration with reverse proxy and WSS, continue to set that up as well. If you had it backed up, you can follow the steps to [restore proxy configuration](#restore-proxy-configuration) below, or you can start to [configure proxy from scratch](nym-node/configuration/proxy-configuration.mdx).
|
||||
|
||||
### Restoring proxy configuration
|
||||
|
||||
If operators moving to a new server had their [proxy configuration backed up](#backup-proxy-configuration), it's possible to simply restore it, following these steps:
|
||||
|
||||
<Steps>
|
||||
###### 1. Copy your backed up directory `/var/www` for landing page to the server
|
||||
- Start setting up reverse proxy and WSS following [this guide](nym-node/configuration/proxy-configuration.mdx) but instead of creating a new `/var/www/<HOSTNAME>` directory, simply copy there the one from the old server, using `scp` command
|
||||
|
||||
```sh
|
||||
scp -r <PATH_TO_LOCAL_WWW_CONFIGURATION_BACKUP> <VPS_USER_NAME>@<VPS_HOST_ADDRESS>:/var/www/
|
||||
```
|
||||
```sh
|
||||
# for example:
|
||||
scp -r $HOME/backup/my_nym_node/var/www root@my-nym-node:/var/www
|
||||
```
|
||||
###### 2. Make sure that domain is correctly setup
|
||||
As you see in the guide you use a domain (same like your `<HOSTNAME>`), make sure you have it registered as and redirected to the new IP by logging into your DNS provider and editing the dashboard of the domain.
|
||||
|
||||
###### 3. Proceed with all needed `node` configuration
|
||||
- In the guide follow the steps to [configure your node reverse proxy](nym-node/configuration/proxy-configuration#reverse-proxy-configuration), like installing Nginx, opening the needed ports etc
|
||||
|
||||
###### 4. Restore Nginx config
|
||||
- When you arrive to the point to configure your [`/etc/nginx/sites-available/<HOSTNAME>`](nym-node/configuration/proxy-configuration#2-add-your-endpoint-configuration-to-nginx-by-creating-a-config-file), use again `scp` instead of creating a new one
|
||||
|
||||
```sh
|
||||
scp -r <PATH_TO_LOCAL_NGINX_CONFIGURATION_BACKUP> <VPS_USER_NAME>@<VPS_HOST_ADDRESS>:/etc/nginx/sites-available
|
||||
```
|
||||
```sh
|
||||
# for example:
|
||||
scp -r $HOME/backup/my_nym_node/etc/nginx/sites-available root@my-nym-node:/etc/nginx/sites-available
|
||||
```
|
||||
###### 5. Edit Nginx configuration file with correct hostname
|
||||
- Open the Nginx config file on your server and see if a domain name needs to be changed to new one. To open the file, use for example nano text editor:
|
||||
```sh
|
||||
nano /etc/nginx/sites-available/<HOSTNAME>
|
||||
```
|
||||
###### 6. Continue with the Nginx setup
|
||||
- Go back to the [proxy setup guide](nym-node/configuration/proxy-configuration#3-activate-and-test-nginx-configuration) and continue from the point [\#3](nym-node/configuration/proxy-configuration#3-activate-and-test-nginx-configuration)
|
||||
|
||||
###### 7. Edit WSS configuration with the correct hostname
|
||||
- Open the WSS config file on your server and see if a domain name needs to be changed to new one. To open the file, use for example nano text editor:
|
||||
```sh
|
||||
nano /etc/nginx/sites-available/wss-config-nym
|
||||
```
|
||||
###### 8. Finish and test the setup
|
||||
|
||||
Continue with the [activating and testing](nym-node/configuration/proxy-configuration#2-activate-and-test-nginx-wss-configuration) your reverse proxy and WSS until the end of the guide.
|
||||
</ Steps>
|
||||
|
||||
<Callout type="info">
|
||||
To copy files to the root directory (paths starting with `/`), you need root permissions on the remote machine. If your server is not running as the root user, the `scp` command won't work directly, as using the `sudo` prefix would apply to your local machine instead of the remote server.
|
||||
|
||||
To resolve this, you can SSH into the remote server and create the configuration files manually using the prefix `sudo` and then copy their content from your local backup.
|
||||
</Callout>
|
||||
|
||||
## Moving a node
|
||||
|
||||
In case of a need to move a Nym Node from one machine to another and avoiding to lose the delegation, here are few steps how to do it.
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { VarInfo } from 'components/variable-info.tsx';
|
||||
import {Callout} from 'nextra/components';
|
||||
import { VarInfo } from 'components/variable-info.tsx'
|
||||
|
||||
# Nym Node
|
||||
|
||||
|
||||
NYM NODE is a tool for running a node within the Nym network. Nym Nodes containing functionality such as `mixnode`, `entry-gateway` and `exit-gateway` are fundamental components of Nym Mixnet architecture. Nym Nodes are ran by decentralised node operators.
|
||||
|
||||
To setup any type of Nym Node, start with either building [Nym's platform](../binaries/building-nym.mdx) from source or download [pre-compiled binaries](../binaries/pre-built-binaries.mdx) on the [configured server (VPS)](preliminary-steps/vps-setup.mdx) where you want to run the node. Your Nym Node will need to be bonded before it can be run. We recommend most users use the [Nym desktop wallet](preliminary-steps/wallet-preparation.mdx) for this.
|
||||
|
||||
@@ -28,15 +28,11 @@ Do not bond your node to the API if the previous steps weren't finished. Bad con
|
||||
|
||||
Any new bonded node will provide only the bare minimum information: host, identity key and optionally custom port of its HTTP API - we highly recommend to set that one up to `8080`. Everything else will be discovered via the self-described API for maximum flexibility. This also includes the sphinx key, meaning if the API is not exposed, the node will be unable to route any traffic.
|
||||
|
||||
**Every operator has to make sure that their nodes [self-described endpoint works](../performance-and-testing#functionality--performance-check), otherwise the node will be un-routable and thus won't get any rewards!**
|
||||
|
||||
<Callout type="warning" emoji="⚠️">
|
||||
**Reveal your menominc phrase only in areas out of surveillance of other people and never share it with others. Nym team will never ask you for your mnemonic phrase - in case you were asked by someone it's a scam, do *not* reply to it!**
|
||||
</Callout>
|
||||
**Every operator has to make sure that their nodes [self-described endpoint works](nodes/performance-and-testing/node-api-check#basic-api-usage), otherwise the node will be un-routable and thus won't get any rewards!**
|
||||
|
||||
## Bond via the Desktop wallet (recommended)
|
||||
|
||||
You can bond your `nym-node` via the Desktop wallet. Nym wallet, just like any Nym binary can be downloaded, verified and made executable following [these simple steps](../../binaries/pre-built-binaries#setup-binaries).
|
||||
You can bond your `nym-node` via the Desktop wallet.
|
||||
|
||||
<Steps>
|
||||
|
||||
@@ -120,13 +116,18 @@ From `nym-wallet` version `1.2.15` onward the application allows and prompts ope
|
||||
|
||||
<Steps>
|
||||
|
||||
###### 1. Download the latest wallet from [the release page](https://github.com/nymtech/nym/releases), verify and make executable
|
||||
###### 1. Download the latest wallet from [the release page](https://github.com/nymtech/nym/releases)
|
||||
|
||||
Nym wallet, just like any Nym binary can be downloaded, verified and made executable following [these simple steps](../../binaries/pre-built-binaries#setup-binaries).
|
||||
###### 2. Verify the binary and extract it if needed
|
||||
|
||||
###### 2. Open the wallet and sign in
|
||||
- Download [`hashes.json`](https://github.com/nymtech/nym/releases/download/nym-wallet-v1.2.15/hashes.json)
|
||||
- Open it with your text editor or print it's content with `cat hashes.json`
|
||||
- Run `sha256sum <WALLET_BINARY>` for example `sha256sum ./nym-wallet_1.2.15_amd64.AppImage`
|
||||
- If your have to extract it (like `.tar.gz`) do it
|
||||
|
||||
###### 3. Migrate!
|
||||
###### 3. Open the wallet and sign in
|
||||
|
||||
###### 4. Migrate!
|
||||
|
||||
- Go to Bonding and you will be prompted with such message:
|
||||
|
||||
@@ -149,48 +150,3 @@ Versions older than `nym-wallet v 1.2.15` will not allow bonding new nodes.
|
||||
## 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](../../../developers/tools/nym-cli/usage#usage) docs.
|
||||
|
||||
## Fund `nym-node` Client Nyx Account
|
||||
|
||||
<Callout type="info">
|
||||
This is not relevant for operators running exclusively `mixnode` functionality. For any type of gateway functionality this is a preparation requirement for the upcoming [ticket rewarding](../../tokenomics/mixnet-rewards#roadmap).
|
||||
</ Callout>
|
||||
|
||||
Every `nym-node` client contains a mnemonic of a Nyx account, generated with node initialisation (first `run` command creating all configuration and data files). This mnemonic is located in `$HOME/.nym/nym-nodes/<ID>/data/cosmos_mnemonic`. **This is *not* the same account as the one used for bonding!**
|
||||
|
||||
This client account will be used for the process of redemption of [zk-nym tickets](../../../network/cryptography/zk-nym) collected by nodes running as `entry-gateway` and `exit-gateway` as the redemption requires gateway to create a multisig proposal on the chain for which the client (node) needs to pay transaction fee.
|
||||
|
||||
Giving the low transaction cost on Cosmos, funding your client Nyx account with 25 NYM tokens should be more than enough. To do so, follow these steps:
|
||||
|
||||
<Steps>
|
||||
|
||||
###### 1. Get your `nym-node` client Nyx account mnemonic phrase
|
||||
- Make sure your screen is not exposed to other people or recording devices
|
||||
- To store sensitive credentials use audited and open source password managers, like [KeePassXC](https://keepassxc.org/)
|
||||
- To print out your node client mnemonic phrase, run:
|
||||
```sh
|
||||
cat $HOME/.nym/nym-nodes/<ID>/data/cosmos_mnemonic
|
||||
```
|
||||
```sh
|
||||
# for example
|
||||
# cat $HOME/.nym/nym-nodes/default-nym-node/data/cosmos_mnemonic
|
||||
```
|
||||
- **Alternatively:** You can use `scp` command to copy the file `cosmos_mnemonic` remotely. If this is your preference, use this command:
|
||||
```sh
|
||||
scp <USER>@<HOST>:.nym/nym-nodes/<ID>/data/cosmos_mnemonic <LOCAL_TARGET_PATH>
|
||||
```
|
||||
- Copy this phrase and save it to your password manager
|
||||
|
||||
|
||||
###### 2. Get the address of your client Nyx account using desktop wallet
|
||||
- Open desktop wallet and choose to sign in with mnemonic
|
||||
- Use the phrase from step 1
|
||||
- Open `Receive` tab and copy Nym account address
|
||||
- We recommend operators to store this address for future funding
|
||||
|
||||
###### 3. Fund the client Nyx account
|
||||
- Open wallet with Nym tokens and send a minimum of 25 NYM to the address copied in the previous step
|
||||
- In case you don't have any spare NYM, you can send tokens from any exchange directly to the address copied in the previous step
|
||||
</ Steps>
|
||||
|
||||
Now your `nym-node` client can use inbuilt Nyx account to create a multisig proposal on chain and redeem user tickets.
|
||||
|
||||
@@ -7,25 +7,22 @@ import BuildInfo from 'components/outputs/command-outputs/nym-node-build-info.md
|
||||
import NymNodeHelp from 'components/outputs/command-outputs/nym-node-help.md';
|
||||
import NymNodeRunHelp from 'components/outputs/command-outputs/nym-node-run-help.md';
|
||||
import { AccordionTemplate } from 'components/accordion-template.tsx';
|
||||
import TermsConditions from 'components/operators/snippets/tc-info.mdx';
|
||||
|
||||
# Nym Node Setup & Run
|
||||
|
||||
This documentation page provides a guide on how to set up and run a [NYM NODE](../nym-node.mdx), along with explanations of available flags, commands, and examples.
|
||||
|
||||
<VarInfo/ >
|
||||
|
||||
## Current version
|
||||
|
||||
```sh
|
||||
nym-node
|
||||
Binary Name: nym-node
|
||||
Build Timestamp: 2025-01-16T11:54:17.079662337Z
|
||||
Build Version: 1.3.1
|
||||
Commit SHA: 5ab164d229f85bd2dd27ec6e38292c281df2f678
|
||||
Commit Date: 2025-01-16T12:51:53.000000000+01:00
|
||||
Build Timestamp: 2024-12-18T10:18:42.978852430Z
|
||||
Build Version: 1.2.1
|
||||
Commit SHA: 8d5a41a790e96ae5e821964865affaa7d3343eab
|
||||
Commit Date: 2024-12-18T11:07:49.000000000+01:00
|
||||
Commit Branch: HEAD
|
||||
rustc Version: 1.84.0
|
||||
rustc Version: 1.83.0
|
||||
rustc Channel: stable
|
||||
cargo Profile: release
|
||||
```
|
||||
@@ -34,39 +31,52 @@ cargo Profile: release
|
||||
<BuildInfo />
|
||||
*/}
|
||||
|
||||
## Functionality (mode)
|
||||
## Summary
|
||||
|
||||
<Callout type="info">
|
||||
From `nym-node v1.3.0` operators can choose multiple functionalities for their `nym-node` binary (flagged as `--mode`).
|
||||
|
||||
**However, the clients are yet to be developed to be able to make a proper selection for multi-mode nodes and therefore we ask operators to sign only one functionality to `--mode` option at a time. Please chose out of: `mixnode` or `entry-gateway` or `exit-gateway`.**
|
||||
<VarInfo/ >
|
||||
|
||||
We are developing a design where operators can enable multiple modes, and let the Nym API to position the node according the network's needs in the beginning of each epoch.
|
||||
</Callout>
|
||||
To run a new node, you can simply execute the `nym-node` command without any flags. By default, the node will set necessary configurations. If you later decide to change a setting, you can use the `-w` flag.
|
||||
|
||||
Nym Node has three functionalities in the network: `entry-gateway`, `mixnode` and `exit-gateway`.
|
||||
The most crucial aspect of running the node is specifying the `--mode`. At the moment it can be only one of three: `mixnode`, `entry-gateway`, and `exit-gateway`.
|
||||
|
||||
- **Entry Gateway (`--mode entry-gateway`)**: A the node to which local client connects. It checks the bandwidth allowance, using [zk-nyms](../../../network/cryptography/zk-nym) and either sends [Sphinx packets](../../../network/cryptography/sphinx) through the mixnet or directly to Exit Gateway in case of dVPN (2-hop) routing. This node also recieves replies and sends them back to users local client.
|
||||
Currently the `nym-node` binary can only be run in a single `--mode` at any one time. In the future however, operators will be able to specify multiple modes that a single `nym-node` binary can run. Our goal is to have as many nodes as possible enabling multiple modes, and allow the Nym API to position the node according the network's needs in the beginning of each epoch.
|
||||
|
||||
- **Mixnode (`--mode mixnode`)**: Nodes organized in three layers, randmoly selected every epoch (60 minutes), mixing Sphinx packets, adding a slight latency to defend users agains time correlation attacks and sending them further to the next layer or to the Exit Gateway
|
||||
Every `exit-gateway` mode is basically an `entry-gateway` with NR (Network Requester) and IPR (IP Packet Router) enabled. This means that every `exit-gateway` is automatically seen as an `entry-gateway` but not the opposite.
|
||||
|
||||
- **Exit Gateway (`--mode exit-gateway`)**: The final node in the mixnet. It puts all packets together and using inbuilt Network requester and IP packet router, it sends traffic to the open internet. This node also recieves replies and sends them back to the user client.
|
||||
Gateway operators can check out the node performance, connectivity and much more in our new tool [harbourmaster.nymtech.net](https://harbourmaster.nymtech.net/).
|
||||
|
||||
<Callout type="warning">
|
||||
Exit Gateway is the only node routing data directly to the open internet. Therefore it exposes IP of operators server (VPS) to abuse complains. Before you decide to run an Exit Gateway, please read our [Community Counsel pages](../../community-counsel/exit-gateway) containing more information and some legal content.
|
||||
</Callout>
|
||||
To determine which mode your node is running, you can check the `:8080/api/v1/roles` endpoint. For example:
|
||||
```sh
|
||||
# sustitude <IPv4_ADDRESS> or <HOSTNAME> with the one corresponding to your node
|
||||
# for http
|
||||
http://<IPv4_ADDRESS>:8080/api/v1/roles
|
||||
# or
|
||||
http://<IPv4_ADDRESS>/api/v1/roles
|
||||
|
||||
Everything essential for each mode exists on `nym-node` by default. For instance, if you run a Mixnode, you'll find that a NR (Network Requester) and IPR (IP Packet Router) addresses exist, but they will be ignored in `mixnode` mode.
|
||||
# for reversed proxy/WSS
|
||||
https://<HOSTNAME>/api/v1/roles
|
||||
```
|
||||
|
||||
Note that every `exit-gateway` mode is basically an `entry-gateway` with NR (Network Requester) and IPR (IP Packet Router) enabled. This means that every `exit-gateway` can work as an `entry-gateway` but not the opposite.
|
||||
Everything necessary will exist on your node by default. For instance, if you're running a mixnode, you'll find that a NR (Network Requester) and IPR (IP Packet Router) address exist, but they will be ignored in `mixnode` mode.
|
||||
|
||||
## Command & Examples
|
||||
For more information about available endpoints and their status, you can refer to:
|
||||
```sh
|
||||
# sustitude <IPv4_ADDRESS> or <HOSTNAME> with the one corresponding to your node
|
||||
# for http
|
||||
http://<IPv4_ADDRESS>:8080/api/v1/swagger/#/
|
||||
# or
|
||||
http://<IPv4_ADDRESS>/api/v1/swagger/#/
|
||||
|
||||
**`nym-node` introduces a default human readible ID (local only) `default-nym-node`, which is used if there is not an explicit custom `--id <ID>` specified. All configuration is stored in `~/.nym/nym-nodes/default-nym-node/config/config.toml` or `~/.nym/nym-nodes/<ID>/config/config.toml` respectively.**
|
||||
# for reversed proxy/WSS
|
||||
https://<HOSTNAME>/api/v1/swagger/#/
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### Help Command
|
||||
|
||||
There are a few changes from the individual binaries used in the past. For example by default `run` command does initialisation function as well, local node `--id` will be set by default (1default-nym-node`) unless specified otherwise.
|
||||
There are a few changes from the individual binaries used in the past. For example by default `run` command does `init` function as well, local node `--id` will be set by default unless specified otherwise etcetera.
|
||||
|
||||
<Callout type="info" emoji="ℹ️">
|
||||
You can always use `--help` flag to see the commands or arguments associated with a given command.
|
||||
@@ -86,7 +96,13 @@ To list all available flags for each command, run `./nym-node <COMMAND> --help`
|
||||
The Wireguard flags currently have limited functionality. From version `1.1.6` ([`v2024.9-topdeck`](https://github.com/nymtech/nym/releases/tag/nym-binaries-v2024.9-topdeck)) wireguard is available and recommended to be switched on for nodes running as Gateways. Keep in mind that this option needs a bit of a special [configuration](configuration.md#wireguard-setup).
|
||||
</Callout>
|
||||
|
||||
<TermsConditions />
|
||||
### Terms & Conditions
|
||||
|
||||
<Callout type="info" emoji="ℹ️">
|
||||
From `nym-node` version `1.1.3` onward is required to accept [**Operators Terms & Conditions**](https://nymtech.net/terms-and-conditions/operators/v1.0.0) in order to be part of the active set. Make sure to read them before you add the flag.
|
||||
</Callout>
|
||||
|
||||
There has been a long ongoing discussion whether and how to apply Terms and Conditions for Nym network operators, with an aim to stay aligned with the philosophy of Free Software and provide legal defense for both node operators and Nym developers. To understand better the reasoning behind this decision, you can listen to the first [Nym Operator Town Hall](https://www.youtube.com/live/7hwb8bAZIuc?si=3mQ2ed7AyUA1SsCp&t=915) introducing the T&Cs or to [Operator AMA with CEO Harry Halpin](https://www.youtube.com/watch?v=yIN-zYQw0I0) from June 4th, 2024, explaining pros and cons of T&Cs implementation.
|
||||
|
||||
Accepting T&Cs is done via a flag `--accept-operator-terms-and-conditions` added explicitly to `nym-node run` command every time. If you use [systemd](configuration.md#systemd) automation, add the flag to your service file's `ExecStart` line.
|
||||
|
||||
@@ -110,6 +126,14 @@ curl -X 'GET' \
|
||||
}
|
||||
```
|
||||
|
||||
### Commands & Examples
|
||||
|
||||
**`nym-node` introduces a default human readible ID (local only) `default-nym-node`, which is used if there is not an explicit custom `--id <ID>` specified. All configuration is stored in `~/.nym/nym-nodes/default-nym-node/config/config.toml` or `~/.nym/nym-nodes/<ID>/config/config.toml` respectively.**
|
||||
|
||||
<Callout type="info" emoji="ℹ️">
|
||||
All commands with more options listed below include `--accept-operator-terms-and-conditions` flag, read [Terms & Conditions](#terms--conditions) chapter above before executing these commands.
|
||||
</Callout>
|
||||
|
||||
#### Essential Parameters & Variables
|
||||
|
||||
Running a `nym-node` in a `mixnode` mode requires less configuration than a full `exit-gateway` setup, we recommend operators to still follow through with all documented [configuration](configuration.md). Before you scroll down to syntax examples for the mode of your choice please familiarise yourself with the essential [paramters and variables](../../variables.mdx) convention we use in the guide.
|
||||
@@ -119,13 +143,13 @@ To prevent over-flooding of our documentation we cannot provide with every singl
|
||||
</Callout>
|
||||
|
||||
|
||||
## Setup & Run
|
||||
### Initialise & Run
|
||||
|
||||
When we use `run` command for the first time the node will initialise all essential configuration and data files (unless specified with a flag `--deny-init`) stored at `$HOME/.nym/nym-nodes/<ID>` where the most important is the `config.toml` file stored at `$HOME/.nym/nym-nodes/<ID>/config/`. Below are some examples of initialising and running `nym-node` with different modes (`--mode`) like `mixnode`, `entry-gateway`, `exit-gateway`.
|
||||
When we use `run` command the node will do `init` as well, unless we specify with a flag `--deny-init`. Below are some examples of initialising and running `nym-node` with different modes (`--mode`) like `mixnode`, `entry-gateway`, `exit-gateway`.
|
||||
|
||||
Please keep in mind that currently we ask operators to run only one functionality (`--mode`) at a time.
|
||||
Please keep in mind that currently you can run only one functionality (`--mode`) per a `nym-node` instance. We are yet to finalise implement the multi-functionality solution under one node bonded to one Nyx account. Every `exit-gateway` can function as `entry-gateway` by default, not vice versa.
|
||||
|
||||
There is a simple default command to initialise and run your node: `./nym-node run --mode <MODE>`, however there quite a few parameters to be configured.
|
||||
There is a simple default command to initialise and run your node: `./nym-node run --mode <MODE>`, however there quite a few parameters to be configured. When `nym-node` gets to be `run`, these parameters are read by the binary from the configuration file located at `.nym/nym-nodes/<ID>/config/config.toml`.
|
||||
|
||||
If an operator specifies any paramteres with optional flags alongside `run` command, these parameters passed in the option will take place over the ones in `config.toml` but they will not overwrite them by default. To overwrite them with the values passed with `run` command, a flag `-w` (`--write-changes`) must be added.
|
||||
|
||||
@@ -141,7 +165,7 @@ Alternatively operators can just open a text editor and change these values manu
|
||||
In such case, you can `run` a node to initalise it or try if everything works, but then stop the proces and paste your entire `run` command syntax (below) to the `ExecStart` line of your `/etc/systemd/system/nym-node.service` and start the node as a [service](configuration.md#following-steps-for-nym-nodes-running-as-systemd-service).
|
||||
</Callout>
|
||||
|
||||
## Migrate
|
||||
### Migrate
|
||||
|
||||
<Callout type="warning">
|
||||
**Legacy binaries `nym-mixnode` and `nym-gateway` had been deprecated, [`nym-node`](../nym-node.mdx) is the only binary to use for `gateway` or `mixnode` functionalities!**
|
||||
@@ -162,35 +186,7 @@ Make sure to use `--deny-init` flag to prevent initialisation of a new node.
|
||||
**After you upgraded your node to the latest release of `nym-node`, make sure that you also follow [the steps to migrate your node in the Mixnet smart contract](bonding#migrate-to-nym-node-in-mixnet-smart-contract), othewise your node will never receive any rewards.**
|
||||
|
||||
|
||||
## Functionality & Performance Check
|
||||
|
||||
We have a chapter called [Performance Monitoring & Testing](../nodes/performance-and-testing) including much more information and tooling. If you want to just quickly check your nodes performance, connectivity and much more, visit [harbourmaster.nymtech.net](https://harbourmaster.nymtech.net/).
|
||||
|
||||
For more information about available endpoints and their status, you can refer to:
|
||||
```sh
|
||||
# sustitude <IPv4_ADDRESS> or <HOSTNAME> with the one corresponding to your node
|
||||
# for http
|
||||
http://<IPv4_ADDRESS>:8080/api/v1/swagger/#/
|
||||
# or
|
||||
http://<IPv4_ADDRESS>/api/v1/swagger/#/
|
||||
|
||||
# for reversed proxy/WSS
|
||||
https://<HOSTNAME>/api/v1/swagger/#/
|
||||
```
|
||||
|
||||
For example to determine which mode your node is running, you can check the `:8080/api/v1/roles` endpoint:
|
||||
```sh
|
||||
# sustitude <IPv4_ADDRESS> or <HOSTNAME> with the one corresponding to your node
|
||||
# for http
|
||||
http://<IPv4_ADDRESS>:8080/api/v1/roles
|
||||
# or
|
||||
http://<IPv4_ADDRESS>/api/v1/roles
|
||||
|
||||
# for reversed proxy/WSS
|
||||
https://<HOSTNAME>/api/v1/roles
|
||||
```
|
||||
|
||||
## Next steps
|
||||
### Next steps
|
||||
|
||||
If there are any problems checkout the troubleshooting section or report an issue.
|
||||
|
||||
|
||||
@@ -8,34 +8,6 @@ As developers we need to be constantly improving the software. Operators have as
|
||||
|
||||
Therefore [monitoring](#monitoring) and [testing](#testing) are essential pieces of our common work. We call out all Nym operators to join the efforts!
|
||||
|
||||
## Functionality & Performance Check
|
||||
|
||||
If you want to just quickly check your nodes performance, connectivity and much more, visit [harbourmaster.nymtech.net](https://harbourmaster.nymtech.net/).
|
||||
|
||||
For more information about available endpoints and their status, you can refer to:
|
||||
```sh
|
||||
# sustitude <IPv4_ADDRESS> or <HOSTNAME> with the one corresponding to your node
|
||||
# for http
|
||||
http://<IPv4_ADDRESS>:8080/api/v1/swagger/#/
|
||||
# or
|
||||
http://<IPv4_ADDRESS>/api/v1/swagger/#/
|
||||
|
||||
# for reversed proxy/WSS
|
||||
https://<HOSTNAME>/api/v1/swagger/#/
|
||||
```
|
||||
|
||||
For example to determine which mode your node is running, you can check the `:8080/api/v1/roles` endpoint:
|
||||
```sh
|
||||
# sustitude <IPv4_ADDRESS> or <HOSTNAME> with the one corresponding to your node
|
||||
# for http
|
||||
http://<IPv4_ADDRESS>:8080/api/v1/roles
|
||||
# or
|
||||
http://<IPv4_ADDRESS>/api/v1/roles
|
||||
|
||||
# for reversed proxy/WSS
|
||||
https://<HOSTNAME>/api/v1/roles
|
||||
```
|
||||
|
||||
## Monitoring
|
||||
|
||||
There are multiple ways to monitor performance of nodes and the machines on which they run. For the purpose of maximal privacy and decentralisation of the data - preventing Nym Mixnet from any global adversary takeover - we created these pages as a source of mutual empowerment, a place where operators can share and learn new skills to **setup metrics monitors on their own infrastructure**.
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"gateway-probe": "Gateway Probe",
|
||||
"node-api-check": "Node API Check",
|
||||
"prometheus-grafana": "Prometheus & Grafana"
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
There are a couple of steps that need completing before starting to set up your `nym-node`:
|
||||
|
||||
1. **[Prepare your wallet](preliminary-steps/wallet-preparation.mdx):** [desktop](https://nym.com/wallet) or [CLI](../../developers/tools/nym-cli/commands.mdx).
|
||||
1. **[Prepare your wallet](preliminary-steps/wallet-preparation.mdx):** [desktop](https://nym.com/download/wallet) or [CLI](../../developers/tools/nym-cli/commands.mdx).
|
||||
2. **[Requisition and setup a VPS](preliminary-steps/vps-setup.mdx)** (Virtual Private Server)
|
||||
|
||||
Make sure to follow these steps carefully as it prevents a lot of troubleshooting later on.
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
## Mainnet
|
||||
|
||||
Head to our [website](https://nym.com/wallet) and download Nym wallet for your operating system.
|
||||
Head to our [website](https://nym.com/download/wallet) and download Nym wallet for your operating system.
|
||||
|
||||
{/*
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ curl -o sandbox.env -L https://raw.githubusercontent.com/nymtech/nym/develop/env
|
||||
- In case you downloaded `sandbox.env` to same directory, `<PATH>` is not needed
|
||||
|
||||
###### 3. Bond your node to Nym Sandbox environment
|
||||
- Open [Nym Wallet](https://nym.com/wallet) and switch to testnet
|
||||
- Open [Nym Wallet](https://nym.com/download/wallet) and switch to testnet
|
||||
- Go to [faucet.nymtech.net](https://faucet.nymtech.net) and aquire 101 testnet NYM tokens
|
||||
- Follow the steps on the [bonding page](nodes/nym-node/bonding.mdx)
|
||||
|
||||
|
||||
@@ -113,6 +113,8 @@ There are a few community explorers as well.
|
||||
|
||||
Enter your **identity key** to find your node. Check the contents of the `Mixnode stats` and `Routing score` sections.
|
||||
|
||||
You can run [Node API Check CLI](../testing/node-api-check.mdx) to query all API endpoints of your node at once.
|
||||
|
||||
[Here](https://github.com/cosmos/chain-registry/blob/master/nyx/chain.json#L158-L187) is a dictionary with Nyx chain registry entry regarding all explorers.
|
||||
|
||||
If you want more information, or if your node isn't showing up on the explorer of your choice and you want to double-check, here are some examples on how to check if the node is configured properly.
|
||||
@@ -343,7 +345,7 @@ In case your Gateway appeared on the [blacklist](https://validator.nymtech.net/a
|
||||
|
||||
**What to do**
|
||||
|
||||
Begin with a sanity check by opening [harbourmaster.nymtech.net](https://harbourmaster.nymtech.net) and check your node there. To see IPv4 and IPv6 routing in real time (harbourmaster can have a cache up to 90 min), run [Gateway Probe CLI](../testing/gateway-probe.mdx).
|
||||
Begin with a sanity check by opening [harbourmaster.nymtech.net](https://harbourmaster.nymtech.net) and check your node there. To query all API endpoints of your node at once, you can run [Node API Check CLI](../testing/node-api-check.mdx). To see IPv4 and IPv6 routing in real time (harbourmaster can have a cache up to 90 min), run [Gateway Probe CLI](../testing/gateway-probe.mdx).
|
||||
|
||||
Then follow these steps:
|
||||
|
||||
|
||||
@@ -12,8 +12,7 @@ use js_sys::Promise;
|
||||
use std::sync::Arc;
|
||||
use wasm_bindgen::prelude::*;
|
||||
use wasm_bindgen_futures::future_to_promise;
|
||||
use wasm_storage::RawDbResult;
|
||||
use wasm_storage::{Build, Database, VersionChangeEvent, WasmStorage};
|
||||
use wasm_storage::{IdbVersionChangeEvent, WasmStorage};
|
||||
use wasm_utils::check_promise_result;
|
||||
use wasm_utils::error::{PromisableResult, PromisableResultError};
|
||||
use zeroize::Zeroizing;
|
||||
@@ -34,8 +33,8 @@ pub struct ExtensionStorage {
|
||||
}
|
||||
|
||||
#[allow(clippy::type_complexity)]
|
||||
fn db_migration() -> Box<dyn Fn(VersionChangeEvent, Database) -> RawDbResult<()>> {
|
||||
Box::new(|evt: VersionChangeEvent, db: Database| -> RawDbResult<()> {
|
||||
fn db_migration() -> Box<dyn Fn(&IdbVersionChangeEvent) -> Result<(), JsValue>> {
|
||||
Box::new(|evt: &IdbVersionChangeEvent| -> Result<(), JsValue> {
|
||||
// Even if the web-sys bindings expose the version as a f64, the IndexedDB API
|
||||
// works with an unsigned integer.
|
||||
// See <https://github.com/rustwasm/wasm-bindgen/issues/1149>
|
||||
@@ -43,7 +42,9 @@ fn db_migration() -> Box<dyn Fn(VersionChangeEvent, Database) -> RawDbResult<()>
|
||||
|
||||
if old_version < 1 {
|
||||
// migrating to version 1
|
||||
db.create_object_store(v1::MNEMONICS_STORE).build()?;
|
||||
let db = evt.db();
|
||||
|
||||
db.create_object_store(v1::MNEMONICS_STORE)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -121,7 +122,7 @@ impl ExtensionStorage {
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
async fn get_all_mnemonic_keys_async(&self) -> Result<Vec<JsValue>, ExtensionStorageError> {
|
||||
async fn get_all_mnemonic_keys_async(&self) -> Result<js_sys::Array, ExtensionStorageError> {
|
||||
self.inner
|
||||
.get_all_keys(v1::MNEMONICS_STORE)
|
||||
.await
|
||||
|
||||
+1
-2
@@ -3,7 +3,7 @@
|
||||
|
||||
[package]
|
||||
name = "nym-node"
|
||||
version = "1.3.1"
|
||||
version = "1.3.0"
|
||||
authors.workspace = true
|
||||
repository.workspace = true
|
||||
homepage.workspace = true
|
||||
@@ -16,7 +16,6 @@ license = "GPL-3.0"
|
||||
[dependencies]
|
||||
async-trait = { workspace = true }
|
||||
anyhow.workspace = true
|
||||
arc-swap = { workspace = true }
|
||||
bip39 = { workspace = true, features = ["zeroize"] }
|
||||
bs58.workspace = true
|
||||
celes = { workspace = true } # country codes
|
||||
|
||||
@@ -11,13 +11,13 @@ license.workspace = true
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
base64 = { workspace = true }
|
||||
celes = { workspace = true } # country codes
|
||||
humantime = { workspace = true }
|
||||
humantime-serde = { workspace = true }
|
||||
schemars = { workspace = true, features = ["preserve_order"] }
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
serde_json = { workspace = true }
|
||||
strum = { workspace = true, features = ["derive"] }
|
||||
time = { workspace = true, features = ["serde", "formatting", "parsing"] }
|
||||
thiserror = { workspace = true }
|
||||
|
||||
|
||||
@@ -11,16 +11,16 @@ use async_trait::async_trait;
|
||||
use nym_bin_common::build_information::BinaryBuildInformationOwned;
|
||||
use nym_http_api_client::{ApiClient, HttpClientError};
|
||||
|
||||
use super::v1::gateway::models::Wireguard;
|
||||
use super::v1::metrics::models::SessionStats;
|
||||
use crate::api::v1::authenticator::models::Authenticator;
|
||||
use crate::api::v1::health::models::NodeHealth;
|
||||
use crate::api::v1::ip_packet_router::models::IpPacketRouter;
|
||||
use crate::api::v1::network_requester::exit_policy::models::UsedExitPolicy;
|
||||
use crate::api::v1::network_requester::models::NetworkRequester;
|
||||
use crate::api::v1::node_load::models::NodeLoad;
|
||||
pub use nym_http_api_client::Client;
|
||||
|
||||
use super::v1::gateway::models::Wireguard;
|
||||
use super::v1::metrics::models::SessionStats;
|
||||
|
||||
pub type NymNodeApiClientError = HttpClientError<ErrorResponse>;
|
||||
|
||||
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
|
||||
@@ -30,10 +30,6 @@ pub trait NymNodeApiClientExt: ApiClient {
|
||||
self.get_json_from(routes::api::v1::health_absolute()).await
|
||||
}
|
||||
|
||||
async fn get_node_load(&self) -> Result<NodeLoad, NymNodeApiClientError> {
|
||||
self.get_json_from(routes::api::v1::load_absolute()).await
|
||||
}
|
||||
|
||||
async fn get_host_information(&self) -> Result<SignedHostInformation, NymNodeApiClientError> {
|
||||
self.get_json_from(routes::api::v1::host_info_absolute())
|
||||
.await
|
||||
|
||||
@@ -9,4 +9,3 @@ pub mod metrics;
|
||||
pub mod mixnode;
|
||||
pub mod network_requester;
|
||||
pub mod node;
|
||||
pub mod node_load;
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
// Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
pub mod models;
|
||||
@@ -1,79 +0,0 @@
|
||||
// Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use strum::{Display, EnumString};
|
||||
|
||||
#[derive(
|
||||
Display,
|
||||
Default,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Clone,
|
||||
Copy,
|
||||
Debug,
|
||||
EnumString,
|
||||
PartialEq,
|
||||
Eq,
|
||||
JsonSchema,
|
||||
PartialOrd,
|
||||
)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
#[strum(serialize_all = "snake_case")]
|
||||
#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
|
||||
pub enum Load {
|
||||
#[default]
|
||||
Unknown,
|
||||
|
||||
// order of the variants matter as we've derived `PartialOrd` on them
|
||||
Negligible, // 0 - 0.1
|
||||
Low, // 0.1 - 0.3
|
||||
Medium, // 0.3 - 0.6
|
||||
High, // 0.6 - 0.8
|
||||
VeryHigh, // 0.8 - 0.95
|
||||
AtCapacity, // >= 0.95
|
||||
}
|
||||
|
||||
impl Load {
|
||||
// returns load of one tier higher
|
||||
pub fn increment(&self) -> Self {
|
||||
match self {
|
||||
Self::Unknown => Self::Unknown,
|
||||
Self::Negligible => Self::Low,
|
||||
Self::Low => Self::Medium,
|
||||
Self::Medium => Self::High,
|
||||
Self::High => Self::VeryHigh,
|
||||
Self::VeryHigh => Self::AtCapacity,
|
||||
Self::AtCapacity => Self::AtCapacity,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<f64> for Load {
|
||||
fn from(value: f64) -> Self {
|
||||
if value == 0. || value.is_nan() || value.is_infinite() {
|
||||
Self::Unknown
|
||||
} else if value <= 0.1 {
|
||||
Self::Negligible
|
||||
} else if value <= 0.3 {
|
||||
Self::Low
|
||||
} else if value <= 0.6 {
|
||||
Self::Medium
|
||||
} else if value <= 0.8 {
|
||||
Self::High
|
||||
} else if value <= 0.95 {
|
||||
Self::VeryHigh
|
||||
} else {
|
||||
Self::AtCapacity
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Copy, JsonSchema)]
|
||||
#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
|
||||
pub struct NodeLoad {
|
||||
pub total: Load,
|
||||
pub machine: Load,
|
||||
pub network: Load,
|
||||
}
|
||||
@@ -35,7 +35,6 @@ pub mod routes {
|
||||
pub const NODE_DESCRIPTION: &str = "/description";
|
||||
pub const AUXILIARY: &str = "/auxiliary-details";
|
||||
pub const HEALTH: &str = "/health";
|
||||
pub const LOAD: &str = "/load";
|
||||
pub const SWAGGER: &str = "/swagger";
|
||||
|
||||
pub const GATEWAY: &str = "/gateway";
|
||||
@@ -47,7 +46,6 @@ pub mod routes {
|
||||
|
||||
// define helper functions to get absolute routes
|
||||
absolute_route!(health_absolute, v1_absolute(), HEALTH);
|
||||
absolute_route!(load_absolute, v1_absolute(), LOAD);
|
||||
absolute_route!(roles_absolute, v1_absolute(), ROLES);
|
||||
absolute_route!(build_info_absolute, v1_absolute(), BUILD_INFO);
|
||||
absolute_route!(host_info_absolute, v1_absolute(), HOST_INFO);
|
||||
|
||||
@@ -101,7 +101,7 @@ impl HostArgs {
|
||||
#[derive(clap::Args, Debug)]
|
||||
pub(crate) struct HttpArgs {
|
||||
/// Socket address this node will use for binding its http API.
|
||||
/// default: `[::]:8080`
|
||||
/// default: `0.0.0.0:8080`
|
||||
#[clap(
|
||||
long,
|
||||
env = NYMNODE_HTTP_BIND_ADDRESS_ARG
|
||||
@@ -181,7 +181,7 @@ impl HttpArgs {
|
||||
#[derive(clap::Args, Debug)]
|
||||
pub(crate) struct MixnetArgs {
|
||||
/// Address this node will bind to for listening for mixnet packets
|
||||
/// default: `[::]:1789`
|
||||
/// default: `0.0.0.0:1789`
|
||||
#[clap(
|
||||
long,
|
||||
env = NYMNODE_MIXNET_BIND_ADDRESS_ARG
|
||||
@@ -258,7 +258,7 @@ pub(crate) struct WireguardArgs {
|
||||
pub(crate) wireguard_enabled: Option<bool>,
|
||||
|
||||
/// Socket address this node will use for binding its wireguard interface.
|
||||
/// default: `[::]:51822`
|
||||
/// default: `0.0.0.0:51822`
|
||||
#[clap(
|
||||
long,
|
||||
env = NYMNODE_WG_BIND_ADDRESS_ARG
|
||||
@@ -315,7 +315,7 @@ impl WireguardArgs {
|
||||
#[derive(clap::Args, Debug)]
|
||||
pub(crate) struct VerlocArgs {
|
||||
/// Socket address this node will use for binding its verloc API.
|
||||
/// default: `[::]:1790`
|
||||
/// default: `0.0.0.0:1790`
|
||||
#[clap(
|
||||
long,
|
||||
env = NYMNODE_VERLOC_BIND_ADDRESS_ARG
|
||||
@@ -377,7 +377,7 @@ impl MetricsArgs {
|
||||
#[derive(clap::Args, Debug, Zeroize, ZeroizeOnDrop)]
|
||||
pub(crate) struct EntryGatewayArgs {
|
||||
/// Socket address this node will use for binding its client websocket API.
|
||||
/// default: `[::]:9000`
|
||||
/// default: `0.0.0.0:9000`
|
||||
#[clap(
|
||||
long,
|
||||
env = NYMNODE_ENTRY_BIND_ADDRESS_ARG
|
||||
@@ -431,7 +431,7 @@ impl EntryGatewayArgs {
|
||||
mut section: config::GatewayTasksConfig,
|
||||
) -> config::GatewayTasksConfig {
|
||||
if let Some(bind_address) = self.entry_bind_address {
|
||||
section.ws_bind_address = bind_address
|
||||
section.bind_address = bind_address
|
||||
}
|
||||
if let Some(ws_port) = self.announce_ws_port {
|
||||
section.announce_ws_port = Some(ws_port)
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
use crate::config::persistence::GatewayTasksPaths;
|
||||
use nym_config::defaults::{DEFAULT_CLIENT_LISTENING_PORT, TICKETBOOK_VALIDITY_DAYS};
|
||||
use nym_config::helpers::in6addr_any_init;
|
||||
use nym_config::helpers::inaddr_any;
|
||||
use nym_config::serde_helpers::de_maybe_port;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::net::SocketAddr;
|
||||
@@ -22,8 +22,8 @@ pub struct GatewayTasksConfig {
|
||||
pub enforce_zk_nyms: bool,
|
||||
|
||||
/// Socket address this node will use for binding its client websocket API.
|
||||
/// default: `[::]:9000`
|
||||
pub ws_bind_address: SocketAddr,
|
||||
/// default: `0.0.0.0:9000`
|
||||
pub bind_address: SocketAddr,
|
||||
|
||||
/// Custom announced port for listening for websocket client traffic.
|
||||
/// If unspecified, the value from the `bind_address` will be used instead
|
||||
@@ -188,7 +188,7 @@ impl GatewayTasksConfig {
|
||||
GatewayTasksConfig {
|
||||
storage_paths: GatewayTasksPaths::new(data_dir),
|
||||
enforce_zk_nyms: false,
|
||||
ws_bind_address: SocketAddr::new(in6addr_any_init(), DEFAULT_WS_PORT),
|
||||
bind_address: SocketAddr::new(inaddr_any(), DEFAULT_WS_PORT),
|
||||
announce_ws_port: None,
|
||||
announce_wss_port: None,
|
||||
debug: Default::default(),
|
||||
|
||||
@@ -13,7 +13,7 @@ fn ephemeral_gateway_config(config: &Config) -> nym_gateway::config::Config {
|
||||
nym_gateway::config::Config::new(
|
||||
nym_gateway::config::Gateway {
|
||||
enforce_zk_nyms: config.gateway_tasks.enforce_zk_nyms,
|
||||
websocket_bind_address: config.gateway_tasks.ws_bind_address,
|
||||
websocket_bind_address: config.gateway_tasks.bind_address,
|
||||
nym_api_urls: config.mixnet.nym_api_urls.clone(),
|
||||
nyxd_urls: config.mixnet.nyxd_urls.clone(),
|
||||
},
|
||||
|
||||
@@ -13,7 +13,7 @@ use nym_config::defaults::{
|
||||
WG_TUN_DEVICE_IP_ADDRESS_V6,
|
||||
};
|
||||
use nym_config::defaults::{WG_TUN_DEVICE_NETMASK_V4, WG_TUN_DEVICE_NETMASK_V6};
|
||||
use nym_config::helpers::{in6addr_any_init, inaddr_any};
|
||||
use nym_config::helpers::inaddr_any;
|
||||
use nym_config::serde_helpers::de_maybe_port;
|
||||
use nym_config::serde_helpers::de_maybe_stringified;
|
||||
use nym_config::{
|
||||
@@ -444,7 +444,7 @@ pub struct Host {
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct Http {
|
||||
/// Socket address this node will use for binding its http API.
|
||||
/// default: `[::]:8080`
|
||||
/// default: `0.0.0.0:8080`
|
||||
pub bind_address: SocketAddr,
|
||||
|
||||
/// Path to assets directory of custom landing page of this node.
|
||||
@@ -470,27 +470,17 @@ pub struct Http {
|
||||
/// This option is superseded by `expose_system_hardware`
|
||||
/// default: true
|
||||
pub expose_crypto_hardware: bool,
|
||||
|
||||
/// Specify the cache ttl of the node load.
|
||||
/// default: 30s
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub node_load_cache_ttl: Duration,
|
||||
}
|
||||
|
||||
impl Http {
|
||||
pub const DEFAULT_NODE_LOAD_CACHE_TTL: Duration = Duration::from_secs(30);
|
||||
}
|
||||
|
||||
impl Default for Http {
|
||||
fn default() -> Self {
|
||||
Http {
|
||||
bind_address: SocketAddr::new(in6addr_any_init(), DEFAULT_HTTP_PORT),
|
||||
bind_address: SocketAddr::new(inaddr_any(), DEFAULT_HTTP_PORT),
|
||||
landing_page_assets_path: None,
|
||||
access_token: None,
|
||||
expose_system_info: true,
|
||||
expose_system_hardware: true,
|
||||
expose_crypto_hardware: true,
|
||||
node_load_cache_ttl: Self::DEFAULT_NODE_LOAD_CACHE_TTL,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -500,7 +490,7 @@ impl Default for Http {
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct Mixnet {
|
||||
/// Address this node will bind to for listening for mixnet packets
|
||||
/// default: `[::]:1789`
|
||||
/// default: `0.0.0.0:1789`
|
||||
pub bind_address: SocketAddr,
|
||||
|
||||
/// If applicable, custom port announced in the self-described API that other clients and nodes
|
||||
@@ -594,7 +584,7 @@ impl Default for Mixnet {
|
||||
};
|
||||
|
||||
Mixnet {
|
||||
bind_address: SocketAddr::new(in6addr_any_init(), DEFAULT_MIXNET_PORT),
|
||||
bind_address: SocketAddr::new(inaddr_any(), DEFAULT_MIXNET_PORT),
|
||||
announce_port: None,
|
||||
nym_api_urls,
|
||||
nyxd_urls,
|
||||
@@ -607,7 +597,7 @@ impl Default for Mixnet {
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct Verloc {
|
||||
/// Socket address this node will use for binding its verloc API.
|
||||
/// default: `[::]:1790`
|
||||
/// default: `0.0.0.0:1790`
|
||||
pub bind_address: SocketAddr,
|
||||
|
||||
/// If applicable, custom port announced in the self-described API that other clients and nodes
|
||||
@@ -628,7 +618,7 @@ impl Verloc {
|
||||
impl Default for Verloc {
|
||||
fn default() -> Self {
|
||||
Verloc {
|
||||
bind_address: SocketAddr::new(in6addr_any_init(), Self::DEFAULT_VERLOC_PORT),
|
||||
bind_address: SocketAddr::new(inaddr_any(), Self::DEFAULT_VERLOC_PORT),
|
||||
announce_port: None,
|
||||
debug: Default::default(),
|
||||
}
|
||||
@@ -697,7 +687,7 @@ pub struct Wireguard {
|
||||
pub enabled: bool,
|
||||
|
||||
/// Socket address this node will use for binding its wireguard interface.
|
||||
/// default: `[::]:51822`
|
||||
/// default: `0.0.0.0:51822`
|
||||
pub bind_address: SocketAddr,
|
||||
|
||||
/// Private IPv4 address of the wireguard gateway.
|
||||
|
||||
@@ -7,7 +7,6 @@ mod old_config_v3;
|
||||
mod old_config_v4;
|
||||
mod old_config_v5;
|
||||
mod old_config_v6;
|
||||
mod old_config_v7;
|
||||
|
||||
pub use old_config_v1::try_upgrade_config_v1;
|
||||
pub use old_config_v2::try_upgrade_config_v2;
|
||||
@@ -15,4 +14,3 @@ pub use old_config_v3::try_upgrade_config_v3;
|
||||
pub use old_config_v4::try_upgrade_config_v4;
|
||||
pub use old_config_v5::try_upgrade_config_v5;
|
||||
pub use old_config_v6::try_upgrade_config_v6;
|
||||
pub use old_config_v7::try_upgrade_config_v7;
|
||||
|
||||
@@ -3,6 +3,11 @@
|
||||
|
||||
#![allow(dead_code)]
|
||||
|
||||
use crate::config::authenticator::{Authenticator, AuthenticatorDebug};
|
||||
use crate::config::gateway_tasks::ZkNymTicketHandlerDebug;
|
||||
use crate::config::service_providers::{
|
||||
IpPacketRouter, IpPacketRouterDebug, NetworkRequester, NetworkRequesterDebug,
|
||||
};
|
||||
use crate::config::*;
|
||||
use crate::error::NymNodeError;
|
||||
use celes::Country;
|
||||
@@ -18,7 +23,6 @@ use nym_config::{
|
||||
serde_helpers::{de_maybe_port, de_maybe_stringified},
|
||||
};
|
||||
use nym_config::{parse_urls, read_config_from_toml_file};
|
||||
use old_configs::old_config_v7::*;
|
||||
use persistence::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::env;
|
||||
@@ -81,13 +85,13 @@ pub enum NodeModeV6 {
|
||||
ExitGateway,
|
||||
}
|
||||
|
||||
impl From<NodeModeV6> for NodeModesV7 {
|
||||
impl From<NodeModeV6> for NodeModes {
|
||||
fn from(config: NodeModeV6) -> Self {
|
||||
match config {
|
||||
NodeModeV6::Mixnode => *NodeModesV7::default().with_mixnode(),
|
||||
NodeModeV6::EntryGateway => *NodeModesV7::default().with_entry(),
|
||||
NodeModeV6::Mixnode => *NodeModes::default().with_mixnode(),
|
||||
NodeModeV6::EntryGateway => *NodeModes::default().with_entry(),
|
||||
// in old version exit implied entry
|
||||
NodeModeV6::ExitGateway => *NodeModesV7::default().with_entry().with_exit(),
|
||||
NodeModeV6::ExitGateway => *NodeModes::default().with_entry().with_exit(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -949,7 +953,7 @@ impl ConfigV6 {
|
||||
pub async fn try_upgrade_config_v6<P: AsRef<Path>>(
|
||||
path: P,
|
||||
prev_config: Option<ConfigV6>,
|
||||
) -> Result<ConfigV7, NymNodeError> {
|
||||
) -> Result<Config, NymNodeError> {
|
||||
debug!("attempting to load v6 config...");
|
||||
|
||||
let old_cfg = if let Some(prev_config) = prev_config {
|
||||
@@ -958,22 +962,22 @@ pub async fn try_upgrade_config_v6<P: AsRef<Path>>(
|
||||
ConfigV6::read_from_path(&path)?
|
||||
};
|
||||
|
||||
let cfg = ConfigV7 {
|
||||
let cfg = Config {
|
||||
save_path: old_cfg.save_path,
|
||||
id: old_cfg.id,
|
||||
modes: old_cfg.mode.into(),
|
||||
host: HostV7 {
|
||||
host: Host {
|
||||
public_ips: old_cfg.host.public_ips,
|
||||
hostname: old_cfg.host.hostname,
|
||||
location: old_cfg.host.location,
|
||||
},
|
||||
mixnet: MixnetV7 {
|
||||
mixnet: Mixnet {
|
||||
bind_address: old_cfg.mixnet.bind_address,
|
||||
announce_port: old_cfg.mixnet.announce_port,
|
||||
nym_api_urls: old_cfg.mixnet.nym_api_urls,
|
||||
nyxd_urls: old_cfg.mixnet.nyxd_urls,
|
||||
debug: MixnetDebugV7 {
|
||||
maximum_forward_packet_delay: MixnetDebugV7::DEFAULT_MAXIMUM_FORWARD_PACKET_DELAY,
|
||||
debug: MixnetDebug {
|
||||
maximum_forward_packet_delay: MixnetDebug::DEFAULT_MAXIMUM_FORWARD_PACKET_DELAY,
|
||||
packet_forwarding_initial_backoff: old_cfg
|
||||
.mixnet
|
||||
.debug
|
||||
@@ -987,8 +991,8 @@ pub async fn try_upgrade_config_v6<P: AsRef<Path>>(
|
||||
unsafe_disable_noise: old_cfg.mixnet.debug.unsafe_disable_noise,
|
||||
},
|
||||
},
|
||||
storage_paths: NymNodePathsV7 {
|
||||
keys: KeysPathsV7 {
|
||||
storage_paths: NymNodePaths {
|
||||
keys: KeysPaths {
|
||||
private_ed25519_identity_key_file: old_cfg
|
||||
.storage_paths
|
||||
.keys
|
||||
@@ -1016,7 +1020,7 @@ pub async fn try_upgrade_config_v6<P: AsRef<Path>>(
|
||||
},
|
||||
description: old_cfg.storage_paths.description,
|
||||
},
|
||||
http: HttpV7 {
|
||||
http: Http {
|
||||
bind_address: old_cfg.http.bind_address,
|
||||
landing_page_assets_path: old_cfg.http.landing_page_assets_path,
|
||||
access_token: old_cfg.http.access_token,
|
||||
@@ -1024,10 +1028,10 @@ pub async fn try_upgrade_config_v6<P: AsRef<Path>>(
|
||||
expose_system_hardware: old_cfg.http.expose_system_hardware,
|
||||
expose_crypto_hardware: old_cfg.http.expose_crypto_hardware,
|
||||
},
|
||||
verloc: VerlocV7 {
|
||||
verloc: Verloc {
|
||||
bind_address: old_cfg.mixnode.verloc.bind_address,
|
||||
announce_port: old_cfg.mixnode.verloc.announce_port,
|
||||
debug: VerlocDebugV7 {
|
||||
debug: VerlocDebug {
|
||||
packets_per_node: old_cfg.mixnode.verloc.debug.packets_per_node,
|
||||
connection_timeout: old_cfg.mixnode.verloc.debug.connection_timeout,
|
||||
packet_timeout: old_cfg.mixnode.verloc.debug.packet_timeout,
|
||||
@@ -1037,7 +1041,7 @@ pub async fn try_upgrade_config_v6<P: AsRef<Path>>(
|
||||
retry_timeout: old_cfg.mixnode.verloc.debug.retry_timeout,
|
||||
},
|
||||
},
|
||||
wireguard: WireguardV7 {
|
||||
wireguard: Wireguard {
|
||||
enabled: old_cfg.wireguard.enabled,
|
||||
bind_address: old_cfg.wireguard.bind_address,
|
||||
private_ipv4: old_cfg.wireguard.private_ipv4,
|
||||
@@ -1045,7 +1049,7 @@ pub async fn try_upgrade_config_v6<P: AsRef<Path>>(
|
||||
announced_port: old_cfg.wireguard.announced_port,
|
||||
private_network_prefix_v4: old_cfg.wireguard.private_network_prefix_v4,
|
||||
private_network_prefix_v6: old_cfg.wireguard.private_network_prefix_v6,
|
||||
storage_paths: WireguardPathsV7 {
|
||||
storage_paths: WireguardPaths {
|
||||
private_diffie_hellman_key_file: old_cfg
|
||||
.wireguard
|
||||
.storage_paths
|
||||
@@ -1056,8 +1060,8 @@ pub async fn try_upgrade_config_v6<P: AsRef<Path>>(
|
||||
.public_diffie_hellman_key_file,
|
||||
},
|
||||
},
|
||||
gateway_tasks: GatewayTasksConfigV7 {
|
||||
storage_paths: GatewayTasksPathsV7 {
|
||||
gateway_tasks: GatewayTasksConfig {
|
||||
storage_paths: GatewayTasksPaths {
|
||||
clients_storage: old_cfg.entry_gateway.storage_paths.clients_storage,
|
||||
stats_storage: old_cfg.entry_gateway.storage_paths.stats_storage,
|
||||
cosmos_mnemonic: old_cfg.entry_gateway.storage_paths.cosmos_mnemonic,
|
||||
@@ -1066,9 +1070,9 @@ pub async fn try_upgrade_config_v6<P: AsRef<Path>>(
|
||||
bind_address: old_cfg.entry_gateway.bind_address,
|
||||
announce_ws_port: old_cfg.entry_gateway.announce_ws_port,
|
||||
announce_wss_port: old_cfg.entry_gateway.announce_wss_port,
|
||||
debug: GatewayTasksConfigDebugV7 {
|
||||
debug: gateway_tasks::Debug {
|
||||
message_retrieval_limit: old_cfg.entry_gateway.debug.message_retrieval_limit,
|
||||
zk_nym_tickets: ZkNymTicketHandlerDebugV7 {
|
||||
zk_nym_tickets: ZkNymTicketHandlerDebug {
|
||||
revocation_bandwidth_penalty: old_cfg
|
||||
.entry_gateway
|
||||
.debug
|
||||
@@ -1094,11 +1098,11 @@ pub async fn try_upgrade_config_v6<P: AsRef<Path>>(
|
||||
..Default::default()
|
||||
},
|
||||
},
|
||||
service_providers: ServiceProvidersConfigV7 {
|
||||
storage_paths: ServiceProvidersPathsV7 {
|
||||
service_providers: ServiceProvidersConfig {
|
||||
storage_paths: ServiceProvidersPaths {
|
||||
clients_storage: old_cfg.exit_gateway.storage_paths.clients_storage,
|
||||
stats_storage: old_cfg.exit_gateway.storage_paths.stats_storage,
|
||||
network_requester: NetworkRequesterPathsV7 {
|
||||
network_requester: NetworkRequesterPaths {
|
||||
private_ed25519_identity_key_file: old_cfg
|
||||
.exit_gateway
|
||||
.storage_paths
|
||||
@@ -1135,7 +1139,7 @@ pub async fn try_upgrade_config_v6<P: AsRef<Path>>(
|
||||
.network_requester
|
||||
.gateway_registrations,
|
||||
},
|
||||
ip_packet_router: IpPacketRouterPathsV7 {
|
||||
ip_packet_router: IpPacketRouterPaths {
|
||||
private_ed25519_identity_key_file: old_cfg
|
||||
.exit_gateway
|
||||
.storage_paths
|
||||
@@ -1172,7 +1176,7 @@ pub async fn try_upgrade_config_v6<P: AsRef<Path>>(
|
||||
.ip_packet_router
|
||||
.gateway_registrations,
|
||||
},
|
||||
authenticator: AuthenticatorPathsV7 {
|
||||
authenticator: AuthenticatorPaths {
|
||||
private_ed25519_identity_key_file: old_cfg
|
||||
.exit_gateway
|
||||
.storage_paths
|
||||
@@ -1212,8 +1216,8 @@ pub async fn try_upgrade_config_v6<P: AsRef<Path>>(
|
||||
},
|
||||
open_proxy: old_cfg.exit_gateway.open_proxy,
|
||||
upstream_exit_policy_url: old_cfg.exit_gateway.upstream_exit_policy_url,
|
||||
network_requester: NetworkRequesterV7 {
|
||||
debug: NetworkRequesterDebugV7 {
|
||||
network_requester: NetworkRequester {
|
||||
debug: NetworkRequesterDebug {
|
||||
enabled: old_cfg.exit_gateway.network_requester.debug.enabled,
|
||||
disable_poisson_rate: old_cfg
|
||||
.exit_gateway
|
||||
@@ -1223,8 +1227,8 @@ pub async fn try_upgrade_config_v6<P: AsRef<Path>>(
|
||||
client_debug: old_cfg.exit_gateway.network_requester.debug.client_debug,
|
||||
},
|
||||
},
|
||||
ip_packet_router: IpPacketRouterV7 {
|
||||
debug: IpPacketRouterDebugV7 {
|
||||
ip_packet_router: IpPacketRouter {
|
||||
debug: IpPacketRouterDebug {
|
||||
enabled: old_cfg.exit_gateway.ip_packet_router.debug.enabled,
|
||||
disable_poisson_rate: old_cfg
|
||||
.exit_gateway
|
||||
@@ -1234,19 +1238,19 @@ pub async fn try_upgrade_config_v6<P: AsRef<Path>>(
|
||||
client_debug: old_cfg.exit_gateway.ip_packet_router.debug.client_debug,
|
||||
},
|
||||
},
|
||||
authenticator: AuthenticatorV7 {
|
||||
debug: AuthenticatorDebugV7 {
|
||||
authenticator: Authenticator {
|
||||
debug: AuthenticatorDebug {
|
||||
enabled: old_cfg.authenticator.debug.enabled,
|
||||
disable_poisson_rate: old_cfg.authenticator.debug.disable_poisson_rate,
|
||||
client_debug: old_cfg.authenticator.debug.client_debug,
|
||||
},
|
||||
},
|
||||
debug: ServiceProvidersConfigDebugV7 {
|
||||
debug: service_providers::Debug {
|
||||
message_retrieval_limit: old_cfg.exit_gateway.debug.message_retrieval_limit,
|
||||
},
|
||||
},
|
||||
metrics: Default::default(),
|
||||
logging: LoggingSettingsV7 {},
|
||||
logging: LoggingSettings {},
|
||||
debug: Default::default(),
|
||||
};
|
||||
Ok(cfg)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -30,6 +30,7 @@ pub struct ServiceProvidersConfig {
|
||||
#[serde(default)]
|
||||
pub debug: Debug,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct Debug {
|
||||
|
||||
@@ -46,7 +46,7 @@ location = '{{ host.location }}'
|
||||
|
||||
[mixnet]
|
||||
# Address this node will bind to for listening for mixnet packets
|
||||
# default: `[::]:1789`
|
||||
# default: `0.0.0.0:1789`
|
||||
bind_address = '{{ mixnet.bind_address }}'
|
||||
|
||||
# If applicable, custom port announced in the self-described API that other clients and nodes
|
||||
@@ -95,7 +95,7 @@ public_x25519_noise_key_file = '{{ storage_paths.keys.public_x25519_noise_key_fi
|
||||
|
||||
[http]
|
||||
# Socket address this node will use for binding its http API.
|
||||
# default: `[::]:8080`
|
||||
# default: `0.0.0.0:8080`
|
||||
bind_address = '{{ http.bind_address }}'
|
||||
|
||||
# Path to assets directory of custom landing page of this node
|
||||
@@ -126,7 +126,7 @@ expose_crypto_hardware = {{ http.expose_crypto_hardware }}
|
||||
enabled = {{ wireguard.enabled }}
|
||||
|
||||
# Socket address this node will use for binding its wireguard interface.
|
||||
# default: `[::]:51822`
|
||||
# default: `0.0.0.0:51822`
|
||||
bind_address = '{{ wireguard.bind_address }}'
|
||||
|
||||
# Private IP address of the wireguard gateway.
|
||||
@@ -161,7 +161,7 @@ public_diffie_hellman_key_file = '{{ wireguard.storage_paths.public_diffie_hellm
|
||||
|
||||
[verloc]
|
||||
# Socket address this node will use for binding its verloc API.
|
||||
# default: `[::]:1790`
|
||||
# default: `0.0.0.0:1790`
|
||||
bind_address = '{{ verloc.bind_address }}'
|
||||
|
||||
# If applicable, custom port announced in the self-described API that other clients and nodes
|
||||
@@ -179,8 +179,8 @@ announce_port ={{#if verloc.announce_port }} {{ verloc.announce_port }} {{else}}
|
||||
enforce_zk_nyms = {{ gateway_tasks.enforce_zk_nyms }}
|
||||
|
||||
# Socket address this node will use for binding its client websocket API.
|
||||
# default: `[::]:9000`
|
||||
ws_bind_address = '{{ gateway_tasks.ws_bind_address }}'
|
||||
# default: `0.0.0.0:9000`
|
||||
bind_address = '{{ gateway_tasks.bind_address }}'
|
||||
|
||||
# Custom announced port for listening for websocket client traffic.
|
||||
# If unspecified, the value from the `bind_address` will be used instead
|
||||
|
||||
@@ -14,8 +14,7 @@ async fn try_upgrade_config(path: &Path) -> Result<(), NymNodeError> {
|
||||
let cfg = try_upgrade_config_v3(path, cfg).await.ok();
|
||||
let cfg = try_upgrade_config_v4(path, cfg).await.ok();
|
||||
let cfg = try_upgrade_config_v5(path, cfg).await.ok();
|
||||
let cfg = try_upgrade_config_v6(path, cfg).await.ok();
|
||||
match try_upgrade_config_v7(path, cfg).await {
|
||||
match try_upgrade_config_v6(path, cfg).await {
|
||||
Ok(cfg) => cfg.save(),
|
||||
Err(e) => {
|
||||
tracing::error!("Failed to finish upgrade - {e}");
|
||||
|
||||
@@ -72,7 +72,7 @@ pub(crate) fn get_system_info(
|
||||
system_name: System::name(),
|
||||
kernel_version: System::kernel_version(),
|
||||
os_version: System::os_version(),
|
||||
cpu_arch: Some(System::cpu_arch()),
|
||||
cpu_arch: System::cpu_arch(),
|
||||
hardware,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,8 +14,8 @@ use nym_node_requests::api::v1::health::models::NodeHealth;
|
||||
tag = "Health",
|
||||
responses(
|
||||
(status = 200, content(
|
||||
(NodeHealth = "application/json"),
|
||||
(NodeHealth = "application/yaml")
|
||||
(Vec<NodeHealth> = "application/json"),
|
||||
(Vec<NodeHealth> = "application/yaml")
|
||||
), description = "the api is available and healthy")
|
||||
),
|
||||
params(OutputParams)
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
// Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
use crate::node::http::state::AppState;
|
||||
use axum::extract::{Query, State};
|
||||
use nym_http_api_common::{FormattedResponse, OutputParams};
|
||||
use nym_node_requests::api::v1::node_load::models::NodeLoad;
|
||||
|
||||
/// Returns current relative load this node.
|
||||
#[utoipa::path(
|
||||
get,
|
||||
path = "/load",
|
||||
context_path = "/api/v1",
|
||||
tag = "Node",
|
||||
responses(
|
||||
(status = 200, content(
|
||||
(NodeLoad = "application/json"),
|
||||
(NodeLoad = "application/yaml")
|
||||
), description = "current node load")
|
||||
),
|
||||
params(OutputParams)
|
||||
)]
|
||||
pub(crate) async fn root_load(
|
||||
Query(output): Query<OutputParams>,
|
||||
State(state): State<AppState>,
|
||||
) -> NodeLoadResponse {
|
||||
let output = output.output.unwrap_or_default();
|
||||
let load = state.cached_load.current_load();
|
||||
|
||||
output.to_response(load)
|
||||
}
|
||||
|
||||
pub type NodeLoadResponse = FormattedResponse<NodeLoad>;
|
||||
@@ -10,7 +10,6 @@ pub mod authenticator;
|
||||
pub mod gateway;
|
||||
pub mod health;
|
||||
pub mod ip_packet_router;
|
||||
pub mod load;
|
||||
pub mod metrics;
|
||||
pub mod mixnode;
|
||||
pub mod network_requester;
|
||||
@@ -31,7 +30,6 @@ pub struct Config {
|
||||
pub(super) fn routes(config: Config) -> Router<AppState> {
|
||||
Router::new()
|
||||
.route(v1::HEALTH, get(health::root_health))
|
||||
.route(v1::LOAD, get(load::root_load))
|
||||
.nest(v1::METRICS, metrics::routes(config.metrics))
|
||||
.nest(v1::GATEWAY, gateway::routes(config.gateway))
|
||||
.nest(v1::MIXNODE, mixnode::routes(config.mixnode))
|
||||
|
||||
@@ -24,7 +24,6 @@ use utoipa_swagger_ui::SwaggerUi;
|
||||
api::v1::metrics::verloc::verloc_stats,
|
||||
api::v1::metrics::prometheus::prometheus_metrics,
|
||||
api::v1::health::root_health,
|
||||
api::v1::load::root_load,
|
||||
api::v1::gateway::root::root_gateway,
|
||||
api::v1::gateway::client_interfaces::client_interfaces,
|
||||
api::v1::gateway::client_interfaces::mixnet_websockets,
|
||||
@@ -39,8 +38,6 @@ use utoipa_swagger_ui::SwaggerUi;
|
||||
nym_http_api_common::OutputParams,
|
||||
api_requests::v1::health::models::NodeHealth,
|
||||
api_requests::v1::health::models::NodeStatus,
|
||||
api_requests::v1::node_load::models::NodeLoad,
|
||||
api_requests::v1::node_load::models::Load,
|
||||
api_requests::v1::node::models::BinaryBuildInformationOwned,
|
||||
api_requests::v1::node::models::HostInformation,
|
||||
api_requests::v1::node::models::HostKeys,
|
||||
|
||||
@@ -1,209 +0,0 @@
|
||||
// Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
use arc_swap::ArcSwap;
|
||||
use nym_node_requests::api::v1::node_load::models::{Load, NodeLoad};
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use sysinfo::{CpuRefreshKind, MemoryRefreshKind, Networks, System};
|
||||
use time::OffsetDateTime;
|
||||
use tracing::debug;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct CachedNodeLoad {
|
||||
ttl: Duration,
|
||||
being_updated: Arc<AtomicBool>,
|
||||
inner: Arc<ArcSwap<CachedNodeLoadInner>>,
|
||||
}
|
||||
|
||||
impl CachedNodeLoad {
|
||||
pub(crate) fn new(ttl: Duration) -> Self {
|
||||
CachedNodeLoad {
|
||||
ttl,
|
||||
being_updated: Arc::new(Default::default()),
|
||||
inner: Arc::new(ArcSwap::new(Arc::new(CachedNodeLoadInner::initial()))),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn current_load(&self) -> NodeLoad {
|
||||
let now = OffsetDateTime::now_utc();
|
||||
|
||||
let inner = self.inner.load();
|
||||
if inner.timestamp + self.ttl < now {
|
||||
// new
|
||||
let already_being_updated = self.being_updated.swap(true, Ordering::SeqCst);
|
||||
if already_being_updated {
|
||||
// use the 'stale' entry because it is already being updated by another thread
|
||||
inner.load
|
||||
} else {
|
||||
self.update_cache()
|
||||
}
|
||||
} else {
|
||||
inner.load
|
||||
}
|
||||
}
|
||||
|
||||
fn update_cache(&self) -> NodeLoad {
|
||||
let old = self.inner.load();
|
||||
let current_load = CachedNodeLoadInner::update(&old);
|
||||
let load = current_load.load;
|
||||
self.inner.store(Arc::new(current_load));
|
||||
self.being_updated.store(false, Ordering::SeqCst);
|
||||
load
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CachedNodeLoadInner {
|
||||
timestamp: OffsetDateTime,
|
||||
last_transmitted: u64,
|
||||
last_received: u64,
|
||||
load: NodeLoad,
|
||||
}
|
||||
|
||||
struct RawUsage {
|
||||
load_per_cpu: f64,
|
||||
memory_usage: f64,
|
||||
swap_usage: f64,
|
||||
eth_transmitted: u64,
|
||||
eth_received: u64,
|
||||
total_swap: u64,
|
||||
}
|
||||
|
||||
impl RawUsage {
|
||||
fn current() -> RawUsage {
|
||||
let mut system = sysinfo::System::new();
|
||||
let networks = Networks::new_with_refreshed_list();
|
||||
|
||||
system.refresh_memory_specifics(MemoryRefreshKind::everything());
|
||||
system.refresh_cpu_specifics(CpuRefreshKind::nothing());
|
||||
|
||||
let average_load = System::load_average();
|
||||
let cpu_count = system.cpus().len();
|
||||
|
||||
let load_per_cpu = average_load.five / cpu_count as f64;
|
||||
|
||||
let total_memory = system.total_memory();
|
||||
let used_memory = system.used_memory();
|
||||
|
||||
let memory_usage = used_memory as f64 / total_memory as f64;
|
||||
|
||||
let total_swap = system.total_swap();
|
||||
let used_swap = system.free_swap();
|
||||
|
||||
let swap_usage = used_swap as f64 / total_swap as f64;
|
||||
|
||||
let mut eth_transmitted = 0;
|
||||
let mut eth_received = 0;
|
||||
|
||||
// we're only interested in interfaces with 'eth' or 'en' prefix
|
||||
// (that's a very weak assumption, but that's just first iteration of this endpoint)
|
||||
for (interface, data) in networks.list() {
|
||||
if interface.starts_with("eth") || interface.starts_with("en") {
|
||||
eth_transmitted += data.total_transmitted();
|
||||
eth_received += data.total_received();
|
||||
}
|
||||
}
|
||||
|
||||
debug!(average_load = ?average_load, memory_usage=memory_usage, swap_usage = swap_usage, "current load");
|
||||
|
||||
RawUsage {
|
||||
load_per_cpu,
|
||||
memory_usage,
|
||||
swap_usage,
|
||||
eth_transmitted,
|
||||
eth_received,
|
||||
total_swap,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CachedNodeLoadInner {
|
||||
pub fn initial() -> CachedNodeLoadInner {
|
||||
let timestamp = OffsetDateTime::now_utc();
|
||||
let raw_usage = RawUsage::current();
|
||||
|
||||
let mut base_load = Load::from(raw_usage.load_per_cpu);
|
||||
let memory_load = Load::from(raw_usage.memory_usage);
|
||||
|
||||
// if memory load is of higher tier, increment the base load by one level
|
||||
// (i.e. for example from 'Low' to 'Medium')
|
||||
if memory_load > base_load {
|
||||
base_load = base_load.increment();
|
||||
}
|
||||
|
||||
if raw_usage.total_swap > 1024 * 1024 * 1024 {
|
||||
// same with swap
|
||||
let swap_load = Load::from(raw_usage.swap_usage);
|
||||
if swap_load > base_load {
|
||||
base_load = base_load.increment();
|
||||
}
|
||||
}
|
||||
|
||||
CachedNodeLoadInner {
|
||||
timestamp,
|
||||
last_transmitted: raw_usage.eth_transmitted,
|
||||
last_received: raw_usage.eth_received,
|
||||
load: NodeLoad {
|
||||
total: base_load,
|
||||
machine: base_load,
|
||||
network: Load::Unknown,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update(previous: &Self) -> CachedNodeLoadInner {
|
||||
let timestamp = OffsetDateTime::now_utc();
|
||||
let raw_usage = RawUsage::current();
|
||||
|
||||
let time_delta = (timestamp - previous.timestamp).as_seconds_f64();
|
||||
let tx_delta = raw_usage.eth_transmitted - previous.last_transmitted;
|
||||
let rx_delta = raw_usage.eth_received - previous.last_received;
|
||||
|
||||
let tx_bs = tx_delta as f64 / time_delta;
|
||||
let rx_bs = rx_delta as f64 / time_delta;
|
||||
|
||||
// currently we consider value of 1Gbps to be maximum load
|
||||
// in the future we should allow specifying custom sizes of network cards
|
||||
// (Gbps = Bytes/s * 0.000000008)
|
||||
let tx_gbps = tx_bs * 0.000000008;
|
||||
let rx_gbps = rx_bs * 0.000000008;
|
||||
let network_load = Load::from(tx_gbps.max(rx_gbps));
|
||||
|
||||
debug!(tx_gbps = tx_gbps, rx_gbps = rx_gbps, "network load");
|
||||
|
||||
let mut base_load = Load::from(raw_usage.load_per_cpu);
|
||||
let memory_load = Load::from(raw_usage.memory_usage);
|
||||
|
||||
// if memory load is of higher tier, increment the base load by one level
|
||||
// (i.e. for example from 'Low' to 'Medium')
|
||||
if memory_load > base_load {
|
||||
base_load = base_load.increment();
|
||||
}
|
||||
|
||||
if raw_usage.total_swap > 1024 * 1024 * 1024 {
|
||||
// same with swap
|
||||
let swap_load = Load::from(raw_usage.swap_usage);
|
||||
if swap_load > base_load {
|
||||
base_load = base_load.increment();
|
||||
}
|
||||
}
|
||||
|
||||
let total_load = if base_load > network_load {
|
||||
base_load
|
||||
} else {
|
||||
base_load.increment()
|
||||
};
|
||||
|
||||
CachedNodeLoadInner {
|
||||
timestamp,
|
||||
last_transmitted: raw_usage.eth_transmitted,
|
||||
last_received: raw_usage.eth_received,
|
||||
load: NodeLoad {
|
||||
total: total_load,
|
||||
machine: base_load,
|
||||
network: network_load,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,39 +1,29 @@
|
||||
// Copyright 2023-2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
use crate::node::http::state::load::CachedNodeLoad;
|
||||
use crate::node::http::state::metrics::MetricsAppState;
|
||||
use nym_node_metrics::NymNodeMetrics;
|
||||
use nym_verloc::measurements::SharedVerlocStats;
|
||||
use std::time::Duration;
|
||||
use tokio::time::Instant;
|
||||
|
||||
pub mod load;
|
||||
pub mod metrics;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct AppState {
|
||||
pub(crate) startup_time: Instant,
|
||||
|
||||
pub(crate) cached_load: CachedNodeLoad,
|
||||
|
||||
pub(crate) metrics: MetricsAppState,
|
||||
}
|
||||
|
||||
impl AppState {
|
||||
#[allow(clippy::new_without_default)]
|
||||
pub fn new(
|
||||
metrics: NymNodeMetrics,
|
||||
verloc: SharedVerlocStats,
|
||||
load_cache_ttl: Duration,
|
||||
) -> Self {
|
||||
pub fn new(metrics: NymNodeMetrics, verloc: SharedVerlocStats) -> Self {
|
||||
AppState {
|
||||
// is it 100% accurate?
|
||||
// no.
|
||||
// does it have to be?
|
||||
// also no.
|
||||
startup_time: Instant::now(),
|
||||
cached_load: CachedNodeLoad::new(load_cache_ttl),
|
||||
metrics: MetricsAppState { metrics, verloc },
|
||||
}
|
||||
}
|
||||
|
||||
@@ -560,7 +560,7 @@ impl NymNode {
|
||||
.config
|
||||
.gateway_tasks
|
||||
.announce_ws_port
|
||||
.unwrap_or(self.config.gateway_tasks.ws_bind_address.port());
|
||||
.unwrap_or(self.config.gateway_tasks.bind_address.port());
|
||||
|
||||
Ok(nym_topology::RoutingNode {
|
||||
node_id: u32::MAX,
|
||||
@@ -606,7 +606,7 @@ impl NymNode {
|
||||
if self.modes().entry {
|
||||
info!(
|
||||
"starting the clients websocket... on {}",
|
||||
self.config.gateway_tasks.ws_bind_address
|
||||
self.config.gateway_tasks.bind_address
|
||||
);
|
||||
let websocket = gateway_tasks_builder
|
||||
.build_websocket_listener(active_clients_store.clone())
|
||||
@@ -711,7 +711,7 @@ impl NymNode {
|
||||
.config
|
||||
.gateway_tasks
|
||||
.announce_ws_port
|
||||
.unwrap_or(self.config.gateway_tasks.ws_bind_address.port()),
|
||||
.unwrap_or(self.config.gateway_tasks.bind_address.port()),
|
||||
wss_port: self.config.gateway_tasks.announce_wss_port,
|
||||
});
|
||||
let gateway_details = api_requests::v1::gateway::models::Gateway {
|
||||
@@ -785,11 +785,7 @@ impl NymNode {
|
||||
config.api.v1_config.node.roles.ip_packet_router_enabled = true;
|
||||
}
|
||||
|
||||
let app_state = AppState::new(
|
||||
self.metrics.clone(),
|
||||
self.verloc_stats.clone(),
|
||||
self.config.http.node_load_cache_ttl,
|
||||
);
|
||||
let app_state = AppState::new(self.metrics.clone(), self.verloc_stats.clone());
|
||||
|
||||
Ok(NymNodeRouter::new(config, app_state)
|
||||
.build_server(&self.config.http.bind_address)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user