From 2569deb080e90b2800664cd787caad4c2271ae44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Mon, 4 Nov 2024 21:15:29 +0000 Subject: [PATCH] bugfix: [wallet] displaying delegations for native nymnodes (#5087) * fixed return type for getting nymnode details * fixed nym-api queries if using relative paths * fixed queries for delegations of native nymnodes --- .../validator-client/src/nym_api/mod.rs | 24 +++- .../contract_traits/mixnet_query_client.rs | 13 +- common/http-api-client/src/lib.rs | 1 + common/types/src/delegation.rs | 10 +- .../src/operations/mixnet/delegate.rs | 111 +++++++++++++----- 5 files changed, 115 insertions(+), 44 deletions(-) diff --git a/common/client-libs/validator-client/src/nym_api/mod.rs b/common/client-libs/validator-client/src/nym_api/mod.rs index 6556a80102..13a1ca7671 100644 --- a/common/client-libs/validator-client/src/nym_api/mod.rs +++ b/common/client-libs/validator-client/src/nym_api/mod.rs @@ -696,16 +696,32 @@ pub trait NymApiClientExt: ApiClient { &self, node_id: NodeId, ) -> Result { - self.get_json_from(format!("/v1/nym-nodes/performance/{node_id}")) - .await + self.get_json( + &[ + routes::API_VERSION, + "nym-nodes", + "performance", + &node_id.to_string(), + ], + NO_PARAMS, + ) + .await } async fn get_node_annotation( &self, node_id: NodeId, ) -> Result { - self.get_json_from(format!("/v1/nym-nodes/annotation/{node_id}")) - .await + self.get_json( + &[ + routes::API_VERSION, + "nym-nodes", + "annotation", + &node_id.to_string(), + ], + NO_PARAMS, + ) + .await } #[deprecated] diff --git a/common/client-libs/validator-client/src/nyxd/contract_traits/mixnet_query_client.rs b/common/client-libs/validator-client/src/nyxd/contract_traits/mixnet_query_client.rs index 21529ad086..b6fdadbce1 100644 --- a/common/client-libs/validator-client/src/nyxd/contract_traits/mixnet_query_client.rs +++ b/common/client-libs/validator-client/src/nyxd/contract_traits/mixnet_query_client.rs @@ -10,10 +10,10 @@ use cosmrs::AccountId; use nym_contracts_common::signing::Nonce; use nym_mixnet_contract_common::gateway::{PreassignedGatewayIdsResponse, PreassignedId}; use nym_mixnet_contract_common::nym_node::{ - EpochAssignmentResponse, NodeDetailsByIdentityResponse, NodeOwnershipResponse, - NodeRewardingDetailsResponse, PagedNymNodeBondsResponse, PagedNymNodeDetailsResponse, - PagedUnbondedNymNodesResponse, Role, RolesMetadataResponse, StakeSaturationResponse, - UnbondedNodeResponse, UnbondedNymNode, + EpochAssignmentResponse, NodeDetailsByIdentityResponse, NodeDetailsResponse, + NodeOwnershipResponse, NodeRewardingDetailsResponse, PagedNymNodeBondsResponse, + PagedNymNodeDetailsResponse, PagedUnbondedNymNodesResponse, Role, RolesMetadataResponse, + StakeSaturationResponse, UnbondedNodeResponse, UnbondedNymNode, }; use nym_mixnet_contract_common::reward_params::WorkFactor; use nym_mixnet_contract_common::{ @@ -316,10 +316,7 @@ pub trait MixnetQueryClient { .await } - async fn get_nymnode_details( - &self, - node_id: NodeId, - ) -> Result { + async fn get_nymnode_details(&self, node_id: NodeId) -> Result { self.query_mixnet_contract(MixnetQueryMsg::GetNymNodeDetails { node_id }) .await } diff --git a/common/http-api-client/src/lib.rs b/common/http-api-client/src/lib.rs index ce502c112a..549c843958 100644 --- a/common/http-api-client/src/lib.rs +++ b/common/http-api-client/src/lib.rs @@ -315,6 +315,7 @@ impl Client { parse_response(res, true).await } + #[instrument(level = "debug", skip_all)] pub async fn get_json_endpoint(&self, endpoint: S) -> Result> where for<'a> T: Deserialize<'a>, diff --git a/common/types/src/delegation.rs b/common/types/src/delegation.rs index f906c04cd1..3060a02e3a 100644 --- a/common/types/src/delegation.rs +++ b/common/types/src/delegation.rs @@ -3,7 +3,7 @@ use crate::deprecated::DelegationEvent; use crate::error::TypesError; use crate::mixnode::NodeCostParams; use cosmwasm_std::Decimal; -use nym_mixnet_contract_common::{Delegation as MixnetContractDelegation, NodeId}; +use nym_mixnet_contract_common::{Delegation as MixnetContractDelegation, NodeId, NodeRewarding}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; @@ -70,6 +70,14 @@ pub struct DelegationWithEverything { pub mixnode_is_unbonding: Option, } +pub struct NodeInformation { + pub owner: String, + pub mix_id: NodeId, + pub node_identity: String, + pub rewarding_details: NodeRewarding, + pub is_unbonding: bool, +} + #[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))] #[cfg_attr( feature = "generate-ts", diff --git a/nym-wallet/src-tauri/src/operations/mixnet/delegate.rs b/nym-wallet/src-tauri/src/operations/mixnet/delegate.rs index 6d960031fe..744aeb1bb7 100644 --- a/nym-wallet/src-tauri/src/operations/mixnet/delegate.rs +++ b/nym-wallet/src-tauri/src/operations/mixnet/delegate.rs @@ -7,7 +7,9 @@ use crate::vesting::delegate::vesting_undelegate_from_mixnode; use nym_mixnet_contract_common::mixnode::MixStakeSaturationResponse; use nym_mixnet_contract_common::NodeId; use nym_types::currency::DecCoin; -use nym_types::delegation::{Delegation, DelegationWithEverything, DelegationsSummaryResponse}; +use nym_types::delegation::{ + Delegation, DelegationWithEverything, DelegationsSummaryResponse, NodeInformation, +}; use nym_types::deprecated::{ convert_to_delegation_events, DelegationEvent, WrappedDelegationEvent, }; @@ -19,6 +21,7 @@ use nym_validator_client::nyxd::contract_traits::{ MixnetQueryClient, MixnetSigningClient, NymContractsProvider, PagedMixnetQueryClient, }; use nym_validator_client::nyxd::Fee; +use nym_validator_client::DirectSigningHttpRpcValidatorClient; use tap::TapFallible; #[tauri::command] @@ -141,6 +144,58 @@ pub async fn undelegate_all_from_mixnode( Ok(res) } +pub(crate) async fn get_node_information( + client: &DirectSigningHttpRpcValidatorClient, + node_id: NodeId, + error_strings: &mut Vec, +) -> Result, BackendError> { + let native_nymnode = client + .nyxd + .get_nymnode_details(node_id) + .await + .inspect_err(|err| { + let str_err = + format!("Failed to get nymnode details for node_id = {node_id}. Error: {err}"); + log::error!(" <<< {str_err}",); + error_strings.push(str_err); + })?; + + if let Some(native) = native_nymnode.details { + return Ok(Some(NodeInformation { + is_unbonding: native.is_unbonding(), + owner: native.bond_information.owner.to_string(), + mix_id: node_id, + node_identity: native.bond_information.node.identity_key, + rewarding_details: native.rewarding_details, + })); + } + + let legacy_mixnode = client + .nyxd + .get_mixnode_details(node_id) + .await + .inspect_err(|err| { + let str_err = format!( + "Failed to get legacy mixnode details for node_id = {node_id}. Error: {err}", + ); + log::error!(" <<< {}", str_err); + error_strings.push(str_err); + })? + .mixnode_details; + + if let Some(legacy) = legacy_mixnode { + return Ok(Some(NodeInformation { + is_unbonding: legacy.is_unbonding(), + owner: legacy.bond_information.owner.to_string(), + mix_id: node_id, + node_identity: legacy.bond_information.mix_node.identity_key, + rewarding_details: legacy.rewarding_details, + })); + } + + Ok(None) +} + // TODO: fix later (yeah...) #[allow(deprecated)] #[tauri::command] @@ -208,21 +263,9 @@ pub async fn get_all_mix_delegations( d.amount ); - let mixnode = client - .nyxd - .get_mixnode_details(d.mix_id) - .await - .tap_err(|err| { - let str_err = format!( - "Failed to get mixnode details for mix_id = {}. Error: {}", - d.mix_id, err - ); - log::error!(" <<< {}", str_err); - error_strings.push(str_err); - })? - .mixnode_details; + let node_details = get_node_information(client, d.mix_id, &mut error_strings).await?; - let accumulated_by_operator = mixnode + let accumulated_by_operator = node_details .as_ref() .map(|m| { guard.display_coin_from_base_decimal(&base_mix_denom, m.rewarding_details.operator) @@ -238,10 +281,13 @@ pub async fn get_all_mix_delegations( }) .unwrap_or_default(); - let accumulated_by_delegates = mixnode + let accumulated_by_delegates = node_details .as_ref() .map(|m| { - guard.display_coin_from_base_decimal(&base_mix_denom, m.rewarding_details.delegates) + reg.attempt_create_display_coin_from_base_dec_amount( + &base_mix_denom, + m.rewarding_details.delegates, + ) }) .transpose() .tap_err(|err| { @@ -254,7 +300,7 @@ pub async fn get_all_mix_delegations( }) .unwrap_or_default(); - let cost_params = mixnode + let cost_params = node_details .as_ref() .map(|m| { NodeCostParams::from_mixnet_contract_mixnode_cost_params( @@ -335,21 +381,26 @@ pub async fn get_all_mix_delegations( " >>> Get average uptime percentage: mix_iid = {}", d.mix_id ); - let avg_uptime_percent = client + + let current_performance = client .nym_api - .get_mixnode_avg_uptime(d.mix_id) + .get_current_node_performance(d.mix_id) .await - .tap_err(|err| { + .inspect_err(|err| { let str_err = format!( - "Failed to get average uptime percentage for mix_id = {}. Error: {}", - d.mix_id, err + "Failed to get current node performance for node_id = {}. Error: {err}", + d.mix_id ); log::error!(" <<< {}", str_err); error_strings.push(str_err); }) .ok() - .map(|r| r.avg_uptime); - log::trace!(" <<< {:?}", avg_uptime_percent); + .and_then(|r| r.performance); + + // convert to old u8 + let current_uptime = current_performance.map(|p| (p * 100.) as u8); + + log::trace!(" <<< {:?}", current_uptime); log::trace!( " >>> Convert delegated on block height to timestamp: block_height = {}", @@ -377,9 +428,9 @@ pub async fn get_all_mix_delegations( pending_events.len() ); - let mixnode_is_unbonding = mixnode.as_ref().map(|m| m.is_unbonding()); + let mixnode_is_unbonding = node_details.as_ref().map(|m| m.is_unbonding); log::trace!( - " >>> mixnode with mix_id: {} is unbonding: {:?}", + " >>> node with mix_id: {} is unbonding: {:?}", d.mix_id, mixnode_is_unbonding ); @@ -387,16 +438,14 @@ pub async fn get_all_mix_delegations( with_everything.push(DelegationWithEverything { owner: d.owner, mix_id: d.mix_id, - node_identity: mixnode - .map(|m| m.bond_information.mix_node.identity_key) - .unwrap_or_default(), + node_identity: node_details.map(|m| m.node_identity).unwrap_or_default(), amount: d.amount, block_height: d.height, uses_vesting_contract_tokens, delegated_on_iso_datetime, stake_saturation: stake_saturation.uncapped_saturation, accumulated_by_operator, - avg_uptime_percent, + avg_uptime_percent: current_uptime, accumulated_by_delegates, cost_params, unclaimed_rewards: accumulated_rewards,