Compare commits
49 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b24a3befe8 | |||
| 63a8f96ea5 | |||
| 50b044a100 | |||
| ba645694d4 | |||
| be44811a65 | |||
| 62e1d32e4f | |||
| 9a4bbe1d67 | |||
| 98090d18b4 | |||
| 79f8066c13 | |||
| d0209766a3 | |||
| 844030091f | |||
| a7a421b006 | |||
| 6680fbd61a | |||
| fe2d21cf88 | |||
| eeaca9fc10 | |||
| 7255f79b9c | |||
| 589069504a | |||
| 4da7bc7442 | |||
| 35be8de9f1 | |||
| 2b14a9e6f8 | |||
| e9269da897 | |||
| 7bceeadf16 | |||
| e72ce8fa92 | |||
| 1ccdd5d660 | |||
| c6d38d3c4f | |||
| e8e2bf107f | |||
| efe4e5c1c1 | |||
| 2230609a72 | |||
| 6d80c37b21 | |||
| cb8b4c56af | |||
| 4d486abfef | |||
| b694845e4c | |||
| 5cb2800d15 | |||
| fd14394958 | |||
| 134883522d | |||
| 221e01e9b8 | |||
| dcc48db301 | |||
| 7528109693 | |||
| 203d682f2c | |||
| 589575eed8 | |||
| 35bf1cc717 | |||
| f5e02d5652 | |||
| 2fc641a7ff | |||
| 0ccca19cc2 | |||
| a07e567eb2 | |||
| f3400a0aa5 | |||
| bf8614a545 | |||
| a3e19b4563 | |||
| 54aef7c242 |
@@ -54,6 +54,20 @@ jobs:
|
||||
override: true
|
||||
components: rustfmt, clippy
|
||||
|
||||
# To avoid running out of disk space, skip generating debug symbols
|
||||
- name: Set debug to false (unix)
|
||||
if: contains(matrix.os, 'ubuntu') || contains(matrix.os, 'mac')
|
||||
run: |
|
||||
sed -i.bak 's/\[profile.dev\]/\[profile.dev\]\ndebug = false/' Cargo.toml
|
||||
git diff
|
||||
|
||||
- name: Set debug to false (win)
|
||||
if: contains(matrix.os, 'windows')
|
||||
shell: pwsh
|
||||
run: |
|
||||
(Get-Content Cargo.toml) -replace '\[profile.dev\]', "`$&`ndebug = false" | Set-Content Cargo.toml
|
||||
git diff
|
||||
|
||||
- name: Check formatting
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
|
||||
@@ -9,6 +9,8 @@ on:
|
||||
paths:
|
||||
- 'contracts/**'
|
||||
- 'common/**'
|
||||
- 'Cargo.lock'
|
||||
- 'Cargo.toml'
|
||||
- '.github/workflows/ci-contracts.yml'
|
||||
|
||||
jobs:
|
||||
|
||||
@@ -30,6 +30,12 @@ jobs:
|
||||
override: true
|
||||
components: rustfmt, clippy
|
||||
|
||||
- name: Set debug to false
|
||||
working-directory: nym-wallet
|
||||
run: |
|
||||
sed -i.bak '1s/^/\[profile.dev\]\ndebug = false\n\n/' Cargo.toml
|
||||
git diff
|
||||
|
||||
- name: Build all binaries
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
|
||||
@@ -45,6 +45,11 @@ jobs:
|
||||
- name: Install wasm-bindgen-cli
|
||||
run: cargo install wasm-bindgen-cli
|
||||
|
||||
- name: Set debug to false
|
||||
run: |
|
||||
sed -i.bak 's/\[profile.dev\]/\[profile.dev\]\ndebug = false/' Cargo.toml
|
||||
git diff
|
||||
|
||||
- name: "Build"
|
||||
run: make sdk-wasm-build
|
||||
|
||||
|
||||
@@ -4,6 +4,42 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [2025.3-ruta] (2025-02-10)
|
||||
|
||||
- Push down forget me to client configs ([#5431])
|
||||
- Fix statistics shutdown ([#5426])
|
||||
- Make wait_for_graceful_shutdown to be pub ([#5424])
|
||||
- Upgrade to thiserror 2.0 ([#5414])
|
||||
- build(deps): bump the patch-updates group across 1 directory with 9 updates ([#5406])
|
||||
- Relocate a validator api function ([#5401])
|
||||
- Send shutdown instead of panic when reaching max fail ([#5398])
|
||||
- Change Explorer URL to new smooshed nodes ([#5396])
|
||||
- reduce log severity for checking topology validity ([#5395])
|
||||
- MixnetClient can send ClientRequests ([#5381])
|
||||
- Fix missing path triggers for CI ([#5380])
|
||||
- Uncouple storage reference for bandwidth client ([#5372])
|
||||
- build(deps): bump tokio from 1.40.0 to 1.43.0 ([#5370])
|
||||
- DNS resolver configuration for internal HTTP client lookups ([#5355])
|
||||
- Update README.md ([#5328])
|
||||
- Update README.md ([#5327])
|
||||
|
||||
[#5431]: https://github.com/nymtech/nym/pull/5431
|
||||
[#5426]: https://github.com/nymtech/nym/pull/5426
|
||||
[#5424]: https://github.com/nymtech/nym/pull/5424
|
||||
[#5414]: https://github.com/nymtech/nym/pull/5414
|
||||
[#5406]: https://github.com/nymtech/nym/pull/5406
|
||||
[#5401]: https://github.com/nymtech/nym/pull/5401
|
||||
[#5398]: https://github.com/nymtech/nym/pull/5398
|
||||
[#5396]: https://github.com/nymtech/nym/pull/5396
|
||||
[#5395]: https://github.com/nymtech/nym/pull/5395
|
||||
[#5381]: https://github.com/nymtech/nym/pull/5381
|
||||
[#5380]: https://github.com/nymtech/nym/pull/5380
|
||||
[#5372]: https://github.com/nymtech/nym/pull/5372
|
||||
[#5370]: https://github.com/nymtech/nym/pull/5370
|
||||
[#5355]: https://github.com/nymtech/nym/pull/5355
|
||||
[#5328]: https://github.com/nymtech/nym/pull/5328
|
||||
[#5327]: https://github.com/nymtech/nym/pull/5327
|
||||
|
||||
## [2025.2-hu] (2025-02-04)
|
||||
|
||||
- Feature/remove double spending bloomfilter ([#5417])
|
||||
|
||||
Generated
+272
-192
@@ -128,6 +128,21 @@ dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "alloc-no-stdlib"
|
||||
version = "2.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3"
|
||||
|
||||
[[package]]
|
||||
name = "alloc-stdlib"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece"
|
||||
dependencies = [
|
||||
"alloc-no-stdlib",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "allocator-api2"
|
||||
version = "0.2.18"
|
||||
@@ -262,47 +277,6 @@ version = "0.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711"
|
||||
|
||||
[[package]]
|
||||
name = "askama"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b79091df18a97caea757e28cd2d5fda49c6cd4bd01ddffd7ff01ace0c0ad2c28"
|
||||
dependencies = [
|
||||
"askama_derive",
|
||||
"askama_escape",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "askama_derive"
|
||||
version = "0.12.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "19fe8d6cb13c4714962c072ea496f3392015f0989b1a2847bb4b2d9effd71d83"
|
||||
dependencies = [
|
||||
"askama_parser",
|
||||
"basic-toml",
|
||||
"mime",
|
||||
"mime_guess",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"serde",
|
||||
"syn 2.0.90",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "askama_escape"
|
||||
version = "0.10.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "619743e34b5ba4e9703bba34deac3427c72507c7159f5fd030aea8cac0cfe341"
|
||||
|
||||
[[package]]
|
||||
name = "askama_parser"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "acb1161c6b64d1c3d83108213c2a2533a342ac225aabd0bda218278c2ddb00c0"
|
||||
dependencies = [
|
||||
"nom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "assert-json-diff"
|
||||
version = "2.0.2"
|
||||
@@ -324,6 +298,22 @@ dependencies = [
|
||||
"futures-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-compression"
|
||||
version = "0.4.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df895a515f70646414f4b45c0b79082783b80552b373a68283012928df56f522"
|
||||
dependencies = [
|
||||
"brotli",
|
||||
"flate2",
|
||||
"futures-core",
|
||||
"memchr",
|
||||
"pin-project-lite",
|
||||
"tokio",
|
||||
"zstd",
|
||||
"zstd-safe",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-lock"
|
||||
version = "3.4.0"
|
||||
@@ -479,10 +469,10 @@ dependencies = [
|
||||
"axum-macros",
|
||||
"bytes",
|
||||
"futures-util",
|
||||
"http 1.1.0",
|
||||
"http 1.2.0",
|
||||
"http-body 1.0.0",
|
||||
"http-body-util",
|
||||
"hyper 1.4.1",
|
||||
"hyper 1.6.0",
|
||||
"hyper-util",
|
||||
"itoa",
|
||||
"matchit",
|
||||
@@ -497,7 +487,7 @@ dependencies = [
|
||||
"serde_urlencoded",
|
||||
"sync_wrapper 1.0.1",
|
||||
"tokio",
|
||||
"tower 0.5.1",
|
||||
"tower 0.5.2",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
@@ -540,7 +530,7 @@ dependencies = [
|
||||
"async-trait",
|
||||
"bytes",
|
||||
"futures-util",
|
||||
"http 1.1.0",
|
||||
"http 1.2.0",
|
||||
"http-body 1.0.0",
|
||||
"http-body-util",
|
||||
"mime",
|
||||
@@ -563,13 +553,13 @@ dependencies = [
|
||||
"bytes",
|
||||
"futures-util",
|
||||
"headers",
|
||||
"http 1.1.0",
|
||||
"http 1.2.0",
|
||||
"http-body 1.0.0",
|
||||
"http-body-util",
|
||||
"mime",
|
||||
"pin-project-lite",
|
||||
"serde",
|
||||
"tower 0.5.1",
|
||||
"tower 0.5.2",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
@@ -598,9 +588,9 @@ dependencies = [
|
||||
"axum 0.7.7",
|
||||
"bytes",
|
||||
"cookie",
|
||||
"http 1.1.0",
|
||||
"http 1.2.0",
|
||||
"http-body-util",
|
||||
"hyper 1.4.1",
|
||||
"hyper 1.6.0",
|
||||
"hyper-util",
|
||||
"mime",
|
||||
"pretty_assertions",
|
||||
@@ -611,7 +601,7 @@ dependencies = [
|
||||
"serde_urlencoded",
|
||||
"smallvec",
|
||||
"tokio",
|
||||
"tower 0.5.1",
|
||||
"tower 0.5.2",
|
||||
"url",
|
||||
]
|
||||
|
||||
@@ -838,6 +828,27 @@ version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ab9008b6bb9fc80b5277f2fe481c09e828743d9151203e804583eb4c9e15b31d"
|
||||
|
||||
[[package]]
|
||||
name = "brotli"
|
||||
version = "7.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cc97b8f16f944bba54f0433f07e30be199b6dc2bd25937444bbad560bcea29bd"
|
||||
dependencies = [
|
||||
"alloc-no-stdlib",
|
||||
"alloc-stdlib",
|
||||
"brotli-decompressor",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "brotli-decompressor"
|
||||
version = "4.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "74fa05ad7d803d413eb8380983b092cbbaf9a85f151b871360e7b00cd7060b37"
|
||||
dependencies = [
|
||||
"alloc-no-stdlib",
|
||||
"alloc-stdlib",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bs58"
|
||||
version = "0.5.1"
|
||||
@@ -955,14 +966,16 @@ version = "1.1.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b62ac837cdb5cb22e10a256099b4fc502b1dfe560cb282963a974d7abd80e476"
|
||||
dependencies = [
|
||||
"jobserver",
|
||||
"libc",
|
||||
"shlex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "celes"
|
||||
version = "2.4.0"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "39b9a21273925d7cc9e8a9a5f068122341336813c607014f5ef64f82b6acba58"
|
||||
checksum = "54441489dce7026efc8f01d1aa996c23fa39dd615a953d0e934433a42f61dd30"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
@@ -1068,9 +1081,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.28"
|
||||
version = "4.5.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3e77c3243bd94243c03672cb5154667347c457ca271254724f9f393aee1c05ff"
|
||||
checksum = "92b7b18d71fad5313a1e320fa9897994228ce274b60faa4d694fe0ea89cd9e6d"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
@@ -1078,9 +1091,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.27"
|
||||
version = "4.5.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b26884eb4b57140e4d2d93652abfa49498b938b3c9179f9fc487b0acc3edad7"
|
||||
checksum = "a35db2071778a7344791a4fb4f95308b5673d219dee3ae348b86642574ecc90c"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
@@ -1090,9 +1103,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap_complete"
|
||||
version = "4.5.44"
|
||||
version = "4.5.45"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "375f9d8255adeeedd51053574fd8d4ba875ea5fa558e86617b07f09f1680c8b6"
|
||||
checksum = "1e3040c8291884ddf39445dc033c70abc2bc44a42f0a3a00571a0f483a83f0cd"
|
||||
dependencies = [
|
||||
"clap",
|
||||
]
|
||||
@@ -1133,12 +1146,12 @@ checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422"
|
||||
|
||||
[[package]]
|
||||
name = "colored"
|
||||
version = "2.1.0"
|
||||
version = "2.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cbf2150cce219b664a8a70df7a1f933836724b503f8a413af9365b4dcc4d90b8"
|
||||
checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"windows-sys 0.48.0",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1302,7 +1315,7 @@ version = "0.26.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "462e1f6a8e005acc8835d32d60cbd7973ed65ea2a8d8473830e675f050956427"
|
||||
dependencies = [
|
||||
"prost 0.13.4",
|
||||
"prost 0.13.5",
|
||||
"tendermint-proto 0.40.1",
|
||||
]
|
||||
|
||||
@@ -2407,7 +2420,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "explorer-api"
|
||||
version = "1.1.45"
|
||||
version = "1.1.47"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"clap",
|
||||
@@ -2880,7 +2893,7 @@ dependencies = [
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
"gloo-utils 0.2.0",
|
||||
"http 1.1.0",
|
||||
"http 1.2.0",
|
||||
"js-sys",
|
||||
"pin-project",
|
||||
"serde",
|
||||
@@ -2931,9 +2944,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "goblin"
|
||||
version = "0.6.1"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0d6b4de4a8eb6c46a8c77e1d3be942cb9a8bf073c22374578e5ba4b08ed0ff68"
|
||||
checksum = "1b363a30c165f666402fe6a3024d3bec7ebc898f96a4a23bd1c99f8dbf3f4f47"
|
||||
dependencies = [
|
||||
"log",
|
||||
"plain",
|
||||
@@ -3050,7 +3063,7 @@ dependencies = [
|
||||
"base64 0.21.7",
|
||||
"bytes",
|
||||
"headers-core",
|
||||
"http 1.1.0",
|
||||
"http 1.2.0",
|
||||
"httpdate",
|
||||
"mime",
|
||||
"sha1",
|
||||
@@ -3062,7 +3075,7 @@ version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "54b4a22553d4242c49fddb9ba998a99962b5cc6f22cb5a3482bec22522403ce4"
|
||||
dependencies = [
|
||||
"http 1.1.0",
|
||||
"http 1.2.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3118,9 +3131,9 @@ checksum = "7ebdb29d2ea9ed0083cd8cece49bbd968021bd99b0849edb4a9a7ee0fdf6a4e0"
|
||||
|
||||
[[package]]
|
||||
name = "hickory-proto"
|
||||
version = "0.24.2"
|
||||
version = "0.24.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "447afdcdb8afb9d0a852af6dc65d9b285ce720ed7a59e42a8bf2e931c67bc1b5"
|
||||
checksum = "2ad3d6d98c648ed628df039541a5577bee1a7c83e9e16fe3dbedeea4cdfeb971"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"bytes",
|
||||
@@ -3132,7 +3145,7 @@ dependencies = [
|
||||
"futures-util",
|
||||
"h2",
|
||||
"http 0.2.12",
|
||||
"idna 1.0.3",
|
||||
"idna",
|
||||
"ipnet",
|
||||
"once_cell",
|
||||
"rand 0.8.5",
|
||||
@@ -3248,9 +3261,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "http"
|
||||
version = "1.1.0"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258"
|
||||
checksum = "f16ca2af56261c99fba8bac40a10251ce8188205a4c448fbb745a2e4daa76fea"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"fnv",
|
||||
@@ -3275,7 +3288,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"http 1.1.0",
|
||||
"http 1.2.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3286,7 +3299,7 @@ checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-util",
|
||||
"http 1.1.0",
|
||||
"http 1.2.0",
|
||||
"http-body 1.0.0",
|
||||
"pin-project-lite",
|
||||
]
|
||||
@@ -3376,14 +3389,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "hyper"
|
||||
version = "1.4.1"
|
||||
version = "1.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05"
|
||||
checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-channel",
|
||||
"futures-util",
|
||||
"http 1.1.0",
|
||||
"http 1.2.0",
|
||||
"http-body 1.0.0",
|
||||
"httparse",
|
||||
"httpdate",
|
||||
@@ -3415,8 +3428,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a0bea761b46ae2b24eb4aef630d8d1c398157b6fc29e6350ecf090a0b70c952c"
|
||||
dependencies = [
|
||||
"futures-util",
|
||||
"http 1.1.0",
|
||||
"hyper 1.4.1",
|
||||
"http 1.2.0",
|
||||
"hyper 1.6.0",
|
||||
"hyper-util",
|
||||
"rustls 0.22.4",
|
||||
"rustls-pki-types",
|
||||
@@ -3446,9 +3459,9 @@ dependencies = [
|
||||
"bytes",
|
||||
"futures-channel",
|
||||
"futures-util",
|
||||
"http 1.1.0",
|
||||
"http 1.2.0",
|
||||
"http-body 1.0.0",
|
||||
"hyper 1.4.1",
|
||||
"hyper 1.6.0",
|
||||
"pin-project-lite",
|
||||
"socket2",
|
||||
"tokio",
|
||||
@@ -3603,16 +3616,6 @@ version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6"
|
||||
dependencies = [
|
||||
"unicode-bidi",
|
||||
"unicode-normalization",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "1.0.3"
|
||||
@@ -3953,6 +3956,15 @@ version = "1.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
|
||||
|
||||
[[package]]
|
||||
name = "jobserver"
|
||||
version = "0.1.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.76"
|
||||
@@ -4735,7 +4747,7 @@ checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3"
|
||||
|
||||
[[package]]
|
||||
name = "nym-api"
|
||||
version = "1.1.49"
|
||||
version = "1.1.51"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@@ -4983,7 +4995,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-cli"
|
||||
version = "1.1.47"
|
||||
version = "1.1.49"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"base64 0.22.1",
|
||||
@@ -5066,7 +5078,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-client"
|
||||
version = "1.1.47"
|
||||
version = "1.1.49"
|
||||
dependencies = [
|
||||
"bs58",
|
||||
"clap",
|
||||
@@ -5115,7 +5127,7 @@ dependencies = [
|
||||
"gloo-timers",
|
||||
"http-body-util",
|
||||
"humantime-serde",
|
||||
"hyper 1.4.1",
|
||||
"hyper 1.6.0",
|
||||
"hyper-util",
|
||||
"log",
|
||||
"nym-bandwidth-controller",
|
||||
@@ -5407,7 +5419,7 @@ dependencies = [
|
||||
"time",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
"tower 0.4.13",
|
||||
"tower 0.5.2",
|
||||
"tower-http",
|
||||
"tracing",
|
||||
"url",
|
||||
@@ -5559,6 +5571,7 @@ dependencies = [
|
||||
"rand_chacha 0.3.1",
|
||||
"serde",
|
||||
"serde_bytes",
|
||||
"sha2 0.10.8",
|
||||
"subtle-encoding",
|
||||
"thiserror 2.0.11",
|
||||
"x25519-dalek",
|
||||
@@ -5849,7 +5862,7 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"hickory-resolver",
|
||||
"http 1.1.0",
|
||||
"http 1.2.0",
|
||||
"nym-bin-common",
|
||||
"once_cell",
|
||||
"reqwest 0.12.4",
|
||||
@@ -5875,7 +5888,7 @@ dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_yaml",
|
||||
"tower 0.4.13",
|
||||
"tower 0.5.2",
|
||||
"tracing",
|
||||
"utoipa",
|
||||
"zeroize",
|
||||
@@ -6125,7 +6138,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-network-requester"
|
||||
version = "1.1.48"
|
||||
version = "1.1.50"
|
||||
dependencies = [
|
||||
"addr",
|
||||
"anyhow",
|
||||
@@ -6176,7 +6189,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-node"
|
||||
version = "1.4.0"
|
||||
version = "1.6.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"arc-swap",
|
||||
@@ -6474,7 +6487,7 @@ dependencies = [
|
||||
"dotenvy",
|
||||
"futures",
|
||||
"hex",
|
||||
"http 1.1.0",
|
||||
"http 1.2.0",
|
||||
"httpcodec",
|
||||
"log",
|
||||
"nym-bandwidth-controller",
|
||||
@@ -6551,7 +6564,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-socks5-client"
|
||||
version = "1.1.47"
|
||||
version = "1.1.49"
|
||||
dependencies = [
|
||||
"bs58",
|
||||
"clap",
|
||||
@@ -6976,7 +6989,7 @@ dependencies = [
|
||||
"nym-network-defaults",
|
||||
"nym-serde-helpers",
|
||||
"nym-vesting-contract-common",
|
||||
"prost 0.13.4",
|
||||
"prost 0.13.5",
|
||||
"reqwest 0.12.4",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@@ -7156,7 +7169,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nymvisor"
|
||||
version = "0.1.12"
|
||||
version = "0.1.14"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bytes",
|
||||
@@ -7186,7 +7199,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nyx-chain-watcher"
|
||||
version = "0.1.9"
|
||||
version = "0.1.11"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@@ -7269,12 +7282,6 @@ version = "1.20.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e"
|
||||
|
||||
[[package]]
|
||||
name = "oneshot-uniffi"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c548d5c78976f6955d72d0ced18c48ca07030f7a1d4024529fedd7c1c01b29c"
|
||||
|
||||
[[package]]
|
||||
name = "oorandom"
|
||||
version = "11.1.3"
|
||||
@@ -7951,12 +7958,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "prost"
|
||||
version = "0.13.4"
|
||||
version = "0.13.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2c0fef6c4230e4ccf618a35c59d7ede15dea37de8427500f50aff708806e42ec"
|
||||
checksum = "2796faa41db3ec313a31f7624d9286acf277b52de526150b7e69f3debf891ee5"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"prost-derive 0.13.4",
|
||||
"prost-derive 0.13.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -7987,12 +7994,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "prost-derive"
|
||||
version = "0.13.4"
|
||||
version = "0.13.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "157c5a9d7ea5c2ed2d9fb8f495b64759f7816c7eaea54ba3978f0d63000162e3"
|
||||
checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"itertools 0.13.0",
|
||||
"itertools 0.10.5",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.90",
|
||||
@@ -8039,11 +8046,11 @@ checksum = "33cb294fe86a74cbcf50d4445b37da762029549ebeea341421c7c70370f86cac"
|
||||
|
||||
[[package]]
|
||||
name = "publicsuffix"
|
||||
version = "2.2.3"
|
||||
version = "2.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "96a8c1bda5ae1af7f99a2962e49df150414a43d62404644d98dd5c3a93d07457"
|
||||
checksum = "6f42ea446cab60335f76979ec15e12619a2165b5ae2c12166bef27d283a9fadf"
|
||||
dependencies = [
|
||||
"idna 0.3.0",
|
||||
"idna",
|
||||
"psl-types",
|
||||
]
|
||||
|
||||
@@ -8329,14 +8336,15 @@ version = "0.12.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "566cafdd92868e0939d3fb961bd0dc25fcfaaed179291093b3d43e6b3150ea10"
|
||||
dependencies = [
|
||||
"async-compression",
|
||||
"base64 0.22.1",
|
||||
"bytes",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"http 1.1.0",
|
||||
"http 1.2.0",
|
||||
"http-body 1.0.0",
|
||||
"http-body-util",
|
||||
"hyper 1.4.1",
|
||||
"hyper 1.6.0",
|
||||
"hyper-rustls 0.26.0",
|
||||
"hyper-util",
|
||||
"ipnet",
|
||||
@@ -8412,6 +8420,45 @@ dependencies = [
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rinja"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3dc4940d00595430b3d7d5a01f6222b5e5b51395d1120bdb28d854bb8abb17a5"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"rinja_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rinja_derive"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08d9ed0146aef6e2825f1b1515f074510549efba38d71f4554eec32eb36ba18b"
|
||||
dependencies = [
|
||||
"basic-toml",
|
||||
"memchr",
|
||||
"mime",
|
||||
"mime_guess",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rinja_parser",
|
||||
"rustc-hash",
|
||||
"serde",
|
||||
"syn 2.0.90",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rinja_parser"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "93f9a866e2e00a7a1fb27e46e9e324a6f7c0e7edc4543cae1d38f4e4a100c610"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"nom",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ripemd"
|
||||
version = "0.1.3"
|
||||
@@ -8633,6 +8680,12 @@ version = "0.1.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
|
||||
|
||||
[[package]]
|
||||
name = "rustc-hash"
|
||||
version = "2.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d"
|
||||
|
||||
[[package]]
|
||||
name = "rustc_version"
|
||||
version = "0.2.3"
|
||||
@@ -8831,18 +8884,18 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||
|
||||
[[package]]
|
||||
name = "scroll"
|
||||
version = "0.11.0"
|
||||
version = "0.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "04c565b551bafbef4157586fa379538366e4385d42082f255bfd96e4fe8519da"
|
||||
checksum = "6ab8598aa408498679922eff7fa985c25d58a90771bd6be794434c5277eab1a6"
|
||||
dependencies = [
|
||||
"scroll_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scroll_derive"
|
||||
version = "0.11.1"
|
||||
version = "0.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1db149f81d46d2deba7cd3c50772474707729550221e69588478ebf9ada425ae"
|
||||
checksum = "7f81c2fde025af7e69b1d1420531c8a8811ca898919db177141a85313b1cb932"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -9333,6 +9386,12 @@ version = "1.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
|
||||
|
||||
[[package]]
|
||||
name = "smawk"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c"
|
||||
|
||||
[[package]]
|
||||
name = "snafu"
|
||||
version = "0.7.5"
|
||||
@@ -9947,7 +10006,7 @@ dependencies = [
|
||||
"k256",
|
||||
"num-traits",
|
||||
"once_cell",
|
||||
"prost 0.13.4",
|
||||
"prost 0.13.5",
|
||||
"ripemd",
|
||||
"serde",
|
||||
"serde_bytes",
|
||||
@@ -10002,7 +10061,7 @@ checksum = "9ae9e1705aa0fa5ecb2c6aa7fb78c2313c4a31158ea5f02048bf318f849352eb"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"flex-error",
|
||||
"prost 0.13.4",
|
||||
"prost 0.13.5",
|
||||
"serde",
|
||||
"serde_bytes",
|
||||
"subtle-encoding",
|
||||
@@ -10102,6 +10161,15 @@ dependencies = [
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "textwrap"
|
||||
version = "0.16.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9"
|
||||
dependencies = [
|
||||
"smawk",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.69"
|
||||
@@ -10503,14 +10571,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tower"
|
||||
version = "0.5.1"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2873938d487c3cfb9aed7546dc9f2711d867c9f90c46b889989a2cb84eba6b4f"
|
||||
checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"pin-project-lite",
|
||||
"sync_wrapper 0.1.2",
|
||||
"sync_wrapper 1.0.1",
|
||||
"tokio",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
@@ -10523,10 +10591,12 @@ version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e9cd434a998747dd2c4276bc96ee2e0c7a2eadf3cae88e52be55a05fa9053f5"
|
||||
dependencies = [
|
||||
"async-compression",
|
||||
"bitflags 2.5.0",
|
||||
"bytes",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"http 1.1.0",
|
||||
"http 1.2.0",
|
||||
"http-body 1.0.0",
|
||||
"http-body-util",
|
||||
"http-range-header",
|
||||
@@ -10792,7 +10862,7 @@ dependencies = [
|
||||
"byteorder",
|
||||
"bytes",
|
||||
"data-encoding",
|
||||
"http 1.1.0",
|
||||
"http 1.2.0",
|
||||
"httparse",
|
||||
"log",
|
||||
"rand 0.8.5",
|
||||
@@ -10913,12 +10983,13 @@ checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e"
|
||||
|
||||
[[package]]
|
||||
name = "uniffi"
|
||||
version = "0.25.3"
|
||||
version = "0.29.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "21345172d31092fd48c47fd56c53d4ae9e41c4b1f559fb8c38c1ab1685fd919f"
|
||||
checksum = "ba62a57e90f9baed5ad02a71a0870180fa1cc35499093b2d21be2edfb68ec0f7"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"camino",
|
||||
"cargo_metadata 0.15.4",
|
||||
"clap",
|
||||
"uniffi_bindgen",
|
||||
"uniffi_build",
|
||||
@@ -10928,33 +10999,32 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "uniffi_bindgen"
|
||||
version = "0.25.3"
|
||||
version = "0.29.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fd992f2929a053829d5875af1eff2ee3d7a7001cb3b9a46cc7895f2caede6940"
|
||||
checksum = "2242f35214f1e0e3b47c495d340c69f649f9a9ece3a943a29e275686cc884533"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"askama",
|
||||
"camino",
|
||||
"cargo_metadata 0.15.4",
|
||||
"clap",
|
||||
"fs-err",
|
||||
"glob",
|
||||
"goblin",
|
||||
"heck 0.4.1",
|
||||
"heck 0.5.0",
|
||||
"once_cell",
|
||||
"paste",
|
||||
"rinja",
|
||||
"serde",
|
||||
"textwrap",
|
||||
"toml 0.5.11",
|
||||
"uniffi_meta",
|
||||
"uniffi_testing",
|
||||
"uniffi_udl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uniffi_build"
|
||||
version = "0.25.3"
|
||||
version = "0.29.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "001964dd3682d600084b3aaf75acf9c3426699bc27b65e96bb32d175a31c74e9"
|
||||
checksum = "c887a6c9a2857d8dc2ab0c8d578e8aa4978145b4fd65ed44296341e89aebc3cc"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"camino",
|
||||
@@ -10962,38 +11032,34 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uniffi_checksum_derive"
|
||||
version = "0.25.3"
|
||||
name = "uniffi_core"
|
||||
version = "0.29.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "55137c122f712d9330fd985d66fa61bdc381752e89c35708c13ce63049a3002c"
|
||||
checksum = "cad9fbdeb7ae4daf8d0f7704a3b638c37018eb16bb701e30fa17a2dd3e2d39c1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bytes",
|
||||
"once_cell",
|
||||
"paste",
|
||||
"static_assertions",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uniffi_internal_macros"
|
||||
version = "0.29.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "22a9dba1d78b9ce429439891089c223478043d52a1c3176a0fcea2b5573a7fcf"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"syn 2.0.90",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uniffi_core"
|
||||
version = "0.25.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6121a127a3af1665cd90d12dd2b3683c2643c5103281d0fed5838324ca1fad5b"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bytes",
|
||||
"camino",
|
||||
"log",
|
||||
"once_cell",
|
||||
"oneshot-uniffi",
|
||||
"paste",
|
||||
"static_assertions",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uniffi_macros"
|
||||
version = "0.25.3"
|
||||
version = "0.29.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "11cf7a58f101fcedafa5b77ea037999b88748607f0ef3a33eaa0efc5392e92e4"
|
||||
checksum = "78dd5f8eefba5898b901086f5e7916da67b9a5286a01cc44e910cd75fa37c630"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"camino",
|
||||
"fs-err",
|
||||
"once_cell",
|
||||
@@ -11002,44 +11068,29 @@ dependencies = [
|
||||
"serde",
|
||||
"syn 2.0.90",
|
||||
"toml 0.5.11",
|
||||
"uniffi_build",
|
||||
"uniffi_meta",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uniffi_meta"
|
||||
version = "0.25.3"
|
||||
version = "0.29.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "71dc8573a7b1ac4b71643d6da34888273ebfc03440c525121f1b3634ad3417a2"
|
||||
checksum = "9d5965b1d4ffacef1eaa72fef9c00d2491641e87ad910f6c5859b9c503ddb16a"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bytes",
|
||||
"siphasher",
|
||||
"uniffi_checksum_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uniffi_testing"
|
||||
version = "0.25.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "118448debffcb676ddbe8c5305fb933ab7e0123753e659a71dc4a693f8d9f23c"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"camino",
|
||||
"cargo_metadata 0.15.4",
|
||||
"fs-err",
|
||||
"once_cell",
|
||||
"uniffi_internal_macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uniffi_udl"
|
||||
version = "0.25.3"
|
||||
version = "0.29.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "889edb7109c6078abe0e53e9b4070cf74a6b3468d141bdf5ef1bd4d1dc24a1c3"
|
||||
checksum = "279b82bac9a382c796a0d210bb8354a0b813499b28aa1de046c85d78ca389805"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"textwrap",
|
||||
"uniffi_meta",
|
||||
"uniffi_testing",
|
||||
"weedle2",
|
||||
]
|
||||
|
||||
@@ -11072,7 +11123,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60"
|
||||
dependencies = [
|
||||
"form_urlencoded",
|
||||
"idna 1.0.3",
|
||||
"idna",
|
||||
"percent-encoding",
|
||||
"serde",
|
||||
]
|
||||
@@ -11134,11 +11185,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "utoipa-swagger-ui"
|
||||
version = "8.0.3"
|
||||
version = "8.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a5c80b4dd79ea382e8374d67dcce22b5c6663fa13a82ad3886441d1bbede5e35"
|
||||
checksum = "db4b5ac679cc6dfc5ea3f2823b0291c777750ffd5e13b21137e0f7ac0e8f9617"
|
||||
dependencies = [
|
||||
"axum 0.7.7",
|
||||
"base64 0.22.1",
|
||||
"mime_guess",
|
||||
"regex",
|
||||
"rust-embed",
|
||||
@@ -11500,9 +11552,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "weedle2"
|
||||
version = "4.0.0"
|
||||
version = "5.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2e79c5206e1f43a2306fd64bdb95025ee4228960f2e6c5a8b173f3caaf807741"
|
||||
checksum = "998d2c24ec099a87daf9467808859f9d82b61f1d9c9701251aea037f514eae0e"
|
||||
dependencies = [
|
||||
"nom",
|
||||
]
|
||||
@@ -12180,3 +12232,31 @@ dependencies = [
|
||||
"once_cell",
|
||||
"simd-adler32",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zstd"
|
||||
version = "0.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fcf2b778a664581e31e389454a7072dab1647606d44f7feea22cd5abb9c9f3f9"
|
||||
dependencies = [
|
||||
"zstd-safe",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zstd-safe"
|
||||
version = "7.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "54a3ab4db68cea366acc5c897c7b4d4d1b8994a9cd6e6f841f8964566a419059"
|
||||
dependencies = [
|
||||
"zstd-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zstd-sys"
|
||||
version = "2.0.13+zstd.1.5.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38ff0f21cfee8f97d94cef41359e0c89aa6113028ab0291aa8ca0038995a95aa"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
+20
-13
@@ -187,18 +187,21 @@ readme = "README.md"
|
||||
|
||||
[workspace.dependencies]
|
||||
addr = "0.15.6"
|
||||
aead = "0.5.2"
|
||||
aes = "0.8.1"
|
||||
aes-gcm = "0.10.1"
|
||||
aes-gcm-siv = "0.11.1"
|
||||
aead = "0.5.2"
|
||||
ammonia = "4"
|
||||
anyhow = "1.0.95"
|
||||
arc-swap = "1.7.1"
|
||||
argon2 = "0.5.0"
|
||||
async-trait = "0.1.86"
|
||||
axum-client-ip = "0.6.1"
|
||||
axum = "0.7.5"
|
||||
axum-client-ip = "0.6.1"
|
||||
axum-extra = "0.9.4"
|
||||
axum-test = "16.2.0"
|
||||
base64 = "0.22.1"
|
||||
base85rs = "0.1.3"
|
||||
bincode = "1.3.3"
|
||||
bip39 = { version = "2.0.0", features = ["zeroize"] }
|
||||
bit-vec = "0.7.0" # can we unify those?
|
||||
@@ -209,16 +212,16 @@ bs58 = "0.5.1"
|
||||
bytecodec = "0.4.15"
|
||||
bytes = "1.7.2"
|
||||
cargo_metadata = "0.18.1"
|
||||
celes = "2.4.0"
|
||||
celes = "2.5.0"
|
||||
cfg-if = "1.0.0"
|
||||
chacha20 = "0.9.0"
|
||||
chacha20poly1305 = "0.10.1"
|
||||
chrono = "0.4.39"
|
||||
cipher = "0.4.3"
|
||||
clap = "4.5.28"
|
||||
clap = "4.5.30"
|
||||
clap_complete = "4.5"
|
||||
clap_complete_fig = "4.5"
|
||||
colored = "2.0"
|
||||
colored = "2.2"
|
||||
comfy-table = "7.1.4"
|
||||
console = "0.15.10"
|
||||
console-subscriber = "0.1.1"
|
||||
@@ -239,8 +242,9 @@ doc-comment = "0.3"
|
||||
dotenvy = "0.15.6"
|
||||
ecdsa = "0.16"
|
||||
ed25519-dalek = "2.1"
|
||||
etherparse = "0.13.0"
|
||||
env_logger = "0.11.6"
|
||||
envy = "0.4"
|
||||
etherparse = "0.13.0"
|
||||
eyre = "0.6.9"
|
||||
fastrand = "2.1.1"
|
||||
flate2 = "1.0.35"
|
||||
@@ -259,10 +263,10 @@ hmac = "0.12.1"
|
||||
http = "1"
|
||||
http-body-util = "0.1"
|
||||
httpcodec = "0.2.3"
|
||||
human-repr = "1.1.0"
|
||||
humantime = "2.1.0"
|
||||
humantime-serde = "1.1.1"
|
||||
human-repr = "1.1.0"
|
||||
hyper = "1.4.1"
|
||||
hyper = "1.6.0"
|
||||
hyper-util = "0.1"
|
||||
indicatif = "0.17.11"
|
||||
inquire = "0.6.2"
|
||||
@@ -276,7 +280,6 @@ ledger-transport = "0.10.0"
|
||||
ledger-transport-hid = "0.10.0"
|
||||
log = "0.4"
|
||||
maxminddb = "0.23.0"
|
||||
rs_merkle = "1.4.2"
|
||||
mime = "0.3.17"
|
||||
moka = { version = "0.12", features = ["future"] }
|
||||
nix = "0.27.1"
|
||||
@@ -291,7 +294,7 @@ petgraph = "0.6.5"
|
||||
pin-project = "1.1"
|
||||
pin-project-lite = "0.2.16"
|
||||
pretty_env_logger = "0.4.0"
|
||||
publicsuffix = "2.2.3"
|
||||
publicsuffix = "2.3.0"
|
||||
quote = "1"
|
||||
rand = "0.8.5"
|
||||
rand_chacha = "0.3"
|
||||
@@ -305,6 +308,7 @@ reqwest = { version = "0.12.4", default-features = false }
|
||||
rocket = "0.5.0"
|
||||
rocket_cors = "0.6.0"
|
||||
rocket_okapi = "0.8.0"
|
||||
rs_merkle = "1.4.2"
|
||||
safer-ffi = "0.1.13"
|
||||
schemars = "0.8.21"
|
||||
semver = "1.0.25"
|
||||
@@ -331,24 +335,27 @@ tempfile = "3.15"
|
||||
thiserror = "2.0"
|
||||
time = "0.3.37"
|
||||
tokio = "1.43"
|
||||
tokio-postgres = "0.7"
|
||||
tokio-stream = "0.1.17"
|
||||
tokio-test = "0.4.4"
|
||||
tokio-tun = "0.11.5"
|
||||
tokio-tungstenite = { version = "0.20.1" }
|
||||
tokio-util = "0.7.13"
|
||||
toml = "0.8.20"
|
||||
tower = "0.4.13"
|
||||
tower = "0.5.2"
|
||||
tower-http = "0.5.2"
|
||||
tracing = "0.1.41"
|
||||
tracing-log = "0.2"
|
||||
tracing-opentelemetry = "0.19.0"
|
||||
tracing-subscriber = "0.3.19"
|
||||
tracing-tree = "0.2.2"
|
||||
tracing-log = "0.2"
|
||||
ts-rs = "10.1.0"
|
||||
tungstenite = { version = "0.20.1", default-features = false }
|
||||
uniffi = "0.29.0"
|
||||
uniffi_build = "0.29.0"
|
||||
url = "2.5"
|
||||
utoipa = "5.2"
|
||||
utoipa-swagger-ui = "8.0"
|
||||
utoipa-swagger-ui = "8.1"
|
||||
utoipauto = "0.2"
|
||||
uuid = "*"
|
||||
vergen = { version = "=8.3.1", default-features = false }
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "nym-client"
|
||||
version = "1.1.47"
|
||||
version = "1.1.49"
|
||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"]
|
||||
description = "Implementation of the Nym Client"
|
||||
edition = "2021"
|
||||
|
||||
@@ -49,7 +49,7 @@ impl SocketClient {
|
||||
client_output: ClientOutput,
|
||||
client_state: ClientState,
|
||||
self_address: &Recipient,
|
||||
shutdown: nym_task::TaskClient,
|
||||
task_client: nym_task::TaskClient,
|
||||
packet_type: PacketType,
|
||||
) {
|
||||
info!("Starting websocket listener...");
|
||||
@@ -77,10 +77,15 @@ impl SocketClient {
|
||||
shared_lane_queue_lengths,
|
||||
reply_controller_sender,
|
||||
Some(packet_type),
|
||||
task_client.fork("websocket_handler"),
|
||||
);
|
||||
|
||||
websocket::Listener::new(config.socket.host, config.socket.listening_port)
|
||||
.start(websocket_handler, shutdown);
|
||||
websocket::Listener::new(
|
||||
config.socket.host,
|
||||
config.socket.listening_port,
|
||||
task_client.with_suffix("websocket_listener"),
|
||||
)
|
||||
.start(websocket_handler);
|
||||
}
|
||||
|
||||
/// blocking version of `start_socket` method. Will run forever (or until SIGINT is sent)
|
||||
|
||||
@@ -19,6 +19,7 @@ use nym_sphinx::receiver::ReconstructedMessage;
|
||||
use nym_task::connections::{
|
||||
ConnectionCommand, ConnectionCommandSender, ConnectionId, LaneQueueLengths, TransmissionLane,
|
||||
};
|
||||
use nym_task::TaskClient;
|
||||
use std::time::Duration;
|
||||
use tokio::net::TcpStream;
|
||||
use tokio::time::Instant;
|
||||
@@ -43,9 +44,11 @@ pub(crate) struct HandlerBuilder {
|
||||
lane_queue_lengths: LaneQueueLengths,
|
||||
reply_controller_sender: ReplyControllerSender,
|
||||
packet_type: Option<PacketType>,
|
||||
task_client: TaskClient,
|
||||
}
|
||||
|
||||
impl HandlerBuilder {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub(crate) fn new(
|
||||
msg_input: InputMessageSender,
|
||||
client_connection_tx: ConnectionCommandSender,
|
||||
@@ -54,6 +57,7 @@ impl HandlerBuilder {
|
||||
lane_queue_lengths: LaneQueueLengths,
|
||||
reply_controller_sender: ReplyControllerSender,
|
||||
packet_type: Option<PacketType>,
|
||||
task_client: TaskClient,
|
||||
) -> Self {
|
||||
Self {
|
||||
msg_input,
|
||||
@@ -63,11 +67,14 @@ impl HandlerBuilder {
|
||||
lane_queue_lengths,
|
||||
reply_controller_sender,
|
||||
packet_type,
|
||||
task_client,
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: make sure we only ever have one active handler
|
||||
pub fn create_active_handler(&self) -> Handler {
|
||||
let mut task_client = self.task_client.fork("active_handler");
|
||||
task_client.disarm();
|
||||
Handler {
|
||||
msg_input: self.msg_input.clone(),
|
||||
client_connection_tx: self.client_connection_tx.clone(),
|
||||
@@ -78,6 +85,7 @@ impl HandlerBuilder {
|
||||
lane_queue_lengths: self.lane_queue_lengths.clone(),
|
||||
reply_controller_sender: self.reply_controller_sender.clone(),
|
||||
packet_type: self.packet_type,
|
||||
task_client,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -92,16 +100,18 @@ pub(crate) struct Handler {
|
||||
lane_queue_lengths: LaneQueueLengths,
|
||||
reply_controller_sender: ReplyControllerSender,
|
||||
packet_type: Option<PacketType>,
|
||||
task_client: TaskClient,
|
||||
}
|
||||
|
||||
impl Drop for Handler {
|
||||
fn drop(&mut self) {
|
||||
if self
|
||||
if let Err(err) = self
|
||||
.buffer_requester
|
||||
.unbounded_send(ReceivedBufferMessage::ReceiverDisconnect)
|
||||
.is_err()
|
||||
{
|
||||
error!("we failed to disconnect the receiver from the buffer! presumably the shutdown procedure has been initiated!")
|
||||
if !self.task_client.is_shutdown_poll() {
|
||||
error!("failed to disconnect the receiver from the buffer: {err}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -125,10 +135,23 @@ impl Handler {
|
||||
};
|
||||
|
||||
// get the number of pending replies waiting for reply surbs
|
||||
let reply_queue_length = self
|
||||
let reply_queue_length = match self
|
||||
.reply_controller_sender
|
||||
.get_lane_queue_length(connection_id)
|
||||
.await;
|
||||
.await
|
||||
{
|
||||
Ok(length) => length,
|
||||
Err(err) => {
|
||||
if !self.task_client.is_shutdown_poll() {
|
||||
error!(
|
||||
"Failed to get reply queue length for connection {connection_id}: {err}"
|
||||
);
|
||||
}
|
||||
// We're just going to assume that the queue is empty, and I think that's okay
|
||||
// during shutdown.
|
||||
0
|
||||
}
|
||||
};
|
||||
|
||||
let queue_length = base_length + reply_queue_length;
|
||||
|
||||
@@ -168,10 +191,11 @@ impl Handler {
|
||||
|
||||
// the ack control is now responsible for chunking, etc.
|
||||
let input_msg = InputMessage::new_regular(recipient, message, lane, self.packet_type);
|
||||
self.msg_input
|
||||
.send(input_msg)
|
||||
.await
|
||||
.expect("InputMessageReceiver has stopped receiving!");
|
||||
if let Err(err) = self.msg_input.send(input_msg).await {
|
||||
if !self.task_client.is_shutdown_poll() {
|
||||
error!("Failed to send message to the input buffer: {err}");
|
||||
}
|
||||
}
|
||||
|
||||
// Only reply back with a `LaneQueueLength` if the sender providided a connection id
|
||||
let TransmissionLane::ConnectionId(connection_id) = lane else {
|
||||
@@ -200,10 +224,11 @@ impl Handler {
|
||||
|
||||
let input_msg =
|
||||
InputMessage::new_anonymous(recipient, message, reply_surbs, lane, self.packet_type);
|
||||
self.msg_input
|
||||
.send(input_msg)
|
||||
.await
|
||||
.expect("InputMessageReceiver has stopped receiving!");
|
||||
if let Err(err) = self.msg_input.send(input_msg).await {
|
||||
if !self.task_client.is_shutdown_poll() {
|
||||
error!("Failed to send anonymous message to the input buffer: {err}");
|
||||
}
|
||||
}
|
||||
|
||||
// Only reply back with a `LaneQueueLength` if the sender providided a connection id
|
||||
let TransmissionLane::ConnectionId(connection_id) = lane else {
|
||||
@@ -227,10 +252,11 @@ impl Handler {
|
||||
});
|
||||
|
||||
let input_msg = InputMessage::new_reply(recipient_tag, message, lane, self.packet_type);
|
||||
self.msg_input
|
||||
.send(input_msg)
|
||||
.await
|
||||
.expect("InputMessageReceiver has stopped receiving!");
|
||||
if let Err(err) = self.msg_input.send(input_msg).await {
|
||||
if !self.task_client.is_shutdown_poll() {
|
||||
error!("Failed to send reply message to the input buffer: {err}");
|
||||
}
|
||||
}
|
||||
|
||||
// Only reply back with a `LaneQueueLength` if the sender providided a connection id
|
||||
let TransmissionLane::ConnectionId(connection_id) = lane else {
|
||||
@@ -245,9 +271,14 @@ impl Handler {
|
||||
}
|
||||
|
||||
fn handle_closed_connection(&self, connection_id: u64) -> Option<ServerResponse> {
|
||||
self.client_connection_tx
|
||||
if let Err(err) = self
|
||||
.client_connection_tx
|
||||
.unbounded_send(ConnectionCommand::Close(connection_id))
|
||||
.unwrap();
|
||||
{
|
||||
if !self.task_client.is_shutdown_poll() {
|
||||
error!("Failed to send close connection command: {err}");
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
@@ -362,11 +393,10 @@ impl Handler {
|
||||
}
|
||||
}
|
||||
|
||||
async fn listen_for_requests(
|
||||
&mut self,
|
||||
mut msg_receiver: ReconstructedMessagesReceiver,
|
||||
mut task_client: nym_task::TaskClient,
|
||||
) {
|
||||
async fn listen_for_requests(&mut self, mut msg_receiver: ReconstructedMessagesReceiver) {
|
||||
let mut task_client = self.task_client.fork("select");
|
||||
task_client.disarm();
|
||||
|
||||
while !task_client.is_shutdown() {
|
||||
tokio::select! {
|
||||
// we can either get a client request from the websocket
|
||||
@@ -415,15 +445,7 @@ impl Handler {
|
||||
}
|
||||
|
||||
// consume self to make sure `drop` is called after this is done
|
||||
pub(crate) async fn handle_connection(
|
||||
mut self,
|
||||
socket: TcpStream,
|
||||
mut task_client: nym_task::TaskClient,
|
||||
) {
|
||||
// We don't want a crash in the connection handler to trigger a shutdown of the whole
|
||||
// process.
|
||||
task_client.disarm();
|
||||
|
||||
pub(crate) async fn handle_connection(mut self, socket: TcpStream) {
|
||||
let ws_stream = match accept_async(socket).await {
|
||||
Ok(ws_stream) => ws_stream,
|
||||
Err(err) => {
|
||||
@@ -436,14 +458,18 @@ impl Handler {
|
||||
let (reconstructed_sender, reconstructed_receiver) = mpsc::unbounded();
|
||||
|
||||
// tell the buffer to start sending stuff to us
|
||||
self.buffer_requester
|
||||
.unbounded_send(ReceivedBufferMessage::ReceiverAnnounce(
|
||||
reconstructed_sender,
|
||||
))
|
||||
.expect("the buffer request failed!");
|
||||
if let Err(err) =
|
||||
self.buffer_requester
|
||||
.unbounded_send(ReceivedBufferMessage::ReceiverAnnounce(
|
||||
reconstructed_sender,
|
||||
))
|
||||
{
|
||||
if !self.task_client.is_shutdown_poll() {
|
||||
error!("failed to announce the receiver to the buffer: {err}");
|
||||
}
|
||||
}
|
||||
|
||||
self.listen_for_requests(reconstructed_receiver, task_client)
|
||||
.await;
|
||||
self.listen_for_requests(reconstructed_receiver).await;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
use super::handler::HandlerBuilder;
|
||||
use log::*;
|
||||
use nym_task::TaskClient;
|
||||
use std::net::IpAddr;
|
||||
use std::{net::SocketAddr, process, sync::Arc};
|
||||
use tokio::io::AsyncWriteExt;
|
||||
@@ -22,21 +23,19 @@ impl State {
|
||||
pub(crate) struct Listener {
|
||||
address: SocketAddr,
|
||||
state: State,
|
||||
task_client: TaskClient,
|
||||
}
|
||||
|
||||
impl Listener {
|
||||
pub(crate) fn new(host: IpAddr, port: u16) -> Self {
|
||||
pub(crate) fn new(host: IpAddr, port: u16, task_client: TaskClient) -> Self {
|
||||
Listener {
|
||||
address: SocketAddr::new(host, port),
|
||||
state: State::AwaitingConnection,
|
||||
task_client,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) async fn run(
|
||||
&mut self,
|
||||
handler: HandlerBuilder,
|
||||
mut task_client: nym_task::TaskClient,
|
||||
) {
|
||||
pub(crate) async fn run(&mut self, handler: HandlerBuilder) {
|
||||
let tcp_listener = match tokio::net::TcpListener::bind(self.address).await {
|
||||
Ok(listener) => listener,
|
||||
Err(err) => {
|
||||
@@ -47,11 +46,11 @@ impl Listener {
|
||||
|
||||
let notify = Arc::new(Notify::new());
|
||||
|
||||
loop {
|
||||
while !self.task_client.is_shutdown() {
|
||||
tokio::select! {
|
||||
// When the handler finishes we check if shutdown is signalled
|
||||
_ = notify.notified() => {
|
||||
if task_client.is_shutdown() {
|
||||
if self.task_client.is_shutdown() {
|
||||
log::trace!("Websocket listener: detected shutdown after connection closed");
|
||||
break;
|
||||
}
|
||||
@@ -60,7 +59,7 @@ impl Listener {
|
||||
}
|
||||
// ... but when there is no connected client at the time of shutdown being
|
||||
// signalled, we handle it here.
|
||||
_ = task_client.recv() => {
|
||||
_ = self.task_client.recv() => {
|
||||
if !self.state.is_connected() {
|
||||
log::trace!("Not connected: shutting down");
|
||||
break;
|
||||
@@ -88,9 +87,8 @@ impl Listener {
|
||||
// hanging because the executor doesn't come back here
|
||||
let notify_clone = Arc::clone(¬ify);
|
||||
let fresh_handler = handler.create_active_handler();
|
||||
let task_client_handler = task_client.clone();
|
||||
tokio::spawn(async move {
|
||||
fresh_handler.handle_connection(socket, task_client_handler).await;
|
||||
fresh_handler.handle_connection(socket).await;
|
||||
notify_clone.notify_one();
|
||||
});
|
||||
self.state = State::Connected;
|
||||
@@ -104,13 +102,9 @@ impl Listener {
|
||||
log::debug!("Websocket listener: Exiting");
|
||||
}
|
||||
|
||||
pub(crate) fn start(
|
||||
mut self,
|
||||
handler: HandlerBuilder,
|
||||
shutdown: nym_task::TaskClient,
|
||||
) -> JoinHandle<()> {
|
||||
pub(crate) fn start(mut self, handler: HandlerBuilder) -> JoinHandle<()> {
|
||||
info!("Running websocket on {:?}", self.address.to_string());
|
||||
|
||||
tokio::spawn(async move { self.run(handler, shutdown).await })
|
||||
tokio::spawn(async move { self.run(handler).await })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "nym-socks5-client"
|
||||
version = "1.1.47"
|
||||
version = "1.1.49"
|
||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
|
||||
description = "A SOCKS5 localhost proxy that converts incoming messages to Sphinx and sends them to a Nym address"
|
||||
edition = "2021"
|
||||
|
||||
@@ -60,7 +60,7 @@ impl From<IpAddr> for IpPair {
|
||||
std::net::IpAddr::V4(ipv4_addr) => (ipv4_addr.octets()[2], ipv4_addr.octets()[3]),
|
||||
std::net::IpAddr::V6(ipv6_addr) => (ipv6_addr.octets()[14], ipv6_addr.octets()[15]),
|
||||
};
|
||||
let last_bytes = (before_last_byte as u16) << 8 | last_byte as u16;
|
||||
let last_bytes = ((before_last_byte as u16) << 8) | last_byte as u16;
|
||||
let ipv4 = Ipv4Addr::new(
|
||||
WG_TUN_DEVICE_IP_ADDRESS_V4.octets()[0],
|
||||
WG_TUN_DEVICE_IP_ADDRESS_V4.octets()[1],
|
||||
|
||||
@@ -40,6 +40,7 @@ use nym_client_core_config_types::ForgetMe;
|
||||
use nym_client_core_gateways_storage::{GatewayDetails, GatewaysDetailsStore};
|
||||
use nym_credential_storage::storage::Storage as CredentialStorage;
|
||||
use nym_crypto::asymmetric::{encryption, identity};
|
||||
use nym_crypto::hkdf::DerivationMaterial;
|
||||
use nym_gateway_client::client::config::GatewayClientConfig;
|
||||
use nym_gateway_client::{
|
||||
AcknowledgementReceiver, GatewayClient, GatewayConfig, MixnetMessageReceiver, PacketRouter,
|
||||
@@ -192,6 +193,8 @@ pub struct BaseClientBuilder<C, S: MixnetClientStorage> {
|
||||
|
||||
#[cfg(unix)]
|
||||
connection_fd_callback: Option<Arc<dyn Fn(RawFd) + Send + Sync>>,
|
||||
|
||||
derivation_material: Option<DerivationMaterial>,
|
||||
}
|
||||
|
||||
impl<C, S> BaseClientBuilder<C, S>
|
||||
@@ -216,9 +219,19 @@ where
|
||||
setup_method: GatewaySetup::MustLoad { gateway_id: None },
|
||||
#[cfg(unix)]
|
||||
connection_fd_callback: None,
|
||||
derivation_material: None,
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn with_derivation_material(
|
||||
mut self,
|
||||
derivation_material: Option<DerivationMaterial>,
|
||||
) -> Self {
|
||||
self.derivation_material = derivation_material;
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn with_forget_me(mut self, forget_me: &ForgetMe) -> Self {
|
||||
self.config.debug.forget_me = *forget_me;
|
||||
@@ -297,7 +310,7 @@ where
|
||||
topology_accessor: TopologyAccessor,
|
||||
mix_tx: BatchMixMessageSender,
|
||||
stats_tx: ClientStatsSender,
|
||||
shutdown: TaskClient,
|
||||
task_client: TaskClient,
|
||||
) {
|
||||
info!("Starting loop cover traffic stream...");
|
||||
|
||||
@@ -310,9 +323,10 @@ where
|
||||
debug_config.traffic,
|
||||
debug_config.cover_traffic,
|
||||
stats_tx,
|
||||
task_client,
|
||||
);
|
||||
|
||||
stream.start_with_shutdown(shutdown);
|
||||
stream.start();
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
@@ -327,7 +341,7 @@ where
|
||||
reply_controller_receiver: ReplyControllerReceiver,
|
||||
lane_queue_lengths: LaneQueueLengths,
|
||||
client_connection_rx: ConnectionCommandReceiver,
|
||||
shutdown: TaskClient,
|
||||
task_client: TaskClient,
|
||||
packet_type: PacketType,
|
||||
stats_tx: ClientStatsSender,
|
||||
) {
|
||||
@@ -345,8 +359,9 @@ where
|
||||
lane_queue_lengths,
|
||||
client_connection_rx,
|
||||
stats_tx,
|
||||
task_client,
|
||||
)
|
||||
.start_with_shutdown(shutdown, packet_type);
|
||||
.start(packet_type);
|
||||
}
|
||||
|
||||
// buffer controlling all messages fetched from provider
|
||||
@@ -369,8 +384,9 @@ where
|
||||
reply_key_storage,
|
||||
reply_controller_sender,
|
||||
metrics_reporter,
|
||||
shutdown,
|
||||
);
|
||||
controller.start_with_shutdown(shutdown)
|
||||
controller.start()
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
@@ -559,15 +575,22 @@ where
|
||||
topology_accessor: TopologyAccessor,
|
||||
local_gateway: NodeIdentity,
|
||||
wait_for_gateway: bool,
|
||||
mut shutdown: TaskClient,
|
||||
mut task_client: TaskClient,
|
||||
) -> Result<(), ClientCoreError> {
|
||||
let topology_refresher_config =
|
||||
TopologyRefresherConfig::new(topology_config.topology_refresh_rate);
|
||||
|
||||
if topology_config.disable_refreshing {
|
||||
// if we're not spawning the refresher, don't cause shutdown immediately
|
||||
info!("The background topology refesher is not going to be started");
|
||||
task_client.disarm();
|
||||
}
|
||||
|
||||
let mut topology_refresher = TopologyRefresher::new(
|
||||
topology_refresher_config,
|
||||
topology_accessor,
|
||||
topology_provider,
|
||||
task_client,
|
||||
);
|
||||
// before returning, block entire runtime to refresh the current network view so that any
|
||||
// components depending on topology would see a non-empty view
|
||||
@@ -608,15 +631,11 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
if topology_config.disable_refreshing {
|
||||
// if we're not spawning the refresher, don't cause shutdown immediately
|
||||
info!("The topology refesher is not going to be started");
|
||||
shutdown.disarm();
|
||||
} else {
|
||||
if !topology_config.disable_refreshing {
|
||||
// don't spawn the refresher if we don't want to be refreshing the topology.
|
||||
// only use the initial values obtained
|
||||
info!("Starting topology refresher...");
|
||||
topology_refresher.start_with_shutdown(shutdown);
|
||||
topology_refresher.start();
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -627,17 +646,17 @@ where
|
||||
user_agent: Option<UserAgent>,
|
||||
client_stats_id: String,
|
||||
input_sender: Sender<InputMessage>,
|
||||
shutdown: TaskClient,
|
||||
task_client: TaskClient,
|
||||
) -> ClientStatsSender {
|
||||
info!("Starting statistics control...");
|
||||
StatisticsControl::create_and_start_with_shutdown(
|
||||
StatisticsControl::create_and_start(
|
||||
config.debug.stats_reporting,
|
||||
user_agent
|
||||
.map(|u| u.application)
|
||||
.unwrap_or("unknown".to_string()),
|
||||
client_stats_id,
|
||||
input_sender.clone(),
|
||||
shutdown.with_suffix("controller"),
|
||||
task_client,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -647,8 +666,8 @@ where
|
||||
) -> (BatchMixMessageSender, ClientRequestSender) {
|
||||
info!("Starting mix traffic controller...");
|
||||
let (mix_traffic_controller, mix_tx, client_tx) =
|
||||
MixTrafficController::new(gateway_transceiver);
|
||||
mix_traffic_controller.start_with_shutdown(shutdown);
|
||||
MixTrafficController::new(gateway_transceiver, shutdown);
|
||||
mix_traffic_controller.start();
|
||||
(mix_tx, client_tx)
|
||||
}
|
||||
|
||||
@@ -684,6 +703,7 @@ where
|
||||
setup_method: GatewaySetup,
|
||||
key_store: &S::KeyStore,
|
||||
details_store: &S::GatewaysDetailsStore,
|
||||
derivation_material: Option<DerivationMaterial>,
|
||||
) -> Result<InitialisationResult, ClientCoreError>
|
||||
where
|
||||
<S::KeyStore as KeyStore>::StorageError: Sync + Send,
|
||||
@@ -693,7 +713,12 @@ where
|
||||
if key_store.load_keys().await.is_err() {
|
||||
info!("could not find valid client keys - a new set will be generated");
|
||||
let mut rng = OsRng;
|
||||
let keys = ClientKeys::generate_new(&mut rng);
|
||||
let keys = if let Some(derivation_material) = derivation_material {
|
||||
ClientKeys::from_master_key(&mut rng, &derivation_material)
|
||||
.map_err(|_| ClientCoreError::HkdfDerivationError {})?
|
||||
} else {
|
||||
ClientKeys::generate_new(&mut rng)
|
||||
};
|
||||
store_client_keys(keys, key_store).await?;
|
||||
}
|
||||
|
||||
@@ -715,6 +740,7 @@ where
|
||||
self.setup_method,
|
||||
self.client_store.key_store(),
|
||||
self.client_store.gateway_details_store(),
|
||||
self.derivation_material,
|
||||
)
|
||||
.await?;
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ use nym_sphinx::cover::generate_loop_cover_packet;
|
||||
use nym_sphinx::params::{PacketSize, PacketType};
|
||||
use nym_sphinx::utils::sample_poisson_duration;
|
||||
use nym_statistics_common::clients::{packet_statistics::PacketStatisticsEvent, ClientStatsSender};
|
||||
use nym_task::TaskClient;
|
||||
use rand::{rngs::OsRng, CryptoRng, Rng};
|
||||
use std::pin::Pin;
|
||||
use std::sync::Arc;
|
||||
@@ -64,6 +65,8 @@ where
|
||||
packet_type: PacketType,
|
||||
|
||||
stats_tx: ClientStatsSender,
|
||||
|
||||
task_client: TaskClient,
|
||||
}
|
||||
|
||||
impl<R> Stream for LoopCoverTrafficStream<R>
|
||||
@@ -110,6 +113,7 @@ impl LoopCoverTrafficStream<OsRng> {
|
||||
traffic_config: config::Traffic,
|
||||
cover_config: config::CoverTraffic,
|
||||
stats_tx: ClientStatsSender,
|
||||
task_client: TaskClient,
|
||||
) -> Self {
|
||||
let rng = OsRng;
|
||||
|
||||
@@ -128,6 +132,7 @@ impl LoopCoverTrafficStream<OsRng> {
|
||||
secondary_packet_size: traffic_config.secondary_packet_size,
|
||||
packet_type: traffic_config.packet_type,
|
||||
stats_tx,
|
||||
task_client,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -175,7 +180,7 @@ impl LoopCoverTrafficStream<OsRng> {
|
||||
}
|
||||
};
|
||||
|
||||
let cover_message = generate_loop_cover_packet(
|
||||
let cover_message = match generate_loop_cover_packet(
|
||||
&mut self.rng,
|
||||
topology_ref,
|
||||
&self.ack_key,
|
||||
@@ -184,8 +189,15 @@ impl LoopCoverTrafficStream<OsRng> {
|
||||
self.cover_traffic.loop_cover_traffic_average_delay,
|
||||
cover_traffic_packet_size,
|
||||
self.packet_type,
|
||||
)
|
||||
.expect("Somehow failed to generate a loop cover message with a valid topology");
|
||||
) {
|
||||
Ok(cover_message) => cover_message,
|
||||
Err(err) => {
|
||||
warn!(
|
||||
"Somehow failed to generate a loop cover message with a valid topology: {err}"
|
||||
);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
if let Err(err) = self.mix_tx.try_send(vec![cover_message]) {
|
||||
match err {
|
||||
@@ -217,7 +229,7 @@ impl LoopCoverTrafficStream<OsRng> {
|
||||
tokio::task::yield_now().await;
|
||||
}
|
||||
|
||||
pub fn start_with_shutdown(mut self, mut shutdown: nym_task::TaskClient) {
|
||||
pub fn start(mut self) {
|
||||
if self.cover_traffic.disable_loop_cover_traffic_stream {
|
||||
// we should have never got here in the first place - the task should have never been created to begin with
|
||||
// so panic and review the code that lead to this branch
|
||||
@@ -231,6 +243,8 @@ impl LoopCoverTrafficStream<OsRng> {
|
||||
);
|
||||
self.set_next_delay(sampled);
|
||||
|
||||
let mut shutdown = self.task_client.fork("select");
|
||||
|
||||
spawn_future(async move {
|
||||
debug!("Started LoopCoverTrafficStream with graceful shutdown support");
|
||||
|
||||
|
||||
@@ -2,7 +2,10 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::client::key_manager::persistence::KeyStore;
|
||||
use nym_crypto::asymmetric::{encryption, identity};
|
||||
use nym_crypto::{
|
||||
asymmetric::{encryption, identity},
|
||||
hkdf::{DerivationMaterial, InvalidLength},
|
||||
};
|
||||
use nym_gateway_requests::shared_key::{LegacySharedKeys, SharedGatewayKey, SharedSymmetricKey};
|
||||
use nym_sphinx::acknowledgements::AckKey;
|
||||
use rand::{CryptoRng, RngCore};
|
||||
@@ -10,6 +13,7 @@ use std::sync::Arc;
|
||||
use zeroize::ZeroizeOnDrop;
|
||||
|
||||
pub mod persistence;
|
||||
mod test;
|
||||
|
||||
// Note: to support key rotation in the future, all keys will require adding an extra smart pointer,
|
||||
// most likely an AtomicCell, or if it doesn't work as I think it does, a Mutex. Although I think
|
||||
@@ -43,6 +47,24 @@ impl ClientKeys {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_master_key<R>(
|
||||
rng: &mut R,
|
||||
derivation_material: &DerivationMaterial,
|
||||
) -> Result<Self, InvalidLength>
|
||||
where
|
||||
R: RngCore + CryptoRng,
|
||||
{
|
||||
let secret = derivation_material.derive_secret()?;
|
||||
Ok(ClientKeys {
|
||||
identity_keypair: Arc::new(identity::KeyPair::from_secret(
|
||||
secret,
|
||||
derivation_material.index(),
|
||||
)),
|
||||
encryption_keypair: Arc::new(encryption::KeyPair::new(rng)),
|
||||
ack_key: Arc::new(AckKey::new(rng)),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn from_keys(
|
||||
id_keypair: identity::KeyPair,
|
||||
enc_keypair: encryption::KeyPair,
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::client::key_manager::ClientKeys;
|
||||
use nym_crypto::hkdf::DerivationMaterial;
|
||||
use rand::SeedableRng;
|
||||
use rand_chacha::ChaCha20Rng;
|
||||
|
||||
#[test]
|
||||
fn test_from_master_key_success() {
|
||||
// Set up a deterministic RNG.
|
||||
let seed = [33u8; 32];
|
||||
let mut rng = ChaCha20Rng::from_seed(seed);
|
||||
|
||||
// Set up the derivation material.
|
||||
let master_key = b"this is a secret master key";
|
||||
let salt = b"unique-salt";
|
||||
let derivation_material = DerivationMaterial::new(master_key, 0, salt);
|
||||
|
||||
// Generate ClientKeys from the master key.
|
||||
let client_keys = ClientKeys::from_master_key(&mut rng, &derivation_material)
|
||||
.expect("Failed to create client keys");
|
||||
|
||||
assert_eq!(
|
||||
client_keys.identity_keypair().public_key().to_string(),
|
||||
String::from("FX4Undr5LPPBA7zThWWpAKXKQTXSbW1C28PnxbCqUkU4")
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
client_keys.identity_keypair().private_key().to_string(),
|
||||
String::from("6S3uMi2rU5SwyUUYCiMrF5qqdcYnEDMYLggBSvavVzEt")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_master_key_deterministic_identity() {
|
||||
// Using identical derivation material should result in the exactly same identity keypair.
|
||||
let seed = [1u8; 32];
|
||||
let mut rng1 = ChaCha20Rng::from_seed(seed);
|
||||
let mut rng2 = ChaCha20Rng::from_seed(seed);
|
||||
|
||||
let master_key = b"another secret master key";
|
||||
let salt = b"deterministic-salt";
|
||||
let index = 7u32;
|
||||
let derivation_material = DerivationMaterial::new(master_key, index, salt);
|
||||
|
||||
let client_keys1 = ClientKeys::from_master_key(&mut rng1, &derivation_material)
|
||||
.expect("Failed to create client keys (first instance)");
|
||||
let client_keys2 = ClientKeys::from_master_key(&mut rng2, &derivation_material)
|
||||
.expect("Failed to create client keys (second instance)");
|
||||
|
||||
assert_eq!(
|
||||
client_keys1.identity_keypair().public_key().to_string(),
|
||||
client_keys2.identity_keypair().public_key().to_string()
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
client_keys1.identity_keypair().private_key().to_string(),
|
||||
client_keys2.identity_keypair().private_key().to_string()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_master_key_different_indices() {
|
||||
// Changing the index should yield a different identity key.
|
||||
let seed = [5u8; 32];
|
||||
let mut rng = ChaCha20Rng::from_seed(seed);
|
||||
|
||||
let master_key = b"same secret key";
|
||||
let salt = b"same-salt";
|
||||
|
||||
let derivation_material1 = DerivationMaterial::new(master_key, 1, salt);
|
||||
let derivation_material2 = DerivationMaterial::new(master_key, 2, salt);
|
||||
|
||||
let client_keys1 = ClientKeys::from_master_key(&mut rng, &derivation_material1)
|
||||
.expect("Failed to create client keys for index 1");
|
||||
let client_keys2 = ClientKeys::from_master_key(&mut rng, &derivation_material2)
|
||||
.expect("Failed to create client keys for index 2");
|
||||
|
||||
assert_ne!(
|
||||
client_keys1.identity_keypair().public_key().to_string(),
|
||||
client_keys2.identity_keypair().public_key().to_string()
|
||||
);
|
||||
|
||||
assert_ne!(
|
||||
client_keys1.identity_keypair().private_key().to_string(),
|
||||
client_keys2.identity_keypair().private_key().to_string()
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ use crate::spawn_future;
|
||||
use log::*;
|
||||
use nym_gateway_requests::ClientRequest;
|
||||
use nym_sphinx::forwarding::packet::MixPacket;
|
||||
use nym_task::TaskClient;
|
||||
use transceiver::ErasedGatewayError;
|
||||
|
||||
pub type BatchMixMessageSender = tokio::sync::mpsc::Sender<Vec<MixPacket>>;
|
||||
@@ -32,11 +33,14 @@ pub struct MixTrafficController {
|
||||
// TODO: this is temporary work-around.
|
||||
// in long run `gateway_client` will be moved away from `MixTrafficController` anyway.
|
||||
consecutive_gateway_failure_count: usize,
|
||||
|
||||
task_client: TaskClient,
|
||||
}
|
||||
|
||||
impl MixTrafficController {
|
||||
pub fn new<T>(
|
||||
gateway_transceiver: T,
|
||||
task_client: TaskClient,
|
||||
) -> (
|
||||
MixTrafficController,
|
||||
BatchMixMessageSender,
|
||||
@@ -56,6 +60,7 @@ impl MixTrafficController {
|
||||
mix_rx: message_receiver,
|
||||
client_rx: client_receiver,
|
||||
consecutive_gateway_failure_count: 0,
|
||||
task_client,
|
||||
},
|
||||
message_sender,
|
||||
client_sender,
|
||||
@@ -64,6 +69,7 @@ impl MixTrafficController {
|
||||
|
||||
pub fn new_dynamic(
|
||||
gateway_transceiver: Box<dyn GatewayTransceiver + Send>,
|
||||
task_client: TaskClient,
|
||||
) -> (
|
||||
MixTrafficController,
|
||||
BatchMixMessageSender,
|
||||
@@ -78,6 +84,7 @@ impl MixTrafficController {
|
||||
mix_rx: message_receiver,
|
||||
client_rx: client_receiver,
|
||||
consecutive_gateway_failure_count: 0,
|
||||
task_client,
|
||||
},
|
||||
message_sender,
|
||||
client_sender,
|
||||
@@ -109,11 +116,11 @@ impl MixTrafficController {
|
||||
result
|
||||
}
|
||||
|
||||
pub fn start_with_shutdown(mut self, mut shutdown: nym_task::TaskClient) {
|
||||
pub fn start(mut self) {
|
||||
spawn_future(async move {
|
||||
debug!("Started MixTrafficController with graceful shutdown support");
|
||||
|
||||
loop {
|
||||
while !self.task_client.is_shutdown() {
|
||||
tokio::select! {
|
||||
mix_packets = self.mix_rx.recv() => match mix_packets {
|
||||
Some(mix_packets) => {
|
||||
@@ -125,7 +132,7 @@ impl MixTrafficController {
|
||||
error!("Failed to send sphinx packet to the gateway {MAX_FAILURE_COUNT} times in a row - assuming the gateway is dead");
|
||||
// Do we need to handle the embedded mixnet client case
|
||||
// separately?
|
||||
shutdown.send_we_stopped(Box::new(ClientCoreError::GatewayFailedToForwardMessages));
|
||||
self.task_client.send_we_stopped(Box::new(ClientCoreError::GatewayFailedToForwardMessages));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -146,13 +153,13 @@ impl MixTrafficController {
|
||||
log::trace!("MixTrafficController, client request channel closed");
|
||||
}
|
||||
},
|
||||
_ = shutdown.recv_with_delay() => {
|
||||
_ = self.task_client.recv() => {
|
||||
log::trace!("MixTrafficController: Received shutdown");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
shutdown.recv_timeout().await;
|
||||
self.task_client.recv_timeout().await;
|
||||
|
||||
log::debug!("MixTrafficController: Exiting");
|
||||
});
|
||||
|
||||
+15
-6
@@ -11,6 +11,7 @@ use nym_sphinx::{
|
||||
acknowledgements::{identifier::recover_identifier, AckKey},
|
||||
chunking::fragment::{FragmentIdentifier, COVER_FRAG_ID},
|
||||
};
|
||||
use nym_task::TaskClient;
|
||||
use std::sync::Arc;
|
||||
|
||||
/// Module responsible for listening for any data resembling acknowledgements from the network
|
||||
@@ -20,6 +21,7 @@ pub(super) struct AcknowledgementListener {
|
||||
ack_receiver: AcknowledgementReceiver,
|
||||
action_sender: AckActionSender,
|
||||
stats_tx: ClientStatsSender,
|
||||
task_client: TaskClient,
|
||||
}
|
||||
|
||||
impl AcknowledgementListener {
|
||||
@@ -28,12 +30,14 @@ impl AcknowledgementListener {
|
||||
ack_receiver: AcknowledgementReceiver,
|
||||
action_sender: AckActionSender,
|
||||
stats_tx: ClientStatsSender,
|
||||
task_client: TaskClient,
|
||||
) -> Self {
|
||||
AcknowledgementListener {
|
||||
ack_key,
|
||||
ack_receiver,
|
||||
action_sender,
|
||||
stats_tx,
|
||||
task_client,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,9 +68,14 @@ impl AcknowledgementListener {
|
||||
trace!("Received {} from the mix network", frag_id);
|
||||
self.stats_tx
|
||||
.report(PacketStatisticsEvent::RealAckReceived(ack_content.len()).into());
|
||||
self.action_sender
|
||||
if let Err(err) = self
|
||||
.action_sender
|
||||
.unbounded_send(Action::new_remove(frag_id))
|
||||
.unwrap();
|
||||
{
|
||||
if !self.task_client.is_shutdown_poll() {
|
||||
error!("Failed to send remove action to action controller: {err}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn handle_ack_receiver_item(&mut self, item: Vec<Vec<u8>>) {
|
||||
@@ -76,10 +85,10 @@ impl AcknowledgementListener {
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) async fn run_with_shutdown(&mut self, mut shutdown: nym_task::TaskClient) {
|
||||
pub(super) async fn run(&mut self) {
|
||||
debug!("Started AcknowledgementListener with graceful shutdown support");
|
||||
|
||||
while !shutdown.is_shutdown() {
|
||||
while !self.task_client.is_shutdown() {
|
||||
tokio::select! {
|
||||
acks = self.ack_receiver.next() => match acks {
|
||||
Some(acks) => self.handle_ack_receiver_item(acks).await,
|
||||
@@ -88,12 +97,12 @@ impl AcknowledgementListener {
|
||||
break;
|
||||
}
|
||||
},
|
||||
_ = shutdown.recv_with_delay() => {
|
||||
_ = self.task_client.recv() => {
|
||||
log::trace!("AcknowledgementListener: Received shutdown");
|
||||
}
|
||||
}
|
||||
}
|
||||
shutdown.recv_timeout().await;
|
||||
self.task_client.recv_timeout().await;
|
||||
log::debug!("AcknowledgementListener: Exiting");
|
||||
}
|
||||
}
|
||||
|
||||
+15
-16
@@ -9,6 +9,7 @@ use log::*;
|
||||
use nym_nonexhaustive_delayqueue::{Expired, NonExhaustiveDelayQueue, QueueKey};
|
||||
use nym_sphinx::chunking::fragment::FragmentIdentifier;
|
||||
use nym_sphinx::Delay as SphinxDelay;
|
||||
use nym_task::TaskClient;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
@@ -101,6 +102,8 @@ pub(super) struct ActionController {
|
||||
|
||||
/// Channel for notifying `RetransmissionRequestListener` about expired acknowledgements.
|
||||
retransmission_sender: RetransmissionRequestSender,
|
||||
|
||||
task_client: TaskClient,
|
||||
}
|
||||
|
||||
impl ActionController {
|
||||
@@ -108,6 +111,7 @@ impl ActionController {
|
||||
config: Config,
|
||||
retransmission_sender: RetransmissionRequestSender,
|
||||
incoming_actions: AckActionReceiver,
|
||||
task_client: TaskClient,
|
||||
) -> Self {
|
||||
ActionController {
|
||||
config,
|
||||
@@ -115,6 +119,7 @@ impl ActionController {
|
||||
pending_acks_timers: NonExhaustiveDelayQueue::new(),
|
||||
incoming_actions,
|
||||
retransmission_sender,
|
||||
task_client,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -216,11 +221,7 @@ impl ActionController {
|
||||
}
|
||||
|
||||
// note: when the entry expires it's automatically removed from pending_acks_timers
|
||||
fn handle_expired_ack_timer(
|
||||
&mut self,
|
||||
expired_ack: Expired<FragmentIdentifier>,
|
||||
task_client: &mut nym_task::TaskClient,
|
||||
) {
|
||||
fn handle_expired_ack_timer(&mut self, expired_ack: Expired<FragmentIdentifier>) {
|
||||
// I'm honestly not sure how to handle it, because getting it means other things in our
|
||||
// system are already misbehaving. If we ever see this panic, then I guess we should worry
|
||||
// about it. Perhaps just reschedule it at later point?
|
||||
@@ -238,15 +239,13 @@ impl ActionController {
|
||||
// downgrading an arc and then upgrading vs cloning is difference of 30ns vs 15ns
|
||||
// so it's literally a NO difference while it might prevent us from unnecessarily
|
||||
// resending data (in maybe 1 in 1 million cases, but it's something)
|
||||
if self
|
||||
if let Err(err) = self
|
||||
.retransmission_sender
|
||||
.unbounded_send(Arc::downgrade(pending_ack_data))
|
||||
.is_err()
|
||||
{
|
||||
assert!(
|
||||
task_client.is_shutdown_poll(),
|
||||
"Failed to send pending ack for retransmission"
|
||||
);
|
||||
if !self.task_client.is_shutdown_poll() {
|
||||
log::error!("Failed to send pending ack for retransmission: {err}");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// this shouldn't cause any issues but shouldn't have happened to begin with!
|
||||
@@ -265,10 +264,10 @@ impl ActionController {
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) async fn run_with_shutdown(&mut self, mut shutdown: nym_task::TaskClient) {
|
||||
pub(super) async fn run(&mut self) {
|
||||
debug!("Started ActionController with graceful shutdown support");
|
||||
|
||||
loop {
|
||||
while !self.task_client.is_shutdown() {
|
||||
tokio::select! {
|
||||
action = self.incoming_actions.next() => match action {
|
||||
Some(action) => self.process_action(action),
|
||||
@@ -280,19 +279,19 @@ impl ActionController {
|
||||
}
|
||||
},
|
||||
expired_ack = self.pending_acks_timers.next() => match expired_ack {
|
||||
Some(expired_ack) => self.handle_expired_ack_timer(expired_ack, &mut shutdown),
|
||||
Some(expired_ack) => self.handle_expired_ack_timer(expired_ack),
|
||||
None => {
|
||||
log::trace!("ActionController: Stopping since ack channel closed");
|
||||
break;
|
||||
}
|
||||
},
|
||||
_ = shutdown.recv_with_delay() => {
|
||||
_ = self.task_client.recv() => {
|
||||
log::trace!("ActionController: Received shutdown");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
shutdown.recv_timeout().await;
|
||||
self.task_client.recv_timeout().await;
|
||||
log::debug!("ActionController: Exiting");
|
||||
}
|
||||
}
|
||||
|
||||
+15
-5
@@ -11,6 +11,7 @@ use nym_sphinx::anonymous_replies::requests::AnonymousSenderTag;
|
||||
use nym_sphinx::forwarding::packet::MixPacket;
|
||||
use nym_sphinx::params::PacketType;
|
||||
use nym_task::connections::TransmissionLane;
|
||||
use nym_task::TaskClient;
|
||||
use rand::{CryptoRng, Rng};
|
||||
|
||||
/// Module responsible for dealing with the received messages: splitting them, creating acknowledgements,
|
||||
@@ -23,6 +24,7 @@ where
|
||||
input_receiver: InputMessageReceiver,
|
||||
message_handler: MessageHandler<R>,
|
||||
reply_controller_sender: ReplyControllerSender,
|
||||
task_client: TaskClient,
|
||||
}
|
||||
|
||||
impl<R> InputMessageListener<R>
|
||||
@@ -36,11 +38,13 @@ where
|
||||
input_receiver: InputMessageReceiver,
|
||||
message_handler: MessageHandler<R>,
|
||||
reply_controller_sender: ReplyControllerSender,
|
||||
task_client: TaskClient,
|
||||
) -> Self {
|
||||
InputMessageListener {
|
||||
input_receiver,
|
||||
message_handler,
|
||||
reply_controller_sender,
|
||||
task_client,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,8 +67,14 @@ where
|
||||
lane: TransmissionLane,
|
||||
) {
|
||||
// offload reply handling to the dedicated task
|
||||
self.reply_controller_sender
|
||||
if let Err(err) = self
|
||||
.reply_controller_sender
|
||||
.send_reply(recipient_tag, data, lane)
|
||||
{
|
||||
if !self.task_client.is_shutdown_poll() {
|
||||
error!("failed to send a reply - {err}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn handle_plain_message(
|
||||
@@ -164,10 +174,10 @@ where
|
||||
};
|
||||
}
|
||||
|
||||
pub(super) async fn run_with_shutdown(&mut self, mut shutdown: nym_task::TaskClient) {
|
||||
pub(super) async fn run(&mut self) {
|
||||
debug!("Started InputMessageListener with graceful shutdown support");
|
||||
|
||||
while !shutdown.is_shutdown() {
|
||||
while !self.task_client.is_shutdown() {
|
||||
tokio::select! {
|
||||
input_msg = self.input_receiver.recv() => match input_msg {
|
||||
Some(input_msg) => {
|
||||
@@ -178,12 +188,12 @@ where
|
||||
break;
|
||||
}
|
||||
},
|
||||
_ = shutdown.recv_with_delay() => {
|
||||
_ = self.task_client.recv() => {
|
||||
log::trace!("InputMessageListener: Received shutdown");
|
||||
}
|
||||
}
|
||||
}
|
||||
shutdown.recv_timeout().await;
|
||||
self.task_client.recv_timeout().await;
|
||||
log::debug!("InputMessageListener: Exiting");
|
||||
}
|
||||
}
|
||||
|
||||
+18
-27
@@ -24,6 +24,7 @@ use nym_sphinx::{
|
||||
Delay as SphinxDelay,
|
||||
};
|
||||
use nym_statistics_common::clients::ClientStatsSender;
|
||||
use nym_task::TaskClient;
|
||||
use rand::{CryptoRng, Rng};
|
||||
use std::{
|
||||
sync::{Arc, Weak},
|
||||
@@ -66,7 +67,7 @@ pub(crate) enum PacketDestination {
|
||||
|
||||
/// Structure representing a data `Fragment` that is on-route to the specified `Recipient`
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct PendingAcknowledgement {
|
||||
pub struct PendingAcknowledgement {
|
||||
message_chunk: Fragment,
|
||||
delay: SphinxDelay,
|
||||
destination: PacketDestination,
|
||||
@@ -216,6 +217,7 @@ where
|
||||
message_handler: MessageHandler<R>,
|
||||
reply_controller_sender: ReplyControllerSender,
|
||||
stats_tx: ClientStatsSender,
|
||||
task_client: TaskClient,
|
||||
) -> Self {
|
||||
let (retransmission_tx, retransmission_rx) = mpsc::unbounded();
|
||||
|
||||
@@ -225,6 +227,7 @@ where
|
||||
action_config,
|
||||
retransmission_tx,
|
||||
connectors.ack_action_receiver,
|
||||
task_client.fork("action_controller"),
|
||||
);
|
||||
|
||||
// will listen for any acks coming from the network
|
||||
@@ -233,6 +236,7 @@ where
|
||||
connectors.ack_receiver,
|
||||
connectors.ack_action_sender.clone(),
|
||||
stats_tx,
|
||||
task_client.fork("acknowledgement_listener"),
|
||||
);
|
||||
|
||||
// will listen for any new messages from the client
|
||||
@@ -240,6 +244,7 @@ where
|
||||
connectors.input_receiver,
|
||||
message_handler.clone(),
|
||||
reply_controller_sender.clone(),
|
||||
task_client.fork("input_message_listener"),
|
||||
);
|
||||
|
||||
// will listen for any ack timeouts and trigger retransmission
|
||||
@@ -249,12 +254,16 @@ where
|
||||
message_handler,
|
||||
retransmission_rx,
|
||||
reply_controller_sender,
|
||||
task_client.fork("retransmission_request_listener"),
|
||||
);
|
||||
|
||||
// will listen for events indicating the packet was sent through the network so that
|
||||
// the retransmission timer should be started.
|
||||
let sent_notification_listener =
|
||||
SentNotificationListener::new(connectors.sent_notifier, connectors.ack_action_sender);
|
||||
let sent_notification_listener = SentNotificationListener::new(
|
||||
connectors.sent_notifier,
|
||||
connectors.ack_action_sender,
|
||||
task_client.with_suffix("sent_notification_listener"),
|
||||
);
|
||||
|
||||
AcknowledgementController {
|
||||
acknowledgement_listener,
|
||||
@@ -265,53 +274,35 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn start_with_shutdown(
|
||||
self,
|
||||
shutdown: nym_task::TaskClient,
|
||||
packet_type: PacketType,
|
||||
) {
|
||||
pub(super) fn start(self, packet_type: PacketType) {
|
||||
let mut acknowledgement_listener = self.acknowledgement_listener;
|
||||
let mut input_message_listener = self.input_message_listener;
|
||||
let mut retransmission_request_listener = self.retransmission_request_listener;
|
||||
let mut sent_notification_listener = self.sent_notification_listener;
|
||||
let mut action_controller = self.action_controller;
|
||||
|
||||
let shutdown_handle = shutdown.fork("acknowledgement_listener");
|
||||
spawn_future(async move {
|
||||
acknowledgement_listener
|
||||
.run_with_shutdown(shutdown_handle)
|
||||
.await;
|
||||
acknowledgement_listener.run().await;
|
||||
debug!("The acknowledgement listener has finished execution!");
|
||||
});
|
||||
|
||||
let shutdown_handle = shutdown.fork("input_message_listener");
|
||||
spawn_future(async move {
|
||||
input_message_listener
|
||||
.run_with_shutdown(shutdown_handle)
|
||||
.await;
|
||||
input_message_listener.run().await;
|
||||
debug!("The input listener has finished execution!");
|
||||
});
|
||||
|
||||
let shutdown_handle = shutdown.fork("retransmission_request_listener");
|
||||
spawn_future(async move {
|
||||
retransmission_request_listener
|
||||
.run_with_shutdown(shutdown_handle, packet_type)
|
||||
.await;
|
||||
retransmission_request_listener.run(packet_type).await;
|
||||
debug!("The retransmission request listener has finished execution!");
|
||||
});
|
||||
|
||||
let shutdown_handle = shutdown.fork("sent_notification_listener");
|
||||
spawn_future(async move {
|
||||
sent_notification_listener
|
||||
.run_with_shutdown(shutdown_handle)
|
||||
.await;
|
||||
sent_notification_listener.run().await;
|
||||
debug!("The sent notification listener has finished execution!");
|
||||
});
|
||||
|
||||
spawn_future(async move {
|
||||
action_controller
|
||||
.run_with_shutdown(shutdown.with_suffix("action_controller"))
|
||||
.await;
|
||||
action_controller.run().await;
|
||||
debug!("The controller has finished execution!");
|
||||
});
|
||||
}
|
||||
|
||||
+32
-17
@@ -14,7 +14,7 @@ use log::*;
|
||||
use nym_sphinx::chunking::fragment::Fragment;
|
||||
use nym_sphinx::preparer::PreparedFragment;
|
||||
use nym_sphinx::{addressing::clients::Recipient, params::PacketType};
|
||||
use nym_task::connections::TransmissionLane;
|
||||
use nym_task::{connections::TransmissionLane, TaskClient};
|
||||
use rand::{CryptoRng, Rng};
|
||||
use std::sync::{Arc, Weak};
|
||||
|
||||
@@ -25,6 +25,7 @@ pub(super) struct RetransmissionRequestListener<R> {
|
||||
message_handler: MessageHandler<R>,
|
||||
request_receiver: RetransmissionRequestReceiver,
|
||||
reply_controller_sender: ReplyControllerSender,
|
||||
task_client: TaskClient,
|
||||
}
|
||||
|
||||
impl<R> RetransmissionRequestListener<R>
|
||||
@@ -37,6 +38,7 @@ where
|
||||
message_handler: MessageHandler<R>,
|
||||
request_receiver: RetransmissionRequestReceiver,
|
||||
reply_controller_sender: ReplyControllerSender,
|
||||
task_client: TaskClient,
|
||||
) -> Self {
|
||||
RetransmissionRequestListener {
|
||||
maximum_retransmissions,
|
||||
@@ -44,6 +46,7 @@ where
|
||||
message_handler,
|
||||
request_receiver,
|
||||
reply_controller_sender,
|
||||
task_client,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,9 +82,12 @@ where
|
||||
if let Some(limit) = self.maximum_retransmissions {
|
||||
if timed_out_ack.retransmissions >= limit {
|
||||
warn!("reached maximum number of allowed retransmissions for the packet");
|
||||
self.action_sender
|
||||
if let Err(err) = self
|
||||
.action_sender
|
||||
.unbounded_send(Action::new_remove(frag_id))
|
||||
.unwrap();
|
||||
{
|
||||
error!("Failed to send remove action to the controller: {err}");
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -93,11 +99,16 @@ where
|
||||
} => {
|
||||
// if this is retransmission for reply, offload it to the dedicated task
|
||||
// that deals with all the surbs
|
||||
return self.reply_controller_sender.send_retransmission_data(
|
||||
if let Err(err) = self.reply_controller_sender.send_retransmission_data(
|
||||
*recipient_tag,
|
||||
weak_timed_out_ack,
|
||||
*extra_surb_request,
|
||||
);
|
||||
) {
|
||||
if !self.task_client.is_shutdown_poll() {
|
||||
error!("Failed to send retransmission data to the reply controller: {err}");
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
PacketDestination::KnownRecipient(recipient) => {
|
||||
self.prepare_normal_retransmission_chunk(
|
||||
@@ -114,9 +125,12 @@ where
|
||||
Err(err) => {
|
||||
warn!("Could not retransmit the packet - {err}");
|
||||
// we NEED to start timer here otherwise we will have this guy permanently stuck in memory
|
||||
self.action_sender
|
||||
if let Err(err) = self
|
||||
.action_sender
|
||||
.unbounded_send(Action::new_start_timer(frag_id))
|
||||
.unwrap();
|
||||
{
|
||||
error!("Failed to send start timer action to the controller: {err}");
|
||||
}
|
||||
return;
|
||||
}
|
||||
};
|
||||
@@ -141,9 +155,14 @@ where
|
||||
// is sent to the `OutQueueControl` and has gone through its internal queue
|
||||
// with the additional poisson delay.
|
||||
// And since Actions are executed in order `UpdateTimer` will HAVE TO be executed before `StartTimer`
|
||||
self.action_sender
|
||||
if let Err(err) = self
|
||||
.action_sender
|
||||
.unbounded_send(Action::new_update_pending_ack(frag_id, new_delay))
|
||||
.unwrap();
|
||||
{
|
||||
if !self.task_client.is_shutdown_poll() {
|
||||
error!("Failed to send update pending ack action to the controller: {err}");
|
||||
}
|
||||
}
|
||||
|
||||
// send to `OutQueueControl` to eventually send to the mix network
|
||||
self.message_handler
|
||||
@@ -157,14 +176,10 @@ where
|
||||
.await
|
||||
}
|
||||
|
||||
pub(super) async fn run_with_shutdown(
|
||||
&mut self,
|
||||
mut shutdown: nym_task::TaskClient,
|
||||
packet_type: PacketType,
|
||||
) {
|
||||
pub(super) async fn run(&mut self, packet_type: PacketType) {
|
||||
debug!("Started RetransmissionRequestListener with graceful shutdown support");
|
||||
|
||||
while !shutdown.is_shutdown() {
|
||||
while !self.task_client.is_shutdown() {
|
||||
tokio::select! {
|
||||
timed_out_ack = self.request_receiver.next() => match timed_out_ack {
|
||||
Some(timed_out_ack) => self.on_retransmission_request(timed_out_ack, packet_type).await,
|
||||
@@ -173,12 +188,12 @@ where
|
||||
break;
|
||||
}
|
||||
},
|
||||
_ = shutdown.recv() => {
|
||||
_ = self.task_client.recv() => {
|
||||
log::trace!("RetransmissionRequestListener: Received shutdown");
|
||||
}
|
||||
}
|
||||
}
|
||||
shutdown.recv_timeout().await;
|
||||
self.task_client.recv_timeout().await;
|
||||
log::debug!("RetransmissionRequestListener: Exiting");
|
||||
}
|
||||
}
|
||||
|
||||
+15
-6
@@ -6,6 +6,7 @@ use super::SentPacketNotificationReceiver;
|
||||
use futures::StreamExt;
|
||||
use log::*;
|
||||
use nym_sphinx::chunking::fragment::{FragmentIdentifier, COVER_FRAG_ID};
|
||||
use nym_task::TaskClient;
|
||||
|
||||
/// Module responsible for starting up retransmission timers.
|
||||
/// It is required because when we send our packet to the `real traffic stream` controlled
|
||||
@@ -14,16 +15,19 @@ use nym_sphinx::chunking::fragment::{FragmentIdentifier, COVER_FRAG_ID};
|
||||
pub(super) struct SentNotificationListener {
|
||||
sent_notifier: SentPacketNotificationReceiver,
|
||||
action_sender: AckActionSender,
|
||||
task_client: TaskClient,
|
||||
}
|
||||
|
||||
impl SentNotificationListener {
|
||||
pub(super) fn new(
|
||||
sent_notifier: SentPacketNotificationReceiver,
|
||||
action_sender: AckActionSender,
|
||||
task_client: TaskClient,
|
||||
) -> Self {
|
||||
SentNotificationListener {
|
||||
sent_notifier,
|
||||
action_sender,
|
||||
task_client,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,15 +36,20 @@ impl SentNotificationListener {
|
||||
trace!("sent off a cover message - no need to start retransmission timer!");
|
||||
return;
|
||||
}
|
||||
self.action_sender
|
||||
if let Err(err) = self
|
||||
.action_sender
|
||||
.unbounded_send(Action::new_start_timer(frag_id))
|
||||
.unwrap();
|
||||
{
|
||||
if !self.task_client.is_shutdown_poll() {
|
||||
error!("Failed to send start timer action to action controller: {err}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) async fn run_with_shutdown(&mut self, mut shutdown: nym_task::TaskClient) {
|
||||
pub(super) async fn run(&mut self) {
|
||||
debug!("Started SentNotificationListener with graceful shutdown support");
|
||||
|
||||
loop {
|
||||
while !self.task_client.is_shutdown() {
|
||||
tokio::select! {
|
||||
frag_id = self.sent_notifier.next() => match frag_id {
|
||||
Some(frag_id) => {
|
||||
@@ -51,13 +60,13 @@ impl SentNotificationListener {
|
||||
break;
|
||||
}
|
||||
},
|
||||
_ = shutdown.recv_with_delay() => {
|
||||
_ = self.task_client.recv() => {
|
||||
log::trace!("SentNotificationListener: Received shutdown");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
assert!(shutdown.is_shutdown_poll());
|
||||
assert!(self.task_client.is_shutdown_poll());
|
||||
log::debug!("SentNotificationListener: Exiting");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ use nym_sphinx::params::{PacketSize, PacketType};
|
||||
use nym_sphinx::preparer::{MessagePreparer, PreparedFragment};
|
||||
use nym_sphinx::Delay;
|
||||
use nym_task::connections::TransmissionLane;
|
||||
use nym_task::TaskClient;
|
||||
use nym_topology::{NymRouteProvider, NymTopologyError};
|
||||
use rand::{CryptoRng, Rng};
|
||||
use std::collections::HashMap;
|
||||
@@ -149,12 +150,14 @@ pub(crate) struct MessageHandler<R> {
|
||||
topology_access: TopologyAccessor,
|
||||
reply_key_storage: SentReplyKeys,
|
||||
tag_storage: UsedSenderTags,
|
||||
task_client: TaskClient,
|
||||
}
|
||||
|
||||
impl<R> MessageHandler<R>
|
||||
where
|
||||
R: CryptoRng + Rng,
|
||||
{
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub(crate) fn new(
|
||||
config: Config,
|
||||
rng: R,
|
||||
@@ -163,6 +166,7 @@ where
|
||||
topology_access: TopologyAccessor,
|
||||
reply_key_storage: SentReplyKeys,
|
||||
tag_storage: UsedSenderTags,
|
||||
task_client: TaskClient,
|
||||
) -> Self
|
||||
where
|
||||
R: Copy,
|
||||
@@ -183,6 +187,7 @@ where
|
||||
topology_access,
|
||||
reply_key_storage,
|
||||
tag_storage,
|
||||
task_client,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -609,15 +614,25 @@ where
|
||||
}
|
||||
|
||||
pub(crate) fn update_ack_delay(&self, id: FragmentIdentifier, new_delay: Delay) {
|
||||
self.action_sender
|
||||
if let Err(err) = self
|
||||
.action_sender
|
||||
.unbounded_send(Action::UpdatePendingAck(id, new_delay))
|
||||
.expect("action control task has died")
|
||||
{
|
||||
if !self.task_client.is_shutdown_poll() {
|
||||
error!("Failed to send update action to the controller: {err}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn insert_pending_acks(&self, pending_acks: Vec<PendingAcknowledgement>) {
|
||||
self.action_sender
|
||||
if let Err(err) = self
|
||||
.action_sender
|
||||
.unbounded_send(Action::new_insert(pending_acks))
|
||||
.expect("action control task has died")
|
||||
{
|
||||
if !self.task_client.is_shutdown_poll() {
|
||||
error!("Failed to send insert action to the controller: {err}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// tells real message sender (with the poisson timer) to send this to the mix network
|
||||
@@ -631,9 +646,9 @@ where
|
||||
.send((messages, transmission_lane))
|
||||
.await
|
||||
{
|
||||
error!(
|
||||
"Failed to forward messages to the real message sender (OutQueueControl): {err}"
|
||||
);
|
||||
if !self.task_client.is_shutdown_poll() {
|
||||
error!("Failed to forward messages to the real message sender: {err}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ use nym_sphinx::addressing::clients::Recipient;
|
||||
use nym_sphinx::params::PacketType;
|
||||
use nym_statistics_common::clients::ClientStatsSender;
|
||||
use nym_task::connections::{ConnectionCommandReceiver, LaneQueueLengths};
|
||||
use nym_task::TaskClient;
|
||||
use rand::{rngs::OsRng, CryptoRng, Rng};
|
||||
use std::sync::Arc;
|
||||
|
||||
@@ -147,6 +148,7 @@ impl RealMessagesController<OsRng> {
|
||||
lane_queue_lengths: LaneQueueLengths,
|
||||
client_connection_rx: ConnectionCommandReceiver,
|
||||
stats_tx: ClientStatsSender,
|
||||
task_client: TaskClient,
|
||||
) -> Self {
|
||||
let rng = OsRng;
|
||||
|
||||
@@ -177,6 +179,7 @@ impl RealMessagesController<OsRng> {
|
||||
topology_access.clone(),
|
||||
reply_storage.key_storage(),
|
||||
reply_storage.tags_storage(),
|
||||
task_client.fork("message_handler"),
|
||||
);
|
||||
|
||||
let ack_control = AcknowledgementController::new(
|
||||
@@ -186,6 +189,7 @@ impl RealMessagesController<OsRng> {
|
||||
message_handler.clone(),
|
||||
reply_controller_sender,
|
||||
stats_tx.clone(),
|
||||
task_client.fork("ack_control"),
|
||||
);
|
||||
|
||||
let reply_control = ReplyController::new(
|
||||
@@ -193,6 +197,7 @@ impl RealMessagesController<OsRng> {
|
||||
message_handler,
|
||||
reply_storage,
|
||||
reply_controller_receiver,
|
||||
task_client.fork("reply_controller"),
|
||||
);
|
||||
|
||||
let out_queue_control = OutQueueControl::new(
|
||||
@@ -205,6 +210,7 @@ impl RealMessagesController<OsRng> {
|
||||
lane_queue_lengths,
|
||||
client_connection_rx,
|
||||
stats_tx,
|
||||
task_client.with_suffix("out_queue_control"),
|
||||
);
|
||||
|
||||
RealMessagesController {
|
||||
@@ -214,22 +220,20 @@ impl RealMessagesController<OsRng> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn start_with_shutdown(self, shutdown: nym_task::TaskClient, packet_type: PacketType) {
|
||||
pub fn start(self, packet_type: PacketType) {
|
||||
let mut out_queue_control = self.out_queue_control;
|
||||
let ack_control = self.ack_control;
|
||||
let mut reply_control = self.reply_control;
|
||||
|
||||
let shutdown_handle = shutdown.fork("out_queue_control");
|
||||
spawn_future(async move {
|
||||
out_queue_control.run_with_shutdown(shutdown_handle).await;
|
||||
out_queue_control.run().await;
|
||||
debug!("The out queue controller has finished execution!");
|
||||
});
|
||||
let shutdown_handle = shutdown.fork("reply_control");
|
||||
spawn_future(async move {
|
||||
reply_control.run_with_shutdown(shutdown_handle).await;
|
||||
reply_control.run().await;
|
||||
debug!("The reply controller has finished execution!");
|
||||
});
|
||||
|
||||
ack_control.start_with_shutdown(shutdown.with_suffix("ack_control"), packet_type);
|
||||
ack_control.start(packet_type);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ use nym_statistics_common::clients::{packet_statistics::PacketStatisticsEvent, C
|
||||
use nym_task::connections::{
|
||||
ConnectionCommand, ConnectionCommandReceiver, ConnectionId, LaneQueueLengths, TransmissionLane,
|
||||
};
|
||||
use nym_task::TaskClient;
|
||||
use rand::{CryptoRng, Rng};
|
||||
use std::pin::Pin;
|
||||
use std::sync::Arc;
|
||||
@@ -117,6 +118,8 @@ where
|
||||
|
||||
/// Channel used for sending metrics events (specifically `PacketStatistics` events) to the metrics tracker.
|
||||
stats_tx: ClientStatsSender,
|
||||
|
||||
task_client: TaskClient,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -176,6 +179,7 @@ where
|
||||
lane_queue_lengths: LaneQueueLengths,
|
||||
client_connection_rx: ConnectionCommandReceiver,
|
||||
stats_tx: ClientStatsSender,
|
||||
task_client: TaskClient,
|
||||
) -> Self {
|
||||
OutQueueControl {
|
||||
config,
|
||||
@@ -190,6 +194,7 @@ where
|
||||
client_connection_rx,
|
||||
lane_queue_lengths,
|
||||
stats_tx,
|
||||
task_client,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -198,7 +203,9 @@ where
|
||||
// queues and client load rather than the required delay. So realistically we can treat
|
||||
// whatever is about to happen as negligible additional delay.
|
||||
trace!("{} is about to get sent to the mixnet", frag_id);
|
||||
self.sent_notifier.unbounded_send(frag_id).unwrap();
|
||||
if let Err(err) = self.sent_notifier.unbounded_send(frag_id) {
|
||||
error!("Failed to notify about sent message: {err}");
|
||||
}
|
||||
}
|
||||
|
||||
fn loop_cover_message_size(&mut self) -> PacketSize {
|
||||
@@ -271,7 +278,9 @@ where
|
||||
};
|
||||
|
||||
if let Err(err) = self.mix_tx.send(vec![next_message]).await {
|
||||
log::error!("Failed to send: {err}");
|
||||
if !self.task_client.is_shutdown_poll() {
|
||||
log::error!("Failed to send: {err}");
|
||||
}
|
||||
} else {
|
||||
let event = if fragment_id.is_some() {
|
||||
PacketStatisticsEvent::RealPacketSent(packet_size)
|
||||
@@ -504,7 +513,7 @@ where
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
fn log_status(&self, shutdown: &mut nym_task::TaskClient) {
|
||||
fn log_status(&self, shutdown: &mut TaskClient) {
|
||||
use crate::error::ClientCoreStatusMessage;
|
||||
|
||||
let packets = self.transmission_buffer.total_size();
|
||||
@@ -535,14 +544,16 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) async fn run_with_shutdown(&mut self, mut shutdown: nym_task::TaskClient) {
|
||||
pub(super) async fn run(&mut self) {
|
||||
debug!("Started OutQueueControl with graceful shutdown support");
|
||||
|
||||
let mut shutdown = self.task_client.fork("select");
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
{
|
||||
let mut status_timer = tokio::time::interval(Duration::from_secs(5));
|
||||
|
||||
loop {
|
||||
while !shutdown.is_shutdown() {
|
||||
tokio::select! {
|
||||
biased;
|
||||
_ = shutdown.recv() => {
|
||||
|
||||
@@ -20,6 +20,7 @@ use nym_sphinx::message::{NymMessage, PlainMessage};
|
||||
use nym_sphinx::params::ReplySurbKeyDigestAlgorithm;
|
||||
use nym_sphinx::receiver::{MessageReceiver, MessageRecoveryError, ReconstructedMessage};
|
||||
use nym_statistics_common::clients::{packet_statistics::PacketStatisticsEvent, ClientStatsSender};
|
||||
use nym_task::TaskClient;
|
||||
use std::collections::HashSet;
|
||||
use std::sync::Arc;
|
||||
|
||||
@@ -152,6 +153,7 @@ struct ReceivedMessagesBuffer<R: MessageReceiver> {
|
||||
inner: Arc<Mutex<ReceivedMessagesBufferInner<R>>>,
|
||||
reply_key_storage: SentReplyKeys,
|
||||
reply_controller_sender: ReplyControllerSender,
|
||||
task_client: TaskClient,
|
||||
}
|
||||
|
||||
impl<R: MessageReceiver> ReceivedMessagesBuffer<R> {
|
||||
@@ -160,6 +162,7 @@ impl<R: MessageReceiver> ReceivedMessagesBuffer<R> {
|
||||
reply_key_storage: SentReplyKeys,
|
||||
reply_controller_sender: ReplyControllerSender,
|
||||
stats_tx: ClientStatsSender,
|
||||
task_client: TaskClient,
|
||||
) -> Self {
|
||||
ReceivedMessagesBuffer {
|
||||
inner: Arc::new(Mutex::new(ReceivedMessagesBufferInner {
|
||||
@@ -172,6 +175,7 @@ impl<R: MessageReceiver> ReceivedMessagesBuffer<R> {
|
||||
})),
|
||||
reply_key_storage,
|
||||
reply_controller_sender,
|
||||
task_client,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -257,11 +261,15 @@ impl<R: MessageReceiver> ReceivedMessagesBuffer<R> {
|
||||
}
|
||||
};
|
||||
|
||||
self.reply_controller_sender.send_additional_surbs(
|
||||
if let Err(err) = self.reply_controller_sender.send_additional_surbs(
|
||||
msg.sender_tag,
|
||||
reply_surbs,
|
||||
from_surb_request,
|
||||
)
|
||||
) {
|
||||
if !self.task_client.is_shutdown_poll() {
|
||||
error!("{err}");
|
||||
}
|
||||
}
|
||||
}
|
||||
reconstructed
|
||||
}
|
||||
@@ -276,8 +284,14 @@ impl<R: MessageReceiver> ReceivedMessagesBuffer<R> {
|
||||
ReplyMessageContent::Data { message } => reconstructed.push(message.into()),
|
||||
ReplyMessageContent::SurbRequest { recipient, amount } => {
|
||||
debug!("received request for {amount} additional reply SURBs from {recipient}");
|
||||
self.reply_controller_sender
|
||||
.send_additional_surbs_request(*recipient, amount);
|
||||
if let Err(err) = self
|
||||
.reply_controller_sender
|
||||
.send_additional_surbs_request(*recipient, amount)
|
||||
{
|
||||
if !self.task_client.is_shutdown_poll() {
|
||||
error!("{err}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -399,16 +413,19 @@ pub enum ReceivedBufferMessage {
|
||||
struct RequestReceiver<R: MessageReceiver> {
|
||||
received_buffer: ReceivedMessagesBuffer<R>,
|
||||
query_receiver: ReceivedBufferRequestReceiver,
|
||||
task_client: TaskClient,
|
||||
}
|
||||
|
||||
impl<R: MessageReceiver> RequestReceiver<R> {
|
||||
fn new(
|
||||
received_buffer: ReceivedMessagesBuffer<R>,
|
||||
query_receiver: ReceivedBufferRequestReceiver,
|
||||
task_client: TaskClient,
|
||||
) -> Self {
|
||||
RequestReceiver {
|
||||
received_buffer,
|
||||
query_receiver,
|
||||
task_client,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -423,12 +440,12 @@ impl<R: MessageReceiver> RequestReceiver<R> {
|
||||
}
|
||||
}
|
||||
|
||||
async fn run_with_shutdown(&mut self, mut shutdown: nym_task::TaskClient) {
|
||||
async fn run(&mut self) {
|
||||
debug!("Started RequestReceiver with graceful shutdown support");
|
||||
while !shutdown.is_shutdown() {
|
||||
while !self.task_client.is_shutdown() {
|
||||
tokio::select! {
|
||||
biased;
|
||||
_ = shutdown.recv_with_delay() => {
|
||||
_ = self.task_client.recv() => {
|
||||
log::trace!("RequestReceiver: Received shutdown");
|
||||
}
|
||||
request = self.query_receiver.next() => {
|
||||
@@ -441,7 +458,7 @@ impl<R: MessageReceiver> RequestReceiver<R> {
|
||||
},
|
||||
}
|
||||
}
|
||||
shutdown.recv_timeout().await;
|
||||
self.task_client.recv().await;
|
||||
log::debug!("RequestReceiver: Exiting");
|
||||
}
|
||||
}
|
||||
@@ -449,25 +466,25 @@ impl<R: MessageReceiver> RequestReceiver<R> {
|
||||
struct FragmentedMessageReceiver<R: MessageReceiver> {
|
||||
received_buffer: ReceivedMessagesBuffer<R>,
|
||||
mixnet_packet_receiver: MixnetMessageReceiver,
|
||||
task_client: TaskClient,
|
||||
}
|
||||
|
||||
impl<R: MessageReceiver> FragmentedMessageReceiver<R> {
|
||||
fn new(
|
||||
received_buffer: ReceivedMessagesBuffer<R>,
|
||||
mixnet_packet_receiver: MixnetMessageReceiver,
|
||||
task_client: TaskClient,
|
||||
) -> Self {
|
||||
FragmentedMessageReceiver {
|
||||
received_buffer,
|
||||
mixnet_packet_receiver,
|
||||
task_client,
|
||||
}
|
||||
}
|
||||
|
||||
async fn run_with_shutdown(
|
||||
&mut self,
|
||||
mut shutdown: nym_task::TaskClient,
|
||||
) -> Result<(), MessageRecoveryError> {
|
||||
async fn run(&mut self) -> Result<(), MessageRecoveryError> {
|
||||
debug!("Started FragmentedMessageReceiver with graceful shutdown support");
|
||||
while !shutdown.is_shutdown() {
|
||||
while !self.task_client.is_shutdown() {
|
||||
tokio::select! {
|
||||
new_messages = self.mixnet_packet_receiver.next() => {
|
||||
if let Some(new_messages) = new_messages {
|
||||
@@ -477,12 +494,12 @@ impl<R: MessageReceiver> FragmentedMessageReceiver<R> {
|
||||
break;
|
||||
}
|
||||
},
|
||||
_ = shutdown.recv_with_delay() => {
|
||||
_ = self.task_client.recv_with_delay() => {
|
||||
log::trace!("FragmentedMessageReceiver: Received shutdown");
|
||||
}
|
||||
}
|
||||
}
|
||||
shutdown.recv_timeout().await;
|
||||
self.task_client.recv_timeout().await;
|
||||
log::debug!("FragmentedMessageReceiver: Exiting");
|
||||
Ok(())
|
||||
}
|
||||
@@ -501,41 +518,42 @@ impl<R: MessageReceiver + Clone + Send + 'static> ReceivedMessagesBufferControll
|
||||
reply_key_storage: SentReplyKeys,
|
||||
reply_controller_sender: ReplyControllerSender,
|
||||
metrics_reporter: ClientStatsSender,
|
||||
task_client: TaskClient,
|
||||
) -> Self {
|
||||
let received_buffer = ReceivedMessagesBuffer::new(
|
||||
local_encryption_keypair,
|
||||
reply_key_storage,
|
||||
reply_controller_sender,
|
||||
metrics_reporter,
|
||||
task_client.fork("received_messages_buffer"),
|
||||
);
|
||||
|
||||
ReceivedMessagesBufferController {
|
||||
fragmented_message_receiver: FragmentedMessageReceiver::new(
|
||||
received_buffer.clone(),
|
||||
mixnet_packet_receiver,
|
||||
task_client.fork("fragmented_message_receiver"),
|
||||
),
|
||||
request_receiver: RequestReceiver::new(
|
||||
received_buffer,
|
||||
query_receiver,
|
||||
task_client.with_suffix("request_receiver"),
|
||||
),
|
||||
request_receiver: RequestReceiver::new(received_buffer, query_receiver),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn start_with_shutdown(self, shutdown: nym_task::TaskClient) {
|
||||
pub fn start(self) {
|
||||
let mut fragmented_message_receiver = self.fragmented_message_receiver;
|
||||
let mut request_receiver = self.request_receiver;
|
||||
|
||||
let shutdown_handle = shutdown.fork("fragmented_message_receiver");
|
||||
spawn_future(async move {
|
||||
match fragmented_message_receiver
|
||||
.run_with_shutdown(shutdown_handle)
|
||||
.await
|
||||
{
|
||||
match fragmented_message_receiver.run().await {
|
||||
Ok(_) => {}
|
||||
Err(e) => error!("{e}"),
|
||||
}
|
||||
});
|
||||
spawn_future(async move {
|
||||
request_receiver
|
||||
.run_with_shutdown(shutdown.with_suffix("request_receiver"))
|
||||
.await;
|
||||
request_receiver.run().await;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ use nym_sphinx::anonymous_replies::requests::AnonymousSenderTag;
|
||||
use nym_sphinx::anonymous_replies::ReplySurb;
|
||||
use nym_sphinx::chunking::fragment::{Fragment, FragmentIdentifier};
|
||||
use nym_task::connections::{ConnectionId, TransmissionLane};
|
||||
use nym_task::TaskClient;
|
||||
use rand::{CryptoRng, Rng};
|
||||
use std::cmp::{max, min};
|
||||
use std::collections::btree_map::Entry;
|
||||
@@ -68,6 +69,9 @@ pub struct ReplyController<R> {
|
||||
|
||||
message_handler: MessageHandler<R>,
|
||||
full_reply_storage: CombinedReplyStorage,
|
||||
|
||||
// Listen for shutdown signals
|
||||
task_client: TaskClient,
|
||||
}
|
||||
|
||||
impl<R> ReplyController<R>
|
||||
@@ -79,6 +83,7 @@ where
|
||||
message_handler: MessageHandler<R>,
|
||||
full_reply_storage: CombinedReplyStorage,
|
||||
request_receiver: ReplyControllerReceiver,
|
||||
task_client: TaskClient,
|
||||
) -> Self {
|
||||
ReplyController {
|
||||
config,
|
||||
@@ -87,6 +92,7 @@ where
|
||||
pending_retransmissions: HashMap::new(),
|
||||
message_handler,
|
||||
full_reply_storage,
|
||||
task_client,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -846,9 +852,11 @@ where
|
||||
// todo!()
|
||||
// }
|
||||
|
||||
pub(crate) async fn run_with_shutdown(&mut self, mut shutdown: nym_task::TaskClient) {
|
||||
pub(crate) async fn run(&mut self) {
|
||||
debug!("Started ReplyController with graceful shutdown support");
|
||||
|
||||
let mut shutdown = self.task_client.fork("select");
|
||||
|
||||
let polling_rate = Duration::from_secs(5);
|
||||
let mut stale_inspection = new_interval_stream(polling_rate);
|
||||
|
||||
@@ -860,7 +868,7 @@ where
|
||||
while !shutdown.is_shutdown() {
|
||||
tokio::select! {
|
||||
biased;
|
||||
_ = shutdown.recv_with_delay() => {
|
||||
_ = shutdown.recv() => {
|
||||
log::trace!("ReplyController: Received shutdown");
|
||||
},
|
||||
req = self.request_receiver.next() => match req {
|
||||
|
||||
@@ -15,6 +15,27 @@ pub(crate) fn new_control_channels() -> (ReplyControllerSender, ReplyControllerR
|
||||
(tx.into(), rx)
|
||||
}
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum ReplyControllerSenderError {
|
||||
#[error("failed to send retransmission data to reply controller")]
|
||||
SendRetransmissionData(#[source] mpsc::TrySendError<ReplyControllerMessage>),
|
||||
|
||||
#[error("failed to send reply to reply controller")]
|
||||
SendReply(#[source] mpsc::TrySendError<ReplyControllerMessage>),
|
||||
|
||||
#[error("failed to send additional surbs to reply controller")]
|
||||
AdditionalSurbs(#[source] mpsc::TrySendError<ReplyControllerMessage>),
|
||||
|
||||
#[error("failed to send additional surbs request to reply controller")]
|
||||
AdditionalSurbsRequest(#[source] mpsc::TrySendError<ReplyControllerMessage>),
|
||||
|
||||
#[error("failed to request lane queue length from reply controller")]
|
||||
LaneQueueLength(#[source] mpsc::TrySendError<ReplyControllerMessage>),
|
||||
|
||||
#[error("response channel was dropped before we could receive the response")]
|
||||
ResponseChannelDropped(#[source] oneshot::Canceled),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ReplyControllerSender(mpsc::UnboundedSender<ReplyControllerMessage>);
|
||||
|
||||
@@ -30,14 +51,14 @@ impl ReplyControllerSender {
|
||||
recipient: AnonymousSenderTag,
|
||||
timed_out_ack: Weak<PendingAcknowledgement>,
|
||||
extra_surb_request: bool,
|
||||
) {
|
||||
) -> Result<(), ReplyControllerSenderError> {
|
||||
self.0
|
||||
.unbounded_send(ReplyControllerMessage::RetransmitReply {
|
||||
recipient,
|
||||
timed_out_ack,
|
||||
extra_surb_request,
|
||||
})
|
||||
.expect("ReplyControllerReceiver has died!")
|
||||
.map_err(ReplyControllerSenderError::SendRetransmissionData)
|
||||
}
|
||||
|
||||
pub(crate) fn send_reply(
|
||||
@@ -45,14 +66,14 @@ impl ReplyControllerSender {
|
||||
recipient: AnonymousSenderTag,
|
||||
message: Vec<u8>,
|
||||
lane: TransmissionLane,
|
||||
) {
|
||||
) -> Result<(), ReplyControllerSenderError> {
|
||||
self.0
|
||||
.unbounded_send(ReplyControllerMessage::SendReply {
|
||||
recipient,
|
||||
message,
|
||||
lane,
|
||||
})
|
||||
.expect("ReplyControllerReceiver has died!")
|
||||
.map_err(ReplyControllerSenderError::SendReply)
|
||||
}
|
||||
|
||||
pub(crate) fn send_additional_surbs(
|
||||
@@ -60,42 +81,47 @@ impl ReplyControllerSender {
|
||||
sender_tag: AnonymousSenderTag,
|
||||
reply_surbs: Vec<ReplySurb>,
|
||||
from_surb_request: bool,
|
||||
) {
|
||||
) -> Result<(), ReplyControllerSenderError> {
|
||||
self.0
|
||||
.unbounded_send(ReplyControllerMessage::AdditionalSurbs {
|
||||
sender_tag,
|
||||
reply_surbs,
|
||||
from_surb_request,
|
||||
})
|
||||
.expect("ReplyControllerReceiver has died!")
|
||||
.map_err(ReplyControllerSenderError::AdditionalSurbs)
|
||||
}
|
||||
|
||||
pub(crate) fn send_additional_surbs_request(&self, recipient: Recipient, amount: u32) {
|
||||
pub(crate) fn send_additional_surbs_request(
|
||||
&self,
|
||||
recipient: Recipient,
|
||||
amount: u32,
|
||||
) -> Result<(), ReplyControllerSenderError> {
|
||||
self.0
|
||||
.unbounded_send(ReplyControllerMessage::AdditionalSurbsRequest {
|
||||
recipient: Box::new(recipient),
|
||||
amount,
|
||||
})
|
||||
.expect("ReplyControllerReceiver has died!")
|
||||
.map_err(ReplyControllerSenderError::AdditionalSurbsRequest)
|
||||
}
|
||||
|
||||
pub async fn get_lane_queue_length(&self, connection_id: ConnectionId) -> usize {
|
||||
pub async fn get_lane_queue_length(
|
||||
&self,
|
||||
connection_id: ConnectionId,
|
||||
) -> Result<usize, ReplyControllerSenderError> {
|
||||
let (response_tx, response_rx) = oneshot::channel();
|
||||
self.0
|
||||
if let Err(err) = self
|
||||
.0
|
||||
.unbounded_send(ReplyControllerMessage::LaneQueueLength {
|
||||
connection_id,
|
||||
response_channel: response_tx,
|
||||
})
|
||||
.expect("ReplyControllerReceiver has died!");
|
||||
|
||||
match response_rx.await {
|
||||
Ok(length) => length,
|
||||
Err(_) => {
|
||||
error!("The reply controller has dropped our response channel!");
|
||||
// TODO: should we panic here instead? this message implies something weird and unrecoverable has happened
|
||||
0
|
||||
}
|
||||
{
|
||||
return Err(ReplyControllerSenderError::LaneQueueLength(err));
|
||||
}
|
||||
|
||||
response_rx
|
||||
.await
|
||||
.map_err(ReplyControllerSenderError::ResponseChannelDropped)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,7 +136,10 @@ impl ReplyQueueLengths {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get_lane_queue_length(&self, connection_id: ConnectionId) -> usize {
|
||||
pub async fn get_lane_queue_length(
|
||||
&self,
|
||||
connection_id: ConnectionId,
|
||||
) -> Result<usize, ReplyControllerSenderError> {
|
||||
self.reply_controller_sender
|
||||
.get_lane_queue_length(connection_id)
|
||||
.await
|
||||
@@ -120,7 +149,7 @@ impl ReplyQueueLengths {
|
||||
pub(crate) type ReplyControllerReceiver = mpsc::UnboundedReceiver<ReplyControllerMessage>;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) enum ReplyControllerMessage {
|
||||
pub enum ReplyControllerMessage {
|
||||
RetransmitReply {
|
||||
recipient: AnonymousSenderTag,
|
||||
timed_out_ack: Weak<PendingAcknowledgement>,
|
||||
|
||||
@@ -22,7 +22,7 @@ use nym_sphinx::addressing::Recipient;
|
||||
use nym_statistics_common::clients::{
|
||||
ClientStatsController, ClientStatsReceiver, ClientStatsSender,
|
||||
};
|
||||
use nym_task::connections::TransmissionLane;
|
||||
use nym_task::{connections::TransmissionLane, TaskClient};
|
||||
use std::time::Duration;
|
||||
|
||||
use crate::{
|
||||
@@ -51,6 +51,9 @@ pub(crate) struct StatisticsControl {
|
||||
|
||||
/// Config for stats reporting (enabled, address, interval)
|
||||
reporting_config: StatsReporting,
|
||||
|
||||
/// Task client for listening for shutdown
|
||||
task_client: TaskClient,
|
||||
}
|
||||
|
||||
impl StatisticsControl {
|
||||
@@ -59,19 +62,24 @@ impl StatisticsControl {
|
||||
client_type: String,
|
||||
client_stats_id: String,
|
||||
report_tx: InputMessageSender,
|
||||
task_client: TaskClient,
|
||||
) -> (Self, ClientStatsSender) {
|
||||
let (stats_tx, stats_rx) = tokio::sync::mpsc::unbounded_channel();
|
||||
|
||||
let stats = ClientStatsController::new(client_stats_id, client_type);
|
||||
|
||||
let mut task_client_stats_sender = task_client.fork("stats_sender");
|
||||
task_client_stats_sender.disarm();
|
||||
|
||||
(
|
||||
StatisticsControl {
|
||||
stats,
|
||||
stats_rx,
|
||||
report_tx,
|
||||
reporting_config,
|
||||
task_client,
|
||||
},
|
||||
ClientStatsSender::new(Some(stats_tx)),
|
||||
ClientStatsSender::new(Some(stats_tx), task_client_stats_sender),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -91,7 +99,7 @@ impl StatisticsControl {
|
||||
}
|
||||
}
|
||||
|
||||
async fn run_with_shutdown(&mut self, mut task_client: nym_task::TaskClient) {
|
||||
async fn run(&mut self) {
|
||||
log::debug!("Started StatisticsControl with graceful shutdown support");
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
@@ -121,10 +129,10 @@ impl StatisticsControl {
|
||||
let mut snapshot_interval =
|
||||
gloo_timers::future::IntervalStream::new(SNAPSHOT_INTERVAL.as_millis() as u32);
|
||||
|
||||
loop {
|
||||
while !self.task_client.is_shutdown() {
|
||||
tokio::select! {
|
||||
biased;
|
||||
_ = task_client.recv() => {
|
||||
_ = self.task_client.recv() => {
|
||||
log::trace!("StatisticsControl: Received shutdown");
|
||||
break;
|
||||
},
|
||||
@@ -149,29 +157,34 @@ impl StatisticsControl {
|
||||
}
|
||||
|
||||
_ = local_report_interval.next() => {
|
||||
self.stats.local_report(&mut task_client);
|
||||
self.stats.local_report(&mut self.task_client);
|
||||
}
|
||||
}
|
||||
}
|
||||
log::debug!("StatisticsControl: Exiting");
|
||||
}
|
||||
|
||||
pub(crate) fn start_with_shutdown(mut self, task_client: nym_task::TaskClient) {
|
||||
pub(crate) fn start(mut self) {
|
||||
spawn_future(async move {
|
||||
self.run_with_shutdown(task_client).await;
|
||||
self.run().await;
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn create_and_start_with_shutdown(
|
||||
pub(crate) fn create_and_start(
|
||||
reporting_config: StatsReporting,
|
||||
client_type: String,
|
||||
client_stats_id: String,
|
||||
report_tx: InputMessageSender,
|
||||
task_client: nym_task::TaskClient,
|
||||
task_client: TaskClient,
|
||||
) -> ClientStatsSender {
|
||||
let (controller, sender) =
|
||||
Self::create(reporting_config, client_type, client_stats_id, report_tx);
|
||||
controller.start_with_shutdown(task_client);
|
||||
let (controller, sender) = Self::create(
|
||||
reporting_config,
|
||||
client_type,
|
||||
client_stats_id,
|
||||
report_tx,
|
||||
task_client,
|
||||
);
|
||||
controller.start();
|
||||
sender
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ pub(crate) use accessor::{TopologyAccessor, TopologyReadPermit};
|
||||
use futures::StreamExt;
|
||||
use log::*;
|
||||
use nym_sphinx::addressing::nodes::NodeIdentity;
|
||||
use nym_task::TaskClient;
|
||||
use nym_topology::NymTopologyError;
|
||||
use std::time::Duration;
|
||||
|
||||
@@ -43,6 +44,8 @@ pub struct TopologyRefresher {
|
||||
|
||||
refresh_rate: Duration,
|
||||
consecutive_failure_count: usize,
|
||||
|
||||
task_client: TaskClient,
|
||||
}
|
||||
|
||||
impl TopologyRefresher {
|
||||
@@ -50,12 +53,14 @@ impl TopologyRefresher {
|
||||
cfg: TopologyRefresherConfig,
|
||||
topology_accessor: TopologyAccessor,
|
||||
topology_provider: Box<dyn TopologyProvider + Send + Sync>,
|
||||
task_client: TaskClient,
|
||||
) -> Self {
|
||||
TopologyRefresher {
|
||||
topology_provider,
|
||||
topology_accessor,
|
||||
refresh_rate: cfg.refresh_rate,
|
||||
consecutive_failure_count: 0,
|
||||
task_client,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,7 +147,7 @@ impl TopologyRefresher {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn start_with_shutdown(mut self, mut shutdown: nym_task::TaskClient) {
|
||||
pub fn start(mut self) {
|
||||
spawn_future(async move {
|
||||
debug!("Started TopologyRefresher with graceful shutdown support");
|
||||
|
||||
@@ -155,17 +160,17 @@ impl TopologyRefresher {
|
||||
let mut interval =
|
||||
gloo_timers::future::IntervalStream::new(self.refresh_rate.as_millis() as u32);
|
||||
|
||||
while !shutdown.is_shutdown() {
|
||||
while !self.task_client.is_shutdown() {
|
||||
tokio::select! {
|
||||
_ = interval.next() => {
|
||||
self.try_refresh().await;
|
||||
},
|
||||
_ = shutdown.recv() => {
|
||||
_ = self.task_client.recv() => {
|
||||
log::trace!("TopologyRefresher: Received shutdown");
|
||||
},
|
||||
}
|
||||
}
|
||||
shutdown.recv_timeout().await;
|
||||
self.task_client.recv_timeout().await;
|
||||
log::debug!("TopologyRefresher: Exiting");
|
||||
})
|
||||
}
|
||||
|
||||
@@ -222,6 +222,9 @@ pub enum ClientCoreError {
|
||||
"fresh registration with gateway {gateway_id} somehow requires an additional key upgrade!"
|
||||
)]
|
||||
UnexpectedKeyUpgrade { gateway_id: String },
|
||||
|
||||
#[error("failed to derive keys from master key")]
|
||||
HkdfDerivationError {},
|
||||
}
|
||||
|
||||
/// Set of messages that the client can send to listeners via the task manager
|
||||
|
||||
@@ -1053,7 +1053,7 @@ impl GatewayClient<InitOnly, EphemeralCredentialStorage> {
|
||||
connection: SocketState::NotConnected,
|
||||
packet_router,
|
||||
bandwidth_controller: None,
|
||||
stats_reporter: ClientStatsSender::new(None),
|
||||
stats_reporter: ClientStatsSender::new(None, task_client.clone()),
|
||||
negotiated_protocol: None,
|
||||
#[cfg(unix)]
|
||||
connection_fd_callback: None,
|
||||
|
||||
@@ -24,6 +24,7 @@ ed25519-dalek = { workspace = true, features = ["rand_core"], optional = true }
|
||||
rand = { workspace = true, optional = true }
|
||||
serde_bytes = { workspace = true, optional = true }
|
||||
serde = { workspace = true, features = ["derive"], optional = true }
|
||||
sha2 = { workspace = true, optional = true }
|
||||
subtle-encoding = { workspace = true, features = ["bech32-preview"] }
|
||||
thiserror = { workspace = true }
|
||||
zeroize = { workspace = true, optional = true, features = ["zeroize_derive"] }
|
||||
@@ -40,7 +41,7 @@ default = ["sphinx"]
|
||||
aead = ["dep:aead", "aead/std", "aes-gcm-siv", "generic-array"]
|
||||
serde = ["dep:serde", "serde_bytes", "ed25519-dalek/serde", "x25519-dalek/serde"]
|
||||
asymmetric = ["x25519-dalek", "ed25519-dalek", "zeroize"]
|
||||
hashing = ["blake3", "digest", "hkdf", "hmac", "generic-array"]
|
||||
hashing = ["blake3", "digest", "hkdf", "hmac", "generic-array", "sha2"]
|
||||
stream_cipher = ["aes", "ctr", "cipher", "generic-array"]
|
||||
sphinx = ["nym-sphinx-types/sphinx"]
|
||||
outfox = ["nym-sphinx-types/outfox"]
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
pub use ed25519_dalek::SignatureError;
|
||||
use ed25519_dalek::{Signer, SigningKey};
|
||||
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};
|
||||
@@ -18,7 +18,7 @@ pub mod serde_helpers;
|
||||
use nym_sphinx_types::{DestinationAddressBytes, DESTINATION_ADDRESS_LENGTH};
|
||||
|
||||
#[cfg(feature = "rand")]
|
||||
use rand::{CryptoRng, RngCore};
|
||||
use rand::{CryptoRng, Rng, RngCore};
|
||||
#[cfg(feature = "serde")]
|
||||
use serde::de::Error as SerdeError;
|
||||
#[cfg(feature = "serde")]
|
||||
@@ -62,16 +62,33 @@ pub struct KeyPair {
|
||||
// nothing secret about public key
|
||||
#[zeroize(skip)]
|
||||
public_key: PublicKey,
|
||||
|
||||
#[zeroize(skip)]
|
||||
index: u32,
|
||||
}
|
||||
|
||||
/// All keys will always have an index field populated this is to prevent anyone from figuring out if
|
||||
/// the keys are derived or random, and alter their behaviour based on that.
|
||||
impl KeyPair {
|
||||
#[cfg(feature = "rand")]
|
||||
pub fn new<R: RngCore + CryptoRng>(rng: &mut R) -> Self {
|
||||
let index = rng.gen();
|
||||
let ed25519_signing_key = ed25519_dalek::SigningKey::generate(rng);
|
||||
|
||||
KeyPair {
|
||||
private_key: PrivateKey(ed25519_signing_key.to_bytes()),
|
||||
public_key: PublicKey(ed25519_signing_key.verifying_key()),
|
||||
index,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_secret(secret: SecretKey, index: u32) -> Self {
|
||||
let ed25519_signing_key = SigningKey::from(secret);
|
||||
|
||||
KeyPair {
|
||||
private_key: PrivateKey(ed25519_signing_key.to_bytes()),
|
||||
public_key: PublicKey(ed25519_signing_key.verifying_key()),
|
||||
index,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,15 +104,31 @@ impl KeyPair {
|
||||
Ok(KeyPair {
|
||||
private_key: PrivateKey::from_bytes(priv_bytes)?,
|
||||
public_key: PublicKey::from_bytes(pub_bytes)?,
|
||||
index: fake_index(pub_bytes),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Reduces a byte slice into a u32 value by XOR-ing all its bytes into a 4-byte accumulator.
|
||||
/// The process iterates over every byte in the input slice, XOR-ing each one into a slot based on its index modulo 4.
|
||||
/// If the input slice contains fewer than 4 bytes, the remaining positions in the accumulator remain zero.
|
||||
/// Finally, the accumulator is interpreted in big-endian order to produce the resulting u32.
|
||||
/// Index is used to verify deterministic identity key, master key and salt are also requried for verification.
|
||||
fn fake_index(input: &[u8]) -> u32 {
|
||||
let mut accumulator = [0u8; 4];
|
||||
for (i, &byte) in input.iter().enumerate() {
|
||||
accumulator[i % 4] ^= byte;
|
||||
}
|
||||
u32::from_be_bytes(accumulator)
|
||||
}
|
||||
|
||||
impl From<PrivateKey> for KeyPair {
|
||||
fn from(private_key: PrivateKey) -> Self {
|
||||
let public_key = (&private_key).into();
|
||||
KeyPair {
|
||||
public_key: (&private_key).into(),
|
||||
public_key,
|
||||
private_key,
|
||||
index: fake_index(public_key.to_bytes().as_ref()),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -115,6 +148,7 @@ impl PemStorableKeyPair for KeyPair {
|
||||
KeyPair {
|
||||
private_key,
|
||||
public_key,
|
||||
index: fake_index(public_key.to_bytes().as_ref()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,10 @@ use hkdf::{
|
||||
},
|
||||
Hkdf,
|
||||
};
|
||||
use sha2::{Sha256, Sha512};
|
||||
|
||||
pub use hkdf::InvalidLength;
|
||||
use zeroize::ZeroizeOnDrop;
|
||||
|
||||
/// Perform HKDF `extract` then `expand` as a single step.
|
||||
pub fn extract_then_expand<D>(
|
||||
@@ -28,3 +32,80 @@ where
|
||||
|
||||
Ok(okm)
|
||||
}
|
||||
|
||||
/// `DerivationMaterial` encapsulates parameters for deterministic key derivation using
|
||||
/// HKDF (SHA-512).
|
||||
///
|
||||
/// It consists of:
|
||||
/// - A master key (`master_key`): the base secret.
|
||||
/// - An index (`index`): ensures unique derivations.
|
||||
/// - A salt (`salt`): adds additional uniqueness, should be application specific.
|
||||
///
|
||||
/// Use the `derive_secret()` method to generate a 32-byte secret. To prepare for a new derivation,
|
||||
/// call the `next()` method, which increments the index. **It is the caller's responsibility to
|
||||
/// track and persist the derivation index if keys need to be rederived.**
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use nym_crypto::hkdf::DerivationMaterial;
|
||||
///
|
||||
/// let master_key = [0u8; 32]; // your secret master key
|
||||
/// let salt = b"unique-salt-value";
|
||||
/// let material = DerivationMaterial::new(master_key, 0, salt);
|
||||
///
|
||||
/// // Derive a secret
|
||||
/// let secret = material.derive_secret().expect("Failed to derive secret");
|
||||
///
|
||||
/// // Prepare for the next derivation
|
||||
/// let next_material = material.next();
|
||||
/// ```
|
||||
#[derive(ZeroizeOnDrop)]
|
||||
pub struct DerivationMaterial {
|
||||
master_key: [u8; 32],
|
||||
index: u32,
|
||||
salt: Vec<u8>,
|
||||
}
|
||||
|
||||
impl DerivationMaterial {
|
||||
pub fn index(&self) -> u32 {
|
||||
self.index
|
||||
}
|
||||
|
||||
pub fn salt(&self) -> &[u8] {
|
||||
&self.salt
|
||||
}
|
||||
|
||||
/// Derives a 32-byte seed from a master seed and an index using HKDF (with SHA-512).
|
||||
///
|
||||
/// The `salt` and the use of the index (as info) bind this derivation to an application/client.
|
||||
pub fn derive_secret(&self) -> Result<[u8; 32], hkdf::InvalidLength> {
|
||||
let salt = &self.salt;
|
||||
let info = self.index.to_be_bytes(); // Use the index as info
|
||||
let hk = Hkdf::<Sha512>::new(Some(salt), &self.master_key);
|
||||
let mut okm = [0u8; 32];
|
||||
hk.expand(&info, &mut okm)?;
|
||||
Ok(okm)
|
||||
}
|
||||
|
||||
pub fn new<T: AsRef<[u8]>>(master_key: T, index: u32, salt: &[u8]) -> Self {
|
||||
// Coerce master_key to [u8; 32]
|
||||
let mut hasher = Sha256::new();
|
||||
hasher.update(master_key.as_ref());
|
||||
let master_key = hasher.finalize().into();
|
||||
|
||||
Self {
|
||||
master_key,
|
||||
index,
|
||||
salt: salt.to_vec(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn next(&self) -> Self {
|
||||
Self {
|
||||
master_key: self.master_key,
|
||||
index: self.index + 1,
|
||||
salt: self.salt.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ license.workspace = true
|
||||
|
||||
[dependencies]
|
||||
async-trait = { workspace = true }
|
||||
reqwest = { workspace = true, features = ["json"] }
|
||||
reqwest = { workspace = true, features = ["json", "gzip"] }
|
||||
http.workspace = true
|
||||
url = { workspace = true }
|
||||
once_cell = { workspace = true }
|
||||
|
||||
+423
-334
File diff suppressed because it is too large
Load Diff
@@ -7,11 +7,16 @@ use http::HeaderValue;
|
||||
use nym_bin_common::build_information::{BinaryBuildInformation, BinaryBuildInformationOwned};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// Characteristic elements sent to the API providing basic context information of the requesting client.
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
pub struct UserAgent {
|
||||
/// The internal crate / application / subsystem making use of API client
|
||||
pub application: String,
|
||||
/// version of the calling crate / application / subsystem
|
||||
pub version: String,
|
||||
/// client platform
|
||||
pub platform: String,
|
||||
/// source commit version for the calling calling crate / subsystem
|
||||
pub git_commit: String,
|
||||
}
|
||||
|
||||
|
||||
@@ -26,4 +26,4 @@ utoipa = [ "dep:utoipa" ]
|
||||
|
||||
[build-dependencies]
|
||||
regex = { workspace = true }
|
||||
cargo_metadata = { version = "0.18" }
|
||||
cargo_metadata = { workspace = true }
|
||||
|
||||
@@ -31,7 +31,7 @@ nym-pemstore = { path = "../pemstore" }
|
||||
nym-network-defaults = { path = "../network-defaults", default-features = false }
|
||||
|
||||
[dev-dependencies]
|
||||
criterion = { version = "0.5.1", features = ["html_reports"] }
|
||||
criterion = { workspace = true, features = ["html_reports"] }
|
||||
|
||||
|
||||
[[bench]]
|
||||
|
||||
@@ -25,19 +25,28 @@ pub type ClientStatsReceiver = tokio::sync::mpsc::UnboundedReceiver<ClientStatsE
|
||||
#[derive(Clone)]
|
||||
pub struct ClientStatsSender {
|
||||
stats_tx: Option<UnboundedSender<ClientStatsEvents>>,
|
||||
task_client: TaskClient,
|
||||
}
|
||||
|
||||
impl ClientStatsSender {
|
||||
/// Create a new statistics Sender
|
||||
pub fn new(stats_tx: Option<UnboundedSender<ClientStatsEvents>>) -> Self {
|
||||
ClientStatsSender { stats_tx }
|
||||
pub fn new(
|
||||
stats_tx: Option<UnboundedSender<ClientStatsEvents>>,
|
||||
task_client: TaskClient,
|
||||
) -> Self {
|
||||
ClientStatsSender {
|
||||
stats_tx,
|
||||
task_client,
|
||||
}
|
||||
}
|
||||
|
||||
/// Report a statistics event using the sender.
|
||||
pub fn report(&self, event: ClientStatsEvents) {
|
||||
if let Some(tx) = &self.stats_tx {
|
||||
if let Err(err) = tx.send(event) {
|
||||
log::error!("Failed to send stats event: {:?}", err);
|
||||
if !self.task_client.is_shutdown_poll() {
|
||||
log::error!("Failed to send stats event: {err}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -299,6 +299,8 @@ impl Clone for TaskClient {
|
||||
None
|
||||
};
|
||||
|
||||
log::debug!("Cloned task client: {name:?}");
|
||||
|
||||
TaskClient {
|
||||
name,
|
||||
shutdown: AtomicBool::new(self.shutdown.load(Ordering::Relaxed)),
|
||||
@@ -344,6 +346,7 @@ impl TaskClient {
|
||||
format!("unknown-{suffix}")
|
||||
};
|
||||
|
||||
log::debug!("Forked task client: {child_name}");
|
||||
child.name = Some(child_name);
|
||||
child
|
||||
}
|
||||
@@ -377,6 +380,7 @@ impl TaskClient {
|
||||
} else {
|
||||
format!("unknown-{suffix}")
|
||||
};
|
||||
log::debug!("Renamed task client: {name}");
|
||||
self.named(name)
|
||||
}
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ impl PeerHandle {
|
||||
let timeout_check_interval = tokio_stream::wrappers::IntervalStream::new(
|
||||
tokio::time::interval(DEFAULT_PEER_TIMEOUT_CHECK),
|
||||
);
|
||||
let mut task_client = task_client.fork(format!("peer-{public_key}"));
|
||||
let mut task_client = task_client.fork(format!("peer_{public_key}"));
|
||||
task_client.disarm();
|
||||
PeerHandle {
|
||||
public_key,
|
||||
|
||||
@@ -198,8 +198,8 @@ pub mod test_helpers {
|
||||
|
||||
let choices = [true, false];
|
||||
|
||||
// every epoch there's a 2% chance of somebody bonding a node
|
||||
let bonding_weights = [2, 98];
|
||||
// every epoch there's a 3% chance of somebody bonding a node
|
||||
let bonding_weights = [3, 97];
|
||||
|
||||
// and 15% of making a delegation
|
||||
let delegation_weights = [15, 85];
|
||||
@@ -246,28 +246,28 @@ pub mod test_helpers {
|
||||
|
||||
// make sure we cover our edge case of somebody having both liquid and vested delegation towards the same node
|
||||
if epoch_id == 123 {
|
||||
test.add_immediate_delegation(problematic_delegator, stake, 4);
|
||||
test.add_immediate_delegation(problematic_delegator_twin, stake, 4);
|
||||
test.add_immediate_delegation(problematic_delegator, stake, 3);
|
||||
test.add_immediate_delegation(problematic_delegator_twin, stake, 3);
|
||||
}
|
||||
|
||||
if epoch_id == 666 {
|
||||
test.add_immediate_delegation_with_legal_proxy(problematic_delegator, stake, 4);
|
||||
test.add_immediate_delegation_with_legal_proxy(problematic_delegator, stake, 3);
|
||||
test.add_immediate_delegation_with_legal_proxy(
|
||||
problematic_delegator_twin,
|
||||
stake,
|
||||
4,
|
||||
3,
|
||||
);
|
||||
}
|
||||
|
||||
if epoch_id == 234 {
|
||||
test.add_immediate_delegation(problematic_delegator_alt_twin, stake, 4);
|
||||
test.add_immediate_delegation(problematic_delegator_alt_twin, stake, 3);
|
||||
}
|
||||
|
||||
if epoch_id == 420 {
|
||||
test.add_immediate_delegation_with_legal_proxy(
|
||||
problematic_delegator_alt_twin,
|
||||
stake,
|
||||
4,
|
||||
3,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -400,7 +400,7 @@ mod tests {
|
||||
|
||||
let problematic_delegator = "n1foomp";
|
||||
let problematic_delegator_twin = "n1bar";
|
||||
let mix_id = 4;
|
||||
let mix_id = 3;
|
||||
|
||||
let liquid_storage_key = Delegation::generate_storage_key(
|
||||
mix_id,
|
||||
|
||||
+7
-6
@@ -535,9 +535,10 @@
|
||||
}
|
||||
},
|
||||
"node_modules/elliptic": {
|
||||
"version": "6.5.4",
|
||||
"resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz",
|
||||
"integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==",
|
||||
"version": "6.6.1",
|
||||
"resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.6.1.tgz",
|
||||
"integrity": "sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"bn.js": "^4.11.9",
|
||||
"brorand": "^1.1.0",
|
||||
@@ -1635,9 +1636,9 @@
|
||||
"integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A=="
|
||||
},
|
||||
"elliptic": {
|
||||
"version": "6.5.4",
|
||||
"resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz",
|
||||
"integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==",
|
||||
"version": "6.6.1",
|
||||
"resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.6.1.tgz",
|
||||
"integrity": "sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==",
|
||||
"requires": {
|
||||
"bn.js": "^4.11.9",
|
||||
"brorand": "^1.1.0",
|
||||
|
||||
@@ -9,5 +9,5 @@ edition.workspace = true
|
||||
license.workspace = true
|
||||
|
||||
[dependencies]
|
||||
env_logger = "0.11.6"
|
||||
env_logger = { workspace = true }
|
||||
log.workspace = true
|
||||
|
||||
@@ -47,6 +47,128 @@ This page displays a full list of all the changes during our release cycle from
|
||||
|
||||
<VarInfo />
|
||||
|
||||
## `v2025.3-ruta`
|
||||
|
||||
- [Release Binaries](https://github.com/nymtech/nym/releases/tag/nym-binaries-v2025.3-ruta)
|
||||
- [`nym-node`](nodes/nym-node.mdx) version `1.5.0`
|
||||
|
||||
```
|
||||
nym-node
|
||||
Binary Name: nym-node
|
||||
Build Timestamp: 2025-02-13T11:49:34.670488195Z
|
||||
Build Version: 1.5.0
|
||||
Commit SHA: a3e19b4563843055b305ea9a397eb1ad84b5c378
|
||||
Commit Date: 2025-02-10T18:14:47.000000000+01:00
|
||||
Commit Branch: HEAD
|
||||
rustc Version: 1.84.1
|
||||
rustc Channel: stable
|
||||
cargo Profile: release
|
||||
```
|
||||
|
||||
### Operators Updates & Tools
|
||||
|
||||
- **Operators who use Debian based distributions must run their `nym-node` on Debian bookworm (Debian 12)/ Ubuntu 22.04 (and newer).** In case of running older operation system make sure to upgrade your server.
|
||||
|
||||
#### Service Grant Program v2 (SGPv2)
|
||||
|
||||
As we announced in [`hu` release notes](#service-grant-program-v2), we are opened a second iteration Service Grant Program to bootstrap node operations in key target geographies for Nym and ensures the network can provide a good quality of service.
|
||||
|
||||
##### Conditions to join of SGPv2
|
||||
|
||||
<Callout type="warning">
|
||||
**If you are interested to become a part of SGPv2, read the point below. Do *not* buy new machines and do *not* migrate nodes just yet!**
|
||||
</Callout>
|
||||
|
||||
- [Read specs & rules first](#service-grant-program-v2)
|
||||
- The program will start from March 1st.
|
||||
- Accepted participants are expected to run their nodes in assigned location and with [new specs](#service-grant-program-v2) by February 28th the latest.
|
||||
- Squads orchestrating multiple nodes will be prioritized in locations with more slots.
|
||||
- There is no final budget, neither a size per node as we expect that the next round of Service Grants program will be individual grants of varying sizes, depending on how many nodes, location, specs etc.
|
||||
- Every participant of SGPv1 can submit for SGPv2 as many nodes as they currently have grant for, more slots may be offered later on.
|
||||
- New submissions can only do one node per operator unless people come in squads (or DAOs) and can orchestrate multiple nodes on larger dedicated servers.
|
||||
- Actual locations and approximate slots are listed below. If you want to have a node in a location which is not listed but it's near by some of the listed ones, it's not a problem, be honest in the form so we know where you planning to run nodes.
|
||||
- February is the last month we proceed with grants under SGPv1.
|
||||
|
||||
##### How to Join
|
||||
|
||||
1. Have a look at the remaining [locations](#locations), specs and providers. You can contact them directly and make a calculation how much running a node on their service would cost and what size of a grant you expect to receive.
|
||||
2. To apply for a service grant, the first step is to fill in [this form](https://nymtech2.typeform.com/to/LyPJer49) per each node.
|
||||
3. Be responsive on Element for follow up communication.
|
||||
|
||||
##### Locations
|
||||
|
||||
These locations and slots are approximate and constantly change based on new operators submissions. Please keep in mind that we are going to chose people with respect to empty slots in the given location at the time of their submission. In case of competing submissions in the same location we will take the one with better specs vs price ratio.
|
||||
|
||||
| LOCATION | SLOTS |
|
||||
| :-- | --: |
|
||||
| India | 3 |
|
||||
| Austria | 1 |
|
||||
| Poland | 1 |
|
||||
| Russia | 2 |
|
||||
| Canada | 1 |
|
||||
| South Africa | 2 |
|
||||
| Sweden | 2 |
|
||||
| Latvia | 2 |
|
||||
| Lithuania | 1 |
|
||||
| Bahrain | 1 |
|
||||
| Czech Republic | 1 |
|
||||
| Denmark | 1 |
|
||||
| Norway | 1 |
|
||||
| South Korea | 1 |
|
||||
| Ukraine | 1 |
|
||||
| Vietnam | 1 |
|
||||
| Argentina | 1 |
|
||||
| Belarus | 1 |
|
||||
| Croatia | 1 |
|
||||
| Cyprus | 1 |
|
||||
| Ecuador | 1 |
|
||||
| Hungary | 1 |
|
||||
| Malta | 1 |
|
||||
| New Zealand | 1 |
|
||||
|
||||
##### ISPs
|
||||
|
||||
- Have a look into our [ISP list](community-counsel/isp-list) page
|
||||
- Further you can check out Tor community [Good Bad ISPs](https://community.torproject.org/relay/community-resources/good-bad-isps/) page
|
||||
- With any findings or feedback, please add it to this [csv](https://github.com/nymtech/nym/blob/develop/documentation/docs/data/csv/isp-sheet.csv), issue a [Pull Request](community-counsel/add-content) and ping me for review.
|
||||
- We will add much more providers in the coming days
|
||||
|
||||
### Features
|
||||
|
||||
- [DNS resolver configuration for internal HTTP client lookups](https://github.com/nymtech/nym/pull/5355): The resolver itself is the set combination of the google, cloudflare, and quad9 endpoints supporting DoH, DoT, and for google DoH3 as well. This resolver implements a fallback mechanism where, should the DNS-over-X resolution fail, a followup resolution will be done using the hosts configured default (e.g. `/etc/resolve.conf` on linux).
|
||||
|
||||
- [Bump tokio from `1.40.0` to `1.43.0`](https://github.com/nymtech/nym/pull/5370)
|
||||
|
||||
- [Uncouple storage reference for bandwidth client](https://github.com/nymtech/nym/pull/5372): Because of the `Storage` reference in the bandwidth client, the client can't be separated and used in a different place, as it will be linked to the `DisconnectedClient`. Cloning it ensures we uncouple this unnecessary dependence.
|
||||
|
||||
- [`MixnetClient` can send `ClientRequests`](https://github.com/nymtech/nym/pull/5381): Adding a channel to the `MixnetClient`, so that it can signal to the `MixTrafficController` that can send a `ClientRequest` via its `GatewayTransciver`. Additionaly adds a sleep to the `disconnect` call as the socket would close before the channel message got processed.
|
||||
|
||||
- [Use secure DNS for websocket connection establishment](https://github.com/nymtech/nym/pull/5386): Adjust the websocket connection establishment (using `tokio_tungstenite`) to use a custom DNS resolver that tries DoH and DoT. Instead of relying on the `tokio_tungstenite` to open the `tokio::net::TcpStream` ([which it does here](https://github.com/snapview/tokio-tungstenite/blob/aafb2f9e036162f7bffa002cfea502376a690724/src/connect.rs#L91)) which would kick in the default network resolver we do the resolution and open the `TcpStream` ourselves before handing off to the websocket libary.
|
||||
|
||||
- [Reduce log severity for checking topology validity](https://github.com/nymtech/nym/pull/5395)
|
||||
|
||||
- [Change Explorer URL to new smooshed nodes](https://github.com/nymtech/nym/pull/5396)
|
||||
|
||||
- [Send shutdown instead of panic when reaching max fail](https://github.com/nymtech/nym/pull/5398): Remove a panic and an unwrap inside `client-core` that is hit occasionally in the vpn client. This is a change that can have wide ranging impact since it changes the task handling and it's inside `client-core`, which is used in many components and services, so preventing regressions is important.
|
||||
|
||||
- [Relocate a validator api function](https://github.com/nymtech/nym/pull/5401): Adds a function to the `nym-validator-client` crate that hits the network details endpoint and returns an object parsed from `json`. This was floating loose in the `nym-vpn-client` repo.
|
||||
|
||||
- [Bump the patch-updates group across 1 directory with 9 updates](https://github.com/nymtech/nym/pull/5406)
|
||||
|
||||
- [Upgrade to `thiserror` 2.0](https://github.com/nymtech/nym/pull/5414)
|
||||
|
||||
- [Make `wait_for_graceful_shutdown` to be pub](https://github.com/nymtech/nym/pull/5424)
|
||||
|
||||
- [Fix statistics shutdown](https://github.com/nymtech/nym/pull/5426)
|
||||
|
||||
- [Push down forget me to client configs](https://github.com/nymtech/nym/pull/5431)
|
||||
|
||||
### Bugfix
|
||||
|
||||
- [Fix missing path triggers for CI](https://github.com/nymtech/nym/pull/5380): Fix missing path triggers for CI and sort crate list alphabetically to make it easier to maintain.
|
||||
|
||||
|
||||
|
||||
## `v2025.2-hu`
|
||||
|
||||
- [Release Binaries](https://github.com/nymtech/nym/releases/tag/nym-binaries-v2025.2-hu)
|
||||
|
||||
@@ -20,10 +20,10 @@ This documentation page provides a guide on how to set up and run a [NYM NODE](.
|
||||
```sh
|
||||
nym-node
|
||||
Binary Name: nym-node
|
||||
Build Timestamp: 2025-02-04T09:35:42.399220545Z
|
||||
Build Version: 1.4.0
|
||||
Commit SHA: 4c2bf3642e8eec0d55c7753e14429d73ac2d0e99
|
||||
Commit Date: 2025-02-04T10:29:48.000000000+01:00
|
||||
Build Timestamp: 2025-02-13T11:49:34.670488195Z
|
||||
Build Version: 1.5.0
|
||||
Commit SHA: a3e19b4563843055b305ea9a397eb1ad84b5c378
|
||||
Commit Date: 2025-02-10T18:14:47.000000000+01:00
|
||||
Commit Branch: HEAD
|
||||
rustc Version: 1.84.1
|
||||
rustc Channel: stable
|
||||
@@ -62,7 +62,7 @@ Exit Gateway is the only mode routing data directly to the open internet. Theref
|
||||
|
||||
***dVPN routing (2-hop) is the Fast option of NymVPN. It runs a wireguard tunnel inside another wireguard tunnel. dVPN uses 2 Gateway layers (entry and exit) and no Mixnode layers. If an operator announces and [correctly configure](configuration#connectivity-test-and-configuration) their node to route wireguard, the node can be chosen as entry or exit by any client at any time.***
|
||||
|
||||
To activate wireguard routing, operators need to add `--wireguard-enabled true` alongside `nym-node` command `run`.
|
||||
To activate wireguard routing, operators need to add `--wireguard-enabled true` alongside `nym-node` command `run`.
|
||||
|
||||
<Callout type="warning">
|
||||
Wireguard nodes route data directly to the open internet. Therefore it exposes IP of operators server (VPS) to abuse complains. Before you decide to run a node with active wireguard routing, please read our [Community Counsel pages](../../community-counsel/exit-gateway) containing more information and some legal content.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "explorer-api"
|
||||
version = "1.1.45"
|
||||
version = "1.1.47"
|
||||
edition = "2021"
|
||||
license.workspace = true
|
||||
|
||||
|
||||
@@ -95,7 +95,7 @@ where
|
||||
S: AsyncRead + AsyncWrite + Unpin + Send,
|
||||
{
|
||||
// don't accept any new requests if we have already received shutdown
|
||||
if handle.shutdown.is_shutdown() {
|
||||
if handle.shutdown.is_shutdown_poll() {
|
||||
debug!("stopping the handle as we have received a shutdown");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ impl Listener {
|
||||
connection = tcp_listener.accept() => {
|
||||
match connection {
|
||||
Ok((socket, remote_addr)) => {
|
||||
let shutdown = self.shutdown.fork(format!("websocket-handler-{remote_addr}"));
|
||||
let shutdown = self.shutdown.fork(format!("websocket_handler_{remote_addr}"));
|
||||
trace!("received a socket connection from {remote_addr}");
|
||||
// TODO: I think we *REALLY* need a mechanism for having a maximum number of connected
|
||||
// clients or spawned tokio tasks -> perhaps a worker system?
|
||||
|
||||
@@ -225,7 +225,7 @@ impl GatewayTasksBuilder {
|
||||
handler_config,
|
||||
nyxd_client,
|
||||
self.identity_keypair.public_key().to_bytes(),
|
||||
self.shutdown.fork("ecash-manager"),
|
||||
self.shutdown.fork("ecash_manager"),
|
||||
self.storage.clone(),
|
||||
)
|
||||
.await?,
|
||||
@@ -279,13 +279,13 @@ impl GatewayTasksBuilder {
|
||||
let mut message_router_builder = SpMessageRouterBuilder::new(
|
||||
*self.identity_keypair.public_key(),
|
||||
self.mix_packet_sender.clone(),
|
||||
self.shutdown.fork("network-requester-message-router"),
|
||||
self.shutdown.fork("network_requester_message_router"),
|
||||
);
|
||||
let transceiver = message_router_builder.gateway_transceiver();
|
||||
|
||||
let (on_start_tx, on_start_rx) = oneshot::channel();
|
||||
let mut nr_builder = NRServiceProviderBuilder::new(nr_opts.config.clone())
|
||||
.with_shutdown(self.shutdown.fork("network-requester-sp"))
|
||||
.with_shutdown(self.shutdown.fork("network_requester_sp"))
|
||||
.with_custom_gateway_transceiver(transceiver)
|
||||
.with_wait_for_gateway(true)
|
||||
.with_minimum_gateway_performance(0)
|
||||
@@ -314,13 +314,13 @@ impl GatewayTasksBuilder {
|
||||
let mut message_router_builder = SpMessageRouterBuilder::new(
|
||||
*self.identity_keypair.public_key(),
|
||||
self.mix_packet_sender.clone(),
|
||||
self.shutdown.fork("ipr-message-router"),
|
||||
self.shutdown.fork("ipr_message_router"),
|
||||
);
|
||||
let transceiver = message_router_builder.gateway_transceiver();
|
||||
|
||||
let (on_start_tx, on_start_rx) = oneshot::channel();
|
||||
let mut ip_packet_router = IpPacketRouter::new(ip_opts.config.clone())
|
||||
.with_shutdown(self.shutdown.fork("ipr-sp"))
|
||||
.with_shutdown(self.shutdown.fork("ipr_sp"))
|
||||
.with_custom_gateway_transceiver(Box::new(transceiver))
|
||||
.with_wait_for_gateway(true)
|
||||
.with_minimum_gateway_performance(0)
|
||||
@@ -418,7 +418,7 @@ impl GatewayTasksBuilder {
|
||||
let mut message_router_builder = SpMessageRouterBuilder::new(
|
||||
*self.identity_keypair.public_key(),
|
||||
self.mix_packet_sender.clone(),
|
||||
self.shutdown.fork("authenticator-message-router"),
|
||||
self.shutdown.fork("authenticator_message_router"),
|
||||
);
|
||||
let transceiver = message_router_builder.gateway_transceiver();
|
||||
|
||||
@@ -431,7 +431,7 @@ impl GatewayTasksBuilder {
|
||||
)
|
||||
.with_ecash_verifier(ecash_manager)
|
||||
.with_custom_gateway_transceiver(transceiver)
|
||||
.with_shutdown(self.shutdown.fork("authenticator-sp"))
|
||||
.with_shutdown(self.shutdown.fork("authenticator_sp"))
|
||||
.with_wait_for_gateway(true)
|
||||
.with_minimum_gateway_performance(0)
|
||||
.with_custom_topology_provider(topology_provider)
|
||||
@@ -451,7 +451,7 @@ impl GatewayTasksBuilder {
|
||||
pub fn build_stale_messages_cleaner(&self) -> StaleMessagesCleaner {
|
||||
StaleMessagesCleaner::new(
|
||||
&self.storage,
|
||||
self.shutdown.fork("stale-messages-cleaner"),
|
||||
self.shutdown.fork("stale_messages_cleaner"),
|
||||
self.config.debug.stale_messages_max_age,
|
||||
self.config.debug.stale_messages_cleaner_run_interval,
|
||||
)
|
||||
|
||||
+3
-3
@@ -4,7 +4,7 @@
|
||||
[package]
|
||||
name = "nym-api"
|
||||
license = "GPL-3.0"
|
||||
version = "1.1.49"
|
||||
version = "1.1.51"
|
||||
authors.workspace = true
|
||||
edition = "2021"
|
||||
rust-version.workspace = true
|
||||
@@ -65,7 +65,7 @@ zeroize = { workspace = true }
|
||||
# for axum server
|
||||
axum = { workspace = true, features = ["tokio"] }
|
||||
axum-extra = { workspace = true, features = ["typed-header"] }
|
||||
tower-http = { workspace = true, features = ["cors", "trace"] }
|
||||
tower-http = { workspace = true, features = ["cors", "trace", "compression-br", "compression-deflate", "compression-gzip", "compression-zstd"] }
|
||||
utoipa = { workspace = true, features = ["axum_extras", "time"] }
|
||||
utoipauto = { workspace = true }
|
||||
utoipa-swagger-ui = { workspace = true, features = ["axum"] }
|
||||
@@ -136,7 +136,7 @@ sqlx = { workspace = true, features = [
|
||||
] }
|
||||
|
||||
[dev-dependencies]
|
||||
axum-test = "16.2.0"
|
||||
axum-test = { workspace = true }
|
||||
tempfile = { workspace = true }
|
||||
cw3 = { workspace = true }
|
||||
cw-utils = { workspace = true }
|
||||
|
||||
@@ -8,12 +8,19 @@ use nym_crypto::asymmetric::x25519::serde_helpers::bs58_x25519_pubkey;
|
||||
use nym_crypto::asymmetric::{ed25519, x25519};
|
||||
use nym_mixnet_contract_common::nym_node::Role;
|
||||
use nym_mixnet_contract_common::reward_params::Performance;
|
||||
use nym_mixnet_contract_common::NodeId;
|
||||
use nym_mixnet_contract_common::{Interval, NodeId};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::net::IpAddr;
|
||||
use time::OffsetDateTime;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
#[derive(Clone, Copy, Debug, Serialize, Deserialize, schemars::JsonSchema, utoipa::ToSchema)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub enum TopologyRequestStatus {
|
||||
NoUpdates,
|
||||
Fresh(Interval),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, schemars::JsonSchema, ToSchema)]
|
||||
pub struct CachedNodesResponse<T: ToSchema> {
|
||||
pub refreshed_at: OffsetDateTimeJsonSchemaWrapper,
|
||||
@@ -37,6 +44,7 @@ impl<T: ToSchema> CachedNodesResponse<T> {
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, schemars::JsonSchema)]
|
||||
pub struct PaginatedCachedNodesResponse<T> {
|
||||
pub status: Option<TopologyRequestStatus>,
|
||||
pub refreshed_at: OffsetDateTimeJsonSchemaWrapper,
|
||||
pub nodes: PaginatedResponse<T>,
|
||||
}
|
||||
@@ -56,6 +64,28 @@ impl<T> PaginatedCachedNodesResponse<T> {
|
||||
},
|
||||
data: nodes,
|
||||
},
|
||||
status: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fresh(mut self, interval: Option<Interval>) -> Self {
|
||||
let iv = interval.map(TopologyRequestStatus::Fresh);
|
||||
self.status = iv;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn no_updates() -> Self {
|
||||
PaginatedCachedNodesResponse {
|
||||
refreshed_at: OffsetDateTime::now_utc().into(),
|
||||
nodes: PaginatedResponse {
|
||||
pagination: Pagination {
|
||||
total: 0,
|
||||
page: 0,
|
||||
size: 0,
|
||||
},
|
||||
data: Vec::new(),
|
||||
},
|
||||
status: Some(TopologyRequestStatus::NoUpdates),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ use crate::support::http::state::AppState;
|
||||
use axum::{extract, Router};
|
||||
use nym_contracts_common::ContractBuildInformation;
|
||||
use std::collections::HashMap;
|
||||
use tower_http::compression::CompressionLayer;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
pub(crate) fn nym_network_routes() -> Router<AppState> {
|
||||
@@ -16,6 +17,7 @@ pub(crate) fn nym_network_routes() -> Router<AppState> {
|
||||
"/nym-contracts-detailed",
|
||||
axum::routing::get(nym_contracts_detailed),
|
||||
)
|
||||
.layer(CompressionLayer::new())
|
||||
}
|
||||
|
||||
#[utoipa::path(
|
||||
|
||||
@@ -167,7 +167,7 @@ impl PacketSender {
|
||||
let gateway_packet_router = PacketRouter::new(
|
||||
ack_sender,
|
||||
message_sender,
|
||||
task_client.fork("packet-router"),
|
||||
task_client.fork("packet_router"),
|
||||
);
|
||||
|
||||
let shared_keys = fresh_gateway_client_data
|
||||
@@ -184,7 +184,10 @@ impl PacketSender {
|
||||
shared_keys,
|
||||
gateway_packet_router,
|
||||
Some(fresh_gateway_client_data.bandwidth_controller.clone()),
|
||||
nym_statistics_common::clients::ClientStatsSender::new(None),
|
||||
nym_statistics_common::clients::ClientStatsSender::new(
|
||||
None,
|
||||
task_client.fork("client_stats_sender"),
|
||||
),
|
||||
#[cfg(unix)]
|
||||
None,
|
||||
task_client,
|
||||
|
||||
@@ -7,6 +7,7 @@ use axum::extract::State;
|
||||
use axum::{Json, Router};
|
||||
use nym_api_requests::legacy::LegacyMixNodeBondWithLayer;
|
||||
use nym_api_requests::models::{LegacyDescribedGateway, LegacyDescribedMixNode};
|
||||
use tower_http::compression::CompressionLayer;
|
||||
|
||||
// we want to mark the routes as deprecated in swagger, but still expose them
|
||||
#[allow(deprecated)]
|
||||
@@ -20,6 +21,7 @@ pub(crate) fn legacy_nym_node_routes() -> Router<AppState> {
|
||||
"/mixnodes/described",
|
||||
axum::routing::get(get_mixnodes_described),
|
||||
)
|
||||
.layer(CompressionLayer::new())
|
||||
}
|
||||
|
||||
#[utoipa::path(
|
||||
|
||||
@@ -21,6 +21,7 @@ use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::time::Duration;
|
||||
use time::{Date, OffsetDateTime};
|
||||
use tower_http::compression::CompressionLayer;
|
||||
use utoipa::{IntoParams, ToSchema};
|
||||
|
||||
pub(crate) mod legacy;
|
||||
@@ -45,6 +46,7 @@ pub(crate) fn nym_node_routes() -> Router<AppState> {
|
||||
// to make it compatible with all the explorers that were used to using 0-100 values
|
||||
.route("/uptime-history/:node_id", get(get_node_uptime_history))
|
||||
.route("/rewarded-set", get(rewarded_set))
|
||||
.layer(CompressionLayer::new())
|
||||
}
|
||||
|
||||
#[utoipa::path(
|
||||
|
||||
@@ -33,6 +33,7 @@ use axum::routing::get;
|
||||
use axum::Router;
|
||||
use nym_api_requests::nym_nodes::NodeRoleQueryParam;
|
||||
use serde::Deserialize;
|
||||
use tower_http::compression::CompressionLayer;
|
||||
|
||||
pub(crate) mod full_fat;
|
||||
mod helpers;
|
||||
@@ -73,6 +74,7 @@ pub(crate) fn nym_node_routes_unstable() -> Router<AppState> {
|
||||
.nest("/full-fat", Router::new().route("/", get(nodes_detailed)))
|
||||
.route("/gateways/skimmed", get(skimmed::deprecated_gateways_basic))
|
||||
.route("/mixnodes/skimmed", get(skimmed::deprecated_mixnodes_basic))
|
||||
.layer(CompressionLayer::new())
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, utoipa::IntoParams)]
|
||||
@@ -85,6 +87,11 @@ struct NodesParamsWithRole {
|
||||
no_legacy: Option<bool>,
|
||||
page: Option<u32>,
|
||||
per_page: Option<u32>,
|
||||
|
||||
// Identifier for the current epoch of the topology state. When sent by a client we can check if
|
||||
// the client already knows about the latest topology state, allowing a `no-updates` response
|
||||
// instead of wasting bandwidth serving an unchanged topology.
|
||||
epoch_id: Option<u32>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, utoipa::IntoParams)]
|
||||
@@ -95,6 +102,11 @@ struct NodesParams {
|
||||
no_legacy: Option<bool>,
|
||||
page: Option<u32>,
|
||||
per_page: Option<u32>,
|
||||
|
||||
// Identifier for the current epoch of the topology state. When sent by a client we can check if
|
||||
// the client already knows about the latest topology state, allowing a `no-updates` response
|
||||
// instead of wasting bandwidth serving an unchanged topology.
|
||||
epoch_id: Option<u32>,
|
||||
}
|
||||
|
||||
impl From<NodesParamsWithRole> for NodesParams {
|
||||
@@ -104,6 +116,7 @@ impl From<NodesParamsWithRole> for NodesParams {
|
||||
no_legacy: params.no_legacy,
|
||||
page: params.page,
|
||||
per_page: params.per_page,
|
||||
epoch_id: params.epoch_id,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,6 +124,21 @@ where
|
||||
// (ideally it'd be tied directly to the NI iterator, but I couldn't defeat the compiler)
|
||||
let describe_cache = state.describe_nodes_cache_data().await?;
|
||||
|
||||
let maybe_interval = state
|
||||
.nym_contract_cache()
|
||||
.current_interval()
|
||||
.await
|
||||
.to_owned();
|
||||
|
||||
// 4.0 If the client indicates that they already know about the current topology send empty response
|
||||
if let Some(client_known_epoch) = query_params.epoch_id {
|
||||
if let Some(ref interval) = maybe_interval {
|
||||
if client_known_epoch == interval.current_epoch_id() {
|
||||
return Ok(Json(PaginatedCachedNodesResponse::no_updates()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 4. start building the response
|
||||
let mut nodes =
|
||||
build_nym_nodes_response(&rewarded_set, nym_nodes_subset, &annotations, active_only);
|
||||
@@ -137,10 +152,9 @@ where
|
||||
describe_cache.timestamp(),
|
||||
]);
|
||||
|
||||
return Ok(Json(PaginatedCachedNodesResponse::new_full(
|
||||
refreshed_at,
|
||||
nodes,
|
||||
)));
|
||||
return Ok(Json(
|
||||
PaginatedCachedNodesResponse::new_full(refreshed_at, nodes).fresh(maybe_interval),
|
||||
));
|
||||
}
|
||||
|
||||
// 6. grab relevant legacy nodes
|
||||
@@ -162,10 +176,9 @@ where
|
||||
annotated_legacy_nodes.timestamp(),
|
||||
]);
|
||||
|
||||
Ok(Json(PaginatedCachedNodesResponse::new_full(
|
||||
refreshed_at,
|
||||
nodes,
|
||||
)))
|
||||
Ok(Json(
|
||||
PaginatedCachedNodesResponse::new_full(refreshed_at, nodes).fresh(maybe_interval),
|
||||
))
|
||||
}
|
||||
|
||||
/// Deprecated query that gets ALL gateways
|
||||
|
||||
@@ -6,7 +6,9 @@ use crate::api::v1::ticketbook::models::{
|
||||
TicketbookWalletSharesResponse,
|
||||
};
|
||||
use async_trait::async_trait;
|
||||
use nym_http_api_client::{parse_response, HttpClientError, Params, PathSegments, NO_PARAMS};
|
||||
use nym_http_api_client::{
|
||||
parse_response, ApiClient, HttpClientError, Params, PathSegments, NO_PARAMS,
|
||||
};
|
||||
use reqwest::IntoUrl;
|
||||
use serde::de::DeserializeOwned;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
@@ -20,11 +20,11 @@ thiserror.workspace = true
|
||||
zeroize = { workspace = true }
|
||||
|
||||
# wasm-specific deps
|
||||
getrandom = { version = "0.2", features = ["js"] }
|
||||
getrandom = { workspace = true, features = ["js"] }
|
||||
wasm-bindgen = { workspace = true }
|
||||
js-sys = "0.3.76"
|
||||
js-sys = { workspace = true }
|
||||
tsify = { workspace = true, features = ["js"] }
|
||||
serde-wasm-bindgen = "0.6.5"
|
||||
serde-wasm-bindgen = { workspace = true }
|
||||
|
||||
# NYM:
|
||||
nym-bin-common = { path = "../../common/bin-common" }
|
||||
|
||||
@@ -27,7 +27,7 @@ tokio = { workspace = true, features = ["macros", "time"] }
|
||||
tokio-util = { workspace = true }
|
||||
utoipa = { workspace = true, features = ["axum_extras"] }
|
||||
utoipa-swagger-ui = { workspace = true, features = ["axum"] }
|
||||
tokio-postgres = "0.7"
|
||||
tokio-postgres = { workspace = true }
|
||||
|
||||
# internal
|
||||
nym-bin-common = { path = "../common/bin-common" }
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
[package]
|
||||
name = "nym-node-status-api"
|
||||
version = "1.0.0-rc.8"
|
||||
version = "1.0.0-rc.9"
|
||||
authors.workspace = true
|
||||
repository.workspace = true
|
||||
homepage.workspace = true
|
||||
@@ -13,7 +13,7 @@ license.workspace = true
|
||||
rust-version.workspace = true
|
||||
|
||||
[dependencies]
|
||||
ammonia = "4"
|
||||
ammonia = { workspace = true }
|
||||
anyhow = { workspace = true }
|
||||
axum = { workspace = true, features = ["tokio", "macros"] }
|
||||
chrono = { workspace = true }
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
|
||||
[package]
|
||||
name = "nym-node"
|
||||
version = "1.4.0"
|
||||
version = "1.6.0"
|
||||
authors.workspace = true
|
||||
repository.workspace = true
|
||||
homepage.workspace = true
|
||||
|
||||
@@ -70,7 +70,7 @@ pub struct NetworkConfig {
|
||||
|
||||
impl Default for Base {
|
||||
fn default() -> Self {
|
||||
let networks = WalletNetwork::iter().map(Into::into).collect();
|
||||
let networks = WalletNetwork::iter().collect();
|
||||
Base {
|
||||
networks: SupportedNetworks::new(networks),
|
||||
}
|
||||
|
||||
Generated
+12
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "INSERT INTO price_history\n (timestamp, chf, usd, eur, gbp, btc)\n VALUES\n ($1, $2, $3, $4, $5, $6)\n ON CONFLICT(timestamp) DO UPDATE SET\n chf=excluded.chf,\n usd=excluded.usd,\n eur=excluded.eur,\n gbp=excluded.gbp,\n btc=excluded.btc;",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 6
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "140df23f816ff5d7501128682ce378d582b7da78c45bc0de934f92c1abe14bda"
|
||||
}
|
||||
Generated
-12
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "INSERT INTO price_history\n (timestamp, chf, usd, eur, btc)\n VALUES\n ($1, $2, $3, $4, $5)\n ON CONFLICT(timestamp) DO UPDATE SET\n chf=excluded.chf,\n usd=excluded.usd,\n eur=excluded.eur,\n btc=excluded.btc;",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 5
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "26aa8b5b2d6d98257792d4726b3ad476160b26ea84486c563e731cfd757d7904"
|
||||
}
|
||||
+9
-3
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "SELECT timestamp, chf, usd, eur, btc FROM price_history WHERE timestamp >= $1;",
|
||||
"query": "SELECT timestamp, chf, usd, eur, gbp, btc FROM price_history WHERE timestamp >= $1;",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
@@ -24,9 +24,14 @@
|
||||
"type_info": "Float"
|
||||
},
|
||||
{
|
||||
"name": "btc",
|
||||
"name": "gbp",
|
||||
"ordinal": 4,
|
||||
"type_info": "Float"
|
||||
},
|
||||
{
|
||||
"name": "btc",
|
||||
"ordinal": 5,
|
||||
"type_info": "Float"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
@@ -37,8 +42,9 @@
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "5931f7d30101a718f49487e9f7895710f4119917e5f0bf3af4103a428515843b"
|
||||
"hash": "a57b74a049b33aee36b72741056d60df8ad35a747808d5d1d3d525a76bbf0618"
|
||||
}
|
||||
+9
-3
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "SELECT timestamp, chf, usd, eur, btc FROM price_history ORDER BY timestamp DESC LIMIT 1;",
|
||||
"query": "SELECT timestamp, chf, usd, eur, gbp, btc FROM price_history ORDER BY timestamp DESC LIMIT 1;",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
@@ -24,9 +24,14 @@
|
||||
"type_info": "Float"
|
||||
},
|
||||
{
|
||||
"name": "btc",
|
||||
"name": "gbp",
|
||||
"ordinal": 4,
|
||||
"type_info": "Float"
|
||||
},
|
||||
{
|
||||
"name": "btc",
|
||||
"ordinal": 5,
|
||||
"type_info": "Float"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
@@ -37,8 +42,9 @@
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "b3ced10067918010e613f61f6fb6fffe5631446fe66f17b8a86cbdca704a3517"
|
||||
"hash": "f81a3275a1c7cbeefb3fdf7904c677d46a284e0446b96a2fc5bd77630c62d4b8"
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
[package]
|
||||
name = "nyx-chain-watcher"
|
||||
version = "0.1.9"
|
||||
version = "0.1.11"
|
||||
authors.workspace = true
|
||||
repository.workspace = true
|
||||
homepage.workspace = true
|
||||
@@ -35,7 +35,7 @@ serde = { workspace = true, features = ["derive"] }
|
||||
serde_json = { workspace = true }
|
||||
sqlx = { workspace = true, features = ["runtime-tokio-rustls", "sqlite", "time"] }
|
||||
thiserror = { workspace = true }
|
||||
time = { version = "0.3.37" }
|
||||
time = { workspace = true }
|
||||
tokio = { workspace = true, features = ["process", "rt-multi-thread"] }
|
||||
tokio-util = { workspace = true }
|
||||
tracing = { workspace = true }
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TABLE price_history ADD COLUMN gbp REAL NOT NULL DEFAULT 0;
|
||||
@@ -6,6 +6,7 @@ pub(crate) struct CurrencyPrices {
|
||||
pub(crate) chf: f32,
|
||||
pub(crate) usd: f32,
|
||||
pub(crate) eur: f32,
|
||||
pub(crate) gbp: f32,
|
||||
pub(crate) btc: f32,
|
||||
}
|
||||
|
||||
@@ -27,6 +28,7 @@ pub(crate) struct PriceHistory {
|
||||
pub(crate) chf: f64,
|
||||
pub(crate) usd: f64,
|
||||
pub(crate) eur: f64,
|
||||
pub(crate) gbp: f64,
|
||||
pub(crate) btc: f64,
|
||||
}
|
||||
|
||||
|
||||
@@ -11,18 +11,20 @@ pub(crate) async fn insert_nym_prices(
|
||||
let timestamp = price_data.timestamp;
|
||||
sqlx::query!(
|
||||
"INSERT INTO price_history
|
||||
(timestamp, chf, usd, eur, btc)
|
||||
(timestamp, chf, usd, eur, gbp, btc)
|
||||
VALUES
|
||||
($1, $2, $3, $4, $5)
|
||||
($1, $2, $3, $4, $5, $6)
|
||||
ON CONFLICT(timestamp) DO UPDATE SET
|
||||
chf=excluded.chf,
|
||||
usd=excluded.usd,
|
||||
eur=excluded.eur,
|
||||
gbp=excluded.gbp,
|
||||
btc=excluded.btc;",
|
||||
timestamp,
|
||||
price_data.nym.chf,
|
||||
price_data.nym.usd,
|
||||
price_data.nym.eur,
|
||||
price_data.nym.gbp,
|
||||
price_data.nym.btc,
|
||||
)
|
||||
.execute(&mut *conn)
|
||||
@@ -33,7 +35,7 @@ pub(crate) async fn insert_nym_prices(
|
||||
|
||||
pub(crate) async fn get_latest_price(pool: &DbPool) -> anyhow::Result<PriceHistory> {
|
||||
let result = sqlx::query!(
|
||||
"SELECT timestamp, chf, usd, eur, btc FROM price_history ORDER BY timestamp DESC LIMIT 1;"
|
||||
"SELECT timestamp, chf, usd, eur, gbp, btc FROM price_history ORDER BY timestamp DESC LIMIT 1;"
|
||||
)
|
||||
.fetch_one(pool)
|
||||
.await?;
|
||||
@@ -43,6 +45,7 @@ pub(crate) async fn get_latest_price(pool: &DbPool) -> anyhow::Result<PriceHisto
|
||||
chf: result.chf,
|
||||
usd: result.usd,
|
||||
eur: result.eur,
|
||||
gbp: result.gbp,
|
||||
btc: result.btc,
|
||||
})
|
||||
}
|
||||
@@ -52,34 +55,64 @@ pub(crate) async fn get_average_price(pool: &DbPool) -> anyhow::Result<PriceHist
|
||||
let earliest_timestamp = Local::now().sub(chrono::Duration::days(1)).timestamp();
|
||||
|
||||
let result = sqlx::query!(
|
||||
"SELECT timestamp, chf, usd, eur, btc FROM price_history WHERE timestamp >= $1;",
|
||||
"SELECT timestamp, chf, usd, eur, gbp, btc FROM price_history WHERE timestamp >= $1;",
|
||||
earliest_timestamp
|
||||
)
|
||||
.fetch_all(pool)
|
||||
.await?;
|
||||
|
||||
let count = result.len() as f64;
|
||||
|
||||
let mut price = PriceHistory {
|
||||
timestamp: Local::now().timestamp(),
|
||||
chf: 0f64,
|
||||
usd: 0f64,
|
||||
eur: 0f64,
|
||||
gbp: 0f64,
|
||||
btc: 0f64,
|
||||
};
|
||||
|
||||
let mut chf_count = 0;
|
||||
let mut usd_count = 0;
|
||||
let mut eur_count = 0;
|
||||
let mut gbp_count = 0;
|
||||
let mut btc_count = 0;
|
||||
|
||||
for p in &result {
|
||||
price.chf += p.chf;
|
||||
price.usd += p.usd;
|
||||
price.eur += p.eur;
|
||||
price.btc += p.btc;
|
||||
if p.chf != 0f64 {
|
||||
price.chf += p.chf;
|
||||
chf_count += 1;
|
||||
}
|
||||
if p.usd != 0f64 {
|
||||
price.usd += p.usd;
|
||||
usd_count += 1;
|
||||
}
|
||||
if p.eur != 0f64 {
|
||||
price.eur += p.eur;
|
||||
eur_count += 1;
|
||||
}
|
||||
if p.gbp != 0f64 {
|
||||
price.gbp += p.gbp;
|
||||
gbp_count += 1;
|
||||
}
|
||||
if p.btc != 0f64 {
|
||||
price.btc += p.btc;
|
||||
btc_count += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if count > 0f64 {
|
||||
price.chf /= count;
|
||||
price.usd /= count;
|
||||
price.eur /= count;
|
||||
price.btc /= count;
|
||||
if chf_count > 0 {
|
||||
price.chf /= chf_count as f64;
|
||||
}
|
||||
if usd_count > 0 {
|
||||
price.usd /= usd_count as f64;
|
||||
}
|
||||
if eur_count > 0 {
|
||||
price.eur /= eur_count as f64;
|
||||
}
|
||||
if gbp_count > 0 {
|
||||
price.gbp /= gbp_count as f64;
|
||||
}
|
||||
if btc_count > 0 {
|
||||
price.btc /= btc_count as f64;
|
||||
}
|
||||
|
||||
Ok(price)
|
||||
|
||||
@@ -11,7 +11,7 @@ use crate::db::DbPool;
|
||||
const REFRESH_DELAY: Duration = Duration::from_secs(300);
|
||||
const FAILURE_RETRY_DELAY: Duration = Duration::from_secs(60 * 2);
|
||||
const COINGECKO_API_URL: &str =
|
||||
"https://api.coingecko.com/api/v3/simple/price?ids=nym&vs_currencies=chf,usd,eur,btc";
|
||||
"https://api.coingecko.com/api/v3/simple/price?ids=nym&vs_currencies=chf,usd,eur,gbp,btc";
|
||||
|
||||
pub(crate) async fn run_price_scraper(db_pool: &DbPool) -> JoinHandle<()> {
|
||||
loop {
|
||||
|
||||
@@ -10,14 +10,14 @@ crate-type = ["cdylib"]
|
||||
|
||||
[dependencies]
|
||||
# Async runtime
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
tokio = { workspace = true, features = ["full"] }
|
||||
# Nym clients, addressing, packet format, common tools (logging), ffi shared
|
||||
nym-sdk = { path = "../../rust/nym-sdk/" }
|
||||
nym-bin-common = { path = "../../../common/bin-common" }
|
||||
nym-sphinx-anonymous-replies = { path = "../../../common/nymsphinx/anonymous-replies" }
|
||||
nym-ffi-shared = { path = "../shared" }
|
||||
lazy_static = "1.5.0"
|
||||
lazy_static = { workspace = true }
|
||||
# error handling
|
||||
anyhow = "1.0.95"
|
||||
anyhow = { workspace = true }
|
||||
# base58 en/decoding
|
||||
bs58 = "0.5.0"
|
||||
bs58 = { workspace = true }
|
||||
|
||||
@@ -10,22 +10,22 @@ name = "nym_go_ffi"
|
||||
|
||||
[dependencies]
|
||||
# Bindgen
|
||||
uniffi = { version = "0.25.2", features = ["cli"] }
|
||||
uniffi = { workspace = true, features = ["cli"] }
|
||||
# Nym clients, addressing, packet format, common tools (logging), ffi shared
|
||||
nym-sdk = { path = "../../rust/nym-sdk/" }
|
||||
nym-bin-common = { path = "../../../common/bin-common" }
|
||||
nym-sphinx-anonymous-replies = { path = "../../../common/nymsphinx/anonymous-replies" }
|
||||
nym-ffi-shared = { path = "../shared" }
|
||||
# Async runtime
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
lazy_static = "1.5.0"
|
||||
tokio = { workspace = true, features = ["full"] }
|
||||
lazy_static = { workspace = true }
|
||||
# error handling
|
||||
anyhow = "1.0.95"
|
||||
anyhow = { workspace = true }
|
||||
thiserror.workspace = true
|
||||
|
||||
[build-dependencies]
|
||||
uniffi = { version = "0.25.2", features = ["build"] }
|
||||
uniffi_build = { version = "0.25.2", features = ["builtin-bindgen"] }
|
||||
uniffi = { workspace = true, features = ["build"] }
|
||||
uniffi_build = { workspace = true, features = ["builtin-bindgen"] }
|
||||
|
||||
[[bin]]
|
||||
name = "uniffi-bindgen"
|
||||
|
||||
@@ -6,20 +6,20 @@ license.workspace = true
|
||||
|
||||
[dependencies]
|
||||
# Async runtime
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
tokio = { workspace = true, features = ["full"] }
|
||||
# Nym clients, addressing, packet format, common tools (logging)
|
||||
nym-sdk = { path = "../../rust/nym-sdk/" }
|
||||
nym-bin-common = { path = "../../../common/bin-common" }
|
||||
nym-sphinx-anonymous-replies = { path = "../../../common/nymsphinx/anonymous-replies" }
|
||||
# static var macro
|
||||
lazy_static = "1.5.0"
|
||||
lazy_static = { workspace = true }
|
||||
# error handling
|
||||
anyhow = "1.0.95"
|
||||
anyhow = { workspace = true }
|
||||
# base58 en/decoding
|
||||
bs58 = "0.5.0"
|
||||
bs58 = { workspace = true }
|
||||
# UDL test
|
||||
uniffi = { version = "0.25.2", features = ["cli"] }
|
||||
uniffi = { workspace = true, features = ["cli"] }
|
||||
|
||||
[build-dependencies]
|
||||
uniffi = { version = "0.25.2", features = ["build"] }
|
||||
uniffi_build = { version = "0.25.2", features = ["builtin-bindgen"] }
|
||||
uniffi = { workspace = true, features = ["build"] }
|
||||
uniffi_build = { workspace = true, features = ["builtin-bindgen"] }
|
||||
|
||||
@@ -53,11 +53,11 @@ dashmap.workspace = true
|
||||
tokio.workspace = true
|
||||
tokio-stream.workspace = true
|
||||
tokio-util.workspace = true
|
||||
uuid = { version = "1", features = ["v4", "serde"] }
|
||||
bincode = "1.0"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
uuid = { workspace = true, features = ["v4", "serde"] }
|
||||
bincode = { workspace = true }
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
tracing.workspace = true
|
||||
tracing-subscriber = { version = "0.3.18", features = ["env-filter"] }
|
||||
tracing-subscriber = { workspace = true, features = ["env-filter"] }
|
||||
dirs.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
|
||||
@@ -29,6 +29,7 @@ use nym_client_core::init::helpers::gateways_for_init;
|
||||
use nym_client_core::init::setup_gateway;
|
||||
use nym_client_core::init::types::{GatewaySelectionSpecification, GatewaySetup};
|
||||
use nym_credentials_interface::TicketType;
|
||||
use nym_crypto::hkdf::DerivationMaterial;
|
||||
use nym_socks5_client_core::config::Socks5;
|
||||
use nym_task::{TaskClient, TaskHandle, TaskStatus};
|
||||
use nym_topology::provider_trait::TopologyProvider;
|
||||
@@ -64,6 +65,7 @@ pub struct MixnetClientBuilder<S: MixnetClientStorage = Ephemeral> {
|
||||
|
||||
storage: S,
|
||||
forget_me: ForgetMe,
|
||||
derivation_material: Option<DerivationMaterial>,
|
||||
}
|
||||
|
||||
impl MixnetClientBuilder<Ephemeral> {
|
||||
@@ -101,6 +103,7 @@ impl MixnetClientBuilder<OnDiskPersistent> {
|
||||
#[cfg(unix)]
|
||||
connection_fd_callback: None,
|
||||
forget_me: Default::default(),
|
||||
derivation_material: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -133,6 +136,7 @@ where
|
||||
gateway_endpoint_config_path: None,
|
||||
storage,
|
||||
forget_me: Default::default(),
|
||||
derivation_material: None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,9 +158,16 @@ where
|
||||
gateway_endpoint_config_path: self.gateway_endpoint_config_path,
|
||||
storage,
|
||||
forget_me: self.forget_me,
|
||||
derivation_material: self.derivation_material,
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn with_derivation_material(mut self, derivation_material: DerivationMaterial) -> Self {
|
||||
self.derivation_material = Some(derivation_material);
|
||||
self
|
||||
}
|
||||
|
||||
/// Change the underlying storage of this builder to use default implementation of on-disk disk_persistence.
|
||||
#[must_use]
|
||||
pub fn set_default_storage(
|
||||
@@ -312,6 +323,7 @@ where
|
||||
client.connection_fd_callback = self.connection_fd_callback;
|
||||
}
|
||||
client.forget_me = self.forget_me;
|
||||
client.derivation_material = self.derivation_material;
|
||||
Ok(client)
|
||||
}
|
||||
}
|
||||
@@ -366,6 +378,9 @@ where
|
||||
connection_fd_callback: Option<Arc<dyn Fn(std::os::fd::RawFd) + Send + Sync>>,
|
||||
|
||||
forget_me: ForgetMe,
|
||||
|
||||
/// The derivation material to use for the client keys, its up to the caller to save this for rederivation later
|
||||
derivation_material: Option<DerivationMaterial>,
|
||||
}
|
||||
|
||||
impl<S> DisconnectedMixnetClient<S>
|
||||
@@ -403,6 +418,8 @@ where
|
||||
None
|
||||
};
|
||||
|
||||
let forget_me = config.debug_config.forget_me;
|
||||
|
||||
Ok(DisconnectedMixnetClient {
|
||||
config,
|
||||
socks5_config,
|
||||
@@ -417,7 +434,8 @@ where
|
||||
user_agent: None,
|
||||
#[cfg(unix)]
|
||||
connection_fd_callback: None,
|
||||
forget_me: Default::default(),
|
||||
forget_me,
|
||||
derivation_material: None,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -641,7 +659,8 @@ where
|
||||
let mut base_builder: BaseClientBuilder<_, _> =
|
||||
BaseClientBuilder::new(base_config, self.storage, self.dkg_query_client)
|
||||
.with_wait_for_gateway(self.wait_for_gateway)
|
||||
.with_forget_me(&self.forget_me);
|
||||
.with_forget_me(&self.forget_me)
|
||||
.with_derivation_material(self.derivation_material);
|
||||
|
||||
if let Some(user_agent) = self.user_agent {
|
||||
base_builder = base_builder.with_user_agent(user_agent);
|
||||
|
||||
@@ -134,6 +134,18 @@ impl StoragePaths {
|
||||
Ok(non_wasm_helpers::setup_fs_gateways_storage(&self.gateway_registrations).await?)
|
||||
}
|
||||
|
||||
pub fn credential_database_paths(&self) -> Vec<PathBuf> {
|
||||
Self::with_sqlite_journal_paths(&self.credential_database_path)
|
||||
}
|
||||
|
||||
pub fn reply_surb_database_paths(&self) -> Vec<PathBuf> {
|
||||
Self::with_sqlite_journal_paths(&self.reply_surb_database_path)
|
||||
}
|
||||
|
||||
pub fn gateway_registrations_paths(&self) -> Vec<PathBuf> {
|
||||
Self::with_sqlite_journal_paths(&self.gateway_registrations)
|
||||
}
|
||||
|
||||
fn client_keys_paths(&self) -> ClientKeysPaths {
|
||||
ClientKeysPaths {
|
||||
private_identity_key_file: self.private_identity.clone(),
|
||||
@@ -143,6 +155,19 @@ impl StoragePaths {
|
||||
ack_key_file: self.ack_key.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a list of paths that include the sqlite database and journal files (wal, shm)
|
||||
fn with_sqlite_journal_paths<P: AsRef<Path>>(db_file: P) -> Vec<PathBuf> {
|
||||
["-shm", "-wal"]
|
||||
.iter()
|
||||
.map(|ext_suffix| {
|
||||
let mut new_ext = db_file.as_ref().extension().unwrap_or_default().to_owned();
|
||||
new_ext.push(ext_suffix);
|
||||
db_file.as_ref().with_extension(new_ext)
|
||||
})
|
||||
.chain([db_file.as_ref().to_path_buf()])
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<StoragePaths> for CommonClientPaths {
|
||||
|
||||
@@ -41,7 +41,7 @@ pub(crate) async fn execute(args: &Run) -> Result<(), AuthenticatorError> {
|
||||
Arc::new(KeyPair::new(&mut OsRng)),
|
||||
);
|
||||
let task_handler = TaskHandle::default();
|
||||
let handler = DummyHandler::new(peer_rx, task_handler.fork("peer-handler"));
|
||||
let handler = DummyHandler::new(peer_rx, task_handler.fork("peer_handler"));
|
||||
tokio::spawn(async move {
|
||||
handler.run().await;
|
||||
});
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
[package]
|
||||
name = "nym-network-requester"
|
||||
license = "GPL-3.0"
|
||||
version = "1.1.48"
|
||||
version = "1.1.50"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
rust-version = "1.70"
|
||||
|
||||
@@ -15,11 +15,11 @@ dashmap.workspace = true
|
||||
tokio = { workspace = true, features = ["full"] }
|
||||
tokio-stream.workspace = true
|
||||
tokio-util.workspace = true
|
||||
uuid = { version = "1", features = ["v4", "serde"] }
|
||||
bincode = "1.0"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
uuid = { workspace = true, features = ["v4", "serde"] }
|
||||
bincode = { workspace = true }
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
tracing.workspace = true
|
||||
tracing-subscriber = "0.3"
|
||||
tracing-subscriber = { workspace = true }
|
||||
bytecodec = { workspace = true }
|
||||
nym-sdk = { path = "../../sdk/rust/nym-sdk/" }
|
||||
bytes.workspace = true
|
||||
|
||||
@@ -14,7 +14,7 @@ readme.workspace = true
|
||||
crate-type = ["cdylib", "rlib"]
|
||||
|
||||
[dependencies]
|
||||
base85rs = "0.1.3"
|
||||
base85rs = { workspace = true }
|
||||
cosmwasm-std = { workspace = true }
|
||||
cosmwasm-storage = { workspace = true }
|
||||
cosmwasm-schema = { workspace = true }
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "nym-cli"
|
||||
version = "1.1.47"
|
||||
version = "1.1.49"
|
||||
authors.workspace = true
|
||||
edition = "2021"
|
||||
license.workspace = true
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "nymvisor"
|
||||
version = "0.1.12"
|
||||
version = "0.1.14"
|
||||
authors.workspace = true
|
||||
repository.workspace = true
|
||||
homepage.workspace = true
|
||||
|
||||
@@ -190,12 +190,15 @@ impl NymNodeTesterBuilder {
|
||||
|
||||
let gateway_identity = gateway_info.gateway_id;
|
||||
|
||||
let mut stats_sender_task = task_manager.subscribe().named("stats_sender");
|
||||
stats_sender_task.disarm();
|
||||
|
||||
let mut gateway_client =
|
||||
if let Some(existing_client) = initialisation_result.authenticated_ephemeral_client {
|
||||
existing_client.upgrade(
|
||||
packet_router,
|
||||
self.bandwidth_controller.take(),
|
||||
ClientStatsSender::new(None),
|
||||
ClientStatsSender::new(None, stats_sender_task),
|
||||
gateway_task,
|
||||
)
|
||||
} else {
|
||||
@@ -211,7 +214,7 @@ impl NymNodeTesterBuilder {
|
||||
Some(gateway_info.shared_key),
|
||||
packet_router,
|
||||
self.bandwidth_controller.take(),
|
||||
ClientStatsSender::new(None),
|
||||
ClientStatsSender::new(None, stats_sender_task),
|
||||
gateway_task,
|
||||
)
|
||||
};
|
||||
|
||||
@@ -10,7 +10,7 @@ use crate::vpn_api_client::types::{
|
||||
use async_trait::async_trait;
|
||||
use nym_coconut::BlindSignRequest;
|
||||
pub use nym_http_api_client::Client;
|
||||
use nym_http_api_client::{parse_response, PathSegments, NO_PARAMS};
|
||||
use nym_http_api_client::{parse_response, ApiClient, PathSegments, NO_PARAMS};
|
||||
use reqwest::IntoUrl;
|
||||
use serde::de::DeserializeOwned;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user