Compare commits

...

56 Commits

Author SHA1 Message Date
Simon Wicky edfb75b9ef remove test client 2023-03-28 16:12:21 +02:00
Simon Wicky 298591b9e0 Merge commit '009b2131f61dc447ad08b5f1df1e2eef44cde1d2' into simon/instrumented 2023-03-28 13:45:37 +00:00
Simon Wicky 009b2131f6 instrumentation 2023-03-28 13:24:45 +00:00
Simon Wicky e5af0f5d5e Merge commit '3cad2dbb341c23592d22856ced5c8020a7ea20b7' into simon/instrumented 2023-03-28 13:21:46 +00:00
Simon Wicky 3cad2dbb34 Merge remote-tracking branch 'origin/simon/instrumented' into simon/instrumented 2023-03-28 13:18:53 +00:00
Simon Wicky e95e33cd70 Merge commit '6d44fe818ea4c74f476cc6d79434cc8619b45c0c' into simon/instrumented 2023-03-28 13:17:09 +00:00
Simon Wicky 5281895d5b mixnode instrumentation 2023-03-28 12:39:06 +00:00
Simon Wicky 263db0dbc3 Merge commit '6d44fe818ea4c74f476cc6d79434cc8619b45c0c' into Simon/1.1.4 2023-03-28 11:55:06 +00:00
Simon Wicky 6d44fe818e Merge commit '2878e9be9d0c397a746a8c942b818ac1168dff6f' into simon 2023-03-28 11:50:17 +02:00
Simon Wicky b8ec48cf07 small changes to warmup phase 2023-03-28 09:41:35 +00:00
Simon Wicky 99227e837c disable some epoch operations 2023-03-23 07:52:39 +00:00
farbanas 2878e9be9d Merge branch 'release/v1.1.13' 2023-03-22 10:15:32 +01:00
farbanas 7b419c2b12 bump version of contracts 2023-03-22 10:12:33 +01:00
Fran Arbanas 0049126a91 Merge pull request #3200 from nymtech/jon/chore/explicit-cosmwasm-versions-across-workspaces
Set cosmwasm versions on workspace and strictly use 1.0.0
2023-03-22 10:06:18 +01:00
Simon Wicky 34cb142595 packet size the end 2023-03-22 08:40:33 +00:00
Jon Häggblad 80c5194d8b Add explicit cosmwasm-crypto 1.0.0 dev-dependency 2023-03-21 16:34:06 +01:00
Jon Häggblad 27a6b99453 Even more workspace version missed earlier 2023-03-21 16:34:06 +01:00
Jon Häggblad 61982de511 A few more workspace versions 2023-03-21 16:34:06 +01:00
Jon Häggblad efd9883197 Use workspace deps for coconut contracts 2023-03-21 16:34:06 +01:00
Jon Häggblad ce4ae8d90c Set cosmwasm versions on workspace and strictly use 1.0.0 2023-03-21 16:34:06 +01:00
farbanas 1d2722f994 update workflows with specific wasm-opt version 2023-03-21 16:30:40 +01:00
farbanas f7a0b305df update common crate version in contracts 2023-03-21 11:10:55 +01:00
farbanas 746ec71a0d update package versions 2023-03-21 10:54:18 +01:00
farbanas cdfa5ee540 chore: update versions for release/v1.1.13 2023-03-15 15:23:55 +01:00
farbanas 71853f69f3 chore: update changelogs for release/v1.1.13 2023-03-15 15:23:15 +01:00
Tommy Verrall bedff1f258 Merge pull request #3153 from nymtech/oak-14
Validating new interval config parameters to prevent division by zero
2023-03-14 12:38:43 +02:00
Fouad 71a10a9a8b add blockstream green to sp list (#3180) 2023-03-13 17:05:21 +01:00
Jon Häggblad 605aed6f20 mock-nym-api: fix .storybook lint error (#3178) 2023-03-13 12:23:17 +01:00
Tommy Verrall 5aee4b1660 Merge pull request #3167 from nymtech/feature/wallet-3132
Feature/wallet 3132
2023-03-10 17:56:09 +02:00
Tommy Verrall 68a7bb67de Merge pull request #3169 from nymtech/feature/explorer-3168
Feature/explorer 3168
2023-03-10 17:32:22 +02:00
Simon Wicky 2988ae4459 packet size in config 2023-03-10 14:16:53 +00:00
Simon Wicky e653b632ba packet sizes support 2023-03-10 13:18:19 +00:00
Simon Wicky eb216a06b3 redirect mixnodes/active to mixnodes 2023-03-10 13:18:15 +00:00
fmtabbara 31e93428cf use new locked rewards and locked coins endpoints 2023-03-09 16:48:05 +00:00
fmtabbara 5f56b3eeea add bond % tooltip 2023-03-09 16:34:22 +00:00
fmtabbara e69b05693a switch avg and routing score table positions 2023-03-09 16:30:58 +00:00
fmtabbara 8ae2451340 add y-axis label 2023-03-09 16:28:30 +00:00
fmtabbara b3b3279345 fix gateway click thorough from gateway version field 2023-03-09 14:45:45 +00:00
farbanas 94a451c79b fix: updated build-and-upload-binaries-ci workflow with explorer-api and the new contracts 2023-03-09 13:41:22 +01:00
Jędrzej Stuczyński ec7b959028 removed source of future clippy complaints 2023-03-09 11:30:30 +00:00
Jędrzej Stuczyński 7061beea6e exposing tauri operations for spendable vested and reward coins 2023-03-09 11:28:50 +00:00
Fran Arbanas e408162e26 Merge pull request #2747 from nymtech/339-net-switch-bttn
339 net switch bttn
2023-03-09 10:52:00 +01:00
Gala 25ae3895cb updating branch 2023-03-09 10:39:30 +01:00
fmtabbara 60296f2a41 update vesting schedule ui 2023-03-08 17:51:30 +00:00
Fouad 3b97844310 Feature/explorer 2979 (#3147)
* additional unfiltered endpoints for nym-api

* add poor performance UI

* display appropriate UI when node is blacklisted

* update explorer api with blacklisted nodes

* add new unfiltered endpoint

add new unfiltered endpoint

* show blacklisted detail even when node description is unavailable

remove console.log

---------

Co-authored-by: Jędrzej Stuczyński <jedrzej.stuczynski@gmail.com>
2023-03-08 16:15:32 +01:00
Jon Häggblad 8e6d3c34e2 Merge branch 'jon/fix/docs-rs-build' 2023-03-08 09:37:31 +01:00
Jędrzej Stuczyński b1fb8bb18c Validating new interval config parameters to prevent division by zero 2023-03-07 09:51:18 +00:00
Simon Wicky 921f01a789 Merge commit 'f4d0a120bb7f552591c415ece31d9f75bd6ec33e' into Simon/1.1.5 2023-01-31 09:31:24 +00:00
Simon Wicky 27bf8b2e00 tracing first part 2023-01-31 09:25:15 +00:00
Simon Wicky e82a669cd3 merge 1.1.5 2023-01-11 15:17:15 +00:00
Simon Wicky 2015443a90 set default packetsize back to 2 2023-01-10 10:23:51 +00:00
Gala 4f59678ded center layout 2022-12-22 15:31:35 +01:00
Gala 8a1d2af3cf adding changes 2022-12-22 14:44:58 +01:00
Simon Wicky 2c2823f9e1 test instrumentation 2022-12-21 08:31:16 +00:00
Simon Wicky 52b41a5697 add packet sizes support 2022-12-21 08:06:23 +00:00
Simon Wicky 9ee6ae44e2 remove override config, and active nodes 2022-12-21 08:06:13 +00:00
118 changed files with 3975 additions and 1104 deletions
@@ -80,7 +80,7 @@ jobs:
components: rustfmt, clippy
- name: Install wasm-opt
run: cargo install wasm-opt
run: cargo install --version 0.110.0 wasm-opt
- name: Build release contracts
run: make wasm
@@ -99,9 +99,14 @@ jobs:
cp target/release/nym-network-statistics $OUTPUT_DIR
cp target/release/nym-cli $OUTPUT_DIR
cp target/release/credential $OUTPUT_DIR
cp target/release/explorer-api $OUTPUT_DIR
cp contracts/target/wasm32-unknown-unknown/release/mixnet_contract.wasm $OUTPUT_DIR
cp contracts/target/wasm32-unknown-unknown/release/vesting_contract.wasm $OUTPUT_DIR
cp contracts/target/wasm32-unknown-unknown/release/nym_coconut_bandwidth.wasm $OUTPUT_DIR
cp contracts/target/wasm32-unknown-unknown/release/nym_coconut_dkg.wasm $OUTPUT_DIR
cp contracts/target/wasm32-unknown-unknown/release/cw3_flex_multisig.wasm $OUTPUT_DIR
cp contracts/target/wasm32-unknown-unknown/release/cw4_group.wasm $OUTPUT_DIR
- name: Deploy branch to CI www
continue-on-error: true
+1 -1
View File
@@ -20,7 +20,7 @@ jobs:
components: rustfmt, clippy
- name: Install wasm-opt
run: cargo install wasm-opt
run: cargo install --version 0.110.0 wasm-opt
- name: Build release contracts
run: make wasm
-2
View File
@@ -39,7 +39,5 @@ validator-api-config.toml
dist
storybook-static
envs/qwerty.env
Cargo.lock
nym-connect/Cargo.lock
.parcel-cache
**/.DS_Store
+20
View File
@@ -4,6 +4,26 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
## [Unreleased]
## [v1.1.13] (2023-03-15)
- NE - instead of throwing a "Mixnode/Gateway not found" error for blacklisted nodes due to bad performance, show their history but tag them as "Having poor performance" ([#2979])
- NE - Upgrade Sandbox and make below changes: ([#2332])
- Explorer - Updates ([#3168])
- Fix contracts and nym-api audit findings ([#3026])
- Website v2 - deploy infrastructure for strapi and CI ([#2213])
- add blockstream green to sp list ([#3180])
- mock-nym-api: fix .storybook lint error ([#3178])
- Validating new interval config parameters to prevent division by zero ([#3153])
[#2979]: https://github.com/nymtech/nym/issues/2979
[#2332]: https://github.com/nymtech/nym/issues/2332
[#3168]: https://github.com/nymtech/nym/issues/3168
[#3026]: https://github.com/nymtech/nym/issues/3026
[#2213]: https://github.com/nymtech/nym/issues/2213
[#3180]: https://github.com/nymtech/nym/pull/3180
[#3178]: https://github.com/nymtech/nym/pull/3178
[#3153]: https://github.com/nymtech/nym/pull/3153
## [v1.1.12] (2023-03-07)
- Fix generated docs for mixnet and vesting contract on docs.rs ([#3093])
Generated
+748 -489
View File
File diff suppressed because it is too large Load Diff
+10
View File
@@ -107,6 +107,16 @@ license = "Apache-2.0"
[workspace.dependencies]
async-trait = "0.1.64"
cfg-if = "1.0.0"
cosmwasm-derive = "=1.0.0"
cosmwasm-schema = "=1.0.0"
cosmwasm-std = "=1.0.0"
cosmwasm-storage = "=1.0.0"
cw-utils = "=0.13.4"
cw-storage-plus = "=0.13.4"
cw2 = { version = "=0.13.4" }
cw3 = { version = "=0.13.4" }
cw3-fixed-multisig = { version = "=0.13.4" }
cw4 = { version = "=0.13.4" }
dotenvy = "0.15.6"
lazy_static = "1.4.0"
log = "0.4"
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "client-core"
version = "1.1.12"
version = "1.1.13"
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
edition = "2021"
rust-version = "1.66"
@@ -333,7 +333,7 @@ where
fn poll_poisson(&mut self, cx: &mut Context<'_>) -> Poll<Option<StreamMessage>> {
// The average delay could change depending on if backpressure in the downstream channel
// (mix_tx) was detected.
self.adjust_current_average_message_sending_delay();
//self.adjust_current_average_message_sending_delay();
let avg_delay = self.current_average_message_sending_delay();
// Start by checking if we have any incoming messages about closed connections
+22
View File
@@ -697,6 +697,17 @@ pub enum ExtendedPacketSize {
Extended8,
Extended16,
Extended32,
Extended10,
Extended15,
Extended20,
Extended25,
Extended50,
Extended100,
Extended150,
Extended200,
Extended250,
Extended500,
}
impl Default for DebugConfig {
@@ -734,6 +745,17 @@ impl From<ExtendedPacketSize> for PacketSize {
ExtendedPacketSize::Extended8 => PacketSize::ExtendedPacket8,
ExtendedPacketSize::Extended16 => PacketSize::ExtendedPacket16,
ExtendedPacketSize::Extended32 => PacketSize::ExtendedPacket32,
ExtendedPacketSize::Extended10 => PacketSize::ExtendedPacket10,
ExtendedPacketSize::Extended15 => PacketSize::ExtendedPacket15,
ExtendedPacketSize::Extended20 => PacketSize::ExtendedPacket20,
ExtendedPacketSize::Extended25 => PacketSize::ExtendedPacket25,
ExtendedPacketSize::Extended50 => PacketSize::ExtendedPacket50,
ExtendedPacketSize::Extended100 => PacketSize::ExtendedPacket100,
ExtendedPacketSize::Extended150 => PacketSize::ExtendedPacket150,
ExtendedPacketSize::Extended200 => PacketSize::ExtendedPacket200,
ExtendedPacketSize::Extended250 => PacketSize::ExtendedPacket250,
ExtendedPacketSize::Extended500 => PacketSize::ExtendedPacket500,
}
}
}
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "nym-client"
version = "1.1.12"
version = "1.1.13"
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"]
description = "Implementation of the Nym Client"
edition = "2021"
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "nym-socks5-client"
version = "1.1.12"
version = "1.1.13"
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
description = "A SOCKS5 localhost proxy that converts incoming messages to Sphinx and sends them to a Nym address"
edition = "2021"
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "nym-bin-common"
version = "0.2.0"
version = "0.3.0"
description = "Common code for nym binaries"
edition = { workspace = true }
authors = { workspace = true }
@@ -74,7 +74,7 @@ impl PacketRouter {
received_messages.push(received_packet);
} else {
// this can happen if other clients are not padding their messages
warn!("Received message of unexpected size. Probably from an outdated client... len: {}", received_packet.len());
//warn!("Received message of unexpected size. Probably from an outdated client... len: {}", received_packet.len());
received_messages.push(received_packet);
}
}
@@ -8,6 +8,7 @@ edition = "2021"
[dependencies]
futures = "0.3"
tracing = "0.1.37"
log = { workspace = true }
tokio = { version = "1.24.1", features = ["time", "net", "rt"] }
tokio-util = { version = "0.7.4", features = ["codec"] }
@@ -3,11 +3,12 @@
use futures::channel::mpsc;
use futures::StreamExt;
use log::*;
use tracing::*;
use nym_sphinx::framing::codec::SphinxCodec;
use nym_sphinx::framing::packet::FramedSphinxPacket;
use nym_sphinx::params::PacketMode;
use nym_sphinx::{addressing::nodes::NymNodeRoutingAddress, SphinxPacket};
use nym_sphinx::params::packet_sizes::PacketSize;
use std::collections::HashMap;
use std::io;
use std::net::SocketAddr;
@@ -197,6 +198,7 @@ impl Client {
}
impl SendWithoutResponse for Client {
#[instrument(level="info", skip(self, packet), "Sending packet to mixnet", fields(packet_size))]
fn send_without_response(
&mut self,
address: NymNodeRoutingAddress,
@@ -204,13 +206,15 @@ impl SendWithoutResponse for Client {
packet_mode: PacketMode,
) -> io::Result<()> {
trace!("Sending packet to {:?}", address);
let packet_size = PacketSize::get_type(packet.len()).unwrap();
Span::current().record("packet_size", field::debug(packet_size));
let framed_packet =
FramedSphinxPacket::new(packet, packet_mode, self.config.use_legacy_version);
if let Some(sender) = self.conn_new.get_mut(&address) {
if let Err(err) = sender.channel.try_send(framed_packet) {
if err.is_full() {
debug!("Connection to {} seems to not be able to handle all the traffic - dropping the current packet", address);
info!("Connection to {} seems to not be able to handle all the traffic - dropping the current packet", address);
// it's not a 'big' error, but we did not manage to send the packet
// if the queue is full, we can't really do anything but to drop the packet
Err(io::Error::new(
@@ -4,8 +4,8 @@
use crate::client::{Client, Config, SendWithoutResponse};
use futures::channel::mpsc;
use futures::StreamExt;
use log::*;
use nym_sphinx::forwarding::packet::MixPacket;
use tracing::*;
use std::time::Duration;
pub type MixForwardingSender = mpsc::UnboundedSender<MixPacket>;
@@ -53,10 +53,10 @@ impl PacketForwarder {
tokio::select! {
biased;
_ = self.shutdown.recv() => {
log::trace!("PacketForwarder: Received shutdown");
trace!("PacketForwarder: Received shutdown");
}
Some(mix_packet) = self.packet_receiver.next() => {
trace!("Going to forward packet to {:?}", mix_packet.next_hop());
trace!("Going to forward packet to {:?}", mix_packet.next_hop());
let next_hop = mix_packet.next_hop();
let packet_mode = mix_packet.packet_mode();
@@ -40,13 +40,13 @@ async-trait = { workspace = true, optional = true }
bip39 = { version = "1", features = ["rand"], optional = true }
nym-config = { path = "../../config", optional = true }
cosmrs = { git = "https://github.com/neacsu/cosmos-rust", branch = "neacsu/feegrant_support", features = ["rpc", "bip32", "cosmwasm"], optional = true}
cw3 = { version = "0.13.4", optional = true }
cw4 = { version = "0.13.4", optional = true }
cw3 = { workspace = true, optional = true }
cw4 = { workspace = true, optional = true }
prost = { version = "0.10", default-features = false, optional = true }
flate2 = { version = "1.0.20", optional = true }
sha2 = { version = "0.9.5", optional = true }
itertools = { version = "0.10", optional = true }
cosmwasm-std = { version = "1.0.0", optional = true }
cosmwasm-std = { workspace = true, optional = true }
zeroize = { version = "1.5.7", optional = true }
[dev-dependencies]
@@ -749,6 +749,12 @@ where
Ok(self.nym_api.get_mixnodes_detailed().await?)
}
pub async fn get_cached_mixnodes_detailed_unfiltered(
&self,
) -> Result<Vec<MixNodeBondAnnotated>, ValidatorClientError> {
Ok(self.nym_api.get_mixnodes_detailed_unfiltered().await?)
}
pub async fn get_cached_rewarded_mixnodes(
&self,
) -> Result<Vec<MixNodeDetails>, ValidatorClientError> {
@@ -144,6 +144,21 @@ impl Client {
.await
}
pub async fn get_mixnodes_detailed_unfiltered(
&self,
) -> Result<Vec<MixNodeBondAnnotated>, NymAPIError> {
self.query_nym_api(
&[
routes::API_VERSION,
routes::STATUS,
routes::MIXNODES,
routes::DETAILED_UNFILTERED,
],
NO_PARAMS,
)
.await
}
pub async fn get_gateways(&self) -> Result<Vec<GatewayBond>, NymAPIError> {
self.query_nym_api(&[routes::API_VERSION, routes::GATEWAYS], NO_PARAMS)
.await
@@ -8,6 +8,7 @@ pub const MIXNODES: &str = "mixnodes";
pub const GATEWAYS: &str = "gateways";
pub const DETAILED: &str = "detailed";
pub const DETAILED_UNFILTERED: &str = "detailed-unfiltered";
pub const ACTIVE: &str = "active";
pub const REWARDED: &str = "rewarded";
pub const COCONUT_ROUTES: &str = "coconut";
+2 -2
View File
@@ -11,7 +11,7 @@ bs58 = "0.4"
comfy-table = "6.0.0"
cfg-if = "1.0.0"
clap = { version = "4.0", features = ["derive"] }
cw-utils = { version = "0.13.4" }
cw-utils = { workspace = true }
handlebars = "3.0.1"
humantime-serde = "1.0"
k256 = { version = "0.10", features = ["ecdsa", "sha256"] }
@@ -26,7 +26,7 @@ url = "2.2"
tap = "1"
cosmrs = { git = "https://github.com/neacsu/cosmos-rust", branch = "neacsu/feegrant_support" }
cosmwasm-std = { version = "1.0.0" }
cosmwasm-std = { workspace = true }
validator-client = { path = "../client-libs/validator-client", features = ["nyxd-client"] }
nym-network-defaults = { path = "../network-defaults" }
@@ -6,7 +6,7 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
cosmwasm-std = "1.0.0"
cosmwasm-std = { workspace = true }
schemars = "0.8"
serde = { version = "1.0.103", default-features = false, features = ["derive"] }
nym-multisig-contract-common = { path = "../multisig-contract" }
@@ -6,8 +6,8 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
cosmwasm-std = "1.0.0"
cw-utils = "0.13.4"
cosmwasm-std = { workspace = true }
cw-utils = { workspace = true }
schemars = "0.8"
serde = { version = "1.0.103", default-features = false, features = ["derive"] }
@@ -1,6 +1,6 @@
[package]
name = "nym-contracts-common"
version = "0.2.0"
version = "0.3.0"
description = "Common library for Nym cosmwasm contracts"
edition = { workspace = true }
authors = { workspace = true }
@@ -9,7 +9,7 @@ repository = { workspace = true }
[dependencies]
bs58 = "0.4.0"
cosmwasm-std = "1.0.0"
cosmwasm-std = { workspace = true }
schemars = "0.8"
serde = { version = "1.0", features = ["derive"] }
thiserror = "1"
@@ -6,6 +6,6 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
cw4 = { version = "0.13.4" }
cw4 = { workspace = true }
schemars = "0.8"
serde = { version = "1.0.103", default-features = false, features = ["derive"] }
@@ -1,6 +1,6 @@
[package]
name = "nym-mixnet-contract-common"
version = "0.2.0"
version = "0.3.0"
description = "Common library for the Nym mixnet contract"
rust-version = "1.62"
edition = { workspace = true }
@@ -10,12 +10,12 @@ repository = { workspace = true }
[dependencies]
bs58 = "0.4.0"
cosmwasm-std = "1.0.0"
cosmwasm-std = { workspace = true }
serde = { version = "1.0", features = ["derive"] }
serde_repr = "0.1"
schemars = "0.8"
thiserror = "1.0"
contracts-common = { path = "../contracts-common", package = "nym-contracts-common", version = "0.2.0" }
contracts-common = { path = "../contracts-common", package = "nym-contracts-common", version = "0.3.0" }
serde_json = "1.0.0"
humantime-serde = "1.1.1"
@@ -6,11 +6,11 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
cw-utils = { version = "0.13.4" }
cw3 = { version = "0.13.4" }
cw3-fixed-multisig = { version = "0.13.4", features = ["library"] }
cw4 = { version = "0.13.4" }
cosmwasm-std = "1.0.0"
cw-utils = { workspace = true }
cw3 = { workspace = true }
cw3-fixed-multisig = { workspace = true, features = ["library"] }
cw4 = { workspace= true }
cosmwasm-std = { workspace = true }
schemars = "0.8"
serde = { version = "1.0.103", default-features = false, features = ["derive"] }
thiserror = { version = "1.0.23" }
@@ -1,6 +1,6 @@
[package]
name = "nym-vesting-contract-common"
version = "0.2.0"
version = "0.3.0"
description = "Common library for the Nym vesting contract"
edition = { workspace = true }
authors = { workspace = true }
@@ -8,9 +8,9 @@ license = { workspace = true }
repository = { workspace = true }
[dependencies]
cosmwasm-std = "1.0.0"
mixnet-contract-common = { path = "../mixnet-contract", package = "nym-mixnet-contract-common", version = "0.2.0" }
contracts-common = { path = "../contracts-common", package = "nym-contracts-common", version = "0.2.0" }
cosmwasm-std = { workspace = true }
mixnet-contract-common = { path = "../mixnet-contract", package = "nym-mixnet-contract-common", version = "0.3.0" }
contracts-common = { path = "../contracts-common", package = "nym-contracts-common", version = "0.3.0" }
serde = { version = "1.0", features = ["derive"] }
schemars = "0.8"
ts-rs = {version = "6.1.2", optional = true}
+1
View File
@@ -16,6 +16,7 @@ serde = { version = "1.0", features = ["derive"] }
tokio = { version = "1.24.1", features = ["time", "macros", "rt", "net", "io-util"] }
tokio-util = { version = "0.7.4", features = ["codec"] }
url = "2.2"
tracing = "0.1.37"
thiserror = "1.0.37"
nym-crypto = { path = "../crypto" }
@@ -2,7 +2,7 @@
// SPDX-License-Identifier: Apache-2.0
use crate::packet_processor::error::MixProcessingError;
use log::*;
use tracing::*;
use nym_sphinx_acknowledgements::surb_ack::SurbAck;
use nym_sphinx_addressing::nodes::NymNodeRoutingAddress;
use nym_sphinx_forwarding::packet::MixPacket;
@@ -57,6 +57,7 @@ impl SphinxPacketProcessor {
}
/// Takes the received framed packet and tries to unwrap it from the sphinx encryption.
#[instrument(level="debug", skip_all)]
fn perform_initial_unwrapping(
&self,
received: FramedSphinxPacket,
@@ -73,6 +74,7 @@ impl SphinxPacketProcessor {
/// Processed received forward hop packet - tries to extract next hop address, sets delay
/// and packs all the data in a way that can be easily sent to the next hop.
#[instrument(level="debug", skip_all)]
fn process_forward_hop(
&self,
packet: SphinxPacket,
@@ -88,6 +90,7 @@ impl SphinxPacketProcessor {
/// Split data extracted from the final hop sphinx packet into a SURBAck and message
/// that should get delivered to a client.
#[instrument(level="debug", skip_all)]
fn split_hop_data_into_ack_and_message(
&self,
mut extracted_data: Vec<u8>,
@@ -105,6 +108,7 @@ impl SphinxPacketProcessor {
/// Tries to extract a SURBAck that could be sent back into the mix network and message
/// that should get delivered to a client from received Sphinx packet.
#[instrument(level="debug", skip_all)]
fn split_into_ack_and_message(
&self,
data: Vec<u8>,
@@ -116,10 +120,7 @@ impl SphinxPacketProcessor {
trace!("received an ack packet!");
Ok((None, data))
}
PacketSize::RegularPacket
| PacketSize::ExtendedPacket8
| PacketSize::ExtendedPacket16
| PacketSize::ExtendedPacket32 => {
_ => {
trace!("received a normal packet!");
let (ack_data, message) = self.split_hop_data_into_ack_and_message(data)?;
let (ack_first_hop, ack_packet) = SurbAck::try_recover_first_hop_packet(&ack_data)?;
@@ -132,6 +133,7 @@ impl SphinxPacketProcessor {
/// Processed received final hop packet - tries to extract SURBAck out of it (assuming the
/// packet itself is not an ACK) and splits it from the message that should get delivered
/// to the destination.
#[instrument(level="debug", skip_all)]
fn process_final_hop(
&self,
destination: DestinationAddressBytes,
@@ -153,6 +155,7 @@ impl SphinxPacketProcessor {
/// Performs final processing for the unwrapped packet based on whether it was a forward hop
/// or a final hop.
#[instrument(level="debug", skip_all)]
fn perform_final_processing(
&self,
packet: ProcessedPacket,
@@ -170,7 +173,7 @@ impl SphinxPacketProcessor {
}
}
}
#[instrument(level="debug", skip_all, fields(packet_size=?received.packet_size()))]
pub fn process_received(
&self,
received: FramedSphinxPacket,
+83 -1
View File
@@ -20,6 +20,16 @@ const ACK_PACKET_SIZE: usize = HEADER_SIZE + PAYLOAD_OVERHEAD_SIZE + ACK_IV_SIZE
const EXTENDED_PACKET_SIZE_8: usize = HEADER_SIZE + PAYLOAD_OVERHEAD_SIZE + 8 * 1024;
const EXTENDED_PACKET_SIZE_16: usize = HEADER_SIZE + PAYLOAD_OVERHEAD_SIZE + 16 * 1024;
const EXTENDED_PACKET_SIZE_32: usize = HEADER_SIZE + PAYLOAD_OVERHEAD_SIZE + 32 * 1024;
const EXTENDED_PACKET_SIZE_10: usize = HEADER_SIZE + PAYLOAD_OVERHEAD_SIZE + 10 * 1024;
const EXTENDED_PACKET_SIZE_15: usize = HEADER_SIZE + PAYLOAD_OVERHEAD_SIZE + 15 * 1024;
const EXTENDED_PACKET_SIZE_20: usize = HEADER_SIZE + PAYLOAD_OVERHEAD_SIZE + 20 * 1024;
const EXTENDED_PACKET_SIZE_25: usize = HEADER_SIZE + PAYLOAD_OVERHEAD_SIZE + 25 * 1024;
const EXTENDED_PACKET_SIZE_50: usize = HEADER_SIZE + PAYLOAD_OVERHEAD_SIZE + 50 * 1024;
const EXTENDED_PACKET_SIZE_100: usize = HEADER_SIZE + PAYLOAD_OVERHEAD_SIZE + 100 * 1024;
const EXTENDED_PACKET_SIZE_150: usize = HEADER_SIZE + PAYLOAD_OVERHEAD_SIZE + 150 * 1024;
const EXTENDED_PACKET_SIZE_200: usize = HEADER_SIZE + PAYLOAD_OVERHEAD_SIZE + 200 * 1024;
const EXTENDED_PACKET_SIZE_250: usize = HEADER_SIZE + PAYLOAD_OVERHEAD_SIZE + 250 * 1024;
const EXTENDED_PACKET_SIZE_500: usize = HEADER_SIZE + PAYLOAD_OVERHEAD_SIZE + 500 * 1024;
#[derive(Debug, Error)]
pub enum InvalidPacketSize {
@@ -51,6 +61,18 @@ pub enum PacketSize {
// for example for streaming fast and furious in compressed XviD quality
ExtendedPacket16 = 5,
ExtendedPacket10 = 6,
ExtendedPacket15 = 7,
ExtendedPacket20 = 8,
ExtendedPacket25 = 9,
ExtendedPacket50 = 10,
ExtendedPacket100 = 11,
ExtendedPacket150 = 12,
ExtendedPacket200 = 13,
ExtendedPacket250 = 14,
ExtendedPacket500 = 15,
}
impl FromStr for PacketSize {
@@ -63,6 +85,16 @@ impl FromStr for PacketSize {
"extended8" => Ok(Self::ExtendedPacket8),
"extended16" => Ok(Self::ExtendedPacket16),
"extended32" => Ok(Self::ExtendedPacket32),
"extended10" => Ok(Self::ExtendedPacket10),
"extended15" => Ok(Self::ExtendedPacket15),
"extended20" => Ok(Self::ExtendedPacket20),
"extended25" => Ok(Self::ExtendedPacket25),
"extended50" => Ok(Self::ExtendedPacket50),
"extended100" => Ok(Self::ExtendedPacket100),
"extended150" => Ok(Self::ExtendedPacket150),
"extended200" => Ok(Self::ExtendedPacket200),
"extended250" => Ok(Self::ExtendedPacket250),
"extended500" => Ok(Self::ExtendedPacket500),
s => Err(InvalidPacketSize::UnknownExtendedPacketVariant {
received: s.to_string(),
}),
@@ -80,6 +112,16 @@ impl TryFrom<u8> for PacketSize {
_ if value == (PacketSize::ExtendedPacket8 as u8) => Ok(Self::ExtendedPacket8),
_ if value == (PacketSize::ExtendedPacket16 as u8) => Ok(Self::ExtendedPacket16),
_ if value == (PacketSize::ExtendedPacket32 as u8) => Ok(Self::ExtendedPacket32),
_ if value == (PacketSize::ExtendedPacket10 as u8) => Ok(Self::ExtendedPacket10),
_ if value == (PacketSize::ExtendedPacket15 as u8) => Ok(Self::ExtendedPacket15),
_ if value == (PacketSize::ExtendedPacket20 as u8) => Ok(Self::ExtendedPacket20),
_ if value == (PacketSize::ExtendedPacket25 as u8) => Ok(Self::ExtendedPacket25),
_ if value == (PacketSize::ExtendedPacket50 as u8) => Ok(Self::ExtendedPacket50),
_ if value == (PacketSize::ExtendedPacket100 as u8) => Ok(Self::ExtendedPacket100),
_ if value == (PacketSize::ExtendedPacket150 as u8) => Ok(Self::ExtendedPacket150),
_ if value == (PacketSize::ExtendedPacket200 as u8) => Ok(Self::ExtendedPacket200),
_ if value == (PacketSize::ExtendedPacket250 as u8) => Ok(Self::ExtendedPacket250),
_ if value == (PacketSize::ExtendedPacket500 as u8) => Ok(Self::ExtendedPacket500),
v => Err(InvalidPacketSize::UnknownPacketTag { received: v }),
}
}
@@ -93,6 +135,16 @@ impl PacketSize {
PacketSize::ExtendedPacket8 => EXTENDED_PACKET_SIZE_8,
PacketSize::ExtendedPacket16 => EXTENDED_PACKET_SIZE_16,
PacketSize::ExtendedPacket32 => EXTENDED_PACKET_SIZE_32,
PacketSize::ExtendedPacket10 => EXTENDED_PACKET_SIZE_10,
PacketSize::ExtendedPacket15 => EXTENDED_PACKET_SIZE_15,
PacketSize::ExtendedPacket20 => EXTENDED_PACKET_SIZE_20,
PacketSize::ExtendedPacket25 => EXTENDED_PACKET_SIZE_25,
PacketSize::ExtendedPacket50 => EXTENDED_PACKET_SIZE_50,
PacketSize::ExtendedPacket100 => EXTENDED_PACKET_SIZE_100,
PacketSize::ExtendedPacket150 => EXTENDED_PACKET_SIZE_150,
PacketSize::ExtendedPacket200 => EXTENDED_PACKET_SIZE_200,
PacketSize::ExtendedPacket250 => EXTENDED_PACKET_SIZE_250,
PacketSize::ExtendedPacket500 => EXTENDED_PACKET_SIZE_500,
}
}
@@ -115,6 +167,26 @@ impl PacketSize {
Ok(PacketSize::ExtendedPacket16)
} else if PacketSize::ExtendedPacket32.size() == size {
Ok(PacketSize::ExtendedPacket32)
} else if PacketSize::ExtendedPacket10.size() == size {
Ok(PacketSize::ExtendedPacket10)
} else if PacketSize::ExtendedPacket15.size() == size {
Ok(PacketSize::ExtendedPacket15)
} else if PacketSize::ExtendedPacket20.size() == size {
Ok(PacketSize::ExtendedPacket20)
} else if PacketSize::ExtendedPacket25.size() == size {
Ok(PacketSize::ExtendedPacket25)
} else if PacketSize::ExtendedPacket50.size() == size {
Ok(PacketSize::ExtendedPacket50)
} else if PacketSize::ExtendedPacket100.size() == size {
Ok(PacketSize::ExtendedPacket100)
} else if PacketSize::ExtendedPacket150.size() == size {
Ok(PacketSize::ExtendedPacket150)
} else if PacketSize::ExtendedPacket200.size() == size {
Ok(PacketSize::ExtendedPacket200)
} else if PacketSize::ExtendedPacket250.size() == size {
Ok(PacketSize::ExtendedPacket250)
} else if PacketSize::ExtendedPacket500.size() == size {
Ok(PacketSize::ExtendedPacket500)
} else {
Err(InvalidPacketSize::UnknownPacketSize { received: size })
}
@@ -125,7 +197,17 @@ impl PacketSize {
PacketSize::RegularPacket | PacketSize::AckPacket => false,
PacketSize::ExtendedPacket8
| PacketSize::ExtendedPacket16
| PacketSize::ExtendedPacket32 => true,
| PacketSize::ExtendedPacket32
| PacketSize::ExtendedPacket10
| PacketSize::ExtendedPacket15
| PacketSize::ExtendedPacket20
| PacketSize::ExtendedPacket25
| PacketSize::ExtendedPacket50
| PacketSize::ExtendedPacket100
| PacketSize::ExtendedPacket150
| PacketSize::ExtendedPacket200
| PacketSize::ExtendedPacket250
| PacketSize::ExtendedPacket500 => true,
}
}
@@ -47,6 +47,16 @@ impl From<u8> for PacketVersion {
n if n == PacketSize::ExtendedPacket8 as u8 => PacketVersion::Legacy,
n if n == PacketSize::ExtendedPacket16 as u8 => PacketVersion::Legacy,
n if n == PacketSize::ExtendedPacket32 as u8 => PacketVersion::Legacy,
n if n == PacketSize::ExtendedPacket10 as u8 => PacketVersion::Legacy,
n if n == PacketSize::ExtendedPacket15 as u8 => PacketVersion::Legacy,
n if n == PacketSize::ExtendedPacket20 as u8 => PacketVersion::Legacy,
n if n == PacketSize::ExtendedPacket25 as u8 => PacketVersion::Legacy,
n if n == PacketSize::ExtendedPacket50 as u8 => PacketVersion::Legacy,
n if n == PacketSize::ExtendedPacket100 as u8 => PacketVersion::Legacy,
n if n == PacketSize::ExtendedPacket150 as u8 => PacketVersion::Legacy,
n if n == PacketSize::ExtendedPacket200 as u8 => PacketVersion::Legacy,
n if n == PacketSize::ExtendedPacket250 as u8 => PacketVersion::Legacy,
n if n == PacketSize::ExtendedPacket500 as u8 => PacketVersion::Legacy,
n => PacketVersion::Versioned(n),
}
}
+1 -1
View File
@@ -19,7 +19,7 @@ thiserror = "1.0"
url = "2.2"
ts-rs = "6.1.2"
cosmwasm-std = "1.0.0"
cosmwasm-std = { workspace = true }
cosmrs = { git = "https://github.com/neacsu/cosmos-rust", branch = "neacsu/feegrant_support" }
validator-client = { path = "../../common/client-libs/validator-client", features = [
-1
View File
@@ -1 +0,0 @@
Cargo.lock
+2037
View File
File diff suppressed because it is too large Load Diff
+15
View File
@@ -27,3 +27,18 @@ codegen-units = 1
panic = 'abort'
incremental = false
overflow-checks = true
[workspace.dependencies]
cosmwasm-crypto = "=1.0.0"
cosmwasm-derive = "=1.0.0"
cosmwasm-schema = "=1.0.0"
cosmwasm-std = "=1.0.0"
cosmwasm-storage = "=1.0.0"
cw-controllers = "=0.13.4"
cw-multi-test = "=0.13.4"
cw-storage-plus = "=0.13.4"
cw-utils = "=0.13.4"
cw2 = "=0.13.4"
cw3 = "=0.13.4"
cw3-fixed-multisig = "=0.13.4"
cw4 = "=0.13.4"
+4 -4
View File
@@ -13,10 +13,10 @@ nym-bandwidth-claim-contract = { path = "../../common/bandwidth-claim-contract"
nym-coconut-bandwidth-contract-common = { path = "../../common/cosmwasm-smart-contracts/coconut-bandwidth-contract" }
nym-multisig-contract-common = { path = "../../common/cosmwasm-smart-contracts/multisig-contract" }
cosmwasm-std = "1.0.0"
cosmwasm-storage = "1.0.0"
cw-storage-plus = "0.13.4"
cw-controllers = "0.13.4"
cosmwasm-std = { workspace = true }
cosmwasm-storage = { workspace = true }
cw-storage-plus = { workspace = true }
cw-controllers = { workspace = true }
schemars = "0.8"
serde = { version = "1.0.103", default-features = false, features = ["derive"] }
+6 -6
View File
@@ -11,18 +11,18 @@ crate-type = ["cdylib", "rlib"]
[dependencies]
nym-coconut-dkg-common = { path = "../../common/cosmwasm-smart-contracts/coconut-dkg" }
cosmwasm-std = "1.0.0"
cosmwasm-storage = "1.0.0"
cw-storage-plus = "0.13.4"
cw-controllers = "0.13.4"
cw4 = { version = "0.13.4" }
cosmwasm-std = { workspace = true }
cosmwasm-storage = { workspace = true }
cw-storage-plus = { workspace = true }
cw-controllers = { workspace = true }
cw4 = { workspace = true }
schemars = "0.8"
serde = { version = "1.0.103", default-features = false, features = ["derive"] }
thiserror = "1.0.23"
[dev-dependencies]
cw-multi-test = { version = "0.13.4" }
cw-multi-test = { workspace = true }
cw4-group = { path = "../multisig/cw4-group" }
nym-group-contract-common = { path = "../../common/cosmwasm-smart-contracts/group-contract" }
lazy_static = "1.4"
+8 -8
View File
@@ -13,13 +13,13 @@ nym-coconut-dkg-common = { path = "../../common/cosmwasm-smart-contracts/coconut
nym-multisig-contract-common = { path = "../../common/cosmwasm-smart-contracts/multisig-contract" }
nym-group-contract-common = { path = "../../common/cosmwasm-smart-contracts/group-contract" }
cosmwasm-std = "1.0.0"
cosmwasm-storage = "1.0.0"
cw3 = "0.13.4"
cw4 = "0.13.4"
cw-storage-plus = "0.13.4"
cw-controllers = "0.13.4"
cw-utils = "0.13.4"
cosmwasm-std = { workspace = true }
cosmwasm-storage = { workspace = true }
cw3 = { workspace = true }
cw4 = { workspace = true }
cw-storage-plus = { workspace = true }
cw-controllers = { workspace = true }
cw-utils = { workspace = true }
schemars = "0.8"
serde = { version = "1.0.103", default-features = false, features = ["derive"] }
@@ -27,7 +27,7 @@ thiserror = "1.0.23"
nym-coconut-bandwidth = { path = "../coconut-bandwidth" }
nym-coconut-dkg = { path = "../coconut-dkg" }
cw-multi-test = { version = "0.13.4" }
cw-multi-test = { workspace = true }
cw3-flex-multisig = { path = "../multisig/cw3-flex-multisig" }
cw4-group = { path = "../multisig/cw4-group" }
+9 -8
View File
@@ -1,6 +1,6 @@
[package]
name = "nym-mixnet-contract"
version = "1.2.0-pre.0"
version = "1.2.0"
description = "Nym mixnet contract"
edition = { workspace = true }
authors = { workspace = true }
@@ -22,14 +22,15 @@ name = "mixnet_contract"
crate-type = ["cdylib", "rlib"]
[dependencies]
mixnet-contract-common = { path = "../../common/cosmwasm-smart-contracts/mixnet-contract", package = "nym-mixnet-contract-common", version = "0.2.0" }
vesting-contract-common = { path = "../../common/cosmwasm-smart-contracts/vesting-contract", package = "nym-vesting-contract-common", version = "0.2.0" }
mixnet-contract-common = { path = "../../common/cosmwasm-smart-contracts/mixnet-contract", package = "nym-mixnet-contract-common", version = "0.3.0" }
vesting-contract-common = { path = "../../common/cosmwasm-smart-contracts/vesting-contract", package = "nym-vesting-contract-common", version = "0.3.0" }
#nym-config = { path = "../../common/config"}
cosmwasm-std = "1.0.0"
cosmwasm-storage = "1.0.0"
cw2 = { version = "0.13.4" }
cw-storage-plus = "0.13.4"
cosmwasm-std = { workspace = true }
cosmwasm-storage = { workspace = true }
cosmwasm-derive = { workspace = true }
cw2 = { workspace = true }
cw-storage-plus = { workspace = true }
bs58 = "0.4.0"
schemars = "0.8"
@@ -39,7 +40,7 @@ time = { version = "0.3", features = ["macros"] }
semver = { version = "1.0.16", default-features = false }
[dev-dependencies]
cosmwasm-schema = "1.0.0"
cosmwasm-schema = { workspace = true }
rand_chacha = "0.2"
#rand = "0.7"
nym-crypto = { path = "../../common/crypto", features = ["asymmetric", "rand"] }
@@ -327,6 +327,14 @@ pub(crate) fn try_update_interval_config(
) -> Result<Response, MixnetContractError> {
ensure_is_owner(info.sender, deps.storage)?;
if epochs_in_interval == 0 {
return Err(MixnetContractError::EpochsInIntervalZero);
}
if epoch_duration_secs == 0 {
return Err(MixnetContractError::EpochDurationZero);
}
let interval = storage::current_interval(deps.storage)?;
if force_immediately || interval.is_current_interval_over(&env) {
change_interval_config(
@@ -17,13 +17,13 @@ crate-type = ["cdylib", "rlib"]
library = []
[dependencies]
cw-utils = { version = "0.13.4" }
cw2 = { version = "0.13.4" }
cw3 = { version = "0.13.4" }
cw3-fixed-multisig = { version = "0.13.4", features = ["library"] }
cw4 = { version = "0.13.4" }
cw-storage-plus = { version = "0.13.4" }
cosmwasm-std = { version = "1.0.0" }
cw-utils = { workspace = true }
cw2 = { workspace = true }
cw3 = { workspace = true }
cw3-fixed-multisig = { workspace = true, features = ["library"] }
cw4 = { workspace = true }
cw-storage-plus = { workspace = true }
cosmwasm-std = { workspace = true }
schemars = "0.8.1"
serde = { version = "1.0.103", default-features = false, features = ["derive"] }
@@ -33,4 +33,4 @@ nym-multisig-contract-common = { path= "../../../common/cosmwasm-smart-contracts
[dev-dependencies]
cosmwasm-schema = { version = "1.0.0" }
cw4-group = { path = "../cw4-group", version = "0.13.4" }
cw-multi-test = { version = "0.13.4" }
cw-multi-test = { workspace = true }
+7 -7
View File
@@ -26,15 +26,15 @@ library = []
[dependencies]
nym-group-contract-common = { path = "../../../common/cosmwasm-smart-contracts/group-contract" }
cw-utils = { version = "0.13.4" }
cw2 = { version = "0.13.4" }
cw4 = { version = "0.13.4" }
cw-controllers = { version = "0.13.4" }
cw-storage-plus = { version = "0.13.4" }
cosmwasm-std = { version = "1.0.0" }
cw-utils = { workspace = true }
cw2 = { workspace = true }
cw4 = { workspace = true }
cw-controllers = { workspace = true }
cw-storage-plus = { workspace = true }
cosmwasm-std = { workspace = true }
schemars = "0.8.1"
serde = { version = "1.0.103", default-features = false, features = ["derive"] }
thiserror = { version = "1.0.23" }
[dev-dependencies]
cosmwasm-schema = { version = "1.0.0" }
cosmwasm-schema = { workspace = true }
+9 -7
View File
@@ -1,6 +1,6 @@
[package]
name = "nym-vesting-contract"
version = "1.2.0-pre.1"
version = "1.2.0"
description = "Nym vesting contract"
edition = { workspace = true }
authors = { workspace = true }
@@ -20,13 +20,14 @@ name = "vesting_contract"
crate-type = ["cdylib", "rlib"]
[dependencies]
mixnet-contract-common = { path = "../../common/cosmwasm-smart-contracts/mixnet-contract", package = "nym-mixnet-contract-common", version = "0.2.0" }
contracts-common = { path = "../../common/cosmwasm-smart-contracts/contracts-common", package = "nym-contracts-common", version = "0.2.0" }
vesting-contract-common = { path = "../../common/cosmwasm-smart-contracts/vesting-contract", package = "nym-vesting-contract-common", version = "0.2.0" }
mixnet-contract-common = { path = "../../common/cosmwasm-smart-contracts/mixnet-contract", package = "nym-mixnet-contract-common", version = "0.3.0" }
contracts-common = { path = "../../common/cosmwasm-smart-contracts/contracts-common", package = "nym-contracts-common", version = "0.3.0" }
vesting-contract-common = { path = "../../common/cosmwasm-smart-contracts/vesting-contract", package = "nym-vesting-contract-common", version = "0.3.0" }
cosmwasm-std = { version = "1.0.0 "}
cw2 = { version = "0.13.4" }
cw-storage-plus = { version = "0.13.4", features = ["iterator"] }
cosmwasm-std = { workspace = true }
cosmwasm-derive = { workspace = true }
cw2 = { workspace = true }
cw-storage-plus = { workspace = true, features = ["iterator"] }
schemars = "0.8"
serde = { version = "1.0", default-features = false, features = ["derive"] }
@@ -38,6 +39,7 @@ rand_chacha = "0.3.1"
base64 = "0.21.0"
hex = "0.4.3"
serde_json = "1.0.66"
cosmwasm-crypto = { workspace = true }
[build-dependencies]
vergen = { version = "=7.4.3", default-features = false, features = ["build", "git", "rustc"] }
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "explorer-api"
version = "1.1.12"
version = "1.1.13"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+1
View File
@@ -42,6 +42,7 @@ pub(crate) struct PrettyDetailedMixNodeBond {
pub operating_cost: Coin,
pub profit_margin_percent: Percent,
pub family_id: Option<u16>,
pub blacklisted: bool,
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, JsonSchema)]
+1
View File
@@ -162,6 +162,7 @@ impl ThreadsafeMixNodesCache {
operating_cost: rewarding_info.cost_params.interval_operating_cost.clone(),
profit_margin_percent: rewarding_info.cost_params.profit_margin_percent,
family_id,
blacklisted: node.blacklisted,
}
}
+1 -1
View File
@@ -43,7 +43,7 @@ impl ExplorerApiTasks {
async fn retrieve_all_mixnodes(&self) -> Vec<MixNodeBondAnnotated> {
info!("About to retrieve all mixnode bonds...");
self.retrieve_mixnodes(validator_client::Client::get_cached_mixnodes_detailed)
self.retrieve_mixnodes(validator_client::Client::get_cached_mixnodes_detailed_unfiltered)
.await
}
+7
View File
@@ -1,4 +1,5 @@
import {
API_BASE_URL,
BLOCK_API,
COUNTRY_DATA_API,
GATEWAYS_API,
@@ -27,6 +28,7 @@ import {
StatusResponse,
SummaryOverviewResponse,
ValidatorsResponse,
Environment,
GatewayBondAnnotated,
GatewayBond,
DirectoryService,
@@ -157,3 +159,8 @@ export class Api {
return json;
};
}
export const getEnvironment = (): Environment => {
const matchEnv = (env: Environment) => API_BASE_URL?.toLocaleLowerCase().includes(env) && env;
return matchEnv('sandbox') || matchEnv('qa') || 'mainnet';
};
@@ -36,16 +36,16 @@ export const EconomicsInfoColumns: ColumnsType[] = [
tooltipInfo:
'Monthly operational cost of running this node. This cost is set by the operator and it influences how the rewards are split between the operator and delegators.',
},
{
field: 'avgUptime',
title: 'Avg. Score',
width: '10%',
tooltipInfo: "Mixnode's average routing score in the last 24 hour",
},
{
field: 'nodePerformance',
title: 'Routing Score',
width: '10%',
tooltipInfo:
"Mixnode's most recent score (measured in the last 15 minutes). Routing score is relative to that of the network. Each time a gateway is tested, the test packets have to go through the full path of the network (gateway + 3 nodes). If a node in the path drop packets it will affect the score of the gateway and other nodes in the test.",
},
{
field: 'avgUptime',
title: 'Avg. Score',
tooltipInfo: "Mixnode's average routing score in the last 24 hour",
},
];
@@ -53,7 +53,6 @@ export const DelegatorsInfoTable: FCWithChildren<UniversalTableProps<EconomicsIn
{columnsData?.map((_, index: number) => {
const { field } = columnsData[index];
const value: EconomicsRowsType = (eachRow as any)[field];
console.log(value);
return (
<TableCell
key={_.title}
@@ -20,6 +20,7 @@ export type MixnodeRowType = {
stake_saturation: React.ReactNode;
operating_cost: string;
node_performance: NodePerformance['most_recent'];
blacklisted: boolean;
};
export function mixnodeToGridRow(arrayOfMixnodes?: MixNodeResponse): MixnodeRowType[] {
@@ -51,5 +52,6 @@ export function mixNodeResponseItemToMixnodeRowType(item: MixNodeResponseItem):
stake_saturation: uncappedSaturation.toFixed(2),
operating_cost: `${unymToNym(item.operating_cost?.amount, 6)} NYM`,
node_performance: `${toPercentIntegerString(item.node_performance.most_recent)}%`,
blacklisted: item.blacklisted,
};
}
+22 -6
View File
@@ -27,11 +27,18 @@ import { DarkLightSwitchMobile } from './Switch';
export const MobileNav: FCWithChildren = ({ children }) => {
const theme = useTheme();
const { navState, updateNavState } = useMainContext();
const { navState, updateNavState, environment } = useMainContext();
const [drawerOpen, setDrawerOpen] = React.useState(false);
// Set maintenance banner to false by default to don't display it
const [openMaintenance, setOpenMaintenance] = React.useState(false);
const explorerName =
`${environment && environment.charAt(0).toUpperCase() + environment.slice(1)} Explorer` || 'Mainnet Explorer';
const switchNetworkText = environment === 'mainnet' ? 'Switch to Testnet' : 'Switch to Mainnet';
const switchNetworkLink =
environment === 'mainnet' ? 'https://sandbox-explorer.nymtech.net' : 'https://explorer.nymtech.net';
const toggleDrawer = () => {
setDrawerOpen(!drawerOpen);
};
@@ -59,6 +66,7 @@ export const MobileNav: FCWithChildren = ({ children }) => {
sx={{
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
width: '100%',
}}
>
@@ -72,7 +80,7 @@ export const MobileNav: FCWithChildren = ({ children }) => {
}}
>
<IconButton component="a" href={NYM_WEBSITE} target="_blank">
<NymLogo height="40px" width="40px" />
<NymLogo height="24px" width="24px" />
</IconButton>
<Typography
variant="h6"
@@ -81,16 +89,24 @@ export const MobileNav: FCWithChildren = ({ children }) => {
color: theme.palette.nym.networkExplorer.nav.text,
fontSize: '18px',
fontWeight: 600,
ml: 2,
}}
>
<MuiLink component={Link} to="/overview" underline="none" color="inherit">
Network Explorer
<MuiLink component={Link} to="/overview" underline="none" color="inherit" fontSize={14} fontWeight={700}>
{explorerName}
</MuiLink>
<Button
size="small"
variant="outlined"
color="inherit"
href={switchNetworkLink}
sx={{ textTransform: 'none', width: 114, fontSize: '12px', fontWeight: 600, ml: 1 }}
>
{switchNetworkText}
</Button>
</Typography>
</Box>
<Box>
<Box sx={{ mr: 1 }}>
<DarkLightSwitchMobile />
<Button onClick={toggleDrawer}>
<Menu sx={{ color: theme.palette.primary.contrastText }} />
+19 -2
View File
@@ -2,6 +2,7 @@ import * as React from 'react';
import { Link } from 'react-router-dom';
import { ExpandLess, ExpandMore, Menu } from '@mui/icons-material';
import { CSSObject, styled, Theme, useTheme } from '@mui/material/styles';
import Button from '@mui/material/Button';
import MuiLink from '@mui/material/Link';
import Box from '@mui/material/Box';
import ListItem from '@mui/material/ListItem';
@@ -231,13 +232,20 @@ ExpandableButton.defaultProps = {
};
export const Nav: FCWithChildren = ({ children }) => {
const { updateNavState, navState } = useMainContext();
const { updateNavState, navState, environment } = useMainContext();
const [drawerIsOpen, setDrawerToOpen] = React.useState(false);
const [fixedOpen, setFixedOpen] = React.useState(false);
// Set maintenance banner to false by default to don't display it
const [openMaintenance, setOpenMaintenance] = React.useState(false);
const theme = useTheme();
const explorerName =
`${environment && environment.charAt(0).toUpperCase() + environment.slice(1)} Explorer` || 'Mainnet Explorer';
const switchNetworkText = environment === 'mainnet' ? 'Switch to Testnet' : 'Switch to Mainnet';
const switchNetworkLink =
environment === 'mainnet' ? 'https://sandbox-explorer.nymtech.net' : 'https://explorer.nymtech.net';
const setToActive = (id: number) => {
updateNavState(id);
};
@@ -302,8 +310,17 @@ export const Nav: FCWithChildren = ({ children }) => {
}}
>
<MuiLink component={Link} to="/" underline="none" color="inherit">
Network Explorer
{explorerName}
</MuiLink>
<Button
size="small"
variant="outlined"
color="inherit"
href={switchNetworkLink}
sx={{ borderRadius: 2, textTransform: 'none', width: 150, ml: 4, fontSize: 14, fontWeight: 600 }}
>
{switchNetworkText}
</Button>
</Typography>
</Box>
<Box
+1 -1
View File
@@ -54,7 +54,7 @@ export const DarkLightSwitch = styled(Switch)(({ theme }) => ({
export const DarkLightSwitchMobile: FCWithChildren = () => {
const { toggleMode } = useMainContext();
return (
<Button onClick={() => toggleMode()} data-testid="switch-button">
<Button onClick={() => toggleMode()} data-testid="switch-button" sx={{ p: 0, minWidth: 0 }}>
<LightSwitchSVG />
</Button>
);
+9 -1
View File
@@ -10,9 +10,10 @@ import {
MixnodeStatus,
SummaryOverviewResponse,
ValidatorsResponse,
Environment,
} from '../typeDefs/explorer-api';
import { EnumFilterKey } from '../typeDefs/filters';
import { Api } from '../api';
import { Api, getEnvironment } from '../api';
import { NavOptionType, originalNavOptions } from './nav';
interface StateData {
@@ -25,6 +26,7 @@ interface StateData {
mode: PaletteMode;
navState: NavOptionType[];
validators?: ApiState<ValidatorsResponse>;
environment?: Environment;
serviceProviders?: ApiState<DirectoryService>;
}
@@ -49,6 +51,9 @@ export const MainContext = React.createContext<State>({
export const useMainContext = (): React.ContextType<typeof MainContext> => React.useContext<State>(MainContext);
export const MainContextProvider: FCWithChildren = ({ children }) => {
// network explorer environment
const [environment, setEnvironment] = React.useState<Environment>('mainnet');
// light/dark mode
const [mode, setMode] = React.useState<PaletteMode>('dark');
@@ -190,10 +195,12 @@ export const MainContextProvider: FCWithChildren = ({ children }) => {
fetchCountryData(),
fetchServiceProviders(),
]);
setEnvironment(getEnvironment());
}, []);
const state = React.useMemo<State>(
() => ({
environment,
block,
countryData,
fetchMixnodes,
@@ -210,6 +217,7 @@ export const MainContextProvider: FCWithChildren = ({ children }) => {
serviceProviders,
}),
[
environment,
block,
countryData,
gateways,
+6 -1
View File
@@ -111,7 +111,12 @@ const PageGatewayDetailsWithState = ({ selectedGateway }: { selectedGateway: Gat
{uptimeStory && (
<ContentCard title="Routing Score">
{uptimeStory.error && <ComponentError text="There was a problem retrieving routing score." />}
<UptimeChart loading={uptimeStory.isLoading} xLabel="date" uptimeStory={uptimeStory} />
<UptimeChart
loading={uptimeStory.isLoading}
xLabel="Date"
yLabel="Daily average"
uptimeStory={uptimeStory}
/>
</ContentCard>
)}
</Grid>
+3 -3
View File
@@ -153,9 +153,9 @@ export const PageGateways: FCWithChildren = () => {
renderCell: (params: GridRenderCellParams) => (
<MuiLink
sx={{ ...cellStyles }}
href={`${NYM_BIG_DIPPER}/account/${params.value}`}
target="_blank"
data-testid="owner"
component={RRDLink}
to={`/network-components/gateway/${params.row.identity_key}`}
data-testid="version"
>
{params.value}
</MuiLink>
+14 -2
View File
@@ -12,6 +12,7 @@ import { WorldMap } from '../../components/WorldMap';
import { MixNodeDetailSection } from '../../components/MixNodes/DetailSection';
import { MixnodeContextProvider, useMixnodeContext } from '../../context/mixnode';
import { Title } from '../../components/Title';
import { useIsMobile } from '../../hooks/useIsMobile';
const columns: ColumnsType[] = [
{
@@ -41,6 +42,7 @@ const columns: ColumnsType[] = [
field: 'self_percentage',
width: '10%',
title: 'Bond %',
tooltipInfo: "Percentage of the operator's bond to the total stake on the node",
},
{
@@ -64,7 +66,7 @@ const columns: ColumnsType[] = [
*/
const PageMixnodeDetailWithState: FCWithChildren = () => {
const { mixNode, mixNodeRow, description, stats, status, uptimeStory, uniqDelegations } = useMixnodeContext();
console.log(mixNodeRow);
const isMobile = useIsMobile();
return (
<Box component="main">
<Title text="Mixnode Detail" />
@@ -73,6 +75,11 @@ const PageMixnodeDetailWithState: FCWithChildren = () => {
{mixNodeRow && description?.data && (
<MixNodeDetailSection mixNodeRow={mixNodeRow} mixnodeDescription={description.data} />
)}
{mixNodeRow?.blacklisted && (
<Typography textAlign={isMobile ? 'left' : 'right'} fontSize="smaller" sx={{ color: 'error.main' }}>
This node is having a poor performance
</Typography>
)}
</Grid>
</Grid>
<Grid container>
@@ -134,7 +141,12 @@ const PageMixnodeDetailWithState: FCWithChildren = () => {
{uptimeStory && (
<ContentCard title="Routing Score">
{uptimeStory.error && <ComponentError text="There was a problem retrieving routing score." />}
<UptimeChart loading={uptimeStory.isLoading} xLabel="date" uptimeStory={uptimeStory} />
<UptimeChart
loading={uptimeStory.isLoading}
xLabel="Date"
yLabel="Daily average"
uptimeStory={uptimeStory}
/>
</ContentCard>
)}
</Grid>
@@ -22,9 +22,10 @@ const SupportedApps = () => {
<FormControl size="small">
<Select value={selected} onChange={handleChange} displayEmpty sx={{ mr: 2 }}>
<MenuItem value="">Supported Apps</MenuItem>
<MenuItem sx={{ opacity: 1 }}>Keybase</MenuItem>
<MenuItem>Keybase</MenuItem>
<MenuItem>Telegram</MenuItem>
<MenuItem>Electrum</MenuItem>
<MenuItem>Blockstream Green</MenuItem>
</Select>
</FormControl>
);
+3
View File
@@ -89,6 +89,7 @@ export interface MixNodeResponseItem {
uncapped_saturation: number;
operating_cost: Amount;
profit_margin_percent: string;
blacklisted: boolean;
}
export type MixNodeResponse = MixNodeResponseItem[];
@@ -238,6 +239,8 @@ export type MixNodeEconomicDynamicsStatsResponse = {
current_interval_uptime: number;
};
export type Environment = 'mainnet' | 'sandbox' | 'qa';
export type DirectoryServiceProvider = {
id: string;
description: string;
+7 -1
View File
@@ -3,7 +3,7 @@
[package]
name = "nym-gateway"
version = "1.1.12"
version = "1.1.13"
authors = [
"Dave Hrycyszyn <futurechimp@users.noreply.github.com>",
"Jędrzej Stuczyński <andrew@nymtech.net>",
@@ -50,6 +50,12 @@ tokio-stream = { version = "0.1.11", features = ["fs"] }
tokio-tungstenite = "0.14"
tokio-util = { version = "0.7.4", features = ["codec"] }
url = { version = "2.2", features = ["serde"] }
tracing = "0.1.37"
tracing-subscriber = {version = "0.3.16", features = ["registry", "std", "env-filter"]}
tracing-opentelemetry = "0.18.0"
opentelemetry-jaeger = {version = "0.17.0", features = ["collector_client","rt-tokio","isahc_collector_client"]}
opentelemetry = {version = "0.18.0", features = ["rt-tokio"]}
tracing-flame = "0.2.0"
# internal
nym-coconut-interface = { path = "../common/coconut-interface" }
+1
View File
@@ -18,6 +18,7 @@ rand = { version = "0.7.3", features = ["wasm-bindgen"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
thiserror = "1.0"
tracing = "0.1.29"
nym-crypto = { path = "../../common/crypto" }
nym-pemstore = { path = "../../common/pemstore" }
@@ -6,7 +6,6 @@ use crate::registration::handshake::shared_key::{SharedKeySize, SharedKeys};
use crate::registration::handshake::WsItem;
use crate::types;
use futures::{Sink, SinkExt, Stream, StreamExt};
use log::*;
use nym_crypto::{
asymmetric::{encryption, identity},
generic_array::typenum::Unsigned,
@@ -14,6 +13,7 @@ use nym_crypto::{
symmetric::stream_cipher,
};
use nym_sphinx::params::{GatewayEncryptionAlgorithm, GatewaySharedKeyHkdfAlgorithm};
use tracing::*;
use rand::{CryptoRng, RngCore};
use std::convert::{TryFrom, TryInto};
use tungstenite::Message as WsMessage;
+5 -3
View File
@@ -7,6 +7,8 @@ use crate::{
OutputFormat,
};
use clap::Args;
use config::NymConfig;
use tracing::*;
use std::error::Error;
use std::net::IpAddr;
use std::path::PathBuf;
@@ -115,19 +117,19 @@ fn special_addresses() -> Vec<&'static str> {
pub async fn execute(args: Run, output: OutputFormat) -> Result<(), Box<dyn Error + Send + Sync>> {
let id = args.id.clone();
println!("Starting gateway {id}...");
event!(Level::INFO, "Loading config");
let config = build_config(id, args)?;
ensure_config_version_compatibility(&config)?;
if special_addresses().contains(&&*config.get_listening_address().to_string()) {
show_binding_warning(config.get_listening_address().to_string());
}
event!(Level::INFO, "Creating Gateway node");
let mut gateway = crate::node::create_gateway(config).await;
eprintln!(
"\nTo bond your gateway you will need to install the Nym wallet, go to https://nymtech.net/get-involved and select the Download button.\n\
Select the correct version and install it to your machine. You will need to provide the following: \n ");
gateway.print_node_details(output)?;
//.instrument(info_span!("Gateway run"))
gateway.run().await
}
+40 -4
View File
@@ -4,11 +4,18 @@
use clap::{crate_name, crate_version, Parser, ValueEnum};
use colored::Colorize;
use lazy_static::lazy_static;
use log::error;
use nym_bin_common::logging::setup_logging;
use nym_bin_common::{build_information::BinaryBuildInformation, logging::banner};
use nym_network_defaults::setup_env;
use std::error::Error;
use tracing_subscriber::layer::SubscriberExt;
use tracing_subscriber::{EnvFilter, Registry, filter};
use tracing::*;
use tracing_flame::FlameLayer;
use std::time::Duration;
use std::thread::sleep;
mod commands;
mod config;
@@ -64,14 +71,39 @@ impl Cli {
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
setup_logging();
let tracer = opentelemetry_jaeger::new_agent_pipeline()
.with_endpoint("143.42.21.138:6831")
.with_service_name("nym_gateway")
.with_auto_split_batch(true)
.install_batch(opentelemetry::runtime::Tokio)
.expect("Failed to initialize tracer");
//let jaeger_layer = tracing_opentelemetry::layer().with_tracer(tracer);
let hyper_filter = filter::filter_fn(|metadata| {!metadata.target().starts_with("hyper")});
let tokio_filter = filter::filter_fn(|metadata| {!metadata.target().starts_with("tokio")});
let (flame_layer, _guard) = FlameLayer::with_file("./tracing.folded").unwrap();
let subscriber = Registry::default()
.with(EnvFilter::from_default_env())
.with(hyper_filter)
.with(tokio_filter)
.with(tracing_subscriber::fmt::layer().pretty())
.with(flame_layer);
//.with(jaeger_layer)
// tracing::subscriber::set_global_default(subscriber)
// .expect("Failed to set global subscriber");
//tracing_subscriber::fmt::init();
//setup_logging();
if atty::is(atty::Stream::Stdout) {
println!("{}", banner(crate_name!(), crate_version!()));
}
let args = Cli::parse();
setup_env(args.config_env_file.as_ref());
//.instrument(info_span!("Execute Run"))
commands::execute(args).await.map_err(|err| {
if atty::is(atty::Stream::Stdout) {
let error_message = format!("{err}").red();
@@ -79,7 +111,11 @@ async fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
error!("Exiting...");
}
err
})
});
//sleep(Duration::from_secs(5));
//opentelemetry::global::shutdown_tracer_provider();
Ok(())
}
#[cfg(test)]
@@ -9,8 +9,8 @@ use futures::StreamExt;
use gateway_requests::iv::IVConversionError;
use gateway_requests::types::{BinaryRequest, ServerResponse};
use gateway_requests::{ClientControlRequest, GatewayRequestsError};
use log::*;
use nym_sphinx::forwarding::packet::MixPacket;
use tracing::*;
use rand::{CryptoRng, Rng};
use std::convert::TryFrom;
use std::process;
@@ -132,6 +132,7 @@ where
}
/// Explicitly removes handle from the global store.
#[instrument(level="debug", skip_all)]
fn disconnect(self) {
self.inner
.active_clients_store
@@ -180,6 +181,7 @@ where
/// # Arguments
///
/// * `mix_packet`: packet received from the client that should get forwarded into the network.
#[instrument(level="debug", skip_all)]
fn forward_packet(&self, mix_packet: MixPacket) {
if let Err(err) = self.inner.outbound_mix_sender.unbounded_send(mix_packet) {
error!("We failed to forward requested mix packet - {err}. Presumably our mix forwarder has crashed. We cannot continue.");
@@ -279,13 +281,14 @@ where
/// # Arguments
///
/// * `mix_packet`: packet received from the client that should get forwarded into the network.
#[instrument(level="debug", skip_all)]
async fn handle_forward_sphinx(
&self,
mix_packet: MixPacket,
) -> Result<ServerResponse, RequestHandlingError> {
let consumed_bandwidth = mix_packet.sphinx_packet().len() as i64;
let available_bandwidth = self.get_available_bandwidth().await?;
let available_bandwidth = self.get_available_bandwidth().instrument(trace_span!("Get available bandwidth")).await?;
if available_bandwidth < consumed_bandwidth {
return Ok(ServerResponse::new_error(
@@ -293,7 +296,7 @@ where
));
}
self.consume_bandwidth(consumed_bandwidth).await?;
self.consume_bandwidth(consumed_bandwidth).instrument(trace_span!("Consume bandwidth")).await?;
self.forward_packet(mix_packet);
Ok(ServerResponse::Send {
@@ -306,6 +309,7 @@ where
/// # Arguments
///
/// * `bin_msg`: raw message to handle.
#[instrument(level="debug", skip_all)]
async fn handle_binary(&self, bin_msg: Vec<u8>) -> Message {
// this function decrypts the request and checks the MAC
match BinaryRequest::try_from_encrypted_tagged_bytes(bin_msg, &self.client.shared_keys) {
@@ -327,6 +331,7 @@ where
/// # Arguments
///
/// * `raw_request`: raw message to handle.
#[instrument(level="debug", skip_all)]
async fn handle_text(&mut self, raw_request: String) -> Message {
match ClientControlRequest::try_from(raw_request) {
Err(e) => RequestHandlingError::InvalidTextRequest(e).into_error_message(),
@@ -349,6 +354,7 @@ where
/// # Arguments
///
/// * `raw_request`: raw received websocket message.
//#[instrument(level="info", skip_all)]
async fn handle_request(&mut self, raw_request: Message) -> Option<Message> {
// apparently tungstenite auto-handles ping/pong/close messages so for now let's ignore
// them and let's test that claim. If that's not the case, just copy code from
@@ -363,6 +369,7 @@ where
/// Simultaneously listens for incoming client requests, which realistically should only be
/// binary requests to forward sphinx packets or increase bandwidth
/// and for sphinx packets received from the mix network that should be sent back to the client.
#[instrument(level="info", skip_all, name="Serving requests")]
pub(crate) async fn listen_for_requests(mut self, mut shutdown: TaskClient)
where
S: AsyncRead + AsyncWrite + Unpin,
@@ -373,14 +380,16 @@ where
while !shutdown.is_shutdown() {
tokio::select! {
_ = shutdown.recv() => {
log::trace!("client_handling::AuthenticatedHandler: received shutdown");
trace!("client_handling::AuthenticatedHandler: received shutdown");
}
socket_msg = self.inner.read_websocket_message() => {
debug!("Handling client request");
let socket_msg = match socket_msg {
None => break,
Some(Ok(socket_msg)) => socket_msg,
Some(Err(err)) => {
error!("failed to obtain message from websocket stream! stopping connection handler: {err}");
log::error!("failed to obtain message from websocket stream! stopping connection handler: {err}");
break;
}
};
@@ -390,6 +399,7 @@ where
}
if let Some(response) = self.handle_request(socket_msg).await {
trace!("Sending response to client request");
if let Err(err) = self.inner.send_websocket_message(response).await {
warn!(
"Failed to send message over websocket: {err}. Assuming the connection is dead.",
@@ -397,13 +407,17 @@ where
break;
}
}
},
mix_messages = self.mix_receiver.next() => {
//let span = info_span!("Processing mixnet message");
//let guard = span.enter();
let mix_messages = mix_messages.expect("sender was unexpectedly closed! this shouldn't have ever happened!");
if let Err(err) = self.inner.push_packets_to_client(self.client.shared_keys, mix_messages).await {
warn!("failed to send the unwrapped sphinx packets back to the client - {err}, assuming the connection is dead");
break;
}
//drop(guard);
}
}
}
@@ -1,8 +1,9 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use log::*;
use nym_coconut_interface::Credential;
use coconut_interface::Credential;
use tracing::*;
use std::time::{Duration, SystemTime};
use validator_client::nyxd::traits::DkgQueryClient;
use validator_client::{
@@ -17,7 +17,7 @@ use gateway_requests::registration::handshake::error::HandshakeError;
use gateway_requests::registration::handshake::{gateway_handshake, SharedKeys};
use gateway_requests::types::{ClientControlRequest, ServerResponse};
use gateway_requests::{BinaryResponse, PROTOCOL_VERSION};
use log::*;
use tracing::*;
use mixnet_client::forwarder::MixForwardingSender;
use nym_crypto::asymmetric::identity;
use nym_sphinx::DestinationAddressBytes;
@@ -111,6 +111,7 @@ where
/// Attempts to perform websocket handshake with the remote and upgrades the raw TCP socket
/// to the framed WebSocket.
#[instrument(level="debug", skip_all)]
pub(crate) async fn perform_websocket_handshake(&mut self) -> Result<(), WsError>
where
S: AsyncRead + AsyncWrite + Unpin,
@@ -134,6 +135,7 @@ where
/// # Arguments
///
/// * `init_msg`: a client handshake init message which should contain its identity public key as well as an ephemeral key.
#[instrument(level="debug", skip_all)]
async fn perform_registration_handshake(
&mut self,
init_msg: Vec<u8>,
@@ -157,6 +159,7 @@ where
}
/// Attempts to read websocket message from the associated socket.
#[instrument(level="debug", skip_all)]
pub(crate) async fn read_websocket_message(&mut self) -> Option<Result<Message, WsError>>
where
S: AsyncRead + AsyncWrite + Unpin,
@@ -172,6 +175,7 @@ where
/// # Arguments
///
/// * `msg`: WebSocket message to write back to the client.
#[instrument(level="debug", skip_all)]
pub(crate) async fn send_websocket_message(&mut self, msg: Message) -> Result<(), WsError>
where
S: AsyncRead + AsyncWrite + Unpin,
@@ -192,6 +196,7 @@ where
///
/// * `shared_keys`: keys derived between the client and gateway.
/// * `packets`: unwrapped packets that are to be pushed back to the client.
#[instrument(level="debug", skip_all, fields(packets = packets.len()))]
pub(crate) async fn push_packets_to_client(
&mut self,
shared_keys: SharedKeys,
@@ -202,6 +207,7 @@ where
{
// note: into_ws_message encrypts the requests and adds a MAC on it. Perhaps it should
// be more explicit in the naming?
debug!("Pushing {} packets", packets.len());
let messages: Vec<Result<Message, WsError>> = packets
.into_iter()
.map(|received_message| {
@@ -561,6 +567,7 @@ where
/// result in client getting registered or authenticated. All other requests, such as forwarding
/// sphinx packets considered an error and terminate the connection.
// TODO: somehow cleanup this method
#[instrument(level="debug", skip_all)]
pub(crate) async fn perform_initial_authentication(
mut self,
) -> Option<AuthenticatedHandler<R, S, St>>
@@ -597,6 +604,7 @@ where
}
}
Ok(auth_result) => {
debug!("Confirming auth");
if let Err(err) = self
.send_websocket_message(auth_result.server_response.into())
.await
@@ -4,9 +4,9 @@
use crate::node::storage::Storage;
use gateway_requests::registration::handshake::SharedKeys;
use gateway_requests::ServerResponse;
use log::{trace, warn};
use nym_sphinx::DestinationAddressBytes;
use nym_task::TaskClient;
use tracing::*;
use rand::{CryptoRng, Rng};
use tokio::io::{AsyncRead, AsyncWrite};
use tokio_tungstenite::WebSocketStream;
@@ -5,7 +5,7 @@ use crate::node::client_handling::active_clients::ActiveClientsStore;
use crate::node::client_handling::websocket::connection_handler::coconut::CoconutVerifier;
use crate::node::client_handling::websocket::connection_handler::FreshHandler;
use crate::node::storage::Storage;
use log::*;
use tracing::*;
use mixnet_client::forwarder::MixForwardingSender;
use nym_crypto::asymmetric::identity;
use rand::rngs::OsRng;
@@ -60,7 +60,7 @@ impl Listener {
tokio::select! {
biased;
_ = shutdown.recv() => {
log::trace!("client_handling::Listener: received shutdown");
trace!("client_handling::Listener: received shutdown");
}
connection = tcp_listener.accept() => {
match connection {
@@ -79,7 +79,7 @@ impl Listener {
Arc::clone(&self.coconut_verifier),
);
let shutdown = shutdown.clone();
tokio::spawn(async move { handle.start_handling(shutdown).await });
tokio::spawn(async move { handle.start_handling(shutdown).await }.instrument(info_span!("Connection handling", address = %remote_addr)));
}
Err(err) => warn!("failed to get client: {err}"),
}
@@ -102,6 +102,6 @@ impl Listener {
tokio::spawn(async move {
self.run(outbound_mix_sender, storage, active_clients_store, shutdown)
.await
})
}.instrument(info_span!("Client Listener")))
}
}
@@ -7,7 +7,7 @@ use crate::node::mixnet_handling::receiver::packet_processing::PacketProcessor;
use crate::node::storage::error::StorageError;
use crate::node::storage::Storage;
use futures::StreamExt;
use log::*;
use tracing::*;
use mixnet_client::forwarder::MixForwardingSender;
use mixnode_common::packet_processor::processor::ProcessedFinalHop;
use nym_sphinx::forwarding::packet::MixPacket;
@@ -86,7 +86,7 @@ impl<St: Storage> ConnectionHandler<St> {
}
}
}
#[instrument(level="debug", skip_all)]
fn try_push_message_to_client(
&mut self,
client_address: DestinationAddressBytes,
@@ -105,7 +105,7 @@ impl<St: Storage> ConnectionHandler<St> {
}
}
}
#[instrument(level="debug", skip_all)]
pub(crate) async fn store_processed_packet_payload(
&self,
client_address: DestinationAddressBytes,
@@ -118,7 +118,7 @@ impl<St: Storage> ConnectionHandler<St> {
self.storage.store_message(client_address, message).await
}
#[instrument(level="debug", skip_all)]
fn forward_ack(&self, forward_ack: Option<MixPacket>, client_address: DestinationAddressBytes) {
if let Some(forward_ack) = forward_ack {
trace!(
@@ -130,7 +130,7 @@ impl<St: Storage> ConnectionHandler<St> {
self.ack_sender.unbounded_send(forward_ack).unwrap();
}
}
#[instrument(level="debug", skip_all)]
async fn handle_processed_packet(&mut self, processed_final_hop: ProcessedFinalHop) {
let client_address = processed_final_hop.destination;
let message = processed_final_hop.message;
@@ -154,7 +154,7 @@ impl<St: Storage> ConnectionHandler<St> {
// received ack back into the network
self.forward_ack(forward_ack, client_address);
}
//#[instrument(level="info", skip_all)]
async fn handle_received_packet(&mut self, framed_sphinx_packet: FramedSphinxPacket) {
//
// TODO: here be replay attack detection - it will require similar key cache to the one in
@@ -187,7 +187,7 @@ impl<St: Storage> ConnectionHandler<St> {
tokio::select! {
biased;
_ = shutdown.recv() => {
log::trace!("ConnectionHandler: received shutdown");
trace!("ConnectionHandler: received shutdown");
}
Some(framed_sphinx_packet) = framed_conn.next() => {
match framed_sphinx_packet {
@@ -3,8 +3,8 @@
use crate::node::mixnet_handling::receiver::connection_handler::ConnectionHandler;
use crate::node::storage::Storage;
use log::*;
use nym_task::TaskClient;
use tracing::*;
use std::net::SocketAddr;
use std::process;
use tokio::task::JoinHandle;
@@ -37,13 +37,14 @@ impl Listener {
tokio::select! {
biased;
_ = self.shutdown.recv() => {
log::trace!("mixnet_handling::Listener: Received shutdown");
trace!("mixnet_handling::Listener: Received shutdown");
}
connection = tcp_listener.accept() => {
match connection {
Ok((socket, remote_addr)) => {
let handler = connection_handler.clone();
tokio::spawn(handler.handle_connection(socket, remote_addr, self.shutdown.clone()));
tokio::spawn(handler.handle_connection(socket, remote_addr, self.shutdown.clone())
.instrument(info_span!("Mixnet connection handling", address = %remote_addr)));
}
Err(err) => warn!("failed to get client: {err}"),
}
@@ -58,6 +59,6 @@ impl Listener {
{
info!("Running mix listener on {:?}", self.address.to_string());
tokio::spawn(async move { self.run(connection_handler).await })
tokio::spawn(async move { self.run(connection_handler).await }.instrument(info_span!("Mixnet Listener")))
}
}
+3 -4
View File
@@ -14,7 +14,7 @@ use crate::node::statistics::collector::GatewayStatisticsCollector;
use crate::node::storage::Storage;
use crate::{commands::sign::load_identity_keys, OutputFormat};
use colored::Colorize;
use log::*;
use tracing::*;
use mixnet_client::forwarder::{MixForwardingSender, PacketForwarder};
use nym_crypto::asymmetric::{encryption, identity};
use nym_network_defaults::NymNetworkDetails;
@@ -220,8 +220,7 @@ where
self.config.get_use_legacy_sphinx_framing(),
shutdown,
);
tokio::spawn(async move { packet_forwarder.run().await });
tokio::spawn(async move { packet_forwarder.run().await }.instrument(info_span!("Packet Forwarder")));
packet_sender
}
@@ -230,7 +229,7 @@ where
shutdown: TaskManager,
) -> Result<(), Box<dyn Error + Send + Sync>> {
let res = shutdown.catch_interrupt().await;
log::info!("Stopping nym gateway");
info!("Stopping nym gateway");
res
}
+7 -1
View File
@@ -3,7 +3,7 @@
[package]
name = "nym-mixnode"
version = "1.1.13"
version = "1.1.14"
authors = [
"Dave Hrycyszyn <futurechimp@users.noreply.github.com>",
"Jędrzej Stuczyński <andrew@nymtech.net>",
@@ -36,6 +36,12 @@ tokio = { version="1.21.2", features = ["rt-multi-thread", "net", "signal"] }
tokio-util = { version="0.7.3", features = ["codec"] }
toml = "0.5.8"
url = { version = "2.2", features = ["serde"] }
tracing = "0.1.37"
tracing-subscriber = {version = "0.3.16", features = ["registry", "std", "env-filter"]}
tracing-opentelemetry = "0.18.0"
opentelemetry-jaeger = {version = "0.17.0", features = ["collector_client","rt-tokio","isahc_collector_client"]}
opentelemetry = {version = "0.18.0", features = ["rt-tokio"]}
tracing-flame = "0.2.0"
atty = "0.2"
## internal
+30 -1
View File
@@ -7,6 +7,9 @@ extern crate rocket;
use ::nym_config::defaults::setup_env;
use clap::{crate_name, crate_version, Parser, ValueEnum};
use lazy_static::lazy_static;
use tracing_subscriber::layer::SubscriberExt;
use tracing_subscriber::{EnvFilter, Registry, filter};
use tracing_flame::FlameLayer;
use nym_bin_common::logging::setup_logging;
use nym_bin_common::{build_information::BinaryBuildInformation, logging::banner};
@@ -62,7 +65,32 @@ impl Cli {
#[tokio::main]
async fn main() {
setup_logging();
//setup_logging();
//let tracer = opentelemetry_jaeger::new_agent_pipeline()
//.with_endpoint("143.42.21.138:6831")
//.with_service_name("nym_mixnode1")
//.with_auto_split_batch(true)
//.install_batch(opentelemetry::runtime::Tokio)
//.expect("Failed to initialize tracer");
//let jaeger_layer = tracing_opentelemetry::layer().with_tracer(tracer);
let hyper_filter = filter::filter_fn(|metadata| {!metadata.target().starts_with("hyper")});
let tokio_filter = filter::filter_fn(|metadata| {!metadata.target().starts_with("tokio")});
//let (flame_layer, _guard) = FlameLayer::with_file("./tracing.folded").unwrap();
let subscriber = Registry::default()
.with(EnvFilter::from_default_env())
.with(hyper_filter)
.with(tokio_filter)
.with(tracing_subscriber::fmt::layer().pretty());
//.with(flame_layer);
//.with(jaeger_layer);
tracing::subscriber::set_global_default(subscriber)
.expect("Failed to set global subscriber");
if atty::is(atty::Stream::Stdout) {
println!("{}", banner(crate_name!(), crate_version!()));
}
@@ -70,6 +98,7 @@ async fn main() {
let args = Cli::parse();
setup_env(args.config_env_file.as_ref());
commands::execute(args).await;
opentelemetry::global::shutdown_tracer_provider();
}
#[cfg(test)]
@@ -7,8 +7,10 @@ use crate::node::listener::connection_handler::packet_processing::{
use crate::node::packet_delayforwarder::PacketDelayForwardSender;
use crate::node::TaskClient;
use futures::StreamExt;
use log::{error, info};
use tracing::{error, info, trace, debug, warn};
use tracing::*;
use nym_sphinx::forwarding::packet::MixPacket;
use nym_sphinx::params::PacketSize;
use nym_sphinx::framing::codec::SphinxCodec;
use nym_sphinx::framing::packet::FramedSphinxPacket;
use nym_sphinx::Delay as SphinxDelay;
@@ -16,6 +18,7 @@ use std::net::SocketAddr;
use tokio::net::TcpStream;
use tokio::time::Instant;
use tokio_util::codec::Framed;
use std::time::{SystemTime,UNIX_EPOCH};
pub(crate) mod packet_processing;
@@ -35,10 +38,12 @@ impl ConnectionHandler {
delay_forwarding_channel,
}
}
#[instrument(level="debug", skip_all, "Sending to packet forwarder", fields(packet_size))]
fn delay_and_forward_packet(&self, mix_packet: MixPacket, delay: Option<SphinxDelay>) {
// determine instant at which packet should get forwarded. this way we minimise effect of
// being stuck in the queue [of the channel] to get inserted into the delay queue
let packet_size = PacketSize::get_type(mix_packet.sphinx_packet().len()).unwrap();
Span::current().record("packet_size", field::debug(packet_size));
let forward_instant = delay.map(|delay| Instant::now() + delay.to_duration());
// if unbounded_send() failed it means that the receiver channel was disconnected
@@ -47,7 +52,7 @@ impl ConnectionHandler {
.unbounded_send((mix_packet, forward_instant))
.expect("the delay-forwarder has died!");
}
#[instrument(level="info", skip_all, "Handling packet",fields(packet_size=?framed_sphinx_packet.packet_size()))]
fn handle_received_packet(&self, framed_sphinx_packet: FramedSphinxPacket) {
//
// TODO: here be replay attack detection - it will require similar key cache to the one in
@@ -69,7 +74,7 @@ impl ConnectionHandler {
},
}
}
#[instrument(level="info", skip_all, "Connection handling", fields(address=%remote))]
pub(crate) async fn handle_connection(
self,
conn: TcpStream,
@@ -83,7 +88,7 @@ impl ConnectionHandler {
tokio::select! {
biased;
_ = shutdown.recv() => {
log::trace!("ConnectionHandler: received shutdown");
trace!("ConnectionHandler: received shutdown");
}
Some(framed_sphinx_packet) = framed_conn.next() => {
match framed_sphinx_packet {
@@ -96,7 +101,9 @@ impl ConnectionHandler {
// in theory we could process multiple sphinx packet from the same connection in parallel,
// but we already handle multiple concurrent connections so if anything, making
// that change would only slow things down
//println!("{:?}_In_{:?}", SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_micros(), framed_sphinx_packet.packet_size().size());
self.handle_received_packet(framed_sphinx_packet);
//println!("{:?}_Processed_{:?}", SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_micros(), mix_packet.sphinx_packet().len());
}
Err(err) => {
error!(
@@ -113,6 +120,6 @@ impl ConnectionHandler {
"Closing connection from {:?}",
framed_conn.into_inner().peer_addr()
);
log::trace!("ConnectionHandler: Exiting");
trace!("ConnectionHandler: Exiting");
}
}
+7 -6
View File
@@ -2,7 +2,8 @@
// SPDX-License-Identifier: Apache-2.0
use crate::node::listener::connection_handler::ConnectionHandler;
use log::error;
use tracing::*;
use tracing::{error, info, trace, warn};
use std::net::SocketAddr;
use std::process;
use tokio::net::TcpListener;
@@ -21,9 +22,9 @@ impl Listener {
pub(crate) fn new(address: SocketAddr, shutdown: TaskClient) -> Self {
Listener { address, shutdown }
}
#[instrument(level="info", skip_all, "Mixnet Listener")]
async fn run(&mut self, connection_handler: ConnectionHandler) {
log::trace!("Starting Listener");
trace!("Starting Listener");
let listener = match TcpListener::bind(self.address).await {
Ok(listener) => listener,
Err(err) => {
@@ -36,20 +37,20 @@ impl Listener {
tokio::select! {
biased;
_ = self.shutdown.recv() => {
log::trace!("Listener: Received shutdown");
trace!("Listener: Received shutdown");
}
connection = listener.accept() => {
match connection {
Ok((socket, remote_addr)) => {
let handler = connection_handler.clone();
tokio::spawn(handler.handle_connection(socket, remote_addr, self.shutdown.clone()));
tokio::spawn(handler.handle_connection(socket, remote_addr, self.shutdown.clone()).instrument(info_span!("Connection handling", address = %remote_addr)));
}
Err(err) => warn!("Failed to accept incoming connection - {err}"),
}
},
};
}
log::trace!("Listener: Exiting");
trace!("Listener: Exiting");
}
pub(crate) fn start(mut self, connection_handler: ConnectionHandler) -> JoinHandle<()> {
+5 -4
View File
@@ -17,9 +17,10 @@ use crate::node::listener::Listener;
use crate::node::node_description::NodeDescription;
use crate::node::node_statistics::SharedNodeStats;
use crate::node::packet_delayforwarder::{DelayForwarder, PacketDelayForwardSender};
use tracing::*;
use tracing::{info, error, warn};
use crate::OutputFormat;
use colored::Colorize;
use log::{error, info, warn};
use mixnode_common::verloc::{self, AtomicVerlocResult, VerlocMeasurer};
use nym_bin_common::version_checker::parse_version;
use nym_config::NymConfig;
@@ -215,7 +216,7 @@ impl MixNode {
let packet_sender = packet_forwarder.sender();
tokio::spawn(async move { packet_forwarder.run().await });
tokio::spawn(async move { packet_forwarder.run().await }.instrument(info_span!("Packet delay forwarder")));
packet_sender
}
@@ -294,7 +295,7 @@ impl MixNode {
async fn wait_for_interrupt(&self, shutdown: TaskManager) {
let _res = shutdown.catch_interrupt().await;
log::info!("Stopping nym mixnode");
info!("Stopping nym mixnode");
}
pub async fn run(&mut self) {
@@ -304,7 +305,7 @@ impl MixNode {
if duplicate_node_key == self.identity_keypair.public_key().to_base58_string() {
warn!("You seem to have bonded your mixnode before starting it - that's highly unrecommended as in the future it might result in slashing");
} else {
log::error!(
error!(
"Our announce-host is identical to an existing node's announce-host! (its key is {:?})",
duplicate_node_key
);
+10 -5
View File
@@ -4,10 +4,13 @@
use crate::node::node_statistics::UpdateSender;
use futures::channel::mpsc;
use futures::StreamExt;
use nym_sphinx::params::packet_sizes::PacketSize;
use nym_nonexhaustive_delayqueue::{Expired, NonExhaustiveDelayQueue};
use nym_sphinx::forwarding::packet::MixPacket;
use std::io;
use tokio::time::Instant;
use tracing::*;
use tracing::{trace};
use super::TaskClient;
@@ -55,11 +58,13 @@ where
pub(crate) fn sender(&self) -> PacketDelayForwardSender {
self.packet_sender.clone()
}
#[instrument(level="debug", skip_all, "Forwarding packet", fields(packet_size))]
fn forward_packet(&mut self, packet: MixPacket) {
let next_hop = packet.next_hop();
let packet_mode = packet.packet_mode();
let sphinx_packet = packet.into_sphinx_packet();
let packet_size = PacketSize::get_type(sphinx_packet.len()).unwrap();
Span::current().record("packet_size", field::debug(packet_size));
if let Err(err) =
self.mixnet_client
@@ -87,7 +92,7 @@ where
let delayed_packet = packet.into_inner();
self.forward_packet(delayed_packet)
}
#[instrument(level="debug", skip_all, "Handling packet", fields(packet_size))]
fn handle_new_packet(&mut self, new_packet: (MixPacket, Option<Instant>)) {
// in case of a zero delay packet, don't bother putting it in the delay queue,
// just forward it immediately
@@ -105,7 +110,7 @@ where
}
pub(crate) async fn run(&mut self) {
log::trace!("Starting DelayForwarder");
trace!("Starting DelayForwarder");
loop {
tokio::select! {
delayed = self.delay_queue.next() => {
@@ -117,12 +122,12 @@ where
self.handle_new_packet(new_packet.unwrap())
}
_ = self.shutdown.recv() => {
log::trace!("DelayForwarder: Received shutdown");
trace!("DelayForwarder: Received shutdown");
break;
}
}
}
log::trace!("DelayForwarder: Exiting");
trace!("DelayForwarder: Exiting");
}
}
+6 -6
View File
@@ -3,7 +3,7 @@
[package]
name = "nym-api"
version = "1.1.13"
version = "1.1.14"
authors = [
"Dave Hrycyszyn <futurechimp@users.noreply.github.com>",
"Jędrzej Stuczyński <andrew@nymtech.net>",
@@ -68,12 +68,12 @@ nym-coconut-bandwidth-contract-common = { path = "../common/cosmwasm-smart-contr
nym-coconut-dkg-common = { path = "../common/cosmwasm-smart-contracts/coconut-dkg" }
nym-coconut-interface = { path = "../common/coconut-interface" }
nym-config = { path = "../common/config" }
cosmwasm-std = "1.0.0"
cosmwasm-std = { workspace = true }
nym-credential-storage = { path = "../common/credential-storage" }
nym-credentials = { path = "../common/credentials" }
nym-crypto = { path = "../common/crypto" }
cw3 = { version = "0.13.4" }
cw4 = { version = "0.13.4" }
cw3 = { workspace = true }
cw4 = { workspace = true }
nym-dkg = { path = "../common/dkg", features = ["cw-types"] }
gateway-client = { path = "../common/client-libs/gateway-client" }
nym-inclusion-probability = { path = "../common/inclusion-probability" }
@@ -106,5 +106,5 @@ sqlx = { version = "0.6.2", features = [
] }
[dev-dependencies]
cw3 = "0.13.4"
cw-utils = "0.13.4"
cw3 = { workspace = true }
cw-utils = { workspace = true }
+1 -1
View File
@@ -8,7 +8,7 @@ edition = "2021"
[dependencies]
bs58 = "0.4.0"
cosmrs = { git = "https://github.com/neacsu/cosmos-rust", branch = "neacsu/feegrant_support" }
cosmwasm-std = { version = "1.0.0", default-features = false }
cosmwasm-std = { workspace = true, default-features = false }
getset = "0.1.1"
schemars = { version = "0.8", features = ["preserve_order"] }
serde = { version = "1.0", features = ["derive"] }
+2
View File
@@ -111,6 +111,7 @@ pub struct MixNodeBondAnnotated {
pub estimated_operator_apy: Decimal,
pub estimated_delegators_apy: Decimal,
pub family: Option<FamilyHead>,
pub blacklisted: bool,
}
impl MixNodeBondAnnotated {
@@ -137,6 +138,7 @@ pub struct GatewayBondAnnotated {
// NOTE: the performance field is deprecated in favour of node_performance
pub performance: Performance,
pub node_performance: NodePerformance,
pub blacklisted: bool,
}
impl GatewayBondAnnotated {
+3 -3
View File
@@ -102,7 +102,7 @@ impl RewardedSetUpdater {
let epoch_end = interval.current_epoch_end();
let all_mixnodes = self.nym_contract_cache.mixnodes().await;
let all_mixnodes = self.nym_contract_cache.mixnodes_filtered().await;
if all_mixnodes.is_empty() {
// that's a bit weird, but
log::warn!("there don't seem to be any mixnodes on the network!")
@@ -127,8 +127,8 @@ impl RewardedSetUpdater {
}
// Reward all the nodes in the still current, soon to be previous rewarded set
log::info!("Rewarding the current rewarded set...");
self.reward_current_rewarded_set(interval).await?;
//log::info!("Rewarding the current rewarded set...");
//self.reward_current_rewarded_set(interval).await?;
// note: those operations don't really have to be atomic, so it's fine to send them
// as separate transactions
+13 -3
View File
@@ -89,10 +89,15 @@ impl NodeStatusCache {
}
}
pub(crate) async fn mixnodes_annotated(&self) -> Option<Cache<Vec<MixNodeBondAnnotated>>> {
pub(crate) async fn mixnodes_annotated_full(&self) -> Option<Cache<Vec<MixNodeBondAnnotated>>> {
self.get(|c| c.mixnodes_annotated.clone()).await
}
pub(crate) async fn mixnodes_annotated_filtered(&self) -> Option<Vec<MixNodeBondAnnotated>> {
let full = self.mixnodes_annotated_full().await?;
Some(full.value.into_iter().filter(|m| !m.blacklisted).collect())
}
pub(crate) async fn rewarded_set_annotated(&self) -> Option<Cache<Vec<MixNodeBondAnnotated>>> {
self.get(|c| c.rewarded_set_annotated.clone()).await
}
@@ -101,10 +106,15 @@ impl NodeStatusCache {
self.get(|c| c.active_set_annotated.clone()).await
}
pub(crate) async fn gateways_annotated(&self) -> Option<Cache<Vec<GatewayBondAnnotated>>> {
pub(crate) async fn gateways_annotated_full(&self) -> Option<Cache<Vec<GatewayBondAnnotated>>> {
self.get(|c| c.gateways_annotated.clone()).await
}
pub(crate) async fn gateways_annotated_filtered(&self) -> Option<Vec<GatewayBondAnnotated>> {
let full = self.gateways_annotated_full().await?;
Some(full.value.into_iter().filter(|m| !m.blacklisted).collect())
}
pub(crate) async fn inclusion_probabilities(&self) -> Option<Cache<InclusionProbabilities>> {
self.get(|c| c.inclusion_probabilities.clone()).await
}
@@ -126,7 +136,7 @@ impl NodeStatusCache {
return (Some(bond.clone()), MixnodeStatus::Standby);
}
let all_bonded = &self.mixnodes_annotated().await.unwrap().into_inner();
let all_bonded = &self.mixnodes_annotated_filtered().await.unwrap();
if let Some(bond) = all_bonded.iter().find(|mix| mix.mix_id() == mix_id) {
(Some(bond.clone()), MixnodeStatus::Inactive)
} else {
+5 -1
View File
@@ -6,7 +6,7 @@ use nym_mixnet_contract_common::{reward_params::Performance, Interval, MixId};
use nym_mixnet_contract_common::{
GatewayBond, IdentityKey, MixNodeDetails, RewardedSetNodeStatus, RewardingParams,
};
use std::collections::HashMap;
use std::collections::{HashMap, HashSet};
pub(super) fn to_rewarded_set_node_status(
rewarded_set: &[MixNodeDetails],
@@ -84,6 +84,7 @@ pub(super) async fn annotate_nodes_with_details(
current_interval: Interval,
rewarded_set: &HashMap<MixId, RewardedSetNodeStatus>,
mix_to_family: Vec<(IdentityKey, FamilyHead)>,
blacklist: &HashSet<MixId>,
) -> Vec<MixNodeBondAnnotated> {
let mix_to_family = mix_to_family
.into_iter()
@@ -135,6 +136,7 @@ pub(super) async fn annotate_nodes_with_details(
.cloned();
annotated.push(MixNodeBondAnnotated {
blacklisted: blacklist.contains(&mixnode.mix_id()),
mixnode_details: mixnode,
stake_saturation,
uncapped_stake_saturation,
@@ -152,6 +154,7 @@ pub(crate) async fn annotate_gateways_with_details(
storage: &Option<NymApiStorage>,
gateway_bonds: Vec<GatewayBond>,
current_interval: Interval,
blacklist: &HashSet<IdentityKey>,
) -> Vec<GatewayBondAnnotated> {
let mut annotated = Vec::new();
for gateway_bond in gateway_bonds {
@@ -175,6 +178,7 @@ pub(crate) async fn annotate_gateways_with_details(
.unwrap_or_default();
annotated.push(GatewayBondAnnotated {
blacklisted: blacklist.contains(&gateway_bond.gateway.identity_key),
gateway_bond,
performance,
node_performance,
+14 -4
View File
@@ -109,13 +109,17 @@ impl NodeStatusCacheRefresher {
log::info!("Updating node status cache");
// Fetch contract cache data to work with
let mixnode_details = self.contract_cache.mixnodes().await;
let mixnode_details = self.contract_cache.mixnodes_all().await;
let interval_reward_params = self.contract_cache.interval_reward_params().await;
let current_interval = self.contract_cache.current_interval().await;
let rewarded_set = self.contract_cache.rewarded_set().await;
let active_set = self.contract_cache.active_set().await;
let mix_to_family = self.contract_cache.mix_to_family().await;
let gateway_bonds = self.contract_cache.gateways().await;
let gateway_bonds = self.contract_cache.gateways_all().await;
// get blacklists
let mixnodes_blacklist = self.contract_cache.mixnodes_blacklist().await;
let gateways_blacklist = self.contract_cache.gateways_blacklist().await;
let interval_reward_params =
interval_reward_params.ok_or(NodeStatusCacheError::SourceDataMissing)?;
@@ -140,6 +144,7 @@ impl NodeStatusCacheRefresher {
current_interval,
&rewarded_set_node_status,
mix_to_family.to_vec(),
&mixnodes_blacklist,
)
.await;
@@ -147,8 +152,13 @@ impl NodeStatusCacheRefresher {
let (rewarded_set, active_set) =
split_into_active_and_rewarded_set(&mixnodes_annotated, &rewarded_set_node_status);
let gateways_annotated =
annotate_gateways_with_details(&self.storage, gateway_bonds, current_interval).await;
let gateways_annotated = annotate_gateways_with_details(
&self.storage,
gateway_bonds,
current_interval,
&gateways_blacklist,
)
.await;
// Update the cache
self.cache
+35 -13
View File
@@ -24,17 +24,19 @@ async fn get_gateway_bond_annotated(
cache: &NodeStatusCache,
identity: &str,
) -> Result<GatewayBondAnnotated, ErrorResponse> {
let gateways = cache.gateways_annotated().await.ok_or(ErrorResponse::new(
"no data available",
Status::ServiceUnavailable,
))?;
let gateways = cache
.gateways_annotated_filtered()
.await
.ok_or(ErrorResponse::new(
"no data available",
Status::ServiceUnavailable,
))?;
gateways
.into_inner()
.into_iter()
.find(|gateway| gateway.identity() == identity)
.ok_or(ErrorResponse::new(
"mixnode bond not found",
"gateway bond not found",
Status::NotFound,
))
}
@@ -43,13 +45,15 @@ async fn get_mixnode_bond_annotated(
cache: &NodeStatusCache,
mix_id: MixId,
) -> Result<MixNodeBondAnnotated, ErrorResponse> {
let mixnodes = cache.mixnodes_annotated().await.ok_or(ErrorResponse::new(
"no data available",
Status::ServiceUnavailable,
))?;
let mixnodes = cache
.mixnodes_annotated_filtered()
.await
.ok_or(ErrorResponse::new(
"no data available",
Status::ServiceUnavailable,
))?;
mixnodes
.into_inner()
.into_iter()
.find(|mixnode| mixnode.mix_id() == mix_id)
.ok_or(ErrorResponse::new(
@@ -374,7 +378,16 @@ pub(crate) async fn _get_mixnode_inclusion_probabilities(
pub(crate) async fn _get_mixnodes_detailed(cache: &NodeStatusCache) -> Vec<MixNodeBondAnnotated> {
cache
.mixnodes_annotated()
.mixnodes_annotated_filtered()
.await
.unwrap_or_default()
}
pub(crate) async fn _get_mixnodes_detailed_unfiltered(
cache: &NodeStatusCache,
) -> Vec<MixNodeBondAnnotated> {
cache
.mixnodes_annotated_full()
.await
.unwrap_or_default()
.into_inner()
@@ -400,7 +413,16 @@ pub(crate) async fn _get_active_set_detailed(cache: &NodeStatusCache) -> Vec<Mix
pub(crate) async fn _get_gateways_detailed(cache: &NodeStatusCache) -> Vec<GatewayBondAnnotated> {
cache
.gateways_annotated()
.gateways_annotated_filtered()
.await
.unwrap_or_default()
}
pub(crate) async fn _get_gateways_detailed_unfiltered(
cache: &NodeStatusCache,
) -> Vec<GatewayBondAnnotated> {
cache
.gateways_annotated_full()
.await
.unwrap_or_default()
.into_inner()
+2
View File
@@ -48,9 +48,11 @@ pub(crate) fn node_status_routes(
routes::get_gateway_avg_uptime,
routes::get_mixnode_inclusion_probabilities,
routes::get_mixnodes_detailed,
routes::get_mixnodes_detailed_unfiltered,
routes::get_rewarded_set_detailed,
routes::get_active_set_detailed,
routes::get_gateways_detailed,
routes::get_gateways_detailed_unfiltered,
]
} else {
// in the minimal variant we would not have access to endpoints relying on existence
+21 -5
View File
@@ -6,11 +6,11 @@ use super::NodeStatusCache;
use crate::node_status_api::helpers::{
_compute_mixnode_reward_estimation, _gateway_core_status_count, _gateway_report,
_gateway_uptime_history, _get_active_set_detailed, _get_gateway_avg_uptime,
_get_mixnode_avg_uptime, _get_mixnode_inclusion_probabilities,
_get_mixnode_inclusion_probability, _get_mixnode_reward_estimation,
_get_mixnode_stake_saturation, _get_mixnode_status, _get_mixnodes_detailed,
_get_rewarded_set_detailed, _mixnode_core_status_count, _mixnode_report,
_mixnode_uptime_history,
_get_gateways_detailed_unfiltered, _get_mixnode_avg_uptime,
_get_mixnode_inclusion_probabilities, _get_mixnode_inclusion_probability,
_get_mixnode_reward_estimation, _get_mixnode_stake_saturation, _get_mixnode_status,
_get_mixnodes_detailed, _get_mixnodes_detailed_unfiltered, _get_rewarded_set_detailed,
_mixnode_core_status_count, _mixnode_report, _mixnode_uptime_history,
};
use crate::node_status_api::models::ErrorResponse;
use crate::storage::NymApiStorage;
@@ -188,6 +188,14 @@ pub async fn get_mixnodes_detailed(
Json(_get_mixnodes_detailed(cache).await)
}
#[openapi(tag = "status")]
#[get("/mixnodes/detailed-unfiltered")]
pub async fn get_mixnodes_detailed_unfiltered(
cache: &State<NodeStatusCache>,
) -> Json<Vec<MixNodeBondAnnotated>> {
Json(_get_mixnodes_detailed_unfiltered(cache).await)
}
#[openapi(tag = "status")]
#[get("/mixnodes/rewarded/detailed")]
pub async fn get_rewarded_set_detailed(
@@ -211,3 +219,11 @@ pub async fn get_gateways_detailed(
) -> Json<Vec<GatewayBondAnnotated>> {
Json(_get_gateways_detailed(cache).await)
}
#[openapi(tag = "status")]
#[get("/gateways/detailed-unfiltered")]
pub async fn get_gateways_detailed_unfiltered(
cache: &State<NodeStatusCache>,
) -> Json<Vec<GatewayBondAnnotated>> {
Json(_get_gateways_detailed_unfiltered(cache).await)
}
+69 -72
View File
@@ -67,50 +67,48 @@ impl NymContractCache {
}
}
pub async fn mixnodes_blacklist(&self) -> Option<Cache<HashSet<MixId>>> {
pub async fn mixnodes_blacklist(&self) -> Cache<HashSet<MixId>> {
match time::timeout(Duration::from_millis(100), self.inner.read()).await {
Ok(cache) => Some(cache.mixnodes_blacklist.clone()),
Ok(cache) => cache.mixnodes_blacklist.clone(),
Err(err) => {
error!("{err}");
None
Cache::new(HashSet::new())
}
}
}
pub async fn gateways_blacklist(&self) -> Option<Cache<HashSet<IdentityKey>>> {
pub async fn gateways_blacklist(&self) -> Cache<HashSet<IdentityKey>> {
match time::timeout(Duration::from_millis(100), self.inner.read()).await {
Ok(cache) => Some(cache.gateways_blacklist.clone()),
Ok(cache) => cache.gateways_blacklist.clone(),
Err(err) => {
error!("{err}");
None
Cache::new(HashSet::new())
}
}
}
pub async fn update_mixnodes_blacklist(&self, add: HashSet<MixId>, remove: HashSet<MixId>) {
let blacklist = self.mixnodes_blacklist().await;
if let Some(blacklist) = blacklist {
let mut blacklist = blacklist
.value
.union(&add)
.cloned()
.collect::<HashSet<MixId>>();
let to_remove = blacklist
.intersection(&remove)
.cloned()
.collect::<HashSet<MixId>>();
for key in to_remove {
blacklist.remove(&key);
let mut blacklist = blacklist
.value
.union(&add)
.cloned()
.collect::<HashSet<MixId>>();
let to_remove = blacklist
.intersection(&remove)
.cloned()
.collect::<HashSet<MixId>>();
for key in to_remove {
blacklist.remove(&key);
}
match time::timeout(Duration::from_millis(100), self.inner.write()).await {
Ok(mut cache) => {
cache.mixnodes_blacklist.update(blacklist);
}
match time::timeout(Duration::from_millis(100), self.inner.write()).await {
Ok(mut cache) => {
cache.mixnodes_blacklist.update(blacklist);
return;
}
Err(err) => error!("{err}"),
Err(err) => {
error!("Failed to update mixnodes blacklist: {err}");
}
}
error!("Failed to update mixnodes blacklist");
}
pub async fn update_gateways_blacklist(
@@ -119,49 +117,52 @@ impl NymContractCache {
remove: HashSet<IdentityKey>,
) {
let blacklist = self.gateways_blacklist().await;
if let Some(blacklist) = blacklist {
let mut blacklist = blacklist
.value
.union(&add)
.cloned()
.collect::<HashSet<IdentityKey>>();
let to_remove = blacklist
.intersection(&remove)
.cloned()
.collect::<HashSet<IdentityKey>>();
for key in to_remove {
blacklist.remove(&key);
let mut blacklist = blacklist
.value
.union(&add)
.cloned()
.collect::<HashSet<IdentityKey>>();
let to_remove = blacklist
.intersection(&remove)
.cloned()
.collect::<HashSet<IdentityKey>>();
for key in to_remove {
blacklist.remove(&key);
}
match time::timeout(Duration::from_millis(100), self.inner.write()).await {
Ok(mut cache) => {
cache.gateways_blacklist.update(blacklist);
}
match time::timeout(Duration::from_millis(100), self.inner.write()).await {
Ok(mut cache) => {
cache.gateways_blacklist.update(blacklist);
return;
}
Err(err) => error!("{err}"),
Err(err) => {
error!("Failed to update gateways blacklist: {err}");
}
}
error!("Failed to update gateways blacklist");
}
pub async fn mixnodes(&self) -> Vec<MixNodeDetails> {
pub async fn mixnodes_filtered(&self) -> Vec<MixNodeDetails> {
let mixnodes = self.mixnodes_all().await;
if mixnodes.is_empty() {
return Vec::new();
}
let blacklist = self.mixnodes_blacklist().await;
let mixnodes = match time::timeout(Duration::from_millis(100), self.inner.read()).await {
Ok(cache) => cache.mixnodes.clone(),
Err(err) => {
error!("{err}");
return Vec::new();
}
};
if let Some(blacklist) = blacklist {
if !blacklist.is_empty() {
mixnodes
.value
.iter()
.into_iter()
.filter(|mix| !blacklist.value.contains(&mix.mix_id()))
.cloned()
.collect()
} else {
mixnodes.value
mixnodes
}
}
pub async fn mixnodes_all(&self) -> Vec<MixNodeDetails> {
match time::timeout(Duration::from_millis(100), self.inner.read()).await {
Ok(cache) => cache.mixnodes.clone().value,
Err(err) => {
error!("{err}");
Vec::new()
}
}
}
@@ -181,25 +182,21 @@ impl NymContractCache {
}
}
pub async fn gateways(&self) -> Vec<GatewayBond> {
let blacklist = self.gateways_blacklist().await;
let gateways = match time::timeout(Duration::from_millis(100), self.inner.read()).await {
Ok(cache) => cache.gateways.clone(),
Err(err) => {
error!("{err}");
return Vec::new();
}
};
pub async fn gateways_filtered(&self) -> Vec<GatewayBond> {
let gateways = self.gateways_all().await;
if gateways.is_empty() {
return Vec::new();
}
if let Some(blacklist) = blacklist {
let blacklist = self.gateways_blacklist().await;
if !blacklist.is_empty() {
gateways
.value
.iter()
.into_iter()
.filter(|mix| !blacklist.value.contains(mix.identity()))
.cloned()
.collect()
} else {
gateways.value
gateways
}
}
@@ -277,7 +274,7 @@ impl NymContractCache {
return (Some(bond.clone()), MixnodeStatus::Standby);
}
let all_bonded = &self.mixnodes().await;
let all_bonded = &self.mixnodes_filtered().await;
if let Some(bond) = all_bonded.iter().find(|mix| mix.mix_id() == mix_id) {
(Some(bond.clone()), MixnodeStatus::Inactive)
} else {
+15 -5
View File
@@ -20,7 +20,7 @@ use std::collections::HashSet;
#[openapi(tag = "contract-cache")]
#[get("/mixnodes")]
pub async fn get_mixnodes(cache: &State<NymContractCache>) -> Json<Vec<MixNodeDetails>> {
Json(cache.mixnodes().await)
Json(cache.mixnodes_filtered().await)
}
// DEPRECATED: this endpoint now lives in `node_status_api`. Once all consumers are updated,
@@ -41,7 +41,7 @@ pub async fn get_mixnodes_detailed(
#[openapi(tag = "contract-cache")]
#[get("/gateways")]
pub async fn get_gateways(cache: &State<NymContractCache>) -> Json<Vec<GatewayBond>> {
Json(cache.gateways().await)
Json(cache.gateways_filtered().await)
}
#[openapi(tag = "contract-cache")]
@@ -68,7 +68,7 @@ pub async fn get_rewarded_set_detailed(
#[openapi(tag = "contract-cache")]
#[get("/mixnodes/active")]
pub async fn get_active_set(cache: &State<NymContractCache>) -> Json<Vec<MixNodeDetails>> {
Json(cache.active_set().await.value)
Json(cache.mixnodes_filtered().await)
}
// DEPRECATED: this endpoint now lives in `node_status_api`. Once all consumers are updated,
@@ -91,7 +91,12 @@ pub async fn get_active_set_detailed(
pub async fn get_blacklisted_mixnodes(
cache: &State<NymContractCache>,
) -> Json<Option<HashSet<MixId>>> {
Json(cache.mixnodes_blacklist().await.map(|c| c.value))
let blacklist = cache.mixnodes_blacklist().await.value;
if blacklist.is_empty() {
Json(None)
} else {
Json(Some(blacklist))
}
}
#[openapi(tag = "contract-cache")]
@@ -99,7 +104,12 @@ pub async fn get_blacklisted_mixnodes(
pub async fn get_blacklisted_gateways(
cache: &State<NymContractCache>,
) -> Json<Option<HashSet<String>>> {
Json(cache.gateways_blacklist().await.map(|c| c.value))
let blacklist = cache.gateways_blacklist().await.value;
if blacklist.is_empty() {
Json(None)
} else {
Json(Some(blacklist))
}
}
#[openapi(tag = "contract-cache")]
+8
View File
@@ -2,6 +2,14 @@
## [Unreleased]
## [v1.1.13] (2023-03-15)
- Wallet - in the vesting section separate the "Unlocked transferable tokens" into "Unlocked vesting tokens" and "Transferable rewards" for better clarity ([#3132])
- Wallet - change the Bonding flow to include an additional step for the user to provide a unique signature when they bond their node ([#3109])
[#3132]: https://github.com/nymtech/nym/issues/3132
[#3109]: https://github.com/nymtech/nym/issues/3109
## [v1.1.11] (2023-03-07)
- Wallet: optional gas and memo fields ([#2222])
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@nymproject/nym-wallet-app",
"version": "1.1.11",
"version": "1.1.12",
"main": "index.js",
"license": "MIT",
"scripts": {
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "nym_wallet"
version = "1.1.11"
version = "1.1.12"
description = "Nym Native Wallet"
authors = ["Nym Technologies SA"]
license = ""
+2
View File
@@ -126,6 +126,8 @@ fn main() {
vesting::queries::locked_coins,
vesting::queries::original_vesting,
vesting::queries::spendable_coins,
vesting::queries::spendable_vested_coins,
vesting::queries::spendable_reward_coins,
vesting::queries::get_historical_vesting_staking_reward,
vesting::queries::get_spendable_vested_coins,
vesting::queries::get_spendable_reward_coins,
@@ -28,7 +28,7 @@ pub(crate) async fn locked_coins(
)
.await?;
let display = guard.attempt_convert_to_display_dec_coin(res)?;
log::info!("<<< locked coins = {}", display);
log::info!("<<< locked coins = {display}");
Ok(display)
}
@@ -50,7 +50,43 @@ pub(crate) async fn spendable_coins(
.await?;
let display = guard.attempt_convert_to_display_dec_coin(res)?;
log::info!("<<< spendable coins = {}", display);
log::info!("<<< spendable coins = {display}");
Ok(display)
}
#[tauri::command]
pub(crate) async fn spendable_vested_coins(
state: tauri::State<'_, WalletState>,
) -> Result<DecCoin, BackendError> {
log::info!(">>> Query spendable vested coins");
let guard = state.read().await;
let client = guard.current_client()?;
let res = client
.nyxd
.get_spendable_vested_coins(client.nyxd.address().as_ref())
.await?;
let display = guard.attempt_convert_to_display_dec_coin(res)?;
log::info!("<<< spendable vested coins = {display}");
Ok(display)
}
#[tauri::command]
pub(crate) async fn spendable_reward_coins(
state: tauri::State<'_, WalletState>,
) -> Result<DecCoin, BackendError> {
log::info!(">>> Query spendable reward coins");
let guard = state.read().await;
let client = guard.current_client()?;
let res = client
.nyxd
.get_spendable_reward_coins(client.nyxd.address().as_ref())
.await?;
let display = guard.attempt_convert_to_display_dec_coin(res)?;
log::info!("<<< spendable reward coins = {display}");
Ok(display)
}
@@ -73,7 +109,7 @@ pub(crate) async fn vested_coins(
.await?;
let display = guard.attempt_convert_to_display_dec_coin(res)?;
log::info!("<<< vested coins = {}", display);
log::info!("<<< vested coins = {display}");
Ok(display)
}
@@ -96,7 +132,7 @@ pub(crate) async fn vesting_coins(
.await?;
let display = guard.attempt_convert_to_display_dec_coin(res)?;
log::info!("<<< vesting coins = {}", display);
log::info!("<<< vesting coins = {display}");
Ok(display)
}
@@ -161,7 +197,7 @@ pub(crate) async fn get_historical_vesting_staking_reward(
.get_historical_vesting_staking_reward(client.nyxd.address().as_ref())
.await?;
let display = guard.attempt_convert_to_display_dec_coin(res)?;
log::info!("<<< historical vesting staking reward coins = {}", display);
log::info!("<<< historical vesting staking reward coins = {display}");
Ok(display)
}
@@ -178,7 +214,7 @@ pub(crate) async fn get_spendable_vested_coins(
.get_spendable_vested_coins(client.nyxd.address().as_ref())
.await?;
let display = guard.attempt_convert_to_display_dec_coin(res)?;
log::info!("<<< spendable vested coins = {}", display);
log::info!("<<< spendable vested coins = {display}");
Ok(display)
}
@@ -195,7 +231,7 @@ pub(crate) async fn get_spendable_reward_coins(
.get_spendable_reward_coins(client.nyxd.address().as_ref())
.await?;
let display = guard.attempt_convert_to_display_dec_coin(res)?;
log::info!("<<< spendable reward coins = {}", display);
log::info!("<<< spendable reward coins = {display}");
Ok(display)
}
@@ -212,7 +248,7 @@ pub(crate) async fn get_delegated_coins(
.get_delegated_coins(client.nyxd.address().as_ref())
.await?;
let display = guard.attempt_convert_to_display_dec_coin(res)?;
log::info!("<<< delegated coins = {}", display);
log::info!("<<< delegated coins = {display}");
Ok(display)
}
@@ -229,7 +265,7 @@ pub(crate) async fn get_pledged_coins(
.get_pledged_coins(client.nyxd.address().as_ref())
.await?;
let display = guard.attempt_convert_to_display_dec_coin(res)?;
log::info!("<<< pledged coins = {}", display);
log::info!("<<< pledged coins = {display}");
Ok(display)
}
@@ -246,7 +282,7 @@ pub(crate) async fn get_staked_coins(
.get_staked_coins(client.nyxd.address().as_ref())
.await?;
let display = guard.attempt_convert_to_display_dec_coin(res)?;
log::info!("<<< staked coins = {}", display);
log::info!("<<< staked coins = {display}");
Ok(display)
}
@@ -263,7 +299,7 @@ pub(crate) async fn get_withdrawn_coins(
.get_withdrawn_coins(client.nyxd.address().as_ref())
.await?;
let display = guard.attempt_convert_to_display_dec_coin(res)?;
log::info!("<<< pledged coins = {}", display);
log::info!("<<< pledged coins = {display}");
Ok(display)
}
+1 -1
View File
@@ -1,7 +1,7 @@
{
"package": {
"productName": "nym-wallet",
"version": "1.1.11"
"version": "1.1.12"
},
"build": {
"distDir": "../dist",
@@ -1,9 +1,9 @@
/* eslint-disable react/no-array-index-key */
import React, { useContext } from 'react';
import { useTheme } from '@mui/material/styles';
import { Box, Tooltip, Typography } from '@mui/material';
import { Box, Stack, Tooltip, Typography } from '@mui/material';
import { format } from 'date-fns';
import { AppContext } from '../../../context';
import { AppContext } from 'src/context';
const calculateMarkerPosition = (arrLength: number, index: number) => (1 / arrLength) * 100 * index;
@@ -30,30 +30,33 @@ export const VestingTimeline: FCWithChildren<{ percentageComplete: number }> = (
: undefined;
return (
<Box display="flex" flexDirection="column" gap={1} position="relative" width="100%">
<svg width="100%" height="12">
<rect y="2" width="100%" height="6" rx="0" fill="#E6E6E6" />
<rect y="2" width={`${percentageComplete}%`} height="6" rx="0" fill={theme.palette.success.main} />
{vestingAccountInfo?.periods.map((period, i, arr) => (
<Box>
<Stack direction="row" gap={1} alignItems="center">
<Typography variant="body2">{percentageComplete}%</Typography>
<svg width="100%" height="12">
<rect y="2" width="100%" height="6" rx="0" fill="#E6E6E6" />
<rect y="2" width={`${percentageComplete}%`} height="6" rx="0" fill={theme.palette.success.main} />
{vestingAccountInfo?.periods.map((period, i, arr) => (
<Marker
position={`${calculateMarkerPosition(arr.length, i)}%`}
color={
Math.ceil(+percentageComplete) >= calculateMarkerPosition(arr.length, i)
? theme.palette.success.main
: '#B9B9B9'
}
tooltipText={format(new Date(Number(period.start_time) * 1000), 'HH:mm do MMM yyyy')}
key={i}
/>
))}
<Marker
position={`${calculateMarkerPosition(arr.length, i)}%`}
color={
Math.ceil(+percentageComplete) >= calculateMarkerPosition(arr.length, i)
? theme.palette.success.main
: '#B9B9B9'
}
tooltipText={format(new Date(Number(period.start_time) * 1000), 'HH:mm do MMM yyyy')}
key={i}
position="calc(100% - 4px)"
color={percentageComplete === 100 ? theme.palette.success.main : '#B9B9B9'}
tooltipText="End of vesting schedule"
/>
))}
<Marker
position="calc(100% - 4px)"
color={percentageComplete === 100 ? theme.palette.success.main : '#B9B9B9'}
tooltipText="End of vesting schedule"
/>
</svg>
</svg>
</Stack>
{!!nextPeriod && (
<Typography variant="caption" sx={{ color: 'nym.text.muted', position: 'absolute', top: 15, left: 0 }}>
<Typography variant="caption" sx={{ color: 'nym.text.muted', ml: 6 }}>
Next vesting period: {format(new Date(nextPeriod * 1000), 'HH:mm do MMM yyyy')}
</Typography>
)}
@@ -0,0 +1,28 @@
import React from 'react';
import { Card, Stack, Button } from '@mui/material';
import { ModalListItem } from 'src/components/Modals/ModalListItem';
export const TokenTransfer = ({
onTransfer,
unlockedTokens,
unlockedRewards,
unlockedTransferable,
}: {
unlockedTokens?: string;
unlockedRewards?: string;
unlockedTransferable?: string;
onTransfer: () => void;
}) => (
<Card variant="outlined" sx={{ p: 3, height: '100%' }}>
<Stack justifyContent="space-between" sx={{ height: '100%' }}>
<Stack gap={1} sx={{ mb: 2 }}>
<ModalListItem label="Unlocked tokens" value={unlockedTokens} />
<ModalListItem label="Unlocked rewards" value={unlockedRewards} divider />
<ModalListItem fontSize={16} label="Transferable tokens" value={unlockedTransferable} fontWeight={600} />
</Stack>
<Button size="large" fullWidth variant="contained" onClick={onTransfer} disableElevation>
Transfer
</Button>
</Stack>
</Card>
);

Some files were not shown because too many files have changed in this diff Show More