feat: complete migration to unified HTTP client and fix all compilation errors

- Added missing NymApiClientExt trait methods (get_all_expanded_nodes, change_base_urls)
- Fixed all compilation errors across the workspace
- Updated nym-node to use unified client instead of deprecated NymApiClient
- Fixed type conversions for RewardedSetResponse → EpochRewardedSet
- Added nym-http-api-client dependency where needed
- Updated all examples and documentation to use new client API
This commit is contained in:
durch
2025-08-22 17:09:35 +02:00
parent ce0cbd552d
commit eebc9baf15
42 changed files with 440 additions and 189 deletions
+1
View File
@@ -53,6 +53,7 @@ nym-client-core-config-types = { path = "./config-types", features = [
nym-client-core-surb-storage = { path = "./surb-storage" }
nym-client-core-gateways-storage = { path = "./gateways-storage" }
nym-ecash-time = { path = "../ecash-time" }
nym-mixnet-contract-common = { path = "../cosmwasm-smart-contracts/mixnet-contract" }
[target."cfg(not(target_arch = \"wasm32\"))".dependencies]
nym-mixnet-client = { path = "../client-libs/mixnet-client", default-features = false }
@@ -57,7 +57,7 @@ use nym_task::{TaskClient, TaskHandle};
use nym_topology::provider_trait::TopologyProvider;
use nym_topology::HardcodedTopologyProvider;
use nym_validator_client::nym_api::NymApiClientExt;
use nym_validator_client::{nyxd::contract_traits::DkgQueryClient, NymApiClient, UserAgent};
use nym_validator_client::{nyxd::contract_traits::DkgQueryClient, UserAgent};
use rand::prelude::SliceRandom;
use rand::rngs::OsRng;
use rand::thread_rng;
@@ -566,7 +566,7 @@ where
custom_provider: Option<Box<dyn TopologyProvider + Send + Sync>>,
config_topology: config::Topology,
nym_api_urls: Vec<Url>,
nym_api_client: NymApiClient,
nym_api_client: nym_http_api_client::Client,
) -> Box<dyn TopologyProvider + Send + Sync> {
// if no custom provider was ... provided ..., create one using nym-api
custom_provider.unwrap_or_else(|| {
@@ -749,21 +749,42 @@ where
setup_gateway(setup_method, key_store, details_store).await
}
fn construct_nym_api_client(config: &Config, user_agent: Option<UserAgent>) -> NymApiClient {
fn construct_nym_api_client(
config: &Config,
user_agent: Option<UserAgent>,
) -> Result<nym_http_api_client::Client, ClientCoreError> {
let mut nym_api_urls = config.get_nym_api_endpoints();
nym_api_urls.shuffle(&mut thread_rng());
let mut builder = nym_http_api_client::Client::builder::<
_,
nym_validator_client::models::RequestError,
>(nym_api_urls[0].clone())
.map_err(|e| ClientCoreError::NymApiQueryFailure {
source: nym_validator_client::nym_api::error::NymAPIError::GenericRequestFailure(
e.to_string(),
),
})?;
if let Some(user_agent) = user_agent {
NymApiClient::new_with_user_agent(nym_api_urls[0].clone(), user_agent)
} else {
NymApiClient::new(nym_api_urls[0].clone())
builder = builder.with_user_agent(user_agent);
}
builder = builder.with_bincode();
builder
.build::<nym_validator_client::models::RequestError>()
.map_err(|e| ClientCoreError::NymApiQueryFailure {
source: nym_validator_client::nym_api::error::NymAPIError::GenericRequestFailure(
e.to_string(),
),
})
}
async fn determine_key_rotation_state(
client: &NymApiClient,
client: &nym_http_api_client::Client,
) -> Result<KeyRotationConfig, ClientCoreError> {
Ok(client.nym_api.get_key_rotation_info().await?.into())
Ok(client.get_key_rotation_info().await?.into())
}
pub async fn start_base(mut self) -> Result<BaseClient, ClientCoreError>
@@ -830,7 +851,7 @@ where
.dkg_query_client
.map(|client| BandwidthController::new(credential_store, client));
let nym_api_client = Self::construct_nym_api_client(&self.config, self.user_agent.clone());
let nym_api_client = Self::construct_nym_api_client(&self.config, self.user_agent.clone())?;
let key_rotation_config = Self::determine_key_rotation_state(&nym_api_client).await?;
let topology_provider = Self::setup_topology_provider(
@@ -2,8 +2,10 @@
// SPDX-License-Identifier: Apache-2.0
use async_trait::async_trait;
use nym_mixnet_contract_common::EpochRewardedSet;
use nym_topology::provider_trait::{ToTopologyMetadata, TopologyProvider};
use nym_topology::NymTopology;
use nym_validator_client::nym_api::NymApiClientExt;
use rand::prelude::SliceRandom;
use rand::thread_rng;
use std::cmp::min;
@@ -39,30 +41,43 @@ impl Config {
pub struct NymApiTopologyProvider {
config: Config,
validator_client: nym_validator_client::client::NymApiClient,
validator_client: nym_http_api_client::Client,
nym_api_urls: Vec<Url>,
currently_used_api: usize,
use_bincode: bool,
}
impl NymApiTopologyProvider {
pub fn new(
config: impl Into<Config>,
mut nym_api_urls: Vec<Url>,
mut validator_client: nym_validator_client::client::NymApiClient,
validator_client: nym_http_api_client::Client,
) -> Self {
nym_api_urls.shuffle(&mut thread_rng());
validator_client.change_nym_api(nym_api_urls[0].clone());
NymApiTopologyProvider {
let mut provider = NymApiTopologyProvider {
config: config.into(),
validator_client,
nym_api_urls,
currently_used_api: 0,
}
use_bincode: true,
};
// Set the initial API URL
provider.validator_client.change_base_urls(
provider
.nym_api_urls
.iter()
.map(|u| u.clone().into())
.collect(),
);
provider
}
pub fn disable_bincode(&mut self) {
self.validator_client.use_bincode = false;
self.use_bincode = false;
// Note: The unified client doesn't support toggling bincode after creation.
// This would require recreating the client without bincode.
// For now, we'll track the preference but it won't take effect.
warn!("Disabling bincode on existing client is not currently supported");
}
fn use_next_nym_api(&mut self) {
@@ -73,7 +88,9 @@ impl NymApiTopologyProvider {
self.currently_used_api = (self.currently_used_api + 1) % self.nym_api_urls.len();
self.validator_client
.change_nym_api(self.nym_api_urls[self.currently_used_api].clone())
.change_base_urls(vec![self.nym_api_urls[self.currently_used_api]
.clone()
.into()])
}
async fn get_current_compatible_topology(&mut self) -> Option<NymTopology> {
@@ -99,8 +116,13 @@ impl NymApiTopologyProvider {
.filter(|n| n.performance.round_to_integer() >= self.config.min_node_performance())
.collect::<Vec<_>>();
NymTopology::new(metadata.to_topology_metadata(), rewarded_set, Vec::new())
.with_skimmed_nodes(&nodes_filtered)
let epoch_rewarded_set: EpochRewardedSet = rewarded_set.into();
NymTopology::new(
metadata.to_topology_metadata(),
epoch_rewarded_set,
Vec::new(),
)
.with_skimmed_nodes(&nodes_filtered)
} else {
// if we're not using extended topology, we're only getting active set mixnodes and gateways
@@ -148,8 +170,13 @@ impl NymApiTopologyProvider {
}
}
NymTopology::new(metadata.to_topology_metadata(), rewarded_set, Vec::new())
.with_skimmed_nodes(&nodes)
let epoch_rewarded_set: EpochRewardedSet = rewarded_set.into();
NymTopology::new(
metadata.to_topology_metadata(),
epoch_rewarded_set,
Vec::new(),
)
.with_skimmed_nodes(&nodes)
};
if !topology.is_minimally_routable() {
+14 -10
View File
@@ -142,23 +142,27 @@ pub async fn gateways_for_init<R: Rng>(
let nym_api = nym_apis
.choose(rng)
.ok_or(ClientCoreError::ListOfNymApisIsEmpty)?;
// Use the unified HTTP client directly with optional user agent
let mut builder = nym_http_api_client::Client::builder(nym_api.clone())
.map_err(|e| ClientCoreError::ValidatorClientError(
nym_validator_client::ValidatorClientError::NymAPIError { source: e },
))?
.with_bincode(); // Use bincode for better performance
.map_err(|e| {
ClientCoreError::ValidatorClientError(
nym_validator_client::ValidatorClientError::NymAPIError { source: e },
)
})?
.with_bincode(); // Use bincode for better performance
if let Some(user_agent) = user_agent {
builder = builder.with_user_agent(user_agent);
}
let client = builder
.build::<nym_validator_client::models::RequestError>()
.map_err(|e| ClientCoreError::ValidatorClientError(
nym_validator_client::ValidatorClientError::NymAPIError { source: e },
))?;
.map_err(|e| {
ClientCoreError::ValidatorClientError(
nym_validator_client::ValidatorClientError::NymAPIError { source: e },
)
})?;
tracing::debug!("Fetching list of gateways from: {nym_api}");
@@ -5,8 +5,8 @@ use crate::nyxd::{self, NyxdClient};
use crate::signing::direct_wallet::DirectSecp256k1HdWallet;
use crate::signing::signer::{NoSigner, OfflineSigner};
use crate::{
DirectSigningReqwestRpcValidatorClient, QueryReqwestRpcValidatorClient,
ReqwestRpcClient, ValidatorClientError,
DirectSigningReqwestRpcValidatorClient, QueryReqwestRpcValidatorClient, ReqwestRpcClient,
ValidatorClientError,
};
use nym_api_requests::ecash::models::{
AggregatedCoinIndicesSignatureResponse, AggregatedExpirationDateSignatureResponse,
@@ -398,27 +398,9 @@ pub struct NymApiClient {
// we could re-implement the communication with the REST API on port 1317
}
impl From<nym_http_api_client::Client> for NymApiClient {
fn from(nym_api: nym_http_api_client::Client) -> Self {
NymApiClient {
use_bincode: false,
nym_api,
}
}
}
// we have to allow the use of deprecated method here as they're calling the deprecated trait methods
#[allow(deprecated)]
impl NymApiClient {
pub fn new(api_url: Url) -> Self {
let nym_api = nym_http_api_client::Client::new(api_url, None);
NymApiClient {
use_bincode: true,
nym_api,
}
}
#[cfg(not(target_arch = "wasm32"))]
pub fn new_with_timeout(api_url: Url, timeout: std::time::Duration) -> Self {
let nym_api = nym_http_api_client::Client::new(api_url, Some(timeout));
@@ -91,11 +91,14 @@ impl TryFrom<ContractVKShare> for EcashApiClient {
// In non-client applications this resolver can cause warning logs about H2 connection
// failure. This indicates that the long lived https connection was closed by the remote
// peer and the resolver will have to reconnect. It should not impact actual functionality
let api_client = nym_http_api_client::Client::builder::<_, nym_api_requests::models::RequestError>(url_address)
.map_err(|e| EcashApiError::ClientError(e.to_string()))?
.build::<nym_api_requests::models::RequestError>()
.map_err(|e| EcashApiError::ClientError(e.to_string()))?;
let api_client = nym_http_api_client::Client::builder::<
_,
nym_api_requests::models::RequestError,
>(url_address)
.map_err(|e| EcashApiError::ClientError(e.to_string()))?
.build::<nym_api_requests::models::RequestError>()
.map_err(|e| EcashApiError::ClientError(e.to_string()))?;
Ok(EcashApiClient {
api_client,
verification_key: VerificationKeyAuth::try_from_bs58(&share.share)?,
@@ -1,7 +1,7 @@
use crate::nym_api::NymApiClientExt;
use crate::nyxd::contract_traits::MixnetQueryClient;
use crate::nyxd::error::NyxdError;
use crate::nyxd::Config as ClientConfig;
use crate::nym_api::NymApiClientExt;
use crate::{QueryHttpRpcNyxdClient, ValidatorClientError};
use colored::Colorize;
use core::fmt;
@@ -94,7 +94,10 @@ fn setup_connection_tests<H: BuildHasher + 'static>(
{
Ok(client) => Some(ClientForConnectionTest::Api(network, url, client)),
Err(err) => {
eprintln!("Failed to create API client for {}: {err}", network.network_name);
eprintln!(
"Failed to create API client for {}: {err}",
network.network_name
);
None
}
}
@@ -14,7 +14,6 @@ pub mod signing;
pub use crate::error::ValidatorClientError;
pub use crate::rpc::reqwest::ReqwestRpcClient;
pub use crate::signing::direct_wallet::DirectSecp256k1HdWallet;
pub use client::NymApiClient;
pub use client::{Client, Config, EcashApiClient};
pub use nym_api_requests::*;
pub use nym_http_api_client::UserAgent;
@@ -3,6 +3,7 @@
use crate::nym_api::error::NymAPIError;
use crate::nym_api::routes::{ecash, CORE_STATUS_COUNT, SINCE_ARG};
use crate::nym_nodes::SkimmedNodesWithMetadata;
use async_trait::async_trait;
use nym_api_requests::ecash::models::{
AggregatedCoinIndicesSignatureResponse, AggregatedExpirationDateSignatureResponse,
@@ -23,7 +24,6 @@ use nym_api_requests::nym_nodes::{
NodesByAddressesRequestBody, NodesByAddressesResponse, PaginatedCachedNodesResponseV1,
PaginatedCachedNodesResponseV2,
};
use crate::nym_nodes::SkimmedNodesWithMetadata;
use nym_api_requests::pagination::PaginatedResponse;
pub use nym_api_requests::{
ecash::{
@@ -38,7 +38,7 @@ pub use nym_api_requests::{
MixnodeStatusResponse, MixnodeUptimeHistoryResponse, RewardEstimationResponse,
StakeSaturationResponse, UptimeResponse,
},
nym_nodes::{CachedNodesResponse, SemiSkimmedNode, SkimmedNode},
nym_nodes::{CachedNodesResponse, SemiSkimmedNode, SemiSkimmedNodesWithMetadata, SkimmedNode},
NymNetworkDetailsResponse,
};
use nym_contracts_common::IdentityKey;
@@ -247,7 +247,9 @@ pub trait NymApiClientExt: ApiClient {
self.get_rewarded_set().await
}
async fn get_all_basic_nodes_with_metadata(&self) -> Result<SkimmedNodesWithMetadata, NymAPIError> {
async fn get_all_basic_nodes_with_metadata(
&self,
) -> Result<SkimmedNodesWithMetadata, NymAPIError> {
// unroll first loop iteration in order to obtain the metadata
let mut page = 0;
let res = self
@@ -271,7 +273,9 @@ pub trait NymApiClientExt: ApiClient {
// Create a custom error for inconsistent metadata
return Err(NymAPIError::EndpointFailure {
status: reqwest::StatusCode::INTERNAL_SERVER_ERROR,
error: nym_api_requests::models::RequestError::new("Inconsistent paged metadata"),
error: nym_api_requests::models::RequestError::new(
"Inconsistent paged metadata",
),
});
}
@@ -286,6 +290,96 @@ pub trait NymApiClientExt: ApiClient {
Ok(SkimmedNodesWithMetadata::new(nodes, metadata))
}
async fn get_all_basic_active_mixing_assigned_nodes_with_metadata(
&self,
) -> Result<SkimmedNodesWithMetadata, NymAPIError> {
// Get all mixing nodes that are in the active/rewarded set
let mut page = 0;
let res = self
.get_basic_active_mixing_assigned_nodes_v2(false, Some(page), None, false)
.await?;
let metadata = res.metadata;
let mut nodes = res.nodes.data;
if res.nodes.pagination.total == nodes.len() {
return Ok(SkimmedNodesWithMetadata::new(nodes, metadata));
}
page += 1;
loop {
let res = self
.get_basic_active_mixing_assigned_nodes_v2(false, Some(page), None, false)
.await?;
if !metadata.consistency_check(&res.metadata) {
return Err(NymAPIError::EndpointFailure {
status: reqwest::StatusCode::INTERNAL_SERVER_ERROR,
error: nym_api_requests::models::RequestError::new(
"Inconsistent paged metadata",
),
});
}
nodes.append(&mut res.nodes.data.clone());
// Check if we've got all nodes
if nodes.len() >= res.nodes.pagination.total {
break;
} else {
page += 1;
}
}
Ok(SkimmedNodesWithMetadata::new(nodes, metadata))
}
async fn get_all_basic_entry_assigned_nodes_with_metadata(
&self,
) -> Result<SkimmedNodesWithMetadata, NymAPIError> {
// Get all nodes that can act as entry gateways
let mut page = 0;
let res = self
.get_basic_entry_assigned_nodes_v2(false, Some(page), None, false)
.await?;
let metadata = res.metadata;
let mut nodes = res.nodes.data;
if res.nodes.pagination.total == nodes.len() {
return Ok(SkimmedNodesWithMetadata::new(nodes, metadata));
}
page += 1;
loop {
let res = self
.get_basic_entry_assigned_nodes_v2(false, Some(page), None, false)
.await?;
if !metadata.consistency_check(&res.metadata) {
return Err(NymAPIError::EndpointFailure {
status: reqwest::StatusCode::INTERNAL_SERVER_ERROR,
error: nym_api_requests::models::RequestError::new(
"Inconsistent paged metadata",
),
});
}
nodes.append(&mut res.nodes.data.clone());
// Check if we've got all nodes
if nodes.len() >= res.nodes.pagination.total {
break;
} else {
page += 1;
}
}
Ok(SkimmedNodesWithMetadata::new(nodes, metadata))
}
async fn get_all_described_nodes(&self) -> Result<Vec<NymNodeDescription>, NymAPIError> {
// TODO: deal with paging in macro or some helper function or something, because it's the same pattern everywhere
let mut page = 0;
@@ -1435,6 +1529,38 @@ pub trait NymApiClientExt: ApiClient {
)
.await
}
/// Method to change the base API URLs being used by the client
fn change_base_urls(&mut self, urls: Vec<url::Url>);
/// Retrieve expanded information for all bonded nodes on the network
async fn get_all_expanded_nodes(&self) -> Result<SemiSkimmedNodesWithMetadata, NymAPIError> {
// Unroll the first iteration to get the metadata
let mut page = 0;
let res = self.get_expanded_nodes(false, Some(page), None).await?;
let mut nodes = res.nodes.data;
let metadata = res.metadata;
if res.nodes.pagination.total == nodes.len() {
return Ok(SemiSkimmedNodesWithMetadata::new(nodes, metadata));
}
page += 1;
loop {
let mut res = self.get_expanded_nodes(false, Some(page), None).await?;
nodes.append(&mut res.nodes.data);
if nodes.len() < res.nodes.pagination.total {
page += 1
} else {
break;
}
}
Ok(SemiSkimmedNodesWithMetadata::new(nodes, metadata))
}
}
// Client is already nym_http_api_client::Client (re-exported above), so just one impl needed
@@ -1444,4 +1570,8 @@ impl NymApiClientExt for nym_http_api_client::Client {
fn api_url(&self) -> &url::Url {
self.current_url().as_ref()
}
fn change_base_urls(&mut self, urls: Vec<url::Url>) {
self.change_base_urls(urls.into_iter().map(|u| u.into()).collect());
}
}
+1 -1
View File
@@ -2,12 +2,12 @@
// SPDX-License-Identifier: Apache-2.0
use crate::context::errors::ContextError;
pub use nym_http_api_client::Client as NymApiClient;
use nym_network_defaults::{
setup_env,
var_names::{MIXNET_CONTRACT_ADDRESS, NYM_API, NYXD, VESTING_CONTRACT_ADDRESS},
NymNetworkDetails,
};
pub use nym_http_api_client::Client as NymApiClient;
use nym_validator_client::nyxd::{self, AccountId, NyxdClient};
use nym_validator_client::{
DirectSigningHttpRpcNyxdClient, DirectSigningHttpRpcValidatorClient, QueryHttpRpcNyxdClient,
+1 -1
View File
@@ -4,7 +4,7 @@
use crate::ecash::bandwidth::issued::CURRENT_SERIALIZATION_REVISION;
use nym_credentials_interface::CompactEcashError;
use nym_crypto::asymmetric::x25519::KeyRecoveryError;
use nym_validator_client::{ValidatorClientError, nym_api::error::NymAPIError};
use nym_validator_client::{nym_api::error::NymAPIError, ValidatorClientError};
use thiserror::Error;
#[derive(Debug, Error)]
+1
View File
@@ -22,6 +22,7 @@ url = { workspace = true }
nym-validator-client = { path = "../client-libs/validator-client" }
nym-network-defaults = { path = "../network-defaults" }
nym-ecash-signer-check-types = { path = "../ecash-signer-check-types" }
nym-http-api-client = { path = "../http-api-client" }
[lints]
workspace = true
+31 -25
View File
@@ -1,15 +1,14 @@
// Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::{LocalChainStatus, SigningStatus, TypedSignerResult};
use crate::{LocalChainStatus, SignerCheckError, SigningStatus, TypedSignerResult};
use nym_ecash_signer_check_types::dealer_information::RawDealerInformation;
use nym_ecash_signer_check_types::status::{SignerStatus, SignerTestResult};
use nym_validator_client::client::NymApiClientExt;
use nym_validator_client::models::BinaryBuildInformationOwned;
use nym_validator_client::nym_api::NymApiClientExt;
use nym_validator_client::nyxd::contract_traits::dkg_query_client::{
ContractVKShare, DealerDetails,
};
use nym_validator_client::NymApiClient;
use std::time::Duration;
use tracing::{error, warn};
use url::Url;
@@ -32,37 +31,38 @@ pub(crate) mod signing_status {
}
struct ClientUnderTest {
api_client: NymApiClient,
api_client: nym_http_api_client::Client,
build_info: Option<BinaryBuildInformationOwned>,
}
impl ClientUnderTest {
pub(crate) fn new(api_url: &Url) -> Self {
ClientUnderTest {
api_client: NymApiClient::new(api_url.clone()),
pub(crate) fn new(api_url: &Url) -> Result<Self, SignerCheckError> {
// The builder should not fail with a valid URL that's already parsed
// If it does fail, it's an internal error that we can't recover from
let api_client = nym_http_api_client::Client::builder(api_url.clone())?.build()?;
Ok(ClientUnderTest {
api_client,
build_info: None,
}
})
}
pub(crate) async fn try_retrieve_build_information(&mut self) -> bool {
match tokio::time::timeout(
Duration::from_secs(5),
self.api_client.nym_api.build_information(),
)
.await
match tokio::time::timeout(Duration::from_secs(5), self.api_client.build_information())
.await
{
Ok(Ok(build_information)) => {
self.build_info = Some(build_information);
true
}
Ok(Err(err)) => {
warn!("{}: failed to retrieve build information: {err}. the signer is most likely down", self.api_client.api_url());
warn!("{}: failed to retrieve build information: {err}. the signer is most likely down", self.api_client.current_url());
false
}
Err(_timeout) => {
warn!(
"{}: timed out while attempting to retrieve build information",
self.api_client.api_url()
self.api_client.current_url()
);
false
}
@@ -77,7 +77,7 @@ impl ClientUnderTest {
.inspect_err(|err| {
error!(
"ecash signer '{}' reports invalid version {}: {err}",
self.api_client.api_url(),
self.api_client.current_url(),
build_info.build_version
)
})
@@ -121,14 +121,14 @@ impl ClientUnderTest {
// check if it supports the current query
if self.supports_chain_status_query() {
return match self.api_client.nym_api.get_chain_blocks_status().await {
return match self.api_client.get_chain_blocks_status().await {
Ok(status) => LocalChainStatus::Reachable {
response: Box::new(status),
},
Err(err) => {
warn!(
"{}: failed to retrieve local chain status: {err}",
self.api_client.api_url()
self.api_client.current_url()
);
LocalChainStatus::Unreachable
}
@@ -136,14 +136,14 @@ impl ClientUnderTest {
}
// fallback to the legacy query
match self.api_client.nym_api.get_chain_status().await {
match self.api_client.get_chain_status().await {
Ok(status) => LocalChainStatus::ReachableLegacy {
response: Box::new(status),
},
Err(err) => {
warn!(
"{}: failed to retrieve [legacy] local chain status: {err}",
self.api_client.api_url()
self.api_client.current_url()
);
LocalChainStatus::Unreachable
}
@@ -158,14 +158,14 @@ impl ClientUnderTest {
// check if it supports the current query
if self.supports_signing_status_query() {
return match self.api_client.nym_api.get_signer_status().await {
return match self.api_client.get_signer_status().await {
Ok(response) => SigningStatus::Reachable {
response: Box::new(response),
},
Err(err) => {
warn!(
"{}: failed to retrieve signer chain status: {err}",
self.api_client.api_url()
self.api_client.current_url()
);
SigningStatus::Unreachable
}
@@ -173,14 +173,14 @@ impl ClientUnderTest {
}
// fallback to the legacy query
match self.api_client.nym_api.get_signer_information().await {
match self.api_client.get_signer_information().await {
Ok(status) => SigningStatus::ReachableLegacy {
response: Box::new(status),
},
Err(err) => {
warn!(
"{}: failed to retrieve [legacy] signer chain status: {err}",
self.api_client.api_url()
self.api_client.current_url()
);
// NOTE: this might equally mean the signing is disabled
SigningStatus::Unreachable
@@ -201,7 +201,13 @@ pub(crate) async fn check_client(
return SignerStatus::ProvidedInvalidDetails.with_details(dealer_information, dkg_epoch);
};
let mut client = ClientUnderTest::new(&parsed_information.announce_address);
let mut client = match ClientUnderTest::new(&parsed_information.announce_address) {
Ok(client) => client,
Err(err) => {
error!("failed to create client instance: {err}");
return SignerStatus::Unreachable.with_details(dealer_information, dkg_epoch);
}
};
// 8. check basic connection status - can you retrieve build information?
if !client.try_retrieve_build_information().await {
+7
View File
@@ -1,6 +1,7 @@
// Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use nym_http_api_client::HttpClientError;
use nym_validator_client::nyxd::error::NyxdError;
use thiserror::Error;
@@ -11,6 +12,12 @@ pub enum SignerCheckError {
#[error("failed to query the DKG contract: {source}")]
DKGContractQueryFailure { source: NyxdError },
#[error("failed to build client: {source}")]
HttpClient {
#[from]
source: HttpClientError,
},
}
impl SignerCheckError {
+25 -14
View File
@@ -409,15 +409,22 @@ impl ClientBuilder {
/// Create a client builder from network details with sensible defaults
#[cfg(feature = "network-defaults")]
pub fn from_network(network: &nym_network_defaults::NymNetworkDetails) -> Result<Self, HttpClientError> {
let urls = network.nym_api_urls
pub fn from_network(
network: &nym_network_defaults::NymNetworkDetails,
) -> Result<Self, HttpClientError> {
let urls = network
.nym_api_urls
.as_ref()
.ok_or_else(|| HttpClientError::GenericRequestFailure("No API URLs configured in network details".to_string()))?
.ok_or_else(|| {
HttpClientError::GenericRequestFailure(
"No API URLs configured in network details".to_string(),
)
})?
.iter()
.map(|api_url| {
// Convert ApiUrl to our Url type with fronting support
let mut url = Url::parse(&api_url.url)?;
// Add fronting domains if available
#[cfg(feature = "tunneling")]
if let Some(ref front_hosts) = api_url.front_hosts {
@@ -428,19 +435,19 @@ impl ClientBuilder {
url = Url::new(api_url.url.clone(), Some(fronts))
.map_err(|e| HttpClientError::GenericRequestFailure(e.to_string()))?;
}
Ok(url)
})
.collect::<Result<Vec<_>, HttpClientError>>()?;
let mut builder = Self::new_with_urls(urls);
// Enable domain fronting by default (on retry)
#[cfg(feature = "tunneling")]
{
builder = builder.with_fronting(FrontPolicy::OnRetry);
}
Ok(builder)
}
@@ -757,7 +764,7 @@ impl Client {
/// this method. For example, if the client is configured to rotate hosts after each error, this
/// method should be called after the host has been updated -- i.e. as part of the subsequent
/// send.
fn apply_hosts_to_req(&self, r: &mut reqwest::Request) {
fn apply_hosts_to_req(&self, r: &mut reqwest::Request) -> (&str, Option<&str>) {
let url = self.current_url();
r.url_mut().set_host(url.host_str()).unwrap();
@@ -766,24 +773,28 @@ impl Client {
if front.is_enabled() {
let front_host = url.front_str().unwrap_or("");
let actual_host = url.host_str().unwrap_or("");
tracing::debug!(
"Domain fronting enabled: routing via CDN {} to actual host {}",
front_host,
actual_host
);
// this should never fail as we are transplanting the host from one url to another
r.url_mut().set_host(Some(front_host)).unwrap();
let actual_host_header: HeaderValue = actual_host
.parse()
.unwrap_or(HeaderValue::from_static(""));
let actual_host_header: HeaderValue =
actual_host.parse().unwrap_or(HeaderValue::from_static(""));
// If the map did have this key present, the new value is associated with the key
// and all previous values are removed. (reqwest HeaderMap docs)
_ = r.headers_mut().insert(reqwest::header::HOST, actual_host_header);
_ = r
.headers_mut()
.insert(reqwest::header::HOST, actual_host_header);
return (url.as_str(), url.front_str());
}
}
(url.as_str(), None)
}
}
+7 -1
View File
@@ -190,7 +190,13 @@ impl NymNetworkDetails {
},
nym_vpn_api_url: parse_optional_str(mainnet::NYM_VPN_API),
nym_api_urls: Some(mainnet::NYM_APIS.iter().copied().map(Into::into).collect()),
nym_vpn_api_urls: Some(mainnet::NYM_VPN_APIS.iter().copied().map(Into::into).collect()),
nym_vpn_api_urls: Some(
mainnet::NYM_VPN_APIS
.iter()
.copied()
.map(Into::into)
.collect(),
),
}
}
+11 -10
View File
@@ -135,16 +135,17 @@ impl VerlocMeasurer {
let mut api_endpoints = self.config.nym_api_urls.clone();
api_endpoints.shuffle(&mut thread_rng());
for api_endpoint in api_endpoints {
let client = match nym_http_api_client::Client::builder(api_endpoint.clone())
.and_then(|b| b.with_user_agent(self.config.user_agent.clone())
.build::<nym_api_requests::models::RequestError>())
{
Ok(c) => c,
Err(err) => {
warn!("failed to create client for {api_endpoint}: {err}");
continue;
}
};
let client =
match nym_http_api_client::Client::builder(api_endpoint.clone()).and_then(|b| {
b.with_user_agent(self.config.user_agent.clone())
.build::<nym_api_requests::models::RequestError>()
}) {
Ok(c) => c,
Err(err) => {
warn!("failed to create client for {api_endpoint}: {err}");
continue;
}
};
match client.get_all_described_nodes().await {
Ok(res) => return Some(res),
Err(err) => {
+6
View File
@@ -37,6 +37,12 @@ pub enum WasmCoreError {
source: ValidatorClientError,
},
#[error("failed to query nym api: {source}")]
NymApiQueryError {
#[from]
source: nym_validator_client::nym_api::error::NymAPIError,
},
#[error("The provided wasm topology was invalid: {source}")]
WasmTopologyError {
#[from]
+15 -4
View File
@@ -19,9 +19,9 @@ use nym_client_core::init::{
use nym_sphinx::addressing::clients::Recipient;
use nym_sphinx::anonymous_replies::requests::AnonymousSenderTag;
use nym_topology::wasm_helpers::WasmFriendlyNymTopology;
use nym_topology::{NymTopology, RoutingNode};
use nym_topology::{NymTopology, RoutingNode, EpochRewardedSet};
use nym_validator_client::client::IdentityKey;
use nym_validator_client::{NymApiClient, UserAgent};
use nym_validator_client::{nym_api::NymApiClientExt, UserAgent};
use rand::thread_rng;
use url::Url;
use wasm_bindgen::prelude::wasm_bindgen;
@@ -72,7 +72,17 @@ pub async fn current_network_topology_async(
}
};
let api_client = NymApiClient::new(url);
let api_client =
nym_http_api_client::Client::builder::<_, nym_validator_client::models::RequestError>(url.clone())
.map_err(|_err| WasmCoreError::MalformedUrl {
raw: nym_api_url.to_string(),
source: url::ParseError::EmptyHost,
})?
.build::<nym_validator_client::models::RequestError>()
.map_err(|_err| WasmCoreError::MalformedUrl {
raw: nym_api_url.to_string(),
source: url::ParseError::EmptyHost,
})?;
let rewarded_set = api_client.get_current_rewarded_set().await?;
let mixnodes_res = api_client
.get_all_basic_active_mixing_assigned_nodes_with_metadata()
@@ -90,7 +100,8 @@ pub async fn current_network_topology_async(
let gateways = gateways_res.nodes;
let topology = NymTopology::new(metadata.to_topology_metadata(), rewarded_set, Vec::new())
let epoch_rewarded_set: EpochRewardedSet = rewarded_set.into();
let topology = NymTopology::new(metadata.to_topology_metadata(), epoch_rewarded_set, Vec::new())
.with_skimmed_nodes(&mixnodes)
.with_skimmed_nodes(&gateways);
+1 -1
View File
@@ -21,6 +21,7 @@ pub use nym_client_core::{
pub use nym_gateway_client::{
error::GatewayClientError, GatewayClient, GatewayClientConfig, GatewayConfig,
};
pub use nym_http_api_client::Client as ApiClient;
pub use nym_sphinx::{
addressing::{clients::Recipient, nodes::NodeIdentity},
params::PacketType,
@@ -29,7 +30,6 @@ pub use nym_sphinx::{
pub use nym_statistics_common::clients::ClientStatsSender;
pub use nym_task;
pub use nym_topology::{HardcodedTopologyProvider, MixLayer, NymTopology, TopologyProvider};
pub use nym_http_api_client::Client as ApiClient;
pub use nym_validator_client::{DirectSigningReqwestRpcNyxdClient, QueryReqwestRpcNyxdClient};
// TODO: that's a very nasty import path. it should come from contracts instead!
pub use nym_validator_client::client::IdentityKey;
+2 -2
View File
@@ -139,9 +139,9 @@ mod tests {
fn add_dummy_mixes_with_delegations(test: &mut TestSetup, delegators: usize, mixes: usize) {
for i in 0..mixes {
let mix_id = test.add_legacy_mixnode(&test.make_addr(format!("mix-owner{}", i)), None);
let mix_id = test.add_legacy_mixnode(&test.make_addr(format!("mix-owner{i}")), None);
for delegator in 0..delegators {
let name = &test.make_addr(format!("delegator{}", delegator));
let name = &test.make_addr(format!("delegator{delegator}"));
test.add_immediate_delegation(name, 100_000_000u32, mix_id)
}
}
+4 -4
View File
@@ -503,8 +503,8 @@ pub(crate) mod tests {
storage,
id,
&UnbondedMixnode {
identity_key: format!("dummy{}", id),
owner: Addr::unchecked(format!("dummy{}", id)),
identity_key: format!("dummy{id}"),
owner: Addr::unchecked(format!("dummy{id}")),
proxy: None,
unbonding_height: 123,
},
@@ -570,7 +570,7 @@ pub(crate) mod tests {
storage,
id,
&UnbondedMixnode {
identity_key: format!("dummy{}", id),
identity_key: format!("dummy{id}"),
owner: owner.clone(),
proxy: None,
unbonding_height: 123,
@@ -817,7 +817,7 @@ pub(crate) mod tests {
id,
&UnbondedMixnode {
identity_key: identity.to_string(),
owner: Addr::unchecked(format!("dummy{}", id)),
owner: Addr::unchecked(format!("dummy{id}")),
proxy: None,
unbonding_height: 123,
},
+7 -7
View File
@@ -165,9 +165,9 @@ pub mod test_helpers {
#[track_caller]
pub fn assert_eq_with_leeway(a: Uint128, b: Uint128, leeway: Uint128) {
if a > b {
assert!(a - b <= leeway, "{} != {}", a, b)
assert!(a - b <= leeway, "{a} != {b}")
} else {
assert!(b - a <= leeway, "{} != {}", a, b)
assert!(b - a <= leeway, "{a} != {b}")
}
}
@@ -175,9 +175,9 @@ pub mod test_helpers {
pub fn assert_decimals(a: Decimal, b: Decimal) {
let epsilon = Decimal::from_ratio(1u128, 100_000_000u128);
if a > b {
assert!(a - b < epsilon, "{} != {}", a, b)
assert!(a - b < epsilon, "{a} != {b}")
} else {
assert!(b - a < epsilon, "{} != {}", a, b)
assert!(b - a < epsilon, "{a} != {b}")
}
}
@@ -1699,7 +1699,7 @@ pub mod test_helpers {
deps.branch(),
&env,
env.block.height,
Addr::unchecked(format!("owner{}", i)),
Addr::unchecked(format!("owner{i}")),
mix_id,
tests::fixtures::good_mixnode_pledge().pop().unwrap(),
)
@@ -1713,7 +1713,7 @@ pub mod test_helpers {
n: usize,
) {
for i in 0..n {
add_unbonded_mixnode(&mut rng, deps.branch(), None, &addr(format!("owner{}", i)));
add_unbonded_mixnode(&mut rng, deps.branch(), None, &addr(format!("owner{i}")));
}
}
@@ -1765,7 +1765,7 @@ pub mod test_helpers {
id,
&UnbondedMixnode {
identity_key: identity_key
.unwrap_or(&*format!("identity{}", id))
.unwrap_or(&*format!("identity{id}"))
.to_string(),
owner: Addr::unchecked(owner),
proxy: None,
@@ -20,16 +20,22 @@ use nym_sdk::mixnet;
use nym_sdk::mixnet::MixnetMessageSender;
use nym_topology::provider_trait::{async_trait, TopologyProvider};
use nym_topology::{nym_topology_from_detailed, NymTopology};
use nym_validator_client::nym_api::NymApiClientExt;
use url::Url;
struct MyTopologyProvider {
validator_client: nym_validator_client::client::NymApiClient,
validator_client: nym_http_api_client::Client,
}
impl MyTopologyProvider {
fn new(nym_api_url: Url) -> MyTopologyProvider {
let validator_client = nym_http_api_client::Client::builder::<_, nym_validator_client::models::RequestError>(nym_api_url)
.expect("Failed to create API client builder")
.build::<nym_validator_client::models::RequestError>()
.expect("Failed to build API client");
MyTopologyProvider {
validator_client: nym_validator_client::client::NymApiClient::new(nym_api_url),
validator_client,
}
}
+1 -1
View File
@@ -27,7 +27,6 @@ use nym_api_requests::ecash::models::{
};
use nym_api_requests::ecash::BlindSignRequestBody;
use nym_coconut_dkg_common::types::EpochId;
use nym_validator_client::nym_api::NymApiClientExt;
use nym_compact_ecash::scheme::coin_indices_signatures::{
aggregate_annotated_indices_signatures, sign_coin_indices, CoinIndexSignatureShare,
};
@@ -47,6 +46,7 @@ use nym_ecash_contract_common::redeem_credential::BATCH_REDEMPTION_PROPOSAL_TITL
use nym_ecash_time::{ecash_default_expiration_date, ecash_today_date};
use nym_task::TaskClient;
use nym_ticketbooks_merkle::{IssuedTicketbook, IssuedTicketbooksFullMerkleProof, MerkleLeaf};
use nym_validator_client::nym_api::NymApiClientExt;
use nym_validator_client::nyxd::AccountId;
use nym_validator_client::EcashApiClient;
use rand::{thread_rng, RngCore};
+4 -1
View File
@@ -1148,7 +1148,10 @@ impl DummyCommunicationChannel {
cosmos_address: AccountId,
) -> Self {
let client = EcashApiClient {
api_client: nym_http_api_client::Client::new("http://localhost:1234".parse().unwrap(), None),
api_client: nym_http_api_client::Client::new(
"http://localhost:1234".parse().unwrap(),
None,
),
verification_key: aggregated_verification_key,
node_id: 1,
cosmos_address,
@@ -15,8 +15,8 @@ use nym_credentials::IssuanceTicketBook;
use nym_credentials_interface::Base58;
use nym_crypto::asymmetric::ed25519;
use nym_validator_client::ecash::BlindSignRequestBody;
use nym_validator_client::nyxd::Coin;
use nym_validator_client::nym_api::NymApiClientExt;
use nym_validator_client::nyxd::Coin;
use rand::rngs::OsRng;
use std::collections::HashMap;
use std::sync::Arc;
@@ -2,7 +2,7 @@
// SPDX-License-Identifier: GPL-3.0-only
use nym_validator_client::coconut::EcashApiError;
use nym_validator_client::nym_api::{EpochId, error::NymAPIError};
use nym_validator_client::nym_api::{error::NymAPIError, EpochId};
use nym_validator_client::nyxd::error::NyxdError;
use std::io;
use std::net::SocketAddr;
@@ -28,11 +28,11 @@ use nym_credentials::ecash::utils::{ecash_today, EcashTime};
use nym_credentials::{
AggregatedCoinIndicesSignatures, AggregatedExpirationDateSignatures, EpochVerificationKey,
};
use nym_validator_client::nym_api::NymApiClientExt;
use nym_credentials_interface::VerificationKeyAuth;
use nym_ecash_contract_common::msg::ExecuteMsg;
use nym_validator_client::coconut::EcashApiError;
use nym_validator_client::nym_api::EpochId;
use nym_validator_client::nym_api::NymApiClientExt;
use nym_validator_client::nyxd::contract_traits::dkg_query_client::Epoch;
use nym_validator_client::nyxd::contract_traits::{
DkgQueryClient, EcashQueryClient, NymContractsProvider, PagedDkgQueryClient,
+12 -7
View File
@@ -6,6 +6,7 @@ use log::{info, warn};
use nym_bin_common::bin_info;
use nym_client_core::config::ForgetMe;
use nym_crypto::asymmetric::ed25519::PrivateKey;
use nym_mixnet_contract_common::EpochRewardedSet;
use nym_network_defaults::setup_env;
use nym_network_defaults::var_names::NYM_API;
use nym_sdk::mixnet::{self, MixnetClient};
@@ -14,7 +15,6 @@ use nym_topology::provider_trait::ToTopologyMetadata;
use nym_topology::{HardcodedTopologyProvider, NymTopology};
use nym_validator_client::nym_api::NymApiClientExt;
use nym_validator_client::UserAgent;
use nym_mixnet_contract_common::EpochRewardedSet;
use std::fs::File;
use std::io::Write;
use std::sync::LazyLock;
@@ -163,9 +163,12 @@ async fn nym_topology_from_env() -> anyhow::Result<NymTopology> {
let api_url = std::env::var(NYM_API)?;
info!("Generating topology from {api_url}");
let client = nym_http_api_client::Client::builder::<_, nym_validator_client::models::RequestError>(api_url)?
.with_user_agent(UserAgent::from(bin_info!()))
.build::<nym_validator_client::models::RequestError>()?;
let client = nym_http_api_client::Client::builder::<
_,
nym_validator_client::models::RequestError,
>(api_url)?
.with_user_agent(UserAgent::from(bin_info!()))
.build::<nym_validator_client::models::RequestError>()?;
let rewarded_set = client.get_current_rewarded_set().await?;
@@ -177,10 +180,12 @@ async fn nym_topology_from_env() -> anyhow::Result<NymTopology> {
// Convert RewardedSetResponse to EpochRewardedSet which can then be converted to CachedEpochRewardedSet
let epoch_rewarded_set: EpochRewardedSet = rewarded_set.into();
Ok(
NymTopology::new(metadata.to_topology_metadata(), epoch_rewarded_set, Vec::new())
.with_skimmed_nodes(&nodes),
Ok(NymTopology::new(
metadata.to_topology_metadata(),
epoch_rewarded_set,
Vec::new(),
)
.with_skimmed_nodes(&nodes))
}
#[tokio::main]
+10 -15
View File
@@ -10,7 +10,6 @@ use nym_task::ShutdownToken;
use nym_validator_client::client::NymApiClientExt;
use nym_validator_client::models::{KeyRotationInfoResponse, NodeRefreshBody};
use nym_validator_client::nym_api::error::NymAPIError;
use nym_validator_client::NymApiClient;
use rand::prelude::SliceRandom;
use rand::thread_rng;
use std::sync::Arc;
@@ -27,7 +26,7 @@ pub struct NymApisClient {
struct InnerClient {
// NOTE: this was implemented before the internal http client supported multiple URLs
active_client: NymApiClient,
active_client: Client,
available_urls: Vec<Url>,
shutdown_token: ShutdownToken,
currently_used_api: usize,
@@ -45,7 +44,7 @@ impl NymApisClient {
let mut urls = nym_apis.to_vec();
urls.shuffle(&mut thread_rng());
let active_client = nym_http_api_client::Client::builder(urls[0].clone())?
let active_client = Client::builder(urls[0].clone())?
.no_hickory_dns()
.with_user_agent(NymNode::user_agent())
.with_timeout(Duration::from_secs(5))
@@ -53,7 +52,7 @@ impl NymApisClient {
Ok(NymApisClient {
inner: Arc::new(RwLock::new(InnerClient {
active_client: NymApiClient::from(active_client),
active_client: active_client.clone(),
available_urls: urls,
shutdown_token,
currently_used_api: 0,
@@ -90,7 +89,7 @@ impl NymApisClient {
let mut guard = self.inner.write().await;
let next_url = guard.available_urls[last_working_endpoint].clone();
guard.currently_used_api = last_working_endpoint;
guard.active_client.change_nym_api(next_url);
guard.active_client.change_base_urls(vec![next_url.into()]);
}
Ok(res)
@@ -123,10 +122,8 @@ impl InnerClient {
{
let broadcast_fut =
stream::iter(self.available_urls.clone()).for_each_concurrent(None, |url| {
let nym_api = self
.active_client
.nym_api
.clone_with_new_url(url.clone().into());
let mut nym_api = self.active_client.clone();
nym_api.change_base_urls(vec![url.clone().into()]);
let req_fut = req(nym_api, request_body);
async move {
if let Err(err) = req_fut.await {
@@ -172,10 +169,8 @@ impl InnerClient {
.skip(last_working)
.chain(self.available_urls.iter().enumerate().take(last_working))
{
let nym_api = self
.active_client
.nym_api
.clone_with_new_url(url.clone().into());
let mut nym_api = self.active_client.clone();
nym_api.change_base_urls(vec![url.clone().into()]);
let timeout_fut = sleep(timeout_duration);
let query_fut = req(nym_api);
@@ -216,8 +211,8 @@ impl InnerClient {
}
}
impl AsRef<NymApiClient> for InnerClient {
fn as_ref(&self) -> &NymApiClient {
impl AsRef<Client> for InnerClient {
fn as_ref(&self) -> &Client {
&self.active_client
}
}
+7 -7
View File
@@ -7,6 +7,7 @@ use crate::node::routing_filter::network_filter::NetworkRoutingFilter;
use async_trait::async_trait;
use nym_crypto::asymmetric::ed25519;
use nym_gateway::node::UserAgent;
use nym_http_api_client::Client;
use nym_node_metrics::prometheus_wrapper::{PrometheusMetric, PROMETHEUS_METRICS};
use nym_noise::config::NoiseNetworkView;
use nym_task::ShutdownToken;
@@ -20,7 +21,7 @@ use nym_validator_client::nym_api::NymApiClientExt;
use nym_validator_client::nym_nodes::{
NodesByAddressesResponse, SemiSkimmedNode, SemiSkimmedNodesWithMetadata,
};
use nym_validator_client::{NymApiClient, ValidatorClientError};
use nym_validator_client::ValidatorClientError;
use std::collections::{HashMap, HashSet};
use std::net::{IpAddr, SocketAddr};
use std::ops::Deref;
@@ -35,7 +36,7 @@ use url::Url;
const LOCAL_NODE_ID: NodeId = 1234567890;
struct NodesQuerier {
client: NymApiClient,
client: Client,
nym_api_urls: Vec<Url>,
currently_used_api: usize,
}
@@ -49,7 +50,7 @@ impl NodesQuerier {
self.currently_used_api = (self.currently_used_api + 1) % self.nym_api_urls.len();
self.client
.change_nym_api(self.nym_api_urls[self.currently_used_api].clone())
.change_base_urls(self.nym_api_urls.iter().map(|u| u.clone().into()).collect())
}
async fn rewarded_set(&mut self) -> Result<EpochRewardedSet, ValidatorClientError> {
@@ -62,7 +63,7 @@ impl NodesQuerier {
if res.is_err() {
self.use_next_nym_api()
}
res
Ok(res?.into())
}
async fn current_nymnodes(
@@ -77,7 +78,7 @@ impl NodesQuerier {
if res.is_err() {
self.use_next_nym_api()
}
res
Ok(res?)
}
async fn query_for_info(
@@ -86,7 +87,6 @@ impl NodesQuerier {
) -> Result<NodesByAddressesResponse, ValidatorClientError> {
let res = self
.client
.nym_api
.nodes_by_addresses(ips)
.await
.inspect_err(|err| error!("failed to obtain node information: {err}"));
@@ -228,7 +228,7 @@ impl NetworkRefresher {
let mut this = NetworkRefresher {
querier: NodesQuerier {
client: NymApiClient::from(nym_api),
client: nym_api,
nym_api_urls,
currently_used_api: 0,
},
@@ -8,8 +8,8 @@ use crate::rewarder::ticketbook_issuance::types::CredentialIssuer;
use crate::rewarder::ticketbook_issuance::verifier::TicketbookIssuanceVerifier;
use crate::rewarder::Rewarder;
use anyhow::bail;
use nym_validator_client::nym_api::NymApiClientExt;
use nym_ecash_time::ecash_default_expiration_date;
use nym_validator_client::nym_api::NymApiClientExt;
use std::collections::HashSet;
use std::path::PathBuf;
use time::macros::format_description;
@@ -16,7 +16,6 @@ use nym_validator_client::nyxd::{
AccountId, Coin, CosmWasmClient, Hash, PageRequest, StakingQueryClient,
};
use nym_validator_client::{nyxd, DirectSigningHttpRpcNyxdClient};
use nym_validator_client::nym_api::NymApiClientExt;
use std::collections::HashMap;
use std::ops::Deref;
use std::sync::Arc;
@@ -145,7 +144,10 @@ impl NyxdClient {
{
Ok(client) => client,
Err(err) => {
error!("Failed to create API client for issuer {}: {}", info.assigned_index, err);
error!(
"Failed to create API client for issuer {}: {}",
info.assigned_index, err
);
continue;
}
};
@@ -6,8 +6,8 @@ use cosmwasm_std::{Addr, Decimal, Uint128};
use nym_coconut_dkg_common::types::NodeIndex;
use nym_compact_ecash::VerificationKeyAuth;
use nym_crypto::asymmetric::ed25519;
use nym_validator_client::nyxd::{AccountId, Coin};
use nym_validator_client::nym_api::NymApiClientExt;
use nym_validator_client::nyxd::{AccountId, Coin};
use std::fmt::{Display, Formatter};
use tracing::info;
@@ -16,9 +16,9 @@ use nym_validator_client::ecash::models::{
IssuedTicketbooksChallengeCommitmentResponse, IssuedTicketbooksDataRequestBody,
IssuedTicketbooksDataResponse, IssuedTicketbooksDataResponseBody, IssuedTicketbooksForResponse,
};
use nym_validator_client::nym_api::NymApiClientExt;
use nym_validator_client::nyxd::AccountId;
use nym_validator_client::signable::{SignableMessageBody, SignedMessage};
use nym_validator_client::nym_api::NymApiClientExt;
use rand::distributions::{Distribution, WeightedIndex};
use rand::prelude::SliceRandom;
use rand::thread_rng;
+1
View File
@@ -38,6 +38,7 @@ nym-socks5-client-core = { path = "../../../common/socks5-client-core" }
nym-validator-client = { path = "../../../common/client-libs/validator-client", features = [
"http-client",
] }
nym-http-api-client = { path = "../../../common/http-api-client" }
nym-socks5-requests = { path = "../../../common/socks5/requests" }
nym-ordered-buffer = { path = "../../../common/socks5/ordered-buffer" }
nym-service-providers-common = { path = "../../../service-providers/common" }
@@ -4,18 +4,25 @@
use nym_sdk::mixnet;
use nym_sdk::mixnet::MixnetMessageSender;
use nym_topology::provider_trait::{async_trait, ToTopologyMetadata, TopologyProvider};
use nym_topology::NymTopology;
use nym_topology::{EpochRewardedSet, NymTopology};
use nym_validator_client::nym_api::NymApiClientExt;
use url::Url;
struct MyTopologyProvider {
validator_client: nym_validator_client::client::NymApiClient,
validator_client: nym_http_api_client::Client,
}
impl MyTopologyProvider {
fn new(nym_api_url: Url) -> MyTopologyProvider {
MyTopologyProvider {
validator_client: nym_validator_client::client::NymApiClient::new(nym_api_url),
}
let validator_client = nym_http_api_client::Client::builder::<
_,
nym_validator_client::models::RequestError,
>(nym_api_url)
.expect("Failed to create API client builder")
.build::<nym_validator_client::models::RequestError>()
.expect("Failed to build API client");
MyTopologyProvider { validator_client }
}
async fn get_topology(&self) -> NymTopology {
@@ -33,7 +40,8 @@ impl MyTopologyProvider {
let metadata = mixnodes_response.metadata.to_topology_metadata();
let mut base_topology = NymTopology::new(metadata, rewarded_set, Vec::new());
let epoch_rewarded_set: EpochRewardedSet = rewarded_set.into();
let mut base_topology = NymTopology::new(metadata, epoch_rewarded_set, Vec::new());
// in our topology provider only use mixnodes that have node_id divisible by 3
// and has exactly 100 performance score
@@ -36,6 +36,7 @@ nym-crypto = { path = "../../../common/crypto", features = ["asymmetric", "rand"
nym-config = { path = "../../../common/config" }
nym-validator-client = { path = "../../../common/client-libs/validator-client" }
nym-compact-ecash = { path = "../../../common/nym_offline_compact_ecash" }
nym-http-api-client = { path = "../../../common/http-api-client" }
dkg-bypass-contract = { path = "dkg-bypass-contract", default-features = false }
# contracts:
@@ -7,7 +7,7 @@ use crate::manager::network::LoadedNetwork;
use crate::manager::NetworkManager;
use console::style;
use nym_config::{must_get_home, DEFAULT_CONFIG_DIR, DEFAULT_CONFIG_FILENAME, NYM_DIR};
use nym_validator_client::NymApiClient;
use nym_validator_client::nym_api::NymApiClientExt;
use rand::{thread_rng, RngCore};
use std::fs;
use std::fs::OpenOptions;
@@ -91,7 +91,13 @@ impl NetworkManager {
"⌛waiting for any gateway to appear in the directory ({api_url})..."
));
let api_client = NymApiClient::new(api_url);
let api_client = nym_http_api_client::Client::builder::<
_,
nym_validator_client::models::RequestError,
>(api_url.clone())
.expect("Failed to create API client builder")
.build::<nym_validator_client::models::RequestError>()
.expect("Failed to build API client");
let wait_fut = async {
let inner_fut = async {
@@ -25,6 +25,7 @@ time = { workspace = true }
nym-validator-client = { path = "../../../common/client-libs/validator-client" }
nym-bin-common = { path = "../../../common/bin-common", features = ["output_format", "basic_tracing"] }
nym-network-defaults = { path = "../../../common/network-defaults" }
nym-http-api-client = { path = "../../../common/http-api-client" }
[lints]
workspace = true
@@ -1,8 +1,7 @@
// Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
use nym_validator_client::client::NymApiClientExt;
use nym_validator_client::NymApiClient;
use nym_validator_client::nym_api::NymApiClientExt;
use serde::{Deserialize, Serialize};
use std::fmt::Display;
use strum::{Display, EnumProperty};
@@ -48,8 +47,8 @@ impl SignerStatus {
matches!(self.rpc_status, RpcStatus::Up)
}
fn build_api_client(&self) -> Option<NymApiClient> {
let api_endpoint = match self.api_endpoint.as_str().parse() {
fn build_api_client(&self) -> Option<nym_http_api_client::Client> {
let api_endpoint: nym_http_api_client::Url = match self.api_endpoint.as_str().parse() {
Ok(endpoint) => endpoint,
Err(err) => {
error!("{} is not a valid api endpoint: {err}", self.api_endpoint);
@@ -57,14 +56,19 @@ impl SignerStatus {
}
};
Some(NymApiClient::new(api_endpoint))
nym_http_api_client::Client::builder::<_, nym_validator_client::models::RequestError>(
api_endpoint,
)
.ok()?
.build::<nym_validator_client::models::RequestError>()
.ok()
}
pub(crate) async fn try_update_api_version(&mut self) {
let Some(client) = self.build_api_client() else {
return;
};
match client.nym_api.build_information().await {
match client.build_information().await {
Ok(build_info) => {
self.api_version = ApiVersion::Available {
version: build_info.build_version,
@@ -84,7 +88,7 @@ impl SignerStatus {
return;
};
match client.nym_api.get_chain_status().await {
match client.get_chain_status().await {
Ok(chain_status) => {
self.used_rpc_endpoint = RpcEndpoint(chain_status.connected_nyxd);
let last_block =