diff --git a/Cargo.lock b/Cargo.lock index ca7a56a4d24..936dadfbd64 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6061,7 +6061,7 @@ dependencies = [ [[package]] name = "nym-node-status-api" -version = "1.0.0-rc.3" +version = "1.0.0-rc.4" dependencies = [ "anyhow", "axum 0.7.7", @@ -7019,9 +7019,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.102" +version = "0.9.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c597637d56fbc83893a35eb0dd04b2b8e7a50c91e64e9493e398b5df4fb45fa2" +checksum = "45abf306cbf99debc8195b66b7346498d7b10c210de50418b5ccd7ceba08c741" dependencies = [ "cc", "libc", diff --git a/common/client-core/src/client/topology_control/accessor.rs b/common/client-core/src/client/topology_control/accessor.rs index fcb272c9343..6b12d64562c 100644 --- a/common/client-core/src/client/topology_control/accessor.rs +++ b/common/client-core/src/client/topology_control/accessor.rs @@ -38,7 +38,7 @@ pub struct TopologyReadPermit<'a> { permit: RwLockReadGuard<'a, Option>, } -impl<'a> Deref for TopologyReadPermit<'a> { +impl Deref for TopologyReadPermit<'_> { type Target = Option; fn deref(&self) -> &Self::Target { diff --git a/common/client-libs/validator-client/src/nyxd/coin.rs b/common/client-libs/validator-client/src/nyxd/coin.rs index 0fa175a2436..8050273a51d 100644 --- a/common/client-libs/validator-client/src/nyxd/coin.rs +++ b/common/client-libs/validator-client/src/nyxd/coin.rs @@ -32,7 +32,7 @@ impl Div for Coin { } } -impl<'a> Div for &'a Coin { +impl Div for &Coin { type Output = Gas; fn div(self, rhs: GasPrice) -> Self::Output { diff --git a/common/client-libs/validator-client/src/nyxd/fee/gas_price.rs b/common/client-libs/validator-client/src/nyxd/fee/gas_price.rs index 4f0f2fd0a8e..3679cc7500b 100644 --- a/common/client-libs/validator-client/src/nyxd/fee/gas_price.rs +++ b/common/client-libs/validator-client/src/nyxd/fee/gas_price.rs @@ -22,7 +22,7 @@ pub struct GasPrice { pub denom: String, } -impl<'a> Mul for &'a GasPrice { +impl Mul for &GasPrice { type Output = Coin; fn mul(self, gas_limit: Gas) -> Self::Output { diff --git a/common/cosmwasm-smart-contracts/mixnet-contract/src/interval.rs b/common/cosmwasm-smart-contracts/mixnet-contract/src/interval.rs index e36935d66cf..2259af4c7a9 100644 --- a/common/cosmwasm-smart-contracts/mixnet-contract/src/interval.rs +++ b/common/cosmwasm-smart-contracts/mixnet-contract/src/interval.rs @@ -32,7 +32,7 @@ pub(crate) mod string_rfc3339_offset_date_time { struct Rfc3339OffsetDateTimeVisitor; - impl<'de> Visitor<'de> for Rfc3339OffsetDateTimeVisitor { + impl Visitor<'_> for Rfc3339OffsetDateTimeVisitor { type Value = OffsetDateTime; fn expecting(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result { diff --git a/common/dkg/src/bte/proof_chunking.rs b/common/dkg/src/bte/proof_chunking.rs index 6829a536605..1365aecbd78 100644 --- a/common/dkg/src/bte/proof_chunking.rs +++ b/common/dkg/src/bte/proof_chunking.rs @@ -26,9 +26,8 @@ const PARALLEL_RUNS: usize = 32; /// `lambda` ($\lambda$) in the DKG paper const SECURITY_PARAMETER: usize = 256; -// note: ceiling in integer division can be achieved via q = (x + y - 1) / y; /// ceil(SECURITY_PARAMETER / PARALLEL_RUNS) in the paper -const NUM_CHALLENGE_BITS: usize = (SECURITY_PARAMETER + PARALLEL_RUNS - 1) / PARALLEL_RUNS; +const NUM_CHALLENGE_BITS: usize = SECURITY_PARAMETER.div_ceil(PARALLEL_RUNS); // type alias for ease of use type FirstChallenge = Vec>>; diff --git a/common/dkg/src/interpolation/polynomial.rs b/common/dkg/src/interpolation/polynomial.rs index 33c7486a99e..08f748b6491 100644 --- a/common/dkg/src/interpolation/polynomial.rs +++ b/common/dkg/src/interpolation/polynomial.rs @@ -196,7 +196,7 @@ impl<'b> Add<&'b Polynomial> for Polynomial { } } -impl<'a> Add for &'a Polynomial { +impl Add for &Polynomial { type Output = Polynomial; fn add(self, rhs: Polynomial) -> Polynomial { @@ -212,7 +212,7 @@ impl Add for Polynomial { } } -impl<'a, 'b> Add<&'b Polynomial> for &'a Polynomial { +impl<'b> Add<&'b Polynomial> for &Polynomial { type Output = Polynomial; fn add(self, rhs: &'b Polynomial) -> Self::Output { diff --git a/common/gateway-requests/src/registration/handshake/mod.rs b/common/gateway-requests/src/registration/handshake/mod.rs index e5dc1dc59fa..4a6f44b7d7d 100644 --- a/common/gateway-requests/src/registration/handshake/mod.rs +++ b/common/gateway-requests/src/registration/handshake/mod.rs @@ -37,7 +37,7 @@ pub struct GatewayHandshake<'a> { handshake_future: BoxFuture<'a, Result>, } -impl<'a> Future for GatewayHandshake<'a> { +impl Future for GatewayHandshake<'_> { type Output = Result; fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { diff --git a/common/nym_offline_compact_ecash/src/scheme/coin_indices_signatures.rs b/common/nym_offline_compact_ecash/src/scheme/coin_indices_signatures.rs index b08ab368dcb..30c7fe5523c 100644 --- a/common/nym_offline_compact_ecash/src/scheme/coin_indices_signatures.rs +++ b/common/nym_offline_compact_ecash/src/scheme/coin_indices_signatures.rs @@ -324,18 +324,6 @@ pub fn unchecked_aggregate_indices_signatures( _aggregate_indices_signatures(params, vk, signatures_shares, false) } -/// Generates parameters for the scheme setup. -/// -/// # Arguments -/// -/// * `total_coins` - it is the number of coins in a freshly generated wallet. It is the public parameter of the scheme. -/// -/// # Returns -/// -/// A `Parameters` struct containing group parameters, public key, the number of signatures (`total_coins`), -/// and a map of signatures for each index `l`. -/// - #[cfg(test)] mod tests { use super::*; diff --git a/common/nym_offline_compact_ecash/src/scheme/keygen.rs b/common/nym_offline_compact_ecash/src/scheme/keygen.rs index e49c6309df8..8db1597e617 100644 --- a/common/nym_offline_compact_ecash/src/scheme/keygen.rs +++ b/common/nym_offline_compact_ecash/src/scheme/keygen.rs @@ -264,7 +264,7 @@ impl<'b> Add<&'b VerificationKeyAuth> for VerificationKeyAuth { } } -impl<'a> Mul for &'a VerificationKeyAuth { +impl Mul for &VerificationKeyAuth { type Output = VerificationKeyAuth; #[inline] diff --git a/common/nym_offline_compact_ecash/src/scheme/mod.rs b/common/nym_offline_compact_ecash/src/scheme/mod.rs index 8912bf91eb1..7f9687a380a 100644 --- a/common/nym_offline_compact_ecash/src/scheme/mod.rs +++ b/common/nym_offline_compact_ecash/src/scheme/mod.rs @@ -984,7 +984,7 @@ pub struct SerialNumberRef<'a> { pub(crate) inner: &'a [G1Projective], } -impl<'a> SerialNumberRef<'a> { +impl SerialNumberRef<'_> { pub fn to_bytes(&self) -> Vec { let ss_len = self.inner.len(); let mut bytes: Vec = Vec::with_capacity(ss_len * 48); diff --git a/common/nymcoconut/src/elgamal.rs b/common/nymcoconut/src/elgamal.rs index 55db7dcdd27..28943568cea 100644 --- a/common/nymcoconut/src/elgamal.rs +++ b/common/nymcoconut/src/elgamal.rs @@ -206,7 +206,7 @@ impl Deref for PublicKey { } } -impl<'a, 'b> Mul<&'b Scalar> for &'a PublicKey { +impl<'b> Mul<&'b Scalar> for &PublicKey { type Output = G1Projective; fn mul(self, rhs: &'b Scalar) -> Self::Output { diff --git a/common/nymcoconut/src/scheme/keygen.rs b/common/nymcoconut/src/scheme/keygen.rs index 85e057793da..f80c1311437 100644 --- a/common/nymcoconut/src/scheme/keygen.rs +++ b/common/nymcoconut/src/scheme/keygen.rs @@ -305,7 +305,7 @@ impl<'b> Add<&'b VerificationKey> for VerificationKey { } } -impl<'a> Mul for &'a VerificationKey { +impl Mul for &VerificationKey { type Output = VerificationKey; #[inline] diff --git a/common/nymsphinx/addressing/src/clients.rs b/common/nymsphinx/addressing/src/clients.rs index a739e7369e6..743302edbe1 100644 --- a/common/nymsphinx/addressing/src/clients.rs +++ b/common/nymsphinx/addressing/src/clients.rs @@ -64,7 +64,7 @@ impl<'de> Deserialize<'de> for Recipient { { struct RecipientVisitor; - impl<'de> Visitor<'de> for RecipientVisitor { + impl Visitor<'_> for RecipientVisitor { type Value = Recipient; fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result { diff --git a/common/nymsphinx/addressing/src/nodes.rs b/common/nymsphinx/addressing/src/nodes.rs index e0cd745ae99..1126cb7afd0 100644 --- a/common/nymsphinx/addressing/src/nodes.rs +++ b/common/nymsphinx/addressing/src/nodes.rs @@ -1,6 +1,13 @@ // Copyright 2021 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 +//! Encodoing and decoding node routing information. +//! +//! This module is responsible for encoding and decoding node routing information, so that +//! they could be later put into an appropriate field in a sphinx header. +//! Currently, that routing information is an IP address, but in principle it can be anything +//! for as long as it's going to fit in the field. + use nym_crypto::asymmetric::identity; use nym_sphinx_types::{NodeAddressBytes, NODE_ADDRESS_LENGTH}; @@ -12,13 +19,6 @@ use thiserror::Error; pub type NodeIdentity = identity::PublicKey; pub const NODE_IDENTITY_SIZE: usize = identity::PUBLIC_KEY_LENGTH; -/// Encodoing and decoding node routing information. -/// -/// This module is responsible for encoding and decoding node routing information, so that -/// they could be later put into an appropriate field in a sphinx header. -/// Currently, that routing information is an IP address, but in principle it can be anything -/// for as long as it's going to fit in the field. - /// MAX_UNPADDED_LEN represents maximum length an unpadded address could have. /// In this case it's an ipv6 socket address (with version prefix) pub const MAX_NODE_ADDRESS_UNPADDED_LEN: usize = 19; diff --git a/common/nymsphinx/anonymous-replies/src/reply_surb.rs b/common/nymsphinx/anonymous-replies/src/reply_surb.rs index deac5f532d7..f25871ba0be 100644 --- a/common/nymsphinx/anonymous-replies/src/reply_surb.rs +++ b/common/nymsphinx/anonymous-replies/src/reply_surb.rs @@ -56,7 +56,7 @@ impl<'de> Deserialize<'de> for ReplySurb { { struct ReplySurbVisitor; - impl<'de> Visitor<'de> for ReplySurbVisitor { + impl Visitor<'_> for ReplySurbVisitor { type Value = ReplySurb; fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result { diff --git a/common/socks5/requests/src/request.rs b/common/socks5/requests/src/request.rs index 23e844db877..59163daf55a 100644 --- a/common/socks5/requests/src/request.rs +++ b/common/socks5/requests/src/request.rs @@ -253,25 +253,12 @@ impl Socks5RequestContent { /// Deserialize the request type, connection id, destination address and port, /// and the request body from bytes. /// - // TODO: this was already inaccurate - // /// Serialized bytes looks like this: - // /// - // /// -------------------------------------------------------------------------------------- - // /// request_flag | connection_id | address_length | remote_address_bytes | request_data | - // /// 1 | 8 | 2 | address_length | ... | - // /// -------------------------------------------------------------------------------------- - /// - /// The request_flag tells us whether this is a new connection request (`new_connect`), - /// an already-established connection we should send up (`new_send`), or - /// a request to close an established connection (`new_close`). - // connect: // RequestFlag::Connect || CONN_ID || ADDR_LEN || ADDR || // // send: // RequestFlag::Send || CONN_ID || LOCAL_CLOSED || DATA // where DATA: SEQ || TRUE_DATA - pub fn try_from_bytes(b: &[u8]) -> Result { // each request needs to at least contain flag and ConnectionId if b.is_empty() { diff --git a/explorer-api/src/geo_ip/location.rs b/explorer-api/src/geo_ip/location.rs index 59bbb33ad7f..263764943e3 100644 --- a/explorer-api/src/geo_ip/location.rs +++ b/explorer-api/src/geo_ip/location.rs @@ -166,7 +166,7 @@ impl GeoIp { } } -impl<'a> TryFrom<&City<'a>> for Location { +impl TryFrom<&City<'_>> for Location { type Error = String; fn try_from(city: &City) -> Result { diff --git a/explorer-api/src/guards/location.rs b/explorer-api/src/guards/location.rs index 045b03f5b4e..f5ce0b7ee28 100644 --- a/explorer-api/src/guards/location.rs +++ b/explorer-api/src/guards/location.rs @@ -65,7 +65,7 @@ impl<'r> FromRequest<'r> for Location { } } -impl<'a> OpenApiFromRequest<'a> for Location { +impl OpenApiFromRequest<'_> for Location { fn from_request_input( _gen: &mut OpenApiGenerator, _name: String, diff --git a/nym-api/nym-api-requests/src/helpers.rs b/nym-api/nym-api-requests/src/helpers.rs index 651030fc746..292ffb69f49 100644 --- a/nym-api/nym-api-requests/src/helpers.rs +++ b/nym-api/nym-api-requests/src/helpers.rs @@ -64,7 +64,7 @@ pub(crate) mod overengineered_offset_date_time_serde { ])), ]; - impl<'de> Visitor<'de> for OffsetDateTimeVisitor { + impl Visitor<'_> for OffsetDateTimeVisitor { type Value = OffsetDateTime; fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result { diff --git a/nym-api/src/ecash/tests/helpers.rs b/nym-api/src/ecash/tests/helpers.rs index 5cd410056f0..73fac38606f 100644 --- a/nym-api/src/ecash/tests/helpers.rs +++ b/nym-api/src/ecash/tests/helpers.rs @@ -76,7 +76,7 @@ pub(crate) async fn submit_public_keys(controllers: &mut [TestingDkgController], .unwrap(); } - let threshold = (2 * controllers.len() as u64 + 3 - 1) / 3; + let threshold = (2 * controllers.len() as u64).div_ceil(3); let mut guard = controllers[0].chain_state.lock().unwrap(); guard.dkg_contract.epoch.state = EpochState::DealingExchange { resharing }; diff --git a/nym-api/src/network_monitor/monitor/gateway_clients_cache.rs b/nym-api/src/network_monitor/monitor/gateway_clients_cache.rs index 4a321d57cd7..c791f9a6af8 100644 --- a/nym-api/src/network_monitor/monitor/gateway_clients_cache.rs +++ b/nym-api/src/network_monitor/monitor/gateway_clients_cache.rs @@ -59,7 +59,7 @@ impl GatewayClientHandle { } } -impl<'a> UnlockedGatewayClientHandle<'a> { +impl UnlockedGatewayClientHandle<'_> { pub(crate) fn get_mut_unchecked( &mut self, ) -> &mut GatewayClient { diff --git a/nym-credential-proxy/nym-credential-proxy/src/http/state/mod.rs b/nym-credential-proxy/nym-credential-proxy/src/http/state/mod.rs index c4c4a8ebe3b..bcc62f9c7eb 100644 --- a/nym-credential-proxy/nym-credential-proxy/src/http/state/mod.rs +++ b/nym-credential-proxy/nym-credential-proxy/src/http/state/mod.rs @@ -674,7 +674,7 @@ pub(crate) struct ChainWritePermit<'a> { inner: RwLockWriteGuard<'a, DirectSigningHttpRpcNyxdClient>, } -impl<'a> Deref for ChainWritePermit<'a> { +impl Deref for ChainWritePermit<'_> { type Target = DirectSigningHttpRpcNyxdClient; fn deref(&self) -> &Self::Target { diff --git a/nym-node-status-api/nym-node-status-api/Cargo.toml b/nym-node-status-api/nym-node-status-api/Cargo.toml index 0dfb0caffb6..05d1586ae9a 100644 --- a/nym-node-status-api/nym-node-status-api/Cargo.toml +++ b/nym-node-status-api/nym-node-status-api/Cargo.toml @@ -3,7 +3,7 @@ [package] name = "nym-node-status-api" -version = "1.0.0-rc.3" +version = "1.0.0-rc.4" authors.workspace = true repository.workspace = true homepage.workspace = true diff --git a/nym-node-status-api/nym-node-status-api/src/cli/mod.rs b/nym-node-status-api/nym-node-status-api/src/cli/mod.rs index f329e4a9a03..e9d76a1f755 100644 --- a/nym-node-status-api/nym-node-status-api/src/cli/mod.rs +++ b/nym-node-status-api/nym-node-status-api/src/cli/mod.rs @@ -45,11 +45,6 @@ pub(crate) struct Cli { #[arg(value_parser = parse_duration)] pub(crate) nym_api_client_timeout: Duration, - /// Explorer api client timeout. - #[clap(long, default_value = "15", env = "EXPLORER_CLIENT_TIMEOUT")] - #[arg(value_parser = parse_duration)] - pub(crate) explorer_client_timeout: Duration, - /// Connection url for the database. #[clap(long, env = "DATABASE_URL")] pub(crate) database_url: String, @@ -70,10 +65,18 @@ pub(crate) struct Cli { #[arg(value_parser = parse_duration)] pub(crate) testruns_refresh_interval: Duration, + #[clap(long, default_value = "86400", env = "NODE_STATUS_API_GEODATA_TTL")] + #[arg(value_parser = parse_duration)] + pub(crate) geodata_ttl: Duration, + #[clap(env = "NODE_STATUS_API_AGENT_KEY_LIST")] #[arg(value_delimiter = ',')] pub(crate) agent_key_list: Vec, + /// https://github.com/ipinfo/rust + #[clap(long, env = "IPINFO_API_TOKEN")] + pub(crate) ipinfo_api_token: String, + #[clap( long, default_value_t = 40, diff --git a/nym-node-status-api/nym-node-status-api/src/db/models.rs b/nym-node-status-api/nym-node-status-api/src/db/models.rs index 596f634f2e7..7d9e93ed24b 100644 --- a/nym-node-status-api/nym-node-status-api/src/db/models.rs +++ b/nym-node-status-api/nym-node-status-api/src/db/models.rs @@ -12,6 +12,7 @@ pub(crate) struct GatewayRecord { pub(crate) bonded: bool, pub(crate) blacklisted: bool, pub(crate) self_described: String, + // TODO dz shouldn't be an option pub(crate) explorer_pretty_bond: Option, pub(crate) last_updated_utc: i64, pub(crate) performance: u8, @@ -215,7 +216,6 @@ pub(crate) const MIXNODES_BONDED_RESERVE: &str = "mixnodes.bonded.reserve"; pub(crate) const MIXNODES_BLACKLISTED_COUNT: &str = "mixnodes.blacklisted.count"; pub(crate) const GATEWAYS_BONDED_COUNT: &str = "gateways.bonded.count"; -pub(crate) const GATEWAYS_EXPLORER_COUNT: &str = "gateways.explorer.count"; pub(crate) const GATEWAYS_BLACKLISTED_COUNT: &str = "gateways.blacklisted.count"; pub(crate) const MIXNODES_HISTORICAL_COUNT: &str = "mixnodes.historical.count"; @@ -272,7 +272,6 @@ pub(crate) mod gateway { pub(crate) bonded: GatewaySummaryBonded, pub(crate) blacklisted: GatewaySummaryBlacklisted, pub(crate) historical: GatewaySummaryHistorical, - pub(crate) explorer: GatewaySummaryExplorer, } #[derive(Debug, Clone, Deserialize, Serialize, ToSchema)] diff --git a/nym-node-status-api/nym-node-status-api/src/db/queries/summary.rs b/nym-node-status-api/nym-node-status-api/src/db/queries/summary.rs index 103712a9a4e..4b2ecd22a59 100644 --- a/nym-node-status-api/nym-node-status-api/src/db/queries/summary.rs +++ b/nym-node-status-api/nym-node-status-api/src/db/queries/summary.rs @@ -8,7 +8,7 @@ use crate::{ models::{ gateway::{ GatewaySummary, GatewaySummaryBlacklisted, GatewaySummaryBonded, - GatewaySummaryExplorer, GatewaySummaryHistorical, + GatewaySummaryHistorical, }, mixnode::{ MixnodeSummary, MixnodeSummaryBlacklisted, MixnodeSummaryBonded, @@ -82,7 +82,6 @@ async fn from_summary_dto(items: Vec) -> HttpResult const MIXNODES_BONDED_RESERVE: &str = "mixnodes.bonded.reserve"; const MIXNODES_BLACKLISTED_COUNT: &str = "mixnodes.blacklisted.count"; const GATEWAYS_BONDED_COUNT: &str = "gateways.bonded.count"; - const GATEWAYS_EXPLORER_COUNT: &str = "gateways.explorer.count"; const GATEWAYS_BLACKLISTED_COUNT: &str = "gateways.blacklisted.count"; const MIXNODES_HISTORICAL_COUNT: &str = "mixnodes.historical.count"; const GATEWAYS_HISTORICAL_COUNT: &str = "gateways.historical.count"; @@ -96,7 +95,6 @@ async fn from_summary_dto(items: Vec) -> HttpResult // check we have all the keys we are expecting, and build up a map of errors for missing one let keys = [ GATEWAYS_BONDED_COUNT, - GATEWAYS_EXPLORER_COUNT, GATEWAYS_HISTORICAL_COUNT, GATEWAYS_BLACKLISTED_COUNT, MIXNODES_BLACKLISTED_COUNT, @@ -139,10 +137,6 @@ async fn from_summary_dto(items: Vec) -> HttpResult .unwrap_or_default(); let gateways_bonded_count: SummaryDto = map.get(GATEWAYS_BONDED_COUNT).cloned().unwrap_or_default(); - let gateways_explorer_count: SummaryDto = map - .get(GATEWAYS_EXPLORER_COUNT) - .cloned() - .unwrap_or_default(); let mixnodes_historical_count: SummaryDto = map .get(MIXNODES_HISTORICAL_COUNT) .cloned() @@ -187,10 +181,6 @@ async fn from_summary_dto(items: Vec) -> HttpResult count: to_count_i32(&gateways_historical_count), last_updated_utc: to_timestamp(&gateways_historical_count), }, - explorer: GatewaySummaryExplorer { - count: to_count_i32(&gateways_explorer_count), - last_updated_utc: to_timestamp(&gateways_explorer_count), - }, }, }) } diff --git a/nym-node-status-api/nym-node-status-api/src/main.rs b/nym-node-status-api/nym-node-status-api/src/main.rs index 6fcdf344732..6274a01fe51 100644 --- a/nym-node-status-api/nym-node-status-api/src/main.rs +++ b/nym-node-status-api/nym-node-status-api/src/main.rs @@ -28,13 +28,15 @@ async fn main() -> anyhow::Result<()> { let storage = db::Storage::init(connection_url).await?; let db_pool = storage.pool_owned(); let args_clone = args.clone(); + tokio::spawn(async move { monitor::spawn_in_background( db_pool, - args_clone.explorer_client_timeout, args_clone.nym_api_client_timeout, - &args_clone.nyxd_addr, + args_clone.nyxd_addr, args_clone.monitor_refresh_interval, + args_clone.ipinfo_api_token, + args_clone.geodata_ttl, ) .await; tracing::info!("Started monitor task"); diff --git a/nym-node-status-api/nym-node-status-api/src/monitor/geodata.rs b/nym-node-status-api/nym-node-status-api/src/monitor/geodata.rs new file mode 100644 index 00000000000..1042b15cce3 --- /dev/null +++ b/nym-node-status-api/nym-node-status-api/src/monitor/geodata.rs @@ -0,0 +1,112 @@ +use cosmwasm_std::{Addr, Coin}; +use serde::{Deserialize, Serialize}; + +pub(crate) struct IpInfoClient { + client: reqwest::Client, + token: String, +} + +impl IpInfoClient { + pub(crate) fn new(token: impl Into) -> Self { + let client = reqwest::Client::new(); + let token = token.into(); + + Self { client, token } + } + + pub(crate) async fn locate_ip(&self, ip: impl AsRef) -> anyhow::Result { + let url = format!( + "https://ipinfo.io/{}/country?token={}", + ip.as_ref(), + &self.token + ); + let response = self + .client + .get(url) + .send() + .await + // map non 2xx responses to error + .and_then(|res| res.error_for_status()) + .map_err(|err| { + if matches!(err.status(), Some(reqwest::StatusCode::TOO_MANY_REQUESTS)) { + tracing::error!("ipinfo rate limit exceeded"); + } + anyhow::Error::from(err) + })?; + let response_text = response.text().await?.trim().to_string(); + + Ok(Location { + two_letter_iso_country_code: response_text, + }) + } + + /// check DOESN'T consume bandwidth allowance + pub(crate) async fn check_remaining_bandwidth( + &self, + ) -> anyhow::Result { + let url = format!("https://ipinfo.io/me?token={}", &self.token); + let response = self + .client + .get(url) + .send() + .await + // map non 2xx responses to error + .and_then(|res| res.error_for_status()) + .map_err(|err| { + if matches!(err.status(), Some(reqwest::StatusCode::TOO_MANY_REQUESTS)) { + tracing::error!("ipinfo rate limit exceeded"); + } + anyhow::Error::from(err) + })?; + let response: ipinfo::MeResponse = response.json().await?; + + Ok(response.requests) + } +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub(crate) struct NodeGeoData { + pub(crate) identity_key: String, + pub(crate) owner: Addr, + pub(crate) pledge_amount: Coin, + pub(crate) location: Location, +} + +#[derive(Debug, Clone, Default, Serialize, Deserialize)] +pub(crate) struct Location { + pub(crate) two_letter_iso_country_code: String, +} + +impl Location { + pub(crate) fn empty() -> Self { + Self { + two_letter_iso_country_code: String::new(), + } + } +} + +pub(crate) mod ipinfo { + use super::*; + + // clippy doesn't understand it's used for typed deserialization + #[allow(dead_code)] + #[derive(Debug, Clone, Deserialize)] + /// `/me` is undocumented in their developers page + /// https://ipinfo.io/developers/responses + /// but explained here + /// https://community.ipinfo.io/t/easy-way-to-check-allowance-usage/5755/2 + pub(crate) struct MeResponse { + token: String, + pub(crate) requests: MeResponseRequests, + } + + // clippy doesn't understand it's used for typed deserialization + #[allow(dead_code)] + #[derive(Debug, Clone, Deserialize)] + pub(crate) struct MeResponseRequests { + pub(crate) day: u64, + pub(crate) month: u64, + pub(crate) limit: u64, + pub(crate) remaining: u64, + } +} diff --git a/nym-node-status-api/nym-node-status-api/src/monitor/mod.rs b/nym-node-status-api/nym-node-status-api/src/monitor/mod.rs index 7b6c85b6d56..459992b0b3d 100644 --- a/nym-node-status-api/nym-node-status-api/src/monitor/mod.rs +++ b/nym-node-status-api/nym-node-status-api/src/monitor/mod.rs @@ -2,16 +2,17 @@ use crate::db::models::{ gateway, mixnode, GatewayRecord, MixnodeRecord, NetworkSummary, GATEWAYS_BLACKLISTED_COUNT, - GATEWAYS_BONDED_COUNT, GATEWAYS_EXPLORER_COUNT, GATEWAYS_HISTORICAL_COUNT, - MIXNODES_BLACKLISTED_COUNT, MIXNODES_BONDED_ACTIVE, MIXNODES_BONDED_COUNT, - MIXNODES_BONDED_INACTIVE, MIXNODES_BONDED_RESERVE, MIXNODES_HISTORICAL_COUNT, + GATEWAYS_BONDED_COUNT, GATEWAYS_HISTORICAL_COUNT, MIXNODES_BLACKLISTED_COUNT, + MIXNODES_BONDED_ACTIVE, MIXNODES_BONDED_COUNT, MIXNODES_BONDED_INACTIVE, + MIXNODES_BONDED_RESERVE, MIXNODES_HISTORICAL_COUNT, }; use crate::db::{queries, DbPool}; +use crate::monitor::geodata::{Location, NodeGeoData}; use anyhow::anyhow; use cosmwasm_std::Decimal; -use nym_explorer_client::{ExplorerClient, PrettyDetailedGatewayBond}; +use moka::future::Cache; use nym_network_defaults::NymNetworkDetails; -use nym_validator_client::client::NymApiClientExt; +use nym_validator_client::client::{NodeId, NymApiClientExt}; use nym_validator_client::models::{ LegacyDescribedMixNode, MixNodeBondAnnotated, NymNodeDescription, }; @@ -20,40 +21,55 @@ use nym_validator_client::nyxd::contract_traits::PagedMixnetQueryClient; use nym_validator_client::nyxd::{AccountId, NyxdClient}; use nym_validator_client::NymApiClient; use reqwest::Url; -use std::collections::HashSet; +use std::collections::{HashMap, HashSet}; use std::str::FromStr; use tokio::time::Duration; use tracing::instrument; +pub(crate) use geodata::IpInfoClient; + +mod geodata; + // TODO dz should be configurable const FAILURE_RETRY_DELAY: Duration = Duration::from_secs(60); static DELEGATION_PROGRAM_WALLET: &str = "n1rnxpdpx3kldygsklfft0gech7fhfcux4zst5lw"; +struct Monitor { + db_pool: DbPool, + network_details: NymNetworkDetails, + nym_api_client_timeout: Duration, + nyxd_addr: Url, + ipinfo: IpInfoClient, + geocache: Cache, +} + // TODO dz: query many NYM APIs: // multiple instances running directory cache, ask sachin #[instrument(level = "debug", name = "data_monitor", skip_all)] pub(crate) async fn spawn_in_background( db_pool: DbPool, - explorer_client_timeout: Duration, nym_api_client_timeout: Duration, - nyxd_addr: &Url, + nyxd_addr: Url, refresh_interval: Duration, + ipinfo_api_token: String, + geodata_ttl: Duration, ) { - let network_defaults = nym_network_defaults::NymNetworkDetails::new_from_env(); + let geocache = Cache::builder().time_to_live(geodata_ttl).build(); + let ipinfo = IpInfoClient::new(ipinfo_api_token.clone()); + let mut monitor = Monitor { + db_pool, + network_details: nym_network_defaults::NymNetworkDetails::new_from_env(), + nym_api_client_timeout, + nyxd_addr, + ipinfo, + geocache, + }; loop { tracing::info!("Refreshing node info..."); - if let Err(e) = run( - &db_pool, - &network_defaults, - explorer_client_timeout, - nym_api_client_timeout, - nyxd_addr, - ) - .await - { + if let Err(e) = monitor.run().await { tracing::error!( "Monitor run failed: {e}, retrying in {}s...", FAILURE_RETRY_DELAY.as_secs() @@ -70,345 +86,370 @@ pub(crate) async fn spawn_in_background( } } -async fn run( - pool: &DbPool, - network_details: &NymNetworkDetails, - explorer_client_timeout: Duration, - nym_api_client_timeout: Duration, - nyxd_addr: &Url, -) -> anyhow::Result<()> { - let default_api_url = network_details - .endpoints - .first() - .expect("rust sdk mainnet default incorrectly configured") - .api_url() - .clone() - .expect("rust sdk mainnet default missing api_url"); - let default_explorer_url = network_details.explorer_api.clone().map(|url| { - url.parse() - .expect("rust sdk mainnet default explorer url not parseable") - }); - - // TODO dz replace explorer api with ipinfo.io - let default_explorer_url = - default_explorer_url.expect("explorer url missing in network config"); - let explorer_client = - ExplorerClient::new_with_timeout(default_explorer_url, explorer_client_timeout)?; - let explorer_gateways = explorer_client - .unstable_get_gateways() - .await - .log_error("unstable_get_gateways")?; - - let api_client = NymApiClient::new_with_timeout(default_api_url, nym_api_client_timeout); - - let all_nodes = api_client - .get_all_described_nodes() - .await - .log_error("get_all_described_nodes")?; - tracing::debug!("Fetched {} total nodes", all_nodes.len()); - - let gateways = all_nodes - .iter() - .filter(|node| node.description.declared_role.entry) - .collect::>(); - tracing::debug!("Of those, {} gateways", gateways.len()); - for gw in gateways.iter() { - tracing::debug!("{}", gw.ed25519_identity_key().to_base58_string()); - } +impl Monitor { + async fn run(&mut self) -> anyhow::Result<()> { + self.check_ipinfo_bandwidth().await; - let mixnodes = all_nodes - .iter() - .filter(|node| node.description.declared_role.mixnode) - .collect::>(); - tracing::debug!("Of those, {} mixnodes", mixnodes.len()); - - log_gw_in_explorer_not_api(explorer_gateways.as_slice(), gateways.as_slice()); + let default_api_url = self + .network_details + .endpoints + .first() + .expect("rust sdk mainnet default incorrectly configured") + .api_url() + .clone() + .expect("rust sdk mainnet default missing api_url"); - let all_skimmed_nodes = api_client - .get_all_basic_nodes(None) - .await - .log_error("get_all_basic_nodes")?; + let api_client = + NymApiClient::new_with_timeout(default_api_url, self.nym_api_client_timeout); - let mixnodes = api_client - .get_cached_mixnodes() - .await - .log_error("get_cached_mixnodes")?; - tracing::debug!("Fetched {} mixnodes", mixnodes.len()); + let all_nodes = api_client + .get_all_described_nodes() + .await + .log_error("get_all_described_nodes")?; + tracing::debug!("Fetched {} total nodes", all_nodes.len()); - // let gateways_blacklisted = gateways.iter().filter(|gw|gw.) - let gateways_blacklisted = all_skimmed_nodes - .iter() - .filter_map(|node| { - if node.performance.round_to_integer() <= 50 && node.supported_roles.entry { - Some(node.ed25519_identity_pubkey.to_base58_string()) - } else { - None + let gateways = all_nodes + .iter() + .filter(|node| node.description.declared_role.entry) + .collect::>(); + tracing::debug!( + "{}/{} with declared entry gateway capability", + gateways.len(), + all_nodes.len() + ); + + let mixnodes = all_nodes + .iter() + .filter(|node| node.description.declared_role.mixnode) + .collect::>(); + tracing::debug!( + "{}/{} with declared mixnode capability", + mixnodes.len(), + all_nodes.len() + ); + + let bonded_node_info = api_client + .get_all_bonded_nym_nodes() + .await? + .into_iter() + .map(|node| (node.bond_information.node_id, node.bond_information)) + // for faster reads + .collect::>(); + + let mut gateway_geodata = Vec::new(); + for gateway in gateways.iter() { + if let Some(node_info) = bonded_node_info.get(&gateway.node_id) { + let gw_geodata = NodeGeoData { + identity_key: node_info.node.identity_key.to_owned(), + owner: node_info.owner.to_owned(), + pledge_amount: node_info.original_pledge.to_owned(), + location: self.location_cached(gateway).await, + }; + gateway_geodata.push(gw_geodata); } - }) - .collect::>(); - - // Cached mixnodes don't include blacklisted nodes - // We need that to calculate the total locked tokens later - let mixnodes = api_client - .nym_api - .get_mixnodes_detailed_unfiltered() - .await - .log_error("get_mixnodes_detailed_unfiltered")?; - let mixnodes_described = api_client - .nym_api - .get_mixnodes_described() - .await - .log_error("get_mixnodes_described")?; - let mixnodes_active = api_client - .nym_api - .get_active_mixnodes() - .await - .log_error("get_active_mixnodes")?; - let delegation_program_members = - get_delegation_program_details(network_details, nyxd_addr).await?; - - // keep stats for later - let count_bonded_mixnodes = mixnodes.len(); - let count_bonded_gateways = gateways.len(); - let count_explorer_gateways = explorer_gateways.len(); - let count_bonded_mixnodes_active = mixnodes_active.len(); - - let gateway_records = prepare_gateway_data( - &gateways, - &gateways_blacklisted, - explorer_gateways, - all_skimmed_nodes, - )?; - queries::insert_gateways(pool, gateway_records) - .await - .map(|_| { - tracing::debug!("Gateway info written to DB!"); - })?; - - // instead of counting blacklisted GWs returned from API cache, count from the active set - let count_gateways_blacklisted = gateways - .iter() - .filter(|gw| { - let gw_identity = gw.ed25519_identity_key().to_base58_string(); - gateways_blacklisted.contains(&gw_identity) - }) - .count(); + } - if count_gateways_blacklisted > 0 { - queries::write_blacklisted_gateways_to_db(pool, gateways_blacklisted.iter()) + // contains performance data + let all_skimmed_nodes = api_client + .get_all_basic_nodes(None) + .await + .log_error("get_all_basic_nodes")?; + + let gateways_blacklisted = all_skimmed_nodes + .iter() + .filter_map(|node| { + if node.performance.round_to_integer() <= 50 && node.supported_roles.entry { + Some(node.ed25519_identity_pubkey.to_base58_string()) + } else { + None + } + }) + .collect::>(); + + // Cached mixnodes don't include blacklisted nodes + // We need that to calculate the total locked tokens later + // TODO dz deprecated API, remove + let legacy_mixnodes = api_client + .nym_api + .get_mixnodes_detailed_unfiltered() + .await + .log_error("get_mixnodes_detailed_unfiltered")?; + let mixnodes_described = api_client + .nym_api + .get_mixnodes_described() + .await + .log_error("get_mixnodes_described")?; + let mixnodes_active = api_client + .nym_api + .get_basic_active_mixing_assigned_nodes(None, false, None, None) + .await + .log_error("get_active_mixnodes")? + .nodes + .data; + let delegation_program_members = + get_delegation_program_details(&self.network_details, &self.nyxd_addr).await?; + + // keep stats for later + let count_bonded_mixnodes = mixnodes.len(); + let count_bonded_gateways = gateways.len(); + let count_bonded_mixnodes_active = mixnodes_active.len(); + + let gateway_records = self.prepare_gateway_data( + &gateways, + &gateways_blacklisted, + gateway_geodata, + all_skimmed_nodes, + )?; + + let pool = self.db_pool.clone(); + queries::insert_gateways(&pool, gateway_records) .await .map(|_| { - tracing::debug!( - "Gateway blacklist info written to DB! {} blacklisted by Nym API", - count_gateways_blacklisted - ) + tracing::debug!("Gateway info written to DB!"); })?; - } - let mixnode_records = - prepare_mixnode_data(&mixnodes, mixnodes_described, delegation_program_members)?; - queries::insert_mixnodes(pool, mixnode_records) - .await - .map(|_| { - tracing::debug!("Mixnode info written to DB!"); - })?; - - let count_mixnodes_blacklisted = mixnodes.iter().filter(|elem| elem.blacklisted).count(); - - let recently_unbonded_gateways = queries::ensure_gateways_still_bonded(pool, &gateways).await?; - let recently_unbonded_mixnodes = queries::ensure_mixnodes_still_bonded(pool, &mixnodes).await?; - - let count_bonded_mixnodes_reserve = 0; // TODO: NymAPI doesn't report the reserve set size - let count_bonded_mixnodes_inactive = - count_bonded_mixnodes.saturating_sub(count_bonded_mixnodes_active); - - let (all_historical_gateways, all_historical_mixnodes) = calculate_stats(pool).await?; - - // - // write summary keys and values to table - // - - let nodes_summary = vec![ - (MIXNODES_BONDED_COUNT, &count_bonded_mixnodes), - (MIXNODES_BONDED_ACTIVE, &count_bonded_mixnodes_active), - (MIXNODES_BONDED_INACTIVE, &count_bonded_mixnodes_inactive), - (MIXNODES_BONDED_RESERVE, &count_bonded_mixnodes_reserve), - (MIXNODES_BLACKLISTED_COUNT, &count_mixnodes_blacklisted), - (GATEWAYS_BONDED_COUNT, &count_bonded_gateways), - (GATEWAYS_EXPLORER_COUNT, &count_explorer_gateways), - (MIXNODES_HISTORICAL_COUNT, &all_historical_mixnodes), - (GATEWAYS_HISTORICAL_COUNT, &all_historical_gateways), - (GATEWAYS_BLACKLISTED_COUNT, &count_gateways_blacklisted), - ]; - - let last_updated = chrono::offset::Utc::now(); - let last_updated_utc = last_updated.timestamp().to_string(); - let network_summary = NetworkSummary { - mixnodes: mixnode::MixnodeSummary { - bonded: mixnode::MixnodeSummaryBonded { - count: count_bonded_mixnodes.cast_checked()?, - active: count_bonded_mixnodes_active.cast_checked()?, - inactive: count_bonded_mixnodes_inactive.cast_checked()?, - reserve: count_bonded_mixnodes_reserve.cast_checked()?, - last_updated_utc: last_updated_utc.to_owned(), - }, - blacklisted: mixnode::MixnodeSummaryBlacklisted { - count: count_mixnodes_blacklisted.cast_checked()?, - last_updated_utc: last_updated_utc.to_owned(), - }, - historical: mixnode::MixnodeSummaryHistorical { - count: all_historical_mixnodes.cast_checked()?, - last_updated_utc: last_updated_utc.to_owned(), - }, - }, - gateways: gateway::GatewaySummary { - bonded: gateway::GatewaySummaryBonded { - count: count_bonded_gateways.cast_checked()?, - last_updated_utc: last_updated_utc.to_owned(), - }, - blacklisted: gateway::GatewaySummaryBlacklisted { - count: count_gateways_blacklisted.cast_checked()?, - last_updated_utc: last_updated_utc.to_owned(), - }, - historical: gateway::GatewaySummaryHistorical { - count: all_historical_gateways.cast_checked()?, - last_updated_utc: last_updated_utc.to_owned(), + let count_gateways_blacklisted = gateways + .iter() + .filter(|gw| { + let gw_identity = gw.ed25519_identity_key().to_base58_string(); + gateways_blacklisted.contains(&gw_identity) + }) + .count(); + + if count_gateways_blacklisted > 0 { + queries::write_blacklisted_gateways_to_db(&pool, gateways_blacklisted.iter()) + .await + .map(|_| { + tracing::debug!( + "Gateway blacklist info written to DB! {} blacklisted by Nym API", + count_gateways_blacklisted + ) + })?; + } + + let mixnode_records = self.prepare_mixnode_data( + &legacy_mixnodes, + mixnodes_described, + delegation_program_members, + )?; + queries::insert_mixnodes(&pool, mixnode_records) + .await + .map(|_| { + tracing::debug!("Mixnode info written to DB!"); + })?; + + let count_mixnodes_blacklisted = legacy_mixnodes + .iter() + .filter(|elem| elem.blacklisted) + .count(); + + let recently_unbonded_gateways = + queries::ensure_gateways_still_bonded(&pool, &gateways).await?; + let recently_unbonded_mixnodes = + queries::ensure_mixnodes_still_bonded(&pool, &legacy_mixnodes).await?; + + let count_bonded_mixnodes_reserve = 0; // TODO: NymAPI doesn't report the reserve set size + let count_bonded_mixnodes_inactive = count_bonded_mixnodes - count_bonded_mixnodes_active; + + let (all_historical_gateways, all_historical_mixnodes) = calculate_stats(&pool).await?; + + // + // write summary keys and values to table + // + + let nodes_summary = vec![ + (MIXNODES_BONDED_COUNT, &count_bonded_mixnodes), + (MIXNODES_BONDED_ACTIVE, &count_bonded_mixnodes_active), + (MIXNODES_BONDED_INACTIVE, &count_bonded_mixnodes_inactive), + (MIXNODES_BONDED_RESERVE, &count_bonded_mixnodes_reserve), + (MIXNODES_BLACKLISTED_COUNT, &count_mixnodes_blacklisted), + (GATEWAYS_BONDED_COUNT, &count_bonded_gateways), + (MIXNODES_HISTORICAL_COUNT, &all_historical_mixnodes), + (GATEWAYS_HISTORICAL_COUNT, &all_historical_gateways), + (GATEWAYS_BLACKLISTED_COUNT, &count_gateways_blacklisted), + ]; + + let last_updated = chrono::offset::Utc::now(); + let last_updated_utc = last_updated.timestamp().to_string(); + let network_summary = NetworkSummary { + mixnodes: mixnode::MixnodeSummary { + bonded: mixnode::MixnodeSummaryBonded { + count: count_bonded_mixnodes.cast_checked()?, + active: count_bonded_mixnodes_active.cast_checked()?, + inactive: count_bonded_mixnodes_inactive.cast_checked()?, + reserve: count_bonded_mixnodes_reserve.cast_checked()?, + last_updated_utc: last_updated_utc.to_owned(), + }, + blacklisted: mixnode::MixnodeSummaryBlacklisted { + count: count_mixnodes_blacklisted.cast_checked()?, + last_updated_utc: last_updated_utc.to_owned(), + }, + historical: mixnode::MixnodeSummaryHistorical { + count: all_historical_mixnodes.cast_checked()?, + last_updated_utc: last_updated_utc.to_owned(), + }, }, - explorer: gateway::GatewaySummaryExplorer { - count: count_explorer_gateways.cast_checked()?, - last_updated_utc: last_updated_utc.to_owned(), + gateways: gateway::GatewaySummary { + bonded: gateway::GatewaySummaryBonded { + count: count_bonded_gateways.cast_checked()?, + last_updated_utc: last_updated_utc.to_owned(), + }, + blacklisted: gateway::GatewaySummaryBlacklisted { + count: count_gateways_blacklisted.cast_checked()?, + last_updated_utc: last_updated_utc.to_owned(), + }, + historical: gateway::GatewaySummaryHistorical { + count: all_historical_gateways.cast_checked()?, + last_updated_utc: last_updated_utc.to_owned(), + }, }, - }, - }; + }; - queries::insert_summaries(pool, &nodes_summary, &network_summary, last_updated).await?; + queries::insert_summaries(&pool, &nodes_summary, &network_summary, last_updated).await?; - let mut log_lines: Vec = vec![]; - for (key, value) in nodes_summary.iter() { - log_lines.push(format!("{} = {}", key, value)); + let mut log_lines: Vec = vec![]; + for (key, value) in nodes_summary.iter() { + log_lines.push(format!("{} = {}", key, value)); + } + log_lines.push(format!( + "recently_unbonded_mixnodes = {}", + recently_unbonded_mixnodes + )); + log_lines.push(format!( + "recently_unbonded_gateways = {}", + recently_unbonded_gateways + )); + + tracing::info!("Directory summary: \n{}", log_lines.join("\n")); + + Ok(()) } - log_lines.push(format!( - "recently_unbonded_mixnodes = {}", - recently_unbonded_mixnodes - )); - log_lines.push(format!( - "recently_unbonded_gateways = {}", - recently_unbonded_gateways - )); - - tracing::info!("Directory summary: \n{}", log_lines.join("\n")); - - Ok(()) -} - -fn prepare_gateway_data( - gateways: &[&NymNodeDescription], - gateways_blacklisted: &HashSet, - explorer_gateways: Vec, - skimmed_gateways: Vec, -) -> anyhow::Result> { - let mut gateway_records = Vec::new(); - for gateway in gateways { - let identity_key = gateway.ed25519_identity_key().to_base58_string(); - let bonded = true; - let last_updated_utc = chrono::offset::Utc::now().timestamp(); - let blacklisted = gateways_blacklisted.contains(&identity_key); - - let self_described = serde_json::to_string(&gateway.description)?; + #[instrument(level = "debug", skip_all)] + async fn location_cached(&mut self, node: &NymNodeDescription) -> Location { + let node_id = node.node_id; + + match self.geocache.get(&node_id).await { + Some(location) => return location, + None => { + for ip in node.description.host_information.ip_address.iter() { + if let Ok(location) = self.ipinfo.locate_ip(ip.to_string()).await { + self.geocache.insert(node_id, location.clone()).await; + return location; + } + } + // if no data could be retrieved + tracing::debug!("No geodata could be retrieved for {}", node_id); + Location::empty() + } + } + } - let explorer_pretty_bond = explorer_gateways - .iter() - .find(|g| g.gateway.identity_key.eq(&identity_key)); - let explorer_pretty_bond = explorer_pretty_bond.and_then(|g| serde_json::to_string(g).ok()); + fn prepare_gateway_data( + &self, + gateways: &[&NymNodeDescription], + gateways_blacklisted: &HashSet, + gateway_geodata: Vec, + skimmed_gateways: Vec, + ) -> anyhow::Result> { + let mut gateway_records = Vec::new(); + + for gateway in gateways { + let identity_key = gateway.ed25519_identity_key().to_base58_string(); + let bonded = true; + let last_updated_utc = chrono::offset::Utc::now().timestamp(); + let blacklisted = gateways_blacklisted.contains(&identity_key); + + let self_described = serde_json::to_string(&gateway.description)?; + + let explorer_pretty_bond = gateway_geodata + .iter() + .find(|g| g.identity_key.eq(&identity_key)); + let explorer_pretty_bond = + explorer_pretty_bond.and_then(|g| serde_json::to_string(g).ok()); + + let performance = skimmed_gateways + .iter() + .find(|g| { + g.ed25519_identity_pubkey + .to_base58_string() + .eq(&identity_key) + }) + .map(|g| g.performance) + .unwrap_or_default() + .round_to_integer(); + + gateway_records.push(GatewayRecord { + identity_key: identity_key.to_owned(), + bonded, + blacklisted, + self_described, + explorer_pretty_bond, + last_updated_utc, + performance, + }); + } - let performance = skimmed_gateways - .iter() - .find(|g| { - g.ed25519_identity_pubkey - .to_base58_string() - .eq(&identity_key) - }) - .map(|g| g.performance) - .unwrap_or_default() - .round_to_integer(); - - gateway_records.push(GatewayRecord { - identity_key: identity_key.to_owned(), - bonded, - blacklisted, - self_described, - explorer_pretty_bond, - last_updated_utc, - performance, - }); + Ok(gateway_records) } - Ok(gateway_records) -} + fn prepare_mixnode_data( + &self, + mixnodes: &[MixNodeBondAnnotated], + mixnodes_described: Vec, + delegation_program_members: Vec, + ) -> anyhow::Result> { + let mut mixnode_records = Vec::new(); + + for mixnode in mixnodes { + let mix_id = mixnode.mix_id(); + let identity_key = mixnode.identity_key(); + let bonded = true; + let total_stake = decimal_to_i64(mixnode.mixnode_details.total_stake()); + let blacklisted = mixnode.blacklisted; + let node_info = mixnode.mix_node(); + let host = node_info.host.clone(); + let http_port = node_info.http_api_port; + // Contains all the information including what's above + let full_details = serde_json::to_string(&mixnode)?; + + let mixnode_described = mixnodes_described.iter().find(|m| m.bond.mix_id == mix_id); + let self_described = mixnode_described.and_then(|v| serde_json::to_string(v).ok()); + let is_dp_delegatee = delegation_program_members.contains(&mix_id); + + let last_updated_utc = chrono::offset::Utc::now().timestamp(); + + mixnode_records.push(MixnodeRecord { + mix_id, + identity_key: identity_key.to_owned(), + bonded, + total_stake, + host, + http_port, + blacklisted, + full_details, + self_described, + last_updated_utc, + is_dp_delegatee, + }); + } -fn prepare_mixnode_data( - mixnodes: &[MixNodeBondAnnotated], - mixnodes_described: Vec, - delegation_program_members: Vec, -) -> anyhow::Result> { - let mut mixnode_records = Vec::new(); - - for mixnode in mixnodes { - let mix_id = mixnode.mix_id(); - let identity_key = mixnode.identity_key(); - let bonded = true; - let total_stake = decimal_to_i64(mixnode.mixnode_details.total_stake()); - let blacklisted = mixnode.blacklisted; - let node_info = mixnode.mix_node(); - let host = node_info.host.clone(); - let http_port = node_info.http_api_port; - // Contains all the information including what's above - let full_details = serde_json::to_string(&mixnode)?; - - let mixnode_described = mixnodes_described.iter().find(|m| m.bond.mix_id == mix_id); - let self_described = mixnode_described.and_then(|v| serde_json::to_string(v).ok()); - let is_dp_delegatee = delegation_program_members.contains(&mix_id); - - let last_updated_utc = chrono::offset::Utc::now().timestamp(); - - mixnode_records.push(MixnodeRecord { - mix_id, - identity_key: identity_key.to_owned(), - bonded, - total_stake, - host, - http_port, - blacklisted, - full_details, - self_described, - last_updated_utc, - is_dp_delegatee, - }); + Ok(mixnode_records) } - Ok(mixnode_records) -} - -fn log_gw_in_explorer_not_api( - explorer: &[PrettyDetailedGatewayBond], - api_gateways: &[&NymNodeDescription], -) { - let api_gateways = api_gateways - .iter() - .map(|gw| gw.ed25519_identity_key().to_base58_string()) - .collect::>(); - let explorer_only = explorer - .iter() - .filter(|gw| !api_gateways.contains(&gw.gateway.identity_key.to_string())) - .collect::>(); - - tracing::debug!( - "Gateways listed by explorer but not by Nym API: {}", - explorer_only.len() - ); - for gw in explorer_only.iter() { - tracing::debug!("{}", gw.gateway.identity_key.to_string()); + async fn check_ipinfo_bandwidth(&self) { + match self.ipinfo.check_remaining_bandwidth().await { + Ok(bandwidth) => { + tracing::info!( + "ipinfo monthly bandwidth: {}/{} spent", + bandwidth.month, + bandwidth.limit + ); + } + Err(err) => { + tracing::debug!("Couldn't check ipinfo bandwidth: {}", err); + } + } } } diff --git a/sdk/ffi/go/src/lib.rs b/sdk/ffi/go/src/lib.rs index a5c930a2ec8..a0a690c6913 100644 --- a/sdk/ffi/go/src/lib.rs +++ b/sdk/ffi/go/src/lib.rs @@ -1,6 +1,9 @@ // Copyright 2023-2024 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 +// due to autogenerated code +#![allow(clippy::empty_line_after_doc_comments)] + use nym_sdk::mixnet::Recipient; use nym_sphinx_anonymous_replies::requests::AnonymousSenderTag; uniffi::include_scaffolding!("bindings"); diff --git a/tools/internal/testnet-manager/dkg-bypass-contract/src/contract.rs b/tools/internal/testnet-manager/dkg-bypass-contract/src/contract.rs index c04fae8ef29..df70e604f47 100644 --- a/tools/internal/testnet-manager/dkg-bypass-contract/src/contract.rs +++ b/tools/internal/testnet-manager/dkg-bypass-contract/src/contract.rs @@ -33,7 +33,7 @@ pub(crate) struct VkShareIndex<'a> { pub(crate) epoch_id: MultiIndex<'a, EpochId, ContractVKShare, VKShareKey<'a>>, } -impl<'a> IndexList for VkShareIndex<'a> { +impl IndexList for VkShareIndex<'_> { fn get_indexes(&'_ self) -> Box> + '_> { let v: Vec<&dyn Index> = vec![&self.epoch_id]; Box::new(v.into_iter()) @@ -87,7 +87,7 @@ pub fn query(_: Deps<'_>, _: Env, _: EmptyMessage) -> Result, env: Env, msg: MigrateMsg) -> Result { // on migration immediately attempt to rewrite the storage - let threshold = (2 * msg.dealers.len() as u64 + 3 - 1) / 3; + let threshold = (2 * msg.dealers.len() as u64).div_ceil(3); let epoch = CURRENT_EPOCH.load(deps.storage)?; assert_eq!(0, epoch.epoch_id); diff --git a/tools/internal/testnet-manager/src/manager/dkg_skip.rs b/tools/internal/testnet-manager/src/manager/dkg_skip.rs index a132ea69505..77202026652 100644 --- a/tools/internal/testnet-manager/src/manager/dkg_skip.rs +++ b/tools/internal/testnet-manager/src/manager/dkg_skip.rs @@ -58,7 +58,7 @@ impl<'a> FakeDkgKey<'a> { } } -impl<'a> PemStorableKey for FakeDkgKey<'a> { +impl PemStorableKey for FakeDkgKey<'_> { type Error = NetworkManagerError; fn pem_type() -> &'static str { @@ -84,7 +84,7 @@ struct DkgSkipCtx<'a> { ecash_signers: Vec, } -impl<'a> ProgressCtx for DkgSkipCtx<'a> { +impl ProgressCtx for DkgSkipCtx<'_> { fn progress_tracker(&self) -> &ProgressTracker { &self.progress } @@ -138,7 +138,7 @@ impl NetworkManager { // generate required materials let n = api_endpoints.len(); - let threshold = (2 * n + 3 - 1) / 3; + let threshold = (2 * n).div_ceil(3); let ecash_keys = ttp_keygen(threshold as u64, n as u64)?; diff --git a/tools/internal/testnet-manager/src/manager/local_apis.rs b/tools/internal/testnet-manager/src/manager/local_apis.rs index 631f6117f2f..124b2a324f7 100644 --- a/tools/internal/testnet-manager/src/manager/local_apis.rs +++ b/tools/internal/testnet-manager/src/manager/local_apis.rs @@ -24,7 +24,7 @@ struct LocalApisCtx<'a> { signers: Vec, } -impl<'a> ProgressCtx for LocalApisCtx<'a> { +impl ProgressCtx for LocalApisCtx<'_> { fn progress_tracker(&self) -> &ProgressTracker { &self.progress } diff --git a/tools/internal/testnet-manager/src/manager/local_client.rs b/tools/internal/testnet-manager/src/manager/local_client.rs index c037f53719c..fac5e6828a6 100644 --- a/tools/internal/testnet-manager/src/manager/local_client.rs +++ b/tools/internal/testnet-manager/src/manager/local_client.rs @@ -30,7 +30,7 @@ struct LocalClientCtx<'a> { network: &'a LoadedNetwork, } -impl<'a> ProgressCtx for LocalClientCtx<'a> { +impl ProgressCtx for LocalClientCtx<'_> { fn progress_tracker(&self) -> &ProgressTracker { &self.progress } diff --git a/tools/internal/testnet-manager/src/manager/local_nodes.rs b/tools/internal/testnet-manager/src/manager/local_nodes.rs index dc19d444362..75edc76b7d3 100644 --- a/tools/internal/testnet-manager/src/manager/local_nodes.rs +++ b/tools/internal/testnet-manager/src/manager/local_nodes.rs @@ -30,7 +30,7 @@ struct LocalNodesCtx<'a> { gateways: Vec, } -impl<'a> ProgressCtx for LocalNodesCtx<'a> { +impl ProgressCtx for LocalNodesCtx<'_> { fn progress_tracker(&self) -> &ProgressTracker { &self.progress }