Skip to content
Closed
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
786ff31
augment self described API with NoiseInformation field
simonwicky Jan 30, 2024
0d841e5
augment Nym-API described with Noise Info
simonwicky Jan 30, 2024
5908741
adapt noise support to PR chain merge order
simonwicky Jan 30, 2024
7363cda
apply octlol unwrap or default suggestion
simonwicky Feb 6, 2024
d4a2be8
augment topology with described nodes
simonwicky Jan 30, 2024
580457a
add epoch in validator client
simonwicky Jan 30, 2024
0a826b8
add topology access to nodes
simonwicky Jan 30, 2024
8c29fba
move topology control into its own crate
simonwicky Feb 6, 2024
fbbd634
apply octlol suggestion
simonwicky Feb 6, 2024
6924f29
changes on nym-connect and wasm client
simonwicky Feb 6, 2024
a16b21c
cargo fmt
simonwicky Feb 6, 2024
54feb9e
add main noise logic
simonwicky Jan 30, 2024
e4425f9
add noise connection in nodes
simonwicky Jan 30, 2024
06f1271
enable noise support in self described API
simonwicky Jan 30, 2024
293cf2f
apply some of octlol's suggestion
simonwicky Feb 6, 2024
e2fa1ae
apply octlol's type suggestion
simonwicky Feb 6, 2024
e57fcf4
Merge branch 'develop' into simon/noise_nodes
simonwicky Feb 14, 2024
49588e0
Merge branch 'develop' into simon/noise_nodes
simonwicky Mar 4, 2024
7ec35fe
Merge commit '0e56d8c2f733f37ae5cdeace779b58083b12baeb' into simon/no…
simonwicky Mar 11, 2024
30a1f55
change mix_host in Node to a vec
simonwicky Mar 11, 2024
a0e3610
change key retrieval to use bond info
simonwicky Mar 11, 2024
2e12c20
update cargo lock
simonwicky Mar 11, 2024
3846d3c
comment change according to review
simonwicky Mar 11, 2024
6b1657a
apply jstuczyn suggestion
simonwicky Mar 11, 2024
4d273ea
change to psk structure and port checking to allow same ip
simonwicky Mar 11, 2024
011be0d
remove outdated comments
simonwicky Mar 13, 2024
5a9c391
change license
simonwicky Mar 13, 2024
4b3dcb6
Feature Noise XKpsk3 : Fix localnet (#4465)
simonwicky Mar 19, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion common/client-libs/validator-client/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use crate::{
use nym_api_requests::coconut::{
BlindSignRequestBody, BlindedSignatureResponse, VerifyCredentialBody, VerifyCredentialResponse,
};
use nym_api_requests::models::{DescribedGateway, MixNodeBondAnnotated};
use nym_api_requests::models::{DescribedGateway, DescribedNymNode, MixNodeBondAnnotated};
use nym_api_requests::models::{
GatewayCoreStatusResponse, MixnodeCoreStatusResponse, MixnodeStatusResponse,
RewardEstimationResponse, StakeSaturationResponse,
Expand Down Expand Up @@ -289,6 +289,12 @@ impl NymApiClient {
Ok(self.nym_api.get_gateways_described().await?)
}

pub async fn get_cached_described_nodes(
&self,
) -> Result<Vec<DescribedNymNode>, ValidatorClientError> {
Ok(self.nym_api.get_nym_nodes_described().await?)
}

pub async fn get_gateway_core_status_count(
&self,
identity: IdentityKeyRef<'_>,
Expand Down
18 changes: 13 additions & 5 deletions common/client-libs/validator-client/src/nym_api/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ pub use nym_api_requests::{
VerifyCredentialBody, VerifyCredentialResponse,
},
models::{
ComputeRewardEstParam, DescribedGateway, GatewayBondAnnotated, GatewayCoreStatusResponse,
GatewayStatusReportResponse, GatewayUptimeHistoryResponse, InclusionProbabilityResponse,
MixNodeBondAnnotated, MixnodeCoreStatusResponse, MixnodeStatusReportResponse,
MixnodeStatusResponse, MixnodeUptimeHistoryResponse, RewardEstimationResponse,
StakeSaturationResponse, UptimeResponse,
ComputeRewardEstParam, DescribedGateway, DescribedNymNode, GatewayBondAnnotated,
GatewayCoreStatusResponse, GatewayStatusReportResponse, GatewayUptimeHistoryResponse,
InclusionProbabilityResponse, MixNodeBondAnnotated, MixnodeCoreStatusResponse,
MixnodeStatusReportResponse, MixnodeStatusResponse, MixnodeUptimeHistoryResponse,
RewardEstimationResponse, StakeSaturationResponse, UptimeResponse,
},
};
pub use nym_coconut_dkg_common::types::EpochId;
Expand Down Expand Up @@ -95,6 +95,14 @@ pub trait NymApiClientExt: ApiClient {
.await
}

async fn get_nym_nodes_described(&self) -> Result<Vec<DescribedNymNode>, NymAPIError> {
self.get_json(
&[routes::API_VERSION, routes::NYM_NODES, routes::DESCRIBED],
NO_PARAMS,
)
.await
}

async fn get_active_mixnodes(&self) -> Result<Vec<MixNodeDetails>, NymAPIError> {
self.get_json(
&[routes::API_VERSION, routes::MIXNODES, routes::ACTIVE],
Expand Down
1 change: 1 addition & 0 deletions common/client-libs/validator-client/src/nym_api/routes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use nym_network_defaults::NYM_API_VERSION;
pub const API_VERSION: &str = NYM_API_VERSION;
pub const MIXNODES: &str = "mixnodes";
pub const GATEWAYS: &str = "gateways";
pub const NYM_NODES: &str = "nym-nodes";
pub const DESCRIBED: &str = "described";

pub const DETAILED: &str = "detailed";
Expand Down
4 changes: 2 additions & 2 deletions common/topology/src/gateway.rs
Original file line number Diff line number Diff line change
Expand Up @@ -202,8 +202,8 @@ impl<'a> TryFrom<&'a DescribedGateway> for Node {
owner: value.bond.owner.as_str().to_owned(),
host,
mix_host,
clients_ws_port: self_described.mixnet_websockets.ws_port,
clients_wss_port: self_described.mixnet_websockets.wss_port,
clients_ws_port: self_described.mixnet_websockets.unwrap().ws_port, //SW gateway have that field
clients_wss_port: self_described.mixnet_websockets.unwrap().wss_port, //SW gateway have that field
identity_key: identity::PublicKey::from_base58_string(
&self_described.host_information.keys.ed25519,
)?,
Expand Down
2 changes: 2 additions & 0 deletions gateway/src/http/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use nym_network_requester::RequestFilter;
use nym_node::error::NymNodeError;
use nym_node::http::api::api_requests;
use nym_node::http::api::api_requests::v1::network_requester::exit_policy::models::UsedExitPolicy;
use nym_node::http::api::api_requests::v1::node::models::NoiseInformation;
use nym_node::http::api::api_requests::SignedHostInformation;
use nym_node::http::router::WireguardAppState;
use nym_node::wireguard::types::GatewayClientRegistry;
Expand Down Expand Up @@ -260,6 +261,7 @@ impl<'a> HttpApiBuilder<'a> {
self.sphinx_keypair.public_key(),
self.identity_keypair,
)?,
NoiseInformation { supported: false }, //this field comes with Noise support, but with PR chain, the actual support might come later
)
.with_gateway(load_gateway_details(self.gateway_config)?)
.with_landing_page_assets(self.gateway_config.http.landing_page_assets_path.as_ref());
Expand Down
2 changes: 2 additions & 0 deletions mixnode/src/node/http/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use nym_bin_common::bin_info_owned;
use nym_crypto::asymmetric::{encryption, identity};
use nym_node::error::NymNodeError;
use nym_node::http::api::api_requests;
use nym_node::http::api::api_requests::v1::node::models::NoiseInformation;
use nym_node::http::api::api_requests::SignedHostInformation;
use nym_task::TaskClient;

Expand Down Expand Up @@ -93,6 +94,7 @@ impl<'a> HttpApiBuilder<'a> {
self.sphinx_keypair.public_key(),
self.identity_keypair,
)?,
NoiseInformation { supported: false }, //this field comes with Noise support, but with PR chain, the actual support might come later
)
.with_mixnode(load_mixnode_details(self.mixnode_config)?)
.with_landing_page_assets(self.mixnode_config.http.landing_page_assets_path.as_ref());
Expand Down
43 changes: 40 additions & 3 deletions nym-api/nym-api-requests/src/models.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@ use nym_mixnet_contract_common::mixnode::MixNodeDetails;
use nym_mixnet_contract_common::reward_params::{Performance, RewardingParams};
use nym_mixnet_contract_common::rewarding::RewardEstimate;
use nym_mixnet_contract_common::{
GatewayBond, IdentityKey, Interval, MixId, MixNode, Percent, RewardedSetNodeStatus,
GatewayBond, IdentityKey, Interval, MixId, MixNode, MixNodeBond, Percent, RewardedSetNodeStatus,
};
use nym_node_requests::api::v1::gateway::models::WebSockets;
use nym_node_requests::api::v1::node::models::{BinaryBuildInformationOwned, HostInformation};
use nym_node_requests::api::v1::node::models::{
BinaryBuildInformationOwned, HostInformation, NoiseInformation,
};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use std::fmt::{Display, Formatter};
Expand Down Expand Up @@ -370,7 +372,10 @@ pub struct NymNodeDescription {
pub ip_packet_router: Option<IpPacketRouterDetails>,

// for now we only care about their ws/wss situation, nothing more
pub mixnet_websockets: WebSockets,
#[serde(default)]
pub mixnet_websockets: Option<WebSockets>,

pub noise_information: NoiseInformation,
}

#[derive(Clone, Debug, Serialize, Deserialize, schemars::JsonSchema)]
Expand All @@ -388,6 +393,38 @@ impl From<GatewayBond> for DescribedGateway {
}
}

#[derive(Clone, Debug, Serialize, Deserialize, schemars::JsonSchema)]
pub struct DescribedMixnode {
pub bond: MixNodeBond,
pub self_described: Option<NymNodeDescription>,
}

impl From<MixNodeBond> for DescribedMixnode {
fn from(bond: MixNodeBond) -> Self {
DescribedMixnode {
bond,
self_described: None,
}
}
}
#[derive(Clone, Debug, Serialize, Deserialize, schemars::JsonSchema)]
pub enum DescribedNymNode {
Gateway(DescribedGateway),
Mixnode(DescribedMixnode),
}

impl From<GatewayBond> for DescribedNymNode {
fn from(value: GatewayBond) -> Self {
Self::Gateway(value.into())
}
}

impl From<MixNodeDetails> for DescribedNymNode {
fn from(value: MixNodeDetails) -> Self {
Self::Mixnode(value.bond_information.into())
}
}

#[derive(Clone, Debug, Serialize, Deserialize, schemars::JsonSchema)]
pub struct NetworkRequesterDetails {
/// address of the embedded network requester
Expand Down
97 changes: 97 additions & 0 deletions nym-api/src/node_describe_cache/mixnode.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
// Copyright 2023 - Nym Technologies SA <[email protected]>
// SPDX-License-Identifier: GPL-3.0-only

use nym_api_requests::models::NymNodeDescription;
use nym_config::defaults::DEFAULT_HTTP_API_LISTENING_PORT;
use nym_contracts_common::IdentityKey;
use nym_mixnet_contract_common::MixNode;
use nym_node_requests::api::client::NymNodeApiClientExt;

use super::NodeDescribeCacheError;

//this is a copy of try_get_client but for mixnode, to be deleted after smoosh probably
async fn try_get_client(
mixnode: &MixNode,
) -> Result<nym_node_requests::api::Client, NodeDescribeCacheError> {
let mixnode_host = &mixnode.host;

// first try the standard port in case the operator didn't put the node behind the proxy,
// then default https (443)
// finally default http (80)
let addresses_to_try = vec![
format!("http://{mixnode_host}:{DEFAULT_HTTP_API_LISTENING_PORT}"),
format!("https://{mixnode_host}"),
format!("http://{mixnode_host}"),
];

for address in addresses_to_try {
// if provided host was malformed, no point in continuing
let client = match nym_node_requests::api::Client::new_url(address, None) {
Ok(client) => client,
Err(err) => {
return Err(NodeDescribeCacheError::MalformedHost {
host: mixnode_host.clone(),
gateway: mixnode.identity_key.clone(),
source: err,
});
}
};
if let Ok(health) = client.get_health().await {
if health.status.is_up() {
return Ok(client);
}
}
}

Err(NodeDescribeCacheError::NoHttpPortsAvailable {
host: mixnode_host.clone(),
gateway: mixnode.identity_key.clone(),
})
}

pub(crate) async fn get_mixnode_description(
mixnode: MixNode,
) -> Result<(IdentityKey, NymNodeDescription), NodeDescribeCacheError> {
let client = try_get_client(&mixnode).await?;

let host_info =
client
.get_host_information()
.await
.map_err(|err| NodeDescribeCacheError::ApiFailure {
gateway: mixnode.identity_key.clone(),
source: err,
})?;

if !host_info.verify_host_information() {
return Err(NodeDescribeCacheError::MissignedHostInformation {
gateway: mixnode.identity_key,
});
}

let build_info =
client
.get_build_information()
.await
.map_err(|err| NodeDescribeCacheError::ApiFailure {
gateway: mixnode.identity_key.clone(),
source: err,
})?;

let noise_info = if let Ok(noise_info) = client.get_noise_information().await {
noise_info
} else {
Default::default()
};

let description = NymNodeDescription {
host_information: host_info.data,
build_information: build_info,
network_requester: None,
ip_packet_router: None,
mixnet_websockets: None,
noise_information: noise_info,
};

Ok((mixnode.identity_key, description))
}
38 changes: 35 additions & 3 deletions nym-api/src/node_describe_cache/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use crate::support::caching::refresher::{CacheItemProvider, CacheRefresher};
use crate::support::config;
use crate::support::config::DEFAULT_NODE_DESCRIBE_BATCH_SIZE;
use futures_util::{stream, StreamExt};
use mixnode::get_mixnode_description;
use nym_api_requests::models::{
IpPacketRouterDetails, NetworkRequesterDetails, NymNodeDescription,
};
Expand All @@ -17,6 +18,8 @@ use nym_node_requests::api::client::{NymNodeApiClientError, NymNodeApiClientExt}
use std::collections::HashMap;
use thiserror::Error;

pub mod mixnode;

// type alias for ease of use
pub type DescribedNodes = HashMap<IdentityKey, NymNodeDescription>;

Expand Down Expand Up @@ -180,12 +183,19 @@ async fn get_gateway_description(
None
};

let noise_info = if let Ok(noise_info) = client.get_noise_information().await {
noise_info
} else {
Default::default()
};

let description = NymNodeDescription {
host_information: host_info.data,
build_information: build_info,
network_requester,
ip_packet_router,
mixnet_websockets: websockets,
mixnet_websockets: Some(websockets),
noise_information: noise_info,
};

Ok((gateway.identity_key, description))
Expand All @@ -202,16 +212,17 @@ impl CacheItemProvider for NodeDescriptionProvider {

async fn try_refresh(&self) -> Result<Self::Item, Self::Error> {
let gateways = self.contract_cache.gateways_all().await;
let mixnodes = self.contract_cache.mixnodes_all().await;

// let guard = self.network_gateways.get().await?;
// let gateways = &*guard;

if gateways.is_empty() {
if gateways.is_empty() && mixnodes.is_empty() {
return Ok(HashMap::new());
}

// TODO: somehow bypass the 'higher-ranked lifetime error' and remove that redundant clone
let websockets = stream::iter(
let mut websockets = stream::iter(
gateways
// .deref()
// .clone()
Expand All @@ -232,6 +243,27 @@ impl CacheItemProvider for NodeDescriptionProvider {
.collect::<HashMap<_, _>>()
.await;

let mixnodes_websockets = stream::iter(
mixnodes
.into_iter()
.map(|detail| detail.bond_information.mix_node)
.map(get_mixnode_description),
)
.buffer_unordered(self.batch_size)
.filter_map(|res| async move {
match res {
Ok((identity, description)) => Some((identity, description)),
Err(err) => {
debug!("{err}");
None
}
}
})
.collect::<HashMap<_, _>>()
.await;

websockets.extend(mixnodes_websockets);

Ok(websockets)
}
}
Expand Down
3 changes: 2 additions & 1 deletion nym-api/src/nym_nodes/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ pub(crate) mod routes;
/// Merges the routes with http information and returns it to Rocket for serving
pub(crate) fn nym_node_routes(settings: &OpenApiSettings) -> (Vec<Route>, OpenApi) {
openapi_get_routes_spec![
settings: routes::get_gateways_described
settings: routes::get_gateways_described,
routes::get_nym_nodes_described,
]
}
Loading