From e8e9a70ef41cbd03b5acc59fde02eec1a2a00e2d Mon Sep 17 00:00:00 2001 From: dynco-nym <173912580+dynco-nym@users.noreply.github.com> Date: Thu, 12 Jun 2025 09:56:31 +0200 Subject: [PATCH] Feature/node status dvpn directory (#5829) * wip - dvpn directory cache * Endpoint & cache * /gateways works - SkimmedNode data still missing - need to move probe models to monorepo * Rest of the data for /gateways * Revert before merge: pin deps to cheddar release * Filter gw by country * Return percent string instead of u8 * Filter by semver * Bump package version * Fix probe types * Reorg * Add exit, entry endpoints * Different entry/exit selection criteria * Date fix migration * Unpin from cheddar * Revert "Unpin from cheddar" This reverts commit f17239075b90a56fed6a04c63d59cff51f14d02e. * Validation with celes * PR feedback * Fix path * Bump version --------- Co-authored-by: Mark Sinclair --- Cargo.lock | 747 ++++++++++++------ .../nym-node-status-agent/run.sh | 2 +- .../nym-node-status-api/Cargo.toml | 45 +- .../migrations/007_date_fix.sql | 113 +++ .../nym-node-status-api/src/db/models.rs | 3 +- .../src/db/queries/gateways.rs | 5 +- .../src/db/queries/nym_nodes.rs | 2 + .../src/http/api/dvpn/country.rs | 86 ++ .../src/http/api/dvpn/entry.rs | 101 +++ .../src/http/api/dvpn/exit.rs | 101 +++ .../src/http/api/dvpn/mod.rs | 67 ++ .../nym-node-status-api/src/http/api/mod.rs | 5 + .../nym-node-status-api/src/http/error.rs | 11 +- .../nym-node-status-api/src/http/models.rs | 227 +++++- .../nym-node-status-api/src/http/state.rs | 191 ++++- .../src/mixnet_scraper/helpers.rs | 2 +- .../src/monitor/geodata.rs | 4 +- .../nym-node-status-api/src/monitor/mod.rs | 27 +- .../src/node_scraper/mod.rs | 2 +- .../nym-node-status-api/src/testruns/mod.rs | 2 +- 20 files changed, 1453 insertions(+), 290 deletions(-) create mode 100644 nym-node-status-api/nym-node-status-api/migrations/007_date_fix.sql create mode 100644 nym-node-status-api/nym-node-status-api/src/http/api/dvpn/country.rs create mode 100644 nym-node-status-api/nym-node-status-api/src/http/api/dvpn/entry.rs create mode 100644 nym-node-status-api/nym-node-status-api/src/http/api/dvpn/exit.rs create mode 100644 nym-node-status-api/nym-node-status-api/src/http/api/dvpn/mod.rs diff --git a/Cargo.lock b/Cargo.lock index 76513f5ab7..0aed14970b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4846,11 +4846,11 @@ dependencies = [ "nym-node-tester-utils", "nym-pemstore 0.3.0", "nym-serde-helpers 0.1.0", - "nym-sphinx", - "nym-statistics-common", - "nym-task", + "nym-sphinx 0.1.0", + "nym-statistics-common 0.1.0", + "nym-task 0.1.0", "nym-ticketbooks-merkle 0.1.0", - "nym-topology", + "nym-topology 0.1.0", "nym-types", "nym-validator-client 0.1.0", "nym-vesting-contract-common 0.7.0", @@ -4921,7 +4921,7 @@ dependencies = [ [[package]] name = "nym-api-requests" version = "0.1.0" -source = "git+https://github.com/nymtech/nym?branch=release/2025.11-cheddar#e9bb9792ab723a1ad5fe40cb292dc08d4eb40c2f" +source = "git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar#e9bb9792ab723a1ad5fe40cb292dc08d4eb40c2f" dependencies = [ "bs58", "cosmrs", @@ -4930,17 +4930,17 @@ dependencies = [ "getset", "hex", "humantime-serde", - "nym-compact-ecash 0.1.0 (git+https://github.com/nymtech/nym?branch=release/2025.11-cheddar)", - "nym-config 0.1.0 (git+https://github.com/nymtech/nym?branch=release/2025.11-cheddar)", - "nym-contracts-common 0.5.0 (git+https://github.com/nymtech/nym?branch=release/2025.11-cheddar)", - "nym-credentials-interface 0.1.0 (git+https://github.com/nymtech/nym?branch=release/2025.11-cheddar)", - "nym-crypto 0.4.0 (git+https://github.com/nymtech/nym?branch=release/2025.11-cheddar)", - "nym-ecash-time 0.1.0 (git+https://github.com/nymtech/nym?branch=release/2025.11-cheddar)", - "nym-mixnet-contract-common 0.6.0 (git+https://github.com/nymtech/nym?branch=release/2025.11-cheddar)", - "nym-network-defaults 0.1.0 (git+https://github.com/nymtech/nym?branch=release/2025.11-cheddar)", - "nym-node-requests 0.1.0 (git+https://github.com/nymtech/nym?branch=release/2025.11-cheddar)", - "nym-serde-helpers 0.1.0 (git+https://github.com/nymtech/nym?branch=release/2025.11-cheddar)", - "nym-ticketbooks-merkle 0.1.0 (git+https://github.com/nymtech/nym?branch=release/2025.11-cheddar)", + "nym-compact-ecash 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-config 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-contracts-common 0.5.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-credentials-interface 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-crypto 0.4.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-ecash-time 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-mixnet-contract-common 0.6.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-network-defaults 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-node-requests 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-serde-helpers 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-ticketbooks-merkle 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", "schemars", "serde", "serde_json", @@ -4991,8 +4991,8 @@ dependencies = [ "nym-sdk", "nym-service-provider-requests-common", "nym-service-providers-common", - "nym-sphinx", - "nym-task", + "nym-sphinx 0.1.0", + "nym-task 0.1.0", "nym-types", "nym-wireguard", "nym-wireguard-types 0.1.0", @@ -5017,7 +5017,7 @@ dependencies = [ "nym-crypto 0.4.0", "nym-network-defaults 0.1.0", "nym-service-provider-requests-common", - "nym-sphinx", + "nym-sphinx 0.1.0", "nym-wireguard-types 0.1.0", "rand 0.8.5", "serde", @@ -5039,7 +5039,7 @@ dependencies = [ "nym-ecash-contract-common 0.1.0", "nym-ecash-time 0.1.0", "nym-network-defaults 0.1.0", - "nym-task", + "nym-task 0.1.0", "nym-validator-client 0.1.0", "rand 0.8.5", "thiserror 2.0.12", @@ -5072,7 +5072,7 @@ dependencies = [ [[package]] name = "nym-bin-common" version = "0.6.0" -source = "git+https://github.com/nymtech/nym?branch=release/2025.11-cheddar#e9bb9792ab723a1ad5fe40cb292dc08d4eb40c2f" +source = "git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar#e9bb9792ab723a1ad5fe40cb292dc08d4eb40c2f" dependencies = [ "const-str", "log", @@ -5147,7 +5147,7 @@ dependencies = [ "nym-multisig-contract-common 0.1.0", "nym-network-defaults 0.1.0", "nym-pemstore 0.3.0", - "nym-sphinx", + "nym-sphinx 0.1.0", "nym-types", "nym-validator-client 0.1.0", "nym-vesting-contract-common 0.7.0", @@ -5185,9 +5185,9 @@ dependencies = [ "nym-id", "nym-network-defaults 0.1.0", "nym-pemstore 0.3.0", - "nym-sphinx", - "nym-task", - "nym-topology", + "nym-sphinx 0.1.0", + "nym-task 0.1.0", + "nym-topology 0.1.0", "nym-validator-client 0.1.0", "rand 0.8.5", "serde", @@ -5230,15 +5230,15 @@ dependencies = [ "nym-gateway-requests", "nym-http-api-client 0.1.0", "nym-id", - "nym-metrics", + "nym-metrics 0.1.0", "nym-mixnet-client", "nym-network-defaults 0.1.0", "nym-nonexhaustive-delayqueue", "nym-pemstore 0.3.0", - "nym-sphinx", - "nym-statistics-common", - "nym-task", - "nym-topology", + "nym-sphinx 0.1.0", + "nym-statistics-common 0.1.0", + "nym-task 0.1.0", + "nym-topology 0.1.0", "nym-validator-client 0.1.0", "rand 0.8.5", "rand_chacha 0.3.1", @@ -5269,9 +5269,9 @@ dependencies = [ "humantime-serde", "nym-config 0.1.0", "nym-pemstore 0.3.0", - "nym-sphinx-addressing", - "nym-sphinx-params", - "nym-statistics-common", + "nym-sphinx-addressing 0.1.0", + "nym-sphinx-params 0.1.0", + "nym-statistics-common 0.1.0", "serde", "thiserror 2.0.12", "url", @@ -5303,8 +5303,8 @@ dependencies = [ "dashmap", "log", "nym-crypto 0.4.0", - "nym-sphinx", - "nym-task", + "nym-sphinx 0.1.0", + "nym-task 0.1.0", "sqlx", "thiserror 2.0.12", "time", @@ -5338,7 +5338,7 @@ dependencies = [ name = "nym-client-websocket-requests" version = "0.1.0" dependencies = [ - "nym-sphinx", + "nym-sphinx 0.1.0", "serde", "serde_json", ] @@ -5359,15 +5359,15 @@ dependencies = [ [[package]] name = "nym-coconut-dkg-common" version = "0.1.0" -source = "git+https://github.com/nymtech/nym?branch=release/2025.11-cheddar#e9bb9792ab723a1ad5fe40cb292dc08d4eb40c2f" +source = "git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar#e9bb9792ab723a1ad5fe40cb292dc08d4eb40c2f" dependencies = [ "cosmwasm-schema", "cosmwasm-std", "cw-utils", "cw2", "cw4", - "nym-contracts-common 0.5.0 (git+https://github.com/nymtech/nym?branch=release/2025.11-cheddar)", - "nym-multisig-contract-common 0.1.0 (git+https://github.com/nymtech/nym?branch=release/2025.11-cheddar)", + "nym-contracts-common 0.5.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-multisig-contract-common 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", ] [[package]] @@ -5397,7 +5397,7 @@ dependencies = [ [[package]] name = "nym-compact-ecash" version = "0.1.0" -source = "git+https://github.com/nymtech/nym?branch=release/2025.11-cheddar#e9bb9792ab723a1ad5fe40cb292dc08d4eb40c2f" +source = "git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar#e9bb9792ab723a1ad5fe40cb292dc08d4eb40c2f" dependencies = [ "bincode", "bls12_381", @@ -5407,8 +5407,8 @@ dependencies = [ "ff", "group", "itertools 0.14.0", - "nym-network-defaults 0.1.0 (git+https://github.com/nymtech/nym?branch=release/2025.11-cheddar)", - "nym-pemstore 0.3.0 (git+https://github.com/nymtech/nym?branch=release/2025.11-cheddar)", + "nym-network-defaults 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-pemstore 0.3.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", "rand 0.8.5", "serde", "sha2 0.10.9", @@ -5434,12 +5434,12 @@ dependencies = [ [[package]] name = "nym-config" version = "0.1.0" -source = "git+https://github.com/nymtech/nym?branch=release/2025.11-cheddar#e9bb9792ab723a1ad5fe40cb292dc08d4eb40c2f" +source = "git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar#e9bb9792ab723a1ad5fe40cb292dc08d4eb40c2f" dependencies = [ "dirs", "handlebars", "log", - "nym-network-defaults 0.1.0 (git+https://github.com/nymtech/nym?branch=release/2025.11-cheddar)", + "nym-network-defaults 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", "serde", "thiserror 2.0.12", "toml 0.8.22", @@ -5465,7 +5465,7 @@ dependencies = [ [[package]] name = "nym-contracts-common" version = "0.5.0" -source = "git+https://github.com/nymtech/nym?branch=release/2025.11-cheddar#e9bb9792ab723a1ad5fe40cb292dc08d4eb40c2f" +source = "git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar#e9bb9792ab723a1ad5fe40cb292dc08d4eb40c2f" dependencies = [ "bs58", "cosmwasm-schema", @@ -5487,7 +5487,7 @@ dependencies = [ "nym-bin-common 0.6.0", "nym-ffi-shared", "nym-sdk", - "nym-sphinx-anonymous-replies", + "nym-sphinx-anonymous-replies 0.1.0", "tokio", ] @@ -5610,7 +5610,7 @@ dependencies = [ "nym-ecash-contract-common 0.1.0", "nym-gateway-requests", "nym-gateway-storage", - "nym-task", + "nym-task 0.1.0", "nym-validator-client 0.1.0", "rand 0.8.5", "si-scale", @@ -5662,12 +5662,12 @@ dependencies = [ [[package]] name = "nym-credentials-interface" version = "0.1.0" -source = "git+https://github.com/nymtech/nym?branch=release/2025.11-cheddar#e9bb9792ab723a1ad5fe40cb292dc08d4eb40c2f" +source = "git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar#e9bb9792ab723a1ad5fe40cb292dc08d4eb40c2f" dependencies = [ "bls12_381", - "nym-compact-ecash 0.1.0 (git+https://github.com/nymtech/nym?branch=release/2025.11-cheddar)", - "nym-ecash-time 0.1.0 (git+https://github.com/nymtech/nym?branch=release/2025.11-cheddar)", - "nym-network-defaults 0.1.0 (git+https://github.com/nymtech/nym?branch=release/2025.11-cheddar)", + "nym-compact-ecash 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-ecash-time 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-network-defaults 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", "rand 0.8.5", "serde", "strum 0.26.3", @@ -5708,14 +5708,26 @@ dependencies = [ [[package]] name = "nym-crypto" version = "0.4.0" -source = "git+https://github.com/nymtech/nym?branch=release/2025.11-cheddar#e9bb9792ab723a1ad5fe40cb292dc08d4eb40c2f" +source = "git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar#e9bb9792ab723a1ad5fe40cb292dc08d4eb40c2f" dependencies = [ + "aead", + "aes", + "aes-gcm-siv", + "blake3", "bs58", + "cipher", + "ctr", + "digest 0.10.7", "ed25519-dalek", - "nym-pemstore 0.3.0 (git+https://github.com/nymtech/nym?branch=release/2025.11-cheddar)", - "nym-sphinx-types 0.2.0 (git+https://github.com/nymtech/nym?branch=release/2025.11-cheddar)", + "generic-array 0.14.7", + "hkdf", + "hmac", + "nym-pemstore 0.3.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-sphinx-types 0.2.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "rand 0.8.5", "serde", "serde_bytes", + "sha2 0.10.9", "subtle-encoding", "thiserror 2.0.12", "x25519-dalek", @@ -5762,14 +5774,14 @@ dependencies = [ [[package]] name = "nym-ecash-contract-common" version = "0.1.0" -source = "git+https://github.com/nymtech/nym?branch=release/2025.11-cheddar#e9bb9792ab723a1ad5fe40cb292dc08d4eb40c2f" +source = "git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar#e9bb9792ab723a1ad5fe40cb292dc08d4eb40c2f" dependencies = [ "bs58", "cosmwasm-schema", "cosmwasm-std", "cw-controllers", "cw-utils", - "nym-multisig-contract-common 0.1.0 (git+https://github.com/nymtech/nym?branch=release/2025.11-cheddar)", + "nym-multisig-contract-common 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", "thiserror 2.0.12", ] @@ -5784,7 +5796,7 @@ dependencies = [ [[package]] name = "nym-ecash-time" version = "0.1.0" -source = "git+https://github.com/nymtech/nym?branch=release/2025.11-cheddar#e9bb9792ab723a1ad5fe40cb292dc08d4eb40c2f" +source = "git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar#e9bb9792ab723a1ad5fe40cb292dc08d4eb40c2f" dependencies = [ "time", ] @@ -5812,7 +5824,7 @@ dependencies = [ [[package]] name = "nym-exit-policy" version = "0.1.0" -source = "git+https://github.com/nymtech/nym?branch=release/2025.11-cheddar#e9bb9792ab723a1ad5fe40cb292dc08d4eb40c2f" +source = "git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar#e9bb9792ab723a1ad5fe40cb292dc08d4eb40c2f" dependencies = [ "serde", "serde_json", @@ -5831,7 +5843,7 @@ dependencies = [ "nym-bin-common 0.6.0", "nym-crypto 0.4.0", "nym-sdk", - "nym-sphinx-anonymous-replies", + "nym-sphinx-anonymous-replies 0.1.0", "tokio", "uniffi", "uniffi_build", @@ -5865,10 +5877,10 @@ dependencies = [ "nym-network-requester", "nym-node-metrics", "nym-sdk", - "nym-sphinx", - "nym-statistics-common", - "nym-task", - "nym-topology", + "nym-sphinx 0.1.0", + "nym-statistics-common 0.1.0", + "nym-task 0.1.0", + "nym-topology 0.1.0", "nym-types", "nym-validator-client 0.1.0", "nym-wireguard", @@ -5903,9 +5915,9 @@ dependencies = [ "nym-http-api-client 0.1.0", "nym-network-defaults 0.1.0", "nym-pemstore 0.3.0", - "nym-sphinx", - "nym-statistics-common", - "nym-task", + "nym-sphinx 0.1.0", + "nym-statistics-common 0.1.0", + "nym-task 0.1.0", "nym-validator-client 0.1.0", "rand 0.8.5", "serde", @@ -5938,9 +5950,9 @@ dependencies = [ "nym-crypto 0.4.0", "nym-pemstore 0.3.0", "nym-serde-helpers 0.1.0", - "nym-sphinx", - "nym-statistics-common", - "nym-task", + "nym-sphinx 0.1.0", + "nym-statistics-common 0.1.0", + "nym-task 0.1.0", "rand 0.8.5", "serde", "serde_json", @@ -5960,8 +5972,8 @@ name = "nym-gateway-stats-storage" version = "0.1.0" dependencies = [ "nym-node-metrics", - "nym-sphinx", - "nym-statistics-common", + "nym-sphinx 0.1.0", + "nym-statistics-common 0.1.0", "sqlx", "strum 0.26.3", "thiserror 2.0.12", @@ -5978,7 +5990,7 @@ dependencies = [ "defguard_wireguard_rs", "nym-credentials-interface 0.1.0", "nym-gateway-requests", - "nym-sphinx", + "nym-sphinx 0.1.0", "sqlx", "thiserror 2.0.12", "time", @@ -5996,7 +6008,7 @@ dependencies = [ "nym-crypto 0.4.0", "nym-ffi-shared", "nym-sdk", - "nym-sphinx-anonymous-replies", + "nym-sphinx-anonymous-replies 0.1.0", "thiserror 2.0.12", "tokio", "uniffi", @@ -6017,7 +6029,7 @@ dependencies = [ [[package]] name = "nym-group-contract-common" version = "0.1.0" -source = "git+https://github.com/nymtech/nym?branch=release/2025.11-cheddar#e9bb9792ab723a1ad5fe40cb292dc08d4eb40c2f" +source = "git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar#e9bb9792ab723a1ad5fe40cb292dc08d4eb40c2f" dependencies = [ "cosmwasm-schema", "cw-controllers", @@ -6054,7 +6066,7 @@ dependencies = [ [[package]] name = "nym-http-api-client" version = "0.1.0" -source = "git+https://github.com/nymtech/nym?branch=release/2025.11-cheddar#e9bb9792ab723a1ad5fe40cb292dc08d4eb40c2f" +source = "git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar#e9bb9792ab723a1ad5fe40cb292dc08d4eb40c2f" dependencies = [ "async-trait", "bincode", @@ -6063,8 +6075,8 @@ dependencies = [ "hickory-resolver", "http 1.3.1", "mime", - "nym-bin-common 0.6.0 (git+https://github.com/nymtech/nym?branch=release/2025.11-cheddar)", - "nym-http-api-common 0.1.0 (git+https://github.com/nymtech/nym?branch=release/2025.11-cheddar)", + "nym-bin-common 0.6.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-http-api-common 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", "once_cell", "reqwest 0.12.15", "serde", @@ -6099,11 +6111,18 @@ dependencies = [ [[package]] name = "nym-http-api-common" version = "0.1.0" -source = "git+https://github.com/nymtech/nym?branch=release/2025.11-cheddar#e9bb9792ab723a1ad5fe40cb292dc08d4eb40c2f" +source = "git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar#e9bb9792ab723a1ad5fe40cb292dc08d4eb40c2f" dependencies = [ + "axum 0.7.9", + "axum-client-ip", "bincode", + "colored", + "futures", "serde", + "subtle 2.6.1", + "tower 0.5.2", "tracing", + "zeroize", ] [[package]] @@ -6150,7 +6169,7 @@ dependencies = [ "nym-bin-common 0.6.0", "nym-crypto 0.4.0", "nym-service-provider-requests-common", - "nym-sphinx", + "nym-sphinx 0.1.0", "rand 0.8.5", "serde", "thiserror 2.0.12", @@ -6184,8 +6203,8 @@ dependencies = [ "nym-sdk", "nym-service-provider-requests-common", "nym-service-providers-common", - "nym-sphinx", - "nym-task", + "nym-sphinx 0.1.0", + "nym-task 0.1.0", "nym-tun", "nym-types", "nym-wireguard", @@ -6223,6 +6242,17 @@ dependencies = [ "tracing", ] +[[package]] +name = "nym-metrics" +version = "0.1.0" +source = "git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar#e9bb9792ab723a1ad5fe40cb292dc08d4eb40c2f" +dependencies = [ + "dashmap", + "lazy_static", + "prometheus", + "tracing", +] + [[package]] name = "nym-mixnet-client" version = "0.1.0" @@ -6231,8 +6261,8 @@ dependencies = [ "futures", "nym-crypto 0.4.0", "nym-noise", - "nym-sphinx", - "nym-task", + "nym-sphinx 0.1.0", + "nym-task 0.1.0", "rand 0.8.5", "tokio", "tokio-stream", @@ -6267,7 +6297,7 @@ dependencies = [ [[package]] name = "nym-mixnet-contract-common" version = "0.6.0" -source = "git+https://github.com/nymtech/nym?branch=release/2025.11-cheddar#e9bb9792ab723a1ad5fe40cb292dc08d4eb40c2f" +source = "git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar#e9bb9792ab723a1ad5fe40cb292dc08d4eb40c2f" dependencies = [ "bs58", "cosmwasm-schema", @@ -6275,7 +6305,7 @@ dependencies = [ "cw-controllers", "cw-storage-plus", "humantime-serde", - "nym-contracts-common 0.5.0 (git+https://github.com/nymtech/nym?branch=release/2025.11-cheddar)", + "nym-contracts-common 0.5.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", "schemars", "semver 1.0.26", "serde", @@ -6295,15 +6325,15 @@ dependencies = [ "humantime-serde", "log", "nym-crypto 0.4.0", - "nym-metrics", + "nym-metrics 0.1.0", "nym-network-defaults 0.1.0", - "nym-sphinx-acknowledgements", - "nym-sphinx-addressing", - "nym-sphinx-forwarding", - "nym-sphinx-framing", - "nym-sphinx-params", + "nym-sphinx-acknowledgements 0.1.0", + "nym-sphinx-addressing 0.1.0", + "nym-sphinx-forwarding 0.1.0", + "nym-sphinx-framing 0.1.0", + "nym-sphinx-params 0.1.0", "nym-sphinx-types 0.2.0", - "nym-task", + "nym-task 0.1.0", "rand 0.8.5", "serde", "thiserror 2.0.12", @@ -6331,7 +6361,7 @@ dependencies = [ [[package]] name = "nym-multisig-contract-common" version = "0.1.0" -source = "git+https://github.com/nymtech/nym?branch=release/2025.11-cheddar#e9bb9792ab723a1ad5fe40cb292dc08d4eb40c2f" +source = "git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar#e9bb9792ab723a1ad5fe40cb292dc08d4eb40c2f" dependencies = [ "cosmwasm-schema", "cosmwasm-std", @@ -6361,7 +6391,7 @@ dependencies = [ [[package]] name = "nym-network-defaults" version = "0.1.0" -source = "git+https://github.com/nymtech/nym?branch=release/2025.11-cheddar#e9bb9792ab723a1ad5fe40cb292dc08d4eb40c2f" +source = "git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar#e9bb9792ab723a1ad5fe40cb292dc08d4eb40c2f" dependencies = [ "cargo_metadata 0.18.1", "dotenvy", @@ -6389,8 +6419,8 @@ dependencies = [ "nym-gateway-requests", "nym-network-defaults 0.1.0", "nym-sdk", - "nym-sphinx", - "nym-topology", + "nym-sphinx 0.1.0", + "nym-topology 0.1.0", "nym-types", "nym-validator-client 0.1.0", "petgraph", @@ -6436,8 +6466,8 @@ dependencies = [ "nym-service-providers-common", "nym-socks5-proxy-helpers", "nym-socks5-requests", - "nym-sphinx", - "nym-task", + "nym-sphinx 0.1.0", + "nym-task 0.1.0", "nym-types", "publicsuffix", "rand 0.8.5", @@ -6494,7 +6524,7 @@ dependencies = [ "nym-http-api-client 0.1.0", "nym-http-api-common 0.1.0", "nym-ip-packet-router", - "nym-metrics", + "nym-metrics 0.1.0", "nym-mixnet-client", "nym-network-requester", "nym-node-metrics", @@ -6503,16 +6533,16 @@ dependencies = [ "nym-noise-keys", "nym-nonexhaustive-delayqueue", "nym-pemstore 0.3.0", - "nym-sphinx-acknowledgements", - "nym-sphinx-addressing", - "nym-sphinx-forwarding", - "nym-sphinx-framing", - "nym-sphinx-params", - "nym-sphinx-routing", + "nym-sphinx-acknowledgements 0.1.0", + "nym-sphinx-addressing 0.1.0", + "nym-sphinx-forwarding 0.1.0", + "nym-sphinx-framing 0.1.0", + "nym-sphinx-params 0.1.0", + "nym-sphinx-routing 0.1.0", "nym-sphinx-types 0.2.0", - "nym-statistics-common", - "nym-task", - "nym-topology", + "nym-statistics-common 0.1.0", + "nym-task 0.1.0", + "nym-topology 0.1.0", "nym-types", "nym-validator-client 0.1.0", "nym-verloc", @@ -6545,8 +6575,8 @@ version = "0.1.0" dependencies = [ "dashmap", "futures", - "nym-metrics", - "nym-statistics-common", + "nym-metrics 0.1.0", + "nym-statistics-common 0.1.0", "strum 0.26.3", "time", "tokio", @@ -6581,15 +6611,17 @@ dependencies = [ [[package]] name = "nym-node-requests" version = "0.1.0" -source = "git+https://github.com/nymtech/nym?branch=release/2025.11-cheddar#e9bb9792ab723a1ad5fe40cb292dc08d4eb40c2f" +source = "git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar#e9bb9792ab723a1ad5fe40cb292dc08d4eb40c2f" dependencies = [ + "async-trait", "celes", "humantime", "humantime-serde", - "nym-bin-common 0.6.0 (git+https://github.com/nymtech/nym?branch=release/2025.11-cheddar)", - "nym-crypto 0.4.0 (git+https://github.com/nymtech/nym?branch=release/2025.11-cheddar)", - "nym-exit-policy 0.1.0 (git+https://github.com/nymtech/nym?branch=release/2025.11-cheddar)", - "nym-wireguard-types 0.1.0 (git+https://github.com/nymtech/nym?branch=release/2025.11-cheddar)", + "nym-bin-common 0.6.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-crypto 0.4.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-exit-policy 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-http-api-client 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-wireguard-types 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", "schemars", "serde", "serde_json", @@ -6607,7 +6639,7 @@ dependencies = [ "clap", "nym-bin-common 0.6.0", "nym-crypto 0.4.0", - "nym-node-status-client", + "nym-node-status-client 0.1.1", "rand 0.8.5", "tempfile", "tokio", @@ -6617,36 +6649,38 @@ dependencies = [ [[package]] name = "nym-node-status-api" -version = "2.3.3" +version = "3.0.0" dependencies = [ "ammonia", "anyhow", "axum 0.7.9", "bip39", + "celes", "clap", "cosmwasm-std", "envy", "futures-util", "itertools 0.14.0", "moka", - "nym-bin-common 0.6.0", - "nym-contracts-common 0.5.0", - "nym-crypto 0.4.0", - "nym-http-api-client 0.1.0", - "nym-http-api-common 0.1.0", - "nym-mixnet-contract-common 0.6.0", - "nym-network-defaults 0.1.0", + "nym-bin-common 0.6.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-contracts-common 0.5.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-crypto 0.4.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-http-api-client 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-http-api-common 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-mixnet-contract-common 0.6.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-network-defaults 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", "nym-node-metrics", - "nym-node-requests 0.1.0", - "nym-node-status-client", - "nym-serde-helpers 0.1.0", - "nym-statistics-common", - "nym-task", - "nym-validator-client 0.1.0", + "nym-node-requests 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-node-status-client 0.1.0", + "nym-serde-helpers 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-statistics-common 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-task 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-validator-client 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", "rand 0.8.5", "rand_chacha 0.3.1", "regex", "reqwest 0.12.15", + "semver 1.0.26", "serde", "serde_json", "serde_json_path", @@ -6666,6 +6700,22 @@ dependencies = [ "utoipauto", ] +[[package]] +name = "nym-node-status-client" +version = "0.1.0" +source = "git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar#e9bb9792ab723a1ad5fe40cb292dc08d4eb40c2f" +dependencies = [ + "anyhow", + "bincode", + "chrono", + "nym-crypto 0.4.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-http-api-client 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "reqwest 0.12.15", + "serde", + "serde_json", + "tracing", +] + [[package]] name = "nym-node-status-client" version = "0.1.1" @@ -6688,10 +6738,10 @@ dependencies = [ "futures", "log", "nym-crypto 0.4.0", - "nym-sphinx", - "nym-sphinx-params", - "nym-task", - "nym-topology", + "nym-sphinx 0.1.0", + "nym-sphinx-params 0.1.0", + "nym-task 0.1.0", + "nym-topology 0.1.0", "rand 0.8.5", "rand_chacha 0.3.1", "serde", @@ -6805,6 +6855,24 @@ dependencies = [ "zeroize", ] +[[package]] +name = "nym-outfox" +version = "0.1.0" +source = "git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar#e9bb9792ab723a1ad5fe40cb292dc08d4eb40c2f" +dependencies = [ + "blake3", + "chacha20", + "chacha20poly1305", + "getrandom 0.2.15", + "log", + "rand 0.8.5", + "rayon", + "sphinx-packet", + "thiserror 2.0.12", + "x25519-dalek", + "zeroize", +] + [[package]] name = "nym-pemstore" version = "0.3.0" @@ -6817,7 +6885,7 @@ dependencies = [ [[package]] name = "nym-pemstore" version = "0.3.0" -source = "git+https://github.com/nymtech/nym?branch=release/2025.11-cheddar#e9bb9792ab723a1ad5fe40cb292dc08d4eb40c2f" +source = "git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar#e9bb9792ab723a1ad5fe40cb292dc08d4eb40c2f" dependencies = [ "pem", "tracing", @@ -6869,11 +6937,11 @@ dependencies = [ "nym-service-providers-common", "nym-socks5-client-core", "nym-socks5-requests", - "nym-sphinx", - "nym-sphinx-addressing", - "nym-statistics-common", - "nym-task", - "nym-topology", + "nym-sphinx 0.1.0", + "nym-sphinx-addressing 0.1.0", + "nym-statistics-common 0.1.0", + "nym-task 0.1.0", + "nym-topology 0.1.0", "nym-validator-client 0.1.0", "parking_lot", "rand 0.8.5", @@ -6907,7 +6975,7 @@ dependencies = [ [[package]] name = "nym-serde-helpers" version = "0.1.0" -source = "git+https://github.com/nymtech/nym?branch=release/2025.11-cheddar#e9bb9792ab723a1ad5fe40cb292dc08d4eb40c2f" +source = "git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar#e9bb9792ab723a1ad5fe40cb292dc08d4eb40c2f" dependencies = [ "base64 0.22.1", "bs58", @@ -6935,7 +7003,7 @@ dependencies = [ "nym-bin-common 0.6.0", "nym-sdk", "nym-socks5-requests", - "nym-sphinx-anonymous-replies", + "nym-sphinx-anonymous-replies 0.1.0", "serde", "serde_json", "thiserror 2.0.12", @@ -6961,8 +7029,8 @@ dependencies = [ "nym-ordered-buffer", "nym-pemstore 0.3.0", "nym-socks5-client-core", - "nym-sphinx", - "nym-topology", + "nym-sphinx 0.1.0", + "nym-topology 0.1.0", "nym-validator-client 0.1.0", "rand 0.8.5", "serde", @@ -6993,8 +7061,8 @@ dependencies = [ "nym-service-providers-common", "nym-socks5-proxy-helpers", "nym-socks5-requests", - "nym-sphinx", - "nym-task", + "nym-sphinx 0.1.0", + "nym-task 0.1.0", "nym-validator-client 0.1.0", "pin-project", "rand 0.8.5", @@ -7016,7 +7084,7 @@ dependencies = [ "log", "nym-ordered-buffer", "nym-socks5-requests", - "nym-task", + "nym-task 0.1.0", "tokio", "tokio-test", "tokio-util", @@ -7030,7 +7098,7 @@ dependencies = [ "log", "nym-exit-policy 0.1.0", "nym-service-providers-common", - "nym-sphinx-addressing", + "nym-sphinx-addressing 0.1.0", "serde", "serde_json", "tap", @@ -7042,19 +7110,45 @@ name = "nym-sphinx" version = "0.1.0" dependencies = [ "nym-crypto 0.4.0", - "nym-metrics", + "nym-metrics 0.1.0", "nym-mixnet-contract-common 0.6.0", - "nym-sphinx-acknowledgements", - "nym-sphinx-addressing", - "nym-sphinx-anonymous-replies", - "nym-sphinx-chunking", - "nym-sphinx-cover", - "nym-sphinx-forwarding", - "nym-sphinx-framing", - "nym-sphinx-params", - "nym-sphinx-routing", + "nym-sphinx-acknowledgements 0.1.0", + "nym-sphinx-addressing 0.1.0", + "nym-sphinx-anonymous-replies 0.1.0", + "nym-sphinx-chunking 0.1.0", + "nym-sphinx-cover 0.1.0", + "nym-sphinx-forwarding 0.1.0", + "nym-sphinx-framing 0.1.0", + "nym-sphinx-params 0.1.0", + "nym-sphinx-routing 0.1.0", "nym-sphinx-types 0.2.0", - "nym-topology", + "nym-topology 0.1.0", + "rand 0.8.5", + "rand_chacha 0.3.1", + "rand_distr", + "thiserror 2.0.12", + "tokio", + "tracing", +] + +[[package]] +name = "nym-sphinx" +version = "0.1.0" +source = "git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar#e9bb9792ab723a1ad5fe40cb292dc08d4eb40c2f" +dependencies = [ + "nym-crypto 0.4.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-metrics 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-sphinx-acknowledgements 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-sphinx-addressing 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-sphinx-anonymous-replies 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-sphinx-chunking 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-sphinx-cover 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-sphinx-forwarding 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-sphinx-framing 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-sphinx-params 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-sphinx-routing 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-sphinx-types 0.2.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-topology 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", "rand 0.8.5", "rand_chacha 0.3.1", "rand_distr", @@ -7070,17 +7164,34 @@ dependencies = [ "generic-array 0.14.7", "nym-crypto 0.4.0", "nym-pemstore 0.3.0", - "nym-sphinx-addressing", - "nym-sphinx-params", - "nym-sphinx-routing", + "nym-sphinx-addressing 0.1.0", + "nym-sphinx-params 0.1.0", + "nym-sphinx-routing 0.1.0", "nym-sphinx-types 0.2.0", - "nym-topology", + "nym-topology 0.1.0", "rand 0.8.5", "serde", "thiserror 2.0.12", "zeroize", ] +[[package]] +name = "nym-sphinx-acknowledgements" +version = "0.1.0" +source = "git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar#e9bb9792ab723a1ad5fe40cb292dc08d4eb40c2f" +dependencies = [ + "nym-crypto 0.4.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-pemstore 0.3.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-sphinx-addressing 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-sphinx-params 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-sphinx-routing 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-sphinx-types 0.2.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-topology 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "rand 0.8.5", + "thiserror 2.0.12", + "zeroize", +] + [[package]] name = "nym-sphinx-addressing" version = "0.1.0" @@ -7092,17 +7203,28 @@ dependencies = [ "thiserror 2.0.12", ] +[[package]] +name = "nym-sphinx-addressing" +version = "0.1.0" +source = "git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar#e9bb9792ab723a1ad5fe40cb292dc08d4eb40c2f" +dependencies = [ + "nym-crypto 0.4.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-sphinx-types 0.2.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "serde", + "thiserror 2.0.12", +] + [[package]] name = "nym-sphinx-anonymous-replies" version = "0.1.0" dependencies = [ "bs58", "nym-crypto 0.4.0", - "nym-sphinx-addressing", - "nym-sphinx-params", - "nym-sphinx-routing", + "nym-sphinx-addressing 0.1.0", + "nym-sphinx-params 0.1.0", + "nym-sphinx-routing 0.1.0", "nym-sphinx-types 0.2.0", - "nym-topology", + "nym-topology 0.1.0", "rand 0.8.5", "rand_chacha 0.3.1", "thiserror 2.0.12", @@ -7110,6 +7232,25 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "nym-sphinx-anonymous-replies" +version = "0.1.0" +source = "git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar#e9bb9792ab723a1ad5fe40cb292dc08d4eb40c2f" +dependencies = [ + "bs58", + "nym-crypto 0.4.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-sphinx-addressing 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-sphinx-params 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-sphinx-routing 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-sphinx-types 0.2.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-topology 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "rand 0.8.5", + "serde", + "thiserror 2.0.12", + "tracing", + "wasm-bindgen", +] + [[package]] name = "nym-sphinx-chunking" version = "0.1.0" @@ -7117,9 +7258,9 @@ dependencies = [ "dashmap", "log", "nym-crypto 0.4.0", - "nym-metrics", - "nym-sphinx-addressing", - "nym-sphinx-params", + "nym-metrics 0.1.0", + "nym-sphinx-addressing 0.1.0", + "nym-sphinx-params 0.1.0", "nym-sphinx-types 0.2.0", "rand 0.8.5", "serde", @@ -7127,19 +7268,55 @@ dependencies = [ "utoipa", ] +[[package]] +name = "nym-sphinx-chunking" +version = "0.1.0" +source = "git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar#e9bb9792ab723a1ad5fe40cb292dc08d4eb40c2f" +dependencies = [ + "dashmap", + "log", + "nym-crypto 0.4.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-metrics 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-sphinx-addressing 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-sphinx-params 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-sphinx-types 0.2.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "rand 0.8.5", + "serde", + "thiserror 2.0.12", + "utoipa", +] + [[package]] name = "nym-sphinx-cover" version = "0.1.0" dependencies = [ "nym-crypto 0.4.0", - "nym-sphinx-acknowledgements", - "nym-sphinx-addressing", - "nym-sphinx-chunking", - "nym-sphinx-forwarding", - "nym-sphinx-params", - "nym-sphinx-routing", + "nym-sphinx-acknowledgements 0.1.0", + "nym-sphinx-addressing 0.1.0", + "nym-sphinx-chunking 0.1.0", + "nym-sphinx-forwarding 0.1.0", + "nym-sphinx-params 0.1.0", + "nym-sphinx-routing 0.1.0", "nym-sphinx-types 0.2.0", - "nym-topology", + "nym-topology 0.1.0", + "rand 0.8.5", + "thiserror 2.0.12", +] + +[[package]] +name = "nym-sphinx-cover" +version = "0.1.0" +source = "git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar#e9bb9792ab723a1ad5fe40cb292dc08d4eb40c2f" +dependencies = [ + "nym-crypto 0.4.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-sphinx-acknowledgements 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-sphinx-addressing 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-sphinx-chunking 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-sphinx-forwarding 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-sphinx-params 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-sphinx-routing 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-sphinx-types 0.2.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-topology 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", "rand 0.8.5", "thiserror 2.0.12", ] @@ -7148,22 +7325,34 @@ dependencies = [ name = "nym-sphinx-forwarding" version = "0.1.0" dependencies = [ - "nym-sphinx-addressing", - "nym-sphinx-anonymous-replies", - "nym-sphinx-params", + "nym-sphinx-addressing 0.1.0", + "nym-sphinx-anonymous-replies 0.1.0", + "nym-sphinx-params 0.1.0", "nym-sphinx-types 0.2.0", "thiserror 2.0.12", ] +[[package]] +name = "nym-sphinx-forwarding" +version = "0.1.0" +source = "git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar#e9bb9792ab723a1ad5fe40cb292dc08d4eb40c2f" +dependencies = [ + "nym-outfox 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-sphinx-addressing 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-sphinx-params 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-sphinx-types 0.2.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "thiserror 2.0.12", +] + [[package]] name = "nym-sphinx-framing" version = "0.1.0" dependencies = [ "bytes", - "nym-sphinx-acknowledgements", - "nym-sphinx-addressing", - "nym-sphinx-forwarding", - "nym-sphinx-params", + "nym-sphinx-acknowledgements 0.1.0", + "nym-sphinx-addressing 0.1.0", + "nym-sphinx-forwarding 0.1.0", + "nym-sphinx-params 0.1.0", "nym-sphinx-types 0.2.0", "thiserror 2.0.12", "tokio", @@ -7171,6 +7360,22 @@ dependencies = [ "tracing", ] +[[package]] +name = "nym-sphinx-framing" +version = "0.1.0" +source = "git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar#e9bb9792ab723a1ad5fe40cb292dc08d4eb40c2f" +dependencies = [ + "bytes", + "nym-sphinx-acknowledgements 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-sphinx-addressing 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-sphinx-forwarding 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-sphinx-params 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-sphinx-types 0.2.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "thiserror 2.0.12", + "tokio-util", + "tracing", +] + [[package]] name = "nym-sphinx-params" version = "0.1.0" @@ -7181,20 +7386,41 @@ dependencies = [ "thiserror 2.0.12", ] +[[package]] +name = "nym-sphinx-params" +version = "0.1.0" +source = "git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar#e9bb9792ab723a1ad5fe40cb292dc08d4eb40c2f" +dependencies = [ + "nym-crypto 0.4.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-sphinx-types 0.2.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "serde", + "thiserror 2.0.12", +] + [[package]] name = "nym-sphinx-routing" version = "0.1.0" dependencies = [ - "nym-sphinx-addressing", + "nym-sphinx-addressing 0.1.0", "nym-sphinx-types 0.2.0", "thiserror 2.0.12", ] +[[package]] +name = "nym-sphinx-routing" +version = "0.1.0" +source = "git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar#e9bb9792ab723a1ad5fe40cb292dc08d4eb40c2f" +dependencies = [ + "nym-sphinx-addressing 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-sphinx-types 0.2.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "thiserror 2.0.12", +] + [[package]] name = "nym-sphinx-types" version = "0.2.0" dependencies = [ - "nym-outfox", + "nym-outfox 0.1.0", "sphinx-packet", "thiserror 2.0.12", ] @@ -7202,8 +7428,10 @@ dependencies = [ [[package]] name = "nym-sphinx-types" version = "0.2.0" -source = "git+https://github.com/nymtech/nym?branch=release/2025.11-cheddar#e9bb9792ab723a1ad5fe40cb292dc08d4eb40c2f" +source = "git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar#e9bb9792ab723a1ad5fe40cb292dc08d4eb40c2f" dependencies = [ + "nym-outfox 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "sphinx-packet", "thiserror 2.0.12", ] @@ -7218,11 +7446,11 @@ dependencies = [ "celes", "clap", "nym-bin-common 0.6.0", - "nym-http-api-client 0.1.0 (git+https://github.com/nymtech/nym?branch=release/2025.11-cheddar)", + "nym-http-api-client 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", "nym-http-api-common 0.1.0", - "nym-statistics-common", - "nym-task", - "nym-validator-client 0.1.0 (git+https://github.com/nymtech/nym?branch=release/2025.11-cheddar)", + "nym-statistics-common 0.1.0", + "nym-task 0.1.0", + "nym-validator-client 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", "serde", "serde_json", "sqlx", @@ -7246,9 +7474,9 @@ dependencies = [ "log", "nym-credentials-interface 0.1.0", "nym-crypto 0.4.0", - "nym-metrics", - "nym-sphinx", - "nym-task", + "nym-metrics 0.1.0", + "nym-sphinx 0.1.0", + "nym-task 0.1.0", "serde", "serde_json", "sha2 0.10.9", @@ -7262,6 +7490,30 @@ dependencies = [ "wasmtimer", ] +[[package]] +name = "nym-statistics-common" +version = "0.1.0" +source = "git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar#e9bb9792ab723a1ad5fe40cb292dc08d4eb40c2f" +dependencies = [ + "futures", + "log", + "nym-credentials-interface 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-crypto 0.4.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-metrics 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-sphinx 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-task 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "serde", + "serde_json", + "sha2 0.10.9", + "si-scale", + "strum 0.26.3", + "sysinfo", + "thiserror 2.0.12", + "time", + "tokio", + "wasmtimer", +] + [[package]] name = "nym-store-cipher" version = "0.1.0" @@ -7293,6 +7545,23 @@ dependencies = [ "wasmtimer", ] +[[package]] +name = "nym-task" +version = "0.1.0" +source = "git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar#e9bb9792ab723a1ad5fe40cb292dc08d4eb40c2f" +dependencies = [ + "cfg-if", + "futures", + "log", + "thiserror 2.0.12", + "tokio", + "tokio-util", + "tracing", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasmtimer", +] + [[package]] name = "nym-ticketbooks-merkle" version = "0.1.0" @@ -7313,10 +7582,10 @@ dependencies = [ [[package]] name = "nym-ticketbooks-merkle" version = "0.1.0" -source = "git+https://github.com/nymtech/nym?branch=release/2025.11-cheddar#e9bb9792ab723a1ad5fe40cb292dc08d4eb40c2f" +source = "git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar#e9bb9792ab723a1ad5fe40cb292dc08d4eb40c2f" dependencies = [ - "nym-credentials-interface 0.1.0 (git+https://github.com/nymtech/nym?branch=release/2025.11-cheddar)", - "nym-serde-helpers 0.1.0 (git+https://github.com/nymtech/nym?branch=release/2025.11-cheddar)", + "nym-credentials-interface 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-serde-helpers 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", "rs_merkle", "schemars", "serde", @@ -7334,8 +7603,8 @@ dependencies = [ "nym-config 0.1.0", "nym-crypto 0.4.0", "nym-mixnet-contract-common 0.6.0", - "nym-sphinx-addressing", - "nym-sphinx-routing", + "nym-sphinx-addressing 0.1.0", + "nym-sphinx-routing 0.1.0", "nym-sphinx-types 0.2.0", "rand 0.8.5", "reqwest 0.12.15", @@ -7348,6 +7617,26 @@ dependencies = [ "wasm-utils", ] +[[package]] +name = "nym-topology" +version = "0.1.0" +source = "git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar#e9bb9792ab723a1ad5fe40cb292dc08d4eb40c2f" +dependencies = [ + "async-trait", + "nym-api-requests 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-config 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-crypto 0.4.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-mixnet-contract-common 0.6.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-sphinx-addressing 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-sphinx-routing 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-sphinx-types 0.2.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "rand 0.8.5", + "reqwest 0.12.15", + "serde", + "thiserror 2.0.12", + "tracing", +] + [[package]] name = "nym-tun" version = "0.1.0" @@ -7442,7 +7731,7 @@ dependencies = [ [[package]] name = "nym-validator-client" version = "0.1.0" -source = "git+https://github.com/nymtech/nym?branch=release/2025.11-cheddar#e9bb9792ab723a1ad5fe40cb292dc08d4eb40c2f" +source = "git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar#e9bb9792ab723a1ad5fe40cb292dc08d4eb40c2f" dependencies = [ "async-trait", "base64 0.22.1", @@ -7460,19 +7749,19 @@ dependencies = [ "flate2", "futures", "itertools 0.14.0", - "nym-api-requests 0.1.0 (git+https://github.com/nymtech/nym?branch=release/2025.11-cheddar)", - "nym-coconut-dkg-common 0.1.0 (git+https://github.com/nymtech/nym?branch=release/2025.11-cheddar)", - "nym-compact-ecash 0.1.0 (git+https://github.com/nymtech/nym?branch=release/2025.11-cheddar)", - "nym-config 0.1.0 (git+https://github.com/nymtech/nym?branch=release/2025.11-cheddar)", - "nym-contracts-common 0.5.0 (git+https://github.com/nymtech/nym?branch=release/2025.11-cheddar)", - "nym-ecash-contract-common 0.1.0 (git+https://github.com/nymtech/nym?branch=release/2025.11-cheddar)", - "nym-group-contract-common 0.1.0 (git+https://github.com/nymtech/nym?branch=release/2025.11-cheddar)", - "nym-http-api-client 0.1.0 (git+https://github.com/nymtech/nym?branch=release/2025.11-cheddar)", - "nym-mixnet-contract-common 0.6.0 (git+https://github.com/nymtech/nym?branch=release/2025.11-cheddar)", - "nym-multisig-contract-common 0.1.0 (git+https://github.com/nymtech/nym?branch=release/2025.11-cheddar)", - "nym-network-defaults 0.1.0 (git+https://github.com/nymtech/nym?branch=release/2025.11-cheddar)", - "nym-serde-helpers 0.1.0 (git+https://github.com/nymtech/nym?branch=release/2025.11-cheddar)", - "nym-vesting-contract-common 0.7.0 (git+https://github.com/nymtech/nym?branch=release/2025.11-cheddar)", + "nym-api-requests 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-coconut-dkg-common 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-compact-ecash 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-config 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-contracts-common 0.5.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-ecash-contract-common 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-group-contract-common 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-http-api-client 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-mixnet-contract-common 0.6.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-multisig-contract-common 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-network-defaults 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-serde-helpers 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-vesting-contract-common 0.7.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", "prost 0.13.5", "reqwest 0.12.15", "serde", @@ -7511,7 +7800,7 @@ dependencies = [ "nym-network-defaults 0.1.0", "nym-pemstore 0.3.0", "nym-serde-helpers 0.1.0", - "nym-task", + "nym-task 0.1.0", "nym-ticketbooks-merkle 0.1.0", "nym-validator-client 0.1.0", "nyxd-scraper", @@ -7538,7 +7827,7 @@ dependencies = [ "futures", "humantime", "nym-crypto 0.4.0", - "nym-task", + "nym-task 0.1.0", "nym-validator-client 0.1.0", "rand 0.8.5", "thiserror 2.0.12", @@ -7566,12 +7855,12 @@ dependencies = [ [[package]] name = "nym-vesting-contract-common" version = "0.7.0" -source = "git+https://github.com/nymtech/nym?branch=release/2025.11-cheddar#e9bb9792ab723a1ad5fe40cb292dc08d4eb40c2f" +source = "git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar#e9bb9792ab723a1ad5fe40cb292dc08d4eb40c2f" dependencies = [ "cosmwasm-schema", "cosmwasm-std", - "nym-contracts-common 0.5.0 (git+https://github.com/nymtech/nym?branch=release/2025.11-cheddar)", - "nym-mixnet-contract-common 0.6.0 (git+https://github.com/nymtech/nym?branch=release/2025.11-cheddar)", + "nym-contracts-common 0.5.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-mixnet-contract-common 0.6.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", "serde", "thiserror 2.0.12", ] @@ -7638,7 +7927,7 @@ dependencies = [ "nym-gateway-storage", "nym-network-defaults 0.1.0", "nym-node-metrics", - "nym-task", + "nym-task 0.1.0", "nym-wireguard-types 0.1.0", "thiserror 2.0.12", "time", @@ -7666,12 +7955,12 @@ dependencies = [ [[package]] name = "nym-wireguard-types" version = "0.1.0" -source = "git+https://github.com/nymtech/nym?branch=release/2025.11-cheddar#e9bb9792ab723a1ad5fe40cb292dc08d4eb40c2f" +source = "git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar#e9bb9792ab723a1ad5fe40cb292dc08d4eb40c2f" dependencies = [ "base64 0.22.1", "log", - "nym-config 0.1.0 (git+https://github.com/nymtech/nym?branch=release/2025.11-cheddar)", - "nym-network-defaults 0.1.0 (git+https://github.com/nymtech/nym?branch=release/2025.11-cheddar)", + "nym-config 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", + "nym-network-defaults 0.1.0 (git+https://github.com/nymtech/nym.git?branch=release/2025.11-cheddar)", "serde", "thiserror 2.0.12", "x25519-dalek", @@ -7694,7 +7983,7 @@ dependencies = [ "nym-async-file-watcher", "nym-bin-common 0.6.0", "nym-config 0.1.0", - "nym-task", + "nym-task 0.1.0", "reqwest 0.12.15", "serde", "serde_json", @@ -7719,7 +8008,7 @@ dependencies = [ "nym-bin-common 0.6.0", "nym-config 0.1.0", "nym-network-defaults 0.1.0", - "nym-task", + "nym-task 0.1.0", "nym-validator-client 0.1.0", "nyxd-scraper", "reqwest 0.12.15", @@ -11791,11 +12080,11 @@ dependencies = [ "nym-credential-storage", "nym-crypto 0.4.0", "nym-gateway-client", - "nym-sphinx", - "nym-sphinx-acknowledgements", - "nym-statistics-common", - "nym-task", - "nym-topology", + "nym-sphinx 0.1.0", + "nym-sphinx-acknowledgements 0.1.0", + "nym-statistics-common 0.1.0", + "nym-task 0.1.0", + "nym-topology 0.1.0", "nym-validator-client 0.1.0", "rand 0.8.5", "serde", diff --git a/nym-node-status-api/nym-node-status-agent/run.sh b/nym-node-status-api/nym-node-status-agent/run.sh index 544c6ca731..cf42d745d1 100755 --- a/nym-node-status-api/nym-node-status-agent/run.sh +++ b/nym-node-status-api/nym-node-status-agent/run.sh @@ -3,7 +3,7 @@ set -eu export ENVIRONMENT=${ENVIRONMENT:-"mainnet"} -probe_git_ref="nym-vpn-core-v1.4.0" +probe_git_ref="nym-vpn-core-v1.10.0" crate_root=$(dirname $(realpath "$0")) monorepo_root=$(realpath "${crate_root}/../..") diff --git a/nym-node-status-api/nym-node-status-api/Cargo.toml b/nym-node-status-api/nym-node-status-api/Cargo.toml index 867b9ca833..104e4c9863 100644 --- a/nym-node-status-api/nym-node-status-api/Cargo.toml +++ b/nym-node-status-api/nym-node-status-api/Cargo.toml @@ -3,7 +3,7 @@ [package] name = "nym-node-status-api" -version = "2.3.3" +version = "3.0.0" authors.workspace = true repository.workspace = true homepage.workspace = true @@ -17,29 +17,46 @@ ammonia = { workspace = true } anyhow = { workspace = true } axum = { workspace = true, features = ["tokio", "macros"] } bip39 = { workspace = true } +celes = { workspace = true } clap = { workspace = true, features = ["cargo", "derive", "env", "string"] } cosmwasm-std = { workspace = true } envy = { workspace = true } futures-util = { workspace = true } itertools = { workspace = true } moka = { workspace = true, features = ["future"] } -nym-contracts-common = { path = "../../common/cosmwasm-smart-contracts/contracts-common" } -nym-mixnet-contract-common = { path = "../../common/cosmwasm-smart-contracts/mixnet-contract", features = ["utoipa"] } -nym-bin-common = { path = "../../common/bin-common", features = ["models"] } -nym-node-status-client = { path = "../nym-node-status-client" } -nym-crypto = { path = "../../common/crypto", features = ["asymmetric", "serde"] } -nym-http-api-client = { path = "../../common/http-api-client" } -nym-http-api-common = { path = "../../common/http-api-common", features = ["middleware"]} -nym-network-defaults = { path = "../../common/network-defaults" } -nym-serde-helpers = { path = "../../common/serde-helpers" } -nym-statistics-common = { path = "../../common/statistics" } -nym-validator-client = { path = "../../common/client-libs/validator-client" } -nym-task = { path = "../../common/task" } -nym-node-requests = { path = "../../nym-node/nym-node-requests", features = ["openapi"] } +# TODO dz had to switch to cheddar versions because develop is ahead of current +# Nym API: revert after Cheddar is out +nym-contracts-common = { git = "https://github.com/nymtech/nym.git", branch = "release/2025.11-cheddar" } +nym-mixnet-contract-common = { git = "https://github.com/nymtech/nym.git", branch = "release/2025.11-cheddar" } +nym-bin-common = { git = "https://github.com/nymtech/nym.git", branch = "release/2025.11-cheddar" } +nym-node-status-client = { git = "https://github.com/nymtech/nym.git", branch = "release/2025.11-cheddar" } +nym-crypto = { git = "https://github.com/nymtech/nym.git", branch = "release/2025.11-cheddar" } +nym-http-api-client = { git = "https://github.com/nymtech/nym.git", branch = "release/2025.11-cheddar" } +nym-http-api-common = { git = "https://github.com/nymtech/nym.git", branch = "release/2025.11-cheddar", features = ["middleware"]} +nym-network-defaults = { git = "https://github.com/nymtech/nym.git", branch = "release/2025.11-cheddar" } +nym-serde-helpers = { git = "https://github.com/nymtech/nym.git", branch = "release/2025.11-cheddar" } +nym-statistics-common = { git = "https://github.com/nymtech/nym.git", branch = "release/2025.11-cheddar" } +# nym-contracts-common = { path = "../../common/cosmwasm-smart-contracts/contracts-common" } +# nym-mixnet-contract-common = { path = "../../common/cosmwasm-smart-contracts/mixnet-contract", features = ["utoipa"] } +# nym-bin-common = { path = "../../common/bin-common", features = ["models"] } +# nym-node-status-client = { path = "../nym-node-status-client" } +# nym-crypto = { path = "../../common/crypto", features = ["asymmetric", "serde"] } +# nym-http-api-client = { path = "../../common/http-api-client" } +# nym-http-api-common = { path = "../../common/http-api-common", features = ["middleware"]} +# nym-network-defaults = { path = "../../common/network-defaults" } +# nym-serde-helpers = { path = "../../common/serde-helpers" } +# nym-statistics-common = { path = "../../common/statistics" } +# nym-validator-client = { path = "../../common/client-libs/validator-client" } +nym-validator-client = { git = "https://github.com/nymtech/nym.git", branch = "release/2025.11-cheddar" } +# nym-task = { path = "../../common/task" } +# nym-node-requests = { path = "../../nym-node/nym-node-requests", features = ["openapi"] } +nym-task = { git = "https://github.com/nymtech/nym.git", branch = "release/2025.11-cheddar" } +nym-node-requests = { git = "https://github.com/nymtech/nym.git", branch = "release/2025.11-cheddar" } rand = { workspace = true } rand_chacha = { workspace = true } regex = { workspace = true } reqwest = { workspace = true } +semver = { workspace = true } serde = { workspace = true, features = ["derive"] } serde_json = { workspace = true } serde_json_path = { workspace = true } diff --git a/nym-node-status-api/nym-node-status-api/migrations/007_date_fix.sql b/nym-node-status-api/nym-node-status-api/migrations/007_date_fix.sql new file mode 100644 index 0000000000..4db114e9af --- /dev/null +++ b/nym-node-status-api/nym-node-status-api/migrations/007_date_fix.sql @@ -0,0 +1,113 @@ +-- for a couple of days after migrating chrono -> time, we stored dates as +-- 2025-June-DD instead of 2025-06-DD. This migration fixes those entries. +-- +-- Because of a UNIQUE constraint on (node_id, date_utc), we can't just rename in-place. +-- - merge (add) node stats back to the original table where conflict (node_id, date_utc) would exist +-- - delete invalid records from original table (those stats were merged into correct rows above) +-- - insert rows that did not have a conflicting (node_Id, date_utc) combo +-- Conflicts affect only the date which has both kinds of entries, +-- e.g. 2025-06-05 and 2025-June-05 (date when this change was deployed) +-- +-- This applies to both affected tables. + +-- ---------------------------------------- +-- mixnode_daily_stats +-- ---------------------------------------- + +-- First, copy over rows with invalid date to a temp table (in the correct date format) +CREATE TEMP TABLE tmp_mix AS +SELECT + mix_id, + REPLACE(date_utc,'June','06') AS new_date, + SUM(total_stake) AS total_stake_sum, + SUM(packets_received) AS packets_received_sum, + SUM(packets_sent) AS packets_sent_sum, + SUM(packets_dropped) AS packets_dropped_sum +FROM mixnode_daily_stats +WHERE date_utc LIKE '%June%' +GROUP BY mix_id, new_date; + +UPDATE mixnode_daily_stats AS m +SET + total_stake = m.total_stake, + packets_received = m.packets_received + (SELECT packets_received_sum FROM tmp_mix WHERE mix_id = m.mix_id AND new_date = m.date_utc), + packets_sent = m.packets_sent + (SELECT packets_sent_sum FROM tmp_mix WHERE mix_id = m.mix_id AND new_date = m.date_utc), + packets_dropped = m.packets_dropped + (SELECT packets_dropped_sum FROM tmp_mix WHERE mix_id = m.mix_id AND new_date = m.date_utc) +WHERE EXISTS ( + SELECT 1 FROM tmp_mix + WHERE mix_id = m.mix_id + AND new_date = m.date_utc +); + +DELETE FROM mixnode_daily_stats + WHERE date_utc LIKE '%June%'; + +INSERT INTO mixnode_daily_stats + (mix_id, date_utc, total_stake, packets_received, packets_sent, packets_dropped) +SELECT + mix_id, + new_date, + total_stake_sum, + packets_received_sum, + packets_sent_sum, + packets_dropped_sum +FROM tmp_mix AS t +-- only those whose new_date did _not_ already exist +WHERE NOT EXISTS ( + SELECT 1 FROM mixnode_daily_stats AS m + WHERE m.mix_id = t.mix_id + AND m.date_utc = t.new_date +); + +DROP TABLE tmp_mix; + + +-- ---------------------------------------- +-- nym_node_daily_mixing_stats +-- ---------------------------------------- + +CREATE TEMP TABLE tmp_nym_node_stats AS +SELECT + node_id, + REPLACE(date_utc,'June','06') AS new_date, + SUM(total_stake) AS total_stake_sum, + SUM(packets_received) AS packets_received_sum, + SUM(packets_sent) AS packets_sent_sum, + SUM(packets_dropped) AS packets_dropped_sum +FROM nym_node_daily_mixing_stats +WHERE date_utc LIKE '%June%' +GROUP BY node_id, new_date; + +UPDATE nym_node_daily_mixing_stats AS m +SET + total_stake = m.total_stake, + packets_received = m.packets_received + (SELECT packets_received_sum FROM tmp_nym_node_stats WHERE node_id = m.node_id AND new_date = m.date_utc), + packets_sent = m.packets_sent + (SELECT packets_sent_sum FROM tmp_nym_node_stats WHERE node_id = m.node_id AND new_date = m.date_utc), + packets_dropped = m.packets_dropped + (SELECT packets_dropped_sum FROM tmp_nym_node_stats WHERE node_id = m.node_id AND new_date = m.date_utc) +WHERE EXISTS ( + SELECT 1 FROM tmp_nym_node_stats + WHERE node_id = m.node_id + AND new_date = m.date_utc +); + +DELETE FROM nym_node_daily_mixing_stats + WHERE date_utc LIKE '%June%'; + +INSERT INTO nym_node_daily_mixing_stats + (node_id, date_utc, total_stake, packets_received, packets_sent, packets_dropped) +SELECT + node_id, + new_date, + total_stake_sum, + packets_received_sum, + packets_sent_sum, + packets_dropped_sum +FROM tmp_nym_node_stats AS t +WHERE NOT EXISTS ( + SELECT 1 FROM nym_node_daily_mixing_stats AS m + WHERE m.node_id = t.node_id + AND m.date_utc = t.new_date +); + +DROP TABLE tmp_nym_node_stats; + diff --git a/nym-node-status-api/nym-node-status-api/src/db/models.rs b/nym-node-status-api/nym-node-status-api/src/db/models.rs index 9bb9d868d6..1d4c0f1e11 100644 --- a/nym-node-status-api/nym-node-status-api/src/db/models.rs +++ b/nym-node-status-api/nym-node-status-api/src/db/models.rs @@ -1,5 +1,3 @@ -use std::str::FromStr; - use crate::{ http::{self, models::SummaryHistory}, utils::{decimal_to_i64, unix_timestamp_to_utc_rfc3339, NumericalCheckedCast}, @@ -14,6 +12,7 @@ use nym_validator_client::{ }; use serde::{Deserialize, Serialize}; use sqlx::FromRow; +use std::str::FromStr; use strum_macros::{EnumString, FromRepr}; use time::{Date, OffsetDateTime}; use utoipa::ToSchema; diff --git a/nym-node-status-api/nym-node-status-api/src/db/queries/gateways.rs b/nym-node-status-api/nym-node-status-api/src/db/queries/gateways.rs index b7c330da53..adb4241835 100644 --- a/nym-node-status-api/nym-node-status-api/src/db/queries/gateways.rs +++ b/nym-node-status-api/nym-node-status-api/src/db/queries/gateways.rs @@ -107,10 +107,7 @@ pub(crate) async fn get_all_gateways(pool: &DbPool) -> anyhow::Result>>() - .map_err(|e| { - error!("Conversion from DTO failed: {e}. Invalidly stored data?"); - e - })?; + .inspect_err(|e| error!("Conversion from DTO failed: {e}. Invalidly stored data?"))?; tracing::trace!("Fetched {} gateways from DB", items.len()); Ok(items) } diff --git a/nym-node-status-api/nym-node-status-api/src/db/queries/nym_nodes.rs b/nym-node-status-api/nym-node-status-api/src/db/queries/nym_nodes.rs index 59a7984203..5595b10fcc 100644 --- a/nym-node-status-api/nym-node-status-api/src/db/queries/nym_nodes.rs +++ b/nym-node-status-api/nym-node-status-api/src/db/queries/nym_nodes.rs @@ -36,6 +36,8 @@ pub(crate) async fn get_all_nym_nodes(pool: &DbPool) -> anyhow::Result Router { + Router::new() + .route( + "/country/:two_letter_country_code", + axum::routing::get(get_gateways_by_country), + ) + .route("/countries", axum::routing::get(get_gateway_countries)) +} + +#[allow(dead_code)] // clippy doesn't detect usage in utoipa macros +#[derive(Deserialize, IntoParams)] +#[into_params(parameter_in = Path)] +pub(crate) struct TwoLetterCountryCodeParam { + #[param(min_length = 2, max_length = 2)] + #[param(value_type = String)] + #[serde(rename = "two_letter_country_code")] + pub(crate) country: celes::Country, +} + +#[utoipa::path( + tag = "dVPN Directory Cache", + get, + params( + TwoLetterCountryCodeParam + ), + path = "/country/{two_letter_country_code}", + summary = "Gets available gateways from the Nym network directory by country", + context_path = "/dvpn/v1/directory/gateways", + operation_id = "getGatewaysByCountry", + responses( + (status = 200, body = Vec) + ) +)] +#[instrument(level = tracing::Level::INFO, skip(state), fields(two_letter_country_code = country.alpha2))] +pub async fn get_gateways_by_country( + Path(TwoLetterCountryCodeParam { country }): Path, + state: State, +) -> HttpResult>> { + Ok(Json( + state + .cache() + .get_dvpn_gateway_list(state.db_pool(), &MIN_SUPPORTED_VERSION) + .await + .into_iter() + .filter(|gw| gw.location.two_letter_iso_country_code.to_uppercase() == country.alpha2) + .collect(), + )) +} + +#[utoipa::path( + tag = "dVPN Directory Cache", + get, + path = "/countries", + summary = "Gets available exit gateway countries as two-letter ISO country codes from the Nym network directory", + context_path = "/dvpn/v1/directory/gateways", + operation_id = "getGatewayCountries", + responses( + (status = 200, body = Vec) + ) +)] +#[instrument(level = tracing::Level::INFO, skip(state))] +pub async fn get_gateway_countries(state: State) -> HttpResult>> { + Ok(Json( + state + .cache() + .get_dvpn_gateway_list(state.db_pool(), &MIN_SUPPORTED_VERSION) + .await + .into_iter() + .map(|gw| gw.location.two_letter_iso_country_code.to_string()) + // dedup relies on iterator being sorted by country, but we already do that + .dedup() + .collect(), + )) +} diff --git a/nym-node-status-api/nym-node-status-api/src/http/api/dvpn/entry.rs b/nym-node-status-api/nym-node-status-api/src/http/api/dvpn/entry.rs new file mode 100644 index 0000000000..0de1487f6e --- /dev/null +++ b/nym-node-status-api/nym-node-status-api/src/http/api/dvpn/entry.rs @@ -0,0 +1,101 @@ +use crate::http::{ + api::dvpn::{country::TwoLetterCountryCodeParam, MIN_SUPPORTED_VERSION}, + models::DVpnGateway, +}; +use crate::http::{error::HttpResult, state::AppState}; +use axum::{ + extract::{Path, State}, + Json, Router, +}; +use itertools::Itertools; +use tracing::instrument; + +pub(crate) fn routes() -> Router { + Router::new() + .route("/entry", axum::routing::get(get_entry_gateways)) + .route( + "/entry/countries", + axum::routing::get(get_entry_gateway_countries), + ) + .route( + "/entry/country/:two_letter_country_code", + axum::routing::get(get_entry_gateways_by_country), + ) +} + +#[utoipa::path( + tag = "dVPN Directory Cache", + get, + path = "/entry", + summary = "Gets available entry gateways from the Nym network directory", + context_path = "/dvpn/v1/directory/gateways", + operation_id = "getEntryGateways", + responses( + (status = 200, body = Vec) + ) +)] +#[instrument(level = tracing::Level::INFO, skip(state))] +pub async fn get_entry_gateways(state: State) -> HttpResult>> { + Ok(Json( + state + .cache() + .get_entry_dvpn_gateways(state.db_pool(), &MIN_SUPPORTED_VERSION) + .await, + )) +} + +#[utoipa::path( + tag = "dVPN Directory Cache", + get, + path = "/entry/countries", + summary = "Gets available entry gateway countries as two-letter ISO country codes from the Nym network directory", + context_path = "/dvpn/v1/directory/gateways", + operation_id = "getEntryGatewayCountries", + responses( + (status = 200, body = Vec) + ) +)] +#[instrument(level = tracing::Level::INFO, skip(state))] +pub async fn get_entry_gateway_countries(state: State) -> HttpResult>> { + Ok(Json( + state + .cache() + .get_entry_dvpn_gateways(state.db_pool(), &MIN_SUPPORTED_VERSION) + .await + .into_iter() + .map(|gw| gw.location.two_letter_iso_country_code.to_string()) + // dedup relies on iterator being sorted by country, but we already do that + .dedup() + .collect(), + )) +} + +#[utoipa::path( + tag = "dVPN Directory Cache", + get, + params( + TwoLetterCountryCodeParam + ), + path = "/entry/country/{two_letter_country_code}", + summary = "Gets available entry gateways from the Nym network directory by country", + context_path = "/dvpn/v1/directory/gateways", + operation_id = "getEntryGatewaysByCountry", + responses( + (status = 200, body = Vec) + ) +)] +#[instrument(level = tracing::Level::INFO, skip(state), fields(two_letter_country_code = country.alpha2))] +pub async fn get_entry_gateways_by_country( + Path(TwoLetterCountryCodeParam { country }): Path, + state: State, +) -> HttpResult>> { + Ok(Json( + state + .cache() + .get_entry_dvpn_gateways(state.db_pool(), &MIN_SUPPORTED_VERSION) + .await + .into_iter() + .filter(|gw| gw.location.two_letter_iso_country_code.to_uppercase() == country.alpha2) + .collect(), + )) +} diff --git a/nym-node-status-api/nym-node-status-api/src/http/api/dvpn/exit.rs b/nym-node-status-api/nym-node-status-api/src/http/api/dvpn/exit.rs new file mode 100644 index 0000000000..a512fe8ff4 --- /dev/null +++ b/nym-node-status-api/nym-node-status-api/src/http/api/dvpn/exit.rs @@ -0,0 +1,101 @@ +use crate::http::{ + api::dvpn::{country::TwoLetterCountryCodeParam, MIN_SUPPORTED_VERSION}, + models::DVpnGateway, +}; +use crate::http::{error::HttpResult, state::AppState}; +use axum::{ + extract::{Path, State}, + Json, Router, +}; +use itertools::Itertools; +use tracing::instrument; + +pub(crate) fn routes() -> Router { + Router::new() + .route("/exit", axum::routing::get(get_exit_gateways)) + .route( + "/exit/countries", + axum::routing::get(get_entry_gateway_countries), + ) + .route( + "/exit/country/:two_letter_country_code", + axum::routing::get(get_exit_gateways_by_country), + ) +} + +#[utoipa::path( + tag = "dVPN Directory Cache", + get, + path = "/exit", + summary = "Gets available exit gateways from the Nym network directory", + context_path = "/dvpn/v1/directory/gateways", + operation_id = "getExitGateways", + responses( + (status = 200, body = Vec) + ) +)] +#[instrument(level = tracing::Level::INFO, skip(state))] +pub async fn get_exit_gateways(state: State) -> HttpResult>> { + Ok(Json( + state + .cache() + .get_exit_dvpn_gateways(state.db_pool(), &MIN_SUPPORTED_VERSION) + .await, + )) +} + +#[utoipa::path( + tag = "dVPN Directory Cache", + get, + path = "/exit/countries", + summary = "Gets available exit gateway countries as two-letter ISO country codes from the Nym network directory", + context_path = "/dvpn/v1/directory/gateways", + operation_id = "getExitGatewayCountries", + responses( + (status = 200, body = Vec) + ) +)] +#[instrument(level = tracing::Level::INFO, skip(state))] +pub async fn get_entry_gateway_countries(state: State) -> HttpResult>> { + Ok(Json( + state + .cache() + .get_exit_dvpn_gateways(state.db_pool(), &MIN_SUPPORTED_VERSION) + .await + .into_iter() + .map(|gw| gw.location.two_letter_iso_country_code.to_string()) + // dedup relies on iterator being sorted by country, but we already do that + .dedup() + .collect(), + )) +} + +#[utoipa::path( + tag = "dVPN Directory Cache", + get, + params( + TwoLetterCountryCodeParam + ), + path = "/exit/country/{two_letter_country_code}", + summary = "Gets available exit gateways from the Nym network directory by country", + context_path = "/dvpn/v1/directory/gateways", + operation_id = "getExitGatewaysByCountry", + responses( + (status = 200, body = Vec) + ) +)] +#[instrument(level = tracing::Level::INFO, skip(state), fields(two_letter_country_code = country.alpha2))] +pub async fn get_exit_gateways_by_country( + Path(TwoLetterCountryCodeParam { country }): Path, + state: State, +) -> HttpResult>> { + Ok(Json( + state + .cache() + .get_exit_dvpn_gateways(state.db_pool(), &MIN_SUPPORTED_VERSION) + .await + .into_iter() + .filter(|gw| gw.location.two_letter_iso_country_code.to_uppercase() == country.alpha2) + .collect(), + )) +} diff --git a/nym-node-status-api/nym-node-status-api/src/http/api/dvpn/mod.rs b/nym-node-status-api/nym-node-status-api/src/http/api/dvpn/mod.rs new file mode 100644 index 0000000000..1d8cd93694 --- /dev/null +++ b/nym-node-status-api/nym-node-status-api/src/http/api/dvpn/mod.rs @@ -0,0 +1,67 @@ +use crate::http::state::AppState; +use axum::Router; +use axum::{ + extract::{Query, State}, + Json, +}; +use semver::Version; +use serde::Deserialize; +use std::sync::LazyLock; +use tracing::instrument; +use utoipa::IntoParams; + +use crate::http::error::{HttpError, HttpResult}; +use crate::http::models::DVpnGateway; + +pub mod country; +pub mod entry; +pub mod exit; + +static MIN_SUPPORTED_VERSION: LazyLock = LazyLock::new(|| Version::new(1, 6, 2)); + +pub(crate) fn routes() -> Router { + Router::new() + .route("/", axum::routing::get(dvpn_gateways)) + .merge(country::routes()) + .merge(entry::routes()) + .merge(exit::routes()) +} + +#[derive(Deserialize, IntoParams)] +#[into_params(parameter_in = Query)] +pub(crate) struct MinNodeVersionQuery { + min_node_version: Option, +} + +#[utoipa::path( + tag = "dVPN Directory Cache", + get, + params( + MinNodeVersionQuery + ), + path = "", + summary = "Gets available entry and exit gateways from the Nym network directory", + context_path = "/dvpn/v1/directory/gateways", + operation_id = "getGateways", + responses( + (status = 200, body = Vec) + ) +)] +#[instrument(level = tracing::Level::INFO, skip(state))] +pub async fn dvpn_gateways( + Query(MinNodeVersionQuery { min_node_version }): Query, + state: State, +) -> HttpResult>> { + let min_node_version = match min_node_version { + Some(min_version) => semver::Version::parse(&min_version) + .map_err(|_| HttpError::invalid_input("Min version must be valid semver"))?, + None => MIN_SUPPORTED_VERSION.clone(), + }; + + Ok(Json( + state + .cache() + .get_dvpn_gateway_list(state.db_pool(), &min_node_version) + .await, + )) +} diff --git a/nym-node-status-api/nym-node-status-api/src/http/api/mod.rs b/nym-node-status-api/nym-node-status-api/src/http/api/mod.rs index f71f48fe02..5bc06be2b2 100644 --- a/nym-node-status-api/nym-node-status-api/src/http/api/mod.rs +++ b/nym-node-status-api/nym-node-status-api/src/http/api/mod.rs @@ -8,6 +8,7 @@ use utoipa_swagger_ui::SwaggerUi; use crate::http::{server::HttpServer, state::AppState}; +pub(crate) mod dvpn; pub(crate) mod gateways; pub(crate) mod metrics; pub(crate) mod mixnodes; @@ -44,6 +45,10 @@ impl RouterBuilder { "/explorer/v3", Router::new().nest("/nym-nodes", nym_nodes::routes()), ) + .nest( + "/dvpn/v1", + Router::new().nest("/directory/gateways", dvpn::routes()), + ) .nest( "/internal", Router::new().nest("/testruns", testruns::routes()), diff --git a/nym-node-status-api/nym-node-status-api/src/http/error.rs b/nym-node-status-api/nym-node-status-api/src/http/error.rs index e36dc19125..ce0e0f4060 100644 --- a/nym-node-status-api/nym-node-status-api/src/http/error.rs +++ b/nym-node-status-api/nym-node-status-api/src/http/error.rs @@ -11,14 +11,14 @@ pub(crate) struct HttpError { impl HttpError { pub(crate) fn invalid_input(msg: impl Display) -> Self { Self { - message: serde_json::json!({"message": msg.to_string()}).to_string(), + message: msg.to_string(), status: axum::http::StatusCode::BAD_REQUEST, } } pub(crate) fn unauthorized() -> Self { Self { - message: serde_json::json!({"message": "Make sure your public key is registered with NS API"}).to_string(), + message: String::from("Make sure your public key is registered with NS API"), status: axum::http::StatusCode::UNAUTHORIZED, } } @@ -30,22 +30,21 @@ impl HttpError { pub(crate) fn internal() -> Self { Self { - message: serde_json::json!({"message": "Internal server error"}).to_string(), + message: String::from("Internal server error"), status: axum::http::StatusCode::INTERNAL_SERVER_ERROR, } } pub(crate) fn no_testruns_available() -> Self { Self { - message: serde_json::json!({"message": "No testruns available"}).to_string(), + message: String::from("No testruns available"), status: axum::http::StatusCode::SERVICE_UNAVAILABLE, } } pub(crate) fn no_delegations_for_node(node_id: NodeId) -> Self { Self { - message: serde_json::json!({"message": format!("No delegation data for node_id={}", node_id)}) - .to_string(), + message: format!("No delegation data for node_id={}", node_id), status: axum::http::StatusCode::NOT_FOUND, } } diff --git a/nym-node-status-api/nym-node-status-api/src/http/models.rs b/nym-node-status-api/nym-node-status-api/src/http/models.rs index 5633c6e1a6..2ddd8e19df 100644 --- a/nym-node-status-api/nym-node-status-api/src/http/models.rs +++ b/nym-node-status-api/nym-node-status-api/src/http/models.rs @@ -1,8 +1,19 @@ +use std::net::IpAddr; + +use crate::monitor::ExplorerPrettyBond; use cosmwasm_std::{Addr, Coin, Decimal}; use nym_mixnet_contract_common::CoinSchema; use nym_node_requests::api::v1::node::models::NodeDescription; -use nym_validator_client::client::NodeId; +use nym_validator_client::{ + client::NodeId, + models::{ + AuthenticatorDetails, BinaryBuildInformationOwned, IpPacketRouterDetails, NymNodeData, + }, + nym_api::SkimmedNode, + nym_nodes::{BasicEntryInformation, NodeRole}, +}; use serde::{Deserialize, Serialize}; +use tracing::{error, instrument}; use utoipa::ToSchema; pub(crate) use nym_node_status_client::models::TestrunAssignment; @@ -23,6 +34,220 @@ pub struct Gateway { pub config_score: u32, } +#[derive(Debug, Clone, Deserialize, Serialize, ToSchema)] +pub struct BuildInformation { + pub build_version: String, + pub commit_branch: String, + pub commit_sha: String, +} + +#[derive(Debug, Clone, Deserialize, Serialize, ToSchema)] +pub struct Location { + pub two_letter_iso_country_code: String, + pub latitude: f64, + pub longitude: f64, +} + +#[derive(Debug, Clone, Deserialize, Serialize, ToSchema)] +pub struct DVpnGateway { + pub identity_key: String, + pub name: String, + pub ip_packet_router: Option, + pub authenticator: Option, + pub location: Location, + pub last_probe: Option, + #[schema(value_type = Vec)] + pub ip_addresses: Vec, + pub mix_port: u16, + pub role: NodeRole, + pub entry: Option, + // The performance data here originates from the nym-api, and is effectively mixnet performance + // at the time of writing this + pub performance: String, + pub build_information: BinaryBuildInformationOwned, +} + +impl DVpnGateway { + pub fn can_route_entry(&self) -> bool { + self.last_probe + .as_ref() + .map(|probe| match &probe.outcome.as_entry { + directory_gw_probe_outcome::Entry::Tested(entry_test_result) => { + entry_test_result.can_route + } + directory_gw_probe_outcome::Entry::NotTested + | directory_gw_probe_outcome::Entry::EntryFailure => false, + }) + .unwrap_or(false) + } + + pub fn can_route_exit(&self) -> bool { + self.last_probe + .as_ref() + .map(|probe| { + probe + .outcome + .as_exit + .as_ref() + .map(|outcome| { + outcome.can_route_ip_external_v4 && outcome.can_route_ip_external_v6 + }) + .unwrap_or(false) + }) + .unwrap_or(false) + } +} + +/// based on +/// https://github.com/nymtech/nym-vpn-client/blob/nym-vpn-core-v1.10.0/nym-vpn-core/crates/nym-gateway-probe/src/types.rs +/// TODO: long term types should be moved into this repo because nym-vpn-client +/// could pull it as a dependency and we'd have a single source of truth +#[derive(Debug, Clone, Deserialize, Serialize, ToSchema)] +pub struct LastProbeResult { + node: String, + used_entry: String, + outcome: ProbeOutcome, +} + +#[derive(Debug, Clone, Deserialize, Serialize, ToSchema)] +pub struct DirectoryGwProbe { + last_updated_utc: String, + outcome: ProbeOutcome, +} + +#[derive(Debug, Clone, Deserialize, Serialize, ToSchema)] +pub struct ProbeOutcome { + as_entry: directory_gw_probe_outcome::Entry, + as_exit: Option, + wg: Option, +} + +pub mod directory_gw_probe_outcome { + use super::*; + + #[derive(Debug, Clone, Serialize, Deserialize, ToSchema)] + #[serde(untagged)] + #[allow(clippy::enum_variant_names)] + pub enum Entry { + Tested(EntryTestResult), + NotTested, + EntryFailure, + } + + #[derive(Debug, Clone, Serialize, Deserialize, ToSchema)] + pub struct EntryTestResult { + pub can_connect: bool, + pub can_route: bool, + } + + #[derive(Debug, Clone, Deserialize, Serialize, ToSchema)] + pub struct Exit { + pub can_connect: bool, + pub can_route_ip_v4: bool, + pub can_route_ip_external_v4: bool, + pub can_route_ip_v6: bool, + pub can_route_ip_external_v6: bool, + } +} + +pub mod wg_outcome_versions { + use super::*; + + #[derive(Debug, Clone, Deserialize, Serialize, ToSchema)] + pub struct ProbeOutcomeV1 { + pub can_register: bool, + + pub can_handshake_v4: bool, + pub can_resolve_dns_v4: bool, + pub ping_hosts_performance_v4: f32, + pub ping_ips_performance_v4: f32, + + pub can_handshake_v6: bool, + pub can_resolve_dns_v6: bool, + pub ping_hosts_performance_v6: f32, + pub ping_ips_performance_v6: f32, + + pub download_duration_sec_v4: u64, + pub downloaded_file_v4: String, + pub download_error_v4: String, + + pub download_duration_sec_v6: u64, + pub downloaded_file_v6: String, + pub download_error_v6: String, + } +} + +impl DVpnGateway { + #[instrument(level = tracing::Level::INFO, name = "dvpn_gw_new", skip_all, fields(gateway_key = gateway.gateway_identity_key, node_id = skimmed_node.node_id))] + pub(crate) fn new(gateway: Gateway, skimmed_node: &SkimmedNode) -> anyhow::Result { + let location = gateway + .explorer_pretty_bond + .ok_or_else(|| anyhow::anyhow!("Missing explorer_pretty_bond")) + .and_then(|value| { + serde_json::from_value::(value).map_err(From::from) + }) + .map(|bond| bond.location)?; + + let self_described = gateway + .self_described + .ok_or_else(|| anyhow::anyhow!("Missing self_described")) + .and_then(|value| serde_json::from_value::(value).map_err(From::from))?; + + let last_probe_result = match gateway.last_probe_result { + Some(value) => { + let parsed = + serde_json::from_value::(value).inspect_err(|err| { + error!("Failed to deserialize probe result: {err}"); + })?; + Some(parsed) + } + None => None, + }; + + Ok(Self { + identity_key: gateway.gateway_identity_key, + name: gateway.description.moniker, + ip_packet_router: self_described.ip_packet_router, + authenticator: self_described.authenticator, + location: Location { + latitude: location.location.latitude, + longitude: location.location.longitude, + two_letter_iso_country_code: location.two_letter_iso_country_code, + }, + last_probe: last_probe_result.map(|res| DirectoryGwProbe { + last_updated_utc: gateway.last_testrun_utc.unwrap_or_default(), + outcome: res.outcome, + }), + ip_addresses: skimmed_node.ip_addresses.clone(), + mix_port: skimmed_node.mix_port, + role: skimmed_node.role.clone(), + entry: skimmed_node.entry.clone(), + performance: to_percent(gateway.performance), + build_information: self_described.build_information, + }) + } +} + +fn to_percent(performance: u8) -> String { + let fraction = performance as f32 / 100.0; + format!("{:.2}", fraction) +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn to_percent_should_work() { + let starting = [0u8, 33, 50, 99, 100]; + let expected = ["0.00", "0.33", "0.50", "0.99", "1.00"]; + + for (starting, expected) in starting.into_iter().zip(expected) { + assert_eq!(expected, to_percent(starting)); + } + } +} + #[derive(Debug, Clone, Deserialize, Serialize, ToSchema)] pub struct GatewaySkinny { pub gateway_identity_key: String, diff --git a/nym-node-status-api/nym-node-status-api/src/http/state.rs b/nym-node-status-api/nym-node-status-api/src/http/state.rs index c2ebfafd15..0a5ef4fca9 100644 --- a/nym-node-status-api/nym-node-status-api/src/http/state.rs +++ b/nym-node-status-api/nym-node-status-api/src/http/state.rs @@ -1,16 +1,20 @@ use cosmwasm_std::Decimal; +use itertools::Itertools; use moka::{future::Cache, Entry}; use nym_contracts_common::NaiveFloat; use nym_crypto::asymmetric::ed25519::PublicKey; use nym_mixnet_contract_common::NodeId; use nym_validator_client::nym_api::SkimmedNode; +use semver::Version; use std::{collections::HashMap, sync::Arc, time::Duration}; use tokio::sync::RwLock; -use tracing::instrument; +use tracing::{error, instrument, warn}; use crate::{ db::{queries, DbPool}, - http::models::{DailyStats, ExtendedNymNode, Gateway, Mixnode, NodeGeoData, SummaryHistory}, + http::models::{ + DVpnGateway, DailyStats, ExtendedNymNode, Gateway, Mixnode, NodeGeoData, SummaryHistory, + }, monitor::{DelegationsCache, NodeGeoCache}, }; @@ -77,6 +81,7 @@ impl AppState { } static GATEWAYS_LIST_KEY: &str = "gateways"; +static DVPN_GATEWAYS_LIST_KEY: &str = "dvpn_gateways"; static MIXNODES_LIST_KEY: &str = "mixnodes"; static NYM_NODES_LIST_KEY: &str = "nym_nodes"; static MIXSTATS_LIST_KEY: &str = "mixstats"; @@ -88,6 +93,7 @@ const MIXNODE_STATS_HISTORY_DAYS: usize = 30; #[derive(Debug, Clone)] pub(crate) struct HttpCache { gateways: Cache>>>, + dvpn_gateways: Cache>>>, mixnodes: Cache>>>, nym_nodes: Cache>>>, mixstats: Cache>>>, @@ -102,6 +108,10 @@ impl HttpCache { .max_capacity(2) .time_to_live(Duration::from_secs(ttl_seconds)) .build(), + dvpn_gateways: Cache::builder() + .max_capacity(6) + .time_to_live(Duration::from_secs(ttl_seconds)) + .build(), mixnodes: Cache::builder() .max_capacity(2) .time_to_live(Duration::from_secs(ttl_seconds)) @@ -158,10 +168,11 @@ impl HttpCache { let gateways = crate::db::queries::get_all_gateways(db) .await .unwrap_or_default(); - self.upsert_gateway_list(gateways.clone()).await; if gateways.is_empty() { - tracing::warn!("Database contains 0 gateways"); + tracing::warn!("Database: gateway list is empty"); + } else { + self.upsert_gateway_list(gateways.clone()).await; } gateways @@ -169,6 +180,160 @@ impl HttpCache { } } + pub async fn upsert_dvpn_gateway_list( + &self, + new_gateway_list: Vec, + ) -> Entry>>> { + self.dvpn_gateways + .entry_by_ref(DVPN_GATEWAYS_LIST_KEY) + .and_upsert_with(|maybe_entry| async { + if let Some(entry) = maybe_entry { + let v = entry.into_value(); + let mut guard = v.write().await; + *guard = new_gateway_list; + v.clone() + } else { + Arc::new(RwLock::new(new_gateway_list)) + } + }) + .await + } + + pub async fn get_dvpn_gateway_list( + &self, + db: &DbPool, + min_node_version: &Version, + ) -> Vec { + match self.dvpn_gateways.get(DVPN_GATEWAYS_LIST_KEY).await { + Some(guard) => { + tracing::trace!("Fetching from cache..."); + let read_lock = guard.read().await; + read_lock.clone() + } + None => { + tracing::trace!("No gateways (dVPN) in cache, refreshing from DB..."); + + let gateways = self.get_gateway_list(db).await; + + let started_with = gateways.len(); + let Ok(skimmed_nodes) = crate::db::queries::get_described_bonded_nym_nodes(db) + .await + .map(|records| { + records + .into_iter() + .filter_map(|dto| { + SkimmedNode::try_from(dto) + .inspect_err(|err| { + error!("Failed to read SkimmedNode from DB: {err}") + }) + .ok() + }) + .map(|skimmed_node| { + ( + skimmed_node.ed25519_identity_pubkey.to_base58_string(), + skimmed_node, + ) + }) + .collect::>() + }) + .inspect_err(|err| { + // this would fail only in case of internal error: log and return gracefully + error!("Failed to get nym_nodes from DB: {err}"); + }) + else { + return Vec::new(); + }; + + let res_gws = gateways + .into_iter() + .filter(|gw| gw.bonded) + .filter_map(|gw| match skimmed_nodes.get(&gw.gateway_identity_key) { + Some(skimmed_node) => Some((gw, skimmed_node)), + None => { + warn!( + "No SkimmedNode data found for GW, identity_key={}", + gw.gateway_identity_key + ); + None + } + }) + .filter_map( + |(gw, skimmed_node)| match DVpnGateway::new(gw, skimmed_node) { + Ok(gw) => Some(gw), + Err(err) => { + error!( + "Failed to convert GW node_id={} to dVPN form: {}", + skimmed_node.node_id, err + ); + None + } + }, + ) + .filter(|gw| { + let gw_version = &gw.build_information.build_version; + if let Ok(gw_version) = Version::parse(gw_version) { + &gw_version >= min_node_version + } else { + warn!("Failed to parse GW version {}", gw_version); + false + } + }) + .filter(|gw| { + // gateways must have a country + if gw.location.two_letter_iso_country_code.len() == 2 { + true + } else { + warn!( + "Invalid country code: {}", + gw.location.two_letter_iso_country_code + ); + false + } + }) + // sort by country, then by identity key + .sorted_by_key(|item| { + ( + item.location.two_letter_iso_country_code.clone(), + item.identity_key.clone(), + ) + }) + .collect::>(); + + if res_gws.is_empty() && started_with > 0 { + tracing::warn!("Started with {}, got 0 gateways", started_with); + } else { + self.upsert_dvpn_gateway_list(res_gws.clone()).await; + } + + res_gws + } + } + } + + pub async fn get_entry_dvpn_gateways( + &self, + db: &DbPool, + min_node_version: &Version, + ) -> Vec { + self.get_dvpn_gateway_list(db, min_node_version) + .await + .into_iter() + .filter(DVpnGateway::can_route_entry) + .collect() + } + + pub async fn get_exit_dvpn_gateways( + &self, + db: &DbPool, + min_node_version: &Version, + ) -> Vec { + self.get_dvpn_gateway_list(db, min_node_version) + .await + .into_iter() + .filter(DVpnGateway::can_route_exit) + .collect() + } + pub async fn upsert_mixnode_list( &self, new_mixnode_list: Vec, @@ -201,10 +366,11 @@ impl HttpCache { let mixnodes = crate::db::queries::get_all_mixnodes(db) .await .unwrap_or_default(); - self.upsert_mixnode_list(mixnodes.clone()).await; if mixnodes.is_empty() { tracing::warn!("Database contains 0 mixnodes"); + } else { + self.upsert_mixnode_list(mixnodes.clone()).await; } mixnodes @@ -245,14 +411,13 @@ impl HttpCache { None => { tracing::trace!("No nym nodes in cache, refreshing cache from DB..."); - let nym_nodes = aggregate_node_info_from_db(db, node_geocache) - .await - .inspect(|nym_nodes| { - if nym_nodes.is_empty() { - tracing::warn!("Database contains 0 nym nodes"); - } - })?; - self.upsert_nym_node_list(nym_nodes.clone()).await; + let nym_nodes = aggregate_node_info_from_db(db, node_geocache).await?; + + if nym_nodes.is_empty() { + tracing::warn!("Database contains 0 nym nodes"); + } else { + self.upsert_nym_node_list(nym_nodes.clone()).await; + } Ok(nym_nodes) } diff --git a/nym-node-status-api/nym-node-status-api/src/mixnet_scraper/helpers.rs b/nym-node-status-api/nym-node-status-api/src/mixnet_scraper/helpers.rs index 12821f15f2..986f1472c5 100644 --- a/nym-node-status-api/nym-node-status-api/src/mixnet_scraper/helpers.rs +++ b/nym-node-status-api/nym-node-status-api/src/mixnet_scraper/helpers.rs @@ -206,7 +206,7 @@ pub async fn update_daily_stats( let date_utc = format!( "{:04}-{:02}-{:02}", timestamp.year(), - timestamp.month(), + timestamp.month() as u8, timestamp.day() ); diff --git a/nym-node-status-api/nym-node-status-api/src/monitor/geodata.rs b/nym-node-status-api/nym-node-status-api/src/monitor/geodata.rs index 9a7fb3a0d2..e9d6e554ea 100644 --- a/nym-node-status-api/nym-node-status-api/src/monitor/geodata.rs +++ b/nym-node-status-api/nym-node-status-api/src/monitor/geodata.rs @@ -63,7 +63,7 @@ impl IpInfoClient { } } -#[derive(Debug, Clone, Serialize)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub(crate) struct ExplorerPrettyBond { pub(crate) identity_key: String, pub(crate) owner: Addr, @@ -71,7 +71,7 @@ pub(crate) struct ExplorerPrettyBond { pub(crate) location: Location, } -#[derive(Debug, Clone, Default, Serialize)] +#[derive(Debug, Clone, Default, Serialize, Deserialize)] pub(crate) struct Location { pub(crate) two_letter_iso_country_code: String, #[serde(flatten)] diff --git a/nym-node-status-api/nym-node-status-api/src/monitor/mod.rs b/nym-node-status-api/nym-node-status-api/src/monitor/mod.rs index 5fdb3f2f62..7461837fe0 100644 --- a/nym-node-status-api/nym-node-status-api/src/monitor/mod.rs +++ b/nym-node-status-api/nym-node-status-api/src/monitor/mod.rs @@ -7,7 +7,6 @@ use crate::db::models::{ NYMNODES_DESCRIBED_COUNT, NYMNODE_COUNT, }; use crate::db::{queries, DbPool}; -use crate::monitor::geodata::{ExplorerPrettyBond, Location}; use crate::utils::now_utc; use crate::utils::{decimal_to_i64, LogError, NumericalCheckedCast}; use anyhow::anyhow; @@ -30,7 +29,7 @@ use std::{ use tokio::{sync::RwLock, time::Duration}; use tracing::instrument; -pub(crate) use geodata::IpInfoClient; +pub(crate) use geodata::{ExplorerPrettyBond, IpInfoClient, Location}; pub(crate) use node_delegations::DelegationsCache; mod geodata; @@ -106,11 +105,10 @@ impl Monitor { .clone() .expect("rust sdk mainnet default missing api_url"); - let nym_api = - nym_http_api_client::ClientBuilder::new_with_urls(vec![default_api_url.into()]) - .no_hickory_dns() - .with_timeout(self.nym_api_client_timeout) - .build::<&str>()?; + let nym_api = nym_http_api_client::ClientBuilder::new_with_url(default_api_url) + .no_hickory_dns() + .with_timeout(self.nym_api_client_timeout) + .build::<&str>()?; let api_client = NymApiClient::from(nym_api); @@ -134,6 +132,8 @@ impl Monitor { }) .collect::>(); + tracing::info!("🟣 🚪 gateway nodes: {}", gateways.len()); + let bonded_nym_nodes = api_client .get_all_bonded_nym_nodes() .await? @@ -150,7 +150,8 @@ impl Monitor { .await .log_error("get_all_basic_nodes")?; - tracing::info!("🟣 get_all_basic_nodes: {}", nym_nodes.len()); + let nym_node_count = nym_nodes.len(); + tracing::info!("🟣 get_all_basic_nodes: {}", nym_node_count); let nym_node_records = self.prepare_nym_node_data(nym_nodes.clone(), &bonded_nym_nodes, &described_nodes); @@ -251,7 +252,7 @@ impl Monitor { // let nodes_summary = vec![ - (NYMNODE_COUNT, nym_nodes.len()), + (NYMNODE_COUNT, nym_node_count), (ASSIGNED_MIXING_COUNT, assigned_mixing_count), (MIXNODES_LEGACY_COUNT, count_legacy_mixnodes), (NYMNODES_DESCRIBED_COUNT, described_nodes.len()), @@ -267,7 +268,7 @@ impl Monitor { let last_updated = now_utc(); let last_updated_utc = last_updated.unix_timestamp().to_string(); let network_summary = NetworkSummary { - total_nodes: nym_nodes.len().cast_checked()?, + total_nodes: nym_node_count.cast_checked()?, mixnodes: mixnode::MixnodeSummary { bonded: mixnode::MixingNodesSummary { count: assigned_mixing_count.cast_checked()?, @@ -457,11 +458,7 @@ impl Monitor { async fn check_ipinfo_bandwidth(&self) { match self.ipinfo.check_remaining_bandwidth().await { Ok(bandwidth) => { - tracing::info!( - "ipinfo monthly bandwidth: {}/{} spent", - bandwidth.month, - bandwidth.limit - ); + tracing::info!("ipinfo monthly bandwidth: {} spent", bandwidth.month); } Err(err) => { tracing::debug!("Couldn't check ipinfo bandwidth: {}", err); diff --git a/nym-node-status-api/nym-node-status-api/src/node_scraper/mod.rs b/nym-node-status-api/nym-node-status-api/src/node_scraper/mod.rs index c35b95b3b8..aeab6cb4b9 100644 --- a/nym-node-status-api/nym-node-status-api/src/node_scraper/mod.rs +++ b/nym-node-status-api/nym-node-status-api/src/node_scraper/mod.rs @@ -57,7 +57,7 @@ async fn run( .clone() .expect("rust sdk mainnet default missing api_url"); - let nym_api = nym_http_api_client::ClientBuilder::new_with_urls(vec![default_api_url.into()]) + let nym_api = nym_http_api_client::ClientBuilder::new_with_url(default_api_url) .no_hickory_dns() .with_timeout(nym_api_client_timeout) .build::<&str>()?; diff --git a/nym-node-status-api/nym-node-status-api/src/testruns/mod.rs b/nym-node-status-api/nym-node-status-api/src/testruns/mod.rs index 13b9c50d05..e103ebaf72 100644 --- a/nym-node-status-api/nym-node-status-api/src/testruns/mod.rs +++ b/nym-node-status-api/nym-node-status-api/src/testruns/mod.rs @@ -24,7 +24,7 @@ pub(crate) async fn spawn(pool: DbPool, refresh_interval: Duration) { }); } -#[instrument(level = "debug", name = "testrun_queue", skip_all)] +#[instrument(level = "info", name = "testrun_queue", skip_all)] async fn run(pool: &DbPool) -> anyhow::Result<()> { tracing::info!("Spawning testruns..."); if pool.is_closed() {