Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 666ce5e368 | |||
| dbb65259ed | |||
| 38896e6959 | |||
| a56068e28a | |||
| 9a4293a5b9 | |||
| cdddb44099 | |||
| d309b44ad7 | |||
| d062524d32 | |||
| 89eea3100e | |||
| d893c806c2 | |||
| 7846058802 | |||
| f705884a53 |
Generated
+321
-88
@@ -869,9 +869,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "blake3"
|
||||
version = "1.6.1"
|
||||
version = "1.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "675f87afced0413c9bb02843499dbbd3882a237645883f71a2b59644a6d2f753"
|
||||
checksum = "b17679a8d69b6d7fd9cd9801a536cec9fa5e5970b69f9d4747f70b39b031f5e7"
|
||||
dependencies = [
|
||||
"arrayref",
|
||||
"arrayvec",
|
||||
@@ -1184,9 +1184,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.32"
|
||||
version = "4.5.34"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6088f3ae8c3608d19260cd7445411865a485688711b78b5be70d78cd96136f83"
|
||||
checksum = "e958897981290da2a852763fe9cdb89cd36977a5d729023127095fa94d95e2ff"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
@@ -1194,9 +1194,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.32"
|
||||
version = "4.5.34"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "22a7ef7f676155edfb82daa97f99441f3ebf4a58d5e32f295a56259f1b6facc8"
|
||||
checksum = "83b0f35019843db2160b5bb19ae09b4e6411ac33fc6a712003c33e03090e2489"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
@@ -1206,9 +1206,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap_complete"
|
||||
version = "4.5.46"
|
||||
version = "4.5.47"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f5c5508ea23c5366f77e53f5a0070e5a84e51687ec3ef9e0464c86dc8d13ce98"
|
||||
checksum = "c06f5378ea264ad4f82bbc826628b5aad714a75abf6ece087e923010eb937fb6"
|
||||
dependencies = [
|
||||
"clap",
|
||||
]
|
||||
@@ -2016,9 +2016,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "deranged"
|
||||
version = "0.3.11"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4"
|
||||
checksum = "28cfac68e08048ae1883171632c2aef3ebc555621ae56fbccce1cbf22dd7f058"
|
||||
dependencies = [
|
||||
"powerfmt",
|
||||
"serde",
|
||||
@@ -2805,8 +2805,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"js-sys",
|
||||
"libc",
|
||||
"wasi 0.13.3+wasi-0.2.2",
|
||||
"wasm-bindgen",
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
@@ -3402,19 +3404,20 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "hyper-rustls"
|
||||
version = "0.26.0"
|
||||
version = "0.27.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a0bea761b46ae2b24eb4aef630d8d1c398157b6fc29e6350ecf090a0b70c952c"
|
||||
checksum = "2d191583f3da1305256f22463b9bb0471acad48a4e534a5218b9963e9c1f59b2"
|
||||
dependencies = [
|
||||
"futures-util",
|
||||
"http 1.3.1",
|
||||
"hyper 1.6.0",
|
||||
"hyper-util",
|
||||
"rustls 0.22.4",
|
||||
"rustls 0.23.25",
|
||||
"rustls-pki-types",
|
||||
"tokio",
|
||||
"tokio-rustls 0.25.0",
|
||||
"tokio-rustls 0.26.2",
|
||||
"tower-service",
|
||||
"webpki-roots 0.26.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3728,6 +3731,7 @@ dependencies = [
|
||||
"number_prefix",
|
||||
"portable-atomic",
|
||||
"unicode-width 0.2.0",
|
||||
"vt100",
|
||||
"web-time",
|
||||
]
|
||||
|
||||
@@ -3816,7 +3820,7 @@ dependencies = [
|
||||
"socket2",
|
||||
"widestring",
|
||||
"windows-sys 0.48.0",
|
||||
"winreg 0.50.0",
|
||||
"winreg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4129,9 +4133,9 @@ checksum = "9374ef4228402d4b7e403e5838cb880d9ee663314b0a900d5a6aabf0c213552e"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.26"
|
||||
version = "0.4.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e"
|
||||
checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
|
||||
|
||||
[[package]]
|
||||
name = "loom"
|
||||
@@ -4740,7 +4744,7 @@ dependencies = [
|
||||
"pin-project",
|
||||
"rand 0.8.5",
|
||||
"rand_chacha 0.3.1",
|
||||
"reqwest 0.12.4",
|
||||
"reqwest 0.12.15",
|
||||
"schemars",
|
||||
"semver 1.0.26",
|
||||
"serde",
|
||||
@@ -4908,6 +4912,7 @@ dependencies = [
|
||||
"schemars",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tracing",
|
||||
"tracing-opentelemetry",
|
||||
"tracing-subscriber",
|
||||
"tracing-tree",
|
||||
@@ -5311,7 +5316,7 @@ dependencies = [
|
||||
"nym-network-defaults",
|
||||
"nym-validator-client",
|
||||
"rand 0.8.5",
|
||||
"reqwest 0.12.4",
|
||||
"reqwest 0.12.15",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sqlx",
|
||||
@@ -5342,7 +5347,7 @@ dependencies = [
|
||||
"nym-http-api-client",
|
||||
"nym-http-api-common",
|
||||
"nym-serde-helpers",
|
||||
"reqwest 0.12.4",
|
||||
"reqwest 0.12.15",
|
||||
"schemars",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@@ -5538,7 +5543,7 @@ dependencies = [
|
||||
name = "nym-exit-policy"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"reqwest 0.12.4",
|
||||
"reqwest 0.12.15",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror 2.0.12",
|
||||
@@ -5563,7 +5568,7 @@ name = "nym-explorer-client"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"nym-explorer-api-requests",
|
||||
"reqwest 0.12.4",
|
||||
"reqwest 0.12.15",
|
||||
"serde",
|
||||
"thiserror 2.0.12",
|
||||
"tokio",
|
||||
@@ -5774,7 +5779,7 @@ dependencies = [
|
||||
"mime",
|
||||
"nym-bin-common",
|
||||
"once_cell",
|
||||
"reqwest 0.12.4",
|
||||
"reqwest 0.12.15",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror 2.0.12",
|
||||
@@ -5889,7 +5894,7 @@ dependencies = [
|
||||
"nym-wireguard",
|
||||
"nym-wireguard-types",
|
||||
"rand 0.8.5",
|
||||
"reqwest 0.12.4",
|
||||
"reqwest 0.12.15",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror 2.0.12",
|
||||
@@ -6038,7 +6043,7 @@ dependencies = [
|
||||
"petgraph",
|
||||
"rand 0.8.5",
|
||||
"rand_chacha 0.3.1",
|
||||
"reqwest 0.12.4",
|
||||
"reqwest 0.12.15",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tokio",
|
||||
@@ -6085,7 +6090,7 @@ dependencies = [
|
||||
"publicsuffix",
|
||||
"rand 0.8.5",
|
||||
"regex",
|
||||
"reqwest 0.12.4",
|
||||
"reqwest 0.12.15",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sqlx",
|
||||
@@ -6105,22 +6110,25 @@ version = "1.8.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"arc-swap",
|
||||
"arrayref",
|
||||
"async-trait",
|
||||
"axum 0.7.9",
|
||||
"axum-extra",
|
||||
"bip39",
|
||||
"blake2 0.8.1",
|
||||
"bs58",
|
||||
"cargo_metadata 0.18.1",
|
||||
"celes",
|
||||
"chacha",
|
||||
"clap",
|
||||
"colored",
|
||||
"csv",
|
||||
"cupid",
|
||||
"dashmap",
|
||||
"futures",
|
||||
"headers",
|
||||
"human-repr",
|
||||
"humantime-serde",
|
||||
"indicatif",
|
||||
"ipnetwork",
|
||||
"lioness",
|
||||
"nym-authenticator",
|
||||
"nym-bin-common",
|
||||
"nym-client-core-config-types",
|
||||
@@ -6142,6 +6150,8 @@ dependencies = [
|
||||
"nym-sphinx-addressing",
|
||||
"nym-sphinx-forwarding",
|
||||
"nym-sphinx-framing",
|
||||
"nym-sphinx-params",
|
||||
"nym-sphinx-routing",
|
||||
"nym-sphinx-types",
|
||||
"nym-task",
|
||||
"nym-topology",
|
||||
@@ -6151,10 +6161,8 @@ dependencies = [
|
||||
"nym-wireguard",
|
||||
"nym-wireguard-types",
|
||||
"rand 0.8.5",
|
||||
"semver 1.0.26",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"si-scale",
|
||||
"sysinfo",
|
||||
"thiserror 2.0.12",
|
||||
"time",
|
||||
@@ -6163,6 +6171,7 @@ dependencies = [
|
||||
"toml 0.8.20",
|
||||
"tower-http",
|
||||
"tracing",
|
||||
"tracing-indicatif",
|
||||
"tracing-subscriber",
|
||||
"url",
|
||||
"utoipa",
|
||||
@@ -6255,7 +6264,7 @@ dependencies = [
|
||||
"rand 0.8.5",
|
||||
"rand_chacha 0.3.1",
|
||||
"regex",
|
||||
"reqwest 0.12.4",
|
||||
"reqwest 0.12.15",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_json_path",
|
||||
@@ -6284,7 +6293,7 @@ dependencies = [
|
||||
"chrono",
|
||||
"nym-crypto",
|
||||
"nym-http-api-client",
|
||||
"reqwest 0.12.4",
|
||||
"reqwest 0.12.15",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tracing",
|
||||
@@ -6433,7 +6442,7 @@ dependencies = [
|
||||
"parking_lot",
|
||||
"pretty_env_logger",
|
||||
"rand 0.8.5",
|
||||
"reqwest 0.12.4",
|
||||
"reqwest 0.12.15",
|
||||
"serde",
|
||||
"tap",
|
||||
"tempfile",
|
||||
@@ -6542,7 +6551,7 @@ dependencies = [
|
||||
"nym-validator-client",
|
||||
"pin-project",
|
||||
"rand 0.8.5",
|
||||
"reqwest 0.12.4",
|
||||
"reqwest 0.12.15",
|
||||
"schemars",
|
||||
"serde",
|
||||
"tap",
|
||||
@@ -6827,7 +6836,7 @@ dependencies = [
|
||||
"nym-sphinx-routing",
|
||||
"nym-sphinx-types",
|
||||
"rand 0.8.5",
|
||||
"reqwest 0.12.4",
|
||||
"reqwest 0.12.15",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror 2.0.12",
|
||||
@@ -6865,7 +6874,7 @@ dependencies = [
|
||||
"nym-mixnet-contract-common",
|
||||
"nym-validator-client",
|
||||
"nym-vesting-contract-common",
|
||||
"reqwest 0.12.4",
|
||||
"reqwest 0.12.15",
|
||||
"schemars",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@@ -6913,7 +6922,7 @@ dependencies = [
|
||||
"nym-serde-helpers",
|
||||
"nym-vesting-contract-common",
|
||||
"prost 0.13.5",
|
||||
"reqwest 0.12.4",
|
||||
"reqwest 0.12.15",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha2 0.10.8",
|
||||
@@ -7108,7 +7117,7 @@ dependencies = [
|
||||
"nym-bin-common",
|
||||
"nym-config",
|
||||
"nym-task",
|
||||
"reqwest 0.12.4",
|
||||
"reqwest 0.12.15",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha2 0.10.8",
|
||||
@@ -7135,7 +7144,7 @@ dependencies = [
|
||||
"nym-task",
|
||||
"nym-validator-client",
|
||||
"nyxd-scraper",
|
||||
"reqwest 0.12.4",
|
||||
"reqwest 0.12.15",
|
||||
"schemars",
|
||||
"serde",
|
||||
"sqlx",
|
||||
@@ -7186,9 +7195,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.21.1"
|
||||
version = "1.21.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d75b0bedcc4fe52caa0e03d9f1151a323e4aa5e2d78ba3580400cd3c9e2bc4bc"
|
||||
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
|
||||
|
||||
[[package]]
|
||||
name = "oorandom"
|
||||
@@ -7934,6 +7943,60 @@ version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3"
|
||||
|
||||
[[package]]
|
||||
name = "quinn"
|
||||
version = "0.11.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3bd15a6f2967aef83887dcb9fec0014580467e33720d073560cf015a5683012"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"cfg_aliases",
|
||||
"pin-project-lite",
|
||||
"quinn-proto",
|
||||
"quinn-udp",
|
||||
"rustc-hash",
|
||||
"rustls 0.23.25",
|
||||
"socket2",
|
||||
"thiserror 2.0.12",
|
||||
"tokio",
|
||||
"tracing",
|
||||
"web-time",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quinn-proto"
|
||||
version = "0.11.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b820744eb4dc9b57a3398183639c511b5a26d2ed702cedd3febaa1393caa22cc"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"getrandom 0.3.1",
|
||||
"rand 0.9.0",
|
||||
"ring",
|
||||
"rustc-hash",
|
||||
"rustls 0.23.25",
|
||||
"rustls-pki-types",
|
||||
"slab",
|
||||
"thiserror 2.0.12",
|
||||
"tinyvec",
|
||||
"tracing",
|
||||
"web-time",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quinn-udp"
|
||||
version = "0.5.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "541d0f57c6ec747a90738a52741d3221f7960e8ac2f0ff4b1a63680e033b4ab5"
|
||||
dependencies = [
|
||||
"cfg_aliases",
|
||||
"libc",
|
||||
"once_cell",
|
||||
"socket2",
|
||||
"tracing",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.40"
|
||||
@@ -8142,14 +8205,14 @@ dependencies = [
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-futures",
|
||||
"web-sys",
|
||||
"winreg 0.50.0",
|
||||
"winreg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "reqwest"
|
||||
version = "0.12.4"
|
||||
version = "0.12.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "566cafdd92868e0939d3fb961bd0dc25fcfaaed179291093b3d43e6b3150ea10"
|
||||
checksum = "d19c46a6fdd48bc4dab94b6103fccc55d34c67cc0ad04653aad4ea2a07cd7bbb"
|
||||
dependencies = [
|
||||
"async-compression",
|
||||
"base64 0.22.1",
|
||||
@@ -8160,7 +8223,7 @@ dependencies = [
|
||||
"http-body 1.0.1",
|
||||
"http-body-util",
|
||||
"hyper 1.6.0",
|
||||
"hyper-rustls 0.26.0",
|
||||
"hyper-rustls 0.27.5",
|
||||
"hyper-util",
|
||||
"ipnet",
|
||||
"js-sys",
|
||||
@@ -8169,17 +8232,19 @@ dependencies = [
|
||||
"once_cell",
|
||||
"percent-encoding",
|
||||
"pin-project-lite",
|
||||
"rustls 0.22.4",
|
||||
"quinn",
|
||||
"rustls 0.23.25",
|
||||
"rustls-pemfile 2.2.0",
|
||||
"rustls-pki-types",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_urlencoded",
|
||||
"sync_wrapper 0.1.2",
|
||||
"sync_wrapper 1.0.2",
|
||||
"tokio",
|
||||
"tokio-rustls 0.25.0",
|
||||
"tokio-rustls 0.26.2",
|
||||
"tokio-socks",
|
||||
"tokio-util",
|
||||
"tower 0.5.2",
|
||||
"tower-service",
|
||||
"url",
|
||||
"wasm-bindgen",
|
||||
@@ -8187,7 +8252,7 @@ dependencies = [
|
||||
"wasm-streams",
|
||||
"web-sys",
|
||||
"webpki-roots 0.26.8",
|
||||
"winreg 0.52.0",
|
||||
"windows-registry",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -8465,6 +8530,20 @@ dependencies = [
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls"
|
||||
version = "0.23.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "822ee9188ac4ec04a2f0531e55d035fb2de73f18b41a63c70c2712503b6fb13c"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"ring",
|
||||
"rustls-pki-types",
|
||||
"rustls-webpki 0.103.1",
|
||||
"subtle 2.6.1",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls-native-certs"
|
||||
version = "0.6.3"
|
||||
@@ -8513,6 +8592,9 @@ name = "rustls-pki-types"
|
||||
version = "1.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "917ce264624a4b4db1c364dcc35bfca9ded014d0a958cd47ad3e960e988ea51c"
|
||||
dependencies = [
|
||||
"web-time",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls-webpki"
|
||||
@@ -8535,6 +8617,17 @@ dependencies = [
|
||||
"untrusted",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls-webpki"
|
||||
version = "0.103.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fef8b8769aaccf73098557a87cd1816b4f9c7c16811c9c77142aa695c16f2c03"
|
||||
dependencies = [
|
||||
"ring",
|
||||
"rustls-pki-types",
|
||||
"untrusted",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustversion"
|
||||
version = "1.0.19"
|
||||
@@ -9578,6 +9671,9 @@ name = "sync_wrapper"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "synstructure"
|
||||
@@ -9650,9 +9746,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.19.0"
|
||||
version = "3.19.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "488960f40a3fd53d72c2a29a58722561dee8afdd175bd88e3db4677d7b2ba600"
|
||||
checksum = "7437ac7763b9b123ccf33c338a5cc1bac6f69b45a136c19bdd8a65e3916435bf"
|
||||
dependencies = [
|
||||
"fastrand 2.3.0",
|
||||
"getrandom 0.3.1",
|
||||
@@ -9896,9 +9992,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.3.39"
|
||||
version = "0.3.41"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dad298b01a40a23aac4580b67e3dbedb7cc8402f3592d7f49469de2ea4aecdd8"
|
||||
checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40"
|
||||
dependencies = [
|
||||
"deranged",
|
||||
"itoa",
|
||||
@@ -9914,15 +10010,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "time-core"
|
||||
version = "0.1.3"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "765c97a5b985b7c11d7bc27fa927dc4fe6af3a6dfb021d28deb60d3bf51e76ef"
|
||||
checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c"
|
||||
|
||||
[[package]]
|
||||
name = "time-macros"
|
||||
version = "0.2.20"
|
||||
version = "0.2.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e8093bc3e81c3bc5f7879de09619d06c9a5a5e45ca44dfeeb7225bae38005c5c"
|
||||
checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49"
|
||||
dependencies = [
|
||||
"num-conv",
|
||||
"time-core",
|
||||
@@ -10050,6 +10146,16 @@ dependencies = [
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-rustls"
|
||||
version = "0.26.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b"
|
||||
dependencies = [
|
||||
"rustls 0.23.25",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-socks"
|
||||
version = "0.5.2"
|
||||
@@ -10319,6 +10425,18 @@ dependencies = [
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-indicatif"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8201ca430e0cd893ef978226fd3516c06d9c494181c8bf4e5b32e30ed4b40aa1"
|
||||
dependencies = [
|
||||
"indicatif",
|
||||
"tracing",
|
||||
"tracing-core",
|
||||
"tracing-subscriber",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-log"
|
||||
version = "0.1.4"
|
||||
@@ -10603,9 +10721,9 @@ checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e"
|
||||
|
||||
[[package]]
|
||||
name = "uniffi"
|
||||
version = "0.29.0"
|
||||
version = "0.29.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba62a57e90f9baed5ad02a71a0870180fa1cc35499093b2d21be2edfb68ec0f7"
|
||||
checksum = "fe34585ac0275accf6c284d0080cc2840f3898c551cda869ec291b5a4218712c"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"camino",
|
||||
@@ -10619,9 +10737,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "uniffi_bindgen"
|
||||
version = "0.29.0"
|
||||
version = "0.29.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2242f35214f1e0e3b47c495d340c69f649f9a9ece3a943a29e275686cc884533"
|
||||
checksum = "1a792af1424cc8b3c43b44c1a6cb7935ed1fbe5584a74f70e8bab9799740266d"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"camino",
|
||||
@@ -10642,9 +10760,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "uniffi_build"
|
||||
version = "0.29.0"
|
||||
version = "0.29.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c887a6c9a2857d8dc2ab0c8d578e8aa4978145b4fd65ed44296341e89aebc3cc"
|
||||
checksum = "00c4138211f2ae951018fcce6a978e1fcd1a47c3fd0bc0d5472a520520060db1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"camino",
|
||||
@@ -10653,22 +10771,21 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "uniffi_core"
|
||||
version = "0.29.0"
|
||||
version = "0.29.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cad9fbdeb7ae4daf8d0f7704a3b638c37018eb16bb701e30fa17a2dd3e2d39c1"
|
||||
checksum = "c18baace68a52666d33d12d73ca335ecf27a302202cefb53b1f974512bb72417"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bytes",
|
||||
"once_cell",
|
||||
"paste",
|
||||
"static_assertions",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uniffi_internal_macros"
|
||||
version = "0.29.0"
|
||||
version = "0.29.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "22a9dba1d78b9ce429439891089c223478043d52a1c3176a0fcea2b5573a7fcf"
|
||||
checksum = "f9902d4ed16c65e6c0222241024dd0bfeed07ea3deb7c470eb175e5f5ef406cd"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"syn 2.0.98",
|
||||
@@ -10676,9 +10793,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "uniffi_macros"
|
||||
version = "0.29.0"
|
||||
version = "0.29.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78dd5f8eefba5898b901086f5e7916da67b9a5286a01cc44e910cd75fa37c630"
|
||||
checksum = "9d82c82ef945c51082d8763635334b994e63e77650f09d0fae6d28dd08b1de83"
|
||||
dependencies = [
|
||||
"camino",
|
||||
"fs-err",
|
||||
@@ -10693,9 +10810,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "uniffi_meta"
|
||||
version = "0.29.0"
|
||||
version = "0.29.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9d5965b1d4ffacef1eaa72fef9c00d2491641e87ad910f6c5859b9c503ddb16a"
|
||||
checksum = "8d6027b971c2aa86350dd180aee9819729c7b99bacd381534511ff29d2c09cea"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"siphasher 0.3.11",
|
||||
@@ -10704,9 +10821,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "uniffi_udl"
|
||||
version = "0.29.0"
|
||||
version = "0.29.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "279b82bac9a382c796a0d210bb8354a0b813499b28aa1de046c85d78ca389805"
|
||||
checksum = "52300b7a4ab02dc159a038a13d5bfe27aefbad300d91b0b501b3dda094c1e0a2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"textwrap",
|
||||
@@ -10914,6 +11031,39 @@ version = "0.9.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||
|
||||
[[package]]
|
||||
name = "vt100"
|
||||
version = "0.15.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "84cd863bf0db7e392ba3bd04994be3473491b31e66340672af5d11943c6274de"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"log",
|
||||
"unicode-width 0.1.14",
|
||||
"vte",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "vte"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f5022b5fbf9407086c180e9557be968742d839e68346af7792b8592489732197"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"utf8parse",
|
||||
"vte_generate_state_changes",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "vte_generate_state_changes"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2e369bee1b05d510a7b4ed645f5faa90619e05437111783ea5848f28d97d3c2e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "waker-fn"
|
||||
version = "1.2.0"
|
||||
@@ -11298,7 +11448,7 @@ dependencies = [
|
||||
"windows-implement 0.58.0",
|
||||
"windows-interface 0.58.0",
|
||||
"windows-result 0.2.0",
|
||||
"windows-strings",
|
||||
"windows-strings 0.1.0",
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
@@ -11352,6 +11502,17 @@ version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6dccfd733ce2b1753b03b6d3c65edf020262ea35e20ccdf3e288043e6dd620e3"
|
||||
|
||||
[[package]]
|
||||
name = "windows-registry"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4286ad90ddb45071efd1a66dfa43eb02dd0dfbae1545ad6cc3c51cf34d7e8ba3"
|
||||
dependencies = [
|
||||
"windows-result 0.3.1",
|
||||
"windows-strings 0.3.1",
|
||||
"windows-targets 0.53.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-result"
|
||||
version = "0.1.2"
|
||||
@@ -11370,6 +11531,15 @@ dependencies = [
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-result"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06374efe858fab7e4f881500e6e86ec8bc28f9462c47e5a9941a0142ad86b189"
|
||||
dependencies = [
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-strings"
|
||||
version = "0.1.0"
|
||||
@@ -11380,6 +11550,15 @@ dependencies = [
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-strings"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "87fa48cc5d406560701792be122a10132491cff9d0aeb23583cc2dcafc847319"
|
||||
dependencies = [
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.45.0"
|
||||
@@ -11455,13 +11634,29 @@ dependencies = [
|
||||
"windows_aarch64_gnullvm 0.52.6",
|
||||
"windows_aarch64_msvc 0.52.6",
|
||||
"windows_i686_gnu 0.52.6",
|
||||
"windows_i686_gnullvm",
|
||||
"windows_i686_gnullvm 0.52.6",
|
||||
"windows_i686_msvc 0.52.6",
|
||||
"windows_x86_64_gnu 0.52.6",
|
||||
"windows_x86_64_gnullvm 0.52.6",
|
||||
"windows_x86_64_msvc 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.53.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1e4c7e8ceaaf9cb7d7507c974735728ab453b67ef8f18febdd7c11fe59dca8b"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm 0.53.0",
|
||||
"windows_aarch64_msvc 0.53.0",
|
||||
"windows_i686_gnu 0.53.0",
|
||||
"windows_i686_gnullvm 0.53.0",
|
||||
"windows_i686_msvc 0.53.0",
|
||||
"windows_x86_64_gnu 0.53.0",
|
||||
"windows_x86_64_gnullvm 0.53.0",
|
||||
"windows_x86_64_msvc 0.53.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.42.2"
|
||||
@@ -11480,6 +11675,12 @@ version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.53.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.42.2"
|
||||
@@ -11498,6 +11699,12 @@ version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.53.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.42.2"
|
||||
@@ -11516,12 +11723,24 @@ version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.53.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnullvm"
|
||||
version = "0.53.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.42.2"
|
||||
@@ -11540,6 +11759,12 @@ version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.53.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.42.2"
|
||||
@@ -11558,6 +11783,12 @@ version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.53.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.42.2"
|
||||
@@ -11576,6 +11807,12 @@ version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.53.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.42.2"
|
||||
@@ -11594,6 +11831,12 @@ version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.53.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486"
|
||||
|
||||
[[package]]
|
||||
name = "winnow"
|
||||
version = "0.7.3"
|
||||
@@ -11613,16 +11856,6 @@ dependencies = [
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winreg"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a277a57398d4bfa075df44f501a17cfdf8542d224f0d36095a2adc7aee4ef0a5"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen-rt"
|
||||
version = "0.33.0"
|
||||
@@ -11842,7 +12075,7 @@ dependencies = [
|
||||
"nym-crypto",
|
||||
"nym-http-api-client",
|
||||
"rand 0.8.5",
|
||||
"reqwest 0.12.4",
|
||||
"reqwest 0.12.15",
|
||||
"serde",
|
||||
"thiserror 2.0.12",
|
||||
"tokio",
|
||||
|
||||
+7
-6
@@ -203,7 +203,7 @@ bincode = "1.3.3"
|
||||
bip39 = { version = "2.0.0", features = ["zeroize"] }
|
||||
bit-vec = "0.7.0" # can we unify those?
|
||||
bitvec = "1.0.0"
|
||||
blake3 = "1.6.1"
|
||||
blake3 = "1.7.0"
|
||||
bloomfilter = "1.0.14"
|
||||
bs58 = "0.5.1"
|
||||
bytecodec = "0.4.15"
|
||||
@@ -215,7 +215,7 @@ chacha20 = "0.9.0"
|
||||
chacha20poly1305 = "0.10.1"
|
||||
chrono = "0.4.40"
|
||||
cipher = "0.4.3"
|
||||
clap = "4.5.32"
|
||||
clap = "4.5.34"
|
||||
clap_complete = "4.5"
|
||||
clap_complete_fig = "4.5"
|
||||
colored = "2.2"
|
||||
@@ -283,7 +283,7 @@ moka = { version = "0.12", features = ["future"] }
|
||||
nix = "0.27.1"
|
||||
notify = "5.1.0"
|
||||
okapi = "0.7.0"
|
||||
once_cell = "1.21.1"
|
||||
once_cell = "1.21.3"
|
||||
opentelemetry = "0.19.0"
|
||||
opentelemetry-jaeger = "0.18.0"
|
||||
parking_lot = "0.12.3"
|
||||
@@ -302,7 +302,7 @@ rand_pcg = "0.3.1"
|
||||
rand_seeder = "0.2.3"
|
||||
rayon = "1.5.1"
|
||||
regex = "1.10.6"
|
||||
reqwest = { version = "0.12.4", default-features = false }
|
||||
reqwest = { version = "0.12.15", default-features = false }
|
||||
rocket = "0.5.0"
|
||||
rocket_cors = "0.6.0"
|
||||
rocket_okapi = "0.8.0"
|
||||
@@ -331,7 +331,7 @@ tap = "1.0.1"
|
||||
tar = "0.4.44"
|
||||
tempfile = "3.19"
|
||||
thiserror = "2.0"
|
||||
time = "0.3.39"
|
||||
time = "0.3.41"
|
||||
tokio = "1.44"
|
||||
tokio-postgres = "0.7"
|
||||
tokio-stream = "0.1.17"
|
||||
@@ -347,9 +347,10 @@ tracing-log = "0.2"
|
||||
tracing-opentelemetry = "0.19.0"
|
||||
tracing-subscriber = "0.3.19"
|
||||
tracing-tree = "0.2.2"
|
||||
tracing-indicatif = "0.3.9"
|
||||
ts-rs = "10.1.0"
|
||||
tungstenite = { version = "0.20.1", default-features = false }
|
||||
uniffi = "0.29.0"
|
||||
uniffi = "0.29.1"
|
||||
uniffi_build = "0.29.0"
|
||||
url = "2.5"
|
||||
utoipa = "5.2"
|
||||
|
||||
@@ -13,7 +13,7 @@ use std::{fmt, ops::Deref, str::FromStr};
|
||||
#[cfg(feature = "verify")]
|
||||
use hmac::{Hmac, Mac};
|
||||
#[cfg(feature = "verify")]
|
||||
use nym_crypto::asymmetric::encryption::PrivateKey;
|
||||
use nym_crypto::asymmetric::encryption::{PrivateKey, PublicKey};
|
||||
#[cfg(feature = "verify")]
|
||||
use sha2::Sha256;
|
||||
|
||||
@@ -82,16 +82,14 @@ impl GatewayClient {
|
||||
private_ip: IpAddr,
|
||||
nonce: u64,
|
||||
) -> Self {
|
||||
// convert from 1.0 x25519-dalek private key into 2.0 x25519-dalek
|
||||
#[allow(clippy::expect_used)]
|
||||
let static_secret = x25519_dalek::StaticSecret::from(local_secret.to_bytes());
|
||||
let local_public: x25519_dalek::PublicKey = (&static_secret).into();
|
||||
let local_public = PublicKey::from(local_secret);
|
||||
let remote_public = PublicKey::from(remote_public);
|
||||
|
||||
let dh = static_secret.diffie_hellman(&remote_public);
|
||||
let dh = local_secret.diffie_hellman(&remote_public);
|
||||
|
||||
// TODO: change that to use our nym_crypto::hmac module instead
|
||||
#[allow(clippy::expect_used)]
|
||||
let mut mac = HmacSha256::new_from_slice(dh.as_bytes())
|
||||
let mut mac = HmacSha256::new_from_slice(&dh[..])
|
||||
.expect("x25519 shared secret is always 32 bytes long");
|
||||
|
||||
mac.update(local_public.as_bytes());
|
||||
@@ -99,7 +97,7 @@ impl GatewayClient {
|
||||
mac.update(&nonce.to_le_bytes());
|
||||
|
||||
GatewayClient {
|
||||
pub_key: PeerPublicKey::new(local_public),
|
||||
pub_key: PeerPublicKey::new(local_public.into()),
|
||||
private_ip,
|
||||
mac: ClientMac(mac.finalize().into_bytes().to_vec()),
|
||||
}
|
||||
@@ -109,11 +107,8 @@ impl GatewayClient {
|
||||
// Client should perform this step when generating its payload, using its own WG PK
|
||||
#[cfg(feature = "verify")]
|
||||
pub fn verify(&self, gateway_key: &PrivateKey, nonce: u64) -> Result<(), Error> {
|
||||
// convert from 1.0 x25519-dalek private key into 2.0 x25519-dalek
|
||||
#[allow(clippy::expect_used)]
|
||||
let static_secret = x25519_dalek::StaticSecret::from(gateway_key.to_bytes());
|
||||
|
||||
let dh = static_secret.diffie_hellman(&self.pub_key);
|
||||
// use gateways key as a ref to an x25519_dalek key
|
||||
let dh = (gateway_key.as_ref()).diffie_hellman(&self.pub_key);
|
||||
|
||||
// TODO: change that to use our nym_crypto::hmac module instead
|
||||
#[allow(clippy::expect_used)]
|
||||
|
||||
@@ -14,7 +14,7 @@ use std::{fmt, ops::Deref, str::FromStr};
|
||||
#[cfg(feature = "verify")]
|
||||
use hmac::{Hmac, Mac};
|
||||
#[cfg(feature = "verify")]
|
||||
use nym_crypto::asymmetric::encryption::PrivateKey;
|
||||
use nym_crypto::asymmetric::encryption::{PrivateKey, PublicKey};
|
||||
#[cfg(feature = "verify")]
|
||||
use sha2::Sha256;
|
||||
|
||||
@@ -91,16 +91,14 @@ impl GatewayClient {
|
||||
private_ip: IpAddr,
|
||||
nonce: u64,
|
||||
) -> Self {
|
||||
// convert from 1.0 x25519-dalek private key into 2.0 x25519-dalek
|
||||
#[allow(clippy::expect_used)]
|
||||
let static_secret = x25519_dalek::StaticSecret::from(local_secret.to_bytes());
|
||||
let local_public: x25519_dalek::PublicKey = (&static_secret).into();
|
||||
let local_public = PublicKey::from(local_secret);
|
||||
let remote_public = PublicKey::from(remote_public);
|
||||
|
||||
let dh = static_secret.diffie_hellman(&remote_public);
|
||||
let dh = local_secret.diffie_hellman(&remote_public);
|
||||
|
||||
// TODO: change that to use our nym_crypto::hmac module instead
|
||||
#[allow(clippy::expect_used)]
|
||||
let mut mac = HmacSha256::new_from_slice(dh.as_bytes())
|
||||
let mut mac = HmacSha256::new_from_slice(&dh[..])
|
||||
.expect("x25519 shared secret is always 32 bytes long");
|
||||
|
||||
mac.update(local_public.as_bytes());
|
||||
@@ -108,7 +106,7 @@ impl GatewayClient {
|
||||
mac.update(&nonce.to_le_bytes());
|
||||
|
||||
GatewayClient {
|
||||
pub_key: PeerPublicKey::new(local_public),
|
||||
pub_key: PeerPublicKey::new(local_public.into()),
|
||||
private_ip,
|
||||
mac: ClientMac(mac.finalize().into_bytes().to_vec()),
|
||||
}
|
||||
@@ -118,11 +116,8 @@ impl GatewayClient {
|
||||
// Client should perform this step when generating its payload, using its own WG PK
|
||||
#[cfg(feature = "verify")]
|
||||
pub fn verify(&self, gateway_key: &PrivateKey, nonce: u64) -> Result<(), Error> {
|
||||
// convert from 1.0 x25519-dalek private key into 2.0 x25519-dalek
|
||||
#[allow(clippy::expect_used)]
|
||||
let static_secret = x25519_dalek::StaticSecret::from(gateway_key.to_bytes());
|
||||
|
||||
let dh = static_secret.diffie_hellman(&self.pub_key);
|
||||
// use gateways key as a ref to an x25519_dalek key
|
||||
let dh = (gateway_key.as_ref()).diffie_hellman(&self.pub_key);
|
||||
|
||||
// TODO: change that to use our nym_crypto::hmac module instead
|
||||
#[allow(clippy::expect_used)]
|
||||
|
||||
@@ -14,7 +14,7 @@ use std::{fmt, ops::Deref, str::FromStr};
|
||||
#[cfg(feature = "verify")]
|
||||
use hmac::{Hmac, Mac};
|
||||
#[cfg(feature = "verify")]
|
||||
use nym_crypto::asymmetric::encryption::PrivateKey;
|
||||
use nym_crypto::asymmetric::encryption::{PrivateKey, PublicKey};
|
||||
#[cfg(feature = "verify")]
|
||||
use sha2::Sha256;
|
||||
|
||||
@@ -91,16 +91,14 @@ impl GatewayClient {
|
||||
private_ip: IpAddr,
|
||||
nonce: u64,
|
||||
) -> Self {
|
||||
// convert from 1.0 x25519-dalek private key into 2.0 x25519-dalek
|
||||
#[allow(clippy::expect_used)]
|
||||
let static_secret = x25519_dalek::StaticSecret::from(local_secret.to_bytes());
|
||||
let local_public: x25519_dalek::PublicKey = (&static_secret).into();
|
||||
let local_public = PublicKey::from(local_secret);
|
||||
let remote_public = PublicKey::from(remote_public);
|
||||
|
||||
let dh = static_secret.diffie_hellman(&remote_public);
|
||||
let dh = local_secret.diffie_hellman(&remote_public);
|
||||
|
||||
// TODO: change that to use our nym_crypto::hmac module instead
|
||||
#[allow(clippy::expect_used)]
|
||||
let mut mac = HmacSha256::new_from_slice(dh.as_bytes())
|
||||
let mut mac = HmacSha256::new_from_slice(&dh[..])
|
||||
.expect("x25519 shared secret is always 32 bytes long");
|
||||
|
||||
mac.update(local_public.as_bytes());
|
||||
@@ -108,7 +106,7 @@ impl GatewayClient {
|
||||
mac.update(&nonce.to_le_bytes());
|
||||
|
||||
GatewayClient {
|
||||
pub_key: PeerPublicKey::new(local_public),
|
||||
pub_key: PeerPublicKey::new(local_public.into()),
|
||||
private_ip,
|
||||
mac: ClientMac(mac.finalize().into_bytes().to_vec()),
|
||||
}
|
||||
@@ -118,11 +116,8 @@ impl GatewayClient {
|
||||
// Client should perform this step when generating its payload, using its own WG PK
|
||||
#[cfg(feature = "verify")]
|
||||
pub fn verify(&self, gateway_key: &PrivateKey, nonce: u64) -> Result<(), Error> {
|
||||
// convert from 1.0 x25519-dalek private key into 2.0 x25519-dalek
|
||||
#[allow(clippy::expect_used)]
|
||||
let static_secret = x25519_dalek::StaticSecret::from(gateway_key.to_bytes());
|
||||
|
||||
let dh = static_secret.diffie_hellman(&self.pub_key);
|
||||
// use gateways key as a ref to an x25519_dalek key
|
||||
let dh = (gateway_key.as_ref()).diffie_hellman(&self.pub_key);
|
||||
|
||||
// TODO: change that to use our nym_crypto::hmac module instead
|
||||
#[allow(clippy::expect_used)]
|
||||
|
||||
@@ -15,7 +15,7 @@ use std::{fmt, ops::Deref, str::FromStr};
|
||||
#[cfg(feature = "verify")]
|
||||
use hmac::{Hmac, Mac};
|
||||
#[cfg(feature = "verify")]
|
||||
use nym_crypto::asymmetric::encryption::PrivateKey;
|
||||
use nym_crypto::asymmetric::encryption::{PrivateKey, PublicKey};
|
||||
#[cfg(feature = "verify")]
|
||||
use sha2::Sha256;
|
||||
|
||||
@@ -143,16 +143,14 @@ impl GatewayClient {
|
||||
private_ips: IpPair,
|
||||
nonce: u64,
|
||||
) -> Self {
|
||||
// convert from 1.0 x25519-dalek private key into 2.0 x25519-dalek
|
||||
#[allow(clippy::expect_used)]
|
||||
let static_secret = x25519_dalek::StaticSecret::from(local_secret.to_bytes());
|
||||
let local_public: x25519_dalek::PublicKey = (&static_secret).into();
|
||||
let local_public = PublicKey::from(local_secret);
|
||||
let remote_public = PublicKey::from(remote_public);
|
||||
|
||||
let dh = static_secret.diffie_hellman(&remote_public);
|
||||
let dh = local_secret.diffie_hellman(&remote_public);
|
||||
|
||||
// TODO: change that to use our nym_crypto::hmac module instead
|
||||
#[allow(clippy::expect_used)]
|
||||
let mut mac = HmacSha256::new_from_slice(dh.as_bytes())
|
||||
let mut mac = HmacSha256::new_from_slice(&dh[..])
|
||||
.expect("x25519 shared secret is always 32 bytes long");
|
||||
|
||||
mac.update(local_public.as_bytes());
|
||||
@@ -160,7 +158,7 @@ impl GatewayClient {
|
||||
mac.update(&nonce.to_le_bytes());
|
||||
|
||||
GatewayClient {
|
||||
pub_key: PeerPublicKey::new(local_public),
|
||||
pub_key: PeerPublicKey::new(local_public.into()),
|
||||
private_ips,
|
||||
mac: ClientMac(mac.finalize().into_bytes().to_vec()),
|
||||
}
|
||||
@@ -170,11 +168,8 @@ impl GatewayClient {
|
||||
// Client should perform this step when generating its payload, using its own WG PK
|
||||
#[cfg(feature = "verify")]
|
||||
pub fn verify(&self, gateway_key: &PrivateKey, nonce: u64) -> Result<(), Error> {
|
||||
// convert from 1.0 x25519-dalek private key into 2.0 x25519-dalek
|
||||
#[allow(clippy::expect_used)]
|
||||
let static_secret = x25519_dalek::StaticSecret::from(gateway_key.to_bytes());
|
||||
|
||||
let dh = static_secret.diffie_hellman(&self.pub_key);
|
||||
// use gateways key as a ref to an x25519_dalek key
|
||||
let dh = (gateway_key.as_ref()).diffie_hellman(&self.pub_key);
|
||||
|
||||
// TODO: change that to use our nym_crypto::hmac module instead
|
||||
#[allow(clippy::expect_used)]
|
||||
|
||||
@@ -15,7 +15,7 @@ use std::{fmt, ops::Deref, str::FromStr};
|
||||
#[cfg(feature = "verify")]
|
||||
use hmac::{Hmac, Mac};
|
||||
#[cfg(feature = "verify")]
|
||||
use nym_crypto::asymmetric::encryption::PrivateKey;
|
||||
use nym_crypto::asymmetric::encryption::{PrivateKey, PublicKey};
|
||||
#[cfg(feature = "verify")]
|
||||
use sha2::Sha256;
|
||||
|
||||
@@ -143,16 +143,14 @@ impl GatewayClient {
|
||||
private_ips: IpPair,
|
||||
nonce: u64,
|
||||
) -> Self {
|
||||
// convert from 1.0 x25519-dalek private key into 2.0 x25519-dalek
|
||||
#[allow(clippy::expect_used)]
|
||||
let static_secret = x25519_dalek::StaticSecret::from(local_secret.to_bytes());
|
||||
let local_public: x25519_dalek::PublicKey = (&static_secret).into();
|
||||
let local_public = PublicKey::from(local_secret);
|
||||
let remote_public = PublicKey::from(remote_public);
|
||||
|
||||
let dh = static_secret.diffie_hellman(&remote_public);
|
||||
let dh = local_secret.diffie_hellman(&remote_public);
|
||||
|
||||
// TODO: change that to use our nym_crypto::hmac module instead
|
||||
#[allow(clippy::expect_used)]
|
||||
let mut mac = HmacSha256::new_from_slice(dh.as_bytes())
|
||||
let mut mac = HmacSha256::new_from_slice(&dh[..])
|
||||
.expect("x25519 shared secret is always 32 bytes long");
|
||||
|
||||
mac.update(local_public.as_bytes());
|
||||
@@ -160,7 +158,7 @@ impl GatewayClient {
|
||||
mac.update(&nonce.to_le_bytes());
|
||||
|
||||
GatewayClient {
|
||||
pub_key: PeerPublicKey::new(local_public),
|
||||
pub_key: PeerPublicKey::new(local_public.into()),
|
||||
private_ips,
|
||||
mac: ClientMac(mac.finalize().into_bytes().to_vec()),
|
||||
}
|
||||
@@ -170,11 +168,8 @@ impl GatewayClient {
|
||||
// Client should perform this step when generating its payload, using its own WG PK
|
||||
#[cfg(feature = "verify")]
|
||||
pub fn verify(&self, gateway_key: &PrivateKey, nonce: u64) -> Result<(), Error> {
|
||||
// convert from 1.0 x25519-dalek private key into 2.0 x25519-dalek
|
||||
#[allow(clippy::expect_used)]
|
||||
let static_secret = x25519_dalek::StaticSecret::from(gateway_key.to_bytes());
|
||||
|
||||
let dh = static_secret.diffie_hellman(&self.pub_key);
|
||||
// use gateways key as a ref to an x25519_dalek key
|
||||
let dh = (gateway_key.as_ref()).diffie_hellman(&self.pub_key);
|
||||
|
||||
// TODO: change that to use our nym_crypto::hmac module instead
|
||||
#[allow(clippy::expect_used)]
|
||||
|
||||
@@ -21,6 +21,7 @@ serde_json = { workspace = true, optional = true }
|
||||
## tracing
|
||||
tracing-subscriber = { workspace = true, features = ["env-filter"], optional = true }
|
||||
tracing-tree = { workspace = true, optional = true }
|
||||
tracing = { workspace = true, optional = true }
|
||||
opentelemetry-jaeger = { workspace = true, features = ["rt-tokio", "collector_client", "isahc_collector_client"], optional = true }
|
||||
tracing-opentelemetry = { workspace = true, optional = true }
|
||||
utoipa = { workspace = true, optional = true }
|
||||
@@ -35,7 +36,7 @@ default = []
|
||||
openapi = ["utoipa"]
|
||||
output_format = ["serde_json", "dep:clap"]
|
||||
bin_info_schema = ["schemars"]
|
||||
basic_tracing = ["tracing-subscriber"]
|
||||
basic_tracing = ["dep:tracing", "tracing-subscriber"]
|
||||
tracing = [
|
||||
"basic_tracing",
|
||||
"tracing-tree",
|
||||
|
||||
@@ -44,10 +44,38 @@ pub fn setup_logging() {
|
||||
.init();
|
||||
}
|
||||
|
||||
// don't call init so that we could attach additional layers
|
||||
#[cfg(feature = "basic_tracing")]
|
||||
pub fn setup_tracing_logger() {
|
||||
let log_builder = tracing_subscriber::fmt()
|
||||
.with_writer(std::io::stderr)
|
||||
pub fn build_tracing_logger() -> impl tracing_subscriber::layer::SubscriberExt {
|
||||
use tracing_subscriber::prelude::*;
|
||||
|
||||
tracing_subscriber::registry()
|
||||
.with(default_tracing_fmt_layer(std::io::stderr))
|
||||
.with(default_tracing_env_filter())
|
||||
}
|
||||
|
||||
#[cfg(feature = "basic_tracing")]
|
||||
pub fn default_tracing_env_filter() -> tracing_subscriber::filter::EnvFilter {
|
||||
if ::std::env::var("RUST_LOG").is_ok() {
|
||||
tracing_subscriber::filter::EnvFilter::from_default_env()
|
||||
} else {
|
||||
// if the env value was not found, default to `INFO` level rather than `ERROR`
|
||||
tracing_subscriber::filter::EnvFilter::builder()
|
||||
.with_default_directive(tracing_subscriber::filter::LevelFilter::INFO.into())
|
||||
.parse_lossy("")
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "basic_tracing")]
|
||||
pub fn default_tracing_fmt_layer<S, W>(
|
||||
writer: W,
|
||||
) -> impl tracing_subscriber::Layer<S> + Sync + Send + 'static
|
||||
where
|
||||
S: tracing::Subscriber + for<'a> tracing_subscriber::registry::LookupSpan<'a>,
|
||||
W: for<'writer> tracing_subscriber::fmt::MakeWriter<'writer> + Sync + Send + 'static,
|
||||
{
|
||||
tracing_subscriber::fmt::layer()
|
||||
.with_writer(writer)
|
||||
// Use a more compact, abbreviated log format
|
||||
.compact()
|
||||
// Display source code file paths
|
||||
@@ -55,18 +83,13 @@ pub fn setup_tracing_logger() {
|
||||
// Display source code line numbers
|
||||
.with_line_number(true)
|
||||
// Don't display the event's target (module path)
|
||||
.with_target(false);
|
||||
.with_target(false)
|
||||
}
|
||||
|
||||
if ::std::env::var("RUST_LOG").is_ok() {
|
||||
log_builder
|
||||
.with_env_filter(tracing_subscriber::filter::EnvFilter::from_default_env())
|
||||
.init()
|
||||
} else {
|
||||
// default to 'Info
|
||||
log_builder
|
||||
.with_max_level(tracing_subscriber::filter::LevelFilter::INFO)
|
||||
.init()
|
||||
}
|
||||
#[cfg(feature = "basic_tracing")]
|
||||
pub fn setup_tracing_logger() {
|
||||
use tracing_subscriber::util::SubscriberInitExt;
|
||||
build_tracing_logger().init()
|
||||
}
|
||||
|
||||
// TODO: This has to be a macro, running it as a function does not work for the file_appender for some reason
|
||||
|
||||
@@ -24,10 +24,10 @@ use tracing::*;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Config {
|
||||
initial_reconnection_backoff: Duration,
|
||||
maximum_reconnection_backoff: Duration,
|
||||
initial_connection_timeout: Duration,
|
||||
maximum_connection_buffer_size: usize,
|
||||
pub initial_reconnection_backoff: Duration,
|
||||
pub maximum_reconnection_backoff: Duration,
|
||||
pub initial_connection_timeout: Duration,
|
||||
pub maximum_connection_buffer_size: usize,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
@@ -50,7 +50,7 @@ pub trait SendWithoutResponse {
|
||||
// Without response in this context means we will not listen for anything we might get back (not
|
||||
// that we should get anything), including any possible io errors
|
||||
fn send_without_response(
|
||||
&mut self,
|
||||
&self,
|
||||
address: NymNodeRoutingAddress,
|
||||
packet: NymPacket,
|
||||
packet_type: PacketType,
|
||||
@@ -196,7 +196,7 @@ impl Client {
|
||||
}
|
||||
}
|
||||
|
||||
fn make_connection(&mut self, address: NymNodeRoutingAddress, pending_packet: FramedNymPacket) {
|
||||
fn make_connection(&self, address: NymNodeRoutingAddress, pending_packet: FramedNymPacket) {
|
||||
let (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
|
||||
@@ -247,7 +247,7 @@ impl Client {
|
||||
|
||||
impl SendWithoutResponse for Client {
|
||||
fn send_without_response(
|
||||
&mut self,
|
||||
&self,
|
||||
address: NymNodeRoutingAddress,
|
||||
packet: NymPacket,
|
||||
packet_type: PacketType,
|
||||
|
||||
@@ -132,6 +132,10 @@ impl PublicKey {
|
||||
*self.0.as_bytes()
|
||||
}
|
||||
|
||||
pub fn as_bytes(&self) -> &[u8; PUBLIC_KEY_SIZE] {
|
||||
self.0.as_bytes()
|
||||
}
|
||||
|
||||
pub fn from_bytes(b: &[u8]) -> Result<Self, KeyRecoveryError> {
|
||||
if b.len() != PUBLIC_KEY_SIZE {
|
||||
return Err(KeyRecoveryError::InvalidSizePublicKey {
|
||||
@@ -228,7 +232,6 @@ impl<'a> From<&'a PrivateKey> for PublicKey {
|
||||
PublicKey((&pk.0).into())
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for PrivateKey {
|
||||
type Err = KeyRecoveryError;
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@ use ed25519_dalek::{SecretKey, Signer, SigningKey};
|
||||
pub use ed25519_dalek::{Verifier, PUBLIC_KEY_LENGTH, SECRET_KEY_LENGTH, SIGNATURE_LENGTH};
|
||||
use nym_pemstore::traits::{PemStorableKey, PemStorableKeyPair};
|
||||
use std::fmt::{self, Debug, Display, Formatter};
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::str::FromStr;
|
||||
use thiserror::Error;
|
||||
use zeroize::{Zeroize, ZeroizeOnDrop};
|
||||
@@ -154,17 +153,9 @@ impl PemStorableKeyPair for KeyPair {
|
||||
}
|
||||
|
||||
/// ed25519 EdDSA Public Key
|
||||
#[derive(Copy, Clone, Eq, PartialEq)]
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
|
||||
pub struct PublicKey(ed25519_dalek::VerifyingKey);
|
||||
|
||||
impl Hash for PublicKey {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
// each public key has unique bytes representation which can be used
|
||||
// for the hash implementation
|
||||
self.to_bytes().hash(state)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for PublicKey {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
Display::fmt(&self.to_base58_string(), f)
|
||||
|
||||
@@ -12,13 +12,7 @@ license.workspace = true
|
||||
|
||||
[dependencies]
|
||||
async-trait = { workspace = true }
|
||||
reqwest = { workspace = true, features = [
|
||||
"json",
|
||||
"gzip",
|
||||
"deflate",
|
||||
"brotli",
|
||||
"zstd",
|
||||
] }
|
||||
reqwest = { workspace = true, features = ["json", "gzip"] }
|
||||
http.workspace = true
|
||||
url = { workspace = true }
|
||||
once_cell = { workspace = true }
|
||||
@@ -36,10 +30,7 @@ mime = { workspace = true }
|
||||
nym-bin-common = { path = "../bin-common" }
|
||||
|
||||
[target."cfg(not(target_arch = \"wasm32\"))".dependencies]
|
||||
hickory-resolver = { workspace = true, features = [
|
||||
"dns-over-https-rustls",
|
||||
"webpki-roots",
|
||||
] }
|
||||
hickory-resolver = { workspace = true, features = ["dns-over-https-rustls", "webpki-roots"] }
|
||||
|
||||
# for request timeout until https://github.com/seanmonstar/reqwest/issues/1135 is fixed
|
||||
[target."cfg(target_arch = \"wasm32\")".dependencies.wasmtimer]
|
||||
|
||||
@@ -265,18 +265,14 @@ impl ClientBuilder {
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
let reqwest_client_builder = {
|
||||
// Note: I believe the manual enable calls for the compression methods are extra
|
||||
// as the various compression features for `reqwest` crate should be enabled
|
||||
// just by including the feature which:
|
||||
// `"Enable[s] auto decompression by checking the Content-Encoding response header."`
|
||||
let r = reqwest::ClientBuilder::new();
|
||||
|
||||
// Note this is extra as the `gzip` feature for `reqwest` crate should be enabled which
|
||||
// `"Enable[s] auto gzip decompression by checking the Content-Encoding response header."`
|
||||
//
|
||||
// I am going to leave these here anyways so that removing a decompression method
|
||||
// from the features list will throw an error if it is not also removed here.
|
||||
reqwest::ClientBuilder::new()
|
||||
.gzip(true)
|
||||
.deflate(true)
|
||||
.brotli(true)
|
||||
.zstd(true)
|
||||
// I am going to leave it here anyways so that gzip decompression is attempted even if
|
||||
// that feature is removed.
|
||||
r.gzip(true)
|
||||
};
|
||||
|
||||
ClientBuilder {
|
||||
@@ -539,6 +535,11 @@ impl ApiClientCore for Client {
|
||||
|
||||
let mut request = self.reqwest_client.request(method.clone(), url);
|
||||
|
||||
// Indicate that compressed responses are preferred, but if not supported other encodings are fine.
|
||||
// TODO: Down the road we can be more selective about adding this, but it's inclusion here guarantees
|
||||
// that we use compression when available.
|
||||
request = request.header(reqwest::header::ACCEPT_ENCODING, "gzip;q=1.0, *;q=0.5");
|
||||
|
||||
if let Some(body) = json_body {
|
||||
request = request.json(body);
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ use thiserror::Error;
|
||||
use nym_outfox::packet::{OutfoxPacket, OutfoxProcessedPacket};
|
||||
|
||||
#[cfg(feature = "sphinx")]
|
||||
use sphinx_packet::{SphinxPacket, SphinxPacketBuilder};
|
||||
pub use sphinx_packet::{SphinxPacket, SphinxPacketBuilder};
|
||||
|
||||
#[cfg(feature = "outfox")]
|
||||
pub use nym_outfox::{
|
||||
@@ -166,4 +166,20 @@ impl NymPacket {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "sphinx")]
|
||||
pub fn sphinx_packet_ref(&self) -> Option<&SphinxPacket> {
|
||||
match self {
|
||||
NymPacket::Sphinx(packet) => Some(packet),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "sphinx")]
|
||||
pub fn as_sphinx_packet(self) -> Option<SphinxPacket> {
|
||||
match self {
|
||||
NymPacket::Sphinx(packet) => Some(packet),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -363,7 +363,7 @@ impl TaskClient {
|
||||
"unnamed-TaskClient".to_string()
|
||||
};
|
||||
|
||||
log!(target: target, level, "{}", format!("[{target}] {msg}"))
|
||||
log!(target: target, level, "{}", format_args!("[{target}] {msg}"))
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
|
||||
@@ -6,13 +6,12 @@ use base64::engine::general_purpose;
|
||||
use base64::Engine;
|
||||
use serde::Serialize;
|
||||
use std::fmt;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::ops::Deref;
|
||||
use std::str::FromStr;
|
||||
|
||||
use x25519_dalek::PublicKey;
|
||||
|
||||
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
|
||||
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
|
||||
pub struct PeerPublicKey(PublicKey);
|
||||
|
||||
impl PeerPublicKey {
|
||||
@@ -36,12 +35,6 @@ impl fmt::Display for PeerPublicKey {
|
||||
}
|
||||
}
|
||||
|
||||
impl Hash for PeerPublicKey {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.0.as_bytes().hash(state)
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for PeerPublicKey {
|
||||
type Target = PublicKey;
|
||||
|
||||
|
||||
@@ -102,7 +102,7 @@ impl PeerHandle {
|
||||
if SystemTime::now().duration_since(self.startup_timestamp)? >= AUTO_REMOVE_AFTER {
|
||||
log::debug!(
|
||||
"Peer {} has been present for 30 days, removing it",
|
||||
self.public_key.to_string()
|
||||
self.public_key
|
||||
);
|
||||
let success = self.remove_peer().await?;
|
||||
return Ok(!success);
|
||||
@@ -111,7 +111,7 @@ impl PeerHandle {
|
||||
if spent_bandwidth >= BANDWIDTH_CAP_PER_DAY {
|
||||
log::debug!(
|
||||
"Peer {} doesn't have bandwidth anymore, removing it",
|
||||
self.public_key.to_string()
|
||||
self.public_key
|
||||
);
|
||||
let success = self.remove_peer().await?;
|
||||
return Ok(!success);
|
||||
|
||||
Generated
+8
-8
@@ -667,9 +667,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "deranged"
|
||||
version = "0.3.11"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4"
|
||||
checksum = "28cfac68e08048ae1883171632c2aef3ebc555621ae56fbccce1cbf22dd7f058"
|
||||
dependencies = [
|
||||
"powerfmt",
|
||||
]
|
||||
@@ -1851,9 +1851,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.3.39"
|
||||
version = "0.3.41"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dad298b01a40a23aac4580b67e3dbedb7cc8402f3592d7f49469de2ea4aecdd8"
|
||||
checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40"
|
||||
dependencies = [
|
||||
"deranged",
|
||||
"itoa",
|
||||
@@ -1868,15 +1868,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "time-core"
|
||||
version = "0.1.3"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "765c97a5b985b7c11d7bc27fa927dc4fe6af3a6dfb021d28deb60d3bf51e76ef"
|
||||
checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c"
|
||||
|
||||
[[package]]
|
||||
name = "time-macros"
|
||||
version = "0.2.20"
|
||||
version = "0.2.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e8093bc3e81c3bc5f7879de09619d06c9a5a5e45ca44dfeeb7225bae38005c5c"
|
||||
checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49"
|
||||
dependencies = [
|
||||
"num-conv",
|
||||
"time-core",
|
||||
|
||||
@@ -57,7 +57,7 @@ This is a quick summary, to understand the full picture, please see detailed [*R
|
||||
* NymVPN users can chose to route through Nym Network in two ways:
|
||||
- Mixnet: 5 layers routing and mixing - full privacy
|
||||
- Wireguard: 2 layers routing, skipping 3 mixing layers - fast mode
|
||||
* **The current reward system is *Native rewarding* - an intermediate step - where each layer get's rewarded the same**
|
||||
* **The current reward system is [*Naive rewarding*](#naive-rewarding) - an intermediate step - where each layer get's rewarded the same**
|
||||
* In the final model, nodes will get rewarded based on their layer position and the work they do (collected user tickets), where and the reward distribution per layer will be according to a [decision made by the operators](https://forum.nymtech.net/t/poll-what-should-be-the-split-of-mixmining-rewards-among-the-layers-of-the-nym-mixnet/407) as follows:
|
||||
- 5-hop: 16%-16%-16%-16%-36%
|
||||
- 2-hop: 33%-67%
|
||||
|
||||
+21
-7
@@ -21,18 +21,19 @@ bip39 = { workspace = true, features = ["zeroize"] }
|
||||
bs58.workspace = true
|
||||
celes = { workspace = true } # country codes
|
||||
colored = { workspace = true }
|
||||
csv = { workspace = true }
|
||||
clap = { workspace = true, features = ["cargo", "env"] }
|
||||
dashmap = { workspace = true }
|
||||
futures = { workspace = true }
|
||||
humantime-serde = { workspace = true }
|
||||
human-repr = { workspace = true }
|
||||
ipnetwork = { workspace = true }
|
||||
indicatif = { workspace = true }
|
||||
rand = { workspace = true }
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
serde_json.workspace = true
|
||||
si-scale = { workspace = true }
|
||||
thiserror.workspace = true
|
||||
tracing.workspace = true
|
||||
tracing-indicatif = { workspace = true }
|
||||
tracing-subscriber.workspace = true
|
||||
tokio = { workspace = true, features = ["macros", "sync", "rt-multi-thread"] }
|
||||
tokio-util = { workspace = true, features = ["codec"] }
|
||||
@@ -40,9 +41,6 @@ toml = { workspace = true }
|
||||
url = { workspace = true, features = ["serde"] }
|
||||
zeroize = { workspace = true, features = ["zeroize_derive"] }
|
||||
|
||||
# temporary bonding information v1 (to grab and parse nym-mixnode and nym-gateway package versions)
|
||||
semver = { workspace = true }
|
||||
|
||||
# system info:
|
||||
cupid = { workspace = true }
|
||||
sysinfo = { workspace = true }
|
||||
@@ -62,6 +60,8 @@ nym-sphinx-addressing = { path = "../common/nymsphinx/addressing" }
|
||||
nym-sphinx-framing = { path = "../common/nymsphinx/framing" }
|
||||
nym-sphinx-types = { path = "../common/nymsphinx/types" }
|
||||
nym-sphinx-forwarding = { path = "../common/nymsphinx/forwarding" }
|
||||
nym-sphinx-routing = { path = "../common/nymsphinx/routing" }
|
||||
nym-sphinx-params = { path = "../common/nymsphinx/params" }
|
||||
nym-task = { path = "../common/task" }
|
||||
nym-types = { path = "../common/types" }
|
||||
nym-validator-client = { path = "../common/client-libs/validator-client" }
|
||||
@@ -77,8 +77,6 @@ nym-http-api-client = { path = "../common/http-api-client" }
|
||||
# useful for `#[axum_macros::debug_handler]`
|
||||
#axum-macros = "0.3.8"
|
||||
axum.workspace = true
|
||||
axum-extra = { workspace = true, features = ["typed-header"] }
|
||||
headers.workspace = true
|
||||
time = { workspace = true, features = ["serde"] }
|
||||
tower-http = { workspace = true, features = ["fs"] }
|
||||
utoipa = { workspace = true, features = ["axum_extras", "time"] }
|
||||
@@ -95,6 +93,22 @@ nym-network-requester = { path = "../service-providers/network-requester" }
|
||||
nym-ip-packet-router = { path = "../service-providers/ip-packet-router" }
|
||||
|
||||
|
||||
# throughput tester to recreate lioness
|
||||
# we don't care about particular versions - just pull whatever is used by sphinx
|
||||
[dependencies.lioness]
|
||||
version = "*"
|
||||
|
||||
[dependencies.chacha]
|
||||
version = "*"
|
||||
|
||||
[dependencies.arrayref]
|
||||
version = "*"
|
||||
|
||||
[dependencies.blake2]
|
||||
version = "*"
|
||||
|
||||
|
||||
|
||||
[build-dependencies]
|
||||
# temporary bonding information v1 (to grab and parse nym-mixnode and nym-gateway package versions)
|
||||
cargo_metadata = { workspace = true }
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
use crate::cli::helpers::ConfigArgs;
|
||||
use crate::config::upgrade_helpers::try_load_current_config;
|
||||
use crate::error::NymNodeError;
|
||||
use crate::node::bonding_information::BondingInformation;
|
||||
use nym_bin_common::output_format::OutputFormat;
|
||||
|
||||
@@ -21,7 +20,7 @@ pub struct Args {
|
||||
pub(crate) output: OutputFormat,
|
||||
}
|
||||
|
||||
pub async fn execute(args: Args) -> Result<(), NymNodeError> {
|
||||
pub async fn execute(args: Args) -> anyhow::Result<()> {
|
||||
let config = try_load_current_config(args.config.config_path()).await?;
|
||||
let info = BondingInformation::try_load(&config)?;
|
||||
args.output.to_stdout(&info);
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
use crate::error::NymNodeError;
|
||||
use nym_bin_common::bin_info_owned;
|
||||
use nym_bin_common::output_format::OutputFormat;
|
||||
|
||||
@@ -11,7 +10,7 @@ pub(crate) struct Args {
|
||||
output: OutputFormat,
|
||||
}
|
||||
|
||||
pub(crate) fn execute(args: Args) -> Result<(), NymNodeError> {
|
||||
pub(crate) fn execute(args: Args) -> anyhow::Result<()> {
|
||||
println!("{}", args.output.format(&bin_info_owned!()));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ pub(crate) struct Args {
|
||||
_args: Vec<String>,
|
||||
}
|
||||
|
||||
pub(crate) async fn execute(_args: Args) -> Result<(), NymNodeError> {
|
||||
pub(crate) fn execute(_args: Args) -> Result<(), NymNodeError> {
|
||||
let orange = TrueColor {
|
||||
r: 251,
|
||||
g: 110,
|
||||
|
||||
@@ -7,3 +7,4 @@ pub(super) mod migrate;
|
||||
pub(crate) mod node_details;
|
||||
pub(super) mod run;
|
||||
pub(super) mod sign;
|
||||
pub(crate) mod test_throughput;
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
use crate::cli::helpers::ConfigArgs;
|
||||
use crate::config::upgrade_helpers::try_load_current_config;
|
||||
use crate::error::NymNodeError;
|
||||
use crate::node::NymNode;
|
||||
use nym_bin_common::output_format::OutputFormat;
|
||||
|
||||
@@ -21,7 +20,7 @@ pub(crate) struct Args {
|
||||
pub(crate) output: OutputFormat,
|
||||
}
|
||||
|
||||
pub async fn execute(args: Args) -> Result<(), NymNodeError> {
|
||||
pub async fn execute(args: Args) -> anyhow::Result<()> {
|
||||
let config = try_load_current_config(args.config.config_path()).await?;
|
||||
let details = NymNode::new(config).await?.display_details()?;
|
||||
args.output.to_stdout(&details);
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
use crate::cli::helpers::ConfigArgs;
|
||||
use crate::config::upgrade_helpers::try_load_current_config;
|
||||
use crate::error::NymNodeError;
|
||||
use crate::node::helpers::load_ed25519_identity_keypair;
|
||||
use nym_bin_common::output_format::OutputFormat;
|
||||
use nym_crypto::asymmetric::identity;
|
||||
@@ -70,7 +69,7 @@ fn print_signed_contract_msg(
|
||||
|
||||
// SAFETY: clippy ArgGroup ensures only a single branch is actually called
|
||||
#[allow(clippy::unreachable)]
|
||||
pub async fn execute(args: Args) -> Result<(), NymNodeError> {
|
||||
pub async fn execute(args: Args) -> anyhow::Result<()> {
|
||||
let config = try_load_current_config(args.config.config_path()).await?;
|
||||
let identity_keypair =
|
||||
load_ed25519_identity_keypair(config.storage_paths.keys.ed25519_identity_storage_paths())?;
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
// Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
use crate::cli::helpers::ConfigArgs;
|
||||
use crate::logging::granual_filtered_env;
|
||||
use crate::throughput_tester::test_mixing_throughput;
|
||||
use anyhow::bail;
|
||||
use humantime_serde::re::humantime;
|
||||
use indicatif::ProgressStyle;
|
||||
use nym_bin_common::logging::default_tracing_fmt_layer;
|
||||
use std::env::temp_dir;
|
||||
use std::path::PathBuf;
|
||||
use std::time::Duration;
|
||||
use time::OffsetDateTime;
|
||||
use tracing_indicatif::IndicatifLayer;
|
||||
use tracing_subscriber::layer::SubscriberExt;
|
||||
use tracing_subscriber::util::SubscriberInitExt;
|
||||
|
||||
#[derive(Debug, clap::Args)]
|
||||
pub struct Args {
|
||||
#[clap(flatten)]
|
||||
config: ConfigArgs,
|
||||
|
||||
#[clap(long, default_value_t = 10)]
|
||||
senders: usize,
|
||||
|
||||
/// target packet latency, if current value is below threshold, clients will increase their sending rates
|
||||
/// and similarly if it's above it, they will decrease it
|
||||
#[clap(long, default_value = "15ms", value_parser = humantime::parse_duration)]
|
||||
packet_latency_threshold: Duration,
|
||||
|
||||
#[clap(long, default_value_t = 50)]
|
||||
starting_sending_batch_size: usize,
|
||||
|
||||
#[clap(long, default_value = "50ms", value_parser = humantime::parse_duration)]
|
||||
starting_sending_delay: Duration,
|
||||
|
||||
#[clap(long, short)]
|
||||
output_directory: Option<PathBuf>,
|
||||
}
|
||||
|
||||
fn init_test_logger() -> anyhow::Result<()> {
|
||||
let indicatif_layer = IndicatifLayer::new()
|
||||
.with_progress_style(ProgressStyle::with_template(
|
||||
"{span_child_prefix}{spinner} {span_fields} -- {span_name} {wide_msg}",
|
||||
)?)
|
||||
.with_span_child_prefix_symbol("↳ ")
|
||||
.with_span_child_prefix_indent(" ");
|
||||
|
||||
tracing_subscriber::registry()
|
||||
.with(default_tracing_fmt_layer(
|
||||
indicatif_layer.get_stderr_writer(),
|
||||
))
|
||||
.with(indicatif_layer)
|
||||
.with(granual_filtered_env()?)
|
||||
.init();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn execute(args: Args) -> anyhow::Result<()> {
|
||||
init_test_logger()?;
|
||||
|
||||
let output_dir = match args.output_directory {
|
||||
Some(output_dir) => {
|
||||
if !output_dir.is_dir() {
|
||||
bail!("'{}' is not a directory", output_dir.display());
|
||||
}
|
||||
|
||||
output_dir
|
||||
}
|
||||
None => {
|
||||
let now = OffsetDateTime::now_utc().unix_timestamp();
|
||||
temp_dir()
|
||||
.join("nym-node-throughput-testing")
|
||||
.join(now.to_string())
|
||||
}
|
||||
};
|
||||
|
||||
test_mixing_throughput(
|
||||
args.config.config_path(),
|
||||
args.senders,
|
||||
args.packet_latency_threshold,
|
||||
args.starting_sending_batch_size,
|
||||
args.starting_sending_delay,
|
||||
output_dir,
|
||||
)
|
||||
}
|
||||
+35
-11
@@ -1,14 +1,17 @@
|
||||
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
use crate::cli::commands::{bonding_information, build_info, migrate, node_details, run, sign};
|
||||
use crate::cli::commands::{
|
||||
bonding_information, build_info, migrate, node_details, run, sign, test_throughput,
|
||||
};
|
||||
use crate::env::vars::{NYMNODE_CONFIG_ENV_FILE_ARG, NYMNODE_NO_BANNER_ARG};
|
||||
use crate::error::NymNodeError;
|
||||
use crate::logging::setup_tracing_logger;
|
||||
use clap::{Parser, Subcommand};
|
||||
use nym_bin_common::bin_info;
|
||||
use std::future::Future;
|
||||
use std::sync::OnceLock;
|
||||
|
||||
mod commands;
|
||||
pub(crate) mod commands;
|
||||
mod helpers;
|
||||
|
||||
pub const DEFAULT_NYMNODE_ID: &str = "default-nym-node";
|
||||
@@ -42,15 +45,31 @@ pub(crate) struct Cli {
|
||||
}
|
||||
|
||||
impl Cli {
|
||||
pub(crate) async fn execute(self) -> Result<(), NymNodeError> {
|
||||
match self.command {
|
||||
Commands::BuildInfo(args) => build_info::execute(args),
|
||||
Commands::BondingInformation(args) => bonding_information::execute(args).await,
|
||||
Commands::NodeDetails(args) => node_details::execute(args).await,
|
||||
Commands::Run(args) => run::execute(*args).await,
|
||||
Commands::Migrate(args) => migrate::execute(*args).await,
|
||||
Commands::Sign(args) => sign::execute(args).await,
|
||||
fn execute_async<F: Future>(fut: F) -> anyhow::Result<F::Output> {
|
||||
Ok(tokio::runtime::Builder::new_multi_thread()
|
||||
.enable_all()
|
||||
.build()?
|
||||
.block_on(fut))
|
||||
}
|
||||
|
||||
pub(crate) fn execute(self) -> anyhow::Result<()> {
|
||||
// NOTE: `test_throughput` sets up its own logger as it has to include additional layers
|
||||
if !matches!(self.command, Commands::TestThroughput(..)) {
|
||||
setup_tracing_logger()?;
|
||||
}
|
||||
|
||||
match self.command {
|
||||
Commands::BuildInfo(args) => build_info::execute(args)?,
|
||||
Commands::BondingInformation(args) => {
|
||||
{ Self::execute_async(bonding_information::execute(args))? }?
|
||||
}
|
||||
Commands::NodeDetails(args) => { Self::execute_async(node_details::execute(args))? }?,
|
||||
Commands::Run(args) => { Self::execute_async(run::execute(*args))? }?,
|
||||
Commands::Migrate(args) => migrate::execute(*args)?,
|
||||
Commands::Sign(args) => { Self::execute_async(sign::execute(args))? }?,
|
||||
Commands::TestThroughput(args) => test_throughput::execute(args)?,
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,6 +92,11 @@ pub(crate) enum Commands {
|
||||
|
||||
/// Use identity key of this node to sign provided message.
|
||||
Sign(sign::Args),
|
||||
|
||||
/// Attempt to approximate the maximum mixnet throughput if nym-node
|
||||
/// was running on this machine in mixnet mode
|
||||
#[clap(hide = true)]
|
||||
TestThroughput(test_throughput::Args),
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
+16
-17
@@ -1,35 +1,34 @@
|
||||
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
use tracing::level_filters::LevelFilter;
|
||||
use tracing_subscriber::{filter::Directive, EnvFilter};
|
||||
use nym_bin_common::logging::{default_tracing_env_filter, default_tracing_fmt_layer};
|
||||
use tracing_subscriber::filter::Directive;
|
||||
use tracing_subscriber::layer::SubscriberExt;
|
||||
use tracing_subscriber::util::SubscriberInitExt;
|
||||
|
||||
pub(crate) fn setup_tracing_logger() -> anyhow::Result<()> {
|
||||
pub(crate) fn granual_filtered_env() -> anyhow::Result<tracing_subscriber::filter::EnvFilter> {
|
||||
fn directive_checked(directive: impl Into<String>) -> anyhow::Result<Directive> {
|
||||
directive.into().parse().map_err(From::from)
|
||||
}
|
||||
|
||||
let log_builder = tracing_subscriber::fmt()
|
||||
// Use a more compact, abbreviated log format
|
||||
.compact()
|
||||
// Display source code file paths
|
||||
.with_file(true)
|
||||
// Display source code line numbers
|
||||
.with_line_number(true)
|
||||
// Don't display the event's target (module path)
|
||||
.with_target(false);
|
||||
let mut filter = default_tracing_env_filter();
|
||||
|
||||
let mut filter = EnvFilter::builder()
|
||||
// if RUST_LOG isn't set, set default level
|
||||
.with_default_directive(LevelFilter::INFO.into())
|
||||
.from_env_lossy();
|
||||
// these crates are more granularly filtered
|
||||
let filter_crates = ["defguard_wireguard_rs"];
|
||||
for crate_name in filter_crates {
|
||||
filter = filter.add_directive(directive_checked(format!("{}=warn", crate_name))?);
|
||||
}
|
||||
Ok(filter)
|
||||
}
|
||||
|
||||
log_builder.with_env_filter(filter).init();
|
||||
pub(crate) fn build_tracing_logger() -> anyhow::Result<impl SubscriberExt> {
|
||||
Ok(tracing_subscriber::registry()
|
||||
.with(default_tracing_fmt_layer(std::io::stderr))
|
||||
.with(granual_filtered_env()?))
|
||||
}
|
||||
|
||||
pub(crate) fn setup_tracing_logger() -> anyhow::Result<()> {
|
||||
build_tracing_logger()?.init();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#![warn(clippy::expect_used)]
|
||||
#![warn(clippy::unwrap_used)]
|
||||
|
||||
use crate::{cli::Cli, logging::setup_tracing_logger};
|
||||
use crate::cli::Cli;
|
||||
use clap::{crate_name, crate_version, Parser};
|
||||
use nym_bin_common::logging::maybe_print_banner;
|
||||
use nym_config::defaults::setup_env;
|
||||
@@ -15,10 +15,10 @@ mod env;
|
||||
pub(crate) mod error;
|
||||
mod logging;
|
||||
pub(crate) mod node;
|
||||
pub(crate) mod throughput_tester;
|
||||
pub(crate) mod wireguard;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> anyhow::Result<()> {
|
||||
fn main() -> anyhow::Result<()> {
|
||||
// std::env::set_var(
|
||||
// "RUST_LOG",
|
||||
// "trace,handlebars=warn,tendermint_rpc=warn,h2=warn,hyper=warn,rustls=warn,reqwest=warn,tungstenite=warn,async_tungstenite=warn,tokio_util=warn,tokio_tungstenite=warn,tokio-util=warn",
|
||||
@@ -26,13 +26,12 @@ async fn main() -> anyhow::Result<()> {
|
||||
|
||||
let cli = Cli::parse();
|
||||
setup_env(cli.config_env_file.as_ref());
|
||||
setup_tracing_logger()?;
|
||||
|
||||
if !cli.no_banner {
|
||||
maybe_print_banner(crate_name!(), crate_version!());
|
||||
}
|
||||
|
||||
cli.execute().await?;
|
||||
cli.execute()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
use crate::node::mixnet::packet_forwarding::global::is_global_ip;
|
||||
use crate::node::shared_network::RoutingFilter;
|
||||
use futures::StreamExt;
|
||||
use nym_mixnet_client::forwarder::{
|
||||
@@ -13,38 +12,33 @@ use nym_nonexhaustive_delayqueue::{Expired, NonExhaustiveDelayQueue};
|
||||
use nym_sphinx_forwarding::packet::MixPacket;
|
||||
use nym_task::ShutdownToken;
|
||||
use std::io;
|
||||
use std::net::IpAddr;
|
||||
use tokio::time::Instant;
|
||||
use tracing::{debug, error, trace, warn};
|
||||
|
||||
pub(crate) mod global;
|
||||
|
||||
pub struct PacketForwarder<C> {
|
||||
testnet: bool,
|
||||
|
||||
pub struct PacketForwarder<C, F> {
|
||||
delay_queue: NonExhaustiveDelayQueue<MixPacket>,
|
||||
mixnet_client: C,
|
||||
|
||||
metrics: NymNodeMetrics,
|
||||
routing_filter: RoutingFilter,
|
||||
routing_filter: F,
|
||||
|
||||
packet_sender: MixForwardingSender,
|
||||
packet_receiver: MixForwardingReceiver,
|
||||
shutdown: ShutdownToken,
|
||||
}
|
||||
|
||||
impl<C> PacketForwarder<C> {
|
||||
impl<C, F> PacketForwarder<C, F> {
|
||||
pub fn new(
|
||||
client: C,
|
||||
testnet: bool,
|
||||
routing_filter: RoutingFilter,
|
||||
routing_filter: F,
|
||||
metrics: NymNodeMetrics,
|
||||
shutdown: ShutdownToken,
|
||||
) -> Self {
|
||||
let (packet_sender, packet_receiver) = mix_forwarding_channels();
|
||||
|
||||
PacketForwarder {
|
||||
testnet,
|
||||
delay_queue: NonExhaustiveDelayQueue::new(),
|
||||
mixnet_client: client,
|
||||
metrics,
|
||||
@@ -59,22 +53,14 @@ impl<C> PacketForwarder<C> {
|
||||
self.packet_sender.clone()
|
||||
}
|
||||
|
||||
fn should_route(&mut self, ip_addr: IpAddr) -> bool {
|
||||
// only allow non-global ips on testnets
|
||||
if self.testnet && !is_global_ip(&ip_addr) {
|
||||
return true;
|
||||
}
|
||||
|
||||
self.routing_filter.attempt_resolve(ip_addr).should_route()
|
||||
}
|
||||
|
||||
fn forward_packet(&mut self, packet: MixPacket)
|
||||
where
|
||||
C: SendWithoutResponse,
|
||||
F: RoutingFilter,
|
||||
{
|
||||
let next_hop = packet.next_hop();
|
||||
|
||||
if !self.should_route(next_hop.as_ref().ip()) {
|
||||
if !self.routing_filter.should_route(next_hop.as_ref().ip()) {
|
||||
debug!("dropping packet as the egress address does not belong to any known node");
|
||||
self.metrics
|
||||
.mixnet
|
||||
@@ -113,6 +99,7 @@ impl<C> PacketForwarder<C> {
|
||||
fn handle_done_delaying(&mut self, packet: Expired<MixPacket>)
|
||||
where
|
||||
C: SendWithoutResponse,
|
||||
F: RoutingFilter,
|
||||
{
|
||||
let delayed_packet = packet.into_inner();
|
||||
self.forward_packet(delayed_packet);
|
||||
@@ -121,6 +108,7 @@ impl<C> PacketForwarder<C> {
|
||||
fn handle_new_packet(&mut self, new_packet: PacketToForward)
|
||||
where
|
||||
C: SendWithoutResponse,
|
||||
F: RoutingFilter,
|
||||
{
|
||||
// in case of a zero delay packet, don't bother putting it in the delay queue,
|
||||
// just forward it immediately
|
||||
@@ -152,6 +140,7 @@ impl<C> PacketForwarder<C> {
|
||||
pub async fn run(&mut self)
|
||||
where
|
||||
C: SendWithoutResponse,
|
||||
F: RoutingFilter,
|
||||
{
|
||||
let mut processed = 0;
|
||||
trace!("starting PacketForwarder");
|
||||
|
||||
@@ -29,7 +29,7 @@ use crate::node::mixnet::packet_forwarding::PacketForwarder;
|
||||
use crate::node::mixnet::shared::ProcessingConfig;
|
||||
use crate::node::mixnet::SharedFinalHopData;
|
||||
use crate::node::shared_network::{
|
||||
CachedNetwork, CachedTopologyProvider, NetworkRefresher, RoutingFilter,
|
||||
CachedNetwork, CachedTopologyProvider, NetworkRefresher, OpenFilter, RoutingFilter,
|
||||
};
|
||||
use nym_bin_common::bin_info;
|
||||
use nym_crypto::asymmetric::{ed25519, x25519};
|
||||
@@ -461,6 +461,10 @@ impl NymNode {
|
||||
&self.config
|
||||
}
|
||||
|
||||
pub(crate) fn shutdown_token<S: Into<String>>(&self, child_suffix: S) -> ShutdownToken {
|
||||
self.shutdown_manager.clone_token(child_suffix)
|
||||
}
|
||||
|
||||
pub(crate) fn with_accepted_operator_terms_and_conditions(
|
||||
mut self,
|
||||
accepted_operator_terms_and_conditions: bool,
|
||||
@@ -528,12 +532,17 @@ impl NymNode {
|
||||
self.x25519_sphinx_keys.public_key()
|
||||
}
|
||||
|
||||
pub(crate) fn x25519_sphinx_keys(&self) -> Arc<x25519::KeyPair> {
|
||||
self.x25519_sphinx_keys.clone()
|
||||
}
|
||||
|
||||
pub(crate) fn x25519_noise_key(&self) -> &x25519::PublicKey {
|
||||
self.x25519_noise_keys.public_key()
|
||||
}
|
||||
|
||||
async fn build_network_refresher(&self) -> Result<NetworkRefresher, NymNodeError> {
|
||||
NetworkRefresher::initialise_new(
|
||||
self.config.debug.testnet,
|
||||
self.user_agent(),
|
||||
self.config.mixnet.nym_api_urls.clone(),
|
||||
self.config.debug.topology_cache_ttl,
|
||||
@@ -970,12 +979,15 @@ impl NymNode {
|
||||
events_sender
|
||||
}
|
||||
|
||||
pub(crate) fn start_mixnet_listener(
|
||||
pub(crate) fn start_mixnet_listener<F>(
|
||||
&self,
|
||||
active_clients_store: &ActiveClientsStore,
|
||||
routing_filter: RoutingFilter,
|
||||
routing_filter: F,
|
||||
shutdown: ShutdownToken,
|
||||
) -> (MixForwardingSender, ActiveConnections) {
|
||||
) -> (MixForwardingSender, ActiveConnections)
|
||||
where
|
||||
F: RoutingFilter + Send + Sync + 'static,
|
||||
{
|
||||
let processing_config = ProcessingConfig::new(&self.config);
|
||||
|
||||
// we're ALWAYS listening for mixnet packets, either for forward or final hops (or both)
|
||||
@@ -1002,7 +1014,6 @@ impl NymNode {
|
||||
|
||||
let mut packet_forwarder = PacketForwarder::new(
|
||||
mixnet_client,
|
||||
self.config.debug.testnet,
|
||||
routing_filter,
|
||||
self.metrics.clone(),
|
||||
shutdown.clone_with_suffix("mix-packet-forwarder"),
|
||||
@@ -1028,6 +1039,19 @@ impl NymNode {
|
||||
(mix_packet_sender, active_connections)
|
||||
}
|
||||
|
||||
pub(crate) async fn run_minimal_mixnet_processing(self) -> Result<(), NymNodeError> {
|
||||
self.start_mixnet_listener(
|
||||
&ActiveClientsStore::new(),
|
||||
OpenFilter,
|
||||
self.shutdown_manager.clone_token("mixnet-traffic"),
|
||||
);
|
||||
|
||||
self.shutdown_manager.close();
|
||||
self.shutdown_manager.wait_for_shutdown_signal().await;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) async fn run(mut self) -> Result<(), NymNodeError> {
|
||||
info!("starting Nym Node {} with the following modes: mixnode: {}, entry: {}, exit: {}, wireguard: {}",
|
||||
self.ed25519_identity_key(),
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
use crate::error::NymNodeError;
|
||||
use crate::node::mixnet::packet_forwarding::global::is_global_ip;
|
||||
use arc_swap::ArcSwap;
|
||||
use async_trait::async_trait;
|
||||
use nym_gateway::node::UserAgent;
|
||||
@@ -22,8 +23,34 @@ use tracing::log::error;
|
||||
use tracing::{debug, trace, warn};
|
||||
use url::Url;
|
||||
|
||||
pub(crate) trait RoutingFilter {
|
||||
fn should_route(&self, ip: IpAddr) -> bool;
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, Default)]
|
||||
pub(crate) struct OpenFilter;
|
||||
|
||||
impl RoutingFilter for OpenFilter {
|
||||
fn should_route(&self, _: IpAddr) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
impl RoutingFilter for NetworkRoutingFilter {
|
||||
fn should_route(&self, ip: IpAddr) -> bool {
|
||||
// only allow non-global ips on testnets
|
||||
if self.testnet_mode && !is_global_ip(&ip) {
|
||||
return true;
|
||||
}
|
||||
|
||||
self.attempt_resolve(ip).should_route()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct RoutingFilter {
|
||||
pub(crate) struct NetworkRoutingFilter {
|
||||
testnet_mode: bool,
|
||||
|
||||
resolved: KnownNodes,
|
||||
|
||||
// while this is technically behind a lock, it should not be called too often as once resolved it will
|
||||
@@ -31,9 +58,10 @@ pub(crate) struct RoutingFilter {
|
||||
pending: UnknownNodes,
|
||||
}
|
||||
|
||||
impl RoutingFilter {
|
||||
fn new_empty() -> Self {
|
||||
RoutingFilter {
|
||||
impl NetworkRoutingFilter {
|
||||
fn new_empty(testnet_mode: bool) -> Self {
|
||||
NetworkRoutingFilter {
|
||||
testnet_mode,
|
||||
resolved: Default::default(),
|
||||
pending: Default::default(),
|
||||
}
|
||||
@@ -254,11 +282,12 @@ pub struct NetworkRefresher {
|
||||
shutdown_token: ShutdownToken,
|
||||
|
||||
network: CachedNetwork,
|
||||
routing_filter: RoutingFilter,
|
||||
routing_filter: NetworkRoutingFilter,
|
||||
}
|
||||
|
||||
impl NetworkRefresher {
|
||||
pub(crate) async fn initialise_new(
|
||||
testnet: bool,
|
||||
user_agent: UserAgent,
|
||||
nym_api_urls: Vec<Url>,
|
||||
full_refresh_interval: Duration,
|
||||
@@ -280,7 +309,7 @@ impl NetworkRefresher {
|
||||
pending_check_interval,
|
||||
shutdown_token,
|
||||
network: CachedNetwork::new_empty(),
|
||||
routing_filter: RoutingFilter::new_empty(),
|
||||
routing_filter: NetworkRoutingFilter::new_empty(testnet),
|
||||
};
|
||||
|
||||
this.obtain_initial_network().await?;
|
||||
@@ -403,7 +432,7 @@ impl NetworkRefresher {
|
||||
.map_err(|source| NymNodeError::InitialTopologyQueryFailure { source })
|
||||
}
|
||||
|
||||
pub(crate) fn routing_filter(&self) -> RoutingFilter {
|
||||
pub(crate) fn routing_filter(&self) -> NetworkRoutingFilter {
|
||||
self.routing_filter.clone()
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,438 @@
|
||||
// Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
use crate::throughput_tester::stats::ClientStats;
|
||||
use anyhow::bail;
|
||||
use arrayref::array_ref;
|
||||
use blake2::VarBlake2b;
|
||||
use chacha::ChaCha;
|
||||
use futures::{stream, SinkExt, Stream, StreamExt};
|
||||
use human_repr::{HumanCount, HumanDuration, HumanThroughput};
|
||||
use lioness::Lioness;
|
||||
use nym_crypto::asymmetric::x25519;
|
||||
use nym_sphinx_addressing::nodes::NymNodeRoutingAddress;
|
||||
use nym_sphinx_framing::codec::{NymCodec, NymCodecError};
|
||||
use nym_sphinx_framing::packet::FramedNymPacket;
|
||||
use nym_sphinx_params::PacketSize;
|
||||
use nym_sphinx_routing::generate_hop_delays;
|
||||
use nym_sphinx_types::header::keys::PayloadKey;
|
||||
use nym_sphinx_types::{
|
||||
Destination, DestinationAddressBytes, Node, NymPacket, SphinxHeader,
|
||||
DESTINATION_ADDRESS_LENGTH, IDENTIFIER_LENGTH,
|
||||
};
|
||||
use nym_task::ShutdownToken;
|
||||
use rand::rngs::OsRng;
|
||||
use std::net::SocketAddr;
|
||||
use std::pin::Pin;
|
||||
use std::task::{Context, Poll, Waker};
|
||||
use std::time::Duration;
|
||||
use time::OffsetDateTime;
|
||||
use tokio::net::{TcpListener, TcpStream};
|
||||
use tokio::select;
|
||||
use tokio::time::{interval, sleep, Instant};
|
||||
use tokio_util::codec::Framed;
|
||||
use tracing::{debug, error, info, Span};
|
||||
use tracing_indicatif::span_ext::IndicatifSpanExt;
|
||||
|
||||
struct PacketTag {
|
||||
sending_timestamp: OffsetDateTime,
|
||||
batch_id: u64,
|
||||
index: u64,
|
||||
}
|
||||
|
||||
impl PacketTag {
|
||||
const SIZE: usize = 32;
|
||||
|
||||
fn elapsed(&self) -> time::Duration {
|
||||
OffsetDateTime::now_utc() - self.sending_timestamp
|
||||
}
|
||||
|
||||
fn elapsed_nanos(&self) -> u64 {
|
||||
// here we're making few assumptions: the latency is lower than u64::MAX
|
||||
// and it's strictly positive (which are rather valid...)
|
||||
self.elapsed().whole_nanoseconds() as u64
|
||||
}
|
||||
|
||||
fn to_bytes(&self) -> Vec<u8> {
|
||||
self.sending_timestamp
|
||||
.unix_timestamp_nanos()
|
||||
.to_be_bytes()
|
||||
.into_iter()
|
||||
.chain(self.batch_id.to_be_bytes())
|
||||
.chain(self.index.to_be_bytes())
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[allow(clippy::unwrap_used)]
|
||||
fn from_bytes(bytes: &[u8]) -> PacketTag {
|
||||
let sending_timestamp = i128::from_be_bytes(bytes[0..16].try_into().unwrap());
|
||||
let sending_timestamp =
|
||||
OffsetDateTime::from_unix_timestamp_nanos(sending_timestamp).unwrap();
|
||||
|
||||
let batch_id = u64::from_be_bytes(bytes[8..16].try_into().unwrap());
|
||||
let index = u64::from_be_bytes(bytes[16..24].try_into().unwrap());
|
||||
PacketTag {
|
||||
sending_timestamp,
|
||||
batch_id,
|
||||
index,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct ThroughputTestingClient {
|
||||
stats: ClientStats,
|
||||
last_received_update: Instant,
|
||||
last_received_at_update: usize,
|
||||
current_batch: u64,
|
||||
sending_delay: Duration,
|
||||
latency_threshold: Duration,
|
||||
current_batch_size: usize,
|
||||
forward_header_bytes: Vec<u8>,
|
||||
unwrapped_forward_payload_bytes: Vec<u8>,
|
||||
shutdown_token: ShutdownToken,
|
||||
local_address: SocketAddr,
|
||||
listener: TcpListener,
|
||||
forward_connection: Framed<TcpStream, NymCodec>,
|
||||
payload_key: PayloadKey,
|
||||
}
|
||||
|
||||
impl ThroughputTestingClient {
|
||||
pub(crate) async fn try_create(
|
||||
initial_sending_delay: Duration,
|
||||
initial_batch_size: usize,
|
||||
latency_threshold: Duration,
|
||||
node_keys: &x25519::KeyPair,
|
||||
node_listener: SocketAddr,
|
||||
stats: ClientStats,
|
||||
cancellation_token: ShutdownToken,
|
||||
) -> anyhow::Result<Self> {
|
||||
// attempt to bind to some port to receive processed packets
|
||||
let listener = TcpListener::bind(SocketAddr::from(([127, 0, 0, 1], 0))).await?;
|
||||
let local_address = listener.local_addr()?;
|
||||
|
||||
info!("listening on {local_address}");
|
||||
|
||||
// create the sphinx packet we're going to be repeatedly sending
|
||||
// (next hop has to be our mixnode, then this client, and then it doesn't matter since the packet won't
|
||||
// get further processed)
|
||||
let mut rng = OsRng;
|
||||
// keys of this client
|
||||
let ephemeral_keys = x25519::KeyPair::new(&mut rng);
|
||||
|
||||
let route = [
|
||||
Node::new(
|
||||
NymNodeRoutingAddress::from(node_listener).try_into()?,
|
||||
(*node_keys.public_key()).into(),
|
||||
),
|
||||
Node::new(
|
||||
NymNodeRoutingAddress::from(local_address).try_into()?,
|
||||
(*ephemeral_keys.public_key()).into(),
|
||||
),
|
||||
Node::new(
|
||||
NymNodeRoutingAddress::from(local_address).try_into()?,
|
||||
(*ephemeral_keys.public_key()).into(),
|
||||
),
|
||||
];
|
||||
let destination = Destination::new(
|
||||
DestinationAddressBytes::from_bytes([0u8; DESTINATION_ADDRESS_LENGTH]),
|
||||
[0u8; IDENTIFIER_LENGTH],
|
||||
);
|
||||
let delays = generate_hop_delays(Duration::default(), 3);
|
||||
let payload = PacketSize::RegularPacket.payload_size();
|
||||
|
||||
let forward_packet =
|
||||
NymPacket::sphinx_build(payload, b"foomp", &route, &destination, &delays)?;
|
||||
|
||||
// SAFETY: we constructed a sphinx packet...
|
||||
#[allow(clippy::unwrap_used)]
|
||||
let sphinx_packet = forward_packet.as_sphinx_packet().unwrap();
|
||||
let header = &sphinx_packet.header;
|
||||
|
||||
// derive the routing keys of our node so we could tag the payload to figure out latency
|
||||
// by tagging the packet
|
||||
let routing_keys = SphinxHeader::compute_routing_keys(
|
||||
&header.shared_secret,
|
||||
(&node_keys.private_key()).as_ref(),
|
||||
);
|
||||
let payload_key = routing_keys.payload_key;
|
||||
let unwrapped_payload = sphinx_packet.payload.unwrap(&payload_key)?;
|
||||
let unwrapped_forward_payload_bytes = unwrapped_payload.into_bytes();
|
||||
|
||||
let start = Instant::now();
|
||||
let forward_connection = loop {
|
||||
if let Ok(connection) = TcpStream::connect(node_listener).await {
|
||||
break connection;
|
||||
}
|
||||
// fallback
|
||||
sleep(Duration::from_secs(1)).await;
|
||||
if start.elapsed() > Duration::from_secs(10) {
|
||||
bail!("failed to connect to local nym-node")
|
||||
}
|
||||
};
|
||||
|
||||
Ok(ThroughputTestingClient {
|
||||
stats,
|
||||
last_received_update: Instant::now(),
|
||||
last_received_at_update: 0,
|
||||
current_batch: 0,
|
||||
sending_delay: initial_sending_delay,
|
||||
latency_threshold,
|
||||
current_batch_size: initial_batch_size,
|
||||
forward_header_bytes: sphinx_packet.header.to_bytes(),
|
||||
unwrapped_forward_payload_bytes,
|
||||
shutdown_token: cancellation_token,
|
||||
local_address,
|
||||
listener,
|
||||
forward_connection: Framed::new(forward_connection, NymCodec),
|
||||
payload_key,
|
||||
})
|
||||
}
|
||||
|
||||
fn update_progress_bar(&mut self) {
|
||||
let received = self.stats.received();
|
||||
let sent = self.stats.sent();
|
||||
let latency = self.stats.average_latency_duration();
|
||||
let received_since_update = received - self.last_received_at_update;
|
||||
|
||||
let time_delta_secs = self.last_received_update.elapsed().as_secs_f64();
|
||||
let receive_rate = received_since_update as f64 / time_delta_secs;
|
||||
|
||||
self.last_received_at_update = received;
|
||||
self.last_received_update = Instant::now();
|
||||
// I couldn't figure out how to directly pull it from span fields without duplication,
|
||||
// so that's a second best
|
||||
Span::current().pb_set_message(&format!(
|
||||
"{}: CURRENT SENDING DELAY/BATCH: {} / {} | received: {} sent: {} (avg packet latency: {}, avg receive rate: {})",
|
||||
self.local_address,
|
||||
self.sending_delay.human_duration(),
|
||||
self.current_batch_size,
|
||||
received.human_count_bare(),
|
||||
sent.human_count_bare(),
|
||||
latency.human_duration(),
|
||||
receive_rate.human_throughput("packets")
|
||||
));
|
||||
}
|
||||
|
||||
fn lioness_encrypt(&self, block: &mut [u8]) -> anyhow::Result<()> {
|
||||
let lioness_cipher = Lioness::<VarBlake2b, ChaCha>::new_raw(array_ref!(
|
||||
self.payload_key,
|
||||
0,
|
||||
lioness::RAW_KEY_SIZE
|
||||
));
|
||||
lioness_cipher.encrypt(block)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn tag_framed_packet(&self, tag: PacketTag) -> anyhow::Result<FramedNymPacket> {
|
||||
let tag_bytes = tag.to_bytes();
|
||||
|
||||
let mut payload_bytes = self.unwrapped_forward_payload_bytes.clone();
|
||||
payload_bytes[..PacketTag::SIZE].copy_from_slice(&tag_bytes);
|
||||
|
||||
self.lioness_encrypt(&mut payload_bytes)?;
|
||||
|
||||
let mut packet_bytes = self.forward_header_bytes.clone();
|
||||
packet_bytes.append(&mut payload_bytes);
|
||||
|
||||
let forward_packet = NymPacket::sphinx_from_bytes(&packet_bytes)?;
|
||||
Ok(FramedNymPacket::new(forward_packet, Default::default()))
|
||||
}
|
||||
|
||||
async fn send_packets(&mut self) -> anyhow::Result<()> {
|
||||
// mess with our payload in such a way that upon unwrapping by the first hop,
|
||||
// we'll get our tag
|
||||
let mut batch = Vec::with_capacity(self.current_batch_size);
|
||||
let now = OffsetDateTime::now_utc();
|
||||
for i in 0..self.current_batch_size {
|
||||
let tag = PacketTag {
|
||||
sending_timestamp: now,
|
||||
batch_id: self.current_batch,
|
||||
index: i as u64,
|
||||
};
|
||||
let framed_packet = self.tag_framed_packet(tag)?;
|
||||
batch.push(Ok(framed_packet));
|
||||
}
|
||||
|
||||
self.current_batch += 1;
|
||||
self.forward_connection
|
||||
.send_all(&mut stream::iter(batch))
|
||||
.await?;
|
||||
self.stats.new_sent_batch(self.current_batch_size);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// don't bother processing packets, just increment the count because that's the only thing that matters
|
||||
fn handle_received(&mut self, maybe_packet: Result<FramedNymPacket, NymCodecError>) {
|
||||
let Ok(received) = maybe_packet else {
|
||||
error!("FAILED TO RECEIVE PACKET");
|
||||
return;
|
||||
};
|
||||
let inner = received.into_inner();
|
||||
// safety: we sent a sphinx packet...
|
||||
#[allow(clippy::unwrap_used)]
|
||||
let sphinx = inner.as_sphinx_packet().unwrap();
|
||||
let tag = PacketTag::from_bytes(sphinx.payload.as_bytes());
|
||||
|
||||
self.stats.new_received(tag.elapsed_nanos());
|
||||
}
|
||||
|
||||
fn update_sending_rates(&mut self) {
|
||||
let current = self.stats.average_latency_nanos() as f64;
|
||||
let threshold = self.latency_threshold.as_nanos() as f64;
|
||||
|
||||
let saturation = current / threshold;
|
||||
|
||||
let sending_delay_nanos = self.sending_delay.as_nanos();
|
||||
let batch_size = self.current_batch_size;
|
||||
|
||||
let diff = 1. - saturation;
|
||||
|
||||
if saturation > 1. {
|
||||
debug!("saturation {saturation:.2}, packet latency over threshold: need to decrease sending rate");
|
||||
} else {
|
||||
debug!("saturation {saturation:.2}, packet latency under threshold: can increase sending rate");
|
||||
}
|
||||
|
||||
// be conservative and only apply 50% of the diff
|
||||
// (and split it equally between sending delay and batch size)
|
||||
// but also make sure the current values don't increase by more than 5%
|
||||
let mut new_batch_size = (batch_size as f64 * (1. + 0.25 * diff)).floor() as u64;
|
||||
let mut new_sending_delay_nanos =
|
||||
(sending_delay_nanos as f64 * (1. - 0.25 * diff)).floor() as u64;
|
||||
|
||||
if (new_batch_size as f64) > (batch_size as f64 * 1.05) {
|
||||
new_batch_size = ((batch_size as f64) * 1.05) as u64;
|
||||
}
|
||||
if (new_batch_size as f64) < (batch_size as f64 * 0.95) {
|
||||
new_batch_size = ((batch_size as f64) * 0.95) as u64;
|
||||
}
|
||||
|
||||
if (new_sending_delay_nanos as f64) > (sending_delay_nanos as f64 * 1.05) {
|
||||
new_sending_delay_nanos = ((sending_delay_nanos as f64) * 1.05) as u64;
|
||||
}
|
||||
if (new_sending_delay_nanos as f64) < (sending_delay_nanos as f64 * 0.95) {
|
||||
new_sending_delay_nanos = ((sending_delay_nanos as f64) * 0.95) as u64;
|
||||
}
|
||||
|
||||
// normalize values
|
||||
if new_batch_size < 20 {
|
||||
new_batch_size = 20;
|
||||
}
|
||||
let mut new_sending_delay = Duration::from_nanos(new_sending_delay_nanos);
|
||||
|
||||
if new_sending_delay.is_zero() {
|
||||
new_sending_delay = Duration::from_micros(500);
|
||||
}
|
||||
if new_sending_delay.as_millis() > 100 {
|
||||
new_sending_delay = Duration::from_millis(100);
|
||||
}
|
||||
|
||||
debug!(
|
||||
"changing sending delay from {} to {}",
|
||||
self.sending_delay.human_duration(),
|
||||
new_sending_delay.human_duration()
|
||||
);
|
||||
debug!("changing sending batch from {batch_size} to {new_batch_size}");
|
||||
|
||||
self.sending_delay = new_sending_delay;
|
||||
self.current_batch_size = new_batch_size as usize;
|
||||
}
|
||||
|
||||
#[allow(clippy::panic)]
|
||||
pub(crate) async fn run(mut self) -> anyhow::Result<()> {
|
||||
let mut ingress_connection = StreamWrapper::default();
|
||||
|
||||
let mut sending_interval = interval(self.sending_delay);
|
||||
sending_interval.reset();
|
||||
|
||||
// quite arbitrary
|
||||
let mut update_interval = interval(Duration::from_millis(500));
|
||||
update_interval.reset();
|
||||
|
||||
let mut last_rate_update = Instant::now();
|
||||
|
||||
loop {
|
||||
select! {
|
||||
biased;
|
||||
_ = self.shutdown_token.cancelled() => {
|
||||
info!("cancelled");
|
||||
return Ok(());
|
||||
}
|
||||
_ = update_interval.tick() => {
|
||||
self.update_progress_bar();
|
||||
|
||||
// every 500ms attempt to adjust sending rates
|
||||
if last_rate_update.elapsed() > Duration::from_millis(500) {
|
||||
last_rate_update = Instant::now();
|
||||
self.update_sending_rates();
|
||||
sending_interval = interval(self.sending_delay);
|
||||
sending_interval.reset();
|
||||
}
|
||||
|
||||
}
|
||||
accepted = self.listener.accept() => {
|
||||
info!("accepted connection");
|
||||
if ingress_connection.inner.is_some() {
|
||||
// this should never happen under local settings
|
||||
// (and since it's not exposed to 'proper' traffic, it's fine to panic and shutdown)
|
||||
panic!("attempted to overwrite existing connection")
|
||||
}
|
||||
let (stream, _) = accepted?;
|
||||
let framed = Framed::new(stream, NymCodec);
|
||||
ingress_connection.set(framed);
|
||||
}
|
||||
received = ingress_connection.next() => {
|
||||
let Some(received) = received else {
|
||||
// if the stream has terminated, we return
|
||||
if ingress_connection.inner.is_some() {
|
||||
return Ok(())
|
||||
}
|
||||
continue;
|
||||
};
|
||||
self.handle_received(received)
|
||||
}
|
||||
_ = sending_interval.tick() => {
|
||||
self.send_packets().await?;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// I must be blind, because I couldn't find something to do equivalent of `OptionStream`...
|
||||
#[derive(Default)]
|
||||
struct StreamWrapper {
|
||||
inner: Option<Framed<TcpStream, NymCodec>>,
|
||||
maybe_initial_waker: Option<Waker>,
|
||||
}
|
||||
|
||||
impl StreamWrapper {
|
||||
fn set(&mut self, inner: Framed<TcpStream, NymCodec>) {
|
||||
self.inner = Some(inner);
|
||||
if let Some(waker) = self.maybe_initial_waker.take() {
|
||||
waker.wake();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Stream for StreamWrapper {
|
||||
type Item = <Framed<TcpStream, NymCodec> as Stream>::Item;
|
||||
|
||||
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||
match self.inner.as_mut() {
|
||||
None => {
|
||||
self.maybe_initial_waker = Some(cx.waker().clone());
|
||||
Poll::Pending
|
||||
}
|
||||
Some(inner) => Pin::new(inner).poll_next(cx),
|
||||
}
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
match &self.inner {
|
||||
None => (0, None),
|
||||
Some(inner) => inner.size_hint(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,183 @@
|
||||
// Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
use crate::throughput_tester::stats::ClientStats;
|
||||
use colored::Colorize;
|
||||
use human_repr::{HumanCount, HumanDuration, HumanThroughput};
|
||||
use nym_task::ShutdownToken;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
use std::fs::create_dir_all;
|
||||
use std::path::PathBuf;
|
||||
use std::time::Duration;
|
||||
use sysinfo::System;
|
||||
use time::OffsetDateTime;
|
||||
use tokio::select;
|
||||
use tokio::time::{interval, Instant};
|
||||
use tracing::{error, info, Span};
|
||||
use tracing_indicatif::span_ext::IndicatifSpanExt;
|
||||
|
||||
#[derive(Default, Serialize, Deserialize)]
|
||||
pub(crate) struct StatsRecord {
|
||||
timestamp: i64,
|
||||
receive_rate: f64,
|
||||
latency: u64,
|
||||
sent: usize,
|
||||
received: usize,
|
||||
}
|
||||
|
||||
pub(crate) struct GlobalStatsUpdater {
|
||||
system: System,
|
||||
last_update: Instant,
|
||||
last_total_received: usize,
|
||||
header_span: Span,
|
||||
client_stats: Vec<ClientStats>,
|
||||
|
||||
global_records: Vec<StatsRecord>,
|
||||
records: HashMap<usize, Vec<StatsRecord>>,
|
||||
|
||||
output_directory: PathBuf,
|
||||
shutdown: ShutdownToken,
|
||||
}
|
||||
|
||||
impl GlobalStatsUpdater {
|
||||
pub(crate) fn new(
|
||||
header_span: Span,
|
||||
client_stats: Vec<ClientStats>,
|
||||
output_directory: PathBuf,
|
||||
shutdown: ShutdownToken,
|
||||
) -> Self {
|
||||
let mut system_info = System::new_all();
|
||||
system_info.refresh_cpu_usage();
|
||||
|
||||
// pre-allocate vecs
|
||||
let mut records = HashMap::new();
|
||||
for (i, _) in client_stats.iter().enumerate() {
|
||||
records.insert(i, vec![]);
|
||||
}
|
||||
|
||||
GlobalStatsUpdater {
|
||||
system: system_info,
|
||||
last_update: Instant::now(),
|
||||
last_total_received: 0,
|
||||
header_span,
|
||||
client_stats,
|
||||
global_records: vec![],
|
||||
records,
|
||||
output_directory,
|
||||
shutdown,
|
||||
}
|
||||
}
|
||||
|
||||
fn update_stats_span(&mut self) {
|
||||
let now = OffsetDateTime::now_utc().unix_timestamp();
|
||||
let time_delta_secs = self.last_update.elapsed().as_secs_f64();
|
||||
|
||||
let mut all_received = 0;
|
||||
let mut all_sent = 0;
|
||||
let mut all_latencies = 0;
|
||||
for (i, stat) in self.client_stats.iter().enumerate() {
|
||||
// SAFETY: we create all entries during initialisation
|
||||
#[allow(clippy::unwrap_used)]
|
||||
let records = self.records.get_mut(&i).unwrap();
|
||||
|
||||
let mut client_record = StatsRecord::default();
|
||||
|
||||
let sent = stat.sent();
|
||||
let received = stat.received();
|
||||
let latency = stat.average_latency_nanos();
|
||||
|
||||
client_record.timestamp = now;
|
||||
client_record.received = received;
|
||||
client_record.sent = sent;
|
||||
client_record.latency = latency;
|
||||
if let Some(last) = records.last() {
|
||||
let receive_rate = (received - last.received) as f64 / time_delta_secs;
|
||||
client_record.receive_rate = receive_rate;
|
||||
}
|
||||
records.push(client_record);
|
||||
|
||||
all_sent += sent;
|
||||
all_received += received;
|
||||
all_latencies += latency;
|
||||
}
|
||||
|
||||
let receive_rate = (all_received - self.last_total_received) as f64 / time_delta_secs;
|
||||
let avg_rate = receive_rate.human_throughput("packets");
|
||||
let avg_latency = all_latencies as f64 / self.client_stats.len() as f64;
|
||||
|
||||
self.global_records.push(StatsRecord {
|
||||
timestamp: now,
|
||||
receive_rate,
|
||||
latency: avg_latency as u64,
|
||||
sent: all_sent,
|
||||
received: all_received,
|
||||
});
|
||||
|
||||
self.system.refresh_cpu_usage();
|
||||
let cpu_usage = self.system.global_cpu_usage();
|
||||
let cpu_count = self.system.cpus().len();
|
||||
let usage_per_cpu = cpu_usage / cpu_count as f32;
|
||||
|
||||
let formatted_usage = if usage_per_cpu < 0.3 {
|
||||
format!("{:.2}%", usage_per_cpu * 100.).green().bold()
|
||||
} else if usage_per_cpu < 0.7 {
|
||||
format!("{:.2}%", usage_per_cpu * 100.).yellow().bold()
|
||||
} else {
|
||||
format!("{:.2}%", usage_per_cpu * 100.).red().bold()
|
||||
};
|
||||
|
||||
self.header_span.pb_set_message(&format!(
|
||||
"active_clients: {} | total received: {} total sent {} (avg packet latency: {}, total receive rate: {avg_rate}), avg core load: {formatted_usage}",
|
||||
self.client_stats.len(),
|
||||
all_received.human_count_bare(),
|
||||
all_sent.human_count_bare(),
|
||||
Duration::from_nanos(avg_latency as u64).human_duration()
|
||||
));
|
||||
self.last_total_received = all_received;
|
||||
self.last_update = Instant::now();
|
||||
}
|
||||
|
||||
fn save_results_to_files(&self) -> anyhow::Result<()> {
|
||||
create_dir_all(self.output_directory.as_path())?;
|
||||
|
||||
let global = self.output_directory.join("global_stats.csv");
|
||||
let mut writer = csv::Writer::from_path(&global)?;
|
||||
for record in &self.global_records {
|
||||
writer.serialize(record)?;
|
||||
}
|
||||
|
||||
info!("wrote global stats to {}", global.display());
|
||||
|
||||
for (sender_id, records) in self.records.iter() {
|
||||
let output = self
|
||||
.output_directory
|
||||
.join(format!("sender{}.csv", sender_id));
|
||||
let mut writer = csv::Writer::from_path(&output)?;
|
||||
for record in records {
|
||||
writer.serialize(record)?;
|
||||
}
|
||||
info!("wrote client records to {}", output.display());
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) async fn run(&mut self) {
|
||||
let mut update_interval = interval(Duration::from_millis(500));
|
||||
|
||||
loop {
|
||||
select! {
|
||||
biased;
|
||||
_ = self.shutdown.cancelled() => {
|
||||
if let Err(err) = self.save_results_to_files() {
|
||||
error!("failed to save measurement results to files: {err}")
|
||||
}
|
||||
break;
|
||||
}
|
||||
_ = update_interval.tick() => {
|
||||
self.update_stats_span();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,185 @@
|
||||
// Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
use crate::config::upgrade_helpers::try_load_current_config;
|
||||
use crate::node::NymNode;
|
||||
use crate::throughput_tester::client::ThroughputTestingClient;
|
||||
use crate::throughput_tester::global_stats::GlobalStatsUpdater;
|
||||
use crate::throughput_tester::stats::ClientStats;
|
||||
use futures::future::join_all;
|
||||
use human_repr::HumanDuration;
|
||||
use indicatif::{ProgressState, ProgressStyle};
|
||||
use nym_crypto::asymmetric::x25519;
|
||||
use nym_task::ShutdownToken;
|
||||
use rand::{thread_rng, Rng};
|
||||
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use tokio::runtime;
|
||||
use tokio::runtime::Runtime;
|
||||
use tokio::time::sleep;
|
||||
use tracing::{info, info_span, instrument};
|
||||
use tracing_indicatif::span_ext::IndicatifSpanExt;
|
||||
|
||||
pub(crate) mod client;
|
||||
pub(crate) mod global_stats;
|
||||
mod stats;
|
||||
|
||||
pub struct ThroughputTest {
|
||||
node_runtime: Runtime,
|
||||
clients_runtime: Runtime,
|
||||
}
|
||||
|
||||
impl ThroughputTest {
|
||||
fn new(senders: usize) -> anyhow::Result<Self> {
|
||||
Ok(ThroughputTest {
|
||||
node_runtime: runtime::Builder::new_multi_thread()
|
||||
.enable_all()
|
||||
.thread_name("nym-node-pool")
|
||||
.build()?,
|
||||
clients_runtime: runtime::Builder::new_multi_thread()
|
||||
.enable_all()
|
||||
.worker_threads(senders)
|
||||
.thread_name("testing-clients-pool")
|
||||
.build()?,
|
||||
})
|
||||
}
|
||||
|
||||
fn prepare_nymnode(&self, config_path: PathBuf) -> anyhow::Result<NymNode> {
|
||||
self.node_runtime.block_on(async {
|
||||
let mut config = try_load_current_config(config_path).await?;
|
||||
|
||||
// make sure to change bind address to localhost!
|
||||
config
|
||||
.mixnet
|
||||
.bind_address
|
||||
.set_ip(IpAddr::V4(Ipv4Addr::LOCALHOST));
|
||||
|
||||
let nym_node = NymNode::new(config).await?;
|
||||
Ok(nym_node)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(
|
||||
skip_all,
|
||||
fields(
|
||||
sender_id = %sender_id
|
||||
)
|
||||
|
||||
)]
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
async fn run_testing_client(
|
||||
sender_id: usize,
|
||||
node_keys: Arc<x25519::KeyPair>,
|
||||
node_listener: SocketAddr,
|
||||
packet_latency_threshold: Duration,
|
||||
starting_sending_batch_size: usize,
|
||||
starting_sending_delay: Duration,
|
||||
stats: ClientStats,
|
||||
shutdown_token: ShutdownToken,
|
||||
) -> anyhow::Result<()> {
|
||||
let _ = sender_id;
|
||||
let client = ThroughputTestingClient::try_create(
|
||||
starting_sending_delay,
|
||||
starting_sending_batch_size,
|
||||
packet_latency_threshold,
|
||||
&node_keys,
|
||||
node_listener,
|
||||
stats,
|
||||
shutdown_token,
|
||||
)
|
||||
.await?;
|
||||
|
||||
// wait a random amount of time before actually starting to desync the clients a bit
|
||||
// (so they wouldn't update their rates at the same time)
|
||||
let delay = Duration::from_millis(thread_rng().gen_range(10..200));
|
||||
info!(
|
||||
"waiting for {} before attempting to start the processing loop",
|
||||
delay.human_duration()
|
||||
);
|
||||
sleep(delay).await;
|
||||
|
||||
client.run().await
|
||||
}
|
||||
|
||||
pub(crate) fn test_mixing_throughput(
|
||||
config_path: PathBuf,
|
||||
senders: usize,
|
||||
packet_latency_threshold: Duration,
|
||||
starting_sending_batch_size: usize,
|
||||
starting_sending_delay: Duration,
|
||||
output_directory: PathBuf,
|
||||
) -> anyhow::Result<()> {
|
||||
let tester = ThroughputTest::new(senders)?;
|
||||
|
||||
let nym_node = tester.prepare_nymnode(config_path)?;
|
||||
let listener = nym_node.config().mixnet.bind_address;
|
||||
|
||||
let sphinx_keys = nym_node.x25519_sphinx_keys();
|
||||
|
||||
let mut stats = Vec::with_capacity(senders);
|
||||
for _ in 0..senders {
|
||||
stats.push(ClientStats::default())
|
||||
}
|
||||
|
||||
let header_span = info_span!("header");
|
||||
header_span.pb_set_style(
|
||||
&ProgressStyle::with_template(
|
||||
"testing mixing throughput of this machine... {wide_msg} {elapsed}\n{wide_bar}",
|
||||
)?
|
||||
.with_key(
|
||||
"elapsed",
|
||||
|state: &ProgressState, writer: &mut dyn std::fmt::Write| {
|
||||
let _ = writer.write_str(&format!("{}", state.elapsed().human_duration()));
|
||||
},
|
||||
)
|
||||
.progress_chars("---"),
|
||||
);
|
||||
header_span.pb_start();
|
||||
|
||||
// Bit of a hack to show a full "-----" line underneath the header.
|
||||
header_span.pb_set_length(1);
|
||||
header_span.pb_set_position(1);
|
||||
|
||||
let mut tasks_handles = Vec::new();
|
||||
|
||||
for (sender_id, stats) in stats.iter().enumerate() {
|
||||
let token = nym_node.shutdown_token(format!("dummy-load-client-{sender_id}"));
|
||||
|
||||
let client_future = run_testing_client(
|
||||
sender_id,
|
||||
sphinx_keys.clone(),
|
||||
listener,
|
||||
packet_latency_threshold,
|
||||
starting_sending_batch_size,
|
||||
starting_sending_delay,
|
||||
stats.clone(),
|
||||
token,
|
||||
);
|
||||
let handle = tester.clients_runtime.spawn(client_future);
|
||||
tasks_handles.push(handle);
|
||||
}
|
||||
|
||||
let mut global_stats = GlobalStatsUpdater::new(
|
||||
header_span,
|
||||
stats,
|
||||
output_directory,
|
||||
nym_node.shutdown_token("global-stats"),
|
||||
);
|
||||
|
||||
let stats_handle = tester.clients_runtime.spawn(async move {
|
||||
global_stats.run().await;
|
||||
Ok(())
|
||||
});
|
||||
tasks_handles.push(stats_handle);
|
||||
|
||||
tester
|
||||
.node_runtime
|
||||
.block_on(async move { nym_node.run_minimal_mixnet_processing().await })?;
|
||||
|
||||
tester.clients_runtime.block_on(join_all(tasks_handles));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
// Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
use std::sync::atomic::{AtomicU64, AtomicUsize, Ordering};
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
pub(crate) struct ClientStats {
|
||||
inner: Arc<ClientStatsInner>,
|
||||
}
|
||||
|
||||
impl ClientStats {
|
||||
pub(crate) fn new_received(&self, new_measurement: u64) {
|
||||
const ALPHA: f64 = 0.0005;
|
||||
const ONE_SUB_ALPHA: f64 = 1.0 - ALPHA;
|
||||
|
||||
let old_average_latency = self.inner.average_latency_nanos.load(Ordering::SeqCst);
|
||||
|
||||
let new_average = if old_average_latency == 0 {
|
||||
new_measurement
|
||||
} else {
|
||||
((ALPHA * new_measurement as f64) + ONE_SUB_ALPHA * old_average_latency as f64) as u64
|
||||
};
|
||||
|
||||
self.inner.received.fetch_add(1, Ordering::SeqCst);
|
||||
self.inner
|
||||
.average_latency_nanos
|
||||
.store(new_average, Ordering::SeqCst);
|
||||
}
|
||||
|
||||
pub(crate) fn new_sent_batch(&self, batch_size: usize) {
|
||||
self.inner.sent.fetch_add(batch_size, Ordering::SeqCst);
|
||||
}
|
||||
|
||||
pub(crate) fn received(&self) -> usize {
|
||||
self.inner.received.load(Ordering::SeqCst)
|
||||
}
|
||||
|
||||
pub(crate) fn sent(&self) -> usize {
|
||||
self.inner.sent.load(Ordering::SeqCst)
|
||||
}
|
||||
|
||||
pub(crate) fn average_latency_nanos(&self) -> u64 {
|
||||
self.inner.average_latency_nanos.load(Ordering::SeqCst)
|
||||
}
|
||||
|
||||
pub(crate) fn average_latency_duration(&self) -> Duration {
|
||||
Duration::from_nanos(self.average_latency_nanos())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct ClientStatsInner {
|
||||
sent: AtomicUsize,
|
||||
received: AtomicUsize,
|
||||
average_latency_nanos: AtomicU64,
|
||||
}
|
||||
Generated
+2323
-814
File diff suppressed because it is too large
Load Diff
@@ -21,6 +21,7 @@
|
||||
"webpack:prod": "yarn webpack --progress --config webpack.prod.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/helper-simple-access": "^7.25.9",
|
||||
"@emotion/react": "^11.7.0",
|
||||
"@emotion/styled": "^11.6.0",
|
||||
"@hookform/resolvers": "^2.8.0",
|
||||
@@ -33,7 +34,10 @@
|
||||
"@nymproject/react": "^1.0.0",
|
||||
"@nymproject/types": "^1.0.0",
|
||||
"@storybook/react": "^6.5.15",
|
||||
"@tauri-apps/api": "^1.2.0",
|
||||
"@tauri-apps/api": "^2.4.0",
|
||||
"@tauri-apps/cli": "^2.4.0",
|
||||
"@tauri-apps/plugin-clipboard-manager": "^2.2.2",
|
||||
"@tauri-apps/plugin-updater": "^2.0.0",
|
||||
"@tauri-apps/tauri-forage": "^1.0.0-beta.2",
|
||||
"big.js": "^6.2.1",
|
||||
"bs58": "^4.0.1",
|
||||
@@ -67,7 +71,7 @@
|
||||
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.4",
|
||||
"@storybook/react": "^6.5.15",
|
||||
"@svgr/webpack": "^6.1.1",
|
||||
"@tauri-apps/cli": "^1.0.5",
|
||||
"@tauri-apps/cli": "^2.4.0",
|
||||
"@testing-library/jest-dom": "^5.14.1",
|
||||
"@testing-library/react": "^12.0.0",
|
||||
"@types/big.js": "^6.1.6",
|
||||
@@ -125,4 +129,4 @@
|
||||
"webpack-merge": "^5.8.0"
|
||||
},
|
||||
"private": false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,17 +13,21 @@ rust-version = "1.76"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[build-dependencies]
|
||||
tauri-build = { version = "=1.2.1", features = [] }
|
||||
tauri-build = { version = "2", features = [] }
|
||||
|
||||
tauri-codegen = "=1.2.1"
|
||||
tauri-macros = "=1.2.1"
|
||||
|
||||
[dependencies]
|
||||
async-trait = "0.1.68"
|
||||
tauri-plugin-updater = "2"
|
||||
tauri-plugin-clipboard-manager = "2"
|
||||
tauri-plugin-shell = "2"
|
||||
tauri-plugin-process = "2"
|
||||
bip39 = { version = "2.0.0", features = ["zeroize", "rand"] }
|
||||
cfg-if = "1.0.0"
|
||||
colored = "2.0"
|
||||
dirs = "4.0"
|
||||
dirs = "6.0"
|
||||
dotenvy = "0.15.6"
|
||||
eyre = "0.6.5"
|
||||
fern = { version = "0.6.1", features = ["colored"] }
|
||||
@@ -38,7 +42,7 @@ serde_json = "1.0"
|
||||
serde_repr = "0.1"
|
||||
strum = { version = "0.23", features = ["derive"] }
|
||||
tap = "1"
|
||||
tauri = { version = "=1.2.3", features = ["clipboard-all", "shell-open", "updater", "window-maximize", "window-print"] }
|
||||
tauri = { version = "2", features = [] }
|
||||
#tendermint-rpc = "0.23.0"
|
||||
time = { version = "0.3.30", features = ["local-offset"] }
|
||||
thiserror = "1.0"
|
||||
@@ -63,6 +67,11 @@ nym-types = { path = "../../common/types" }
|
||||
nym-wallet-types = { path = "../nym-wallet-types" }
|
||||
nym-store-cipher = { path = "../../common/store-cipher", features = ["json"] }
|
||||
|
||||
|
||||
# https://github.com/ebarnard/rust-plist/issues/151#issuecomment-2746645171
|
||||
# https://github.com/jhpratt/deranged/issues/18
|
||||
deranged = "=0.4.0"
|
||||
|
||||
[dev-dependencies]
|
||||
nym-crypto = { path = "../../common/crypto", features = ["rand"] }
|
||||
rand_chacha = "0.3"
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"identifier": "migrated",
|
||||
"description": "permissions that were migrated from v1",
|
||||
"local": true,
|
||||
"windows": [
|
||||
"main"
|
||||
],
|
||||
"permissions": [
|
||||
"core:default"
|
||||
]
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
|
||||
{"migrated":{"identifier":"migrated","description":"permissions that were migrated from v1","local":true,"windows":["main"],"permissions":["core:default"]}}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -105,7 +105,17 @@ impl NetworkConfig {
|
||||
|
||||
impl Config {
|
||||
fn root_directory() -> PathBuf {
|
||||
tauri::api::path::config_dir().expect("Failed to get config directory")
|
||||
// tauri v1 (via `tauri::api::path::config_dir()`) was internally calling `dirs_next::config_dir()`
|
||||
// which ultimately was getting resolved to
|
||||
// - **Linux:** Resolves to `$XDG_CONFIG_HOME` or `$HOME/.config`.
|
||||
// - **macOS:** Resolves to `$HOME/Library/Application Support`.
|
||||
// - **Windows:** Resolves to `{FOLDERID_RoamingAppData}`.
|
||||
//
|
||||
// tauri v2 calls `dirs::config_dir().ok_or(Error::UnknownPath)` which ultimately does the same thing,
|
||||
// however, it changed its API so that it's called on a `PathResolver`.
|
||||
// but, to instantiate one here would be a hassle as we don't need those specific functionalities,
|
||||
// so let's just recreate tauri's behaviour
|
||||
dirs::config_dir().expect("Failed to get config directory")
|
||||
}
|
||||
|
||||
fn config_directory() -> PathBuf {
|
||||
|
||||
@@ -3,7 +3,7 @@ use std::str::FromStr;
|
||||
use fern::colors::{Color, ColoredLevelConfig};
|
||||
use serde::Serialize;
|
||||
use serde_repr::{Deserialize_repr, Serialize_repr};
|
||||
use tauri::Manager;
|
||||
use tauri::Emitter;
|
||||
use time::{format_description, OffsetDateTime};
|
||||
|
||||
fn formatted_time() -> String {
|
||||
@@ -61,7 +61,7 @@ pub fn setup_logging(app_handle: tauri::AppHandle) -> Result<(), log::SetLoggerE
|
||||
message: record.args().to_string(),
|
||||
level: record.level().into(),
|
||||
};
|
||||
app_handle.emit_all("log://log", msg).unwrap();
|
||||
app_handle.emit("log://log", msg).unwrap();
|
||||
}));
|
||||
|
||||
base_config
|
||||
|
||||
@@ -3,11 +3,11 @@
|
||||
windows_subsystem = "windows"
|
||||
)]
|
||||
|
||||
use tauri::{Manager, Menu};
|
||||
|
||||
use nym_mixnet_contract_common::{Gateway, MixNode};
|
||||
use tauri::menu::{MenuBuilder, MenuItemBuilder, SubmenuBuilder};
|
||||
use tauri::Manager;
|
||||
|
||||
use crate::menu::AddDefaultSubmenus;
|
||||
use crate::menu::SHOW_LOG_WINDOW;
|
||||
use crate::operations::app;
|
||||
use crate::operations::help;
|
||||
use crate::operations::mixnet;
|
||||
@@ -210,13 +210,31 @@ fn main() {
|
||||
app::react::set_react_state,
|
||||
app::react::get_react_state,
|
||||
])
|
||||
.menu(Menu::os_default(&context.package_info().name).add_default_app_submenus())
|
||||
.on_menu_event(|event| {
|
||||
if event.menu_item_id() == menu::SHOW_LOG_WINDOW {
|
||||
let _r = help::log::help_log_toggle_window(event.window().app_handle());
|
||||
.menu(|app| {
|
||||
// Create a menu builder
|
||||
let menu_builder = MenuBuilder::new(app);
|
||||
if ::std::env::var("NYM_WALLET_ENABLE_LOG").is_ok() {
|
||||
let help_text = MenuItemBuilder::with_id(SHOW_LOG_WINDOW, "Show logs")
|
||||
.build(app)
|
||||
.expect("Failed to create menu item");
|
||||
|
||||
let submenu = SubmenuBuilder::new(app, "Help")
|
||||
.items(&[&help_text])
|
||||
.build()
|
||||
.expect("Failed to create help submenu");
|
||||
|
||||
menu_builder.item(&submenu).build()
|
||||
} else {
|
||||
// Build a default menu without the submenu
|
||||
menu_builder.build()
|
||||
}
|
||||
})
|
||||
.setup(|app| Ok(log::setup_logging(app.app_handle())?))
|
||||
.on_menu_event(|app, event| {
|
||||
if event.id() == SHOW_LOG_WINDOW {
|
||||
let _r = help::log::help_log_toggle_window(app.app_handle().clone());
|
||||
}
|
||||
})
|
||||
.setup(|app| Ok(log::setup_logging(app.app_handle().clone())?))
|
||||
.run(context)
|
||||
.expect("error while running tauri application");
|
||||
}
|
||||
|
||||
@@ -1,22 +1,35 @@
|
||||
use tauri::Menu;
|
||||
use tauri::{CustomMenuItem, Submenu};
|
||||
// use tauri::menu::Menu;
|
||||
// use tauri::menu::{MenuBuilder, MenuItemBuilder, SubmenuBuilder};
|
||||
|
||||
pub const SHOW_LOG_WINDOW: &str = "show_log_window";
|
||||
|
||||
pub trait AddDefaultSubmenus {
|
||||
fn add_default_app_submenus(self) -> Self;
|
||||
}
|
||||
|
||||
impl AddDefaultSubmenus for Menu {
|
||||
#[allow(dead_code)]
|
||||
fn add_default_app_submenus(self) -> Self {
|
||||
if ::std::env::var("NYM_WALLET_ENABLE_LOG").is_ok() {
|
||||
let submenu = Submenu::new(
|
||||
"Help",
|
||||
Menu::new().add_item(CustomMenuItem::new(SHOW_LOG_WINDOW, "Show logs")),
|
||||
);
|
||||
return self.add_submenu(submenu);
|
||||
}
|
||||
self
|
||||
}
|
||||
}
|
||||
// pub trait AddDefaultSubmenus {
|
||||
// fn add_default_app_submenus(self) -> Self;
|
||||
// }
|
||||
//
|
||||
// impl<R: tauri::Runtime> AddDefaultSubmenus for Menu<R> {
|
||||
// #[allow(dead_code)]
|
||||
// fn add_default_app_submenus(self) -> Self {
|
||||
// if ::std::env::var("NYM_WALLET_ENABLE_LOG").is_ok() {
|
||||
// let app_handle = self.app_handle();
|
||||
//
|
||||
// let help_text = MenuItemBuilder::with_id(SHOW_LOG_WINDOW, "Show logs")
|
||||
// .build(app_handle)
|
||||
// .expect("Failed to create menu item");
|
||||
//
|
||||
// let submenu = SubmenuBuilder::new(app_handle, "Help")
|
||||
// .items(&[&help_text])
|
||||
// .build()
|
||||
// .expect("Failed to create help submenu");
|
||||
//
|
||||
// let menu_builder = MenuBuilder::new(app_handle);
|
||||
//
|
||||
// match menu_builder.item(&submenu).build() {
|
||||
// Ok(new_menu) => new_menu,
|
||||
// Err(_) => self,
|
||||
// }
|
||||
// } else {
|
||||
// self
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
@@ -3,27 +3,46 @@
|
||||
|
||||
use crate::error::BackendError;
|
||||
use nym_wallet_types::app::AppVersion;
|
||||
use tauri_plugin_updater::UpdaterExt;
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn check_version(handle: tauri::AppHandle) -> Result<AppVersion, BackendError> {
|
||||
log::info!(">>> Getting app version info");
|
||||
let res = tauri::updater::builder(handle)
|
||||
.check()
|
||||
.await
|
||||
.map(|u| AppVersion {
|
||||
current_version: u.current_version().to_string(),
|
||||
latest_version: u.latest_version().to_owned(),
|
||||
is_update_available: u.is_update_available(),
|
||||
|
||||
let updater = handle.updater().map_err(|e| {
|
||||
log::error!("Failed to get updater: {}", e);
|
||||
BackendError::CheckAppVersionError
|
||||
})?;
|
||||
|
||||
// Then check for updates
|
||||
let update_info = updater.check().await.map_err(|e| {
|
||||
log::error!("An error occurred while checking for app update {}", e);
|
||||
BackendError::CheckAppVersionError
|
||||
})?;
|
||||
|
||||
// Process the result
|
||||
if let Some(update) = update_info {
|
||||
log::debug!(
|
||||
"<<< update available: [true], current version {}, latest version {}",
|
||||
update.current_version,
|
||||
update.version
|
||||
);
|
||||
Ok(AppVersion {
|
||||
current_version: update.current_version.to_string(),
|
||||
latest_version: update.version,
|
||||
is_update_available: true,
|
||||
})
|
||||
.map_err(|e| {
|
||||
log::error!("An error ocurred while checking for app update {}", e);
|
||||
BackendError::CheckAppVersionError
|
||||
})?;
|
||||
log::debug!(
|
||||
"<<< update available: [{}], current version {}, latest version {}",
|
||||
res.is_update_available,
|
||||
res.current_version,
|
||||
res.latest_version
|
||||
);
|
||||
Ok(res)
|
||||
} else {
|
||||
// No update available
|
||||
let current_version = handle.package_info().version.to_string();
|
||||
log::debug!(
|
||||
"<<< update available: [false], current version {}",
|
||||
current_version
|
||||
);
|
||||
Ok(AppVersion {
|
||||
current_version: current_version.clone(),
|
||||
latest_version: current_version,
|
||||
is_update_available: false,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,10 +26,10 @@ async fn create_window(
|
||||
) -> Result<(), BackendError> {
|
||||
// create the new window first, to stop the app process from exiting
|
||||
log::info!("Creating {} window...", new_window_label);
|
||||
match tauri::WindowBuilder::new(
|
||||
match tauri::WebviewWindowBuilder::new(
|
||||
&app_handle,
|
||||
new_window_label,
|
||||
tauri::WindowUrl::App(new_window_url.into()),
|
||||
"main",
|
||||
tauri::WebviewUrl::App(new_window_url.into()),
|
||||
)
|
||||
.title("Nym Wallet")
|
||||
.build()
|
||||
@@ -49,7 +49,7 @@ async fn create_window(
|
||||
}
|
||||
|
||||
// close the old window
|
||||
match app_handle.windows().get(try_close_window_label) {
|
||||
match app_handle.get_webview_window(try_close_window_label) {
|
||||
Some(try_close_window) => {
|
||||
if let Err(err) = try_close_window.close() {
|
||||
log::error!("Could not close window: {err}")
|
||||
|
||||
@@ -3,7 +3,7 @@ use tauri::Manager;
|
||||
|
||||
#[tauri::command]
|
||||
pub fn help_log_toggle_window(app_handle: tauri::AppHandle) -> Result<(), BackendError> {
|
||||
if let Some(current_log_window) = app_handle.windows().get("log") {
|
||||
if let Some(current_log_window) = app_handle.get_webview_window("log") {
|
||||
log::info!("Closing log window...");
|
||||
if let Err(err) = current_log_window.close() {
|
||||
log::error!("Unable to close log window: {err}");
|
||||
@@ -12,9 +12,13 @@ pub fn help_log_toggle_window(app_handle: tauri::AppHandle) -> Result<(), Backen
|
||||
}
|
||||
|
||||
log::info!("Creating log window...");
|
||||
match tauri::WindowBuilder::new(&app_handle, "log", tauri::WindowUrl::App("log.html".into()))
|
||||
.title("Nym Wallet Logs")
|
||||
.build()
|
||||
match tauri::WebviewWindowBuilder::new(
|
||||
&app_handle,
|
||||
"log",
|
||||
tauri::WebviewUrl::App("log.html".into()),
|
||||
)
|
||||
.title("Nym Wallet Logs")
|
||||
.build()
|
||||
{
|
||||
Ok(window) => {
|
||||
if let Err(err) = window.set_focus() {
|
||||
|
||||
@@ -38,7 +38,17 @@ pub(crate) const DEFAULT_LOGIN_ID: &str = "default";
|
||||
pub(crate) const DEFAULT_FIRST_ACCOUNT_NAME: &str = "Account 1";
|
||||
|
||||
fn get_storage_directory() -> Result<PathBuf, BackendError> {
|
||||
tauri::api::path::local_data_dir()
|
||||
// tauri v1 (via `tauri::api::path::local_data_dir()`) was internally calling `dirs_next::data_local_dir()`
|
||||
// which ultimately was getting resolved to
|
||||
// - **Linux:** Resolves to `$XDG_DATA_HOME` or `$HOME/.local/share`.
|
||||
// - **macOS:** Resolves to `$HOME/Library/Application Support`.
|
||||
// - **Windows:** Resolves to `{FOLDERID_LocalAppData}`.
|
||||
//
|
||||
// tauri v2 calls `dirs::data_local_dir().ok_or(Error::UnknownPath)` which ultimately does the same thing,
|
||||
// however, it changed its API so that it's called on a `PathResolver`.
|
||||
// but, to instantiate one here would be a hassle as we don't need those specific functionalities,
|
||||
// so let's just recreate tauri's behaviour
|
||||
dirs::data_local_dir()
|
||||
.map(|dir| dir.join(STORAGE_DIR_NAME))
|
||||
.ok_or(BackendError::UnknownStorageDirectory)
|
||||
}
|
||||
|
||||
@@ -1,78 +1,69 @@
|
||||
{
|
||||
"package": {
|
||||
"productName": "nym-wallet",
|
||||
"version": "1.2.16"
|
||||
},
|
||||
"build": {
|
||||
"distDir": "../dist",
|
||||
"devPath": "http://localhost:9000",
|
||||
"beforeDevCommand": "",
|
||||
"beforeBuildCommand": ""
|
||||
},
|
||||
"tauri": {
|
||||
"bundle": {
|
||||
"active": true,
|
||||
"targets": "all",
|
||||
"identifier": "net.nymtech.wallet",
|
||||
"icon": [
|
||||
"icons/32x32.png",
|
||||
"icons/128x128.png",
|
||||
"icons/128x128@2x.png",
|
||||
"icons/icon.icns",
|
||||
"icons/icon.ico"
|
||||
],
|
||||
"resources": [],
|
||||
"externalBin": [],
|
||||
"copyright": "Copyright © 2021-2023 Nym Technologies SA",
|
||||
"category": "Business",
|
||||
"shortDescription": "Nym desktop wallet allows you to manage your NYM tokens",
|
||||
"longDescription": "",
|
||||
"bundle": {
|
||||
"active": true,
|
||||
"targets": "all",
|
||||
"windows": {
|
||||
"certificateThumbprint": "6DB77B1F529A0804FE0E6843A3EB8A8CECFFD408",
|
||||
"digestAlgorithm": "sha256",
|
||||
"timestampUrl": "http://timestamp.comodoca.com"
|
||||
},
|
||||
"icon": [
|
||||
"icons/32x32.png",
|
||||
"icons/128x128.png",
|
||||
"icons/128x128@2x.png",
|
||||
"icons/icon.icns",
|
||||
"icons/icon.ico"
|
||||
],
|
||||
"resources": [],
|
||||
"externalBin": [],
|
||||
"copyright": "Copyright © 2021-2025 Nym Technologies SA",
|
||||
"category": "Business",
|
||||
"shortDescription": "Nym desktop wallet allows you to manage your NYM tokens",
|
||||
"longDescription": "",
|
||||
"macOS": {
|
||||
"frameworks": [],
|
||||
"minimumSystemVersion": "",
|
||||
"exceptionDomain": "",
|
||||
"signingIdentity": "Developer ID Application: Nym Technologies SA (VW5DZLFHM5)",
|
||||
"entitlements": null
|
||||
},
|
||||
"linux": {
|
||||
"deb": {
|
||||
"depends": []
|
||||
},
|
||||
"macOS": {
|
||||
"frameworks": [],
|
||||
"minimumSystemVersion": "",
|
||||
"exceptionDomain": "",
|
||||
"signingIdentity": "Developer ID Application: Nym Technologies SA (VW5DZLFHM5)",
|
||||
"entitlements": null
|
||||
},
|
||||
"windows": {
|
||||
"certificateThumbprint": "6DB77B1F529A0804FE0E6843A3EB8A8CECFFD408",
|
||||
"digestAlgorithm": "sha256",
|
||||
"timestampUrl": "http://timestamp.comodoca.com"
|
||||
}
|
||||
},
|
||||
"createUpdaterArtifacts": "v1Compatible"
|
||||
},
|
||||
"build": {
|
||||
"beforeBuildCommand": "",
|
||||
"frontendDist": "../dist",
|
||||
"beforeDevCommand": "",
|
||||
"devUrl": "http://localhost:9000"
|
||||
},
|
||||
"productName": "nym-wallet",
|
||||
"mainBinaryName": "nym-wallet",
|
||||
"version": "1.2.15",
|
||||
"identifier": "net.nymtech.wallet",
|
||||
"plugins": {
|
||||
"updater": {
|
||||
"active": true,
|
||||
"pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IENCNzQ2M0E5N0VFODE2NApSV1JrZ2U2WE9rYTNETTg1OTBKdE5uWUEra0hML2syOVUvQ2lxZmFZRzZ1T3NWbGM0eVRzUTVhVwo=",
|
||||
"endpoints": [
|
||||
"https://nymtech.net/.wellknown/wallet/updater.json"
|
||||
],
|
||||
"dialog": true,
|
||||
"pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IENCNzQ2M0E5N0VFODE2NApSV1JrZ2U2WE9rYTNETTg1OTBKdE5uWUEra0hML2syOVUvQ2lxZmFZRzZ1T3NWbGM0eVRzUTVhVwo="
|
||||
},
|
||||
"allowlist": {
|
||||
"window": {
|
||||
"maximize": true,
|
||||
"print": true
|
||||
},
|
||||
"clipboard": {
|
||||
"all": true
|
||||
},
|
||||
"shell": {
|
||||
"open": true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"app": {
|
||||
"security": {
|
||||
"csp": "default-src blob: data: filesystem: ws: wss: http: https: tauri: 'unsafe-eval' 'unsafe-inline' 'self' img-src: 'self'; connect-src ipc: http://ipc.localhost"
|
||||
},
|
||||
"windows": [
|
||||
{
|
||||
"title": "Nym Wallet",
|
||||
"width": 1268,
|
||||
"height": 768,
|
||||
"resizable": true
|
||||
"resizable": true,
|
||||
"useHttpsScheme": true
|
||||
}
|
||||
],
|
||||
"security": {
|
||||
"csp": "default-src blob: data: filesystem: ws: wss: http: https: tauri: 'unsafe-eval' 'unsafe-inline' 'self' img-src: 'self'"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { Button, IconButton, Tooltip } from '@mui/material';
|
||||
import { Check, ContentCopy } from '@mui/icons-material';
|
||||
import { clipboard } from '@tauri-apps/api';
|
||||
import { writeText } from '@tauri-apps/plugin-clipboard-manager';
|
||||
import { Console } from '../utils/console';
|
||||
|
||||
export const CopyToClipboard = ({ text = '', iconButton }: { text?: string; iconButton?: boolean }) => {
|
||||
@@ -9,7 +9,7 @@ export const CopyToClipboard = ({ text = '', iconButton }: { text?: string; icon
|
||||
|
||||
const handleCopy = async (_text: string) => {
|
||||
try {
|
||||
await clipboard.writeText(_text);
|
||||
await writeText(_text);
|
||||
setCopied(true);
|
||||
} catch (e) {
|
||||
Console.error(`failed to copy: ${e}`);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { useContext, useEffect, useState } from 'react';
|
||||
import { Button, Stack, Typography } from '@mui/material';
|
||||
import { checkUpdate } from '@tauri-apps/api/updater';
|
||||
import { check } from '@tauri-apps/plugin-updater';
|
||||
import { AppContext } from '../../context';
|
||||
import { checkVersion } from '../../requests';
|
||||
import { Console } from '../../utils/console';
|
||||
@@ -28,7 +28,7 @@ const AppVersion = () => {
|
||||
try {
|
||||
// despite the name, this will spawn an external native window with
|
||||
// an embedded "download and update the Wallet" flow
|
||||
checkUpdate();
|
||||
check();
|
||||
} catch (e) {
|
||||
Console.error(e);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* eslint-disable react/destructuring-assignment */
|
||||
import React from 'react';
|
||||
import { Button, Card, CardContent, TextField } from '@mui/material';
|
||||
import { invoke } from '@tauri-apps/api';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
|
||||
interface DocEntryProps {
|
||||
function: FunctionDef;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { invoke } from '@tauri-apps/api';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import { config } from '../config';
|
||||
import { Console } from '../utils/console';
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { appWindow } from '@tauri-apps/api/window';
|
||||
import { getCurrentWebviewWindow } from '@tauri-apps/api/webviewWindow';
|
||||
import bs58 from 'bs58';
|
||||
import Big from 'big.js';
|
||||
import { valid } from 'semver';
|
||||
@@ -15,6 +15,8 @@ import {
|
||||
} from '../requests';
|
||||
import { Console } from './console';
|
||||
|
||||
const appWindow = getCurrentWebviewWindow();
|
||||
|
||||
export const validateKey = (key: string, bytesLength: number): boolean => {
|
||||
// it must be a valid base58 key
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user