proper type conversions and client compat

This commit is contained in:
Jędrzej Stuczyński
2024-06-10 11:03:26 +01:00
parent 9c19452758
commit f412f45b50
11 changed files with 157 additions and 59 deletions
@@ -0,0 +1,18 @@
/*
* Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
* SPDX-License-Identifier: Apache-2.0
*/
CREATE TABLE remote_gateway_details_temp
(
gateway_id_bs58 TEXT NOT NULL UNIQUE PRIMARY KEY REFERENCES registered_gateway (gateway_id_bs58),
derived_aes128_ctr_blake3_hmac_keys_bs58 TEXT NOT NULL,
gateway_owner_address TEXT,
gateway_listener TEXT NOT NULL,
wg_tun_address TEXT
);
INSERT INTO remote_gateway_details_temp SELECT * FROM remote_gateway_details;
DROP TABLE remote_gateway_details;
ALTER TABLE remote_gateway_details_temp RENAME TO remote_gateway_details;
@@ -65,7 +65,7 @@ impl GatewayDetails {
pub fn new_remote(
gateway_id: identity::PublicKey,
derived_aes128_ctr_blake3_hmac_keys: Arc<SharedKeys>,
gateway_owner_address: AccountId,
gateway_owner_address: Option<AccountId>,
gateway_listener: Url,
wg_tun_address: Option<Url>,
) -> Self {
@@ -170,7 +170,7 @@ pub struct RegisteredGateway {
pub struct RawRemoteGatewayDetails {
pub gateway_id_bs58: String,
pub derived_aes128_ctr_blake3_hmac_keys_bs58: String,
pub gateway_owner_address: String,
pub gateway_owner_address: Option<String>,
pub gateway_listener: String,
pub wg_tun_address: Option<String>,
}
@@ -195,14 +195,19 @@ impl TryFrom<RawRemoteGatewayDetails> for RemoteGatewayDetails {
})?,
);
let gateway_owner_address =
AccountId::from_str(&value.gateway_owner_address).map_err(|source| {
BadGateway::MalformedGatewayOwnerAccountAddress {
gateway_id: value.gateway_id_bs58.clone(),
raw_owner: value.gateway_owner_address.clone(),
source,
}
})?;
let gateway_owner_address = value
.gateway_owner_address
.as_ref()
.map(|raw_owner| {
AccountId::from_str(&raw_owner).map_err(|source| {
BadGateway::MalformedGatewayOwnerAccountAddress {
gateway_id: value.gateway_id_bs58.clone(),
raw_owner: raw_owner.clone(),
source,
}
})
})
.transpose()?;
let gateway_listener = Url::parse(&value.gateway_listener).map_err(|source| {
BadGateway::MalformedListener {
@@ -241,7 +246,7 @@ impl<'a> From<&'a RemoteGatewayDetails> for RawRemoteGatewayDetails {
derived_aes128_ctr_blake3_hmac_keys_bs58: value
.derived_aes128_ctr_blake3_hmac_keys
.to_base58_string(),
gateway_owner_address: value.gateway_owner_address.to_string(),
gateway_owner_address: value.gateway_owner_address.as_ref().map(|o| o.to_string()),
gateway_listener: value.gateway_listener.to_string(),
wg_tun_address: value.wg_tun_address.as_ref().map(|addr| addr.to_string()),
}
@@ -256,7 +261,7 @@ pub struct RemoteGatewayDetails {
// the keys will be zeroized
pub derived_aes128_ctr_blake3_hmac_keys: Arc<SharedKeys>,
pub gateway_owner_address: AccountId,
pub gateway_owner_address: Option<AccountId>,
pub gateway_listener: Url,
@@ -388,7 +388,10 @@ where
let cfg = GatewayConfig::new(
details.gateway_id,
Some(details.gateway_owner_address.to_string()),
details
.gateway_owner_address
.as_ref()
.map(|o| o.to_string()),
gateway_listener,
);
GatewayClient::new(
@@ -92,11 +92,11 @@ pub mod v1_1_33 {
message: format!("the stored gateway id was malformed: {err}"),
})?,
derived_aes128_ctr_blake3_hmac_keys: Arc::new(gateway_shared_key),
gateway_owner_address: gateway_owner.parse().map_err(|err| {
gateway_owner_address: Some(gateway_owner.parse().map_err(|err| {
ClientCoreError::UpgradeFailure {
message: format!("the stored gateway owner address was malformed: {err}"),
}
})?,
})?),
gateway_listener: gateway_listener.parse().map_err(|err| {
ClientCoreError::UpgradeFailure {
message: format!("the stored gateway listener address was malformed: {err}"),
@@ -2,9 +2,9 @@
// SPDX-License-Identifier: Apache-2.0
use async_trait::async_trait;
use log::{error, warn};
use log::{debug, error, warn};
use nym_topology::provider_trait::TopologyProvider;
use nym_topology::{nym_topology_from_detailed, NymTopology, NymTopologyError};
use nym_topology::{NymTopology, NymTopologyError};
use rand::prelude::SliceRandom;
use rand::thread_rng;
use url::Url;
@@ -103,6 +103,12 @@ impl NymApiTopologyProvider {
Ok(gateways) => gateways,
};
debug!(
"there are {} mixnodes and {} gateways in total (before performance filtering)",
mixnodes.len(),
gateways.len()
);
let topology = NymTopology::from_unordered(
mixnodes.iter().filter(|m| {
m.performance.round_to_integer() >= self.config.min_mixnode_performance
+14 -8
View File
@@ -29,7 +29,7 @@ pub enum SelectedGateway {
Remote {
gateway_id: identity::PublicKey,
gateway_owner_address: AccountId,
gateway_owner_address: Option<AccountId>,
gateway_listener: Url,
@@ -84,13 +84,19 @@ impl SelectedGateway {
let wg_tun_address = wg_tun_address(wg_tun_ip_address, &node)?;
let gateway_owner_address = AccountId::from_str(&node.owner).map_err(|source| {
ClientCoreError::MalformedGatewayOwnerAccountAddress {
gateway_id: node.identity_key.to_base58_string(),
raw_owner: node.owner,
err: source.to_string(),
}
})?;
let gateway_owner_address = node
.owner
.as_ref()
.map(|raw_owner| {
AccountId::from_str(&raw_owner).map_err(|source| {
ClientCoreError::MalformedGatewayOwnerAccountAddress {
gateway_id: node.identity_key.to_base58_string(),
raw_owner: raw_owner.clone(),
err: source.to_string(),
}
})
})
.transpose()?;
let gateway_listener =
Url::parse(&gateway_listener).map_err(|source| ClientCoreError::MalformedListener {
+2 -2
View File
@@ -41,7 +41,7 @@ impl<'a> From<&'a mix::Node> for TestableNode {
fn from(value: &'a mix::Node) -> Self {
TestableNode {
encoded_identity: value.identity_key.to_base58_string(),
owner: value.owner.clone(),
owner: value.owner.as_ref().cloned().unwrap_or_default(),
typ: NodeType::Mixnode {
mix_id: value.mix_id,
},
@@ -53,7 +53,7 @@ impl<'a> From<&'a gateway::Node> for TestableNode {
fn from(value: &'a gateway::Node) -> Self {
TestableNode {
encoded_identity: value.identity_key.to_base58_string(),
owner: value.owner.clone(),
owner: value.owner.as_ref().cloned().unwrap_or_default(),
typ: NodeType::Gateway,
}
}
+38 -15
View File
@@ -9,6 +9,8 @@ use nym_sphinx_addressing::nodes::{NodeIdentity, NymNodeRoutingAddress};
use nym_sphinx_types::Node as SphinxNode;
use nym_api_requests::nym_nodes::SkimmedNode;
use rand::seq::SliceRandom;
use rand::thread_rng;
use std::fmt;
use std::fmt::Formatter;
use std::io;
@@ -48,7 +50,6 @@ pub enum GatewayConversionError {
#[derive(Clone)]
pub struct Node {
pub owner: String,
pub host: NetworkAddress,
// we're keeping this as separate resolved field since we do not want to be resolving the potential
// hostname every time we want to construct a path via this node
@@ -62,6 +63,9 @@ pub struct Node {
pub identity_key: identity::PublicKey,
pub sphinx_key: encryption::PublicKey, // TODO: or nymsphinx::PublicKey? both are x25519
// to be removed:
pub owner: Option<String>,
pub version: NodeVersion,
}
@@ -122,7 +126,7 @@ impl fmt::Display for Node {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"Node(id: {}, owner: {}, host: {})",
"Node(id: {}, owner: {:?}, host: {})",
self.identity_key, self.owner, self.host,
)
}
@@ -156,7 +160,7 @@ impl<'a> TryFrom<&'a GatewayBond> for Node {
let mix_host = Self::extract_mix_host(&host, bond.gateway.mix_port)?;
Ok(Node {
owner: bond.owner.as_str().to_owned(),
owner: Some(bond.owner.as_str().to_owned()),
host,
mix_host,
clients_ws_port: bond.gateway.clients_port,
@@ -201,7 +205,7 @@ impl<'a> TryFrom<&'a DescribedGateway> for Node {
let mix_host = SocketAddr::new(ips[0], value.bond.gateway.mix_port);
Ok(Node {
owner: value.bond.owner.as_str().to_owned(),
owner: Some(value.bond.owner.as_str().to_owned()),
host,
mix_host,
clients_ws_port: self_described.mixnet_websockets.ws_port,
@@ -225,17 +229,36 @@ impl<'a> TryFrom<&'a SkimmedNode> for Node {
type Error = GatewayConversionError;
fn try_from(value: &'a SkimmedNode) -> Result<Self, Self::Error> {
todo!()
// Ok(Node {
// owner: "".to_string(),
// host: (),
// mix_host: (),
// clients_ws_port: 0,
// clients_wss_port: None,
// identity_key: (),
// sphinx_key: (),
// version: Default::default(),
// })
let Some(entry_details) = &value.entry else {
return Err(GatewayConversionError::NotGateway);
};
if value.ip_addresses.is_empty() {
return Err(GatewayConversionError::NoIpAddressesProvided {
gateway: value.ed25519_identity_pubkey.clone(),
});
}
// safety: we just checked the slice is not empty
#[allow(clippy::unwrap_used)]
let ip = value.ip_addresses.choose(&mut thread_rng()).unwrap();
let host = if let Some(hostname) = &entry_details.hostname {
NetworkAddress::Hostname(hostname.to_string())
} else {
NetworkAddress::IpAddr(*ip)
};
Ok(Node {
host,
mix_host: SocketAddr::new(*ip, value.mix_port),
clients_ws_port: entry_details.ws_port,
clients_wss_port: entry_details.wss_port,
identity_key: value.ed25519_identity_pubkey.parse()?,
sphinx_key: value.x25519_sphinx_pubkey.parse()?,
owner: None,
version: NodeVersion::Unknown,
})
}
}
+42 -14
View File
@@ -8,7 +8,9 @@ use nym_mixnet_contract_common::{MixId, MixNodeBond};
use nym_sphinx_addressing::nodes::NymNodeRoutingAddress;
use nym_sphinx_types::Node as SphinxNode;
use nym_api_requests::nym_nodes::SkimmedNode;
use nym_api_requests::nym_nodes::{NodeRole, SkimmedNode};
use rand::seq::SliceRandom;
use rand::thread_rng;
use std::fmt::Formatter;
use std::io;
use std::net::SocketAddr;
@@ -29,6 +31,12 @@ pub enum MixnodeConversionError {
source: io::Error,
},
#[error("invalid mix layer")]
InvalidLayer,
#[error("'{mixnode}' has not provided any valid ip addresses")]
NoIpAddressesProvided { mixnode: String },
#[error("provided node is not a mixnode in this epoch!")]
NotMixnode,
}
@@ -36,7 +44,6 @@ pub enum MixnodeConversionError {
#[derive(Clone)]
pub struct Node {
pub mix_id: MixId,
pub owner: String,
pub host: NetworkAddress,
// we're keeping this as separate resolved field since we do not want to be resolving the potential
// hostname every time we want to construct a path via this node
@@ -44,7 +51,10 @@ pub struct Node {
pub identity_key: identity::PublicKey,
pub sphinx_key: encryption::PublicKey, // TODO: or nymsphinx::PublicKey? both are x25519
pub layer: Layer,
// to be removed:
pub version: NodeVersion,
pub owner: Option<String>,
}
impl std::fmt::Debug for Node {
@@ -111,7 +121,7 @@ impl<'a> TryFrom<&'a MixNodeBond> for Node {
Ok(Node {
mix_id: bond.mix_id,
owner: bond.owner.as_str().to_owned(),
owner: Some(bond.owner.as_str().to_owned()),
host,
mix_host,
identity_key: identity::PublicKey::from_base58_string(&bond.mix_node.identity_key)?,
@@ -126,17 +136,35 @@ impl<'a> TryFrom<&'a SkimmedNode> for Node {
type Error = MixnodeConversionError;
fn try_from(value: &'a SkimmedNode) -> Result<Self, Self::Error> {
todo!()
// Ok(Node {
// owner: "".to_string(),
// host: (),
// mix_host: (),
// clients_ws_port: 0,
// clients_wss_port: None,
// identity_key: (),
// sphinx_key: (),
// version: Default::default(),
// })
if value.ip_addresses.is_empty() {
return Err(MixnodeConversionError::NoIpAddressesProvided {
mixnode: value.ed25519_identity_pubkey.clone(),
});
}
let layer = match value.role {
NodeRole::Mixnode { layer } => layer
.try_into()
.map_err(|_| MixnodeConversionError::InvalidLayer)?,
_ => return Err(MixnodeConversionError::NotMixnode),
};
// safety: we just checked the slice is not empty
#[allow(clippy::unwrap_used)]
let ip = value.ip_addresses.choose(&mut thread_rng()).unwrap();
let host = NetworkAddress::IpAddr(*ip);
Ok(Node {
mix_id: value.node_id,
host,
mix_host: SocketAddr::new(*ip, value.mix_port),
identity_key: value.ed25519_identity_pubkey.parse()?,
sphinx_key: value.x25519_sphinx_pubkey.parse()?,
layer,
owner: None,
version: NodeVersion::Unknown,
})
}
}
+4 -2
View File
@@ -109,7 +109,8 @@ pub struct SerializableMixNode {
#[serde(alias = "mix_id")]
pub mix_id: u32,
pub owner: String,
#[cfg_attr(feature = "wasm-serde-types", tsify(optional))]
pub owner: Option<String>,
pub host: String,
@@ -180,7 +181,8 @@ impl<'a> From<&'a mix::Node> for SerializableMixNode {
#[serde(rename_all = "camelCase")]
#[serde(deny_unknown_fields)]
pub struct SerializableGateway {
pub owner: String,
#[cfg_attr(feature = "wasm-serde-types", tsify(optional))]
pub owner: Option<String>,
pub host: String,
+8 -1
View File
@@ -5,6 +5,7 @@ use crate::models::{
GatewayBondAnnotated, MixNodeBondAnnotated, NymNodeDescription, OffsetDateTimeJsonSchemaWrapper,
};
use nym_mixnet_contract_common::reward_params::Performance;
use nym_mixnet_contract_common::MixId;
use serde::{Deserialize, Serialize};
use std::net::IpAddr;
@@ -54,11 +55,15 @@ pub struct BasicEntryInformation {
pub wss_port: Option<u16>,
}
type NodeId = MixId;
// the bare minimum information needed to construct sphinx packets
#[derive(Clone, Debug, Serialize, Deserialize, schemars::JsonSchema)]
pub struct SkimmedNode {
// in directory v3 all nodes (mixnodes AND gateways) will have a unique id
// pub node_id: NodeId,
// but to keep structure consistent, introduce this field now
pub node_id: NodeId,
pub ed25519_identity_pubkey: String,
pub ip_addresses: Vec<IpAddr>,
@@ -103,6 +108,7 @@ impl SkimmedNode {
impl<'a> From<&'a MixNodeBondAnnotated> for SkimmedNode {
fn from(value: &'a MixNodeBondAnnotated) -> Self {
SkimmedNode {
node_id: value.mix_id(),
ed25519_identity_pubkey: value.identity_key().to_string(),
ip_addresses: value.ip_addresses.clone(),
mix_port: value.mix_node().mix_port,
@@ -119,6 +125,7 @@ impl<'a> From<&'a MixNodeBondAnnotated> for SkimmedNode {
impl<'a> From<&'a GatewayBondAnnotated> for SkimmedNode {
fn from(value: &'a GatewayBondAnnotated) -> Self {
SkimmedNode {
node_id: MixId::MAX,
ip_addresses: value.ip_addresses.clone(),
ed25519_identity_pubkey: value.gateway_bond.identity().clone(),
mix_port: value.gateway_bond.gateway.mix_port,