From ea0834502590c02e37f5bb28e92ff98a17e52309 Mon Sep 17 00:00:00 2001 From: dynco-nym <173912580+dynco-nym@users.noreply.github.com> Date: Tue, 27 May 2025 16:45:41 +0200 Subject: [PATCH] /gateways works - SkimmedNode data still missing - need to move probe models to monorepo --- .../nym-node-status-agent/run.sh | 2 +- .../nym-node-status-api/src/http/api/mod.rs | 2 +- .../nym-node-status-api/src/http/models.rs | 203 ++++++++++++------ .../src/monitor/geodata.rs | 4 +- .../nym-node-status-api/src/monitor/mod.rs | 3 +- .../nym-node-status-api/src/testruns/mod.rs | 2 +- 6 files changed, 138 insertions(+), 78 deletions(-) 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..eae0926ad6 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.9.0" crate_root=$(dirname $(realpath "$0")) monorepo_root=$(realpath "${crate_root}/../..") 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 3b0c9e3510..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; @@ -15,7 +16,6 @@ pub(crate) mod nym_nodes; pub(crate) mod services; pub(crate) mod summary; pub(crate) mod testruns; -pub(crate) mod dvpn; pub(crate) struct RouterBuilder { unfinished_router: Router, 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 e086a467c3..17e0f777c8 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,12 +1,20 @@ 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_nodes::{BasicEntryInformation, NodeRole}, +}; use serde::{Deserialize, Serialize}; use utoipa::ToSchema; pub(crate) use nym_node_status_client::models::TestrunAssignment; +use crate::monitor::ExplorerPrettyBond; + #[derive(Debug, Clone, Serialize, Deserialize, ToSchema)] pub struct Gateway { pub gateway_identity_key: String, @@ -23,25 +31,6 @@ pub struct Gateway { pub config_score: u32, } -#[derive(Debug, Clone, Deserialize, Serialize, ToSchema)] -pub enum Role { - // a properly active mixnode - Mixnode { - layer: u8, - }, - - #[serde(alias = "entry", alias = "gateway")] - EntryGateway, - - #[serde(alias = "exit")] - ExitGateway, - - // equivalent of node that's in rewarded set but not in the inactive set - Standby, - - Inactive, -} - #[derive(Debug, Clone, Deserialize, Serialize, ToSchema)] pub struct BuildInformation { pub build_version: String, @@ -49,23 +38,6 @@ pub struct BuildInformation { pub commit_sha: String, } -#[derive(Debug, Clone, Deserialize, Serialize, ToSchema)] -pub struct IpPacketRouter { - pub address: String, -} - -#[derive(Debug, Clone, Deserialize, Serialize, ToSchema)] -pub struct Authenticator { - pub address: String, -} - -#[derive(Debug, Clone, Deserialize, Serialize, ToSchema)] -pub struct EntryInformation { - pub hostname: Option, - pub ws_port: u16, - pub wss_port: Option, -} - #[derive(Debug, Clone, Deserialize, Serialize, ToSchema)] pub struct Location { pub two_letter_iso_country_code: String, @@ -77,39 +49,131 @@ pub struct Location { pub struct DVpnGateway { pub identity_key: String, pub name: String, - pub ip_packet_router: Option, - pub authenticator: Option, + pub ip_packet_router: Option, + pub authenticator: Option, pub location: Location, - pub last_probe: Option, + pub last_probe: Option, pub ip_addresses: Vec, pub mix_port: u16, - pub role: Role, - pub entry: EntryInformation, + 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: u8, - pub build_information: Option, + pub build_information: BinaryBuildInformationOwned, } -impl TryFrom for DVpnGateway { - type Error = (); +#[derive(Debug, Clone, Deserialize, Serialize, ToSchema)] +pub struct LastProbeResult { + node: String, + used_entry: String, + outcome: DirectoryGwProbeOutcome, +} - fn try_from(value: Gateway) -> Result { - Self::try_from(&value) +#[derive(Debug, Clone, Deserialize, Serialize, ToSchema)] +pub struct DirectoryGwProbe { + last_updated_utc: String, + outcome: DirectoryGwProbeOutcome, +} + +#[derive(Debug, Clone, Deserialize, Serialize, ToSchema)] +pub struct DirectoryGwProbeOutcome { + as_entry: directory_gw_probe_outcome::AsEntry, + as_exit: directory_gw_probe_outcome::AsExit, + wg: directory_gw_probe_outcome::Wg, +} + +pub mod directory_gw_probe_outcome { + use super::*; + + #[derive(Debug, Clone, Deserialize, Serialize, ToSchema)] + pub struct AsEntry { + can_connect: bool, + can_route: bool, + } + + #[derive(Debug, Clone, Deserialize, Serialize, ToSchema)] + pub struct AsExit { + can_connect: bool, + can_route_ip_v4: bool, + can_route_ip_external_v4: bool, + can_route_ip_v6: bool, + can_route_ip_external_v6: bool, + } + + #[derive(Debug, Clone, Deserialize, Serialize, ToSchema)] + pub struct Wg { + wg: wg_outcome_versions::DirectoryGatewayProbeOutcomeWGv2, } } -impl TryFrom<&Gateway> for DVpnGateway -{ - type Error = (); +pub mod wg_outcome_versions { + use super::*; + + #[derive(Debug, Clone, Deserialize, Serialize, ToSchema)] + pub struct DirectoryGatewayProbeOutcomeWGv1 { + can_handshake: bool, + can_register: bool, + can_resolve_dns: bool, + ping_hosts_performance: f64, + ping_ips_performance: f64, + } + + #[derive(Debug, Clone, Deserialize, Serialize, ToSchema)] + pub struct DirectoryGatewayProbeOutcomeWGv2 { + 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 TryFrom<&Gateway> for DVpnGateway { + type Error = anyhow::Error; fn try_from(value: &Gateway) -> Result { + Self::try_from(value.to_owned()) + } +} - // TODO: try to parse out values from gateway and fail when unable to parse +impl TryFrom for DVpnGateway { + type Error = anyhow::Error; + + fn try_from(value: Gateway) -> Result { + let location = value + .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 = value + .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 = value + .last_probe_result + .and_then(|value| serde_json::from_value::(value).ok()); // TODO: polyfill `last_probe`, see below from VPN API - /** - + /* const last_testrun_utc = item.last_testrun_utc; const last_probe: DirectoryGatewayProbe | undefined = @@ -141,26 +205,23 @@ impl TryFrom<&Gateway> for DVpnGateway */ Ok(Self { - identity_key: value.gateway_identity_key.clone(), - name: value.description.moniker.clone(), - ip_packet_router: None, // value.ip_packet_router, - authenticator: None, // value.authenticator, + identity_key: value.gateway_identity_key, + name: value.description.moniker, + ip_packet_router: self_described.ip_packet_router, + authenticator: self_described.authenticator, location: Location { - latitude: 0.0f64, - longitude: 0.0f64, - two_letter_iso_country_code: "".to_string(), + latitude: location.location.latitude, + longitude: location.location.longitude, + two_letter_iso_country_code: location.two_letter_iso_country_code, }, - last_probe: value.last_probe_result.clone(), - ip_addresses: vec![], // value.ip_addresses, - mix_port: 0u16, // value.mix_port, - role: Role::EntryGateway, // value.role, - entry: EntryInformation { - ws_port: 0u16, - wss_port: None, - hostname: None, - }, - performance: value.performance, - build_information: None, // value.build_information, + last_probe: last_probe_result.map(|res| res.outcome), + // TODO + ip_addresses: vec![], // value.ip_addresses (SkimmedNode), + mix_port: 0, // value.mix_port (SkimmedNode), + role: NodeRole::EntryGateway, // value.role (SkimmedNode), + entry: None, // (SkimmedNode) + performance: value.performance, // (SkimmedNode) + build_information: self_described.build_information, }) } } 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 cc87dfdbcd..8e6ad8f198 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; 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() {