clients using self-described gateway information

This commit is contained in:
Jędrzej Stuczyński
2023-10-06 11:10:44 +01:00
parent 8f2cb95ffa
commit ee2026e53d
25 changed files with 205 additions and 89 deletions
Generated
+2
View File
@@ -6072,6 +6072,7 @@ dependencies = [
"opentelemetry",
"opentelemetry-jaeger",
"pretty_env_logger",
"schemars",
"semver 0.11.0",
"serde",
"serde_json",
@@ -7338,6 +7339,7 @@ dependencies = [
"async-trait",
"bs58 0.4.0",
"log",
"nym-api-requests",
"nym-bin-common",
"nym-config",
"nym-crypto",
-1
View File
@@ -180,7 +180,6 @@ pub(crate) async fn execute(args: Init) -> Result<(), ClientError> {
let selection_spec = GatewaySelectionSpecification::new(
user_chosen_gateway_id.map(|id| id.to_base58_string()),
Some(args.latency_based_selection),
false,
);
// Load and potentially override config
-1
View File
@@ -185,7 +185,6 @@ pub(crate) async fn execute(args: Init) -> Result<(), Socks5ClientError> {
let selection_spec = GatewaySelectionSpecification::new(
user_chosen_gateway_id.map(|id| id.to_base58_string()),
Some(args.latency_based_selection),
false,
);
// Load and potentially override config
+2
View File
@@ -15,6 +15,7 @@ clap_complete_fig = "4.0"
log = { workspace = true }
pretty_env_logger = "0.4.0"
semver = "0.11"
schemars = { workspace = true, features = ["preserve_order"], optional = true }
serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true, optional = true }
@@ -45,6 +46,7 @@ vergen = { version = "=7.4.3", default-features = false, features = [
default = []
openapi = ["utoipa"]
output_format = ["serde_json"]
bin_info_schema = ["schemars"]
tracing = [
"tracing-subscriber",
"tracing-tree",
@@ -82,6 +82,7 @@ impl BinaryBuildInformation {
#[derive(Clone, Debug, Serialize, Deserialize)]
#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "bin_info_schema", derive(schemars::JsonSchema))]
pub struct BinaryBuildInformationOwned {
/// Provides the name of the binary, i.e. the content of `CARGO_PKG_NAME` environmental variable.
pub binary_name: String,
@@ -69,7 +69,7 @@ impl NymApiTopologyProvider {
Ok(mixes) => mixes,
};
let gateways = match self.validator_client.get_cached_gateways().await {
let gateways = match self.validator_client.get_cached_described_gateways().await {
Err(err) => {
error!("failed to get network gateways - {err}");
return None;
+1 -18
View File
@@ -280,30 +280,13 @@ impl GatewayEndpointConfig {
.map_err(ClientCoreError::UnableToCreatePublicKeyFromGatewayId)
}
pub fn from_node(node: nym_topology::gateway::Node, use_tls: bool) -> Self {
// TODO: in the future this shall return a Result and explicit `use_tls` will be removed in favour of the tls info being available on the struct
if use_tls {
Self::from_topology_node_tls(node)
} else {
Self::from_topology_node_no_tls(node)
}
}
pub fn from_topology_node_no_tls(node: nym_topology::gateway::Node) -> Self {
pub fn from_node(node: nym_topology::gateway::Node) -> Self {
GatewayEndpointConfig {
gateway_id: node.identity_key.to_base58_string(),
gateway_listener: node.clients_address(),
gateway_owner: node.owner,
}
}
pub fn from_topology_node_tls(node: nym_topology::gateway::Node) -> Self {
GatewayEndpointConfig {
gateway_id: node.identity_key.to_base58_string(),
gateway_listener: node.clients_address_tls(),
gateway_owner: node.owner,
}
}
}
#[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)]
+6 -9
View File
@@ -107,20 +107,17 @@ where
let mut new_keys = ManagedKeys::generate_new(&mut rng);
let gateway_details = match selection_specification {
GatewaySelectionSpecification::UniformRemote { must_use_tls } => {
GatewaySelectionSpecification::UniformRemote => {
let gateway = uniformly_random_gateway(&mut rng, &available_gateways)?;
GatewayDetails::Configured(GatewayEndpointConfig::from_node(gateway, must_use_tls))
GatewayDetails::Configured(GatewayEndpointConfig::from_node(gateway))
}
GatewaySelectionSpecification::RemoteByLatency { must_use_tls } => {
GatewaySelectionSpecification::RemoteByLatency => {
let gateway = choose_gateway_by_latency(&mut rng, &available_gateways).await?;
GatewayDetails::Configured(GatewayEndpointConfig::from_node(gateway, must_use_tls))
GatewayDetails::Configured(GatewayEndpointConfig::from_node(gateway))
}
GatewaySelectionSpecification::Specified {
must_use_tls,
identity,
} => {
GatewaySelectionSpecification::Specified { identity } => {
let gateway = get_specified_gateway(&identity, &available_gateways)?;
GatewayDetails::Configured(GatewayEndpointConfig::from_node(gateway, must_use_tls))
GatewayDetails::Configured(GatewayEndpointConfig::from_node(gateway))
}
GatewaySelectionSpecification::Custom {
gateway_identity,
+8 -20
View File
@@ -181,17 +181,14 @@ impl<T> From<PersistedGatewayDetails<T>> for GatewayDetails<T> {
#[derive(Clone)]
pub enum GatewaySelectionSpecification<T = EmptyCustomDetails> {
/// Uniformly choose a random remote gateway.
UniformRemote { must_use_tls: bool },
UniformRemote,
/// Should the new, remote, gateway be selected based on latency.
RemoteByLatency { must_use_tls: bool },
RemoteByLatency,
/// Gateway with this specific identity should be chosen.
// JS: I don't really like the name of this enum variant but couldn't think of anything better at the time
Specified {
must_use_tls: bool,
identity: IdentityKey,
},
Specified { identity: IdentityKey },
// TODO: this doesn't really fit in here..., but where else to put it?
/// This client has handled the selection by itself
@@ -203,27 +200,18 @@ pub enum GatewaySelectionSpecification<T = EmptyCustomDetails> {
impl<T> Default for GatewaySelectionSpecification<T> {
fn default() -> Self {
GatewaySelectionSpecification::UniformRemote {
must_use_tls: false,
}
GatewaySelectionSpecification::UniformRemote
}
}
impl<T> GatewaySelectionSpecification<T> {
pub fn new(
gateway_identity: Option<String>,
latency_based_selection: Option<bool>,
must_use_tls: bool,
) -> Self {
pub fn new(gateway_identity: Option<String>, latency_based_selection: Option<bool>) -> Self {
if let Some(identity) = gateway_identity {
GatewaySelectionSpecification::Specified {
identity,
must_use_tls,
}
GatewaySelectionSpecification::Specified { identity }
} else if let Some(true) = latency_based_selection {
GatewaySelectionSpecification::RemoteByLatency { must_use_tls }
GatewaySelectionSpecification::RemoteByLatency
} else {
GatewaySelectionSpecification::UniformRemote { must_use_tls }
GatewaySelectionSpecification::UniformRemote
}
}
}
@@ -11,7 +11,7 @@ use crate::{
use nym_api_requests::coconut::{
BlindSignRequestBody, BlindedSignatureResponse, VerifyCredentialBody, VerifyCredentialResponse,
};
use nym_api_requests::models::MixNodeBondAnnotated;
use nym_api_requests::models::{DescribedGateway, MixNodeBondAnnotated};
use nym_api_requests::models::{
GatewayCoreStatusResponse, MixnodeCoreStatusResponse, MixnodeStatusResponse,
RewardEstimationResponse, StakeSaturationResponse,
@@ -275,6 +275,12 @@ impl NymApiClient {
Ok(self.nym_api.get_gateways().await?)
}
pub async fn get_cached_described_gateways(
&self,
) -> Result<Vec<DescribedGateway>, ValidatorClientError> {
Ok(self.nym_api.get_gateways_described().await?)
}
pub async fn get_gateway_core_status_count(
&self,
identity: IdentityKeyRef<'_>,
@@ -8,13 +8,7 @@ use http_api_client::{ApiClient, NO_PARAMS};
use nym_api_requests::coconut::{
BlindSignRequestBody, BlindedSignatureResponse, VerifyCredentialBody, VerifyCredentialResponse,
};
use nym_api_requests::models::{
ComputeRewardEstParam, GatewayBondAnnotated, GatewayCoreStatusResponse,
GatewayStatusReportResponse, GatewayUptimeHistoryResponse, InclusionProbabilityResponse,
MixNodeBondAnnotated, MixnodeCoreStatusResponse, MixnodeStatusReportResponse,
MixnodeStatusResponse, MixnodeUptimeHistoryResponse, RewardEstimationResponse,
StakeSaturationResponse, UptimeResponse,
};
use nym_api_requests::models::{ComputeRewardEstParam, DescribedGateway, GatewayBondAnnotated, GatewayCoreStatusResponse, GatewayStatusReportResponse, GatewayUptimeHistoryResponse, InclusionProbabilityResponse, MixNodeBondAnnotated, MixnodeCoreStatusResponse, MixnodeStatusReportResponse, MixnodeStatusResponse, MixnodeUptimeHistoryResponse, RewardEstimationResponse, StakeSaturationResponse, UptimeResponse};
use nym_mixnet_contract_common::mixnode::MixNodeDetails;
use nym_mixnet_contract_common::{GatewayBond, IdentityKeyRef, MixId};
use nym_name_service_common::response::NamesListResponse;
@@ -79,6 +73,14 @@ pub trait NymApiClientExt: ApiClient {
.await
}
async fn get_gateways_described(&self) -> Result<Vec<DescribedGateway>, NymAPIError> {
self.get_json(
&[routes::API_VERSION, routes::GATEWAYS, 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],
@@ -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 DESCRIBED: &str = "described";
pub const DETAILED: &str = "detailed";
pub const DETAILED_UNFILTERED: &str = "detailed-unfiltered";
+4
View File
@@ -35,6 +35,10 @@ nym-sphinx-types = { path = "../nymsphinx/types", features = ["sphinx", "outfox"
nym-sphinx-routing = { path = "../nymsphinx/routing" }
nym-bin-common = { path = "../bin-common" }
# I'm not sure how to feel about pulling in this dependency here...
nym-api-requests = { path = "../../nym-api/nym-api-requests" }
# 'serializable' feature
nym-config = { path = "../config", optional = true }
+93 -5
View File
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: Apache-2.0
use crate::{filter, NetworkAddress, NodeVersion};
use nym_api_requests::models::DescribedGateway;
use nym_crypto::asymmetric::{encryption, identity};
use nym_mixnet_contract_common::GatewayBond;
use nym_sphinx_addressing::nodes::{NodeIdentity, NymNodeRoutingAddress};
@@ -10,6 +11,7 @@ use std::convert::{TryFrom, TryInto};
use std::fmt;
use std::fmt::Formatter;
use std::io;
use std::net::AddrParseError;
use std::net::SocketAddr;
use thiserror::Error;
@@ -27,6 +29,17 @@ pub enum GatewayConversionError {
#[source]
source: io::Error,
},
#[error("'{gateway}' has not provided any valid ip addresses")]
NoIpAddressesProvided { gateway: String },
#[error("'{gateway}' has provided a malformed ip address: {err}")]
MalformedIpAddress {
gateway: String,
#[source]
err: AddrParseError,
},
}
#[derive(Clone)]
@@ -36,7 +49,13 @@ pub struct Node {
// 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
pub mix_host: SocketAddr,
pub clients_port: u16,
// #[serde(alias = "clients_port")]
pub clients_ws_port: u16,
// #[serde(default)]
pub clients_wss_port: Option<u16>,
pub identity_key: identity::PublicKey,
pub sphinx_key: encryption::PublicKey, // TODO: or nymsphinx::PublicKey? both are x25519
pub version: NodeVersion,
@@ -82,11 +101,17 @@ impl Node {
}
pub fn clients_address(&self) -> String {
format!("ws://{}:{}", self.host, self.clients_port)
self.clients_address_tls()
.unwrap_or_else(|| self.clients_address_no_tls())
}
pub fn clients_address_tls(&self) -> String {
format!("wss://{}:443", self.host)
pub fn clients_address_no_tls(&self) -> String {
format!("ws://{}:{}", self.host, self.clients_ws_port)
}
pub fn clients_address_tls(&self) -> Option<String> {
self.clients_wss_port
.map(|p| format!("wss://{}:{p}", self.host))
}
}
@@ -131,7 +156,8 @@ impl<'a> TryFrom<&'a GatewayBond> for Node {
owner: bond.owner.as_str().to_owned(),
host,
mix_host,
clients_port: bond.gateway.clients_port,
clients_ws_port: bond.gateway.clients_port,
clients_wss_port: None,
identity_key: identity::PublicKey::from_base58_string(&bond.gateway.identity_key)?,
sphinx_key: encryption::PublicKey::from_base58_string(&bond.gateway.sphinx_key)?,
version: bond.gateway.version.as_str().into(),
@@ -146,3 +172,65 @@ impl TryFrom<GatewayBond> for Node {
Node::try_from(&bond)
}
}
impl<'a> TryFrom<&'a DescribedGateway> for Node {
type Error = GatewayConversionError;
fn try_from(value: &'a DescribedGateway) -> Result<Self, Self::Error> {
let Some(ref self_described) = value.self_described else {
return (&value.bond).try_into();
};
let ips = &self_described.host_information.ip_address;
if ips.is_empty() {
return Err(GatewayConversionError::NoIpAddressesProvided {
gateway: value.bond.gateway.identity_key.clone(),
});
}
let ips = ips
.iter()
.map(|ip| ip.parse())
.collect::<Result<Vec<_>, _>>()
.map_err(|err| GatewayConversionError::MalformedIpAddress {
gateway: value.bond.gateway.identity_key.clone(),
err,
})?;
let host = match &self_described.host_information.hostname {
None => NetworkAddress::IpAddr(ips[0]),
Some(hostname) => NetworkAddress::Hostname(hostname.clone()),
};
// get ip from the self-reported values so we wouldn't need to do any hostname resolution
// (which doesn't really work in wasm)
let mix_host = SocketAddr::new(ips[0], value.bond.gateway.mix_port);
Ok(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,
identity_key: identity::PublicKey::from_base58_string(
&self_described.host_information.keys.ed25519,
)?,
sphinx_key: encryption::PublicKey::from_base58_string(
&self_described.host_information.keys.x25519,
)?,
version: self_described
.build_information
.build_version
.as_str()
.into(),
})
}
}
impl TryFrom<DescribedGateway> for Node {
type Error = GatewayConversionError;
fn try_from(value: DescribedGateway) -> Result<Self, Self::Error> {
Node::try_from(&value)
}
}
+28 -4
View File
@@ -19,6 +19,7 @@ use std::str::FromStr;
#[cfg(feature = "serializable")]
use ::serde::{Deserialize, Deserializer, Serialize, Serializer};
use nym_api_requests::models::DescribedGateway;
pub mod error;
pub mod filter;
@@ -403,10 +404,33 @@ impl<'de> Deserialize<'de> for NymTopology {
}
}
pub fn nym_topology_from_detailed(
pub trait IntoGatewayNode: TryInto<gateway::Node>
where
<Self as TryInto<gateway::Node>>::Error: Display,
{
fn identity(&self) -> IdentityKeyRef;
}
impl IntoGatewayNode for GatewayBond {
fn identity(&self) -> IdentityKeyRef {
&self.gateway.identity_key
}
}
impl IntoGatewayNode for DescribedGateway {
fn identity(&self) -> IdentityKeyRef {
&self.bond.gateway.identity_key
}
}
pub fn nym_topology_from_detailed<G>(
mix_details: Vec<MixNodeDetails>,
gateway_bonds: Vec<GatewayBond>,
) -> NymTopology {
gateway_bonds: Vec<G>,
) -> NymTopology
where
G: IntoGatewayNode,
<G as TryInto<gateway::Node>>::Error: Display,
{
let mut mixes = BTreeMap::new();
for bond in mix_details
.into_iter()
@@ -435,7 +459,7 @@ pub fn nym_topology_from_detailed(
let mut gateways = Vec::with_capacity(gateway_bonds.len());
for bond in gateway_bonds.into_iter() {
let gate_id = bond.gateway.identity_key.clone();
let gate_id = bond.identity().to_owned();
match bond.try_into() {
Ok(gate) => gateways.push(gate),
Err(err) => {
+13 -4
View File
@@ -190,7 +190,12 @@ pub struct SerializableGateway {
#[cfg_attr(feature = "wasm-serde-types", tsify(optional))]
#[serde(alias = "clients_port")]
pub clients_port: Option<u16>,
#[serde(alias = "clients_ws_port")]
pub clients_ws_port: Option<u16>,
#[cfg_attr(feature = "wasm-serde-types", tsify(optional))]
#[serde(alias = "clients_wss_port")]
pub clients_wss_port: Option<u16>,
#[serde(alias = "identity_key")]
pub identity_key: String,
@@ -209,7 +214,9 @@ impl TryFrom<SerializableGateway> for gateway::Node {
let host = gateway::Node::parse_host(&value.host)?;
let mix_port = value.mix_port.unwrap_or(DEFAULT_MIX_LISTENING_PORT);
let clients_port = value.clients_port.unwrap_or(DEFAULT_CLIENT_LISTENING_PORT);
let clients_ws_port = value
.clients_ws_port
.unwrap_or(DEFAULT_CLIENT_LISTENING_PORT);
let version = value.version.map(|v| v.as_str().into()).unwrap_or_default();
// try to completely resolve the host in the mix situation to avoid doing it every
@@ -224,7 +231,8 @@ impl TryFrom<SerializableGateway> for gateway::Node {
owner: value.owner,
host,
mix_host,
clients_port,
clients_ws_port,
clients_wss_port: value.clients_wss_port,
identity_key: identity::PublicKey::from_base58_string(&value.identity_key)
.map_err(GatewayConversionError::from)?,
sphinx_key: encryption::PublicKey::from_base58_string(&value.sphinx_key)
@@ -241,7 +249,8 @@ impl<'a> From<&'a gateway::Node> for SerializableGateway {
host: value.host.to_string(),
explicit_ip: Some(value.mix_host.ip()),
mix_port: Some(value.mix_host.port()),
clients_port: Some(value.clients_port),
clients_ws_port: Some(value.clients_ws_port),
clients_wss_port: value.clients_wss_port,
identity_key: value.identity_key.to_base58_string(),
sphinx_key: value.sphinx_key.to_base58_string(),
version: Some(value.version.to_string()),
+3 -7
View File
@@ -86,15 +86,13 @@ pub fn current_network_topology(nym_api_url: String) -> Promise {
pub async fn setup_gateway_wasm(
client_store: &ClientStorage,
force_tls: bool,
chosen_gateway: Option<IdentityKey>,
gateways: &[gateway::Node],
) -> Result<InitialisationResult, WasmCoreError> {
let setup = if client_store.has_full_gateway_info().await? {
GatewaySetup::MustLoad
} else {
let selection_spec =
GatewaySelectionSpecification::new(chosen_gateway.clone(), None, force_tls);
let selection_spec = GatewaySelectionSpecification::new(chosen_gateway.clone(), None);
GatewaySetup::New {
specification: selection_spec,
@@ -110,21 +108,19 @@ pub async fn setup_gateway_wasm(
pub async fn setup_gateway_from_api(
client_store: &ClientStorage,
force_tls: bool,
chosen_gateway: Option<IdentityKey>,
nym_apis: &[Url],
) -> Result<InitialisationResult, WasmCoreError> {
let mut rng = thread_rng();
let gateways = current_gateways(&mut rng, nym_apis).await?;
setup_gateway_wasm(client_store, force_tls, chosen_gateway, &gateways).await
setup_gateway_wasm(client_store, chosen_gateway, &gateways).await
}
pub async fn setup_from_topology(
explicit_gateway: Option<IdentityKey>,
force_tls: bool,
topology: &NymTopology,
client_store: &ClientStorage,
) -> Result<InitialisationResult, WasmCoreError> {
let gateways = topology.gateways();
setup_gateway_wasm(client_store, force_tls, explicit_gateway, gateways).await
setup_gateway_wasm(client_store, explicit_gateway, gateways).await
}
+4 -1
View File
@@ -10,7 +10,7 @@ use nym_mixnet_contract_common::{
GatewayBond, IdentityKey, Interval, MixId, MixNode, Percent, RewardedSetNodeStatus,
};
use nym_node_requests::api::v1::gateway::models::WebSockets;
use nym_node_requests::api::v1::node::models::HostInformation;
use nym_node_requests::api::v1::node::models::{BinaryBuildInformationOwned, HostInformation};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use std::fmt::{Display, Formatter};
@@ -360,6 +360,9 @@ pub struct CirculatingSupplyResponse {
pub struct NymNodeDescription {
pub host_information: HostInformation,
// TODO: do we really care about ALL build info or just the version?
pub build_information: BinaryBuildInformationOwned,
// for now we only care about their ws/wss situation, nothing more
pub mixnet_websockets: WebSockets,
}
+10
View File
@@ -100,6 +100,15 @@ async fn get_gateway_description(
});
}
let build_info =
client
.get_build_information()
.await
.map_err(|err| NodeDescribeCacheError::ApiFailure {
gateway: gateway.identity_key.clone(),
source: err,
})?;
let websockets =
client
.get_mixnet_websockets()
@@ -111,6 +120,7 @@ async fn get_gateway_description(
let description = NymNodeDescription {
host_information: host_info.data,
build_information: build_info,
mixnet_websockets: websockets,
};
+2
View File
@@ -3918,6 +3918,7 @@ dependencies = [
"clap_complete_fig",
"log",
"pretty_env_logger",
"schemars",
"semver 0.11.0",
"serde",
"vergen",
@@ -4628,6 +4629,7 @@ dependencies = [
"async-trait",
"bs58 0.4.0",
"log",
"nym-api-requests",
"nym-bin-common",
"nym-config",
"nym-crypto",
@@ -204,8 +204,7 @@ pub async fn init_socks5_config(provider_address: String, chosen_gateway_id: Str
}
let gateway_setup = if register_gateway {
let selection_spec =
GatewaySelectionSpecification::new(Some(chosen_gateway_id), None, false);
let selection_spec = GatewaySelectionSpecification::new(Some(chosen_gateway_id), None);
let mut rng = rand_07::thread_rng();
let available_gateways =
current_gateways(&mut rng, &config.core.base.client.nym_api_urls).await?;
+1 -1
View File
@@ -25,7 +25,7 @@ http-api-client = { path = "../../common/http-api-client", optional = true }
## openapi:
utoipa = { workspace = true, optional = true }
nym-bin-common = { path = "../../common/bin-common" }
nym-bin-common = { path = "../../common/bin-common", features = ["bin_info_schema"] }
[features]
default = ["client"]
@@ -8,6 +8,7 @@ use async_trait::async_trait;
use http_api_client::{ApiClient, HttpClientError};
pub use http_api_client::Client;
use nym_bin_common::build_information::BinaryBuildInformationOwned;
pub type NymNodeApiClientError = HttpClientError;
@@ -18,6 +19,10 @@ pub trait NymNodeApiClientExt: ApiClient {
self.get_json_from(routes::api::v1::host_info_absolute())
.await
}
async fn get_build_information(&self) -> Result<BinaryBuildInformationOwned, NymNodeApiClientError> {
self.get_json_from(routes::api::v1::build_info_absolute()).await
}
// TODO: implement calls for other endpoints; for now I only care about the wss
async fn get_mixnet_websockets(&self) -> Result<WebSockets, NymNodeApiClientError> {
+3 -6
View File
@@ -419,11 +419,8 @@ where
let gateway_setup = if self.has_valid_gateway_info().await {
GatewaySetup::MustLoad
} else {
let selection_spec = GatewaySelectionSpecification::new(
self.config.user_chosen_gateway.clone(),
None,
false,
);
let selection_spec =
GatewaySelectionSpecification::new(self.config.user_chosen_gateway.clone(), None);
let mut rng = OsRng;
@@ -487,7 +484,7 @@ where
if !known_gateway {
let selection_spec =
GatewaySelectionSpecification::new(self.config.user_chosen_gateway, None, false);
GatewaySelectionSpecification::new(self.config.user_chosen_gateway, None);
let mut rng = OsRng;
let setup = GatewaySetup::New {
@@ -171,7 +171,6 @@ pub(crate) async fn execute(args: &Init) -> Result<(), NetworkRequesterError> {
let selection_spec = GatewaySelectionSpecification::new(
user_chosen_gateway_id.map(|id| id.to_base58_string()),
Some(args.latency_based_selection),
false,
);
// Load and potentially override config