Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2466112829 | |||
| e5306908e4 |
@@ -1 +0,0 @@
|
||||
nym-validator-rewarder/.sqlx/** diff=nodiff
|
||||
@@ -31,5 +31,3 @@ updates:
|
||||
update-types:
|
||||
- "patch"
|
||||
open-pull-requests-limit: 10
|
||||
assignees:
|
||||
- "octol"
|
||||
|
||||
+1
-2
@@ -54,8 +54,7 @@ nym-network-monitor/__pycache__
|
||||
nym-network-monitor/*.key
|
||||
nym-network-monitor/.envrc
|
||||
nym-network-monitor/.envrc
|
||||
nym-api/redocly/formatted-openapi.json
|
||||
|
||||
|
||||
*.sqlite
|
||||
.build
|
||||
.build
|
||||
Generated
+97
-83
@@ -2196,15 +2196,10 @@ dependencies = [
|
||||
"bincode",
|
||||
"bytecodec",
|
||||
"bytes",
|
||||
"clap 4.5.20",
|
||||
"dashmap",
|
||||
"dirs",
|
||||
"futures",
|
||||
"nym-bin-common",
|
||||
"nym-crypto",
|
||||
"nym-sdk",
|
||||
"serde",
|
||||
"tempfile",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
"tokio-util",
|
||||
@@ -3841,12 +3836,6 @@ dependencies = [
|
||||
"scopeguard",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lockfree-object-pool"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9374ef4228402d4b7e403e5838cb880d9ee663314b0a900d5a6aabf0c213552e"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.22"
|
||||
@@ -4066,30 +4055,6 @@ dependencies = [
|
||||
"wasm-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mixnet-check-all-gateways"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bincode",
|
||||
"clap 4.5.20",
|
||||
"dirs",
|
||||
"echo-server",
|
||||
"futures",
|
||||
"nym-bin-common",
|
||||
"nym-crypto",
|
||||
"nym-sdk",
|
||||
"reqwest 0.12.4",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tempfile",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mixnet-connectivity-check"
|
||||
version = "0.1.0"
|
||||
@@ -4390,6 +4355,27 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_enum"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179"
|
||||
dependencies = [
|
||||
"num_enum_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_enum_derive"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56"
|
||||
dependencies = [
|
||||
"proc-macro-crate",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.90",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_threads"
|
||||
version = "0.1.7"
|
||||
@@ -5015,7 +5001,6 @@ dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
"utoipa",
|
||||
"vergen",
|
||||
]
|
||||
|
||||
@@ -5207,7 +5192,6 @@ dependencies = [
|
||||
"strum 0.26.3",
|
||||
"thiserror",
|
||||
"time",
|
||||
"utoipa",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -5339,7 +5323,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-ffi-shared"
|
||||
version = "0.2.1"
|
||||
version = "0.2.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bs58",
|
||||
@@ -5500,7 +5484,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-go-ffi"
|
||||
version = "0.2.1"
|
||||
version = "0.2.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"lazy_static",
|
||||
@@ -5671,20 +5655,18 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"dashmap",
|
||||
"lazy_static",
|
||||
"log",
|
||||
"prometheus",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nym-mixnet-client"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"dashmap",
|
||||
"futures",
|
||||
"nym-sphinx",
|
||||
"nym-task",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
"tokio-util",
|
||||
"tracing",
|
||||
]
|
||||
@@ -6178,7 +6160,6 @@ dependencies = [
|
||||
"reqwest 0.12.4",
|
||||
"serde",
|
||||
"tap",
|
||||
"tempfile",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
@@ -6547,7 +6528,6 @@ dependencies = [
|
||||
"serde_json",
|
||||
"sha2 0.10.8",
|
||||
"time",
|
||||
"utoipa",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -6611,7 +6591,6 @@ dependencies = [
|
||||
"thiserror",
|
||||
"ts-rs",
|
||||
"url",
|
||||
"utoipa",
|
||||
"x25519-dalek",
|
||||
]
|
||||
|
||||
@@ -7504,6 +7483,39 @@ dependencies = [
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-crate"
|
||||
version = "3.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284"
|
||||
dependencies = [
|
||||
"toml_edit 0.21.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
|
||||
dependencies = [
|
||||
"proc-macro-error-attr",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error-attr"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error-attr2"
|
||||
version = "2.0.0"
|
||||
@@ -7935,6 +7947,7 @@ checksum = "566cafdd92868e0939d3fb961bd0dc25fcfaaed179291093b3d43e6b3150ea10"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"bytes",
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"http 1.1.0",
|
||||
@@ -8860,12 +8873,6 @@ dependencies = [
|
||||
"rand_core 0.6.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "simd-adler32"
|
||||
version = "0.3.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe"
|
||||
|
||||
[[package]]
|
||||
name = "siphasher"
|
||||
version = "0.3.11"
|
||||
@@ -9923,7 +9930,7 @@ dependencies = [
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
"toml_edit",
|
||||
"toml_edit 0.22.14",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -9935,6 +9942,17 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_edit"
|
||||
version = "0.21.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1"
|
||||
dependencies = [
|
||||
"indexmap 2.2.6",
|
||||
"toml_datetime",
|
||||
"winnow 0.5.40",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_edit"
|
||||
version = "0.22.14"
|
||||
@@ -9945,7 +9963,7 @@ dependencies = [
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
"winnow",
|
||||
"winnow 0.6.13",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -10592,9 +10610,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
||||
|
||||
[[package]]
|
||||
name = "utoipa"
|
||||
version = "5.2.0"
|
||||
version = "4.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "514a48569e4e21c86d0b84b5612b5e73c0b2cf09db63260134ba426d4e8ea714"
|
||||
checksum = "c5afb1a60e207dca502682537fefcfd9921e71d0b83e9576060f09abc6efab23"
|
||||
dependencies = [
|
||||
"indexmap 2.2.6",
|
||||
"serde",
|
||||
@@ -10604,10 +10622,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "utoipa-gen"
|
||||
version = "5.2.0"
|
||||
version = "4.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5629efe65599d0ccd5d493688cbf6e03aa7c1da07fe59ff97cf5977ed0637f66"
|
||||
checksum = "7bf0e16c02bc4bf5322ab65f10ab1149bdbcaa782cba66dc7057370a3f8190be"
|
||||
dependencies = [
|
||||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"regex",
|
||||
@@ -10617,13 +10636,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "utoipa-swagger-ui"
|
||||
version = "8.0.3"
|
||||
version = "7.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a5c80b4dd79ea382e8374d67dcce22b5c6663fa13a82ad3886441d1bbede5e35"
|
||||
checksum = "943e0ff606c6d57d410fd5663a4d7c074ab2c5f14ab903b9514565e59fa1189e"
|
||||
dependencies = [
|
||||
"axum 0.7.7",
|
||||
"mime_guess",
|
||||
"regex",
|
||||
"reqwest 0.12.4",
|
||||
"rust-embed",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@@ -10634,18 +10654,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "utoipauto"
|
||||
version = "0.2.0"
|
||||
version = "0.1.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cba36db2c397c614110554a60fbb4bb97d5f8c6823775c766e6f455e37377047"
|
||||
checksum = "608b8f2279483be386261655b562e40877ea434eb92093c894a644fda2021860"
|
||||
dependencies = [
|
||||
"utoipauto-macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "utoipauto-core"
|
||||
version = "0.2.0"
|
||||
version = "0.1.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "268d76aaebb80eba79240b805972e52d7d410d4bcc52321b951318b0f440cd60"
|
||||
checksum = "17e82ab96c5a55263b5bed151b8426410d93aa909a453acdbd4b6792b5af7d64"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -10654,9 +10674,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "utoipauto-macro"
|
||||
version = "0.2.0"
|
||||
version = "0.1.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "382673bda1d05c85b4550d32fd4192ccd4cffe9a908543a0795d1e7682b36246"
|
||||
checksum = "86b8338dc3c9526011ffaa2aa6bd60ddfda9d49d2123108690755c6e34844212"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -11247,6 +11267,15 @@ version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"
|
||||
|
||||
[[package]]
|
||||
name = "winnow"
|
||||
version = "0.5.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winnow"
|
||||
version = "0.6.13"
|
||||
@@ -11359,9 +11388,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "zip"
|
||||
version = "2.1.6"
|
||||
version = "1.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "40dd8c92efc296286ce1fbd16657c5dbefff44f1b4ca01cc5f517d8b7b3d3e2e"
|
||||
checksum = "9cc23c04387f4da0374be4533ad1208cbb091d5c11d070dfef13676ad6497164"
|
||||
dependencies = [
|
||||
"arbitrary",
|
||||
"crc32fast",
|
||||
@@ -11369,9 +11398,8 @@ dependencies = [
|
||||
"displaydoc",
|
||||
"flate2",
|
||||
"indexmap 2.2.6",
|
||||
"memchr",
|
||||
"num_enum",
|
||||
"thiserror",
|
||||
"zopfli",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -11401,17 +11429,3 @@ dependencies = [
|
||||
"wasmtimer",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zopfli"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e5019f391bac5cf252e93bbcc53d039ffd62c7bfb7c150414d61369afe57e946"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"crc32fast",
|
||||
"lockfree-object-pool",
|
||||
"log",
|
||||
"once_cell",
|
||||
"simd-adler32",
|
||||
]
|
||||
|
||||
+5
-5
@@ -128,7 +128,7 @@ members = [
|
||||
"nym-node-status-api/nym-node-status-client",
|
||||
"nym-outfox",
|
||||
"nym-validator-rewarder",
|
||||
# "tools/echo-server",
|
||||
"tools/echo-server",
|
||||
"tools/internal/ssl-inject",
|
||||
# "tools/internal/sdk-version-bump",
|
||||
"tools/internal/testnet-manager",
|
||||
@@ -149,7 +149,7 @@ members = [
|
||||
"tools/internal/testnet-manager",
|
||||
"tools/internal/testnet-manager/dkg-bypass-contract",
|
||||
"common/verloc",
|
||||
"tools/internal/mixnet-connectivity-check", "tools/internal/mixnet-check-all-gateways",
|
||||
"tools/internal/mixnet-connectivity-check",
|
||||
]
|
||||
|
||||
default-members = [
|
||||
@@ -347,9 +347,9 @@ tracing-log = "0.2"
|
||||
ts-rs = "10.0.0"
|
||||
tungstenite = { version = "0.20.1", default-features = false }
|
||||
url = "2.5"
|
||||
utoipa = "5.2"
|
||||
utoipa-swagger-ui = "8.0"
|
||||
utoipauto = "0.2"
|
||||
utoipa = "4.2"
|
||||
utoipa-swagger-ui = "7.1"
|
||||
utoipauto = "0.1"
|
||||
uuid = "*"
|
||||
vergen = { version = "=8.3.1", default-features = false }
|
||||
walkdir = "2"
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
Boost Software License - Version 1.0 - August 17th, 2003
|
||||
|
||||
Permission is hereby granted, free of charge, to any person or organization
|
||||
obtaining a copy of the software and accompanying documentation covered by
|
||||
this license (the "Software") to use, reproduce, display, distribute,
|
||||
execute, and transmit the Software, and to prepare derivative works of the
|
||||
Software, and to permit third-parties to whom the Software is furnished to
|
||||
do so, all subject to the following:
|
||||
|
||||
The copyright notices in the Software and this entire statement, including
|
||||
the above license grant, this restriction and the following disclaimer,
|
||||
must be included in all copies of the Software, in whole or in part, and
|
||||
all derivative works of the Software, unless such copies or derivative
|
||||
works are solely in the form of machine-executable object code generated by
|
||||
a source language processor.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
@@ -8,12 +8,10 @@ license.workspace = true
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
dashmap = { workspace = true }
|
||||
futures = { workspace = true }
|
||||
tracing = { workspace = true }
|
||||
tokio = { workspace = true, features = ["time", "sync"] }
|
||||
tokio = { workspace = true, features = ["time"] }
|
||||
tokio-util = { workspace = true, features = ["codec"], optional = true }
|
||||
tokio-stream = { workspace = true }
|
||||
|
||||
# internal
|
||||
nym-sphinx = { path = "../../nymsphinx" }
|
||||
|
||||
@@ -1,24 +1,21 @@
|
||||
// Copyright 2021-2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use dashmap::DashMap;
|
||||
use futures::channel::mpsc;
|
||||
use futures::StreamExt;
|
||||
use nym_sphinx::addressing::nodes::NymNodeRoutingAddress;
|
||||
use nym_sphinx::framing::codec::NymCodec;
|
||||
use nym_sphinx::framing::packet::FramedNymPacket;
|
||||
use nym_sphinx::params::PacketType;
|
||||
use nym_sphinx::NymPacket;
|
||||
use std::collections::HashMap;
|
||||
use std::io;
|
||||
use std::net::SocketAddr;
|
||||
use std::ops::Deref;
|
||||
use std::sync::atomic::{AtomicU32, AtomicUsize, Ordering};
|
||||
use std::sync::atomic::{AtomicU32, Ordering};
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use tokio::net::TcpStream;
|
||||
use tokio::sync::mpsc;
|
||||
use tokio::sync::mpsc::error::TrySendError;
|
||||
use tokio::time::sleep;
|
||||
use tokio_stream::wrappers::ReceiverStream;
|
||||
use tokio_util::codec::Framed;
|
||||
use tracing::*;
|
||||
|
||||
@@ -58,37 +55,11 @@ pub trait SendWithoutResponse {
|
||||
}
|
||||
|
||||
pub struct Client {
|
||||
active_connections: ActiveConnections,
|
||||
connections_count: Arc<AtomicUsize>,
|
||||
conn_new: HashMap<NymNodeRoutingAddress, ConnectionSender>,
|
||||
config: Config,
|
||||
}
|
||||
|
||||
#[derive(Default, Clone)]
|
||||
pub struct ActiveConnections {
|
||||
inner: Arc<DashMap<NymNodeRoutingAddress, ConnectionSender>>,
|
||||
}
|
||||
|
||||
impl ActiveConnections {
|
||||
pub fn pending_packets(&self) -> usize {
|
||||
self.inner
|
||||
.iter()
|
||||
.map(|sender| {
|
||||
let max_capacity = sender.channel.max_capacity();
|
||||
let capacity = sender.channel.capacity();
|
||||
max_capacity - capacity
|
||||
})
|
||||
.sum()
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for ActiveConnections {
|
||||
type Target = DashMap<NymNodeRoutingAddress, ConnectionSender>;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.inner
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ConnectionSender {
|
||||
struct ConnectionSender {
|
||||
channel: mpsc::Sender<FramedNymPacket>,
|
||||
current_reconnection_attempt: Arc<AtomicU32>,
|
||||
}
|
||||
@@ -102,53 +73,46 @@ impl ConnectionSender {
|
||||
}
|
||||
}
|
||||
|
||||
struct ManagedConnection {
|
||||
address: SocketAddr,
|
||||
message_receiver: ReceiverStream<FramedNymPacket>,
|
||||
connection_timeout: Duration,
|
||||
current_reconnection: Arc<AtomicU32>,
|
||||
}
|
||||
|
||||
impl ManagedConnection {
|
||||
fn new(
|
||||
address: SocketAddr,
|
||||
message_receiver: mpsc::Receiver<FramedNymPacket>,
|
||||
connection_timeout: Duration,
|
||||
current_reconnection: Arc<AtomicU32>,
|
||||
) -> Self {
|
||||
ManagedConnection {
|
||||
address,
|
||||
message_receiver: ReceiverStream::new(message_receiver),
|
||||
connection_timeout,
|
||||
current_reconnection,
|
||||
impl Client {
|
||||
pub fn new(config: Config) -> Client {
|
||||
Client {
|
||||
conn_new: HashMap::new(),
|
||||
config,
|
||||
}
|
||||
}
|
||||
|
||||
async fn run(self) {
|
||||
let address = self.address;
|
||||
async fn manage_connection(
|
||||
address: SocketAddr,
|
||||
receiver: mpsc::Receiver<FramedNymPacket>,
|
||||
connection_timeout: Duration,
|
||||
current_reconnection: &AtomicU32,
|
||||
) {
|
||||
let connection_fut = TcpStream::connect(address);
|
||||
|
||||
let conn = match tokio::time::timeout(self.connection_timeout, connection_fut).await {
|
||||
let conn = match tokio::time::timeout(connection_timeout, connection_fut).await {
|
||||
Ok(stream_res) => match stream_res {
|
||||
Ok(stream) => {
|
||||
debug!("Managed to establish connection to {}", self.address);
|
||||
debug!("Managed to establish connection to {}", address);
|
||||
// if we managed to connect, reset the reconnection count (whatever it might have been)
|
||||
self.current_reconnection.store(0, Ordering::Release);
|
||||
current_reconnection.store(0, Ordering::Release);
|
||||
Framed::new(stream, NymCodec)
|
||||
}
|
||||
Err(err) => {
|
||||
debug!("failed to establish connection to {address} (err: {err})",);
|
||||
debug!(
|
||||
"failed to establish connection to {} (err: {})",
|
||||
address, err
|
||||
);
|
||||
return;
|
||||
}
|
||||
},
|
||||
Err(_) => {
|
||||
debug!(
|
||||
"failed to connect to {address} within {:?}",
|
||||
self.connection_timeout
|
||||
"failed to connect to {} within {:?}",
|
||||
address, connection_timeout
|
||||
);
|
||||
|
||||
// we failed to connect - increase reconnection attempt
|
||||
self.current_reconnection.fetch_add(1, Ordering::SeqCst);
|
||||
current_reconnection.fetch_add(1, Ordering::SeqCst);
|
||||
return;
|
||||
}
|
||||
};
|
||||
@@ -156,28 +120,15 @@ impl ManagedConnection {
|
||||
// Take whatever the receiver channel produces and put it on the connection.
|
||||
// We could have as well used conn.send_all(receiver.map(Ok)), but considering we don't care
|
||||
// about neither receiver nor the connection, it doesn't matter which one gets consumed
|
||||
if let Err(err) = self.message_receiver.map(Ok).forward(conn).await {
|
||||
warn!("Failed to forward packets to {address}: {err}");
|
||||
if let Err(err) = receiver.map(Ok).forward(conn).await {
|
||||
warn!("Failed to forward packets to {} - {err}", address);
|
||||
}
|
||||
|
||||
debug!(
|
||||
"connection manager to {address} is finished. Either the connection failed or mixnet client got dropped",
|
||||
"connection manager to {} is finished. Either the connection failed or mixnet client got dropped",
|
||||
address
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
impl Client {
|
||||
pub fn new(config: Config, connections_count: Arc<AtomicUsize>) -> Client {
|
||||
Client {
|
||||
active_connections: Default::default(),
|
||||
connections_count,
|
||||
config,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn active_connections(&self) -> ActiveConnections {
|
||||
self.active_connections.clone()
|
||||
}
|
||||
|
||||
/// If we're trying to reconnect, determine how long we should wait.
|
||||
fn determine_backoff(&self, current_attempt: u32) -> Option<Duration> {
|
||||
@@ -197,7 +148,7 @@ impl Client {
|
||||
}
|
||||
|
||||
fn make_connection(&mut self, address: NymNodeRoutingAddress, pending_packet: FramedNymPacket) {
|
||||
let (sender, receiver) = mpsc::channel(self.config.maximum_connection_buffer_size);
|
||||
let (mut sender, receiver) = mpsc::channel(self.config.maximum_connection_buffer_size);
|
||||
|
||||
// this CAN'T fail because we just created the channel which has a non-zero capacity
|
||||
if self.config.maximum_connection_buffer_size > 0 {
|
||||
@@ -205,16 +156,15 @@ impl Client {
|
||||
}
|
||||
|
||||
// if we already tried to connect to `address` before, grab the current attempt count
|
||||
let current_reconnection_attempt =
|
||||
if let Some(mut existing) = self.active_connections.get_mut(&address) {
|
||||
existing.channel = sender;
|
||||
Arc::clone(&existing.current_reconnection_attempt)
|
||||
} else {
|
||||
let new_entry = ConnectionSender::new(sender);
|
||||
let current_attempt = Arc::clone(&new_entry.current_reconnection_attempt);
|
||||
self.active_connections.insert(address, new_entry);
|
||||
current_attempt
|
||||
};
|
||||
let current_reconnection_attempt = if let Some(existing) = self.conn_new.get_mut(&address) {
|
||||
existing.channel = sender;
|
||||
Arc::clone(&existing.current_reconnection_attempt)
|
||||
} else {
|
||||
let new_entry = ConnectionSender::new(sender);
|
||||
let current_attempt = Arc::clone(&new_entry.current_reconnection_attempt);
|
||||
self.conn_new.insert(address, new_entry);
|
||||
current_attempt
|
||||
};
|
||||
|
||||
// load the actual value.
|
||||
let reconnection_attempt = current_reconnection_attempt.load(Ordering::Acquire);
|
||||
@@ -223,7 +173,6 @@ impl Client {
|
||||
// copy the value before moving into another task
|
||||
let initial_connection_timeout = self.config.initial_connection_timeout;
|
||||
|
||||
let connections_count = self.connections_count.clone();
|
||||
tokio::spawn(async move {
|
||||
// before executing the manager, wait for what was specified, if anything
|
||||
if let Some(backoff) = backoff {
|
||||
@@ -231,16 +180,13 @@ impl Client {
|
||||
sleep(backoff).await;
|
||||
}
|
||||
|
||||
connections_count.fetch_add(1, Ordering::SeqCst);
|
||||
ManagedConnection::new(
|
||||
Self::manage_connection(
|
||||
address.into(),
|
||||
receiver,
|
||||
initial_connection_timeout,
|
||||
current_reconnection_attempt,
|
||||
¤t_reconnection_attempt,
|
||||
)
|
||||
.run()
|
||||
.await;
|
||||
connections_count.fetch_sub(1, Ordering::SeqCst);
|
||||
.await
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -255,47 +201,49 @@ impl SendWithoutResponse for Client {
|
||||
trace!("Sending packet to {address:?}");
|
||||
let framed_packet = FramedNymPacket::new(packet, packet_type);
|
||||
|
||||
let Some(sender) = self.active_connections.get_mut(&address) else {
|
||||
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);
|
||||
// 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(
|
||||
io::ErrorKind::WouldBlock,
|
||||
"connection queue is full",
|
||||
))
|
||||
} else if err.is_disconnected() {
|
||||
debug!(
|
||||
"Connection to {} seems to be dead. attempting to re-establish it...",
|
||||
address
|
||||
);
|
||||
// it's not a 'big' error, but we did not manage to send the packet, but queue
|
||||
// it up to send it as soon as the connection is re-established
|
||||
self.make_connection(address, err.into_inner());
|
||||
Err(io::Error::new(
|
||||
io::ErrorKind::ConnectionAborted,
|
||||
"reconnection attempt is in progress",
|
||||
))
|
||||
} else {
|
||||
// this can't really happen, but let's safe-guard against it in case something changes in futures library
|
||||
Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
"unknown connection buffer error",
|
||||
))
|
||||
}
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
} else {
|
||||
// there was never a connection to begin with
|
||||
debug!("establishing initial connection to {}", address);
|
||||
// it's not a 'big' error, but we did not manage to send the packet, but queue the packet
|
||||
// for sending for as soon as the connection is created
|
||||
self.make_connection(address, framed_packet);
|
||||
return Err(io::Error::new(
|
||||
Err(io::Error::new(
|
||||
io::ErrorKind::NotConnected,
|
||||
"connection is in progress",
|
||||
));
|
||||
};
|
||||
|
||||
let sending_res = sender.channel.try_send(framed_packet);
|
||||
drop(sender);
|
||||
|
||||
sending_res.map_err(|err| {
|
||||
match err {
|
||||
TrySendError::Full(_) => {
|
||||
debug!("Connection to {address} seems to not be able to handle all the traffic - dropping the current packet");
|
||||
// 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
|
||||
io::Error::new(
|
||||
io::ErrorKind::WouldBlock,
|
||||
"connection queue is full",
|
||||
)
|
||||
}
|
||||
TrySendError::Closed(dropped) => {
|
||||
debug!(
|
||||
"Connection to {address} seems to be dead. attempting to re-establish it...",
|
||||
);
|
||||
|
||||
// it's not a 'big' error, but we did not manage to send the packet, but queue
|
||||
// it up to send it as soon as the connection is re-established
|
||||
self.make_connection(address, dropped);
|
||||
io::Error::new(
|
||||
io::ErrorKind::ConnectionAborted,
|
||||
"reconnection attempt is in progress",
|
||||
)
|
||||
}
|
||||
}
|
||||
} )
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -304,15 +252,12 @@ mod tests {
|
||||
use super::*;
|
||||
|
||||
fn dummy_client() -> Client {
|
||||
Client::new(
|
||||
Config {
|
||||
initial_reconnection_backoff: Duration::from_millis(10_000),
|
||||
maximum_reconnection_backoff: Duration::from_millis(300_000),
|
||||
initial_connection_timeout: Duration::from_millis(1_500),
|
||||
maximum_connection_buffer_size: 128,
|
||||
},
|
||||
Default::default(),
|
||||
)
|
||||
Client::new(Config {
|
||||
initial_reconnection_backoff: Duration::from_millis(10_000),
|
||||
maximum_reconnection_backoff: Duration::from_millis(300_000),
|
||||
initial_connection_timeout: Duration::from_millis(1_500),
|
||||
maximum_connection_buffer_size: 128,
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -13,7 +13,6 @@ cosmwasm-std = { workspace = true }
|
||||
cosmwasm-schema = { workspace = true }
|
||||
cw-storage-plus = { workspace = true }
|
||||
schemars = { workspace = true }
|
||||
utoipa = { workspace = true, optional = true }
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
thiserror = { workspace = true }
|
||||
|
||||
@@ -24,5 +23,4 @@ serde_json = { workspace = true }
|
||||
vergen = { workspace = true, features = ["build", "git", "gitcl", "rustc", "cargo"] }
|
||||
|
||||
[features]
|
||||
naive_float = []
|
||||
utoipa = ["dep:utoipa"]
|
||||
naive_float = []
|
||||
@@ -221,7 +221,6 @@ fn default_unknown() -> String {
|
||||
// TODO: there's no reason this couldn't be used for proper binaries, but in that case
|
||||
// perhaps the struct should get renamed and moved to a "more" common crate
|
||||
#[cw_serde]
|
||||
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
|
||||
pub struct ContractBuildInformation {
|
||||
/// Provides the name of the binary, i.e. the content of `CARGO_PKG_NAME` environmental variable.
|
||||
#[serde(default = "default_unknown")]
|
||||
|
||||
@@ -42,11 +42,9 @@ pub struct Gateway {
|
||||
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
|
||||
pub struct GatewayBond {
|
||||
/// Original amount pledged by the operator of this node.
|
||||
#[cfg_attr(feature = "utoipa", schema(value_type = crate::CoinSchema))]
|
||||
pub pledge_amount: Coin,
|
||||
|
||||
/// Address of the owner of this gateway.
|
||||
#[cfg_attr(feature = "utoipa", schema(value_type = String))]
|
||||
pub owner: Addr,
|
||||
|
||||
/// Block height at which this gateway has been bonded.
|
||||
@@ -57,7 +55,6 @@ pub struct GatewayBond {
|
||||
|
||||
/// Entity who bonded this gateway on behalf of the owner.
|
||||
/// If exists, it's most likely the address of the vesting contract.
|
||||
#[cfg_attr(feature = "utoipa", schema(value_type = String))]
|
||||
pub proxy: Option<Addr>,
|
||||
}
|
||||
|
||||
|
||||
@@ -82,25 +82,20 @@ impl MixNodeDetails {
|
||||
|
||||
// currently this struct is shared between mixnodes and nymnodes
|
||||
#[cw_serde]
|
||||
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
|
||||
pub struct NodeRewarding {
|
||||
/// Information provided by the operator that influence the cost function.
|
||||
pub cost_params: NodeCostParams,
|
||||
|
||||
/// Total pledge and compounded reward earned by the node operator.
|
||||
#[cfg_attr(feature = "utoipa", schema(value_type = String))]
|
||||
pub operator: Decimal,
|
||||
|
||||
/// Total delegation and compounded reward earned by all node delegators.
|
||||
#[cfg_attr(feature = "utoipa", schema(value_type = String))]
|
||||
pub delegates: Decimal,
|
||||
|
||||
/// Cumulative reward earned by the "unit delegation" since the block 0.
|
||||
#[cfg_attr(feature = "utoipa", schema(value_type = String))]
|
||||
pub total_unit_reward: Decimal,
|
||||
|
||||
/// Value of the theoretical "unit delegation" that has delegated to this node at block 0.
|
||||
#[cfg_attr(feature = "utoipa", schema(value_type = String))]
|
||||
pub unit_delegation: Decimal,
|
||||
|
||||
/// Marks the epoch when this node was last rewarded so that we wouldn't accidentally attempt
|
||||
@@ -497,17 +492,14 @@ impl NodeRewarding {
|
||||
::cosmwasm_schema::schemars::JsonSchema,
|
||||
)]
|
||||
#[schemars(crate = "::cosmwasm_schema::schemars")]
|
||||
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
|
||||
pub struct MixNodeBond {
|
||||
/// Unique id assigned to the bonded mixnode.
|
||||
pub mix_id: NodeId,
|
||||
|
||||
/// Address of the owner of this mixnode.
|
||||
#[cfg_attr(feature = "utoipa", schema(value_type = String))]
|
||||
pub owner: Addr,
|
||||
|
||||
/// Original amount pledged by the operator of this node.
|
||||
#[cfg_attr(feature = "utoipa", schema(value_type = crate::CoinSchema))]
|
||||
pub original_pledge: Coin,
|
||||
|
||||
// REMOVED (but might be needed due to legacy things, idk yet)
|
||||
@@ -518,7 +510,6 @@ pub struct MixNodeBond {
|
||||
|
||||
/// Entity who bonded this mixnode on behalf of the owner.
|
||||
/// If exists, it's most likely the address of the vesting contract.
|
||||
#[cfg_attr(feature = "utoipa", schema(value_type = Option<String>))]
|
||||
pub proxy: Option<Addr>,
|
||||
|
||||
/// Block height at which this mixnode has been bonded.
|
||||
@@ -554,7 +545,6 @@ impl MixNodeBond {
|
||||
feature = "generate-ts",
|
||||
ts(export, export_to = "ts-packages/types/src/types/rust/Mixnode.ts")
|
||||
)]
|
||||
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
|
||||
pub struct MixNode {
|
||||
/// Network address of this mixnode, for example 1.1.1.1 or foo.mixnode.com
|
||||
pub host: String,
|
||||
@@ -581,14 +571,11 @@ pub struct MixNode {
|
||||
/// The cost parameters, or the cost function, defined for the particular mixnode that influences
|
||||
/// how the rewards should be split between the node operator and its delegators.
|
||||
#[cw_serde]
|
||||
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
|
||||
pub struct NodeCostParams {
|
||||
/// The profit margin of the associated node, i.e. the desired percent of the reward to be distributed to the operator.
|
||||
#[cfg_attr(feature = "utoipa", schema(value_type = String))]
|
||||
pub profit_margin_percent: Percent,
|
||||
|
||||
/// Operating cost of the associated node per the entire interval.
|
||||
#[cfg_attr(feature = "utoipa", schema(value_type = crate::CoinSchema))]
|
||||
pub interval_operating_cost: Coin,
|
||||
}
|
||||
|
||||
@@ -693,9 +680,7 @@ pub struct PendingMixNodeChanges {
|
||||
}
|
||||
|
||||
#[derive(Default, Copy, Clone, Debug, Serialize, Deserialize, JsonSchema)]
|
||||
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
|
||||
pub struct LegacyPendingMixNodeChanges {
|
||||
#[cfg_attr(feature = "utoipa", schema(value_type = Option<u32>))]
|
||||
pub pledge_change: Option<EpochEventId>,
|
||||
}
|
||||
|
||||
|
||||
@@ -231,7 +231,6 @@ pub struct RoleMetadata {
|
||||
|
||||
/// Full details associated with given node.
|
||||
#[cw_serde]
|
||||
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
|
||||
pub struct NymNodeDetails {
|
||||
/// Basic bond information of this node, such as owner address, original pledge, etc.
|
||||
pub bond_information: NymNodeBond,
|
||||
@@ -289,19 +288,14 @@ impl NymNodeDetails {
|
||||
}
|
||||
|
||||
#[cw_serde]
|
||||
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
|
||||
pub struct NymNodeBond {
|
||||
/// Unique id assigned to the bonded node.
|
||||
#[cfg_attr(feature = "utoipa", schema(value_type = u32))]
|
||||
pub node_id: NodeId,
|
||||
|
||||
/// Address of the owner of this nym-node.
|
||||
#[cfg_attr(feature = "utoipa", schema(value_type = String))]
|
||||
pub owner: Addr,
|
||||
|
||||
/// Original amount pledged by the operator of this node.
|
||||
|
||||
#[cfg_attr(feature = "utoipa", schema(value_type = crate::CoinSchema))]
|
||||
pub original_pledge: Coin,
|
||||
|
||||
/// Block height at which this nym-node has been bonded.
|
||||
@@ -354,7 +348,6 @@ impl NymNodeBond {
|
||||
feature = "generate-ts",
|
||||
ts(export, export_to = "ts-packages/types/src/types/rust/NymNode.ts")
|
||||
)]
|
||||
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
|
||||
pub struct NymNode {
|
||||
/// Network address of this nym-node, for example 1.1.1.1 or foo.mixnode.com
|
||||
/// that is used to discover other capabilities of this node.
|
||||
@@ -365,7 +358,6 @@ pub struct NymNode {
|
||||
pub custom_http_port: Option<u16>,
|
||||
|
||||
/// Base58-encoded ed25519 EdDSA public key.
|
||||
#[cfg_attr(feature = "utoipa", schema(value_type = String))]
|
||||
pub identity_key: IdentityKey,
|
||||
// TODO: I don't think we want to include sphinx keys here,
|
||||
// given we want to rotate them and keeping that in sync with contract will be a PITA
|
||||
@@ -443,11 +435,8 @@ pub struct NodeConfigUpdate {
|
||||
export_to = "ts-packages/types/src/types/rust/PendingNodeChanges.ts"
|
||||
)
|
||||
)]
|
||||
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
|
||||
pub struct PendingNodeChanges {
|
||||
#[cfg_attr(feature = "utoipa", schema(value_type = Option<u32>))]
|
||||
pub pledge_change: Option<EpochEventId>,
|
||||
#[cfg_attr(feature = "utoipa", schema(value_type = Option<u32>))]
|
||||
pub cost_params_change: Option<IntervalEventId>,
|
||||
}
|
||||
|
||||
|
||||
@@ -21,37 +21,31 @@ pub type WorkFactor = Decimal;
|
||||
)]
|
||||
#[cw_serde]
|
||||
#[derive(Copy)]
|
||||
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
|
||||
pub struct IntervalRewardParams {
|
||||
/// Current value of the rewarding pool.
|
||||
/// It is expected to be constant throughout the interval.
|
||||
#[cfg_attr(feature = "generate-ts", ts(type = "string"))]
|
||||
#[cfg_attr(feature = "utoipa", schema(value_type = String))]
|
||||
pub reward_pool: Decimal,
|
||||
|
||||
/// Current value of the staking supply.
|
||||
/// It is expected to be constant throughout the interval.
|
||||
#[cfg_attr(feature = "generate-ts", ts(type = "string"))]
|
||||
#[cfg_attr(feature = "utoipa", schema(value_type = String))]
|
||||
pub staking_supply: Decimal,
|
||||
|
||||
/// Defines the percentage of stake needed to reach saturation for all of the nodes in the rewarded set.
|
||||
/// Also known as `beta`.
|
||||
#[cfg_attr(feature = "generate-ts", ts(type = "string"))]
|
||||
#[cfg_attr(feature = "utoipa", schema(value_type = String))]
|
||||
pub staking_supply_scale_factor: Percent,
|
||||
|
||||
// computed values
|
||||
/// Current value of the computed reward budget per epoch, per node.
|
||||
/// It is expected to be constant throughout the interval.
|
||||
#[cfg_attr(feature = "generate-ts", ts(type = "string"))]
|
||||
#[cfg_attr(feature = "utoipa", schema(value_type = String))]
|
||||
pub epoch_reward_budget: Decimal,
|
||||
|
||||
/// Current value of the stake saturation point.
|
||||
/// It is expected to be constant throughout the interval.
|
||||
#[cfg_attr(feature = "generate-ts", ts(type = "string"))]
|
||||
#[cfg_attr(feature = "utoipa", schema(value_type = String))]
|
||||
pub stake_saturation_point: Decimal,
|
||||
|
||||
// constants(-ish)
|
||||
@@ -60,7 +54,6 @@ pub struct IntervalRewardParams {
|
||||
/// It is not really expected to be changing very often.
|
||||
/// As a matter of fact, unless there's a very specific reason, it should remain constant.
|
||||
#[cfg_attr(feature = "generate-ts", ts(type = "string"))]
|
||||
#[cfg_attr(feature = "utoipa", schema(value_type = String))]
|
||||
pub sybil_resistance: Percent,
|
||||
|
||||
// default: 10
|
||||
@@ -68,7 +61,6 @@ pub struct IntervalRewardParams {
|
||||
/// It is not really expected to be changing very often.
|
||||
/// As a matter of fact, unless there's a very specific reason, it should remain constant.
|
||||
#[cfg_attr(feature = "generate-ts", ts(type = "string"))]
|
||||
#[cfg_attr(feature = "utoipa", schema(value_type = String))]
|
||||
pub active_set_work_factor: Decimal,
|
||||
|
||||
// default: 2%
|
||||
@@ -78,7 +70,6 @@ pub struct IntervalRewardParams {
|
||||
/// It is not really expected to be changing very often.
|
||||
/// As a matter of fact, unless there's a very specific reason, it should remain constant.
|
||||
#[cfg_attr(feature = "generate-ts", ts(type = "string"))]
|
||||
#[cfg_attr(feature = "utoipa", schema(value_type = String))]
|
||||
pub interval_pool_emission: Percent,
|
||||
}
|
||||
|
||||
@@ -99,7 +90,6 @@ impl IntervalRewardParams {
|
||||
)]
|
||||
#[cw_serde]
|
||||
#[derive(Copy)]
|
||||
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
|
||||
pub struct RewardingParams {
|
||||
/// Parameters that should remain unchanged throughout an interval.
|
||||
pub interval: IntervalRewardParams,
|
||||
@@ -264,7 +254,6 @@ impl RewardingParams {
|
||||
)]
|
||||
#[cw_serde]
|
||||
#[derive(Copy)]
|
||||
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
|
||||
pub struct RewardedSetParams {
|
||||
/// The expected number of nodes assigned entry gateway role (i.e. [`Role::EntryGateway`])
|
||||
pub entry_gateways: u32,
|
||||
|
||||
@@ -17,12 +17,10 @@ pub mod simulator;
|
||||
)]
|
||||
#[cw_serde]
|
||||
#[derive(Copy, Default)]
|
||||
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
|
||||
pub struct RewardEstimate {
|
||||
/// The amount of **decimal** coins that are going to get distributed to the node,
|
||||
/// i.e. the operator and all its delegators.
|
||||
#[cfg_attr(feature = "generate-ts", ts(type = "string"))]
|
||||
#[cfg_attr(feature = "utoipa", schema(value_type = String))]
|
||||
pub total_node_reward: Decimal,
|
||||
|
||||
// note that operator reward includes the operating_cost,
|
||||
@@ -30,17 +28,14 @@ pub struct RewardEstimate {
|
||||
// in that case the operator reward would still be `1nym` as opposed to 0
|
||||
/// The share of the reward that is going to get distributed to the node operator.
|
||||
#[cfg_attr(feature = "generate-ts", ts(type = "string"))]
|
||||
#[cfg_attr(feature = "utoipa", schema(value_type = String))]
|
||||
pub operator: Decimal,
|
||||
|
||||
/// The share of the reward that is going to get distributed among the node delegators.
|
||||
#[cfg_attr(feature = "generate-ts", ts(type = "string"))]
|
||||
#[cfg_attr(feature = "utoipa", schema(value_type = String))]
|
||||
pub delegates: Decimal,
|
||||
|
||||
/// The operating cost of this node. Note: it's already included in the operator reward.
|
||||
#[cfg_attr(feature = "generate-ts", ts(type = "string"))]
|
||||
#[cfg_attr(feature = "utoipa", schema(value_type = String))]
|
||||
pub operating_cost: Decimal,
|
||||
}
|
||||
|
||||
|
||||
@@ -175,14 +175,6 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "utoipa")]
|
||||
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
|
||||
#[cfg_attr(feature = "utoipa", schema(title = "Coin"))]
|
||||
pub struct CoinSchema {
|
||||
pub denom: String,
|
||||
pub amount: String,
|
||||
}
|
||||
|
||||
/// The current state of the mixnet contract.
|
||||
#[cw_serde]
|
||||
pub struct ContractState {
|
||||
|
||||
@@ -16,7 +16,6 @@ serde = { workspace = true, features = ["derive"] }
|
||||
thiserror = { workspace = true }
|
||||
strum = { workspace = true, features = ["derive"] }
|
||||
time = { workspace = true, features = ["serde"] }
|
||||
utoipa = { workspace = true }
|
||||
rand = { workspace = true }
|
||||
|
||||
nym-compact-ecash = { path = "../nym_offline_compact_ecash" }
|
||||
|
||||
@@ -86,6 +86,7 @@ impl Display for AddressPolicyAction {
|
||||
/// ```
|
||||
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
|
||||
#[cfg_attr(feature = "openapi", aliases(ExitPolicy))]
|
||||
pub struct AddressPolicy {
|
||||
/// A list of rules to apply to find out whether an address is
|
||||
/// contained by this policy.
|
||||
@@ -726,10 +727,10 @@ mod test {
|
||||
let policy = AddressPolicy::parse_from_torrc(
|
||||
r#"
|
||||
ExitPolicy reject 1.2.3.4/32:*
|
||||
ExitPolicy reject 1.2.3.5:*
|
||||
ExitPolicy reject 1.2.3.5:*
|
||||
ExitPolicy reject 1.2.3.6/16:*
|
||||
ExitPolicy reject 1.2.3.6/16:123-456
|
||||
ExitPolicy accept *:53
|
||||
ExitPolicy reject 1.2.3.6/16:123-456
|
||||
ExitPolicy accept *:53
|
||||
ExitPolicy accept6 *6:119
|
||||
ExitPolicy accept *4:120
|
||||
ExitPolicy reject6 [FC00::]/7:*
|
||||
|
||||
@@ -10,6 +10,7 @@ use serde::{Deserialize, Serialize};
|
||||
pub mod middleware;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
|
||||
pub enum FormattedResponse<T> {
|
||||
Json(Json<T>),
|
||||
Yaml(Yaml<T>),
|
||||
|
||||
@@ -65,14 +65,6 @@ impl<T> NonExhaustiveDelayQueue<T> {
|
||||
pub fn remove(&mut self, key: &QueueKey) -> Expired<T> {
|
||||
self.inner.remove(key)
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
self.inner.len()
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.inner.is_empty()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Default for NonExhaustiveDelayQueue<T> {
|
||||
|
||||
@@ -12,6 +12,6 @@ license.workspace = true
|
||||
|
||||
[dependencies]
|
||||
prometheus = { workspace = true }
|
||||
tracing = { workspace = true }
|
||||
log = { workspace = true }
|
||||
dashmap = { workspace = true }
|
||||
lazy_static = { workspace = true }
|
||||
|
||||
+81
-390
@@ -1,18 +1,14 @@
|
||||
use dashmap::DashMap;
|
||||
pub use log::error;
|
||||
use log::{debug, warn};
|
||||
use std::fmt;
|
||||
use tracing::{debug, error, warn};
|
||||
|
||||
use prometheus::{
|
||||
core::Collector, Encoder as _, Gauge, Histogram, HistogramOpts, IntCounter, IntGauge, Registry,
|
||||
TextEncoder,
|
||||
};
|
||||
|
||||
pub use prometheus::HistogramTimer;
|
||||
pub use std::time::Instant;
|
||||
|
||||
use prometheus::{core::Collector, Encoder as _, IntCounter, IntGauge, Registry, TextEncoder};
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! prepend_package_name {
|
||||
($name: tt) => {
|
||||
($name: literal) => {
|
||||
&format!(
|
||||
"{}_{}",
|
||||
std::module_path!()
|
||||
@@ -27,29 +23,15 @@ macro_rules! prepend_package_name {
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! inc_by {
|
||||
($name:literal, $x:expr, $help: expr) => {
|
||||
$crate::REGISTRY.maybe_register_and_inc_by(
|
||||
$crate::prepend_package_name!($name),
|
||||
$x as i64,
|
||||
$help,
|
||||
);
|
||||
};
|
||||
($name:literal, $x:expr) => {
|
||||
$crate::REGISTRY.maybe_register_and_inc_by(
|
||||
$crate::prepend_package_name!($name),
|
||||
$x as i64,
|
||||
None,
|
||||
);
|
||||
$crate::REGISTRY.inc_by($crate::prepend_package_name!($name), $x as i64);
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! inc {
|
||||
($name:literal, $help: expr) => {
|
||||
$crate::REGISTRY.maybe_register_and_inc($crate::prepend_package_name!($name), $help);
|
||||
};
|
||||
($name:literal) => {
|
||||
$crate::REGISTRY.maybe_register_and_inc($crate::prepend_package_name!($name), None);
|
||||
$crate::REGISTRY.inc($crate::prepend_package_name!($name));
|
||||
};
|
||||
}
|
||||
|
||||
@@ -60,71 +42,6 @@ macro_rules! metrics {
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! set_metric {
|
||||
($name:literal, $x:expr, $help: expr) => {
|
||||
$crate::REGISTRY.maybe_register_and_set(
|
||||
$crate::prepend_package_name!($name),
|
||||
$x as i64,
|
||||
$help,
|
||||
);
|
||||
};
|
||||
($name:literal, $x:expr) => {
|
||||
$crate::REGISTRY.maybe_register_and_set(
|
||||
$crate::prepend_package_name!($name),
|
||||
$x as i64,
|
||||
None,
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! set_metric_float {
|
||||
($name:literal, $x:expr, $help: expr) => {
|
||||
$crate::REGISTRY.maybe_register_and_set_float(
|
||||
$crate::prepend_package_name!($name),
|
||||
$x as f64,
|
||||
$help,
|
||||
);
|
||||
};
|
||||
($name:literal, $x:expr) => {
|
||||
$crate::REGISTRY.maybe_register_and_set_float(
|
||||
$crate::prepend_package_name!($name),
|
||||
$x as f64,
|
||||
None,
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! add_histogram_obs {
|
||||
($name:expr, $x:expr, $b:expr, $help:expr) => {
|
||||
$crate::REGISTRY.maybe_register_and_add_to_histogram(
|
||||
$crate::prepend_package_name!($name),
|
||||
$x as f64,
|
||||
Some($b),
|
||||
$help,
|
||||
);
|
||||
};
|
||||
|
||||
($name:expr, $x:expr, $b:expr) => {
|
||||
$crate::REGISTRY.maybe_register_and_add_to_histogram(
|
||||
$crate::prepend_package_name!($name),
|
||||
$x as f64,
|
||||
Some($b),
|
||||
None,
|
||||
);
|
||||
};
|
||||
($name:expr, $x:expr) => {
|
||||
$crate::REGISTRY.maybe_register_and_add_to_histogram(
|
||||
$crate::prepend_package_name!($name),
|
||||
$x as f64,
|
||||
None,
|
||||
None,
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! nanos {
|
||||
( $name:literal, $x:expr ) => {{
|
||||
@@ -133,7 +50,7 @@ macro_rules! nanos {
|
||||
let r = $x;
|
||||
let duration = start.elapsed().as_nanos() as i64;
|
||||
let name = $crate::prepend_package_name!($name);
|
||||
$crate::REGISTRY.maybe_register_and_inc_by(&format!("{}_nanos", $name), duration, None);
|
||||
$crate::REGISTRY.inc_by(&format!("{}_nanos", $name), duration);
|
||||
r
|
||||
}};
|
||||
}
|
||||
@@ -142,100 +59,15 @@ lazy_static::lazy_static! {
|
||||
pub static ref REGISTRY: MetricsController = MetricsController::default();
|
||||
}
|
||||
|
||||
pub fn metrics_registry() -> &'static MetricsController {
|
||||
®ISTRY
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct MetricsController {
|
||||
registry: Registry,
|
||||
registry_index: DashMap<String, Metric>,
|
||||
}
|
||||
|
||||
pub enum Metric {
|
||||
IntCounter(Box<IntCounter>),
|
||||
IntGauge(Box<IntGauge>),
|
||||
FloatGauge(Box<Gauge>),
|
||||
Histogram(Box<Histogram>),
|
||||
}
|
||||
|
||||
impl Metric {
|
||||
pub fn new_int_counter(name: &str, help: &str) -> Option<Self> {
|
||||
match IntCounter::new(sanitize_metric_name(name), help) {
|
||||
Ok(c) => Some(c.into()),
|
||||
Err(err) => {
|
||||
error!("Failed to create counter {name:?}: {err}");
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_int_gauge(name: &str, help: &str) -> Option<Self> {
|
||||
match IntGauge::new(sanitize_metric_name(name), help) {
|
||||
Ok(g) => Some(g.into()),
|
||||
Err(err) => {
|
||||
error!("Failed to create gauge {name:?}: {err}");
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_float_gauge(name: &str, help: &str) -> Option<Self> {
|
||||
match Gauge::new(sanitize_metric_name(name), help) {
|
||||
Ok(g) => Some(g.into()),
|
||||
Err(err) => {
|
||||
error!("Failed to create gauge {name:?}: {err}");
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_histogram(name: &str, help: &str, buckets: Option<&[f64]>) -> Option<Self> {
|
||||
let mut opts = HistogramOpts::new(sanitize_metric_name(name), help);
|
||||
if let Some(buckets) = buckets {
|
||||
opts = opts.buckets(buckets.to_vec())
|
||||
}
|
||||
match Histogram::with_opts(opts) {
|
||||
Ok(h) => Some(Metric::Histogram(Box::new(h))),
|
||||
Err(err) => {
|
||||
error!("failed to create histogram {name:?}: {err}");
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn as_collector(&self) -> Box<dyn Collector> {
|
||||
match self {
|
||||
Metric::IntCounter(c) => c.clone(),
|
||||
Metric::IntGauge(g) => g.clone(),
|
||||
Metric::FloatGauge(g) => g.clone(),
|
||||
Metric::Histogram(h) => h.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<IntCounter> for Metric {
|
||||
fn from(v: IntCounter) -> Self {
|
||||
Metric::IntCounter(Box::new(v))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<IntGauge> for Metric {
|
||||
fn from(v: IntGauge) -> Self {
|
||||
Metric::IntGauge(Box::new(v))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Gauge> for Metric {
|
||||
fn from(v: Gauge) -> Self {
|
||||
Metric::FloatGauge(Box::new(v))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Histogram> for Metric {
|
||||
fn from(v: Histogram) -> Self {
|
||||
Metric::Histogram(Box::new(v))
|
||||
}
|
||||
enum Metric {
|
||||
C(Box<IntCounter>),
|
||||
G(Box<IntGauge>),
|
||||
}
|
||||
|
||||
fn fq_name(c: &dyn Collector) -> String {
|
||||
@@ -249,92 +81,34 @@ impl Metric {
|
||||
#[inline(always)]
|
||||
fn fq_name(&self) -> String {
|
||||
match self {
|
||||
Metric::IntCounter(c) => fq_name(c.as_ref()),
|
||||
Metric::IntGauge(g) => fq_name(g.as_ref()),
|
||||
Metric::FloatGauge(g) => fq_name(g.as_ref()),
|
||||
Metric::Histogram(h) => fq_name(h.as_ref()),
|
||||
Metric::C(c) => fq_name(c.as_ref()),
|
||||
Metric::G(g) => fq_name(g.as_ref()),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn inc(&self) {
|
||||
match self {
|
||||
Metric::IntCounter(c) => c.inc(),
|
||||
Metric::IntGauge(g) => g.inc(),
|
||||
Metric::FloatGauge(g) => g.inc(),
|
||||
Metric::Histogram(_) => {
|
||||
warn!("invalid operation: attempted to call increment on a histogram")
|
||||
}
|
||||
Metric::C(c) => c.inc(),
|
||||
Metric::G(g) => g.inc(),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn inc_by(&self, value: i64) {
|
||||
match self {
|
||||
Metric::IntCounter(c) => c.inc_by(value as u64),
|
||||
Metric::IntGauge(g) => g.add(value),
|
||||
Metric::FloatGauge(g) => {
|
||||
warn!("attempted to increment a float gauge ('{}') by an integer - this is most likely a bug", self.fq_name());
|
||||
g.add(value as f64)
|
||||
}
|
||||
Metric::Histogram(_) => {
|
||||
warn!("invalid operation: attempted to call increment on a histogram")
|
||||
}
|
||||
Metric::C(c) => c.inc_by(value as u64),
|
||||
Metric::G(g) => g.add(value),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn set(&self, value: i64) {
|
||||
match self {
|
||||
Metric::IntCounter(_c) => {
|
||||
Metric::C(_c) => {
|
||||
warn!("Cannot set value for counter {:?}", self.fq_name());
|
||||
}
|
||||
Metric::IntGauge(g) => g.set(value),
|
||||
Metric::FloatGauge(g) => {
|
||||
warn!("attempted to set a float gauge ('{}') to an integer value - this is most likely a bug", self.fq_name());
|
||||
g.set(value as f64)
|
||||
}
|
||||
Metric::Histogram(_) => {
|
||||
warn!("invalid operation: attempted to call set on a histogram")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn set_float(&self, value: f64) {
|
||||
match self {
|
||||
Metric::IntCounter(_c) => {
|
||||
warn!("Cannot set value for counter {:?}", self.fq_name());
|
||||
}
|
||||
Metric::IntGauge(g) => {
|
||||
warn!("attempted to set a integer gauge ('{}') to a float value - this is most likely a bug", self.fq_name());
|
||||
g.set(value as i64)
|
||||
}
|
||||
Metric::FloatGauge(g) => g.set(value),
|
||||
Metric::Histogram(_) => {
|
||||
warn!("invalid operation: attempted to call increment on a histogram")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn add_histogram_observation(&self, value: f64) {
|
||||
match self {
|
||||
Metric::Histogram(h) => {
|
||||
h.observe(value);
|
||||
}
|
||||
_ => warn!("attempted to add histogram observation on a non-histogram metric"),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn start_timer(&self) -> Option<HistogramTimer> {
|
||||
match self {
|
||||
Metric::Histogram(h) => Some(h.start_timer()),
|
||||
_ => {
|
||||
warn!("attempted to start histogram observation on a non-histogram metric");
|
||||
None
|
||||
}
|
||||
Metric::G(g) => g.set(value),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -371,165 +145,93 @@ impl MetricsController {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn register_int_gauge<'a>(&self, name: &str, help: impl Into<Option<&'a str>>) {
|
||||
let Some(metric) = Metric::new_int_gauge(name, help.into().unwrap_or(name)) else {
|
||||
return;
|
||||
};
|
||||
self.register_metric(metric);
|
||||
}
|
||||
|
||||
pub fn register_float_gauge<'a>(&self, name: &str, help: impl Into<Option<&'a str>>) {
|
||||
let Some(metric) = Metric::new_float_gauge(name, help.into().unwrap_or(name)) else {
|
||||
return;
|
||||
};
|
||||
self.register_metric(metric);
|
||||
}
|
||||
|
||||
pub fn register_int_counter<'a>(&self, name: &str, help: impl Into<Option<&'a str>>) {
|
||||
let Some(metric) = Metric::new_int_counter(name, help.into().unwrap_or(name)) else {
|
||||
return;
|
||||
};
|
||||
self.register_metric(metric);
|
||||
}
|
||||
|
||||
pub fn register_histogram<'a>(
|
||||
&self,
|
||||
name: &str,
|
||||
help: impl Into<Option<&'a str>>,
|
||||
buckets: Option<&[f64]>,
|
||||
) {
|
||||
let Some(metric) = Metric::new_histogram(name, help.into().unwrap_or(name), buckets) else {
|
||||
return;
|
||||
};
|
||||
self.register_metric(metric);
|
||||
}
|
||||
|
||||
pub fn set(&self, name: &str, value: i64) -> bool {
|
||||
pub fn set(&self, name: &str, value: i64) {
|
||||
if let Some(metric) = self.registry_index.get(name) {
|
||||
metric.set(value);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
let gauge = match IntGauge::new(sanitize_metric_name(name), name) {
|
||||
Ok(g) => g,
|
||||
Err(e) => {
|
||||
debug!("Failed to create gauge {:?}:\n{}", name, e);
|
||||
return;
|
||||
}
|
||||
};
|
||||
self.register_gauge(Box::new(gauge));
|
||||
self.set(name, value)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_float(&self, name: &str, value: f64) -> bool {
|
||||
if let Some(metric) = self.registry_index.get(name) {
|
||||
metric.set_float(value);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_to_histogram(&self, name: &str, value: f64) -> bool {
|
||||
if let Some(metric) = self.registry_index.get(name) {
|
||||
metric.add_histogram_observation(value);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
pub fn start_timer(&self, name: &str) -> Option<HistogramTimer> {
|
||||
self.registry_index
|
||||
.get(name)
|
||||
.and_then(|metric| metric.start_timer())
|
||||
}
|
||||
|
||||
pub fn inc(&self, name: &str) -> bool {
|
||||
pub fn inc(&self, name: &str) {
|
||||
if let Some(metric) = self.registry_index.get(name) {
|
||||
metric.inc();
|
||||
true
|
||||
} else {
|
||||
false
|
||||
let counter = match IntCounter::new(sanitize_metric_name(name), name) {
|
||||
Ok(c) => c,
|
||||
Err(e) => {
|
||||
debug!("Failed to create counter {:?}:\n{}", name, e);
|
||||
return;
|
||||
}
|
||||
};
|
||||
self.register_counter(Box::new(counter));
|
||||
self.inc(name)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn inc_by(&self, name: &str, value: i64) -> bool {
|
||||
pub fn inc_by(&self, name: &str, value: i64) {
|
||||
if let Some(metric) = self.registry_index.get(name) {
|
||||
metric.inc_by(value);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
let counter = match IntCounter::new(sanitize_metric_name(name), name) {
|
||||
Ok(c) => c,
|
||||
Err(e) => {
|
||||
debug!("Failed to create counter {:?}:\n{}", name, e);
|
||||
return;
|
||||
}
|
||||
};
|
||||
self.register_counter(Box::new(counter));
|
||||
self.inc_by(name, value)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn maybe_register_and_set<'a>(
|
||||
&self,
|
||||
name: &str,
|
||||
value: i64,
|
||||
help: impl Into<Option<&'a str>>,
|
||||
) {
|
||||
if !self.set(name, value) {
|
||||
let help = help.into();
|
||||
self.register_int_gauge(name, help);
|
||||
self.set(name, value);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn maybe_register_and_set_float<'a>(
|
||||
&self,
|
||||
name: &str,
|
||||
value: f64,
|
||||
help: impl Into<Option<&'a str>>,
|
||||
) {
|
||||
if !self.set_float(name, value) {
|
||||
let help = help.into();
|
||||
self.register_float_gauge(name, help);
|
||||
self.set_float(name, value);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn maybe_register_and_add_to_histogram<'a>(
|
||||
&self,
|
||||
name: &str,
|
||||
value: f64,
|
||||
buckets: Option<&[f64]>,
|
||||
help: impl Into<Option<&'a str>>,
|
||||
) {
|
||||
if !self.add_to_histogram(name, value) {
|
||||
let help = help.into();
|
||||
self.register_histogram(name, help, buckets);
|
||||
self.add_to_histogram(name, value);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn maybe_register_and_inc<'a>(&self, name: &str, help: impl Into<Option<&'a str>>) {
|
||||
if !self.inc(name) {
|
||||
let help = help.into();
|
||||
self.register_int_counter(name, help);
|
||||
self.inc(name);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn maybe_register_and_inc_by<'a>(
|
||||
&self,
|
||||
name: &str,
|
||||
value: i64,
|
||||
help: impl Into<Option<&'a str>>,
|
||||
) {
|
||||
if !self.inc_by(name, value) {
|
||||
let help = help.into();
|
||||
self.register_int_counter(name, help);
|
||||
self.inc_by(name, value);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn register_metric(&self, metric: impl Into<Metric>) {
|
||||
let m = metric.into();
|
||||
let fq_name = m.fq_name();
|
||||
fn register_gauge(&self, metric: Box<IntGauge>) {
|
||||
let fq_name = metric
|
||||
.desc()
|
||||
.first()
|
||||
.map(|d| d.fq_name.clone())
|
||||
.unwrap_or_default();
|
||||
|
||||
if self.registry_index.contains_key(&fq_name) {
|
||||
return;
|
||||
}
|
||||
|
||||
match self.registry.register(m.as_collector()) {
|
||||
match self.registry.register(metric.clone()) {
|
||||
Ok(_) => {
|
||||
self.registry_index.insert(fq_name, m);
|
||||
self.registry_index
|
||||
.insert(fq_name, Metric::G(metric.clone()));
|
||||
}
|
||||
Err(err) => {
|
||||
debug!("Failed to register '{fq_name}': {err}")
|
||||
Err(e) => {
|
||||
debug!("Failed to register {:?}:\n{}", fq_name, e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn register_counter(&self, metric: Box<IntCounter>) {
|
||||
let fq_name = metric
|
||||
.desc()
|
||||
.first()
|
||||
.map(|d| d.fq_name.clone())
|
||||
.unwrap_or_default();
|
||||
|
||||
if self.registry_index.contains_key(&fq_name) {
|
||||
return;
|
||||
}
|
||||
match self.registry.register(metric.clone()) {
|
||||
Ok(_) => {
|
||||
self.registry_index
|
||||
.insert(fq_name, Metric::C(metric.clone()));
|
||||
}
|
||||
Err(e) => {
|
||||
debug!("Failed to register {:?}:\n{}", fq_name, e)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -573,15 +275,4 @@ mod tests {
|
||||
"packets_sent_34_242_65_133:1789"
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn prepend_package_name() {
|
||||
let literal = prepend_package_name!("foo");
|
||||
assert_eq!(literal, "nym_metrics_foo");
|
||||
|
||||
let bar = "bar";
|
||||
let format = format!("foomp_{}", bar);
|
||||
let formatted = prepend_package_name!(format);
|
||||
assert_eq!(formatted, "nym_metrics_foomp_bar");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,4 +63,4 @@ par_signing = ["rayon"]
|
||||
# but given it's not done very frequently, it shouldn't be too much of a problem
|
||||
# furthermore, we can't and shouldn't dedicate the entire nym-api CPU just for verification,
|
||||
# but this feature might potentially be desirable for clients.
|
||||
par_verify = ["rayon"]
|
||||
par_verify = ["rayon"]
|
||||
@@ -4,10 +4,10 @@
|
||||
use crate::ecash_group_parameters;
|
||||
use crate::error::Result;
|
||||
use crate::helpers::{g1_tuple_to_bytes, recover_g1_tuple};
|
||||
use bls12_381::{G1Projective, Scalar};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use subtle::Choice;
|
||||
|
||||
pub use bls12_381::{G1Projective, G2Projective, Scalar};
|
||||
pub type SignerIndex = u64;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
|
||||
|
||||
@@ -36,7 +36,7 @@ pub mod common_types;
|
||||
pub mod constants;
|
||||
pub mod error;
|
||||
mod helpers;
|
||||
pub mod proofs;
|
||||
mod proofs;
|
||||
pub mod scheme;
|
||||
pub mod tests;
|
||||
mod traits;
|
||||
|
||||
@@ -14,7 +14,6 @@ readme.workspace = true
|
||||
sha2 = { workspace = true }
|
||||
rs_merkle = { workspace = true }
|
||||
schemars = { workspace = true }
|
||||
utoipa = { workspace = true }
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
time = { workspace = true }
|
||||
|
||||
@@ -24,4 +23,4 @@ nym-serde-helpers = { path = "../serde-helpers", features = ["date", "base64", "
|
||||
[dev-dependencies]
|
||||
rand_chacha = { workspace = true }
|
||||
rand = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
@@ -14,18 +14,15 @@ use serde::{Deserialize, Serialize};
|
||||
use sha2::Digest;
|
||||
use std::fmt::{Debug, Formatter};
|
||||
use time::Date;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
// no point in importing the entire contract commons just for this one type
|
||||
pub type DepositId = u32;
|
||||
pub type DKGEpochId = u64;
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, JsonSchema, ToSchema)]
|
||||
#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, JsonSchema)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct IssuedTicketbook {
|
||||
#[schema(value_type = u32)]
|
||||
pub deposit_id: DepositId,
|
||||
#[schema(value_type = u32)]
|
||||
pub epoch_id: DKGEpochId,
|
||||
|
||||
// 96 bytes serialised 'BlindedSignature'
|
||||
@@ -40,11 +37,9 @@ pub struct IssuedTicketbook {
|
||||
|
||||
#[schemars(with = "String")]
|
||||
#[serde(with = "nym_serde_helpers::date")]
|
||||
#[schema(value_type = String)]
|
||||
pub expiration_date: Date,
|
||||
|
||||
#[schemars(with = "String")]
|
||||
#[schema(value_type = String)]
|
||||
pub ticketbook_type: TicketType,
|
||||
}
|
||||
|
||||
@@ -85,7 +80,7 @@ pub struct InsertedMerkleLeaf {
|
||||
pub leaf: MerkleLeaf,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialOrd, PartialEq, Eq, ToSchema)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialOrd, PartialEq, Eq)]
|
||||
pub struct MerkleLeaf {
|
||||
#[schemars(with = "String")]
|
||||
#[serde(with = "nym_serde_helpers::hex")]
|
||||
@@ -167,14 +162,16 @@ impl IssuedTicketbooksMerkleTree {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, JsonSchema, ToSchema)]
|
||||
#[derive(Serialize, Deserialize, JsonSchema)]
|
||||
pub struct IssuedTicketbooksFullMerkleProof {
|
||||
#[schemars(with = "String")]
|
||||
#[serde(with = "inner_proof_base64_serde")]
|
||||
#[schema(value_type = String)]
|
||||
inner_proof: MerkleProof<Sha256>,
|
||||
|
||||
included_leaves: Vec<MerkleLeaf>,
|
||||
|
||||
total_leaves: usize,
|
||||
|
||||
#[schemars(with = "String")]
|
||||
#[serde(with = "nym_serde_helpers::hex")]
|
||||
root: Vec<u8>,
|
||||
|
||||
@@ -22,7 +22,6 @@ strum = { workspace = true, features = ["derive"] }
|
||||
thiserror = { workspace = true }
|
||||
ts-rs = { workspace = true }
|
||||
url = { workspace = true }
|
||||
utoipa = { workspace = true }
|
||||
x25519-dalek = { workspace = true, features = ["static_secrets"] }
|
||||
|
||||
cosmwasm-std = { workspace = true }
|
||||
|
||||
@@ -3,7 +3,6 @@ use nym_mixnet_contract_common::NodeId;
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{collections::HashSet, sync::LazyLock, time::SystemTime};
|
||||
use utoipa::ToSchema;
|
||||
|
||||
static NETWORK_MONITORS: LazyLock<HashSet<String>> = LazyLock::new(|| {
|
||||
let mut nm = HashSet::new();
|
||||
@@ -11,9 +10,8 @@ static NETWORK_MONITORS: LazyLock<HashSet<String>> = LazyLock::new(|| {
|
||||
nm
|
||||
});
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, JsonSchema, Clone, ToSchema)]
|
||||
#[derive(Debug, Serialize, Deserialize, JsonSchema, Clone)]
|
||||
pub struct NodeResult {
|
||||
#[schema(value_type = u32)]
|
||||
pub node_id: NodeId,
|
||||
pub identity: String,
|
||||
pub reliability: u8,
|
||||
@@ -36,7 +34,7 @@ pub enum MonitorResults {
|
||||
Gateway(Vec<NodeResult>),
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, JsonSchema, ToSchema)]
|
||||
#[derive(Serialize, Deserialize, JsonSchema)]
|
||||
pub struct MonitorMessage {
|
||||
results: Vec<NodeResult>,
|
||||
signature: String,
|
||||
|
||||
@@ -95,7 +95,6 @@ allow = [
|
||||
"Apache-2.0",
|
||||
"BSD-2-Clause",
|
||||
"BSD-3-Clause",
|
||||
"BSL-1.0",
|
||||
"ISC",
|
||||
"0BSD",
|
||||
"MPL-2.0",
|
||||
|
||||
@@ -5,7 +5,7 @@ Migrate your `nym-gateway` to `nym-node --mode entry-gateway` or `--mode exit-ga
|
||||
<Steps>
|
||||
###### 1. Move relevant info from `config.toml`
|
||||
```sh
|
||||
./nym-node migrate --config-file ~/.nym/gateways/<ID>/config/config.toml gateway
|
||||
./nym-node migrate --config-file ~/.nym/gateways/<GATEWAY_ID>/config/config.toml gateway
|
||||
```
|
||||
|
||||
###### 2. Initialise with new `nym-node` config chosing one of the options below:
|
||||
@@ -19,6 +19,5 @@ Migrate your `nym-gateway` to `nym-node --mode entry-gateway` or `--mode exit-ga
|
||||
```sh
|
||||
./nym-node run --id <ID> --mode exit-gateway --public-ips "$(curl -4 https://ifconfig.me)" --hostname <HOSTNAME> --http-bind-address 0.0.0.0:8080 --mixnet-bind-address 0.0.0.0:1789 --location <LOCATION> --accept-operator-terms-and-conditions --wireguard-enabled true
|
||||
```
|
||||
|
||||
</Steps>
|
||||
</>
|
||||
|
||||
@@ -1 +1 @@
|
||||
Monday, December 23rd 2024, 11:36:26 UTC
|
||||
Monday, December 9th 2024, 19:43:12 UTC
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
```sh
|
||||
|
||||
Binary Name: nym-api
|
||||
Build Timestamp: 2024-12-18T17:33:13.184930493Z
|
||||
Build Version: 1.1.47
|
||||
Commit SHA: b628a5f8148f74c646915292c8b6dc0a46202a27
|
||||
Commit Date: 2024-12-13T11:49:27.000000000+01:00
|
||||
Build Timestamp: 2024-12-18T10:26:40.905460408Z
|
||||
Build Version: 1.1.46
|
||||
Commit SHA: 62045d76b32265f6a5e6358ab7aebbc827d47dcd
|
||||
Commit Date: 2024-11-26T11:53:05.000000000+01:00
|
||||
Commit Branch: master
|
||||
rustc Version: 1.84.0-nightly
|
||||
rustc Channel: nightly
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
```sh
|
||||
|
||||
Binary Name: nym-client
|
||||
Build Timestamp: 2024-12-18T17:33:13.184930493Z
|
||||
Build Version: 1.1.45
|
||||
Commit SHA: b628a5f8148f74c646915292c8b6dc0a46202a27
|
||||
Commit Date: 2024-12-13T11:49:27.000000000+01:00
|
||||
Build Timestamp: 2024-12-18T10:26:40.905460408Z
|
||||
Build Version: 1.1.44
|
||||
Commit SHA: 62045d76b32265f6a5e6358ab7aebbc827d47dcd
|
||||
Commit Date: 2024-11-26T11:53:05.000000000+01:00
|
||||
Commit Branch: master
|
||||
rustc Version: 1.84.0-nightly
|
||||
rustc Channel: nightly
|
||||
|
||||
@@ -68,16 +68,6 @@ const completion: Fig.Spec = {
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "--stats-reporting-address",
|
||||
description: "Sets the address to report statistics",
|
||||
hidden: true,
|
||||
isRepeatable: true,
|
||||
args: {
|
||||
name: "stats_reporting_address",
|
||||
isOptional: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "--disable-socket",
|
||||
description: "Whether to not start the websocket",
|
||||
@@ -211,16 +201,6 @@ const completion: Fig.Spec = {
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "--stats-reporting-address",
|
||||
description: "Sets the address to report statistics",
|
||||
hidden: true,
|
||||
isRepeatable: true,
|
||||
args: {
|
||||
name: "stats_reporting_address",
|
||||
isOptional: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "--disable-socket",
|
||||
description: "Whether to not start the websocket",
|
||||
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
```sh
|
||||
[2m2024-12-18T17:36:27.004764Z[0m [31mERROR[0m [2mnym-node/src/config/upgrade_helpers.rs[0m[2m:[0m[2m19[0m[2m:[0m Failed to finish upgrade - failed to load config file using path '/home/m/.nym/nym-nodes/default-nym-node/config/config.toml'. detailed message: No such file or directory (os error 2)
|
||||
[2m2024-11-06T12:18:46.723546Z[0m [31mERROR[0m [2mnym-node/src/config/upgrade_helpers.rs[0m[2m:[0m[2m17[0m[2m:[0m Failed to finish upgrade - failed to load config file using path '/home/m/.nym/nym-nodes/default-nym-node/config/config.toml'. detailed message: No such file or directory (os error 2)
|
||||
```
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
```sh
|
||||
|
||||
Binary Name: nym-node
|
||||
Build Timestamp: 2024-12-18T17:33:13.184930493Z
|
||||
Build Version: 1.2.0
|
||||
Commit SHA: b628a5f8148f74c646915292c8b6dc0a46202a27
|
||||
Commit Date: 2024-12-13T11:49:27.000000000+01:00
|
||||
Build Timestamp: 2024-12-18T10:26:40.905460408Z
|
||||
Build Version: 1.1.11
|
||||
Commit SHA: 62045d76b32265f6a5e6358ab7aebbc827d47dcd
|
||||
Commit Date: 2024-11-26T11:53:05.000000000+01:00
|
||||
Commit Branch: master
|
||||
rustc Version: 1.84.0-nightly
|
||||
rustc Channel: nightly
|
||||
|
||||
@@ -1,8 +1,72 @@
|
||||
```sh
|
||||
Attempt to migrate an existing mixnode or gateway into a nym-node
|
||||
|
||||
Usage: nym-node migrate
|
||||
Usage: nym-node migrate [OPTIONS] <--id <ID>|--config-file <CONFIG_FILE>> <NODE_TYPE>
|
||||
|
||||
Arguments:
|
||||
<NODE_TYPE> Type of node (mixnode or gateway) to migrate into a nym-node [possible values: mixnode, gateway]
|
||||
|
||||
Options:
|
||||
-h, --help Print help
|
||||
--id <ID>
|
||||
Id of the node that's going to get migrated
|
||||
--config-file <CONFIG_FILE>
|
||||
Path to a configuration file of the node that's going to get migrated
|
||||
--preserve-id
|
||||
Specify whether to preserve id of the imported node
|
||||
--public-ips <PUBLIC_IPS>
|
||||
Comma separated list of public ip addresses that will be announced to the nym-api and subsequently to the clients. In nearly all circumstances, it's going to be identical to the address you're going to use for bonding [env: NYMNODE_PUBLIC_IPS=]
|
||||
--hostname <HOSTNAME>
|
||||
Optional hostname associated with this gateway that will be announced to the nym-api and subsequently to the clients [env: NYMNODE_HOSTNAME=]
|
||||
--location <LOCATION>
|
||||
Optional **physical** location of this node's server. Either full country name (e.g. 'Poland'), two-letter alpha2 (e.g. 'PL'), three-letter alpha3 (e.g. 'POL') or three-digit numeric-3 (e.g. '616') can be provided [env: NYMNODE_LOCATION=]
|
||||
--http-bind-address <HTTP_BIND_ADDRESS>
|
||||
Socket address this node will use for binding its http API. default: `0.0.0.0:8080` [env: NYMNODE_HTTP_BIND_ADDRESS=]
|
||||
--landing-page-assets-path <LANDING_PAGE_ASSETS_PATH>
|
||||
Path to assets directory of custom landing page of this node [env: NYMNODE_HTTP_LANDING_ASSETS=]
|
||||
--http-access-token <HTTP_ACCESS_TOKEN>
|
||||
An optional bearer token for accessing certain http endpoints. Currently only used for prometheus metrics [env: NYMNODE_HTTP_ACCESS_TOKEN=]
|
||||
--expose-system-info <EXPOSE_SYSTEM_INFO>
|
||||
Specify whether basic system information should be exposed. default: true [env: NYMNODE_HTTP_EXPOSE_SYSTEM_INFO=] [possible values: true, false]
|
||||
--expose-system-hardware <EXPOSE_SYSTEM_HARDWARE>
|
||||
Specify whether basic system hardware information should be exposed. default: true [env: NYMNODE_HTTP_EXPOSE_SYSTEM_HARDWARE=] [possible values: true, false]
|
||||
--expose-crypto-hardware <EXPOSE_CRYPTO_HARDWARE>
|
||||
Specify whether detailed system crypto hardware information should be exposed. default: true [env: NYMNODE_HTTP_EXPOSE_CRYPTO_HARDWARE=] [possible values: true, false]
|
||||
--mixnet-bind-address <MIXNET_BIND_ADDRESS>
|
||||
Address this node will bind to for listening for mixnet packets default: `0.0.0.0:1789` [env: NYMNODE_MIXNET_BIND_ADDRESS=]
|
||||
--mixnet-announce-port <MIXNET_ANNOUNCE_PORT>
|
||||
If applicable, custom port announced in the self-described API that other clients and nodes will use. Useful when the node is behind a proxy [env: NYMNODE_MIXNET_ANNOUNCE_PORT=]
|
||||
--nym-api-urls <NYM_API_URLS>
|
||||
Addresses to nym APIs from which the node gets the view of the network [env: NYMNODE_NYM_APIS=]
|
||||
--nyxd-urls <NYXD_URLS>
|
||||
Addresses to nyxd chain endpoint which the node will use for chain interactions [env: NYMNODE_NYXD=]
|
||||
--wireguard-enabled <WIREGUARD_ENABLED>
|
||||
Specifies whether the wireguard service is enabled on this node [env: NYMNODE_WG_ENABLED=] [possible values: true, false]
|
||||
--wireguard-bind-address <WIREGUARD_BIND_ADDRESS>
|
||||
Socket address this node will use for binding its wireguard interface. default: `0.0.0.0:51822` [env: NYMNODE_WG_BIND_ADDRESS=]
|
||||
--wireguard-private-ip <WIREGUARD_PRIVATE_IP>
|
||||
Private IP address of the wireguard gateway. default: `10.1.0.1` [env: NYMNODE_WG_IP=]
|
||||
--wireguard-announced-port <WIREGUARD_ANNOUNCED_PORT>
|
||||
Port announced to external clients wishing to connect to the wireguard interface. Useful in the instances where the node is behind a proxy [env: NYMNODE_WG_ANNOUNCED_PORT=]
|
||||
--wireguard-private-network-prefix <WIREGUARD_PRIVATE_NETWORK_PREFIX>
|
||||
The prefix denoting the maximum number of the clients that can be connected via Wireguard. The maximum value for IPv4 is 32 and for IPv6 is 128 [env: NYMNODE_WG_PRIVATE_NETWORK_PREFIX=]
|
||||
--verloc-bind-address <VERLOC_BIND_ADDRESS>
|
||||
Socket address this node will use for binding its verloc API. default: `0.0.0.0:1790` [env: NYMNODE_VERLOC_BIND_ADDRESS=]
|
||||
--verloc-announce-port <VERLOC_ANNOUNCE_PORT>
|
||||
If applicable, custom port announced in the self-described API that other clients and nodes will use. Useful when the node is behind a proxy [env: NYMNODE_VERLOC_ANNOUNCE_PORT=]
|
||||
--entry-bind-address <ENTRY_BIND_ADDRESS>
|
||||
Socket address this node will use for binding its client websocket API. default: `0.0.0.0:9000` [env: NYMNODE_ENTRY_BIND_ADDRESS=]
|
||||
--announce-ws-port <ANNOUNCE_WS_PORT>
|
||||
Custom announced port for listening for websocket client traffic. If unspecified, the value from the `bind_address` will be used instead [env: NYMNODE_ENTRY_ANNOUNCE_WS_PORT=]
|
||||
--announce-wss-port <ANNOUNCE_WSS_PORT>
|
||||
If applicable, announced port for listening for secure websocket client traffic [env: NYMNODE_ENTRY_ANNOUNCE_WSS_PORT=]
|
||||
--enforce-zk-nyms <ENFORCE_ZK_NYMS>
|
||||
Indicates whether this gateway is accepting only coconut credentials for accessing the mixnet or if it also accepts non-paying clients [env: NYMNODE_ENFORCE_ZK_NYMS=] [possible values: true, false]
|
||||
--mnemonic <MNEMONIC>
|
||||
Custom cosmos wallet mnemonic used for zk-nym redemption. If no value is provided, a fresh mnemonic is going to be generated [env: NYMNODE_MNEMONIC=]
|
||||
--upstream-exit-policy-url <UPSTREAM_EXIT_POLICY_URL>
|
||||
Specifies the url for an upstream source of the exit policy used by this node [env: NYMNODE_UPSTREAM_EXIT_POLICY=]
|
||||
--open-proxy <OPEN_PROXY>
|
||||
Specifies whether this exit node should run in 'open-proxy' mode and thus would attempt to resolve **ANY** request it receives [env: NYMNODE_OPEN_PROXY=] [possible values: true, false]
|
||||
-h, --help
|
||||
Print help
|
||||
```
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
```sh
|
||||
** Attention **
|
||||
This binary DOES NOT' support migrating from older mixnode/gateway binaries anymore
|
||||
please use an older version instead before attempting to use this binary again.
|
||||
|
||||
```
|
||||
@@ -1,3 +1,3 @@
|
||||
```sh
|
||||
[2m2024-12-18T17:36:27.019221Z[0m [31mERROR[0m [2mnym-node/src/config/upgrade_helpers.rs[0m[2m:[0m[2m19[0m[2m:[0m Failed to finish upgrade - failed to load config file using path '/home/m/.nym/nym-nodes/default-nym-node/config/config.toml'. detailed message: No such file or directory (os error 2)
|
||||
[2m2024-11-06T12:18:46.742880Z[0m [31mERROR[0m [2mnym-node/src/config/upgrade_helpers.rs[0m[2m:[0m[2m17[0m[2m:[0m Failed to finish upgrade - failed to load config file using path '/home/m/.nym/nym-nodes/default-nym-node/config/config.toml'. detailed message: No such file or directory (os error 2)
|
||||
```
|
||||
|
||||
@@ -54,6 +54,8 @@ Options:
|
||||
Specifies whether the wireguard service is enabled on this node [env: NYMNODE_WG_ENABLED=] [possible values: true, false]
|
||||
--wireguard-bind-address <WIREGUARD_BIND_ADDRESS>
|
||||
Socket address this node will use for binding its wireguard interface. default: `0.0.0.0:51822` [env: NYMNODE_WG_BIND_ADDRESS=]
|
||||
--wireguard-private-ip <WIREGUARD_PRIVATE_IP>
|
||||
Private IP address of the wireguard gateway. default: `10.1.0.1` [env: NYMNODE_WG_IP=]
|
||||
--wireguard-announced-port <WIREGUARD_ANNOUNCED_PORT>
|
||||
Port announced to external clients wishing to connect to the wireguard interface. Useful in the instances where the node is behind a proxy [env: NYMNODE_WG_ANNOUNCED_PORT=]
|
||||
--wireguard-private-network-prefix <WIREGUARD_PRIVATE_NETWORK_PREFIX>
|
||||
|
||||
+4
-4
@@ -1,10 +1,10 @@
|
||||
```sh
|
||||
|
||||
Binary Name: nym-socks5-client
|
||||
Build Timestamp: 2024-12-18T17:33:13.184930493Z
|
||||
Build Version: 1.1.45
|
||||
Commit SHA: b628a5f8148f74c646915292c8b6dc0a46202a27
|
||||
Commit Date: 2024-12-13T11:49:27.000000000+01:00
|
||||
Build Timestamp: 2024-12-18T10:26:40.905460408Z
|
||||
Build Version: 1.1.44
|
||||
Commit SHA: 62045d76b32265f6a5e6358ab7aebbc827d47dcd
|
||||
Commit Date: 2024-11-26T11:53:05.000000000+01:00
|
||||
Commit Branch: master
|
||||
rustc Version: 1.84.0-nightly
|
||||
rustc Channel: nightly
|
||||
|
||||
-20
@@ -68,16 +68,6 @@ const completion: Fig.Spec = {
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "--stats-reporting-address",
|
||||
description: "Sets the address to report statistics",
|
||||
hidden: true,
|
||||
isRepeatable: true,
|
||||
args: {
|
||||
name: "stats_reporting_address",
|
||||
isOptional: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "--provider",
|
||||
description: "Address of the socks5 provider to send messages to",
|
||||
@@ -219,16 +209,6 @@ const completion: Fig.Spec = {
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "--stats-reporting-address",
|
||||
description: "Sets the address to report statistics",
|
||||
hidden: true,
|
||||
isRepeatable: true,
|
||||
args: {
|
||||
name: "stats_reporting_address",
|
||||
isOptional: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "--use-anonymous-replies",
|
||||
description: "Specifies whether this client is going to use an anonymous sender tag for communication with the service provider. While this is going to hide its actual address information, it will make the actual communication slower and consume nearly double the bandwidth as it will require sending reply SURBs",
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
```sh
|
||||
|
||||
Binary Name: nymvisor
|
||||
Build Timestamp: 2024-12-18T17:33:13.184930493Z
|
||||
Build Version: 0.1.10
|
||||
Commit SHA: b628a5f8148f74c646915292c8b6dc0a46202a27
|
||||
Commit Date: 2024-12-13T11:49:27.000000000+01:00
|
||||
Build Timestamp: 2024-12-18T10:26:40.905460408Z
|
||||
Build Version: 0.1.9
|
||||
Commit SHA: 62045d76b32265f6a5e6358ab7aebbc827d47dcd
|
||||
Commit Date: 2024-11-26T11:53:05.000000000+01:00
|
||||
Commit Branch: master
|
||||
rustc Version: 1.84.0-nightly
|
||||
rustc Channel: nightly
|
||||
|
||||
Vendored
+1
-1
@@ -2,4 +2,4 @@
|
||||
/// <reference types="next/image-types/global" />
|
||||
|
||||
// NOTE: This file should not be edited
|
||||
// see https://nextjs.org/docs/pages/building-your-application/configuring/typescript for more information.
|
||||
// see https://nextjs.org/docs/basic-features/typescript for more information.
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
> This client can also be utilised via the [Rust SDK](../rust).
|
||||
|
||||
## What is this client for?
|
||||
Many existing applications are able to use either the SOCKS4, SOCKS4A, or SOCKS5 proxy protocols. If you want to send such an application's traffic through the mixnet, you can use the `nym-socks5-client` to bounce network traffic through the Nym network, like this:
|
||||
|
||||
```mermaid
|
||||
@@ -48,3 +49,9 @@ The `nym-socks5-client` allows you to do the following from your local machine:
|
||||
* Send the Sphinx packets through the Nym Network. Packets are shuffled and mixed as they transit the mixnet.
|
||||
|
||||
The `nym-node` then reassembles the original TCP stream using the packets' sequence numbers, and make the intended request. It will then chop up the response into Sphinx packets and send them back through the mixnet to your `nym-socks5-client`. The application will then receive its data, without even noticing that it wasn't talking to a "normal" SOCKS5 proxy!
|
||||
|
||||
## Download or compile socks5 client
|
||||
|
||||
If you are using OSX or a Debian-based operating system, you can download the `nym-socks5-client` binary from our [Github releases page](https://github.com/nymtech/nym/releases).
|
||||
|
||||
If you are using a different operating system, or want to build from source, simply use `cargo build --release` from the root of the Nym monorepo.
|
||||
|
||||
@@ -152,10 +152,10 @@ Example output:
|
||||
```sh
|
||||
|
||||
Binary Name: nym-socks5-client
|
||||
Build Timestamp: 2024-12-18T17:33:13.184930493Z
|
||||
Build Version: 1.1.45
|
||||
Commit SHA: b628a5f8148f74c646915292c8b6dc0a46202a27
|
||||
Commit Date: 2024-12-13T11:49:27.000000000+01:00
|
||||
Build Timestamp: 2024-12-18T10:26:40.905460408Z
|
||||
Build Version: 1.1.44
|
||||
Commit SHA: 62045d76b32265f6a5e6358ab7aebbc827d47dcd
|
||||
Commit Date: 2024-11-26T11:53:05.000000000+01:00
|
||||
Commit Branch: master
|
||||
rustc Version: 1.84.0-nightly
|
||||
rustc Channel: nightly
|
||||
@@ -256,16 +256,6 @@ const completion: Fig.Spec = {
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "--stats-reporting-address",
|
||||
description: "Sets the address to report statistics",
|
||||
hidden: true,
|
||||
isRepeatable: true,
|
||||
args: {
|
||||
name: "stats_reporting_address",
|
||||
isOptional: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "--provider",
|
||||
description: "Address of the socks5 provider to send messages to",
|
||||
@@ -407,16 +397,6 @@ const completion: Fig.Spec = {
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "--stats-reporting-address",
|
||||
description: "Sets the address to report statistics",
|
||||
hidden: true,
|
||||
isRepeatable: true,
|
||||
args: {
|
||||
name: "stats_reporting_address",
|
||||
isOptional: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "--use-anonymous-replies",
|
||||
description: "Specifies whether this client is going to use an anonymous sender tag for communication with the service provider. While this is going to hide its actual address information, it will make the actual communication slower and consume nearly double the bandwidth as it will require sending reply SURBs",
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
# Config
|
||||
|
||||
## Default Config Directories
|
||||
# Configuring your client
|
||||
When you initalise a client instance, a configuration directory will be generated and stored in `$HOME_DIR/.nym/socks5-clients/<client-name>/`.
|
||||
|
||||
```
|
||||
@@ -23,7 +21,7 @@ The `config.toml` file contains client configuration options, while the two `pem
|
||||
|
||||
The generated files contain the client name, public/private keypairs, and gateway address. The name `<client_id>` in the example above is just a local identifier so that you can name your clients.
|
||||
|
||||
## Configuring your client for Docker
|
||||
#### Configuring your client for Docker
|
||||
By default, the native client listens to host `127.0.0.1`. However this can be an issue if you wish to run a client in a Dockerized environment, where it can be convenenient to listen on a different host such as `0.0.0.0`.
|
||||
|
||||
You can set this via the `--host` flag during either the `init` or `run` commands.
|
||||
|
||||
@@ -1,10 +1,4 @@
|
||||
# Client setup
|
||||
|
||||
## Download or compile socks5 client
|
||||
|
||||
If you are using OSX or a Debian-based operating system, you can download the `nym-socks5-client` binary from our [Github releases page](https://github.com/nymtech/nym/releases).
|
||||
|
||||
If you are using a different operating system, or want to build from source, simply use `cargo build --release` from the root of the Nym monorepo.
|
||||
## Viewing command help
|
||||
|
||||
You can check that your binaries are properly compiled with:
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
# Usage
|
||||
# Running the socks5 client
|
||||
|
||||
## Run
|
||||
You can run the initialised client by doing this:
|
||||
|
||||
```
|
||||
@@ -8,6 +7,7 @@ You can run the initialised client by doing this:
|
||||
```
|
||||
|
||||
## Automating your socks5 client with systemd
|
||||
|
||||
Create a service file for the socks5 client at `/etc/systemd/system/nym-socks5-client.service`:
|
||||
|
||||
```ini
|
||||
@@ -38,6 +38,7 @@ systemctl status nym-socks5-client.service
|
||||
```
|
||||
|
||||
## Using your Socks5 Client
|
||||
|
||||
After completing the steps above, your local Socks5 Client will be listening on `localhost:1080` ready to proxy traffic to the Network Requester set as the `--provider` when initialising.
|
||||
|
||||
When trying to connect your app, generally the proxy settings are found in `settings->advanced` or `settings->connection`.
|
||||
@@ -51,6 +52,7 @@ Most wallets and other applications will work basically the same way: find the n
|
||||
In some other applications, this might be written as **localhost:1080** if there's only one proxy entry field.
|
||||
|
||||
## Useful Commands
|
||||
|
||||
**no-banner**
|
||||
|
||||
Adding `--no-banner` startup flag will prevent Nym banner being printed even if run in tty environment.
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
# Webassembly Client
|
||||
|
||||
## Overview
|
||||
The Nym webassembly client allows any webassembly-capable runtime to build and send Sphinx packets to the Nym network, for uses in edge computing and browser-based applications.
|
||||
|
||||
This is currently packaged and distributed for ease of use via the [Nym Typescript SDK library](../typescript). **We imagine most developers will use this client via the SDK for ease.**
|
||||
@@ -8,6 +7,7 @@ This is currently packaged and distributed for ease of use via the [Nym Typescri
|
||||
The webassembly client allows for the easy creation of Sphinx packets from within mobile apps and browser-based client-side apps (including Electron or similar).
|
||||
|
||||
## Building apps with Webassembly Client
|
||||
|
||||
Check out the [Typescript SDK docs](../typescript) for examples of usage.
|
||||
|
||||
## Think about what you're sending!
|
||||
|
||||
@@ -117,10 +117,10 @@ Example output:
|
||||
```sh
|
||||
|
||||
Binary Name: nym-client
|
||||
Build Timestamp: 2024-12-18T17:33:13.184930493Z
|
||||
Build Version: 1.1.45
|
||||
Commit SHA: b628a5f8148f74c646915292c8b6dc0a46202a27
|
||||
Commit Date: 2024-12-13T11:49:27.000000000+01:00
|
||||
Build Timestamp: 2024-12-18T10:26:40.905460408Z
|
||||
Build Version: 1.1.44
|
||||
Commit SHA: 62045d76b32265f6a5e6358ab7aebbc827d47dcd
|
||||
Commit Date: 2024-11-26T11:53:05.000000000+01:00
|
||||
Commit Branch: master
|
||||
rustc Version: 1.84.0-nightly
|
||||
rustc Channel: nightly
|
||||
@@ -221,16 +221,6 @@ const completion: Fig.Spec = {
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "--stats-reporting-address",
|
||||
description: "Sets the address to report statistics",
|
||||
hidden: true,
|
||||
isRepeatable: true,
|
||||
args: {
|
||||
name: "stats_reporting_address",
|
||||
isOptional: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "--disable-socket",
|
||||
description: "Whether to not start the websocket",
|
||||
@@ -364,16 +354,6 @@ const completion: Fig.Spec = {
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "--stats-reporting-address",
|
||||
description: "Sets the address to report statistics",
|
||||
hidden: true,
|
||||
isRepeatable: true,
|
||||
args: {
|
||||
name: "stats_reporting_address",
|
||||
isOptional: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "--disable-socket",
|
||||
description: "Whether to not start the websocket",
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
# Message Queue
|
||||
|
||||
## Sphinx Packet Streams
|
||||
Clients, once connected to the Mixnet, **are always sending traffic into the Mixnet**; as well as the packets that you as a developer are sending from your application logic, they send [cover traffic](../../network/concepts/cover-traffic) at a constant rate defined by a Poisson process. This is part of the network's mitigation of timing attacks.
|
||||
|
||||
There are two constant streams of sphinx packets leaving the client at the rate defined by the Poisson process.
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
# Message-based Paradigm
|
||||
|
||||
## Message Format
|
||||
For the moment, Mixnet clients work assuming they will be piped atomic messages looking something like this:
|
||||
|
||||
```
|
||||
|
||||
@@ -6,7 +6,7 @@ import { GitHubRepoSearch } from '../../code-snippets/mixfetchurl';
|
||||
# Integration Options
|
||||
Developers might want to either integrate a Mixnet client or just to interact with the blockchain. See the relevant section below.
|
||||
|
||||
## Integrating Mixnet Functionality
|
||||
### Integrating Mixnet Functionality
|
||||
There are several options available to developers wanting to embed a Nym client in their application code.
|
||||
|
||||
<Tabs items={['Rust/Go/C++', 'Typescript/Javascript','Other']}>
|
||||
@@ -34,7 +34,8 @@ There are several options available to developers wanting to embed a Nym client
|
||||
<Tabs.Tab> If your app is not written in any of the supported languages, you might still be able to send traffic through a standalone [socks5 client](./clients/socks5) but will have to think about packaging and bundling the client binary with e.g. a `systemd` file for autostart to run the client as a daemon. If you want to discuss FFI options reach out to us via our public dev channel. </Tabs.Tab>
|
||||
</Tabs>
|
||||
|
||||
## Interacting with Nyx
|
||||
### Interacting with Nyx
|
||||
|
||||
If instead of relying on the Mixnet you wish to interact with the Nyx chain, either as a payment processor or to get on-chain events, see [interacting with the chain](./chain).
|
||||
|
||||
> Note that depending on your setup, you might already be able to combine interacting with the chain with using the Mixnet: check the options above for more.
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
"development-status": "Development Status",
|
||||
"mixnet": "Mixnet Module",
|
||||
"tcpproxy": "TcpProxy Module",
|
||||
"client-pool": "Client Pool",
|
||||
"ffi": "FFI",
|
||||
"tutorials": "Tutorials (Coming Soon)"
|
||||
}
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
# Client Pool
|
||||
|
||||
We have a configurable-size Client Pool for processes that require multiple clients in quick succession (this is used by default by the [`TcpProxyClient`](./tcpproxy) for instance)
|
||||
|
||||
This will be useful for developers looking to build connection logic, or just are using raw SDK clients in a sitatuation where there are multiple connections with a lot of churn.
|
||||
|
||||
> You can find this code [here](https://github.com/nymtech/nym/blob/develop/sdk/rust/nym-sdk/examples/client_pool.rs)
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"architecture": "Architecture",
|
||||
"example": "Example"
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
# Client Pool Architecture
|
||||
|
||||
## Motivations
|
||||
In situations where multiple connections are expected, and the number of connections can vary greatly, the Client Pool reduces time spent waiting for the creation of a Mixnet Client blocking your code sending traffic through the Mixnet. Instead, a configurable number of Clients can be generated and run in the background which can be very quickly grabbed, used, and disconnected.
|
||||
|
||||
The Pool can be simply run as a background process for the runtime of your program.
|
||||
|
||||
## Clients & Lifetimes
|
||||
The Client Pool creates **ephemeral Mixnet Clients** which are used and then disconnected. Using the [`TcpProxy`](../tcpproxy) as an example, Clients are used for the lifetime of a single incoming TCP connection; after the TCP connection is closed, the Mixnet client is disconnected.
|
||||
|
||||
Clients are popped from the pool when in use, and another Client is created to take its place. If connections are coming in faster than Clients are replenished, you can instead generate an ephemeral Client on the fly, or wait; this is up to the developer to decide. You can see an example of this logic in the example on the next page.
|
||||
|
||||
## Runtime Loop
|
||||
Aside from a few helper / getter functions and a graceful `disconnect_pool()`, the Client Pool is mostly made up of a very simple loop around some conditional logic making up `start()`:
|
||||
- if the number of Clients in the pool is `< client_pool_reserve_number` (set on `new()`) then create more,
|
||||
- if the number of Clients in the pool `== client_pool_reserve_number` (set on `new()`) then `sleep`,
|
||||
- if `client_pool_reserve_number == 0` just `sleep`.
|
||||
|
||||
`disconnect_pool()` will cause this loop to `break` via cancellation token.
|
||||
@@ -1,100 +0,0 @@
|
||||
# Client Pool Example
|
||||
|
||||
> You can find this code [here](https://github.com/nymtech/nym/blob/develop/sdk/rust/nym-sdk/examples/client_pool.rs)
|
||||
|
||||
```rust
|
||||
use anyhow::Result;
|
||||
use nym_network_defaults::setup_env;
|
||||
use nym_sdk::client_pool::ClientPool;
|
||||
use nym_sdk::mixnet::{MixnetClientBuilder, NymNetworkDetails};
|
||||
use tokio::signal::ctrl_c;
|
||||
|
||||
// This client pool is used internally by the TcpProxyClient but can also be used by the Mixnet module, in case you're quickly swapping clients in and out but won't want to use the TcpProxy module.
|
||||
//
|
||||
// Run with: cargo run --example client_pool -- ../../../envs/<NETWORK>.env
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<()> {
|
||||
nym_bin_common::logging::setup_logging();
|
||||
setup_env(std::env::args().nth(1));
|
||||
|
||||
let conn_pool = ClientPool::new(2); // Start the Client Pool with 2 Clients always being kept in reserve
|
||||
let client_maker = conn_pool.clone();
|
||||
tokio::spawn(async move {
|
||||
client_maker.start().await?;
|
||||
Ok::<(), anyhow::Error>(())
|
||||
});
|
||||
|
||||
println!("\n\nWaiting a few seconds to fill pool\n\n");
|
||||
tokio::time::sleep(tokio::time::Duration::from_secs(10)).await;
|
||||
|
||||
let pool_clone_one = conn_pool.clone();
|
||||
let pool_clone_two = conn_pool.clone();
|
||||
|
||||
tokio::spawn(async move {
|
||||
let client_one = match pool_clone_one.get_mixnet_client().await {
|
||||
Some(client) => {
|
||||
println!("Grabbed client {} from pool", client.nym_address());
|
||||
client
|
||||
}
|
||||
None => {
|
||||
println!("Not enough clients in pool, creating ephemeral client");
|
||||
let net = NymNetworkDetails::new_from_env();
|
||||
let client = MixnetClientBuilder::new_ephemeral()
|
||||
.network_details(net)
|
||||
.build()?
|
||||
.connect_to_mixnet()
|
||||
.await?;
|
||||
println!(
|
||||
"Using {} for the moment, created outside of the connection pool",
|
||||
client.nym_address()
|
||||
);
|
||||
client
|
||||
}
|
||||
};
|
||||
let our_address = client_one.nym_address();
|
||||
println!("\n\nClient 1: {our_address}\n\n");
|
||||
client_one.disconnect().await;
|
||||
tokio::time::sleep(tokio::time::Duration::from_secs(10)).await; // Emulate doing something
|
||||
return Ok::<(), anyhow::Error>(());
|
||||
});
|
||||
|
||||
tokio::spawn(async move {
|
||||
let client_two = match pool_clone_two.get_mixnet_client().await {
|
||||
Some(client) => {
|
||||
println!("Grabbed client {} from pool", client.nym_address());
|
||||
client
|
||||
}
|
||||
None => {
|
||||
println!("Not enough clients in pool, creating ephemeral client");
|
||||
let net = NymNetworkDetails::new_from_env();
|
||||
let client = MixnetClientBuilder::new_ephemeral()
|
||||
.network_details(net)
|
||||
.build()?
|
||||
.connect_to_mixnet()
|
||||
.await?;
|
||||
println!(
|
||||
"Using {} for the moment, created outside of the connection pool",
|
||||
client.nym_address()
|
||||
);
|
||||
client
|
||||
}
|
||||
};
|
||||
let our_address = *client_two.nym_address();
|
||||
println!("\n\nClient 2: {our_address}\n\n");
|
||||
client_two.disconnect().await;
|
||||
tokio::time::sleep(tokio::time::Duration::from_secs(10)).await; // Emulate doing something
|
||||
return Ok::<(), anyhow::Error>(());
|
||||
});
|
||||
|
||||
wait_for_ctrl_c(conn_pool).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn wait_for_ctrl_c(pool: ClientPool) -> Result<()> {
|
||||
println!("\n\nPress CTRL_C to disconnect pool\n\n");
|
||||
ctrl_c().await?;
|
||||
println!("CTRL_C received. Killing client pool");
|
||||
pool.disconnect_pool().await;
|
||||
Ok(())
|
||||
}
|
||||
```
|
||||
@@ -7,12 +7,9 @@ In the future the SDK will be made up of several modules, each of which will all
|
||||
|-----------|---------------------------------------------------------------------------------------|----------|
|
||||
| Mixnet | Create / load clients & keypairs, subscribe to Mixnet events, send & receive messages | ✔️ |
|
||||
| TcpProxy | Utilise the TcpProxyClient and TcpProxyServer abstractions for streaming | ✔️ |
|
||||
| ClientPool| Create a pool of quickly useable Mixnet clients | ✔️ |
|
||||
| Ecash | Create & verify Ecash credentials | ❌ |
|
||||
| Validator | Sign & broadcast Nyx blockchain transactions, query the blockchain | ❌ |
|
||||
|
||||
The `Mixnet` module currently exposes the logic of two clients: the [websocket client](../clients/websocket), and the [socks client](../clients/socks5).
|
||||
|
||||
The `TcpProxy` module exposes functionality to set up client/server instances that expose a localhost TcpSocket to read/write to.
|
||||
|
||||
The `ClientPool` is a configurable pool of ephemeral clients which can be created as a background process and quickly grabbed.
|
||||
|
||||
@@ -22,7 +22,7 @@ The main functionality of exposed functions will be imported from `sdk/ffi/share
|
||||
|
||||
Furthermore, the `shared/` code makes sure that client access is thread-safe, and that client actions happen in blocking threads on the Rust side of the FFI boundary.
|
||||
|
||||
## Mixnet Module
|
||||
### Mixnet Module
|
||||
This is the basic mixnet component of the SDK, exposing client functionality with which people can build custom interfaces with the Mixnet. These functions are exposed to both Go and C/C++ via the `sdk/ffi/shared/` crate.
|
||||
|
||||
| `shared/lib.rs` function | Rust Function |
|
||||
@@ -36,13 +36,13 @@ This is the basic mixnet component of the SDK, exposing client functionality wit
|
||||
|
||||
> We have also implemented `listen_for_incoming_internal()` which is a wrapper around the Mixnet client's `wait_for_messages()`. This is a helper method for listening out for and handling incoming messages.
|
||||
|
||||
### Currently Unsupported Functionality
|
||||
#### Currently Unsupported Functionality
|
||||
At the time of writing the following functionality is not exposed to the shared FFI library:
|
||||
- `split_sender()`: the ability to [split a client into sender and receiver](./mixnet/examples/split-send) for concurrent send/receive.
|
||||
- The use of [custom network topologies](./mixnet/examples/custom-topology).
|
||||
- `Socks5::new()`: creation and use of the [socks5/4a/4 proxy client](./mixnet/examples/socks).
|
||||
|
||||
## TcpProxy Module
|
||||
### TcpProxy Module
|
||||
A connection abstraction which exposes a local TCP socket which developers are able to interact with basically as expected, being able to read/write to/from a bytestream, without really having to take into account the workings of the Mixnet/Sphinx/the [message-based](../concepts/messages) format of the underlying client.
|
||||
|
||||
<Callout type="info" emoji="ℹ️">
|
||||
@@ -58,6 +58,3 @@ A connection abstraction which exposes a local TCP socket which developers are a
|
||||
| `proxy_server_new_internal(upstream_address: &str, config_dir: &str, env: Option<String>)` | `NymProxyServer::new(upstream_address, config_dir, env)` |
|
||||
| `proxy_server_run_internal()` | `NymProxyServer.run_with_shutdown()` |
|
||||
| `proxy_server_address_internal()` | `NymProxyServer.nym_address()` |
|
||||
|
||||
## Client Pool
|
||||
There are currently no FFI bindings for the Client Pool. This will be coming in the future. The bindings for the TcpProxy have been updated to be able to use the Client Pool under the hood, but the standalone Pool is not yet exposed to FFI.
|
||||
|
||||
@@ -112,6 +112,3 @@ Whether the `data` of a SURB request being empty is a feature or a bug is to be
|
||||
You can find a few helper functions [here](./message-helpers.md) to help deal with this issue in the meantime.
|
||||
|
||||
> If you can think of a more succinct or different way of handling this do reach out - we're happy to hear other opinions
|
||||
|
||||
## Lots of `duplicate fragment received` messages
|
||||
You might see a lot of `WARN` level logs about duplicate fragments in your logs, depending on the log level you're using. This occurs when a packet is retransmitted somewhere in the Mixnet, but then the original makes it to the destination client as well. This is not something to do with your client logic, but instead the state of the Mixnet.
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
{
|
||||
"architecture": "Architecture",
|
||||
"examples": "Examples",
|
||||
"troubleshooting": "Troubleshooting"
|
||||
"examples": "Examples"
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ The motivation behind the creation of the `TcpProxy` module is to allow develope
|
||||
|
||||
## Clients
|
||||
Each of the sub-modules exposed by the `TcpProxy` deal with Nym clients in a different way.
|
||||
- the `NymProxyClient` relies on the [`Client Pool`](../client-pool) to create clients and keep a certain number of them in reserve. If the amount of incoming TCP connections rises quicker than the Client Pool can create clients, or you have the pool size set to `0`, the `TcpProxyClient` creates an ephemeral client per new TCP connection, which is closed according to the configurable timeout: we map one ephemeral client per TCP connection. This is to deal with multiple simultaneous streams.
|
||||
- the `NymProxyClient` creates an ephemeral client per new TCP connection, which is closed according to the configurable timeout: we map one ephemeral client per TCP connection. This is to deal with multiple simultaneous streams. In the future, this will be superceded by a connection pool in order to speed up new connections.
|
||||
- the `NymProxyServer` has a single Nym client with a persistent identity.
|
||||
|
||||
## Framing
|
||||
|
||||
@@ -18,8 +18,6 @@ use tokio::net::TcpStream;
|
||||
use tokio::signal;
|
||||
use tokio_stream::StreamExt;
|
||||
use tokio_util::codec;
|
||||
use tokio_util::sync::CancellationToken;
|
||||
use tracing_subscriber::{fmt, prelude::*, EnvFilter};
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
struct ExampleMessage {
|
||||
@@ -28,8 +26,6 @@ struct ExampleMessage {
|
||||
tcp_conn: i8,
|
||||
}
|
||||
|
||||
// This example just starts off a bunch of Tcp connections on a loop to a remote endpoint: in this case the TcpListener behind the NymProxyServer instance on the echo server found in `nym/tools/echo-server/`. It pipes a few messages to it, logs the replies, and keeps track of the number of replies received per connection.
|
||||
//
|
||||
// To run:
|
||||
// - run the echo server with `cargo run`
|
||||
// - run this example with `cargo run --example tcp_proxy_multistream -- <ECHO_SERVER_NYM_ADDRESS> <ENV_FILE_PATH> <CLIENT_PORT>` e.g.
|
||||
@@ -44,13 +40,8 @@ async fn main() -> anyhow::Result<()> {
|
||||
// Nym client logging is very informative but quite verbose.
|
||||
// The Message Decay related logging gives you an ideas of the internals of the proxy message ordering: you need to switch
|
||||
// to DEBUG to see the contents of the msg buffer, sphinx packet chunking, etc.
|
||||
tracing_subscriber::registry()
|
||||
.with(fmt::layer())
|
||||
.with(
|
||||
EnvFilter::new("info")
|
||||
.add_directive("nym_sdk::client_pool=info".parse().unwrap())
|
||||
.add_directive("nym_sdk::tcp_proxy_client=debug".parse().unwrap()),
|
||||
)
|
||||
tracing_subscriber::fmt()
|
||||
.with_max_level(tracing::Level::INFO)
|
||||
.init();
|
||||
|
||||
let env_path = env::args().nth(2).expect("Env file not specified");
|
||||
@@ -58,42 +49,23 @@ async fn main() -> anyhow::Result<()> {
|
||||
|
||||
let listen_port = env::args().nth(3).expect("Port not specified");
|
||||
|
||||
// Within the TcpProxyClient, individual client shutdown is triggered by the timeout. The final argument is how many clients to keep in reserve in the client pool when running the TcpProxy.
|
||||
// Within the TcpProxyClient, individual client shutdown is triggered by the timeout.
|
||||
let proxy_client =
|
||||
tcp_proxy::NymProxyClient::new(server, "127.0.0.1", &listen_port, 45, Some(env), 2).await?;
|
||||
|
||||
// For our disconnect() logic below
|
||||
let proxy_clone = proxy_client.clone();
|
||||
tcp_proxy::NymProxyClient::new(server, "127.0.0.1", &listen_port, 45, Some(env)).await?;
|
||||
|
||||
tokio::spawn(async move {
|
||||
proxy_client.run().await?;
|
||||
Ok::<(), anyhow::Error>(())
|
||||
});
|
||||
|
||||
let example_cancel_token = CancellationToken::new();
|
||||
let client_cancel_token = example_cancel_token.clone();
|
||||
let watcher_cancel_token = example_cancel_token.clone();
|
||||
|
||||
// Cancel listener thread
|
||||
tokio::spawn(async move {
|
||||
signal::ctrl_c().await?;
|
||||
println!(":: CTRL_C received, shutting down + cleanup up proxy server config files");
|
||||
watcher_cancel_token.cancel();
|
||||
proxy_clone.disconnect().await;
|
||||
Ok::<(), anyhow::Error>(())
|
||||
});
|
||||
|
||||
println!("waiting for everything to be set up..");
|
||||
tokio::time::sleep(tokio::time::Duration::from_secs(5)).await;
|
||||
println!("done. sending bytes");
|
||||
|
||||
// In the info traces you will see the different session IDs being set up, one for each TcpStream.
|
||||
for i in 0..8 {
|
||||
let client_cancel_inner_token = client_cancel_token.clone();
|
||||
if client_cancel_token.is_cancelled() {
|
||||
break;
|
||||
}
|
||||
for i in 0..4 {
|
||||
let conn_id = i;
|
||||
println!("Starting TCP connection {}", conn_id);
|
||||
let local_tcp_addr = format!("127.0.0.1:{}", listen_port.clone());
|
||||
tokio::spawn(async move {
|
||||
// Now the client and server proxies are running we can create and pipe traffic to/from
|
||||
@@ -109,10 +81,7 @@ async fn main() -> anyhow::Result<()> {
|
||||
|
||||
// Lets just send a bunch of messages to the server with variable delays between them, with a message and tcp connection ids to keep track of ordering on the server side (for illustrative purposes **only**; keeping track of anonymous replies is handled by the proxy under the hood with Single Use Reply Blocks (SURBs); for this illustration we want some kind of app-level message id, but irl most of the time you'll probably be parsing on e.g. the incoming response type instead)
|
||||
tokio::spawn(async move {
|
||||
for i in 0..8 {
|
||||
if client_cancel_inner_token.is_cancelled() {
|
||||
break;
|
||||
}
|
||||
for i in 0..4 {
|
||||
let mut rng = SmallRng::from_entropy();
|
||||
let delay: f64 = rng.gen_range(2.5..5.0);
|
||||
tokio::time::sleep(tokio::time::Duration::from_secs_f64(delay)).await;
|
||||
@@ -127,7 +96,12 @@ async fn main() -> anyhow::Result<()> {
|
||||
.write_all(&serialised)
|
||||
.await
|
||||
.expect("couldn't write to stream");
|
||||
println!(">> client sent msg {} on conn {}", &i, &conn_id);
|
||||
println!(
|
||||
">> client sent {}: {} bytes on conn {}",
|
||||
&i,
|
||||
msg.message_bytes.len(),
|
||||
&conn_id
|
||||
);
|
||||
}
|
||||
Ok::<(), anyhow::Error>(())
|
||||
});
|
||||
@@ -139,8 +113,17 @@ async fn main() -> anyhow::Result<()> {
|
||||
while let Some(Ok(bytes)) = framed_read.next().await {
|
||||
match bincode::deserialize::<ExampleMessage>(&bytes) {
|
||||
Ok(msg) => {
|
||||
println!(
|
||||
"<< client received {}: {} bytes on conn {}",
|
||||
msg.message_id,
|
||||
msg.message_bytes.len(),
|
||||
msg.tcp_conn
|
||||
);
|
||||
reply_counter += 1;
|
||||
println!("<< conn {} received {}/8", msg.tcp_conn, reply_counter);
|
||||
println!(
|
||||
"tcp connection {} replies received {}/4",
|
||||
msg.tcp_conn, reply_counter
|
||||
);
|
||||
}
|
||||
Err(e) => {
|
||||
println!("<< client received something that wasn't an example message of {} bytes. error: {}", bytes.len(), e);
|
||||
@@ -155,12 +138,15 @@ async fn main() -> anyhow::Result<()> {
|
||||
tokio::time::sleep(tokio::time::Duration::from_secs_f64(delay)).await;
|
||||
}
|
||||
|
||||
// Once timeout is passed, you can either wait for graceful shutdown or just hard stop it.
|
||||
signal::ctrl_c().await?;
|
||||
println!("CTRL+C received, shutting down");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// emulate a series of small messages followed by a closing larger one
|
||||
fn gen_bytes_fixed(i: usize) -> Vec<u8> {
|
||||
let amounts = [10, 15, 50, 1000, 10, 15, 500, 2000];
|
||||
let amounts = [10, 15, 50, 1000];
|
||||
let len = amounts[i];
|
||||
let mut rng = rand::thread_rng();
|
||||
(0..len).map(|_| rng.gen::<u8>()).collect()
|
||||
|
||||
@@ -21,8 +21,6 @@ use tokio::net::{TcpListener, TcpStream};
|
||||
use tokio::signal;
|
||||
use tokio_stream::StreamExt;
|
||||
use tokio_util::codec;
|
||||
use tokio_util::sync::CancellationToken;
|
||||
use tracing_subscriber::{fmt, prelude::*, EnvFilter};
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
struct ExampleMessage {
|
||||
@@ -30,14 +28,7 @@ struct ExampleMessage {
|
||||
message_bytes: Vec<u8>,
|
||||
}
|
||||
|
||||
// This is a basic example which opens a single TCP connection and writes a bunch of messages between a client and an echo
|
||||
// server, so only uses a single session under the hood and doesn't really show off the message ordering capabilities; this is mainly
|
||||
// just a quick introductory illustration on how:
|
||||
// - the mixnet does message ordering
|
||||
// - the NymProxyClient and NymProxyServer can be hooked into and used to communicate between two otherwise pretty vanilla TcpStreams
|
||||
//
|
||||
// For a more irl example checkout tcp_proxy_multistream.rs
|
||||
//
|
||||
|
||||
// Run this with:
|
||||
// `cargo run --example tcp_proxy_single_connection <SERVER_LISTEN_PORT> <ENV_FILE_PATH> <CLIENT_LISTEN_PATH>` e.g.
|
||||
// `cargo run --example tcp_proxy_single_connection 8081 ../../../envs/canary.env 8080 `
|
||||
@@ -48,9 +39,8 @@ async fn main() -> anyhow::Result<()> {
|
||||
|
||||
// Comment this out to just see println! statements from this example, as Nym client logging is very informative but quite verbose.
|
||||
// The Message Decay related logging gives you an ideas of the internals of the proxy message ordering. To see the contents of the msg buffer, sphinx packet chunking, etc change the tracing::Level to DEBUG.
|
||||
tracing_subscriber::registry()
|
||||
.with(fmt::layer())
|
||||
.with(EnvFilter::new("nym_sdk::tcp_proxy=info"))
|
||||
tracing_subscriber::fmt()
|
||||
.with_max_level(tracing::Level::INFO)
|
||||
.init();
|
||||
|
||||
let server_port = env::args()
|
||||
@@ -73,14 +63,10 @@ async fn main() -> anyhow::Result<()> {
|
||||
|
||||
// We'll run the instance with a long timeout since we're sending everything down the same Tcp connection, so should be using a single session.
|
||||
// Within the TcpProxyClient, individual client shutdown is triggered by the timeout.
|
||||
// The final argument is how many clients to keep in reserve in the client pool when running the TcpProxy.
|
||||
let proxy_client =
|
||||
tcp_proxy::NymProxyClient::new(*proxy_nym_addr, "127.0.0.1", &client_port, 5, Some(env), 1)
|
||||
tcp_proxy::NymProxyClient::new(*proxy_nym_addr, "127.0.0.1", &client_port, 60, Some(env))
|
||||
.await?;
|
||||
|
||||
// For our disconnect() logic below
|
||||
let proxy_clone = proxy_client.clone();
|
||||
|
||||
tokio::spawn(async move {
|
||||
proxy_server.run_with_shutdown().await?;
|
||||
Ok::<(), anyhow::Error>(())
|
||||
@@ -91,28 +77,10 @@ async fn main() -> anyhow::Result<()> {
|
||||
Ok::<(), anyhow::Error>(())
|
||||
});
|
||||
|
||||
let example_cancel_token = CancellationToken::new();
|
||||
let server_cancel_token = example_cancel_token.clone();
|
||||
let client_cancel_token = example_cancel_token.clone();
|
||||
let watcher_cancel_token = example_cancel_token.clone();
|
||||
|
||||
// Cancel listener thread
|
||||
tokio::spawn(async move {
|
||||
signal::ctrl_c().await?;
|
||||
println!(":: CTRL_C received, shutting down + cleanup up proxy server config files");
|
||||
fs::remove_dir_all(conf_path)?;
|
||||
watcher_cancel_token.cancel();
|
||||
proxy_clone.disconnect().await;
|
||||
Ok::<(), anyhow::Error>(())
|
||||
});
|
||||
|
||||
// 'Server side' thread: echo back incoming as response to the messages sent in the 'client side' thread below
|
||||
tokio::spawn(async move {
|
||||
let listener = TcpListener::bind(upstream_tcp_addr).await?;
|
||||
loop {
|
||||
if server_cancel_token.is_cancelled() {
|
||||
break;
|
||||
}
|
||||
let (socket, _) = listener.accept().await.unwrap();
|
||||
let (read, mut write) = socket.into_split();
|
||||
let codec = codec::BytesCodec::new();
|
||||
@@ -150,9 +118,9 @@ async fn main() -> anyhow::Result<()> {
|
||||
Ok::<(), anyhow::Error>(())
|
||||
});
|
||||
|
||||
// Just wait for Nym clients to connect, TCP clients to bind, etc. If there isn't a client in the pool (or you started it with 0) already then the TcpProxyClient just spins up an ephemeral client itself.
|
||||
// Just wait for Nym clients to connect, TCP clients to bind, etc.
|
||||
println!("waiting for everything to be set up..");
|
||||
tokio::time::sleep(tokio::time::Duration::from_secs(10)).await;
|
||||
tokio::time::sleep(tokio::time::Duration::from_secs(5)).await;
|
||||
println!("done. sending bytes");
|
||||
|
||||
// Now the client and server proxies are running we can create and pipe traffic to/from
|
||||
@@ -172,9 +140,6 @@ async fn main() -> anyhow::Result<()> {
|
||||
tokio::spawn(async move {
|
||||
let mut rng = SmallRng::from_entropy();
|
||||
for i in 0..10 {
|
||||
if client_cancel_token.is_cancelled() {
|
||||
break;
|
||||
}
|
||||
let random_bytes = gen_bytes_fixed(i as usize);
|
||||
let msg = ExampleMessage {
|
||||
message_id: i,
|
||||
@@ -214,12 +179,15 @@ async fn main() -> anyhow::Result<()> {
|
||||
}
|
||||
}
|
||||
|
||||
// Once timeout is passed, you can either wait for graceful shutdown or just hard stop it.
|
||||
signal::ctrl_c().await?;
|
||||
println!(":: CTRL+C received, shutting down + cleanup up proxy server config files");
|
||||
fs::remove_dir_all(conf_path)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn gen_bytes_fixed(i: usize) -> Vec<u8> {
|
||||
// let amounts = vec![1, 10, 50, 100, 150, 200, 350, 500, 750, 1000];
|
||||
let amounts = [158, 1088, 505, 1001, 150, 200, 3500, 500, 750, 100];
|
||||
let amounts = vec![1, 10, 50, 100, 150, 200, 350, 500, 750, 1000];
|
||||
let len = amounts[i];
|
||||
let mut rng = rand::thread_rng();
|
||||
(0..len).map(|_| rng.gen::<u8>()).collect()
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
# Troubleshooting
|
||||
|
||||
## Lots of `duplicate fragment received` messages
|
||||
You might see a lot of `WARN` level logs about duplicate fragments in your logs, depending on the log level you're using. This occurs when a packet is retransmitted somewhere in the Mixnet, but then the original makes it to the destination client as well. This is not something to do with your client logic, but instead the state of the Mixnet.
|
||||
@@ -1,8 +1,34 @@
|
||||
# Nym-CLI
|
||||
|
||||
## What is this tool for?
|
||||
This is a CLI tool for interacting with:
|
||||
|
||||
* the Nyx blockchain (account management, querying the chain state, etc)
|
||||
* the smart contracts deployed on Nyx (bonding and un-bonding mixnodes, collecting rewards, etc)
|
||||
|
||||
It provides a convenient wrapper around the `nymd` client, and has similar functionality to the `nyxd` binary for querying the chain or executing smart contract methods.
|
||||
|
||||
## Building
|
||||
The `nym-cli` binary can be built by running `cargo build --release` in the `nym/tools/nym-cli` directory.
|
||||
|
||||
## Usage
|
||||
See the [commands](./nym-cli/commands.mdx) page for an overview of all command options.
|
||||
|
||||
### Staking on someone's behalf (for custodians)
|
||||
|
||||
There is a limitation the staking address can only perform the following actions (and are visible via the Nym Wallet:
|
||||
|
||||
- Bond on the gateway's or mix node's behalf.
|
||||
- Delegate or Un-delegate (to a mix node in order to begin receiving rewards)
|
||||
- Claiming the rewards on the account
|
||||
|
||||
```admonish note title=""
|
||||
The staking address has no ability to withdraw any coins from the parent's account.
|
||||
```
|
||||
|
||||
The staking address must maintain the same level of security as the parent mnemonic; while the parent mnemonic's delegations and bonding events will be visible to the parent owner, the staking address will be the only account capable of undoing the bonding and delegating from the mix nodes or gateway.
|
||||
|
||||
Query for staking on behalf of someone else
|
||||
```
|
||||
./nym-cli --mnemonic <staking address mnemonic> mixnet delegators delegate --mix-id <input> --identity-key <input> --amount <input>
|
||||
```
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"usage": "Usage",
|
||||
"commands": "Commands"
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
# Usage
|
||||
|
||||
## Building
|
||||
The `nym-cli` binary can be built by running `cargo build --release` in the `nym/tools/nym-cli` directory.
|
||||
|
||||
## Usage
|
||||
See the [commands](./nym-cli/commands.mdx) page for an overview of all command options.
|
||||
|
||||
## Staking on someone's behalf (for custodians)
|
||||
|
||||
There is a limitation the staking address can only perform the following actions (and are visible via the Nym Wallet:
|
||||
|
||||
- Bond on the gateway's or mix node's behalf.
|
||||
- Delegate or Un-delegate (to a mix node in order to begin receiving rewards)
|
||||
- Claiming the rewards on the account
|
||||
|
||||
```admonish note title=""
|
||||
The staking address has no ability to withdraw any coins from the parent's account.
|
||||
```
|
||||
|
||||
The staking address must maintain the same level of security as the parent mnemonic; while the parent mnemonic's delegations and bonding events will be visible to the parent owner, the staking address will be the only account capable of undoing the bonding and delegating from the mix nodes or gateway.
|
||||
|
||||
Query for staking on behalf of someone else
|
||||
```
|
||||
./nym-cli --mnemonic <staking address mnemonic> mixnet delegators delegate --mix-id <input> --identity-key <input> --amount <input>
|
||||
```
|
||||
@@ -39,8 +39,6 @@ Options:
|
||||
Listen port [default: 8080]
|
||||
-e, --env-path <ENV_PATH>
|
||||
Optional env filepath - if none is supplied then the proxy defaults to using mainnet else just use a path to one of the supplied files in envs/ e.g. ./envs/sandbox.env
|
||||
--client-pool-reserve <CLIENT_POOL_RESERVE>
|
||||
How many clients to have running in reserve for quick access by incoming connections [default: 2]
|
||||
-h, --help
|
||||
Print help
|
||||
```
|
||||
|
||||
@@ -168,24 +168,19 @@ In such case, you can `run` a node to initalise it or try if everything works, b
|
||||
### Migrate
|
||||
|
||||
<Callout type="warning">
|
||||
**Legacy binaries `nym-mixnode` and `nym-gateway` had been deprecated, [`nym-node`](../nym-node.mdx) is the only binary to use for `gateway` or `mixnode` functionalities!**
|
||||
Migration is a must for all deprecated nodes (`nym-mixnode`, `nym-gateway`). These binaries from version 1.1.35 (`nym-gateway`) and 1.1.37 (`nym-mixnode`) onwards will no longer have `init` command and `nym-node` is the only binary to use for `gateway` or `mixnode` fucntionalities.
|
||||
|
||||
From `2024.14-crunch` release (`nym-node v1.2.0`) onward, `nym-node` binary does *not* have `migrate` command included. In case you are still running a legacy node and want to migrate, [download](https://github.com/nymtech/nym/releases) an older `nym-node` binary and upgrade to the latest after migrating.
|
||||
|
||||
Furthermore, giving that legacy nodes had been deprecated for several months, Nym cannot promise 100% serialisation for operators migrating from long outdated versions. If you are about to migrate, start with [`nym-node v1.1.0`](https://github.com/nymtech/nym/releases/tag/nym-binaries-v2024.3-eclipse) and keep upgrading version by version all the way to the latest one.
|
||||
**Nym cannot promise 100% serialisation for operators migrating from long outdated versions to the newest ones. If you are about to migrate, start with [`nym-node v1.1.0`](https://github.com/nymtech/nym/releases/tag/nym-binaries-v2024.3-eclipse) and keep upgrading version by version all the way to the latest one.**
|
||||
</Callout>
|
||||
|
||||
Operators who are about to migrate their nodes need to configure their [VPS](vps-setup.md) and setup `nym-node` which can be downloaded as a [pre-built binary](../binaries/pre-built-binaries.md) or compiled from [source](../binaries/building-nym.md).
|
||||
|
||||
To migrate a `nym-mixnode` or a `nym-gateway` to `nym-node` use, the `migrate` command with `--config-file` flag pointing to the original `config.toml` file, with a conditional argument defining which type of node this configuration belongs to. The exact steps are below.
|
||||
To migrate a `nym-mixnode` or a `nym-gateway` to `nym-node` is fairly simple, use the `migrate` command with `--config-file` flag pointing to the original `config.toml` file, with a conditional argument defining which type of node this configuration belongs to. Examples are below.
|
||||
|
||||
Make sure to use `--deny-init` flag to prevent initialisation of a new node.
|
||||
|
||||
<MigrateTabs />
|
||||
|
||||
**After you upgraded your node to the latest release of `nym-node`, make sure that you also follow [the steps to migrate your node in the Mixnet smart contract](bonding#migrate-to-nym-node-in-mixnet-smart-contract), othewise your node will never receive any rewards.**
|
||||
|
||||
|
||||
### Next steps
|
||||
|
||||
If there are any problems checkout the troubleshooting section or report an issue.
|
||||
|
||||
@@ -163,11 +163,4 @@ impl ActiveClientsStore {
|
||||
pub(crate) fn size(&self) -> usize {
|
||||
self.inner.len()
|
||||
}
|
||||
|
||||
pub fn pending_packets(&self) -> usize {
|
||||
self.inner
|
||||
.iter()
|
||||
.map(|client| client.get_sender_ref().len())
|
||||
.sum()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ use nym_crypto::asymmetric::identity;
|
||||
use nym_gateway_storage::GatewayStorage;
|
||||
use nym_mixnet_client::forwarder::MixForwardingSender;
|
||||
use nym_node_metrics::events::MetricEventsSender;
|
||||
use nym_node_metrics::NymNodeMetrics;
|
||||
use std::sync::Arc;
|
||||
|
||||
// I can see this being possible expanded with say storage or client store
|
||||
@@ -18,7 +17,6 @@ pub(crate) struct CommonHandlerState {
|
||||
pub(crate) local_identity: Arc<identity::KeyPair>,
|
||||
pub(crate) only_coconut_credentials: bool,
|
||||
pub(crate) bandwidth_cfg: BandwidthFlushingBehaviourConfig,
|
||||
pub(crate) metrics: NymNodeMetrics,
|
||||
pub(crate) metrics_sender: MetricEventsSender,
|
||||
pub(crate) outbound_mix_sender: MixForwardingSender,
|
||||
pub(crate) active_clients_store: ActiveClientsStore,
|
||||
|
||||
@@ -61,13 +61,7 @@ impl Listener {
|
||||
remote_addr,
|
||||
shutdown,
|
||||
);
|
||||
tokio::spawn(async move {
|
||||
// TODO: refactor it similarly to the mixnet listener on the nym-node
|
||||
let metrics_ref = handle.shared_state.metrics.clone();
|
||||
metrics_ref.network.new_ingress_websocket_client();
|
||||
handle.start_handling().await;
|
||||
metrics_ref.network.disconnected_ingress_websocket_client();
|
||||
});
|
||||
tokio::spawn(handle.start_handling());
|
||||
}
|
||||
Err(err) => warn!("failed to get client: {err}"),
|
||||
}
|
||||
|
||||
@@ -252,7 +252,6 @@ impl GatewayTasksBuilder {
|
||||
local_identity: Arc::clone(&self.identity_keypair),
|
||||
only_coconut_credentials: self.config.gateway.enforce_zk_nyms,
|
||||
bandwidth_cfg: (&self.config).into(),
|
||||
metrics: self.metrics.clone(),
|
||||
metrics_sender: self.metrics_sender.clone(),
|
||||
outbound_mix_sender: self.mix_packet_sender.clone(),
|
||||
active_clients_store: active_clients_store.clone(),
|
||||
|
||||
+1
-1
@@ -105,7 +105,7 @@ nym-gateway-client = { path = "../common/client-libs/gateway-client" }
|
||||
nym-inclusion-probability = { path = "../common/inclusion-probability" }
|
||||
nym-mixnet-contract-common = { path = "../common/cosmwasm-smart-contracts/mixnet-contract", features = ["utoipa"] }
|
||||
nym-vesting-contract-common = { path = "../common/cosmwasm-smart-contracts/vesting-contract" }
|
||||
nym-contracts-common = { path = "../common/cosmwasm-smart-contracts/contracts-common", features = ["naive_float", "utoipa"] }
|
||||
nym-contracts-common = { path = "../common/cosmwasm-smart-contracts/contracts-common", features = ["naive_float"] }
|
||||
nym-multisig-contract-common = { path = "../common/cosmwasm-smart-contracts/multisig-contract" }
|
||||
nym-coconut = { path = "../common/nymcoconut", features = ["key-zeroize"] }
|
||||
nym-sphinx = { path = "../common/nymsphinx" }
|
||||
|
||||
@@ -31,7 +31,7 @@ nym-crypto = { path = "../../common/crypto", features = ["serde", "asymmetric"]
|
||||
nym-ecash-time = { path = "../../common/ecash-time" }
|
||||
nym-compact-ecash = { path = "../../common/nym_offline_compact_ecash" }
|
||||
nym-contracts-common = { path = "../../common/cosmwasm-smart-contracts/contracts-common", features = ["naive_float"] }
|
||||
nym-mixnet-contract-common = { path = "../../common/cosmwasm-smart-contracts/mixnet-contract", features = ["utoipa"] }
|
||||
nym-mixnet-contract-common = { path = "../../common/cosmwasm-smart-contracts/mixnet-contract" }
|
||||
nym-node-requests = { path = "../../nym-node/nym-node-requests", default-features = false, features = ["openapi"] }
|
||||
nym-network-defaults = { path = "../../common/network-defaults" }
|
||||
nym-ticketbooks-merkle = { path = "../../common/ticketbooks-merkle" }
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright 2023-2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::helpers::PlaceholderJsonSchemaImpl;
|
||||
use cosmrs::AccountId;
|
||||
use nym_compact_ecash::scheme::coin_indices_signatures::AnnotatedCoinIndexSignature;
|
||||
use nym_compact_ecash::scheme::expiration_date_signatures::AnnotatedExpirationDateSignature;
|
||||
@@ -13,6 +14,7 @@ use nym_credentials_interface::{
|
||||
};
|
||||
use nym_crypto::asymmetric::{ed25519, identity};
|
||||
use nym_ticketbooks_merkle::{IssuedTicketbook, IssuedTicketbooksFullMerkleProof};
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sha2::Digest;
|
||||
use std::collections::BTreeMap;
|
||||
@@ -21,25 +23,25 @@ use thiserror::Error;
|
||||
use time::Date;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, ToSchema)]
|
||||
#[derive(Serialize, Deserialize, Clone, JsonSchema, ToSchema)]
|
||||
pub struct VerifyEcashTicketBody {
|
||||
/// The cryptographic material required for spending the underlying credential.
|
||||
#[schema(value_type = String)]
|
||||
#[schemars(with = "PlaceholderJsonSchemaImpl")]
|
||||
pub credential: CredentialSpendingData,
|
||||
|
||||
/// Cosmos address of the sender of the credential
|
||||
#[schema(value_type = String)]
|
||||
#[schemars(with = "String")]
|
||||
pub gateway_cosmos_addr: AccountId,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, ToSchema)]
|
||||
#[derive(Serialize, Deserialize, Clone, JsonSchema, ToSchema)]
|
||||
pub struct VerifyEcashCredentialBody {
|
||||
/// The cryptographic material required for spending the underlying credential.
|
||||
#[schema(value_type = openapi_schema::CredentialSpendingData)]
|
||||
#[schemars(with = "PlaceholderJsonSchemaImpl")]
|
||||
pub credential: CredentialSpendingData,
|
||||
|
||||
/// Cosmos address of the sender of the credential
|
||||
#[schema(value_type = String)]
|
||||
#[schemars(with = "String")]
|
||||
pub gateway_cosmos_addr: AccountId,
|
||||
|
||||
/// Multisig proposal for releasing funds for the provided bandwidth credential
|
||||
@@ -60,16 +62,8 @@ impl VerifyEcashCredentialBody {
|
||||
}
|
||||
}
|
||||
|
||||
/// Used exclusively as part of OpenAPI docs
|
||||
#[derive(ToSchema)]
|
||||
pub enum EcashTicketVerificationResult {
|
||||
Ok(()),
|
||||
EcashTicketVerificationRejection,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, ToSchema)]
|
||||
#[derive(Debug, Serialize, Deserialize, JsonSchema, ToSchema)]
|
||||
pub struct EcashTicketVerificationResponse {
|
||||
#[schema(value_type = EcashTicketVerificationResult)]
|
||||
pub verified: Result<(), EcashTicketVerificationRejection>,
|
||||
}
|
||||
|
||||
@@ -81,18 +75,18 @@ impl EcashTicketVerificationResponse {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Error, Serialize, Deserialize, ToSchema)]
|
||||
#[derive(Debug, Error, Serialize, Deserialize, JsonSchema, ToSchema)]
|
||||
pub enum EcashTicketVerificationRejection {
|
||||
#[error("invalid ticket spent date. expected either today's ({today}) or yesterday's* ({yesterday}) date but got {received} instead\n*assuming it's before 1AM UTC")]
|
||||
InvalidSpentDate {
|
||||
#[schemars(with = "String")]
|
||||
#[serde(with = "crate::helpers::date_serde")]
|
||||
#[schema(value_type = String, example = "1970-01-01")]
|
||||
today: Date,
|
||||
#[schemars(with = "String")]
|
||||
#[serde(with = "crate::helpers::date_serde")]
|
||||
#[schema(value_type = String, example = "1970-01-01")]
|
||||
yesterday: Date,
|
||||
#[schemars(with = "String")]
|
||||
#[serde(with = "crate::helpers::date_serde")]
|
||||
#[schema(value_type = String, example = "1970-01-01")]
|
||||
received: Date,
|
||||
},
|
||||
|
||||
@@ -112,26 +106,26 @@ pub enum EcashTicketVerificationRejection {
|
||||
}
|
||||
|
||||
// All strings are base58 encoded representations of structs
|
||||
#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, ToSchema)]
|
||||
#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, JsonSchema, ToSchema)]
|
||||
pub struct BlindSignRequestBody {
|
||||
#[schema(value_type = openapi_schema::WithdrawalRequest)]
|
||||
#[schemars(with = "PlaceholderJsonSchemaImpl")]
|
||||
pub inner_sign_request: WithdrawalRequest,
|
||||
|
||||
/// the id of the associated deposit
|
||||
pub deposit_id: u32,
|
||||
|
||||
/// Signature on the inner sign request and the tx hash
|
||||
#[schema(value_type = String)]
|
||||
#[schemars(with = "PlaceholderJsonSchemaImpl")]
|
||||
pub signature: identity::Signature,
|
||||
|
||||
#[schema(value_type = openapi_schema::PublicKeyUser)]
|
||||
#[schemars(with = "PlaceholderJsonSchemaImpl")]
|
||||
pub ecash_pubkey: PublicKeyUser,
|
||||
|
||||
#[schemars(with = "String")]
|
||||
#[serde(with = "crate::helpers::date_serde")]
|
||||
#[schema(value_type = String, example = "1970-01-01")]
|
||||
pub expiration_date: Date,
|
||||
|
||||
#[schema(value_type = String)]
|
||||
#[schemars(with = "String")]
|
||||
pub ticketbook_type: TicketType,
|
||||
}
|
||||
|
||||
@@ -186,9 +180,9 @@ impl BlindSignRequestBody {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, ToSchema)]
|
||||
#[derive(Debug, Serialize, Deserialize, JsonSchema, ToSchema)]
|
||||
pub struct BlindedSignatureResponse {
|
||||
#[schema(value_type = openapi_schema::BlindedSignature)]
|
||||
#[schemars(with = "PlaceholderJsonSchemaImpl")]
|
||||
pub blinded_signature: BlindedSignature,
|
||||
}
|
||||
|
||||
@@ -217,9 +211,9 @@ impl BlindedSignatureResponse {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, ToSchema)]
|
||||
#[derive(Serialize, Deserialize, JsonSchema, ToSchema)]
|
||||
pub struct MasterVerificationKeyResponse {
|
||||
#[schema(value_type = openapi_schema::VerificationKeyAuth)]
|
||||
#[schemars(with = "PlaceholderJsonSchemaImpl")]
|
||||
pub key: VerificationKeyAuth,
|
||||
}
|
||||
|
||||
@@ -229,9 +223,9 @@ impl MasterVerificationKeyResponse {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, ToSchema)]
|
||||
#[derive(Serialize, Deserialize, JsonSchema, ToSchema)]
|
||||
pub struct VerificationKeyResponse {
|
||||
#[schema(value_type = openapi_schema::VerificationKeyAuth)]
|
||||
#[schemars(with = "PlaceholderJsonSchemaImpl")]
|
||||
pub key: VerificationKeyAuth,
|
||||
}
|
||||
|
||||
@@ -241,8 +235,9 @@ impl VerificationKeyResponse {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[derive(Serialize, Deserialize, JsonSchema)]
|
||||
pub struct CosmosAddressResponse {
|
||||
#[schemars(with = "String")]
|
||||
pub addr: AccountId,
|
||||
}
|
||||
|
||||
@@ -252,189 +247,45 @@ impl CosmosAddressResponse {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, ToSchema)]
|
||||
#[derive(Serialize, Deserialize, JsonSchema, ToSchema)]
|
||||
pub struct PartialExpirationDateSignatureResponse {
|
||||
pub epoch_id: u64,
|
||||
|
||||
#[schemars(with = "String")]
|
||||
#[serde(with = "crate::helpers::date_serde")]
|
||||
#[schema(value_type = String, example = "1970-01-01")]
|
||||
#[schema(value_type = String)]
|
||||
pub expiration_date: Date,
|
||||
#[schema(value_type = openapi_schema::AnnotatedExpirationDateSignature)]
|
||||
#[schemars(with = "PlaceholderJsonSchemaImpl")]
|
||||
pub signatures: Vec<AnnotatedExpirationDateSignature>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, ToSchema)]
|
||||
#[derive(Serialize, Deserialize, JsonSchema, ToSchema)]
|
||||
pub struct PartialCoinIndicesSignatureResponse {
|
||||
pub epoch_id: u64,
|
||||
#[schema(value_type = openapi_schema::AnnotatedCoinIndexSignature)]
|
||||
#[schemars(with = "PlaceholderJsonSchemaImpl")]
|
||||
pub signatures: Vec<AnnotatedCoinIndexSignature>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, ToSchema)]
|
||||
#[derive(Serialize, Deserialize, JsonSchema, ToSchema)]
|
||||
pub struct AggregatedExpirationDateSignatureResponse {
|
||||
pub epoch_id: u64,
|
||||
|
||||
#[schemars(with = "String")]
|
||||
#[serde(with = "crate::helpers::date_serde")]
|
||||
#[schema(value_type = String, example = "1970-01-01")]
|
||||
pub expiration_date: Date,
|
||||
|
||||
#[schema(value_type = Vec<openapi_schema::AnnotatedExpirationDateSignature>)]
|
||||
#[schemars(with = "PlaceholderJsonSchemaImpl")]
|
||||
pub signatures: Vec<AnnotatedExpirationDateSignature>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, ToSchema)]
|
||||
#[derive(Serialize, Deserialize, JsonSchema, ToSchema)]
|
||||
pub struct AggregatedCoinIndicesSignatureResponse {
|
||||
pub epoch_id: u64,
|
||||
#[schema(value_type = openapi_schema::Signature)]
|
||||
#[schemars(with = "PlaceholderJsonSchemaImpl")]
|
||||
pub signatures: Vec<AnnotatedCoinIndexSignature>,
|
||||
}
|
||||
|
||||
/// duplicate types from `nym-compact-ecash`, but these do derive `ToSchema```
|
||||
pub mod openapi_schema {
|
||||
#![allow(dead_code)]
|
||||
use nym_compact_ecash::common_types::{G2Projective, Scalar};
|
||||
|
||||
use super::*;
|
||||
|
||||
#[derive(ToSchema)]
|
||||
pub struct AnnotatedExpirationDateSignature {
|
||||
pub signature: Signature,
|
||||
pub expiration_timestamp: u32,
|
||||
pub spending_timestamp: u32,
|
||||
}
|
||||
|
||||
#[derive(ToSchema)]
|
||||
pub struct AnnotatedCoinIndexSignature {
|
||||
pub signature: Signature,
|
||||
pub index: u64,
|
||||
}
|
||||
|
||||
#[derive(ToSchema)]
|
||||
pub struct Signature {
|
||||
#[schema(value_type = String)]
|
||||
pub(crate) h: G1Projective,
|
||||
#[schema(value_type = String)]
|
||||
pub(crate) s: G1Projective,
|
||||
}
|
||||
|
||||
#[derive(ToSchema)]
|
||||
pub struct PublicKeyUser {
|
||||
#[schema(value_type = String)]
|
||||
pub(crate) pk: G1Projective,
|
||||
}
|
||||
|
||||
#[derive(ToSchema)]
|
||||
pub struct BlindedSignature {
|
||||
#[schema(value_type = String)]
|
||||
pub h: G1Projective,
|
||||
#[schema(value_type = String)]
|
||||
pub c: G1Projective,
|
||||
}
|
||||
|
||||
#[derive(ToSchema)]
|
||||
pub struct VerificationKeyAuth {
|
||||
#[schema(value_type = String)]
|
||||
pub(crate) alpha: G2Projective,
|
||||
#[schema(value_type = Vec<String>)]
|
||||
pub(crate) beta_g1: Vec<G1Projective>,
|
||||
#[schema(value_type = Vec<String>)]
|
||||
pub(crate) beta_g2: Vec<G2Projective>,
|
||||
}
|
||||
|
||||
#[derive(ToSchema)]
|
||||
pub struct WithdrawalRequest {
|
||||
#[schema(value_type = String)]
|
||||
joined_commitment_hash: G1Projective,
|
||||
#[schema(value_type = String)]
|
||||
joined_commitment: G1Projective,
|
||||
#[schema(value_type = Vec<String>)]
|
||||
private_attributes_commitments: Vec<G1Projective>,
|
||||
zk_proof: WithdrawalReqProof,
|
||||
}
|
||||
|
||||
#[derive(ToSchema)]
|
||||
pub struct WithdrawalReqProof {
|
||||
#[schema(value_type = String)]
|
||||
challenge: Scalar,
|
||||
#[schema(value_type = String)]
|
||||
response_opening: Scalar,
|
||||
#[schema(value_type = Vec<String>)]
|
||||
response_openings: Vec<Scalar>,
|
||||
#[schema(value_type = Vec<String>)]
|
||||
response_attributes: Vec<Scalar>,
|
||||
}
|
||||
|
||||
#[derive(ToSchema)]
|
||||
pub struct CredentialSpendingData {
|
||||
pub payment: Payment,
|
||||
|
||||
#[schema(value_type = [u8; 72], format = Binary)]
|
||||
pub pay_info: PayInfo,
|
||||
|
||||
pub spend_date: Date,
|
||||
|
||||
// pub value: u64,
|
||||
/// The (DKG) epoch id under which the credential has been issued so that the verifier could use correct verification key for validation.
|
||||
pub epoch_id: u64,
|
||||
}
|
||||
|
||||
#[derive(ToSchema)]
|
||||
pub struct Payment {
|
||||
#[schema(value_type = String)]
|
||||
pub kappa: G2Projective,
|
||||
#[schema(value_type = String)]
|
||||
pub kappa_e: G2Projective,
|
||||
pub sig: Signature,
|
||||
|
||||
pub sig_exp: Signature,
|
||||
#[schema(value_type = Vec<String>)]
|
||||
pub kappa_k: Vec<G2Projective>,
|
||||
pub omega: Vec<Signature>,
|
||||
#[schema(value_type = Vec<String>)]
|
||||
pub ss: Vec<G1Projective>,
|
||||
#[schema(value_type = Vec<String>)]
|
||||
pub tt: Vec<G1Projective>,
|
||||
#[schema(value_type = Vec<String>)]
|
||||
pub aa: Vec<G1Projective>,
|
||||
pub spend_value: u64,
|
||||
#[schema(value_type = String)]
|
||||
pub cc: G1Projective,
|
||||
pub t_type: u8,
|
||||
pub zk_proof: SpendProof,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Debug, Clone, Copy, ToSchema)]
|
||||
pub struct PayInfo {
|
||||
#[schema(content_encoding = "base16")]
|
||||
pub pay_info_bytes: [u8; 72],
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, ToSchema)]
|
||||
pub struct SpendProof {
|
||||
#[schema(value_type = String)]
|
||||
challenge: Scalar,
|
||||
#[schema(value_type = String)]
|
||||
response_r: Scalar,
|
||||
#[schema(value_type = String)]
|
||||
response_r_e: Scalar,
|
||||
#[schema(value_type = Vec<String>)]
|
||||
responses_r_k: Vec<Scalar>,
|
||||
#[schema(value_type = Vec<String>)]
|
||||
responses_l: Vec<Scalar>,
|
||||
#[schema(value_type = Vec<String>)]
|
||||
responses_o_a: Vec<Scalar>,
|
||||
#[schema(value_type = String)]
|
||||
response_o_c: Scalar,
|
||||
#[schema(value_type = Vec<String>)]
|
||||
responses_mu: Vec<Scalar>,
|
||||
#[schema(value_type = Vec<String>)]
|
||||
responses_o_mu: Vec<Scalar>,
|
||||
#[schema(value_type = Vec<String>)]
|
||||
responses_attributes: Vec<Scalar>,
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize, Debug)]
|
||||
#[derive(Clone, Serialize, Deserialize, Debug, JsonSchema)]
|
||||
pub struct Pagination<T> {
|
||||
/// last_key is the last value returned in the previous query.
|
||||
/// it's used to indicate the start of the next (this) page.
|
||||
@@ -446,8 +297,12 @@ pub struct Pagination<T> {
|
||||
pub limit: Option<u32>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, ToSchema)]
|
||||
pub struct SerialNumberWrapper(#[serde(with = "nym_serde_helpers::bs58")] Vec<u8>);
|
||||
#[derive(Clone, Serialize, Deserialize, Debug, JsonSchema, PartialEq)]
|
||||
pub struct SerialNumberWrapper(
|
||||
#[serde(with = "nym_serde_helpers::bs58")]
|
||||
#[schemars(with = "String")]
|
||||
Vec<u8>,
|
||||
);
|
||||
|
||||
impl Deref for SerialNumberWrapper {
|
||||
type Target = Vec<u8>;
|
||||
@@ -468,13 +323,14 @@ impl From<Vec<u8>> for SerialNumberWrapper {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, ToSchema)]
|
||||
#[derive(Clone, Serialize, Deserialize, Debug, JsonSchema, PartialEq)]
|
||||
pub struct BatchRedeemTicketsBody {
|
||||
#[serde(with = "nym_serde_helpers::bs58")]
|
||||
#[schemars(with = "String")]
|
||||
pub digest: Vec<u8>,
|
||||
pub included_serial_numbers: Vec<SerialNumberWrapper>,
|
||||
pub proposal_id: u64,
|
||||
#[schema(value_type = String)]
|
||||
#[schemars(with = "String")]
|
||||
pub gateway_cosmos_addr: AccountId,
|
||||
}
|
||||
|
||||
@@ -510,15 +366,16 @@ impl BatchRedeemTicketsBody {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, ToSchema)]
|
||||
#[derive(Debug, Serialize, Deserialize, JsonSchema, ToSchema)]
|
||||
pub struct EcashBatchTicketRedemptionResponse {
|
||||
pub proposal_accepted: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize, Debug, ToSchema)]
|
||||
#[derive(Clone, Serialize, Deserialize, Debug, JsonSchema, ToSchema)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SpentCredentialsResponse {
|
||||
#[serde(with = "nym_serde_helpers::base64")]
|
||||
#[schemars(with = "String")]
|
||||
#[schema(value_type = String)]
|
||||
pub bitmap: Vec<u8>,
|
||||
}
|
||||
@@ -531,19 +388,18 @@ impl SpentCredentialsResponse {
|
||||
|
||||
pub type DepositId = u32;
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize, Debug, ToSchema, PartialEq, Eq)]
|
||||
#[derive(Clone, Serialize, Deserialize, Debug, JsonSchema, ToSchema, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CommitedDeposit {
|
||||
#[schema(value_type = u32)]
|
||||
pub deposit_id: DepositId,
|
||||
pub merkle_index: usize,
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize, Debug, ToSchema)]
|
||||
#[derive(Clone, Serialize, Deserialize, Debug, JsonSchema, ToSchema)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct IssuedTicketbooksForResponseBody {
|
||||
#[schemars(with = "String")]
|
||||
#[serde(with = "crate::helpers::date_serde")]
|
||||
#[schema(value_type = String, example = "1970-01-01")]
|
||||
pub expiration_date: Date,
|
||||
pub deposits: Vec<CommitedDeposit>,
|
||||
pub merkle_root: Option<[u8; 32]>,
|
||||
@@ -563,13 +419,13 @@ impl IssuedTicketbooksForResponseBody {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize, Debug, ToSchema)]
|
||||
#[derive(Clone, Serialize, Deserialize, Debug, JsonSchema, ToSchema)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct IssuedTicketbooksForResponse {
|
||||
pub body: IssuedTicketbooksForResponseBody,
|
||||
|
||||
/// Signature on the body
|
||||
#[schema(value_type = String)]
|
||||
/// Signature on the body
|
||||
#[schemars(with = "PlaceholderJsonSchemaImpl")]
|
||||
pub signature: identity::Signature,
|
||||
}
|
||||
|
||||
@@ -581,24 +437,22 @@ impl IssuedTicketbooksForResponse {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, ToSchema, Debug)]
|
||||
#[derive(Serialize, Deserialize, JsonSchema, ToSchema, Debug)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct IssuedTicketbooksChallengeRequest {
|
||||
#[schemars(with = "String")]
|
||||
#[serde(with = "crate::helpers::date_serde")]
|
||||
#[schema(value_type = String, example = "1970-01-01")]
|
||||
pub expiration_date: Date,
|
||||
#[schema(value_type = Vec<u32>)]
|
||||
pub deposits: Vec<DepositId>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, ToSchema, Clone, Debug)]
|
||||
#[derive(Serialize, Deserialize, JsonSchema, ToSchema, Clone, Debug)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct IssuedTicketbooksChallengeResponseBody {
|
||||
#[schemars(with = "String")]
|
||||
#[serde(with = "crate::helpers::date_serde")]
|
||||
#[schema(value_type = String, example = "1970-01-01")]
|
||||
pub expiration_date: Date,
|
||||
|
||||
#[schema(value_type = BTreeMap<u32, IssuedTicketbook>)]
|
||||
pub partial_ticketbooks: BTreeMap<DepositId, IssuedTicketbook>,
|
||||
pub merkle_proof: IssuedTicketbooksFullMerkleProof,
|
||||
}
|
||||
@@ -632,12 +486,12 @@ impl IssuedTicketbooksChallengeResponseBody {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, ToSchema)]
|
||||
#[derive(Serialize, Deserialize, JsonSchema, ToSchema, Clone, Debug)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct IssuedTicketbooksChallengeResponse {
|
||||
pub body: IssuedTicketbooksChallengeResponseBody,
|
||||
|
||||
#[schema(value_type = String)]
|
||||
#[schemars(with = "PlaceholderJsonSchemaImpl")]
|
||||
pub signature: identity::Signature,
|
||||
}
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ impl From<LegacyMixNodeBondWithLayer> for MixNodeBond {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, ToSchema)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct LegacyMixNodeDetailsWithLayer {
|
||||
/// Basic bond information of this mixnode, such as owner address, original pledge, etc.
|
||||
pub bond_information: LegacyMixNodeBondWithLayer,
|
||||
|
||||
@@ -72,7 +72,7 @@ impl Display for RequestError {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema, ToSchema)]
|
||||
#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
|
||||
#[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))]
|
||||
#[cfg_attr(
|
||||
feature = "generate-ts",
|
||||
@@ -145,7 +145,7 @@ pub struct NodePerformance {
|
||||
pub last_24h: Performance,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Copy, Hash, JsonSchema, ToSchema)]
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Copy, Hash, JsonSchema)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))]
|
||||
#[cfg_attr(
|
||||
@@ -190,7 +190,7 @@ impl From<DisplayRole> for Role {
|
||||
// imo for now there's no point in exposing more than that,
|
||||
// nym-api shouldn't be calculating apy or stake saturation for you.
|
||||
// it should just return its own metrics (performance) and then you can do with it as you wish
|
||||
#[derive(Clone, Copy, Debug, Default, Serialize, Deserialize, JsonSchema, ToSchema)]
|
||||
#[derive(Clone, Copy, Debug, Default, Serialize, Deserialize, JsonSchema)]
|
||||
#[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))]
|
||||
#[cfg_attr(
|
||||
feature = "generate-ts",
|
||||
@@ -202,14 +202,13 @@ impl From<DisplayRole> for Role {
|
||||
pub struct NodeAnnotation {
|
||||
#[cfg_attr(feature = "generate-ts", ts(type = "string"))]
|
||||
// legacy
|
||||
#[schema(value_type = String)]
|
||||
pub last_24h_performance: Performance,
|
||||
pub current_role: Option<DisplayRole>,
|
||||
|
||||
pub detailed_performance: DetailedNodePerformance,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default, Serialize, Deserialize, JsonSchema, ToSchema)]
|
||||
#[derive(Clone, Copy, Debug, Default, Serialize, Deserialize, JsonSchema)]
|
||||
#[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))]
|
||||
#[cfg_attr(
|
||||
feature = "generate-ts",
|
||||
@@ -245,7 +244,7 @@ impl DetailedNodePerformance {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default, Serialize, Deserialize, JsonSchema, ToSchema)]
|
||||
#[derive(Clone, Copy, Debug, Default, Serialize, Deserialize, JsonSchema)]
|
||||
#[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))]
|
||||
#[cfg_attr(
|
||||
feature = "generate-ts",
|
||||
@@ -267,7 +266,7 @@ impl RoutingScore {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default, Serialize, Deserialize, JsonSchema, ToSchema)]
|
||||
#[derive(Clone, Copy, Debug, Default, Serialize, Deserialize, JsonSchema)]
|
||||
#[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))]
|
||||
#[cfg_attr(
|
||||
feature = "generate-ts",
|
||||
@@ -398,15 +397,12 @@ pub struct MixNodeBondAnnotated {
|
||||
#[schema(value_type = String)]
|
||||
pub performance: Performance,
|
||||
pub node_performance: NodePerformance,
|
||||
#[schema(value_type = String)]
|
||||
pub estimated_operator_apy: Decimal,
|
||||
#[schema(value_type = String)]
|
||||
pub estimated_delegators_apy: Decimal,
|
||||
pub blacklisted: bool,
|
||||
|
||||
// a rather temporary thing until we query self-described endpoints of mixnodes
|
||||
#[serde(default)]
|
||||
#[schema(value_type = Vec<String>)]
|
||||
pub ip_addresses: Vec<IpAddr>,
|
||||
}
|
||||
|
||||
@@ -475,13 +471,11 @@ pub struct GatewayBondAnnotated {
|
||||
pub self_described: Option<GatewayDescription>,
|
||||
|
||||
// NOTE: the performance field is deprecated in favour of node_performance
|
||||
#[schema(value_type = String)]
|
||||
pub performance: Performance,
|
||||
pub node_performance: NodePerformance,
|
||||
pub blacklisted: bool,
|
||||
|
||||
#[serde(default)]
|
||||
#[schema(value_type = Vec<String>)]
|
||||
pub ip_addresses: Vec<IpAddr>,
|
||||
}
|
||||
|
||||
@@ -532,24 +526,21 @@ impl GatewayBondAnnotated {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, ToSchema)]
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct GatewayDescription {
|
||||
// for now only expose what we need. this struct will evolve in the future (or be incorporated into nym-node properly)
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, JsonSchema, ToSchema, IntoParams)]
|
||||
pub struct ComputeRewardEstParam {
|
||||
#[schema(value_type = Option<String>)]
|
||||
#[param(value_type = Option<String>)]
|
||||
#[schema(value_type = String)]
|
||||
pub performance: Option<Performance>,
|
||||
pub active_in_rewarded_set: Option<bool>,
|
||||
pub pledge_amount: Option<u64>,
|
||||
pub total_delegation: Option<u64>,
|
||||
#[schema(value_type = Option<CoinSchema>)]
|
||||
#[param(value_type = Option<CoinSchema>)]
|
||||
#[schema(value_type = CoinSchema)]
|
||||
pub interval_operating_cost: Option<Coin>,
|
||||
#[schema(value_type = Option<String>)]
|
||||
#[param(value_type = Option<String>)]
|
||||
#[schema(value_type = String)]
|
||||
pub profit_margin_percent: Option<Percent>,
|
||||
}
|
||||
|
||||
@@ -707,11 +698,8 @@ pub struct MixnodeStatusReportResponse {
|
||||
pub mix_id: NodeId,
|
||||
pub identity: IdentityKey,
|
||||
pub owner: String,
|
||||
#[schema(value_type = u8)]
|
||||
pub most_recent: Uptime,
|
||||
#[schema(value_type = u8)]
|
||||
pub last_hour: Uptime,
|
||||
#[schema(value_type = u8)]
|
||||
pub last_day: Uptime,
|
||||
}
|
||||
|
||||
@@ -837,7 +825,6 @@ pub struct CirculatingSupplyResponse {
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, schemars::JsonSchema, ToSchema)]
|
||||
pub struct HostInformation {
|
||||
#[schema(value_type = Vec<String>)]
|
||||
pub ip_address: Vec<IpAddr>,
|
||||
pub hostname: Option<String>,
|
||||
pub keys: HostKeys,
|
||||
@@ -857,18 +844,15 @@ impl From<nym_node_requests::api::v1::node::models::HostInformation> for HostInf
|
||||
pub struct HostKeys {
|
||||
#[serde(with = "bs58_ed25519_pubkey")]
|
||||
#[schemars(with = "String")]
|
||||
#[schema(value_type = String)]
|
||||
pub ed25519: ed25519::PublicKey,
|
||||
|
||||
#[serde(with = "bs58_x25519_pubkey")]
|
||||
#[schemars(with = "String")]
|
||||
#[schema(value_type = String)]
|
||||
pub x25519: x25519::PublicKey,
|
||||
|
||||
#[serde(default)]
|
||||
#[serde(with = "option_bs58_x25519_pubkey")]
|
||||
#[schemars(with = "Option<String>")]
|
||||
#[schema(value_type = String)]
|
||||
pub x25519_noise: Option<x25519::PublicKey>,
|
||||
}
|
||||
|
||||
@@ -912,7 +896,6 @@ pub struct OffsetDateTimeJsonSchemaWrapper(
|
||||
default = "unix_epoch",
|
||||
with = "crate::helpers::overengineered_offset_date_time_serde"
|
||||
)]
|
||||
#[schema(inline)]
|
||||
pub OffsetDateTime,
|
||||
);
|
||||
|
||||
@@ -1250,13 +1233,13 @@ pub struct SignerInformationResponse {
|
||||
pub verification_key: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, schemars::JsonSchema, Default, ToSchema)]
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, schemars::JsonSchema, Default)]
|
||||
pub struct TestNode {
|
||||
pub node_id: Option<u32>,
|
||||
pub identity_key: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, schemars::JsonSchema, ToSchema)]
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, schemars::JsonSchema)]
|
||||
pub struct TestRoute {
|
||||
pub gateway: TestNode,
|
||||
pub layer1: TestNode,
|
||||
@@ -1291,12 +1274,10 @@ pub struct NetworkMonitorRunDetailsResponse {
|
||||
pub struct NoiseDetails {
|
||||
#[schemars(with = "String")]
|
||||
#[serde(with = "bs58_x25519_pubkey")]
|
||||
#[schema(value_type = String)]
|
||||
pub x25119_pubkey: x25519::PublicKey,
|
||||
|
||||
pub mixnet_port: u16,
|
||||
|
||||
#[schema(value_type = Vec<String>)]
|
||||
pub ip_addresses: Vec<IpAddr>,
|
||||
}
|
||||
|
||||
@@ -1304,14 +1285,12 @@ pub struct NoiseDetails {
|
||||
pub struct NodeRefreshBody {
|
||||
#[serde(with = "bs58_ed25519_pubkey")]
|
||||
#[schemars(with = "String")]
|
||||
#[schema(value_type = String)]
|
||||
pub node_identity: ed25519::PublicKey,
|
||||
|
||||
// a poor man's nonce
|
||||
pub request_timestamp: i64,
|
||||
|
||||
#[schemars(with = "PlaceholderJsonSchemaImpl")]
|
||||
#[schema(value_type = String)]
|
||||
pub signature: ed25519::Signature,
|
||||
}
|
||||
|
||||
|
||||
@@ -14,19 +14,19 @@ use std::net::IpAddr;
|
||||
use time::OffsetDateTime;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, schemars::JsonSchema, ToSchema)]
|
||||
pub struct CachedNodesResponse<T: ToSchema> {
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, schemars::JsonSchema)]
|
||||
pub struct CachedNodesResponse<T> {
|
||||
pub refreshed_at: OffsetDateTimeJsonSchemaWrapper,
|
||||
pub nodes: Vec<T>,
|
||||
}
|
||||
|
||||
impl<T: ToSchema> From<Vec<T>> for CachedNodesResponse<T> {
|
||||
impl<T> From<Vec<T>> for CachedNodesResponse<T> {
|
||||
fn from(nodes: Vec<T>) -> Self {
|
||||
CachedNodesResponse::new(nodes)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ToSchema> CachedNodesResponse<T> {
|
||||
impl<T> CachedNodesResponse<T> {
|
||||
pub fn new(nodes: Vec<T>) -> Self {
|
||||
CachedNodesResponse {
|
||||
refreshed_at: OffsetDateTime::now_utc().into(),
|
||||
@@ -130,7 +130,6 @@ pub struct SkimmedNode {
|
||||
|
||||
#[serde(with = "bs58_ed25519_pubkey")]
|
||||
#[schemars(with = "String")]
|
||||
#[schema(value_type = String)]
|
||||
pub ed25519_identity_pubkey: ed25519::PublicKey,
|
||||
|
||||
#[schema(value_type = Vec<String>)]
|
||||
@@ -140,7 +139,6 @@ pub struct SkimmedNode {
|
||||
|
||||
#[serde(with = "bs58_x25519_pubkey")]
|
||||
#[schemars(with = "String")]
|
||||
#[schema(value_type = String)]
|
||||
pub x25519_sphinx_pubkey: x25519::PublicKey,
|
||||
|
||||
#[serde(alias = "epoch_role")]
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
# This file instructs Redocly's linter to ignore the rules contained for specific parts of your API.
|
||||
# See https://redocly.com/docs/cli/ for more information.
|
||||
formatted-openapi.json:
|
||||
path-parameters-defined:
|
||||
- >-
|
||||
#/paths/~1v1~1status~1mixnode~1{mix_id}~1compute-reward-estimation/post/parameters/0/name
|
||||
- >-
|
||||
#/paths/~1v1~1status~1mixnode~1{mix_id}~1compute-reward-estimation/post/parameters/1/name
|
||||
- >-
|
||||
#/paths/~1v1~1status~1mixnode~1{mix_id}~1compute-reward-estimation/post/parameters/2/name
|
||||
- >-
|
||||
#/paths/~1v1~1status~1mixnode~1{mix_id}~1compute-reward-estimation/post/parameters/3/name
|
||||
- >-
|
||||
#/paths/~1v1~1status~1mixnode~1{mix_id}~1compute-reward-estimation/post/parameters/4/name
|
||||
- >-
|
||||
#/paths/~1v1~1status~1mixnode~1{mix_id}~1compute-reward-estimation/post/parameters/5/name
|
||||
operation-operationId-unique:
|
||||
- >-
|
||||
#/paths/~1v1~1status~1mixnodes~1active~1detailed/get/get_active_set_detailed
|
||||
- '#/paths/~1v1~1status~1mixnodes~1detailed/get/get_mixnodes_detailed'
|
||||
- >-
|
||||
#/paths/~1v1~1status~1mixnodes~1rewarded~1detailed/get/get_rewarded_set_detailed
|
||||
no-unused-components:
|
||||
- '#/components/schemas/AxumErrorResponse'
|
||||
- '#/components/schemas/DateQuery'
|
||||
- '#/components/schemas/EcashTicketVerificationRejection'
|
||||
- '#/components/schemas/ExpirationDatePathParam'
|
||||
- '#/components/schemas/FullFatNode'
|
||||
- '#/components/schemas/G2ProjectiveSchema'
|
||||
- '#/components/schemas/HistoricalPerformanceResponse'
|
||||
- '#/components/schemas/HistoricalUptimeResponse'
|
||||
- '#/components/schemas/MasterVerificationKeyResponse'
|
||||
- '#/components/schemas/MixnodeStatusReport'
|
||||
- '#/components/schemas/NodeId'
|
||||
- '#/components/schemas/NodeRoleQueryParam'
|
||||
- '#/components/schemas/NoiseDetails'
|
||||
- '#/components/schemas/NymNodeDescription'
|
||||
- '#/components/schemas/NymNodeDetails'
|
||||
- '#/components/schemas/PaginationRequest'
|
||||
- '#/components/schemas/PartialCoinIndicesSignatureResponse'
|
||||
- '#/components/schemas/PayInfo'
|
||||
- '#/components/schemas/SpentCredentialsResponse'
|
||||
- '#/components/schemas/UptimeHistoryResponse'
|
||||
- '#/components/schemas/VerifyEcashCredentialBody'
|
||||
- '#/components/responses/AxumErrorResponse'
|
||||
- '#/components/responses/CirculatingSupplyResponse'
|
||||
- '#/components/responses/RequestError'
|
||||
@@ -1,12 +0,0 @@
|
||||
extends:
|
||||
- minimal
|
||||
apis:
|
||||
nym-api:
|
||||
root: ./formatted-openapi.json
|
||||
rules:
|
||||
# https://redocly.com/docs/cli/rules/oas/operation-summary
|
||||
operation-summary: off
|
||||
# https://redocly.com/docs/cli/rules/oas/security-defined
|
||||
security-defined: off
|
||||
# https://redocly.com/docs/cli/rules/oas/operation-2xx-response
|
||||
operation-2xx-response: off
|
||||
@@ -1,27 +0,0 @@
|
||||
# Test / validate OpenAPI spec
|
||||
|
||||
`redocly` CLI is an [OpenAPI linter][docs] that enforces good practices by
|
||||
checking whether a series of lints are applied to your OpenAPI spec.
|
||||
|
||||
## Install
|
||||
|
||||
You need `npm` and `npx` ([official instructions][instructions])
|
||||
|
||||
## Run
|
||||
|
||||
```
|
||||
./redocly.sh
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
- redocly.yaml is the main [config file](https://redocly.com/docs/redoc/config)
|
||||
|
||||
## Ignore file
|
||||
|
||||
- specifies lints to ignore (some lints may be false alarms/not applicable)
|
||||
- if you want to add current CLI warnings to an ignore file, run redocly CLI
|
||||
with `--generate-ignore-file`
|
||||
|
||||
[docs]: https://redocly.com/docs/redoc
|
||||
[instructions]: https://redocly.com/docs/cli/installation
|
||||
@@ -1,5 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
curl -s http://localhost:8000/api-docs/openapi.json | jq . > formatted-openapi.json
|
||||
npx @redocly/cli@latest lint --config .redocly.yaml \
|
||||
# --generate-ignore-file
|
||||
@@ -48,7 +48,7 @@ pub(crate) struct ExpirationDatePathParam {
|
||||
context_path = "/v1/ecash",
|
||||
responses(
|
||||
(status = 200, body = IssuedTicketbooksForResponse),
|
||||
(status = 400, body = String, description = "this nym-api is not an ecash signer in the current epoch"),
|
||||
(status = 400, body = ErrorResponse, description = "this nym-api is not an ecash signer in the current epoch"),
|
||||
)
|
||||
)]
|
||||
async fn issued_ticketbooks_for(
|
||||
@@ -73,7 +73,7 @@ async fn issued_ticketbooks_for(
|
||||
context_path = "/v1/ecash",
|
||||
responses(
|
||||
(status = 200, body = IssuedTicketbooksChallengeResponse),
|
||||
(status = 400, body = String, description = "this nym-api is not an ecash signer in the current epoch"),
|
||||
(status = 400, body = ErrorResponse, description = "this nym-api is not an ecash signer in the current epoch"),
|
||||
)
|
||||
)]
|
||||
async fn issued_ticketbooks_challenge(
|
||||
|
||||
@@ -42,7 +42,7 @@ pub(crate) fn partial_signing_routes() -> Router<AppState> {
|
||||
path = "/v1/ecash/blind-sign",
|
||||
responses(
|
||||
(status = 200, body = BlindedSignatureResponse),
|
||||
(status = 400, body = String, description = "this nym-api is not an ecash signer in the current epoch"),
|
||||
(status = 400, body = ErrorResponse, description = "this nym-api is not an ecash signer in the current epoch"),
|
||||
|
||||
)
|
||||
)]
|
||||
@@ -118,7 +118,7 @@ struct ExpirationDateParam {
|
||||
path = "/v1/ecash/partial-expiration-date-signatures",
|
||||
responses(
|
||||
(status = 200, body = PartialExpirationDateSignatureResponse),
|
||||
(status = 400, body = String, description = "this nym-api is not an ecash signer in the current epoch"),
|
||||
(status = 400, body = ErrorResponse, description = "this nym-api is not an ecash signer in the current epoch"),
|
||||
)
|
||||
)]
|
||||
async fn partial_expiration_date_signatures(
|
||||
@@ -156,7 +156,7 @@ async fn partial_expiration_date_signatures(
|
||||
path = "/v1/ecash/partial-coin-indices-signatures",
|
||||
responses(
|
||||
(status = 200, body = PartialExpirationDateSignatureResponse),
|
||||
(status = 400, body = String, description = "this nym-api is not an ecash signer in the current epoch"),
|
||||
(status = 400, body = ErrorResponse, description = "this nym-api is not an ecash signer in the current epoch"),
|
||||
)
|
||||
)]
|
||||
async fn partial_coin_indices_signatures(
|
||||
|
||||
@@ -52,7 +52,7 @@ fn reject_ticket(
|
||||
path = "/v1/ecash/verify-ecash-ticket",
|
||||
responses(
|
||||
(status = 200, body = EcashTicketVerificationResponse),
|
||||
(status = 400, body = String, description = "this nym-api is not an ecash signer in the current epoch"),
|
||||
(status = 400, body = ErrorResponse, description = "this nym-api is not an ecash signer in the current epoch"),
|
||||
)
|
||||
)]
|
||||
async fn verify_ticket(
|
||||
@@ -155,7 +155,7 @@ async fn verify_ticket(
|
||||
path = "/v1/ecash/batch-redeem-ecash-tickets",
|
||||
responses(
|
||||
(status = 200, body = EcashBatchTicketRedemptionResponse),
|
||||
(status = 400, body = String, description = "this nym-api is not an ecash signer in the current epoch"),
|
||||
(status = 400, body = ErrorResponse, description = "this nym-api is not an ecash signer in the current epoch"),
|
||||
)
|
||||
)]
|
||||
async fn batch_redeem_tickets(
|
||||
@@ -235,7 +235,7 @@ async fn batch_redeem_tickets(
|
||||
get,
|
||||
path = "/v1/ecash/double-spending-filter-v1",
|
||||
responses(
|
||||
(status = 500, body = String, description = "bloomfilters got disabled"),
|
||||
(status = 500, body = ErrorResponse, description = "bloomfilters got disabled"),
|
||||
)
|
||||
)]
|
||||
#[deprecated]
|
||||
|
||||
@@ -47,19 +47,12 @@ pub(crate) struct ContractVersionSchemaResponse {
|
||||
pub version: String,
|
||||
}
|
||||
|
||||
#[allow(dead_code)] // not dead, used in OpenAPI docs
|
||||
#[derive(ToSchema)]
|
||||
pub struct ContractInformationContractVersion {
|
||||
pub(crate) address: Option<String>,
|
||||
pub(crate) details: Option<ContractVersionSchemaResponse>,
|
||||
}
|
||||
|
||||
#[utoipa::path(
|
||||
tag = "network",
|
||||
get,
|
||||
path = "/v1/network/nym-contracts",
|
||||
responses(
|
||||
(status = 200, body = HashMap<String, ContractInformationContractVersion>)
|
||||
(status = 200, body = HashMap<String, ContractInformation<ContractVersionSchemaResponse>>)
|
||||
)
|
||||
)]
|
||||
async fn nym_contracts(
|
||||
@@ -80,19 +73,12 @@ async fn nym_contracts(
|
||||
.into()
|
||||
}
|
||||
|
||||
#[allow(dead_code)] // not dead, used in OpenAPI docs
|
||||
#[derive(ToSchema)]
|
||||
pub struct ContractInformationBuildInformation {
|
||||
pub(crate) address: Option<String>,
|
||||
pub(crate) details: Option<ContractBuildInformation>,
|
||||
}
|
||||
|
||||
#[utoipa::path(
|
||||
tag = "network",
|
||||
get,
|
||||
path = "/v1/network/nym-contracts-detailed",
|
||||
responses(
|
||||
(status = 200, body = HashMap<String, ContractInformationBuildInformation>)
|
||||
(status = 200, body = HashMap<String, ContractInformation<ContractBuildInformation>>)
|
||||
)
|
||||
)]
|
||||
async fn nym_contracts_detailed(
|
||||
|
||||
@@ -4,9 +4,8 @@
|
||||
use nym_config::defaults::NymNetworkDetails;
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use utoipa::ToSchema;
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize, JsonSchema, ToSchema)]
|
||||
#[derive(Clone, Serialize, Deserialize, JsonSchema, utoipa::ToSchema)]
|
||||
pub struct NetworkDetails {
|
||||
pub(crate) connected_nyxd: String,
|
||||
pub(crate) network: NymNetworkDetails,
|
||||
@@ -21,7 +20,7 @@ impl NetworkDetails {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize, JsonSchema, ToSchema)]
|
||||
#[derive(Clone, Serialize, Deserialize, JsonSchema, utoipa::ToSchema)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub struct ContractInformation<T> {
|
||||
pub(crate) address: Option<String>,
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
// Copyright 2021-2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
// we want to mark the routes as deprecated in swagger, but still expose them
|
||||
#![allow(deprecated)]
|
||||
use crate::node_status_api::handlers::MixIdParam;
|
||||
use crate::node_status_api::helpers::{
|
||||
_get_active_set_legacy_mixnodes_detailed, _get_legacy_mixnodes_detailed,
|
||||
@@ -22,6 +20,8 @@ use nym_mixnet_contract_common::NodeId;
|
||||
use nym_types::monitoring::MonitorMessage;
|
||||
use tracing::error;
|
||||
|
||||
// we want to mark the routes as deprecated in swagger, but still expose them
|
||||
#[allow(deprecated)]
|
||||
pub(super) fn mandatory_routes() -> Router<AppState> {
|
||||
Router::new()
|
||||
.route(
|
||||
@@ -63,9 +63,9 @@ pub(super) fn mandatory_routes() -> Router<AppState> {
|
||||
path = "/v1/status/submit-gateway-monitoring-results",
|
||||
responses(
|
||||
(status = 200),
|
||||
(status = 400, body = String, description = "TBD"),
|
||||
(status = 403, body = String, description = "TBD"),
|
||||
(status = 500, body = String, description = "TBD"),
|
||||
(status = 400, body = ErrorResponse, description = "TBD"),
|
||||
(status = 403, body = ErrorResponse, description = "TBD"),
|
||||
(status = 500, body = ErrorResponse, description = "TBD"),
|
||||
),
|
||||
)]
|
||||
pub(crate) async fn submit_gateway_monitoring_results(
|
||||
@@ -107,9 +107,9 @@ pub(crate) async fn submit_gateway_monitoring_results(
|
||||
path = "/v1/status/submit-node-monitoring-results",
|
||||
responses(
|
||||
(status = 200),
|
||||
(status = 400, body = String, description = "TBD"),
|
||||
(status = 403, body = String, description = "TBD"),
|
||||
(status = 500, body = String, description = "TBD"),
|
||||
(status = 400, body = ErrorResponse, description = "TBD"),
|
||||
(status = 403, body = ErrorResponse, description = "TBD"),
|
||||
(status = 500, body = ErrorResponse, description = "TBD"),
|
||||
),
|
||||
)]
|
||||
pub(crate) async fn submit_node_monitoring_results(
|
||||
@@ -198,7 +198,7 @@ async fn get_mixnode_stake_saturation(
|
||||
),
|
||||
path = "/v1/status/mixnode/{mix_id}/inclusion-probability",
|
||||
responses(
|
||||
(status = 200, body = nym_api_requests::models::InclusionProbabilityResponse)
|
||||
(status = 200, body = InclusionProbabilityResponse)
|
||||
)
|
||||
)]
|
||||
#[deprecated]
|
||||
@@ -217,7 +217,7 @@ async fn get_mixnode_inclusion_probability(
|
||||
get,
|
||||
path = "/v1/status/mixnodes/inclusion-probability",
|
||||
responses(
|
||||
(status = 200, body = nym_api_requests::models::AllInclusionProbabilitiesResponse)
|
||||
(status = 200, body = AllInclusionProbabilitiesResponse)
|
||||
)
|
||||
)]
|
||||
#[deprecated]
|
||||
|
||||
@@ -22,7 +22,6 @@ use std::fmt::Display;
|
||||
use thiserror::Error;
|
||||
use time::{Date, OffsetDateTime};
|
||||
use tracing::error;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
#[error("Received uptime value was within 0-100 range (got {received})")]
|
||||
@@ -129,17 +128,14 @@ impl From<Uptime> for Performance {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize, Debug, JsonSchema, ToSchema)]
|
||||
#[derive(Clone, Serialize, Deserialize, Debug, JsonSchema)]
|
||||
pub struct MixnodeStatusReport {
|
||||
#[schema(value_type = u32)]
|
||||
pub(crate) mix_id: NodeId,
|
||||
#[schema(value_type = String)]
|
||||
pub(crate) identity: IdentityKey,
|
||||
#[schema(value_type = u8)]
|
||||
|
||||
pub(crate) most_recent: Uptime,
|
||||
#[schema(value_type = u8)]
|
||||
|
||||
pub(crate) last_hour: Uptime,
|
||||
#[schema(value_type = u8)]
|
||||
pub(crate) last_day: Uptime,
|
||||
}
|
||||
|
||||
@@ -319,12 +315,8 @@ impl From<HistoricalUptime> for OldHistoricalUptimeResponse {
|
||||
|
||||
// TODO rocket remove smurf name after eliminating `rocket`
|
||||
pub(crate) type AxumResult<T> = Result<T, AxumErrorResponse>;
|
||||
|
||||
// #[derive(ToSchema, ToResponse)]
|
||||
// #[schema(title = "ErrorResponse")]
|
||||
pub(crate) struct AxumErrorResponse {
|
||||
message: RequestError,
|
||||
// #[schema(value_type = u16)]
|
||||
status: StatusCode,
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ pub(crate) fn legacy_nym_node_routes() -> Router<AppState> {
|
||||
get,
|
||||
path = "/v1/gateways/described",
|
||||
responses(
|
||||
(status = 200, body = Vec<LegacyDescribedGateway>)
|
||||
(status = 200, body = Vec<DescribedGateway>)
|
||||
)
|
||||
)]
|
||||
#[deprecated]
|
||||
@@ -81,7 +81,7 @@ async fn get_gateways_described(
|
||||
get,
|
||||
path = "/v1/mixnodes/described",
|
||||
responses(
|
||||
(status = 200, body = Vec<LegacyDescribedMixNode>)
|
||||
(status = 200, body = Vec<DescribedMixNode>)
|
||||
)
|
||||
)]
|
||||
#[deprecated]
|
||||
|
||||
@@ -12,7 +12,7 @@ use nym_api_requests::nym_nodes::{CachedNodesResponse, FullFatNode};
|
||||
tag = "Unstable Nym Nodes",
|
||||
get,
|
||||
params(NodesParamsWithRole),
|
||||
path = "",
|
||||
path = "/",
|
||||
context_path = "/v1/unstable/nym-nodes/full-fat",
|
||||
responses(
|
||||
// (status = 200, body = CachedNodesResponse<FullFatNode>)
|
||||
|
||||
@@ -88,7 +88,6 @@ struct NodesParamsWithRole {
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, utoipa::IntoParams)]
|
||||
#[into_params(parameter_in = Query)]
|
||||
struct NodesParams {
|
||||
#[allow(dead_code)]
|
||||
semver_compatibility: Option<String>,
|
||||
|
||||
@@ -12,7 +12,7 @@ use nym_api_requests::nym_nodes::{CachedNodesResponse, SemiSkimmedNode};
|
||||
tag = "Unstable Nym Nodes",
|
||||
get,
|
||||
params(NodesParamsWithRole),
|
||||
path = "",
|
||||
path = "/",
|
||||
context_path = "/v1/unstable/nym-nodes/semi-skimmed",
|
||||
responses(
|
||||
// (status = 200, body = CachedNodesResponse<SemiSkimmedNode>)
|
||||
|
||||
@@ -9,20 +9,16 @@ use crate::support::caching::Cache;
|
||||
use crate::support::http::state::AppState;
|
||||
use axum::extract::{Query, State};
|
||||
use axum::Json;
|
||||
use nym_api_requests::models::{
|
||||
NodeAnnotation, NymNodeDescription, OffsetDateTimeJsonSchemaWrapper,
|
||||
};
|
||||
use nym_api_requests::models::{NodeAnnotation, NymNodeDescription};
|
||||
use nym_api_requests::nym_nodes::{
|
||||
CachedNodesResponse, NodeRole, NodeRoleQueryParam, PaginatedCachedNodesResponse, SkimmedNode,
|
||||
};
|
||||
use nym_api_requests::pagination::PaginatedResponse;
|
||||
use nym_mixnet_contract_common::NodeId;
|
||||
use nym_topology::CachedEpochRewardedSet;
|
||||
use std::collections::HashMap;
|
||||
use std::future::Future;
|
||||
use tokio::sync::RwLockReadGuard;
|
||||
use tracing::trace;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
pub type PaginatedSkimmedNodes = AxumResult<Json<PaginatedCachedNodesResponse<SkimmedNode>>>;
|
||||
|
||||
@@ -274,25 +270,16 @@ async fn nodes_basic(
|
||||
)))
|
||||
}
|
||||
|
||||
#[allow(dead_code)] // not dead, used in OpenAPI docs
|
||||
#[derive(ToSchema)]
|
||||
#[schema(title = "PaginatedCachedNodesResponse")]
|
||||
pub struct PaginatedCachedNodesResponseSchema {
|
||||
pub refreshed_at: OffsetDateTimeJsonSchemaWrapper,
|
||||
#[schema(value_type = SkimmedNode)]
|
||||
pub nodes: PaginatedResponse<SkimmedNode>,
|
||||
}
|
||||
|
||||
/// Return all Nym Nodes and optionally legacy mixnodes/gateways (if `no-legacy` flag is not used)
|
||||
/// that are currently bonded.
|
||||
#[utoipa::path(
|
||||
tag = "Unstable Nym Nodes",
|
||||
get,
|
||||
params(NodesParamsWithRole),
|
||||
path = "",
|
||||
path = "/",
|
||||
context_path = "/v1/unstable/nym-nodes/skimmed",
|
||||
responses(
|
||||
(status = 200, body = PaginatedCachedNodesResponseSchema)
|
||||
(status = 200, body = PaginatedCachedNodesResponse<SkimmedNode>)
|
||||
)
|
||||
)]
|
||||
pub(super) async fn nodes_basic_all(
|
||||
@@ -325,7 +312,7 @@ pub(super) async fn nodes_basic_all(
|
||||
path = "/active",
|
||||
context_path = "/v1/unstable/nym-nodes/skimmed",
|
||||
responses(
|
||||
(status = 200, body = PaginatedCachedNodesResponseSchema)
|
||||
(status = 200, body = PaginatedCachedNodesResponse<SkimmedNode>)
|
||||
)
|
||||
)]
|
||||
pub(super) async fn nodes_basic_active(
|
||||
@@ -377,7 +364,7 @@ async fn mixnodes_basic(
|
||||
path = "/mixnodes/all",
|
||||
context_path = "/v1/unstable/nym-nodes/skimmed",
|
||||
responses(
|
||||
(status = 200, body = PaginatedCachedNodesResponseSchema)
|
||||
(status = 200, body = PaginatedCachedNodesResponse<SkimmedNode>)
|
||||
)
|
||||
)]
|
||||
pub(super) async fn mixnodes_basic_all(
|
||||
@@ -396,7 +383,7 @@ pub(super) async fn mixnodes_basic_all(
|
||||
path = "/mixnodes/active",
|
||||
context_path = "/v1/unstable/nym-nodes/skimmed",
|
||||
responses(
|
||||
(status = 200, body = PaginatedCachedNodesResponseSchema)
|
||||
(status = 200, body = PaginatedCachedNodesResponse<SkimmedNode>)
|
||||
)
|
||||
)]
|
||||
pub(super) async fn mixnodes_basic_active(
|
||||
@@ -434,7 +421,7 @@ async fn entry_gateways_basic(
|
||||
path = "/entry-gateways/active",
|
||||
context_path = "/v1/unstable/nym-nodes/skimmed",
|
||||
responses(
|
||||
(status = 200, body = PaginatedCachedNodesResponseSchema)
|
||||
(status = 200, body = PaginatedCachedNodesResponse<SkimmedNode>)
|
||||
)
|
||||
)]
|
||||
pub(super) async fn entry_gateways_basic_active(
|
||||
@@ -453,7 +440,7 @@ pub(super) async fn entry_gateways_basic_active(
|
||||
path = "/entry-gateways/all",
|
||||
context_path = "/v1/unstable/nym-nodes/skimmed",
|
||||
responses(
|
||||
(status = 200, body = PaginatedCachedNodesResponseSchema)
|
||||
(status = 200, body = PaginatedCachedNodesResponse<SkimmedNode>)
|
||||
)
|
||||
)]
|
||||
pub(super) async fn entry_gateways_basic_all(
|
||||
@@ -491,7 +478,7 @@ async fn exit_gateways_basic(
|
||||
path = "/exit-gateways/active",
|
||||
context_path = "/v1/unstable/nym-nodes/skimmed",
|
||||
responses(
|
||||
(status = 200, body = PaginatedCachedNodesResponseSchema)
|
||||
(status = 200, body = PaginatedCachedNodesResponse<SkimmedNode>)
|
||||
)
|
||||
)]
|
||||
pub(super) async fn exit_gateways_basic_active(
|
||||
@@ -510,7 +497,7 @@ pub(super) async fn exit_gateways_basic_active(
|
||||
path = "/exit-gateways/all",
|
||||
context_path = "/v1/unstable/nym-nodes/skimmed",
|
||||
responses(
|
||||
(status = 200, body = PaginatedCachedNodesResponseSchema)
|
||||
(status = 200, body = PaginatedCachedNodesResponse<SkimmedNode>)
|
||||
)
|
||||
)]
|
||||
pub(super) async fn exit_gateways_basic_all(
|
||||
|
||||
@@ -14,8 +14,6 @@ pub struct PaginationRequest {
|
||||
}
|
||||
|
||||
#[derive(Deserialize, IntoParams, ToSchema)]
|
||||
#[schema(title = "NodeId")]
|
||||
#[schema(as = NodeId)]
|
||||
#[into_params(parameter_in = Path)]
|
||||
pub(crate) struct NodeIdParam {
|
||||
#[schema(value_type = u32)]
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user