Skip to content

Commit

Permalink
new routes
Browse files Browse the repository at this point in the history
  • Loading branch information
jstuczyn committed Sep 11, 2024
1 parent 33a3279 commit 24c75af
Show file tree
Hide file tree
Showing 24 changed files with 613 additions and 113 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

76 changes: 74 additions & 2 deletions common/cosmwasm-smart-contracts/contracts-common/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ pub fn truncate_decimal(amount: Decimal) -> Uint128 {
#[derive(Error, Debug)]
pub enum ContractsCommonError {
#[error("Provided percent value ({0}) is greater than 100%")]
InvalidPercent(Decimal),
InvalidPercent(String),

#[error("{source}")]
StdErr {
Expand All @@ -41,7 +41,7 @@ pub struct Percent(#[serde(deserialize_with = "de_decimal_percent")] Decimal);
impl Percent {
pub fn new(value: Decimal) -> Result<Self, ContractsCommonError> {
if value > Decimal::one() {
Err(ContractsCommonError::InvalidPercent(value))
Err(ContractsCommonError::InvalidPercent(value.to_string()))
} else {
Ok(Percent(value))
}
Expand Down Expand Up @@ -129,6 +129,62 @@ impl Deref for Percent {
}
}

// this is not implemented via From traits due to its naive nature and loss of precision
#[cfg(not(target_arch = "wasm32"))]
pub trait NaiveFloat {
fn naive_to_f64(&self) -> f64;

fn naive_try_from_f64(val: f64) -> Result<Self, ContractsCommonError>
where
Self: Sized;
}

#[cfg(not(target_arch = "wasm32"))]
impl NaiveFloat for Percent {
fn naive_to_f64(&self) -> f64 {
use cosmwasm_std::Fraction;

// note: this conversion loses precision with too many decimal places,
// but for the purposes of displaying basic performance, that's not an issue
self.numerator().u128() as f64 / self.denominator().u128() as f64
}

fn naive_try_from_f64(val: f64) -> Result<Self, ContractsCommonError>
where
Self: Sized,
{
// we are only interested in positive values between 0 and 1
if !(0. ..=1.).contains(&val) {
return Err(ContractsCommonError::InvalidPercent(val.to_string()));
}

fn gcd(mut x: u64, mut y: u64) -> u64 {
while y > 0 {
let rem = x % y;
x = y;
y = rem;
}

x
}

fn to_rational(x: f64) -> (u64, u64) {
let log = x.log2().floor();
if log >= 0.0 {
(x as u64, 1)
} else {
let num: u64 = (x / f64::EPSILON) as _;
let den: u64 = (1.0 / f64::EPSILON) as _;
let gcd = gcd(num, den);
(num / gcd, den / gcd)
}
}

let (n, d) = to_rational(val);
Percent::new(Decimal::from_ratio(n, d))
}
}

// implement custom Deserialize because we want to validate Percent has the correct range
fn de_decimal_percent<'de, D>(deserializer: D) -> Result<Decimal, D::Error>
where
Expand Down Expand Up @@ -216,6 +272,7 @@ impl ContractBuildInformation {
#[cfg(test)]
mod tests {
use super::*;
use cosmwasm_std::Fraction;

#[test]
fn percent_serde() {
Expand Down Expand Up @@ -255,4 +312,19 @@ mod tests {
let p = serde_json::from_str::<'_, Percent>("\"1.00\"").unwrap();
assert_eq!(p.round_to_integer(), 100);
}

#[test]
fn naive_float_conversion() {
// around 15 decimal places is the maximum precision we can handle
// which is still way more than enough for what we use it for
let float: f64 = "0.546295475423853".parse().unwrap();
let percent: Percent = "0.546295475423853".parse().unwrap();

assert_eq!(float, percent.naive_to_f64());

let epsilon = Decimal::from_ratio(1u64, 1000000000000000u64);
let converted = Percent::naive_try_from_f64(float).unwrap();

assert!(converted.0 - converted.0 < epsilon);
}
}
2 changes: 1 addition & 1 deletion common/cosmwasm-smart-contracts/mixnet-contract/src/msg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -372,7 +372,7 @@ impl ExecuteMsg {
ExecuteMsg::MigrateGateway { .. } => "migrating legacy gateway".into(),
ExecuteMsg::BondNymNode { .. } => "bonding nym-node".into(),
ExecuteMsg::UnbondNymNode { .. } => "unbonding nym-node".into(),
ExecuteMsg::UpdateNodeConfig { update } => "updating node config".into(),
ExecuteMsg::UpdateNodeConfig { .. } => "updating node config".into(),

#[cfg(feature = "contract-testing")]
ExecuteMsg::TestingResolveAllPendingEvents { .. } => {
Expand Down
24 changes: 12 additions & 12 deletions contracts/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions nym-api/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ nym-node-tester-utils = { path = "../common/node-tester-utils" }
nym-node-requests = { path = "../nym-node/nym-node-requests" }
nym-types = { path = "../common/types" }
nym-http-api-common = { path = "../common/http-api-common", features = ["utoipa"] }
nym-serde-helpers = { path = "../common/serde-helpers", features = ["date"] }

[features]
no-reward = []
Expand Down
7 changes: 7 additions & 0 deletions nym-api/migrations/20240726120000_v3_changes.sql
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,10 @@ CREATE TABLE v3_migration_info (
id INTEGER PRIMARY KEY CHECK (id = 0)
);

--CREATE TABLE node_historical_performance (
-- contract_node_id INTEGER NOT NULL,
-- date DATE NOT NULL,
-- performance FLOAT NOT NULL,
--
-- UNIQUE(contract_node_id, date);
--)
4 changes: 1 addition & 3 deletions nym-api/nym-api-requests/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ cosmwasm-std = { workspace = true }
getset = { workspace = true }
schemars = { workspace = true, features = ["preserve_order"] }
serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true }
ts-rs = { workspace = true, optional = true }
tendermint = { workspace = true }
time = { workspace = true, features = ["serde", "parsing", "formatting"] }
Expand All @@ -35,9 +36,6 @@ nym-node-requests = { path = "../../nym-node/nym-node-requests", default-feature
nym-network-defaults = { path = "../../common/network-defaults" }


[dev-dependencies]
serde_json.workspace = true

[features]
default = []
generate-ts = ["ts-rs", "nym-mixnet-contract-common/generate-ts"]
57 changes: 51 additions & 6 deletions nym-api/nym-api-requests/src/models.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use crate::pagination::PaginatedResponse;
use cosmwasm_std::{Addr, Coin, Decimal, Uint128};
use nym_mixnet_contract_common::reward_params::{Performance, RewardingParams};
use nym_mixnet_contract_common::rewarding::RewardEstimate;
use nym_mixnet_contract_common::{IdentityKey, Interval, MixNode, NodeId, Percent};
use nym_mixnet_contract_common::{IdentityKey, Interval, MixNode, NodeId, NymNodeDetails, Percent};
use nym_network_defaults::{DEFAULT_MIX_LISTENING_PORT, DEFAULT_VERLOC_LISTENING_PORT};
use nym_node_requests::api::v1::authenticator::models::Authenticator;
use nym_node_requests::api::v1::gateway::models::Wireguard;
Expand All @@ -26,7 +26,7 @@ use std::fmt::{Debug, Display, Formatter};
use std::net::IpAddr;
use std::ops::{Deref, DerefMut};
use std::{fmt, time::Duration};
use time::OffsetDateTime;
use time::{Date, OffsetDateTime};
use utoipa::{IntoParams, ToResponse, ToSchema};

#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
Expand Down Expand Up @@ -127,12 +127,27 @@ pub struct NodeAnnotation {
pub last_24h_performance: Performance,
}

#[derive(Clone, Copy, Debug, Default, Serialize, Deserialize, JsonSchema)]
#[derive(Clone, Copy, Debug, Serialize, Deserialize, JsonSchema, ToSchema)]
pub struct AnnotationResponse {
pub node_id: Option<NodeId>,
pub node_id: NodeId,
pub annotation: Option<NodeAnnotation>,
}

#[derive(Clone, Copy, Debug, Serialize, Deserialize, JsonSchema, ToSchema)]
pub struct NodePerformanceResponse {
pub node_id: NodeId,
pub performance: Option<f64>,
}

#[derive(Clone, Copy, Debug, Serialize, Deserialize, JsonSchema, ToSchema)]
pub struct NodeDatePerformanceResponse {
pub node_id: NodeId,
#[schema(value_type = String, example = "1970-01-01")]
#[schemars(with = "String")]
pub date: Date,
pub performance: Option<f64>,
}

#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, ToSchema)]
#[schema(title = "LegacyMixNodeDetailsWithLayer")]
pub struct LegacyMixNodeDetailsWithLayerSchema {
Expand Down Expand Up @@ -392,8 +407,38 @@ pub struct GatewayStatusReportResponse {
pub last_day: Uptime,
}

#[derive(Serialize, Deserialize, schemars::JsonSchema, ToSchema)]
pub struct PerformanceHistoryResponse {
pub node_id: NodeId,
pub history: PaginatedResponse<HistoricalPerformanceResponse>,
}

#[derive(Serialize, Deserialize, schemars::JsonSchema, ToSchema)]
pub struct UptimeHistoryResponse {
pub node_id: NodeId,
pub history: PaginatedResponse<HistoricalUptimeResponse>,
}

#[derive(Clone, Serialize, Deserialize, schemars::JsonSchema, ToSchema)]
pub struct HistoricalUptimeResponse {
#[schema(value_type = String, example = "1970-01-01")]
#[schemars(with = "String")]
pub date: Date,

pub uptime: Uptime,
}

#[derive(Clone, Serialize, Deserialize, schemars::JsonSchema, ToSchema)]
pub struct HistoricalPerformanceResponse {
#[schema(value_type = String, example = "1970-01-01")]
#[schemars(with = "String")]
pub date: Date,

pub performance: f64,
}

#[derive(Clone, Serialize, Deserialize, schemars::JsonSchema, ToSchema)]
pub struct OldHistoricalUptimeResponse {
pub date: String,
#[schema(value_type = u8)]
pub uptime: Uptime,
Expand All @@ -404,14 +449,14 @@ pub struct MixnodeUptimeHistoryResponse {
pub mix_id: NodeId,
pub identity: String,
pub owner: String,
pub history: Vec<HistoricalUptimeResponse>,
pub history: Vec<OldHistoricalUptimeResponse>,
}

#[derive(Clone, Serialize, Deserialize, schemars::JsonSchema, ToSchema)]
pub struct GatewayUptimeHistoryResponse {
pub identity: String,
pub owner: String,
pub history: Vec<HistoricalUptimeResponse>,
pub history: Vec<OldHistoricalUptimeResponse>,
}

#[derive(ToSchema)]
Expand Down
2 changes: 2 additions & 0 deletions nym-api/src/node_describe_cache/query_helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,8 @@ where
F7: Future,
F8: Future,
{
// okay. the fact I have to bypass clippy here means it wasn't a good idea to create this abomination after all
#[allow(clippy::too_many_arguments)]
fn new(
build_info: F1,
roles: F2,
Expand Down
6 changes: 0 additions & 6 deletions nym-api/src/node_status_api/handlers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,3 @@ pub(crate) fn node_status_routes(network_monitor: bool) -> Router<AppState> {
struct MixIdParam {
mix_id: NodeId,
}

#[derive(Deserialize, IntoParams)]
#[into_params(parameter_in = Path)]
struct NodeIdParam {
node_id: NodeId,
}
Loading

0 comments on commit 24c75af

Please sign in to comment.