Compare commits

...

23 Commits

Author SHA1 Message Date
Jon Häggblad 424e94a04e Send shutdown instead of panic when reaching max fail (#5398)
* Send shutdown instead of panic when reaching max fail

* Stop quicker on failure

* Update comment
2025-02-03 17:28:10 +02:00
benedetta davico d1fb926a2a Merge pull request #5405 from nymtech/downgrade-to-debug
HU - Downgrade harmless log message from info to debug
2025-01-30 11:34:14 +01:00
benedettadavico dea69acd49 Downgrade harmless log message from info to debug 2025-01-30 11:32:54 +01:00
Tommy Verrall ada2d2247a Merge pull request #5404 from nymtech/jstuczyn-patch-1
lower default ticket verification quorum to 0.7
2025-01-30 11:28:32 +01:00
Jędrzej Stuczyński 0159d7c27a lower default ticket verification quorum to 0.7 2025-01-30 10:16:41 +00:00
benedettadavico 28997c7f97 adding changelog for hu 2025-01-28 09:02:54 +01:00
Jędrzej Stuczyński a6c586a33b chore :update version of chain watcher and validator rewarder (#5394) 2025-01-27 15:47:37 +00:00
Jędrzej Stuczyński 7c85c1a271 bugfix: correctly handle ingore epoch roles flag (#5390) 2025-01-24 15:35:06 +00:00
Jędrzej Stuczyński 92c8d1b73f bugfix: terminate mixnet socket listener on shutdown (#5389) 2025-01-24 12:59:14 +00:00
Jędrzej Stuczyński 554e9ca490 feat: make client ignore dual mode nodes by default (#5388) 2025-01-24 12:07:25 +00:00
Bogdan-Ștefan Neacşu 6e6675f7bf Handle ecash network errors differently (#5378) 2025-01-22 15:46:05 +01:00
Bogdan-Ștefan Neacşu a7f7ebfbae Remove empty ephemeral keys (#5376) 2025-01-22 12:11:01 +01:00
Jędrzej Stuczyński 1aec8be85e fixed sql migration for adding default message timestamp (#5374) 2025-01-21 10:00:11 +00:00
benedettadavico 4b474dd8ff bump versions for hu 2025-01-20 15:34:23 +01:00
benedetta davico 9b627dd70f Merge pull request #5363 from nymtech/fix-ci 2025-01-17 11:35:04 +01:00
Bogdan-Ștefan Neacşu 9a0b769425 Bind to [::] on nym-node for both IP versions (#5361)
* Bind to [::] on nym-node for both IP versions

* Force update to be run

* Fix after merging develop
2025-01-17 11:32:33 +01:00
Sachin Kamath 8e14f5f884 Update ci-build-upload-binaries.yml
remove observatory
2025-01-17 15:11:53 +05:30
import this 1b64cb42b0 [DOCs/operators]: Guides, changes and release-notes for v2025.1-reeses (#5340)
* create ToC snippet

* fund node client account

* revamp node guide

* finish setup page revamp

* add new update to changelog

* fix wallet dowload uls

* fix operator steps urls

* fix operator steps urls

* fix operator steps urls

* finish release notes

* finish changelog

* debug build

* correct links syntax

* add remote mnemonic pull command
2025-01-16 15:23:58 +00:00
Jędrzej Stuczyński 03c4895f2b feature: introduce /load endpoint for self-reported quantised NymNode load (#5326)
* feature: introduce /load endpoint for self-reported quantised NymNode load

* return Load::Unknown for value of 0 because it means we misread some data

* add additional filtering on 'en...' endpoints
2025-01-16 15:13:08 +00:00
Jędrzej Stuczyński dcfb092758 updated cosmrs and tendermint-rpc to their most recent versions (#5339) 2025-01-16 14:52:36 +00:00
Jędrzej Stuczyński 9305ad5364 exposed NymApiClient method for obtaining node performance history (#5360)
* exposed NymApiClient method for obtaining node performance history

* using path constants for route definition
2025-01-16 14:50:09 +00:00
Jędrzej Stuczyński ea5aef6c2f Client gateway selection (#5358)
* filter out dual-role gateways during selection

* changed behaviour of egress node validitiy
2025-01-16 14:24:27 +00:00
Jędrzej Stuczyński 61a4433cd9 chore: update indexed_db_futures (#5347)
* chore: update indexed_db_futures

* clippy
2025-01-16 14:23:43 +00:00
88 changed files with 3624 additions and 547 deletions
@@ -79,7 +79,6 @@ jobs:
target/release/nym-socks5-client
target/release/nym-api
target/release/nym-network-requester
target/release/nym-data-observatory
target/release/nym-cli
target/release/nymvisor
target/release/nym-node
@@ -97,7 +96,6 @@ jobs:
cp target/release/nym-socks5-client $OUTPUT_DIR
cp target/release/nym-api $OUTPUT_DIR
cp target/release/nym-network-requester $OUTPUT_DIR
cp target/release/nym-data-observatory $OUTPUT_DIR
cp target/release/nymvisor $OUTPUT_DIR
cp target/release/nym-node $OUTPUT_DIR
cp target/release/nym-cli $OUTPUT_DIR
+70
View File
@@ -4,6 +4,76 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
## [Unreleased]
## [2025.2-hu] (2025-01-28)
- chore :update version of chain watcher and validator rewarder ([#5394])
- bugfix: correctly handle ingore epoch roles flag ([#5390])
- bugfix: terminate mixnet socket listener on shutdown ([#5389])
- feat: make client ignore dual mode nodes by default ([#5388])
- Handle ecash network errors differently ([#5378])
- Remove empty ephemeral keys ([#5376])
- fixed sql migration for adding default message timestamp ([#5374])
- Bind to [::] on nym-node for both IP versions ([#5361])
- exposed NymApiClient method for obtaining node performance history ([#5360])
- Client gateway selection ([#5358])
- chore: refresh wasm sdk ([#5353])
- chore: update indexed_db_futures ([#5347])
- build(deps): bump mikefarah/yq from 4.44.6 to 4.45.1 ([#5342])
- updated cosmrs and tendermint-rpc to their most recent versions ([#5339])
- build(deps): bump ts-rs from 10.0.0 to 10.1.0 ([#5338])
- build(deps): bump tempfile from 3.14.0 to 3.15.0 ([#5337])
- build(deps): bump the patch-updates group with 8 updates ([#5336])
- feature: introduce /load endpoint for self-reported quantised NymNode load ([#5326])
- feature: `CancellationToken`-based shutdowns ([#5325])
- Use expect in geodata test to give error message on failure ([#5314])
- feature: periodically remove stale gateway messages ([#5312])
- build(deps): bump the patch-updates group across 1 directory with 35 updates ([#5310])
- Add dependabot assignes for the root cargo ecosystem ([#5297])
- Move tun constants to network defaults ([#5286])
- Include IPINFO_API_TOKEN in nightly CI ([#5285])
- Nyx Chain Watcher ([#5274])
- bugfix: remove unnecessary arguments for nym-api swagger endpoints ([#5272])
- feature: nym topology revamp ([#5271])
- Add windows to CI builds ([#5269])
- http-api-client: deduplicate code ([#5267])
- build(deps): bump http from 1.1.0 to 1.2.0 ([#5228])
- NS API: add mixnet scraper ([#5200])
- build(deps): bump criterion from 0.4.0 to 0.5.1 ([#4911])
[#5394]: https://github.com/nymtech/nym/pull/5394
[#5390]: https://github.com/nymtech/nym/pull/5390
[#5389]: https://github.com/nymtech/nym/pull/5389
[#5388]: https://github.com/nymtech/nym/pull/5388
[#5378]: https://github.com/nymtech/nym/pull/5378
[#5376]: https://github.com/nymtech/nym/pull/5376
[#5374]: https://github.com/nymtech/nym/pull/5374
[#5361]: https://github.com/nymtech/nym/pull/5361
[#5360]: https://github.com/nymtech/nym/pull/5360
[#5358]: https://github.com/nymtech/nym/pull/5358
[#5353]: https://github.com/nymtech/nym/pull/5353
[#5347]: https://github.com/nymtech/nym/pull/5347
[#5342]: https://github.com/nymtech/nym/pull/5342
[#5339]: https://github.com/nymtech/nym/pull/5339
[#5338]: https://github.com/nymtech/nym/pull/5338
[#5337]: https://github.com/nymtech/nym/pull/5337
[#5336]: https://github.com/nymtech/nym/pull/5336
[#5326]: https://github.com/nymtech/nym/pull/5326
[#5325]: https://github.com/nymtech/nym/pull/5325
[#5314]: https://github.com/nymtech/nym/pull/5314
[#5312]: https://github.com/nymtech/nym/pull/5312
[#5310]: https://github.com/nymtech/nym/pull/5310
[#5297]: https://github.com/nymtech/nym/pull/5297
[#5286]: https://github.com/nymtech/nym/pull/5286
[#5285]: https://github.com/nymtech/nym/pull/5285
[#5274]: https://github.com/nymtech/nym/pull/5274
[#5272]: https://github.com/nymtech/nym/pull/5272
[#5271]: https://github.com/nymtech/nym/pull/5271
[#5269]: https://github.com/nymtech/nym/pull/5269
[#5267]: https://github.com/nymtech/nym/pull/5267
[#5228]: https://github.com/nymtech/nym/pull/5228
[#5200]: https://github.com/nymtech/nym/pull/5200
[#4911]: https://github.com/nymtech/nym/pull/4911
## [2025.1-reeses] (2025-01-15)
- Feture/legacy alert ([#5346])
Generated
+243 -110
View File
@@ -4,9 +4,9 @@ version = 3
[[package]]
name = "accessory"
version = "1.3.1"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87537f9ae7cfa78d5b8ebd1a1db25959f5e737126be4d8eb44a5452fc4b63cde"
checksum = "bb3791c4beae5b827e93558ac83a88e63a841aad61759a05d9b577ef16030470"
dependencies = [
"macroific",
"proc-macro2",
@@ -232,6 +232,12 @@ dependencies = [
"derive_arbitrary",
]
[[package]]
name = "arc-swap"
version = "1.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457"
[[package]]
name = "argon2"
version = "0.5.3"
@@ -473,7 +479,7 @@ dependencies = [
"axum-macros",
"bytes",
"futures-util",
"http 1.2.0",
"http 1.1.0",
"http-body 1.0.0",
"http-body-util",
"hyper 1.4.1",
@@ -534,7 +540,7 @@ dependencies = [
"async-trait",
"bytes",
"futures-util",
"http 1.2.0",
"http 1.1.0",
"http-body 1.0.0",
"http-body-util",
"mime",
@@ -557,7 +563,7 @@ dependencies = [
"bytes",
"futures-util",
"headers",
"http 1.2.0",
"http 1.1.0",
"http-body 1.0.0",
"http-body-util",
"mime",
@@ -592,7 +598,7 @@ dependencies = [
"axum 0.7.7",
"bytes",
"cookie",
"http 1.2.0",
"http 1.1.0",
"http-body-util",
"hyper 1.4.1",
"hyper-util",
@@ -1100,9 +1106,9 @@ dependencies = [
[[package]]
name = "clap_complete"
version = "4.5.42"
version = "4.5.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "33a7e468e750fa4b6be660e8b5651ad47372e8fb114030b594c2d75d48c5ffd0"
checksum = "ac2e663e3e3bed2d32d065a8404024dad306e699a04263ec59919529f803aee9"
dependencies = [
"clap",
]
@@ -1292,9 +1298,9 @@ dependencies = [
[[package]]
name = "core-foundation-sys"
version = "0.8.6"
version = "0.8.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f"
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
[[package]]
name = "cosmos-sdk-proto"
@@ -1309,12 +1315,12 @@ dependencies = [
[[package]]
name = "cosmos-sdk-proto"
version = "0.22.0-pre"
source = "git+https://github.com/cosmos/cosmos-rust?rev=4b1332e6d8258ac845cef71589c8d362a669675a#4b1332e6d8258ac845cef71589c8d362a669675a"
version = "0.26.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "462e1f6a8e005acc8835d32d60cbd7973ed65ea2a8d8473830e675f050956427"
dependencies = [
"prost 0.12.6",
"prost-types 0.12.6",
"tendermint-proto 0.37.0",
"prost 0.13.4",
"tendermint-proto 0.40.1",
]
[[package]]
@@ -1339,11 +1345,12 @@ dependencies = [
[[package]]
name = "cosmrs"
version = "0.17.0-pre"
source = "git+https://github.com/cosmos/cosmos-rust?rev=4b1332e6d8258ac845cef71589c8d362a669675a#4b1332e6d8258ac845cef71589c8d362a669675a"
version = "0.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "210fbe6f98594963b46cc980f126a9ede5db9a3848ca65b71303bebdb01afcd9"
dependencies = [
"bip32",
"cosmos-sdk-proto 0.22.0-pre",
"cosmos-sdk-proto 0.26.1",
"ecdsa",
"eyre",
"k256",
@@ -1352,7 +1359,7 @@ dependencies = [
"serde_json",
"signature",
"subtle-encoding",
"tendermint 0.37.0",
"tendermint 0.40.1",
"tendermint-rpc",
"thiserror 1.0.69",
]
@@ -1955,10 +1962,12 @@ dependencies = [
[[package]]
name = "delegate-display"
version = "2.1.1"
version = "3.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "98a85201f233142ac819bbf6226e36d0b5e129a47bd325084674261c82d4cd66"
checksum = "9926686c832494164c33a36bf65118f4bd6e704000b58c94681bf62e9ad67a74"
dependencies = [
"impartial-ord",
"itoa",
"macroific",
"proc-macro2",
"quote",
@@ -2008,6 +2017,27 @@ dependencies = [
"syn 2.0.90",
]
[[package]]
name = "derive_more"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a9b99b9cbbe49445b21764dc0625032a89b145a2642e67603e1c936f5458d05"
dependencies = [
"derive_more-impl",
]
[[package]]
name = "derive_more-impl"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.90",
"unicode-xid",
]
[[package]]
name = "devise"
version = "0.4.1"
@@ -2382,7 +2412,7 @@ dependencies = [
[[package]]
name = "explorer-api"
version = "1.1.44"
version = "1.1.45"
dependencies = [
"chrono",
"clap",
@@ -2449,9 +2479,9 @@ checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7"
[[package]]
name = "fancy_constructor"
version = "1.3.0"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07b19d0e43eae2bfbafe4931b5e79c73fb1a849ca15cd41a761a7b8587f9a1a2"
checksum = "fac0fd7f4636276b4bd7b3148d0ba2c1c3fbede2b5214e47e7fedb70b02cde44"
dependencies = [
"macroific",
"proc-macro2",
@@ -2843,7 +2873,7 @@ dependencies = [
"futures-core",
"futures-sink",
"gloo-utils 0.2.0",
"http 1.2.0",
"http 1.1.0",
"js-sys",
"pin-project",
"serde",
@@ -3013,7 +3043,7 @@ dependencies = [
"base64 0.21.7",
"bytes",
"headers-core",
"http 1.2.0",
"http 1.1.0",
"httpdate",
"mime",
"sha1",
@@ -3025,7 +3055,7 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "54b4a22553d4242c49fddb9ba998a99962b5cc6f22cb5a3482bec22522403ce4"
dependencies = [
"http 1.2.0",
"http 1.1.0",
]
[[package]]
@@ -3145,9 +3175,9 @@ dependencies = [
[[package]]
name = "http"
version = "1.2.0"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f16ca2af56261c99fba8bac40a10251ce8188205a4c448fbb745a2e4daa76fea"
checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258"
dependencies = [
"bytes",
"fnv",
@@ -3172,7 +3202,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643"
dependencies = [
"bytes",
"http 1.2.0",
"http 1.1.0",
]
[[package]]
@@ -3183,7 +3213,7 @@ checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f"
dependencies = [
"bytes",
"futures-util",
"http 1.2.0",
"http 1.1.0",
"http-body 1.0.0",
"pin-project-lite",
]
@@ -3280,7 +3310,7 @@ dependencies = [
"bytes",
"futures-channel",
"futures-util",
"http 1.2.0",
"http 1.1.0",
"http-body 1.0.0",
"httparse",
"httpdate",
@@ -3312,7 +3342,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a0bea761b46ae2b24eb4aef630d8d1c398157b6fc29e6350ecf090a0b70c952c"
dependencies = [
"futures-util",
"http 1.2.0",
"http 1.1.0",
"hyper 1.4.1",
"hyper-util",
"rustls 0.22.4",
@@ -3343,7 +3373,7 @@ dependencies = [
"bytes",
"futures-channel",
"futures-util",
"http 1.2.0",
"http 1.1.0",
"http-body 1.0.0",
"hyper 1.4.1",
"pin-project-lite",
@@ -3531,6 +3561,17 @@ dependencies = [
"icu_properties",
]
[[package]]
name = "impartial-ord"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ab604ee7085efba6efc65e4ebca0e9533e3aff6cb501d7d77b211e3a781c6d5"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.90",
]
[[package]]
name = "importer-cli"
version = "0.1.0"
@@ -3569,21 +3610,38 @@ checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683"
[[package]]
name = "indexed_db_futures"
version = "0.4.2"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0704b71f13f81b5933d791abf2de26b33c40935143985220299a357721166706"
checksum = "d56078e9bfed55e1d3c0cebad5be921d32f062be8f1e4bf3750b487bc6e7d13e"
dependencies = [
"accessory",
"cfg-if",
"delegate-display",
"derive_more",
"fancy_constructor",
"indexed_db_futures_macros_internal",
"js-sys",
"uuid",
"sealed",
"smallvec",
"thiserror 1.0.69",
"tokio",
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
]
[[package]]
name = "indexed_db_futures_macros_internal"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "caeba94923b68f254abef921cea7e7698bf4675fdd89d7c58bf1ed885b49a27d"
dependencies = [
"macroific",
"proc-macro2",
"quote",
"syn 2.0.90",
]
[[package]]
name = "indexmap"
version = "1.9.3"
@@ -3990,9 +4048,9 @@ checksum = "9374ef4228402d4b7e403e5838cb880d9ee663314b0a900d5a6aabf0c213552e"
[[package]]
name = "log"
version = "0.4.25"
version = "0.4.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f"
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
[[package]]
name = "loom"
@@ -4030,9 +4088,9 @@ checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4"
[[package]]
name = "macroific"
version = "1.3.1"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f05c00ac596022625d01047c421a0d97d7f09a18e429187b341c201cb631b9dd"
checksum = "89f276537b4b8f981bf1c13d79470980f71134b7bdcc5e6e911e910e556b0285"
dependencies = [
"macroific_attr_parse",
"macroific_core",
@@ -4041,32 +4099,33 @@ dependencies = [
[[package]]
name = "macroific_attr_parse"
version = "1.3.0"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd94d5da95b30ae6e10621ad02340909346ad91661f3f8c0f2b62345e46a2f67"
checksum = "ad4023761b45fcd36abed8fb7ae6a80456b0a38102d55e89a57d9a594a236be9"
dependencies = [
"cfg-if",
"proc-macro2",
"quote",
"sealed",
"syn 2.0.90",
]
[[package]]
name = "macroific_core"
version = "1.0.2"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13198c120864097a565ccb3ff947672d969932b7975ebd4085732c9f09435e55"
checksum = "d0a7594d3c14916fa55bef7e9d18c5daa9ed410dd37504251e4b75bbdeec33e3"
dependencies = [
"proc-macro2",
"quote",
"sealed",
"syn 2.0.90",
]
[[package]]
name = "macroific_macro"
version = "1.1.0"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b0c9853143cbed7f1e41dc39fee95f9b361bec65c8dc2a01bf609be01b61f5ae"
checksum = "4da6f2ed796261b0a74e2b52b42c693bb6dee1effba3a482c49592659f824b3b"
dependencies = [
"macroific_attr_parse",
"macroific_core",
@@ -4567,7 +4626,7 @@ checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3"
[[package]]
name = "nym-api"
version = "1.1.48"
version = "1.1.49"
dependencies = [
"anyhow",
"async-trait",
@@ -4657,7 +4716,7 @@ name = "nym-api-requests"
version = "0.1.0"
dependencies = [
"bs58",
"cosmrs 0.17.0-pre",
"cosmrs 0.21.0",
"cosmwasm-std",
"ecdsa",
"getset",
@@ -4676,7 +4735,7 @@ dependencies = [
"serde",
"serde_json",
"sha2 0.10.8",
"tendermint 0.37.0",
"tendermint 0.40.1",
"thiserror 1.0.69",
"time",
"ts-rs",
@@ -4804,7 +4863,7 @@ name = "nym-bity-integration"
version = "0.1.0"
dependencies = [
"anyhow",
"cosmrs 0.17.0-pre",
"cosmrs 0.21.0",
"eyre",
"k256",
"nym-cli-commands",
@@ -4816,7 +4875,7 @@ dependencies = [
[[package]]
name = "nym-cli"
version = "1.1.46"
version = "1.1.47"
dependencies = [
"anyhow",
"base64 0.22.1",
@@ -4851,7 +4910,7 @@ dependencies = [
"clap",
"colored",
"comfy-table",
"cosmrs 0.17.0-pre",
"cosmrs 0.21.0",
"cosmwasm-std",
"csv",
"cw-utils",
@@ -4899,7 +4958,7 @@ dependencies = [
[[package]]
name = "nym-client"
version = "1.1.46"
version = "1.1.47"
dependencies = [
"bs58",
"clap",
@@ -5017,7 +5076,7 @@ name = "nym-client-core-gateways-storage"
version = "0.1.0"
dependencies = [
"async-trait",
"cosmrs 0.17.0-pre",
"cosmrs 0.21.0",
"log",
"nym-crypto",
"nym-gateway-requests",
@@ -5337,7 +5396,7 @@ version = "0.1.0"
dependencies = [
"bincode",
"bls12_381",
"cosmrs 0.17.0-pre",
"cosmrs 0.21.0",
"log",
"nym-api-requests",
"nym-credentials-interface",
@@ -5689,7 +5748,7 @@ name = "nym-http-api-client"
version = "0.1.0"
dependencies = [
"async-trait",
"http 1.2.0",
"http 1.1.0",
"nym-bin-common",
"reqwest 0.12.4",
"serde",
@@ -5963,7 +6022,7 @@ dependencies = [
[[package]]
name = "nym-network-requester"
version = "1.1.47"
version = "1.1.48"
dependencies = [
"addr",
"anyhow",
@@ -6014,9 +6073,10 @@ dependencies = [
[[package]]
name = "nym-node"
version = "1.3.0"
version = "1.4.0"
dependencies = [
"anyhow",
"arc-swap",
"async-trait",
"axum 0.7.7",
"axum-extra",
@@ -6100,7 +6160,6 @@ name = "nym-node-requests"
version = "0.1.0"
dependencies = [
"async-trait",
"base64 0.22.1",
"celes",
"humantime 2.1.0",
"humantime-serde",
@@ -6113,6 +6172,7 @@ dependencies = [
"schemars",
"serde",
"serde_json",
"strum 0.26.3",
"thiserror 1.0.69",
"time",
"tokio",
@@ -6310,7 +6370,7 @@ dependencies = [
"dotenvy",
"futures",
"hex",
"http 1.2.0",
"http 1.1.0",
"httpcodec",
"log",
"nym-bandwidth-controller",
@@ -6387,7 +6447,7 @@ dependencies = [
[[package]]
name = "nym-socks5-client"
version = "1.1.46"
version = "1.1.47"
dependencies = [
"bs58",
"clap",
@@ -6753,7 +6813,7 @@ name = "nym-types"
version = "1.0.0"
dependencies = [
"base64 0.22.1",
"cosmrs 0.17.0-pre",
"cosmrs 0.21.0",
"cosmwasm-std",
"eyre",
"hmac",
@@ -6787,7 +6847,7 @@ dependencies = [
"bip32",
"bip39",
"colored",
"cosmrs 0.17.0-pre",
"cosmrs 0.21.0",
"cosmwasm-std",
"cw-controllers",
"cw-utils",
@@ -6812,7 +6872,7 @@ dependencies = [
"nym-network-defaults",
"nym-serde-helpers",
"nym-vesting-contract-common",
"prost 0.12.6",
"prost 0.13.4",
"reqwest 0.12.4",
"serde",
"serde_json",
@@ -6830,7 +6890,7 @@ dependencies = [
[[package]]
name = "nym-validator-rewarder"
version = "0.2.0"
version = "0.2.1"
dependencies = [
"anyhow",
"bip39",
@@ -6992,7 +7052,7 @@ dependencies = [
[[package]]
name = "nymvisor"
version = "0.1.11"
version = "0.1.12"
dependencies = [
"anyhow",
"bytes",
@@ -7022,7 +7082,7 @@ dependencies = [
[[package]]
name = "nyx-chain-watcher"
version = "0.1.8"
version = "0.1.9"
dependencies = [
"anyhow",
"async-trait",
@@ -7060,14 +7120,14 @@ version = "0.1.0"
dependencies = [
"async-trait",
"const_format",
"cosmrs 0.17.0-pre",
"cosmrs 0.21.0",
"eyre",
"futures",
"humantime 2.1.0",
"serde",
"sha2 0.10.8",
"sqlx",
"tendermint 0.37.0",
"tendermint 0.40.1",
"tendermint-rpc",
"thiserror 1.0.69",
"time",
@@ -7503,18 +7563,18 @@ dependencies = [
[[package]]
name = "pin-project"
version = "1.1.8"
version = "1.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e2ec53ad785f4d35dac0adea7f7dc6f1bb277ad84a680c7afefeae05d1f5916"
checksum = "be57f64e946e500c8ee36ef6331845d40a93055567ec57e8fae13efd33759b95"
dependencies = [
"pin-project-internal",
]
[[package]]
name = "pin-project-internal"
version = "1.1.8"
version = "1.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d56a66c0c55993aa927429d0f8a0abfd74f084e4d9c192cffed01e418d83eefb"
checksum = "3c0f5fad0874fc7abcd4d750e76917eaebbecaa2c20bde22e1dbeeba8beb758c"
dependencies = [
"proc-macro2",
"quote",
@@ -7523,9 +7583,9 @@ dependencies = [
[[package]]
name = "pin-project-lite"
version = "0.2.16"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b"
checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff"
[[package]]
name = "pin-utils"
@@ -7785,6 +7845,16 @@ dependencies = [
"prost-derive 0.12.6",
]
[[package]]
name = "prost"
version = "0.13.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c0fef6c4230e4ccf618a35c59d7ede15dea37de8427500f50aff708806e42ec"
dependencies = [
"bytes",
"prost-derive 0.13.4",
]
[[package]]
name = "prost-derive"
version = "0.11.9"
@@ -7811,6 +7881,19 @@ dependencies = [
"syn 2.0.90",
]
[[package]]
name = "prost-derive"
version = "0.13.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "157c5a9d7ea5c2ed2d9fb8f495b64759f7816c7eaea54ba3978f0d63000162e3"
dependencies = [
"anyhow",
"itertools 0.13.0",
"proc-macro2",
"quote",
"syn 2.0.90",
]
[[package]]
name = "prost-types"
version = "0.11.9"
@@ -8115,7 +8198,7 @@ dependencies = [
"bytes",
"futures-core",
"futures-util",
"http 1.2.0",
"http 1.1.0",
"http-body 1.0.0",
"http-body-util",
"hyper 1.4.1",
@@ -8631,6 +8714,17 @@ dependencies = [
"untrusted",
]
[[package]]
name = "sealed"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22f968c5ea23d555e670b449c1c5e7b2fc399fdaec1d304a17cd48e288abc107"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.90",
]
[[package]]
name = "sec1"
version = "0.7.3"
@@ -9580,17 +9674,16 @@ dependencies = [
[[package]]
name = "sysinfo"
version = "0.30.13"
version = "0.33.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0a5b4ddaee55fb2bea2bf0e5000747e5f5c0de765e5a5ff87f4cd106439f4bb3"
checksum = "4fc858248ea01b66f19d8e8a6d55f41deaf91e9d495246fd01368d99935c6c01"
dependencies = [
"cfg-if",
"core-foundation-sys",
"libc",
"memchr",
"ntapi",
"once_cell",
"rayon",
"windows 0.52.0",
"windows 0.57.0",
]
[[package]]
@@ -9684,9 +9777,9 @@ dependencies = [
[[package]]
name = "tendermint"
version = "0.37.0"
version = "0.40.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "954496fbc9716eb4446cdd6d00c071a3e2f22578d62aa03b40c7e5b4fda3ed42"
checksum = "d9703e34d940c2a293804752555107f8dbe2b84ec4c6dd5203831235868105d2"
dependencies = [
"bytes",
"digest 0.10.7",
@@ -9697,8 +9790,7 @@ dependencies = [
"k256",
"num-traits",
"once_cell",
"prost 0.12.6",
"prost-types 0.12.6",
"prost 0.13.4",
"ripemd",
"serde",
"serde_bytes",
@@ -9708,21 +9800,21 @@ dependencies = [
"signature",
"subtle 2.5.0",
"subtle-encoding",
"tendermint-proto 0.37.0",
"tendermint-proto 0.40.1",
"time",
"zeroize",
]
[[package]]
name = "tendermint-config"
version = "0.37.0"
version = "0.40.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f84b11b57d20ee4492a1452faff85f5c520adc36ca9fe5e701066935255bb89f"
checksum = "89cc3ea9a39b7ee34eefcff771cc067ecaa0c988c1c5ac08defd878471a06f76"
dependencies = [
"flex-error",
"serde",
"serde_json",
"tendermint 0.37.0",
"tendermint 0.40.1",
"toml 0.8.19",
"url",
]
@@ -9747,14 +9839,13 @@ dependencies = [
[[package]]
name = "tendermint-proto"
version = "0.37.0"
version = "0.40.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc87024548c7f3da479885201e3da20ef29e85a3b13d04606b380ac4c7120d87"
checksum = "9ae9e1705aa0fa5ecb2c6aa7fb78c2313c4a31158ea5f02048bf318f849352eb"
dependencies = [
"bytes",
"flex-error",
"prost 0.12.6",
"prost-types 0.12.6",
"prost 0.13.4",
"serde",
"serde_bytes",
"subtle-encoding",
@@ -9763,9 +9854,9 @@ dependencies = [
[[package]]
name = "tendermint-rpc"
version = "0.37.0"
version = "0.40.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dfdc2281e271277fda184d96d874a6fe59f569b130b634289257baacfc95aa85"
checksum = "835a52aa504c63ec05519e31348d3f4ba2fe79493c588e2cad5323d5e81b161a"
dependencies = [
"async-trait",
"async-tungstenite",
@@ -9783,9 +9874,9 @@ dependencies = [
"serde_json",
"subtle 2.5.0",
"subtle-encoding",
"tendermint 0.37.0",
"tendermint 0.40.1",
"tendermint-config",
"tendermint-proto 0.37.0",
"tendermint-proto 0.40.1",
"thiserror 1.0.69",
"time",
"tokio",
@@ -10278,7 +10369,7 @@ dependencies = [
"bitflags 2.5.0",
"bytes",
"futures-util",
"http 1.2.0",
"http 1.1.0",
"http-body 1.0.0",
"http-body-util",
"http-range-header",
@@ -10544,7 +10635,7 @@ dependencies = [
"byteorder",
"bytes",
"data-encoding",
"http 1.2.0",
"http 1.1.0",
"httparse",
"log",
"rand",
@@ -10941,7 +11032,6 @@ checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314"
dependencies = [
"getrandom",
"serde",
"wasm-bindgen",
]
[[package]]
@@ -11144,7 +11234,7 @@ name = "wasm-storage"
version = "0.1.0"
dependencies = [
"async-trait",
"futures",
"getrandom",
"indexed_db_futures",
"js-sys",
"nym-store-cipher",
@@ -11304,11 +11394,11 @@ dependencies = [
[[package]]
name = "windows"
version = "0.52.0"
version = "0.57.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be"
checksum = "12342cb4d8e3b046f3d80effd474a7a02447231330ef77d71daa6fbc40681143"
dependencies = [
"windows-core 0.52.0",
"windows-core 0.57.0",
"windows-targets 0.52.6",
]
@@ -11331,19 +11421,42 @@ dependencies = [
"windows-targets 0.52.6",
]
[[package]]
name = "windows-core"
version = "0.57.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2ed2439a290666cd67ecce2b0ffaad89c2a56b976b736e6ece670297897832d"
dependencies = [
"windows-implement 0.57.0",
"windows-interface 0.57.0",
"windows-result 0.1.2",
"windows-targets 0.52.6",
]
[[package]]
name = "windows-core"
version = "0.58.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99"
dependencies = [
"windows-implement",
"windows-interface",
"windows-result",
"windows-implement 0.58.0",
"windows-interface 0.58.0",
"windows-result 0.2.0",
"windows-strings",
"windows-targets 0.52.6",
]
[[package]]
name = "windows-implement"
version = "0.57.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.90",
]
[[package]]
name = "windows-implement"
version = "0.58.0"
@@ -11355,6 +11468,17 @@ dependencies = [
"syn 2.0.90",
]
[[package]]
name = "windows-interface"
version = "0.57.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.90",
]
[[package]]
name = "windows-interface"
version = "0.58.0"
@@ -11366,6 +11490,15 @@ dependencies = [
"syn 2.0.90",
]
[[package]]
name = "windows-result"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8"
dependencies = [
"windows-targets 0.52.6",
]
[[package]]
name = "windows-result"
version = "0.2.0"
@@ -11381,7 +11514,7 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10"
dependencies = [
"windows-result",
"windows-result 0.2.0",
"windows-targets 0.52.6",
]
+8 -10
View File
@@ -194,6 +194,7 @@ aes-gcm = "0.10.1"
aes-gcm-siv = "0.11.1"
aead = "0.5.2"
anyhow = "1.0.95"
arc-swap = "1.7.1"
argon2 = "0.5.0"
async-trait = "0.1.85"
axum-client-ip = "0.6.1"
@@ -324,7 +325,7 @@ strum = "0.26"
strum_macros = "0.26"
subtle-encoding = "0.5"
syn = "1"
sysinfo = "0.30.13"
sysinfo = "0.33.0"
tap = "1.0.1"
tar = "0.4.43"
tempfile = "3.15"
@@ -386,20 +387,17 @@ cw-controllers = { version = "=1.1.0" }
# cosmrs-related
bip32 = { version = "0.5.2", default-features = false }
# temporarily using a fork again (yay.) because we need staking and slashing support (which are already on main but not released)
# plus response message parsing (which is, as of the time of writing this message, waiting to get merged)
#cosmrs = { path = "../cosmos-rust-fork/cosmos-rust/cosmrs" }
cosmrs = { git = "https://github.com/cosmos/cosmos-rust", rev = "4b1332e6d8258ac845cef71589c8d362a669675a" } # unfortuntely we need a fork by yours truly to get the staking support
tendermint = "0.37.0" # same version as used by cosmrs
tendermint-rpc = "0.37.0" # same version as used by cosmrs
prost = { version = "0.12", default-features = false }
cosmrs = { version = "0.21.0" }
tendermint = "0.40.0"
tendermint-rpc = "0.40.0"
prost = { version = "0.13", default-features = false }
# wasm-related dependencies
gloo-utils = "0.2.0"
gloo-net = "0.6.0"
# TODO: migrate to 0.6+
indexed_db_futures = "0.4.2"
indexed_db_futures = "0.6.0"
js-sys = "0.3.76"
serde-wasm-bindgen = "0.6.5"
tsify = "0.4.5"
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "nym-client"
version = "1.1.46"
version = "1.1.47"
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"]
description = "Implementation of the Nym Client"
edition = "2021"
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "nym-socks5-client"
version = "1.1.46"
version = "1.1.47"
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"
+8 -3
View File
@@ -517,7 +517,7 @@ impl Default for Acknowledgements {
}
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
#[serde(default, deny_unknown_fields)]
#[serde(default)]
pub struct Topology {
/// The uniform delay every which clients are querying the directory server
/// to try to obtain a compatible network topology to send sphinx packets through.
@@ -553,12 +553,15 @@ pub struct Topology {
/// Specifies whether this client should attempt to retrieve all available network nodes
/// as opposed to just active mixnodes/gateways.
/// Useless without `ignore_epoch_roles = true`
pub use_extended_topology: bool,
/// Specifies whether this client should ignore the current epoch role of the target egress node
/// when constructing the final hop packets.
pub ignore_egress_epoch_role: bool,
/// Specifies whether this client should ignore the current epoch role of the ingress node
/// when attempting to establish new connection
pub ignore_ingress_epoch_role: bool,
}
#[allow(clippy::large_enum_variant)]
@@ -596,7 +599,9 @@ impl Default for Topology {
minimum_mixnode_performance: DEFAULT_MIN_MIXNODE_PERFORMANCE,
minimum_gateway_performance: DEFAULT_MIN_GATEWAY_PERFORMANCE,
use_extended_topology: false,
ignore_egress_epoch_role: false,
ignore_egress_epoch_role: true,
ignore_ingress_epoch_role: true,
}
}
}
@@ -115,11 +115,12 @@ where
hardcoded_topology.entry_capable_nodes().cloned().collect()
} else {
let mut rng = rand::thread_rng();
crate::init::helpers::current_gateways(
crate::init::helpers::gateways_for_init(
&mut rng,
&core.client.nym_api_urls,
user_agent,
core.debug.topology.minimum_gateway_performance,
core.debug.topology.ignore_ingress_epoch_role,
)
.await?
};
@@ -170,11 +170,12 @@ where
hardcoded_topology.entry_capable_nodes().cloned().collect()
} else {
let mut rng = rand::thread_rng();
crate::init::helpers::current_gateways(
crate::init::helpers::gateways_for_init(
&mut rng,
&core.client.nym_api_urls,
user_agent,
core.debug.topology.minimum_gateway_performance,
core.debug.topology.ignore_ingress_epoch_role,
)
.await?
};
@@ -4,6 +4,8 @@
// TODO: combine those more closely. Perhaps into a single underlying store.
// Like for persistent, on-disk, storage, what's the point of having 3 different databases?
use rand::rngs::OsRng;
use crate::client::key_manager::persistence::{InMemEphemeralKeys, KeyStore};
use crate::client::replies::reply_storage;
use crate::client::replies::reply_storage::ReplyStorageBackend;
@@ -63,7 +65,6 @@ pub trait MixnetClientStorage {
fn gateway_details_store(&self) -> &Self::GatewaysDetailsStore;
}
#[derive(Default)]
pub struct Ephemeral {
key_store: InMemEphemeralKeys,
reply_store: reply_storage::Empty,
@@ -71,9 +72,14 @@ pub struct Ephemeral {
gateway_details_store: InMemGatewaysDetails,
}
impl Ephemeral {
pub fn new() -> Self {
Default::default()
impl Default for Ephemeral {
fn default() -> Self {
Ephemeral {
key_store: InMemEphemeralKeys::new(&mut OsRng),
reply_store: Default::default(),
credential_store: Default::default(),
gateway_details_store: Default::default(),
}
}
}
@@ -3,6 +3,7 @@
use crate::client::key_manager::ClientKeys;
use async_trait::async_trait;
use rand::{CryptoRng, RngCore};
use std::error::Error;
use tokio::sync::Mutex;
@@ -193,9 +194,19 @@ impl KeyStore for OnDiskKeys {
}
}
#[derive(Default)]
pub struct InMemEphemeralKeys {
keys: Mutex<Option<ClientKeys>>,
keys: Mutex<ClientKeys>,
}
impl InMemEphemeralKeys {
pub fn new<R>(rng: &mut R) -> Self
where
R: RngCore + CryptoRng,
{
InMemEphemeralKeys {
keys: Mutex::new(ClientKeys::generate_new(rng)),
}
}
}
#[derive(Debug, thiserror::Error)]
@@ -208,11 +219,11 @@ impl KeyStore for InMemEphemeralKeys {
type StorageError = EphemeralKeysError;
async fn load_keys(&self) -> Result<ClientKeys, Self::StorageError> {
self.keys.lock().await.clone().ok_or(EphemeralKeysError)
Ok(self.keys.lock().await.clone())
}
async fn store_keys(&self, keys: &ClientKeys) -> Result<(), Self::StorageError> {
*self.keys.lock().await = Some(keys.clone());
*self.keys.lock().await = keys.clone();
Ok(())
}
}
@@ -2,10 +2,12 @@
// SPDX-License-Identifier: Apache-2.0
use crate::client::mix_traffic::transceiver::GatewayTransceiver;
use crate::error::ClientCoreError;
use crate::{spawn_future, ForgetMe};
use log::*;
use nym_gateway_requests::ClientRequest;
use nym_sphinx::forwarding::packet::MixPacket;
use transceiver::ErasedGatewayError;
pub type BatchMixMessageSender = tokio::sync::mpsc::Sender<Vec<MixPacket>>;
pub type BatchMixMessageReceiver = tokio::sync::mpsc::Receiver<Vec<MixPacket>>;
@@ -68,7 +70,10 @@ impl MixTrafficController {
)
}
async fn on_messages(&mut self, mut mix_packets: Vec<MixPacket>) {
async fn on_messages(
&mut self,
mut mix_packets: Vec<MixPacket>,
) -> Result<(), ErasedGatewayError> {
debug_assert!(!mix_packets.is_empty());
let result = if mix_packets.len() == 1 {
@@ -80,21 +85,14 @@ impl MixTrafficController {
.await
};
match result {
Err(err) => {
error!("Failed to send sphinx packet(s) to the gateway: {err}");
self.consecutive_gateway_failure_count += 1;
if self.consecutive_gateway_failure_count == MAX_FAILURE_COUNT {
// todo: in the future this should initiate a 'graceful' shutdown or try
// to reconnect?
panic!("failed to send sphinx packet to the gateway {MAX_FAILURE_COUNT} times in a row - assuming the gateway is dead. Can't do anything about it yet :(")
}
}
Ok(_) => {
trace!("We *might* have managed to forward sphinx packet(s) to the gateway!");
self.consecutive_gateway_failure_count = 0;
}
if result.is_err() {
self.consecutive_gateway_failure_count += 1;
} else {
trace!("We *might* have managed to forward sphinx packet(s) to the gateway!");
self.consecutive_gateway_failure_count = 0;
}
result
}
pub fn start_with_shutdown(mut self, mut shutdown: nym_task::TaskClient) {
@@ -105,7 +103,18 @@ impl MixTrafficController {
tokio::select! {
mix_packets = self.mix_rx.recv() => match mix_packets {
Some(mix_packets) => {
self.on_messages(mix_packets).await;
if let Err(err) = self.on_messages(mix_packets).await {
error!("Failed to send sphinx packet(s) to the gateway: {err}");
if self.consecutive_gateway_failure_count == MAX_FAILURE_COUNT {
// Disconnect from the gateway. If we should try to re-connect
// is handled at a higher layer.
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));
break;
}
}
},
None => {
log::trace!("MixTrafficController: Stopping since channel closed");
@@ -626,9 +626,14 @@ where
messages: Vec<RealMessage>,
transmission_lane: TransmissionLane,
) {
self.real_message_sender
if let Err(err) = self
.real_message_sender
.send((messages, transmission_lane))
.await
.expect("real message receiver task (OutQueueControl) has died");
{
error!(
"Failed to forward messages to the real message sender (OutQueueControl): {err}"
);
}
}
}
@@ -545,7 +545,7 @@ where
loop {
tokio::select! {
biased;
_ = shutdown.recv_with_delay() => {
_ = shutdown.recv() => {
log::trace!("OutQueueControl: Received shutdown");
break;
}
+3
View File
@@ -96,6 +96,9 @@ pub enum ClientCoreError {
#[error("timed out while trying to establish gateway connection")]
GatewayConnectionTimeout,
#[error("failed to forward mix messages to gateway")]
GatewayFailedToForwardMessages,
#[error("no ping measurements for the gateway ({identity}) performed")]
NoGatewayMeasurements { identity: String },
+5 -1
View File
@@ -86,11 +86,12 @@ impl<'a, G: ConnectableGateway> GatewayWithLatency<'a, G> {
}
}
pub async fn current_gateways<R: Rng>(
pub async fn gateways_for_init<R: Rng>(
rng: &mut R,
nym_apis: &[Url],
user_agent: Option<UserAgent>,
minimum_performance: u8,
ignore_epoch_roles: bool,
) -> Result<Vec<RoutingNode>, ClientCoreError> {
let nym_api = nym_apis
.choose(rng)
@@ -108,8 +109,11 @@ pub async fn current_gateways<R: Rng>(
log::trace!("Gateways: {:#?}", gateways);
// filter out gateways below minimum performance and ones that could operate as a mixnode
// (we don't want instability)
let valid_gateways = gateways
.iter()
.filter(|g| ignore_epoch_roles || !g.supported_roles.mixnode)
.filter(|g| g.performance.round_to_integer() >= minimum_performance)
.filter_map(|gateway| gateway.try_into().ok())
.collect::<Vec<_>>();
@@ -19,8 +19,9 @@ use nym_api_requests::ecash::{
PartialExpirationDateSignatureResponse, VerificationKeyResponse,
};
use nym_api_requests::models::{
ApiHealthResponse, GatewayBondAnnotated, GatewayCoreStatusResponse, MixnodeCoreStatusResponse,
MixnodeStatusResponse, NymNodeDescription, RewardEstimationResponse, StakeSaturationResponse,
ApiHealthResponse, GatewayBondAnnotated, GatewayCoreStatusResponse,
HistoricalPerformanceResponse, MixnodeCoreStatusResponse, MixnodeStatusResponse,
NymNodeDescription, RewardEstimationResponse, StakeSaturationResponse,
};
use nym_api_requests::models::{LegacyDescribedGateway, MixNodeBondAnnotated};
use nym_api_requests::nym_nodes::SkimmedNode;
@@ -264,6 +265,31 @@ impl<C, S> Client<C, S> {
Ok(self.nym_api.get_gateways_detailed_unfiltered().await?)
}
pub async fn get_full_node_performance_history(
&self,
node_id: NodeId,
) -> Result<Vec<HistoricalPerformanceResponse>, ValidatorClientError> {
// TODO: deal with paging in macro or some helper function or something, because it's the same pattern everywhere
let mut page = 0;
let mut history = Vec::new();
loop {
let mut res = self
.nym_api
.get_node_performance_history(node_id, Some(page), None)
.await?;
history.append(&mut res.history.data);
if history.len() < res.history.pagination.total {
page += 1
} else {
break;
}
}
Ok(history)
}
// TODO: combine with NymApiClient...
pub async fn get_all_cached_described_nodes(
&self,
@@ -65,6 +65,12 @@ pub enum EcashApiError {
#[from]
source: cosmrs::ErrorReport,
},
#[error("nym api error")]
NymApi {
#[from]
source: crate::ValidatorClientError,
},
}
impl TryFrom<ContractVKShare> for EcashApiClient {
@@ -13,7 +13,7 @@ use nym_api_requests::ecash::models::{
use nym_api_requests::ecash::VerificationKeyResponse;
use nym_api_requests::models::{
AnnotationResponse, ApiHealthResponse, LegacyDescribedMixNode, NodePerformanceResponse,
NodeRefreshBody, NymNodeDescription, RewardedSetResponse,
NodeRefreshBody, NymNodeDescription, PerformanceHistoryResponse, RewardedSetResponse,
};
use nym_api_requests::nym_nodes::PaginatedCachedNodesResponse;
use nym_api_requests::pagination::PaginatedResponse;
@@ -163,6 +163,35 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[tracing::instrument(level = "debug", skip_all)]
async fn get_node_performance_history(
&self,
node_id: NodeId,
page: Option<u32>,
per_page: Option<u32>,
) -> Result<PerformanceHistoryResponse, NymAPIError> {
let mut params = Vec::new();
if let Some(page) = page {
params.push(("page", page.to_string()))
}
if let Some(per_page) = per_page {
params.push(("per_page", per_page.to_string()))
}
self.get_json(
&[
routes::API_VERSION,
routes::NYM_NODES_ROUTES,
routes::NYM_NODES_PERFORMANCE_HISTORY,
&*node_id.to_string(),
],
&params,
)
.await
}
#[tracing::instrument(level = "debug", skip_all)]
async fn get_nodes_described(
&self,
@@ -179,8 +208,15 @@ pub trait NymApiClientExt: ApiClient {
params.push(("per_page", per_page.to_string()))
}
self.get_json(&[routes::API_VERSION, "nym-nodes", "described"], &params)
.await
self.get_json(
&[
routes::API_VERSION,
routes::NYM_NODES_ROUTES,
routes::NYM_NODES_DESCRIBED,
],
&params,
)
.await
}
#[tracing::instrument(level = "debug", skip_all)]
@@ -199,8 +235,15 @@ pub trait NymApiClientExt: ApiClient {
params.push(("per_page", per_page.to_string()))
}
self.get_json(&[routes::API_VERSION, "nym-nodes", "bonded"], &params)
.await
self.get_json(
&[
routes::API_VERSION,
routes::NYM_NODES_ROUTES,
routes::NYM_NODES_BONDED,
],
&params,
)
.await
}
#[deprecated]
@@ -210,7 +253,7 @@ pub trait NymApiClientExt: ApiClient {
&[
routes::API_VERSION,
"unstable",
"nym-nodes",
routes::NYM_NODES_ROUTES,
"mixnodes",
"skimmed",
],
@@ -226,7 +269,7 @@ pub trait NymApiClientExt: ApiClient {
&[
routes::API_VERSION,
"unstable",
"nym-nodes",
routes::NYM_NODES_ROUTES,
"gateways",
"skimmed",
],
@@ -238,7 +281,11 @@ pub trait NymApiClientExt: ApiClient {
#[instrument(level = "debug", skip(self))]
async fn get_rewarded_set(&self) -> Result<RewardedSetResponse, NymAPIError> {
self.get_json(
&[routes::API_VERSION, "nym-nodes", "rewarded-set"],
&[
routes::API_VERSION,
routes::NYM_NODES_ROUTES,
routes::NYM_NODES_REWARDED_SET,
],
NO_PARAMS,
)
.await
@@ -271,7 +318,7 @@ pub trait NymApiClientExt: ApiClient {
&[
routes::API_VERSION,
"unstable",
"nym-nodes",
routes::NYM_NODES_ROUTES,
"skimmed",
"entry-gateways",
"all",
@@ -308,7 +355,7 @@ pub trait NymApiClientExt: ApiClient {
&[
routes::API_VERSION,
"unstable",
"nym-nodes",
routes::NYM_NODES_ROUTES,
"skimmed",
"mixnodes",
"active",
@@ -345,7 +392,7 @@ pub trait NymApiClientExt: ApiClient {
&[
routes::API_VERSION,
"unstable",
"nym-nodes",
routes::NYM_NODES_ROUTES,
"skimmed",
"mixnodes",
"all",
@@ -377,7 +424,12 @@ pub trait NymApiClientExt: ApiClient {
}
self.get_json(
&[routes::API_VERSION, "unstable", "nym-nodes", "skimmed"],
&[
routes::API_VERSION,
"unstable",
routes::NYM_NODES_ROUTES,
"skimmed",
],
&params,
)
.await
@@ -686,8 +738,8 @@ pub trait NymApiClientExt: ApiClient {
self.get_json(
&[
routes::API_VERSION,
"nym-nodes",
"performance",
routes::NYM_NODES_ROUTES,
routes::NYM_NODES_PERFORMANCE,
&node_id.to_string(),
],
NO_PARAMS,
@@ -702,8 +754,8 @@ pub trait NymApiClientExt: ApiClient {
self.get_json(
&[
routes::API_VERSION,
"nym-nodes",
"annotation",
routes::NYM_NODES_ROUTES,
routes::NYM_NODES_ANNOTATION,
&node_id.to_string(),
],
NO_PARAMS,
@@ -927,7 +979,11 @@ pub trait NymApiClientExt: ApiClient {
request: &NodeRefreshBody,
) -> Result<(), NymAPIError> {
self.post_json(
&[routes::API_VERSION, "nym-nodes", "refresh-described"],
&[
routes::API_VERSION,
routes::NYM_NODES_ROUTES,
routes::NYM_NODES_REFRESH_DESCRIBED,
],
NO_PARAMS,
request,
)
@@ -34,6 +34,19 @@ pub mod ecash {
pub const EPOCH_ID_PARAM: &str = "epoch_id";
}
pub const NYM_NODES_ROUTES: &str = "nym-nodes";
pub use nym_nodes::*;
pub mod nym_nodes {
pub const NYM_NODES_PERFORMANCE_HISTORY: &str = "performance-history";
pub const NYM_NODES_PERFORMANCE: &str = "performance";
pub const NYM_NODES_ANNOTATION: &str = "annotation";
pub const NYM_NODES_DESCRIBED: &str = "described";
pub const NYM_NODES_BONDED: &str = "bonded";
pub const NYM_NODES_REWARDED_SET: &str = "rewarded-set";
pub const NYM_NODES_REFRESH_DESCRIBED: &str = "refresh-described";
}
pub const STATUS_ROUTES: &str = "status";
pub const API_STATUS_ROUTES: &str = "api-status";
pub const HEALTH: &str = "health";
@@ -153,13 +153,20 @@ pub trait CosmWasmClient: TendermintRpcClient {
let req = QueryAllBalancesRequest {
address: address.to_string(),
pagination,
resolve_denom: false,
};
let mut res = self
.make_abci_query::<_, QueryAllBalancesResponse>(path.clone(), req)
.await?;
let early_break = res.balances.is_empty();
raw_balances.append(&mut res.balances);
if early_break {
break;
}
if let Some(next_key) = next_page_key(res.pagination) {
pagination = Some(create_pagination(next_key))
} else {
@@ -187,7 +194,13 @@ pub trait CosmWasmClient: TendermintRpcClient {
.make_abci_query::<_, QueryTotalSupplyResponse>(path.clone(), req)
.await?;
let early_break = res.supply.is_empty();
supply.append(&mut res.supply);
if early_break {
break;
}
if let Some(next_key) = next_page_key(res.pagination) {
pagination = Some(create_pagination(next_key))
} else {
@@ -328,7 +341,13 @@ pub trait CosmWasmClient: TendermintRpcClient {
.make_abci_query::<_, QueryCodesResponse>(path.clone(), req)
.await?;
let early_break = res.code_infos.is_empty();
raw_codes.append(&mut res.code_infos);
if early_break {
break;
}
if let Some(next_key) = next_page_key(res.pagination) {
pagination = Some(create_pagination(next_key))
} else {
@@ -373,7 +392,13 @@ pub trait CosmWasmClient: TendermintRpcClient {
.make_abci_query::<_, QueryContractsByCodeResponse>(path.clone(), req)
.await?;
let early_break = res.contracts.is_empty();
raw_contracts.append(&mut res.contracts);
if early_break {
break;
}
if let Some(next_key) = next_page_key(res.pagination) {
pagination = Some(create_pagination(next_key))
} else {
@@ -429,7 +454,13 @@ pub trait CosmWasmClient: TendermintRpcClient {
.make_abci_query::<_, QueryContractHistoryResponse>(path.clone(), req)
.await?;
let early_break = res.entries.is_empty();
raw_entries.append(&mut res.entries);
if early_break {
break;
}
if let Some(next_key) = next_page_key(res.pagination) {
pagination = Some(create_pagination(next_key))
} else {
@@ -4,9 +4,11 @@
use crate::rpc::TendermintRpcClient;
use async_trait::async_trait;
use base64::Engine;
use cosmrs::tendermint;
use cosmrs::tendermint::{block::Height, evidence::Evidence, Hash};
use reqwest::header::HeaderMap;
use reqwest::{header, RequestBuilder};
use tendermint_rpc::dialect::{v0_34, v0_37, v0_38, LatestDialect};
use tendermint_rpc::{
client::CompatMode,
dialect::{self, Dialect},
@@ -21,8 +23,21 @@ macro_rules! perform_with_compat {
($self:expr, $request:expr) => {{
let request = $request;
match $self.compat {
CompatMode::V0_37 => $self.perform_v0_37(request).await,
CompatMode::V0_34 => $self.perform_v0_34(request).await,
CompatMode::V0_38 => {
$self
.perform_request_with_dialect(request, dialect::v0_38::Dialect)
.await
}
CompatMode::V0_37 => {
$self
.perform_request_with_dialect(request, dialect::v0_37::Dialect)
.await
}
CompatMode::V0_34 => {
$self
.perform_request_with_dialect(request, dialect::v0_34::Dialect)
.await
}
}
}};
}
@@ -70,7 +85,11 @@ impl ReqwestRpcClient {
.headers(headers)
}
async fn perform_request<R, S>(&self, request: R) -> Result<R::Output, Error>
async fn perform_request_with_dialect<R, S>(
&self,
request: R,
_dialect: S,
) -> Result<R::Output, Error>
where
R: SimpleRequest<S>,
S: Dialect,
@@ -81,26 +100,25 @@ impl ReqwestRpcClient {
.send()
.await
.map_err(TendermintRpcErrorMap::into_rpc_err)?;
let response_status = response.status();
let bytes = response
.bytes()
.await
.map_err(TendermintRpcErrorMap::into_rpc_err)?;
// Successful JSON-RPC requests are expected to return a 200 OK HTTP status.
// Otherwise, this means that the HTTP request failed as a whole,
// as opposed to the JSON-RPC request returning an error,
// and we cannot expect the response body to be a valid JSON-RPC response.
if response_status != reqwest::StatusCode::OK {
// hehe, that's so nasty but we have to somehow convert between different versions of the same lib
return Err(Error::http_request_failed(
response_status.as_u16().try_into().unwrap(),
));
}
R::Response::from_string(bytes).map(Into::into)
}
async fn perform_v0_34<R>(&self, request: R) -> Result<R::Output, Error>
where
R: SimpleRequest<dialect::v0_34::Dialect>,
{
self.perform_request(request).await
}
async fn perform_v0_37<R>(&self, request: R) -> Result<R::Output, Error>
where
R: SimpleRequest<dialect::v0_37::Dialect>,
{
self.perform_request(request).await
}
}
trait TendermintRpcErrorMap {
@@ -120,18 +138,50 @@ impl TendermintRpcClient for ReqwestRpcClient {
where
R: SimpleRequest,
{
self.perform_request(request).await
self.perform_request_with_dialect(request, LatestDialect)
.await
}
async fn block_results<H>(&self, height: H) -> Result<block_results::Response, Error>
async fn block<H>(&self, height: H) -> Result<endpoint::block::Response, Error>
where
H: Into<Height> + Send,
{
perform_with_compat!(self, block_results::Request::new(height.into()))
perform_with_compat!(self, endpoint::block::Request::new(height.into()))
}
async fn latest_block_results(&self) -> Result<block_results::Response, Error> {
perform_with_compat!(self, block_results::Request::default())
async fn block_by_hash(
&self,
hash: tendermint::Hash,
) -> Result<endpoint::block_by_hash::Response, Error> {
perform_with_compat!(self, endpoint::block_by_hash::Request::new(hash))
}
async fn latest_block(&self) -> Result<endpoint::block::Response, Error> {
perform_with_compat!(self, endpoint::block::Request::default())
}
async fn block_results<H>(&self, height: H) -> Result<endpoint::block_results::Response, Error>
where
H: Into<Height> + Send,
{
perform_with_compat!(self, endpoint::block_results::Request::new(height.into()))
}
async fn latest_block_results(&self) -> Result<endpoint::block_results::Response, Error> {
perform_with_compat!(self, endpoint::block_results::Request::default())
}
async fn block_search(
&self,
query: Query,
page: u32,
per_page: u8,
order: Order,
) -> Result<endpoint::block_search::Response, Error> {
perform_with_compat!(
self,
endpoint::block_search::Request::new(query, page, per_page, order)
)
}
async fn header<H>(&self, height: H) -> Result<endpoint::header::Response, Error>
@@ -140,11 +190,26 @@ impl TendermintRpcClient for ReqwestRpcClient {
{
let height = height.into();
match self.compat {
CompatMode::V0_37 => self.perform(endpoint::header::Request::new(height)).await,
CompatMode::V0_38 => {
self.perform_request_with_dialect(
endpoint::header::Request::new(height),
v0_38::Dialect,
)
.await
}
CompatMode::V0_37 => {
self.perform_request_with_dialect(
endpoint::header::Request::new(height),
v0_37::Dialect,
)
.await
}
CompatMode::V0_34 => {
// Back-fill with a request to /block endpoint and
// taking just the header from the response.
let resp = self.perform_v0_34(block::Request::new(height)).await?;
let resp = self
.perform_request_with_dialect(block::Request::new(height), v0_34::Dialect)
.await?;
Ok(resp.into())
}
}
@@ -152,12 +217,25 @@ impl TendermintRpcClient for ReqwestRpcClient {
async fn header_by_hash(&self, hash: Hash) -> Result<header_by_hash::Response, Error> {
match self.compat {
CompatMode::V0_37 => self.perform(header_by_hash::Request::new(hash)).await,
CompatMode::V0_38 => {
self.perform_request_with_dialect(
header_by_hash::Request::new(hash),
v0_38::Dialect,
)
.await
}
CompatMode::V0_37 => {
self.perform_request_with_dialect(
header_by_hash::Request::new(hash),
v0_37::Dialect,
)
.await
}
CompatMode::V0_34 => {
// Back-fill with a request to /block_by_hash endpoint and
// taking just the header from the response.
let resp = self
.perform_v0_34(block_by_hash::Request::new(hash))
.perform_request_with_dialect(block_by_hash::Request::new(hash), v0_34::Dialect)
.await?;
Ok(resp.into())
}
@@ -167,8 +245,18 @@ impl TendermintRpcClient for ReqwestRpcClient {
/// `/broadcast_evidence`: broadcast an evidence.
async fn broadcast_evidence(&self, e: Evidence) -> Result<evidence::Response, Error> {
match self.compat {
CompatMode::V0_37 => self.perform(evidence::Request::new(e)).await,
CompatMode::V0_34 => self.perform_v0_34(evidence::Request::new(e)).await,
CompatMode::V0_38 => {
self.perform_request_with_dialect(evidence::Request::new(e), v0_38::Dialect)
.await
}
CompatMode::V0_37 => {
self.perform_request_with_dialect(evidence::Request::new(e), v0_37::Dialect)
.await
}
CompatMode::V0_34 => {
self.perform_request_with_dialect(evidence::Request::new(e), v0_34::Dialect)
.await
}
}
}
@@ -113,6 +113,10 @@ impl Role {
pub fn is_standby(&self) -> bool {
matches!(self, Role::Standby)
}
pub fn is_mixnode(&self) -> bool {
matches!(self, Role::Layer1 | Role::Layer2 | Role::Layer3)
}
}
impl Display for Role {
@@ -13,6 +13,7 @@ use nym_api_requests::constants::MIN_BATCH_REDEMPTION_DELAY;
use nym_api_requests::ecash::models::{BatchRedeemTicketsBody, VerifyEcashTicketBody};
use nym_credentials_interface::Bandwidth;
use nym_credentials_interface::{ClientTicket, TicketType};
use nym_validator_client::coconut::EcashApiError;
use nym_validator_client::nym_api::EpochId;
use nym_validator_client::nyxd::contract_traits::{
EcashSigningClient, MultisigQueryClient, MultisigSigningClient, PagedMultisigQueryClient,
@@ -352,7 +353,9 @@ impl CredentialHandler {
}
Err(err) => {
error!("failed to send ticket {ticket_id} for verification to ecash signer '{client}': {err}. if we don't reach quorum, we'll retry later");
Ok(false)
Err(EcashTicketError::ApiFailure(EcashApiError::NymApi {
source: err,
}))
}
}
}
@@ -3,5 +3,22 @@
* SPDX-License-Identifier: GPL-3.0-only
*/
ALTER TABLE message_store
ADD COLUMN timestamp TIMESTAMP WITHOUT TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP;
RENAME TO message_store_old;
-- add new column with message timestamp.
-- note: we can't simply alter existing table to add it since the default value is non-constant
CREATE TABLE message_store
(
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
client_address_bs58 TEXT NOT NULL,
content BLOB NOT NULL,
timestamp TIMESTAMP WITHOUT TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP
);
INSERT INTO message_store(id, client_address_bs58, content)
SELECT id, client_address_bs58, content
FROM message_store_old;
DROP TABLE message_store_old;
+1 -1
View File
@@ -67,7 +67,7 @@ impl Default for ClientStatsReport {
pub struct OsInformation {
pub(crate) os_type: String,
pub(crate) os_version: Option<String>,
pub(crate) os_arch: Option<String>,
pub(crate) os_arch: String,
}
impl OsInformation {
+8 -11
View File
@@ -401,20 +401,17 @@ impl NymTopology {
});
};
// a 'valid' egress is one assigned to either entry role (i.e. entry for another client)
// or exit role (as a service provider)
// a 'valid' egress is one that is currently **not** acting as a mixnode
if !ignore_epoch_roles {
let Some(role) = self.rewarded_set.role(node.node_id) else {
return Err(NymTopologyError::InvalidEgressRole {
node_identity: Box::new(node_identity),
});
};
if !matches!(role, Role::EntryGateway | Role::ExitGateway) {
return Err(NymTopologyError::InvalidEgressRole {
node_identity: Box::new(node_identity),
});
if let Some(role) = self.rewarded_set.role(node.node_id) {
if role.is_mixnode() {
return Err(NymTopologyError::InvalidEgressRole {
node_identity: Box::new(node_identity),
});
}
}
}
Ok(node)
}
+6 -1
View File
@@ -390,12 +390,15 @@ pub struct TopologyWasm {
/// Specifies whether this client should attempt to retrieve all available network nodes
/// as opposed to just active mixnodes/gateways.
/// Useless without `ignore_epoch_roles = true`
pub use_extended_topology: bool,
/// Specifies whether this client should ignore the current epoch role of the target egress node
/// when constructing the final hop packets.
pub ignore_egress_epoch_role: bool,
/// Specifies whether this client should ignore the current epoch role of the ingress node
/// when attempting to establish new connection
pub ignore_ingress_epoch_role: bool,
}
impl Default for TopologyWasm {
@@ -420,6 +423,7 @@ impl From<TopologyWasm> for ConfigTopology {
minimum_gateway_performance: topology.minimum_gateway_performance,
use_extended_topology: topology.use_extended_topology,
ignore_egress_epoch_role: topology.ignore_egress_epoch_role,
ignore_ingress_epoch_role: topology.ignore_ingress_epoch_role,
}
}
}
@@ -437,6 +441,7 @@ impl From<ConfigTopology> for TopologyWasm {
minimum_gateway_performance: topology.minimum_gateway_performance,
use_extended_topology: topology.use_extended_topology,
ignore_egress_epoch_role: topology.ignore_egress_epoch_role,
ignore_ingress_epoch_role: topology.ignore_ingress_epoch_role,
}
}
}
@@ -274,7 +274,6 @@ pub struct TopologyWasmOverride {
/// Specifies whether this client should attempt to retrieve all available network nodes
/// as opposed to just active mixnodes/gateways.
/// Useless without `ignore_epoch_roles = true`
#[tsify(optional)]
pub use_extended_topology: Option<bool>,
@@ -282,6 +281,11 @@ pub struct TopologyWasmOverride {
/// when constructing the final hop packets.
#[tsify(optional)]
pub ignore_egress_epoch_role: Option<bool>,
/// Specifies whether this client should ignore the current epoch role of the ingress node
/// when attempting to establish new connection
#[tsify(optional)]
pub ignore_ingress_epoch_role: Option<bool>,
}
impl From<TopologyWasmOverride> for TopologyWasm {
@@ -311,6 +315,9 @@ impl From<TopologyWasmOverride> for TopologyWasm {
ignore_egress_epoch_role: value
.ignore_egress_epoch_role
.unwrap_or(def.ignore_egress_epoch_role),
ignore_ingress_epoch_role: value
.ignore_ingress_epoch_role
.unwrap_or(def.ignore_ingress_epoch_role),
}
}
}
+28 -5
View File
@@ -10,7 +10,7 @@ use nym_client_core::client::base_client::storage::GatewaysDetailsStore;
use nym_client_core::client::replies::reply_storage::browser_backend;
use nym_client_core::config;
use nym_client_core::error::ClientCoreError;
use nym_client_core::init::helpers::current_gateways;
use nym_client_core::init::helpers::gateways_for_init;
use nym_client_core::init::types::GatewaySelectionSpecification;
use nym_client_core::init::{
self, setup_gateway,
@@ -132,9 +132,17 @@ pub async fn setup_gateway_from_api(
chosen_gateway: Option<IdentityKey>,
nym_apis: &[Url],
minimum_performance: u8,
ignore_epoch_roles: bool,
) -> Result<InitialisationResult, WasmCoreError> {
let mut rng = thread_rng();
let gateways = current_gateways(&mut rng, nym_apis, None, minimum_performance).await?;
let gateways = gateways_for_init(
&mut rng,
nym_apis,
None,
minimum_performance,
ignore_epoch_roles,
)
.await?;
setup_gateway_wasm(client_store, force_tls, chosen_gateway, gateways).await
}
@@ -142,9 +150,17 @@ pub async fn current_gateways_wasm(
nym_apis: &[Url],
user_agent: Option<UserAgent>,
minimum_performance: u8,
ignore_epoch_roles: bool,
) -> Result<Vec<RoutingNode>, ClientCoreError> {
let mut rng = thread_rng();
current_gateways(&mut rng, nym_apis, user_agent, minimum_performance).await
gateways_for_init(
&mut rng,
nym_apis,
user_agent,
minimum_performance,
ignore_epoch_roles,
)
.await
}
pub async fn setup_from_topology(
@@ -163,6 +179,7 @@ pub async fn generate_new_client_keys(store: &ClientStorage) -> Result<(), WasmC
Ok(())
}
#[allow(clippy::too_many_arguments)]
pub async fn add_gateway(
preferred_gateway: Option<IdentityKey>,
latency_based_selection: Option<bool>,
@@ -170,6 +187,7 @@ pub async fn add_gateway(
nym_apis: &[Url],
user_agent: UserAgent,
min_performance: u8,
ignore_epoch_roles: bool,
storage: &ClientStorage,
) -> Result<(), WasmCoreError> {
let selection_spec = GatewaySelectionSpecification::new(
@@ -203,8 +221,13 @@ pub async fn add_gateway(
// Setup gateway by either registering a new one, or creating a new config from the selected
// one but with keys kept, or reusing the gateway configuration.
let available_gateways =
current_gateways_wasm(nym_apis, Some(user_agent), min_performance).await?;
let available_gateways = current_gateways_wasm(
nym_apis,
Some(user_agent),
min_performance,
ignore_epoch_roles,
)
.await?;
// since we're registering with a brand new gateway,
// make sure the list of available gateways doesn't overlap the list of known gateways
+18 -15
View File
@@ -4,13 +4,15 @@
use crate::error::WasmCoreError;
use crate::storage::wasm_client_traits::{v1, v2, WasmClientStorage};
use async_trait::async_trait;
use js_sys::{Array, Promise};
use js_sys::Promise;
use serde::de::DeserializeOwned;
use serde::Serialize;
use wasm_bindgen::prelude::*;
use wasm_bindgen_futures::future_to_promise;
use wasm_storage::traits::BaseWasmStorage;
use wasm_storage::{IdbVersionChangeEvent, WasmStorage};
use wasm_storage::{
Build, Database, RawDbResult, TryFromJs, TryToJs, VersionChangeEvent, WasmStorage,
};
use wasm_utils::error::{simple_js_error, PromisableResult};
use zeroize::Zeroizing;
@@ -44,28 +46,29 @@ impl ClientStorage {
// special care must be taken on JS side to ensure it's correctly used there.
let passphrase = Zeroizing::new(passphrase);
let migrate_fn = Some(|evt: &IdbVersionChangeEvent| -> Result<(), JsValue> {
let migrate_fn = Some(|evt: VersionChangeEvent, db: Database| -> RawDbResult<()> {
// Even if the web-sys bindings expose the version as a f64, the IndexedDB API
// works with an unsigned integer.
// See <https://github.com/rustwasm/wasm-bindgen/issues/1149>
let old_version = evt.old_version() as u32;
let db = evt.db();
if old_version < 1 {
// migrating to version 2
db.create_object_store(v1::KEYS_STORE)?;
db.create_object_store(v1::CORE_STORE)?;
db.create_object_store(v1::KEYS_STORE).build()?;
db.create_object_store(v1::CORE_STORE).build()?;
db.create_object_store(v2::GATEWAY_REGISTRATIONS_ACTIVE_GATEWAY_STORE)?;
db.create_object_store(v2::GATEWAY_REGISTRATIONS_REGISTERED_GATEWAYS_STORE)?;
db.create_object_store(v2::GATEWAY_REGISTRATIONS_ACTIVE_GATEWAY_STORE)
.build()?;
db.create_object_store(v2::GATEWAY_REGISTRATIONS_REGISTERED_GATEWAYS_STORE)
.build()?;
return Ok(());
}
// version 1 -> unimplemented migration
if old_version < 2 {
return Err(simple_js_error("this client is incompatible with existing storage. please initialise it again."));
return Err(simple_js_error("this client is incompatible with existing storage. please initialise it again.").into());
}
Ok(())
@@ -112,7 +115,7 @@ impl BaseWasmStorage for ClientStorage {
async fn read_value<T, K>(&self, store: &str, key: K) -> Result<Option<T>, Self::StorageError>
where
T: DeserializeOwned,
K: JsCast,
K: TryToJs,
{
Ok(self.inner.read_value(store, key).await?)
}
@@ -125,33 +128,33 @@ impl BaseWasmStorage for ClientStorage {
) -> Result<(), Self::StorageError>
where
T: Serialize,
K: JsCast,
K: TryToJs + TryFromJs,
{
Ok(self.inner.store_value(store, key, value).await?)
}
async fn remove_value<K>(&self, store: &str, key: K) -> Result<(), Self::StorageError>
where
K: JsCast,
K: TryToJs,
{
Ok(self.inner.remove_value(store, key).await?)
}
async fn has_value<K>(&self, store: &str, key: K) -> Result<bool, Self::StorageError>
where
K: JsCast,
K: TryToJs,
{
Ok(self.inner.has_value(store, key).await?)
}
async fn key_count<K>(&self, store: &str, key: K) -> Result<u32, Self::StorageError>
where
K: JsCast,
K: TryToJs,
{
Ok(self.inner.key_count(store, key).await?)
}
async fn get_all_keys(&self, store: &str) -> Result<Array, Self::StorageError> {
async fn get_all_keys(&self, store: &str) -> Result<Vec<JsValue>, Self::StorageError> {
Ok(self.inner.get_all_keys(store).await?)
}
}
@@ -286,8 +286,8 @@ pub trait WasmClientStorage: BaseWasmStorage {
.await
.map_err(Into::into)
.map(|arr| {
arr.to_vec()
.into_iter()
arr.iter()
.cloned()
.filter_map(|key| key.as_string())
.collect()
})
+1 -1
View File
@@ -9,7 +9,7 @@ license.workspace = true
[dependencies]
async-trait = { workspace = true }
futures = { workspace = true }
getrandom = { workspace = true, features = ["js"] }
js-sys = { workspace = true }
wasm-bindgen = { workspace = true }
serde = { workspace = true, features = ["derive"] }
+17 -16
View File
@@ -1,7 +1,6 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use indexed_db_futures::web_sys::DomException;
use serde_wasm_bindgen::Error;
use thiserror::Error;
use wasm_bindgen::JsValue;
@@ -12,15 +11,11 @@ pub enum StorageError {
#[error("{0}")]
Json(String),
#[error("DomException {name} ({code}): {message}")]
DomException {
/// DomException code
code: u16,
/// Specific name of the DomException
name: String,
/// Message given to the DomException
message: String,
},
#[error("storage failure: {message}")]
InternalStorageFailure { message: String },
#[error("failed to open the db file: {message}")]
DbOpenFailure { message: String },
#[error("FATAL ERROR: storage key is somehow present {count} times in the table!")]
DuplicateKey { count: u32 },
@@ -46,12 +41,18 @@ impl From<StorageError> for JsValue {
}
}
impl From<DomException> for StorageError {
fn from(value: DomException) -> StorageError {
StorageError::DomException {
name: value.name(),
message: value.message(),
code: value.code(),
impl From<indexed_db_futures::error::Error> for StorageError {
fn from(value: indexed_db_futures::error::Error) -> Self {
StorageError::InternalStorageFailure {
message: value.to_string(),
}
}
}
impl From<indexed_db_futures::error::OpenDbError> for StorageError {
fn from(value: indexed_db_futures::error::OpenDbError) -> Self {
StorageError::DbOpenFailure {
message: value.to_string(),
}
}
}
+69 -52
View File
@@ -1,8 +1,9 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// Copyright 2023-2025 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::cipher_export::StoredExportedStoreCipher;
use crate::error::StorageError;
use indexed_db_futures::transaction::TransactionMode;
use nym_store_cipher::{
Aes256Gcm, Algorithm, EncryptedData, KdfInfo, KeySizeUser, Params, StoreCipher, Unsigned,
Version,
@@ -13,7 +14,10 @@ use std::future::IntoFuture;
use wasm_bindgen::JsValue;
use wasm_utils::console_log;
pub use indexed_db_futures::database::{Database, VersionChangeEvent};
pub use indexed_db_futures::prelude::*;
pub use indexed_db_futures::primitive::{TryFromJs, TryToJs};
pub use indexed_db_futures::Result as RawDbResult;
mod cipher_export;
pub mod error;
@@ -54,31 +58,29 @@ impl WasmStorage {
passphrase: Option<&[u8]>,
) -> Result<Self, StorageError>
where
F: Fn(&IdbVersionChangeEvent) -> Result<(), JsValue> + 'static,
F: Fn(VersionChangeEvent, Database) -> RawDbResult<()> + 'static,
{
let mut db_req: OpenDbRequest = IdbDatabase::open_u32(db_name, version)?;
// we must always ensure the cipher table is present
db_req.set_on_upgrade_needed(Some(
move |evt: &IdbVersionChangeEvent| -> Result<(), JsValue> {
let db = Database::open(db_name)
.with_version(version)
.with_on_upgrade_needed(move |event, db| {
// Even if the web-sys bindings expose the version as a f64, the IndexedDB API
// works with an unsigned integer.
// See <https://github.com/rustwasm/wasm-bindgen/issues/1149>
let old_version = evt.old_version() as u32;
let old_version = event.old_version() as u32;
if old_version < 1 {
evt.db().create_object_store(CIPHER_INFO_STORE)?;
db.create_object_store(CIPHER_INFO_STORE).build()?;
}
if let Some(migrate) = migrate_fn.as_ref() {
migrate(evt)
migrate(event, db)
} else {
Ok(())
}
},
));
})
.await?;
let db: IdbDatabase = db_req.into_future().await?;
let inner = IdbWrapper(db);
let store_cipher = inner.setup_store_cipher(passphrase).await?;
@@ -94,13 +96,12 @@ impl WasmStorage {
}
pub async fn remove(db_name: &str) -> Result<(), StorageError> {
IdbDatabase::delete_by_name(db_name)?.into_future().await?;
Database::delete_by_name(db_name)?.into_future().await?;
Ok(())
}
pub async fn exists(db_name: &str) -> Result<bool, StorageError> {
let db_req: OpenDbRequest = IdbDatabase::open(db_name)?;
let db: IdbDatabase = db_req.into_future().await?;
let db = Database::open(db_name).await?;
// if the db was already created before, at the very least cipher info store should exist,
// thus the iterator should return at least one value
@@ -139,7 +140,7 @@ impl WasmStorage {
pub async fn read_value<T, K>(&self, store: &str, key: K) -> Result<Option<T>, StorageError>
where
T: DeserializeOwned,
K: wasm_bindgen::JsCast,
K: TryToJs,
{
self.inner
.read_value_raw(store, key)
@@ -156,7 +157,7 @@ impl WasmStorage {
) -> Result<(), StorageError>
where
T: Serialize,
K: wasm_bindgen::JsCast,
K: TryToJs + TryFromJs,
{
self.inner
.store_value_raw(store, key, &self.serialize_value(&value)?)
@@ -165,14 +166,14 @@ impl WasmStorage {
pub async fn remove_value<K>(&self, store: &str, key: K) -> Result<(), StorageError>
where
K: wasm_bindgen::JsCast,
K: TryToJs,
{
self.inner.remove_value_raw(store, key).await
}
pub async fn has_value<K>(&self, store: &str, key: K) -> Result<bool, StorageError>
where
K: wasm_bindgen::JsCast,
K: TryToJs,
{
match self.key_count(store, key).await? {
0 => Ok(false),
@@ -183,82 +184,98 @@ impl WasmStorage {
pub async fn key_count<K>(&self, store: &str, key: K) -> Result<u32, StorageError>
where
K: wasm_bindgen::JsCast,
K: TryToJs,
{
self.inner.get_key_count(store, key).await
}
pub async fn get_all_keys(&self, store: &str) -> Result<js_sys::Array, StorageError> {
pub async fn get_all_keys(&self, store: &str) -> Result<Vec<JsValue>, StorageError> {
self.inner.get_all_keys(store).await
}
}
struct IdbWrapper(IdbDatabase);
struct IdbWrapper(Database);
impl IdbWrapper {
async fn read_value_raw<K>(&self, store: &str, key: K) -> Result<Option<JsValue>, StorageError>
where
K: wasm_bindgen::JsCast,
K: TryToJs,
{
self.0
.transaction_on_one_with_mode(store, IdbTransactionMode::Readonly)?
.transaction(store)
.with_mode(TransactionMode::Readonly)
.build()?
.object_store(store)?
.get(&key)?
.get(&key)
.primitive()?
.await
.map_err(Into::into)
}
async fn store_value_raw<K>(
async fn store_value_raw<K, T>(
&self,
store: &str,
key: K,
value: &JsValue,
value: &T,
) -> Result<(), StorageError>
where
K: wasm_bindgen::JsCast,
K: TryToJs + TryFromJs,
T: TryToJs,
{
self.0
.transaction_on_one_with_mode(store, IdbTransactionMode::Readwrite)?
.object_store(store)?
.put_key_val_owned(key, value)?
.into_future()
.await
.map_err(Into::into)
let tx = self
.0
.transaction(store)
.with_mode(TransactionMode::Readwrite)
.build()?;
let store = tx.object_store(store)?;
store.put(value).with_key(key).primitive()?.await?;
tx.commit().await.map_err(Into::into)
}
async fn remove_value_raw<K>(&self, store: &str, key: K) -> Result<(), StorageError>
where
K: wasm_bindgen::JsCast,
K: TryToJs,
{
self.0
.transaction_on_one_with_mode(store, IdbTransactionMode::Readwrite)?
.object_store(store)?
.delete_owned(key)?
.into_future()
.await
.map_err(Into::into)
let tx = self
.0
.transaction(store)
.with_mode(TransactionMode::Readwrite)
.build()?;
let store = tx.object_store(store)?;
store.delete(key).primitive()?.await?;
tx.commit().await.map_err(Into::into)
}
async fn get_key_count<K>(&self, store: &str, key: K) -> Result<u32, StorageError>
where
K: wasm_bindgen::JsCast,
K: TryToJs,
{
self.0
.transaction_on_one_with_mode(store, IdbTransactionMode::Readwrite)?
.transaction(store)
.with_mode(TransactionMode::Readonly)
.build()?
.object_store(store)?
.count_with_key_owned(key)?
.into_future()
.count()
.with_query(key)
.primitive()?
.await
.map_err(Into::into)
}
async fn get_all_keys(&self, store: &str) -> Result<js_sys::Array, StorageError> {
async fn get_all_keys(&self, store: &str) -> Result<Vec<JsValue>, StorageError> {
self.0
.transaction_on_one_with_mode(store, IdbTransactionMode::Readonly)?
.transaction(store)
.with_mode(TransactionMode::Readonly)
.build()?
.object_store(store)?
.get_all_keys()?
.into_future()
.await
.get_all_keys()
.primitive()?
.await?
.collect::<Result<Vec<_>, _>>()
.map_err(Into::into)
}
+14 -13
View File
@@ -3,10 +3,11 @@
use crate::WasmStorage;
use async_trait::async_trait;
use js_sys::Array;
use indexed_db_futures::primitive::{TryFromJs, TryToJs};
use serde::de::DeserializeOwned;
use serde::Serialize;
use std::error::Error;
use wasm_bindgen::JsValue;
#[async_trait(?Send)]
pub trait BaseWasmStorage {
@@ -17,7 +18,7 @@ pub trait BaseWasmStorage {
async fn read_value<T, K>(&self, store: &str, key: K) -> Result<Option<T>, Self::StorageError>
where
T: DeserializeOwned,
K: wasm_bindgen::JsCast;
K: TryToJs;
async fn store_value<T, K>(
&self,
@@ -27,21 +28,21 @@ pub trait BaseWasmStorage {
) -> Result<(), Self::StorageError>
where
T: Serialize,
K: wasm_bindgen::JsCast;
K: TryToJs + TryFromJs;
async fn remove_value<K>(&self, store: &str, key: K) -> Result<(), Self::StorageError>
where
K: wasm_bindgen::JsCast;
K: TryToJs;
async fn has_value<K>(&self, store: &str, key: K) -> Result<bool, Self::StorageError>
where
K: wasm_bindgen::JsCast;
K: TryToJs;
async fn key_count<K>(&self, store: &str, key: K) -> Result<u32, Self::StorageError>
where
K: wasm_bindgen::JsCast;
K: TryToJs;
async fn get_all_keys(&self, store: &str) -> Result<js_sys::Array, Self::StorageError>;
async fn get_all_keys(&self, store: &str) -> Result<Vec<JsValue>, Self::StorageError>;
}
#[async_trait(?Send)]
@@ -55,7 +56,7 @@ impl BaseWasmStorage for WasmStorage {
async fn read_value<T, K>(&self, store: &str, key: K) -> Result<Option<T>, Self::StorageError>
where
T: DeserializeOwned,
K: wasm_bindgen::JsCast,
K: TryToJs,
{
self.read_value(store, key).await
}
@@ -68,33 +69,33 @@ impl BaseWasmStorage for WasmStorage {
) -> Result<(), Self::StorageError>
where
T: Serialize,
K: wasm_bindgen::JsCast,
K: TryToJs + TryFromJs,
{
self.store_value(store, key, value).await
}
async fn remove_value<K>(&self, store: &str, key: K) -> Result<(), Self::StorageError>
where
K: wasm_bindgen::JsCast,
K: TryToJs,
{
self.remove_value(store, key).await
}
async fn has_value<K>(&self, store: &str, key: K) -> Result<bool, Self::StorageError>
where
K: wasm_bindgen::JsCast,
K: TryToJs,
{
self.has_value(store, key).await
}
async fn key_count<K>(&self, store: &str, key: K) -> Result<u32, Self::StorageError>
where
K: wasm_bindgen::JsCast,
K: TryToJs,
{
self.key_count(store, key).await
}
async fn get_all_keys(&self, store: &str) -> Result<Array, Self::StorageError> {
async fn get_all_keys(&self, store: &str) -> Result<Vec<JsValue>, Self::StorageError> {
self.get_all_keys(store).await
}
}
@@ -10,7 +10,7 @@ import Stack from '@mui/material/Stack';
import Paper from '@mui/material/Paper';
import type { SetupMixFetchOps } from '@nymproject/mix-fetch';
const defaultUrl = 'https://nymtech.net/favicon.svg';
const defaultUrl = 'https://nym.com/favicon.svg';
const args = { mode: 'unsafe-ignore-cors' };
const mixFetchOptions: SetupMixFetchOps = {
@@ -0,0 +1,9 @@
import { Callout } from 'nextra/components';
### Terms & Conditions
<Callout type="info" emoji="️">
From `nym-node` version `1.1.3` onward is required to accept [**Operators Terms & Conditions**](https://nymtech.net/terms-and-conditions/operators/v1.0.0) in order to be part of the active set. Make sure to read them before you add the flag.
</Callout>
There has been a long ongoing discussion whether and how to apply Terms and Conditions for Nym network operators, with an aim to stay aligned with the philosophy of Free Software and provide legal defense for both node operators and Nym developers. To understand better the reasoning behind this decision, you can listen to the first [Nym Operator Town Hall](https://www.youtube.com/live/7hwb8bAZIuc?si=3mQ2ed7AyUA1SsCp&t=915) introducing the T&Cs or to [Operator AMA with CEO Harry Halpin](https://www.youtube.com/watch?v=yIN-zYQw0I0) from June 4th, 2024, explaining pros and cons of T&Cs implementation.
@@ -1 +1 @@
Wednesday, January 8th 2025, 15:01:28 UTC
Thursday, January 16th 2025, 09:57:52 UTC
@@ -5,8 +5,6 @@ import { VarInfo } from 'components/variable-info.tsx';
import { AccordionTemplate } from 'components/accordion-template.tsx';
import { Steps } from 'nextra/components';
export const TestingSteps = () => (
<div>
Testing steps performed
@@ -32,15 +30,251 @@ export const TunnelManagerCommands = () => (
);
# Changelog
This page displays a full list of all the changes during our release cycle from `v2024.3-eclipse` onward. Operators can find here the newest updates together with links to relevant documentation. The list is sorted so that the newest changes appear first.
**Note:** Any information shared on this page was up to date at the time of writing. We do *not* maintain changelog retrospectively.
**Note:** Any information published on this page was up to date at the time of writing. We do *not* maintain changelog retrospectively.
<VarInfo />
## `v2025.1-reeses`
- [Release Binaries](https://github.com/nymtech/nym/releases/tag/nym-binaries-v2025.1-reeses)
- [`nym-node`](nodes/nym-node.mdx) version `1.3.0`
```
nym-node
Binary Name: nym-node
Build Timestamp: 2025-01-15T09:50:54.404428047Z
Build Version: 1.3.0
Commit SHA: c202e2d598fabda5fc16a6c1e110255857a2b1ca
Commit Date: 2025-01-15T10:27:39.000000000+01:00
Commit Branch: HEAD
rustc Version: 1.84.0
rustc Channel: stable
cargo Profile: release
```
### Operators Updates & Tools
<Callout type="info">
From `nym-node v1.3.0` operators can choose multiple functionalities for their `nym-node` binary (flagged as `--mode`).
**However, the clients are yet to be developed to be able to make a proper selection for multi-mode nodes and therefore we ask operators to sign only one functionality to `--mode` option at a time. Please chose out of: `mixnode` or `entry-gateway` or `exit-gateway`.**
We are developing a design where operators can enable multiple modes, and let the Nym API to position the node according the network's needs in the beginning of each epoch.
</Callout>
- [Node functionality info updated](nodes/nym-node/setup#functionality-mode)
- [Fund your `nym-node` inbuilt Nyx account](nodes/nym-node/bonding#fund-nym-node-client-nyx-account) to prepare for gateway ticket rewarding
- `config.toml` changes:
- Replaced `mode` with `modes` to allow setting the node to run with say, `entry` + `mixnode` roles simultaneously
- Added `maximum_forward_packet_delay` to `mixnet.debug` section
- Moved `verloc` section from `mixnode.verloc` to top level
- Removed `mixnode` section
- Removed `entry_gateway` section to `gateway_tasks`
- Moved `authenticator` section from `gateway_tasks` (`entry_gateway`) to `service_providers` (`exit_gateway`)
- Renamed `exit_gateway` section to `service_providers`
- Moved top level `authenticator` section to `service_providers` so that it'd live alongside NR and IPR
- Added general `debug` section
- Added `metrics` section
- All documentation migrated to a new URL [nym.com/docs](https://nym.com/docs) alongside the rebranding of Nym organisation.
- Updated [network architecture diagrams](https://nym.com/docs/network/architecture)
- New blow-by-blow mixnet [traffic flow](https://nym.com/docs/network/architecture) section
- [Winter Nym Squad League started](https://forum.nym.com/t/nym-squad-league-farewell-fall-welcome-winter/977)
- From this release onward (New Year) Operators Updates & Tools will be on top of each release changelog followed by features, cryptography and bugfix parts.
- All 2024 release notes were moved to the bottom section called [Archived changelog](#archived-changelog)
### Features
- [build(deps): bump micromatch from `4.0.4` to `4.0.8` in `/testnet-faucet`](https://github.com/nymtech/nym/pull/4813): Bumps [micromatch](https://github.com/micromatch/micromatch) from `4.0.4` to `4.0.8`.
- [Move NS client to separate package under NS API](https://github.com/nymtech/nym/pull/5171):
- Moving NS API client code to separate package outside NS Agent makes the code cleaner & more modular
- NS agent now imports NS API client that it uses
- No functionality change in NS API or NS agent
- [Introduced initial internal commands for nym-cli: ecash key and request generation](https://github.com/nymtech/nym/pull/5174)
- [NS API - Gateway stats scraping](https://github.com/nymtech/nym/pull/5180): This PR adds a metrics scraper that fetches metrics from the `metrics/sessions` endpoint on gateway. The entries are stored and served on the API for one year
- [Remove explorer dependency](https://github.com/nymtech/nym/pull/5190)
- [Hopefully final steps of the smoosh™️](https://github.com/nymtech/nym/pull/5201): this PR is a bit more extensive than initially planned because of all the spaghetti that had to be untangled to make it all happen. The general idea is that now it's possible to run your node simultaneously in multiple modes. for example `mixnode` + `entry` or `entry` + `exit`, etc. The modes do the following:
- `mixnode`: allows the node to handle **forward** sphinx packets
- `entry-gateway`: allows the node to accepts websocket connections from incoming clients and to handle **final hop** sphinx packets
- `exit-gateway`: allows the node to handle **final hop** sphinx packets as well as starts NR and IPR service providers
Furthermore, if node runs with `wireguard` enabled, it will start local `authenticator` service provider which will also implicitly enable final hop packet handling regardless of the underlying mode. There are also various of other smaller (and bigger) changes:
- Upon receiving a forward packet, its delay is now clamped so that one could not dos the node by asking it to delay it for, for example, a year
- As mentioned above, node can now run in multiple modes at the same time,
- `/metrics/mixing` endpoint got deprecated (it still provides the same information, however) and might be removed in future release
- Introduced `/metrics/packet-stats` endpoint that provides more extensive information about packets received/sent
- It is now possible to control whether the node should log its statistics to console
- The console logs are also updated with the current packet rates
- All nodes now run the "verloc" protocol and measure every other node on the network
- Metrics got revamped and unified:
- All running metrics are stored in a single `NymNodeMetrics` struct
- There exists a `MetricsAggregator` that listens to any metrics events that might require additional processing
- Any new metrics event types can be easily added by registering a new handler via `register_handler`. the type must implement `MetricsHandler` trait and use unique variant of `MetricsEvent` enum. for example `GatewaySessionStatsHandler`. It is, however, possible to have opaque handlers, such as the already implemented `LegacyMixingStatsUpdater` and `MixnetMetricsCleaner`
- Everything in `mixnode` directory has been removed because there was nothing really left there. The mixing socket listener was unified in `nym-node` and similarly `verloc` was also moved there
- `gateway` directory was similarly reduced in size. Now it also creates appropriate tasks as opposed to the whole gateway process. eventually it might also be further stripped, but today is not that day.
- Removed the generic parameter on the `GatewayStorage` to simplify all the generics down the stack. it wasn't used anyway
CLI:
- Added `--modes` argument to specify all node modes with a single command (or `env` variable). for example: `--modes="mixnode,entry"`. Can't be used alongside `--modes`
- Extended `--mode` argument to allow specifying it multiple times, for example: `--mode mixnode --mode entry`. can't be used alongside `--mode`
Config changes:
- Replaced `mode` with `modes` to allow setting the node to run with say, `entry` + `mixnode` roles simultaneously
- Added `maximum_forward_packet_delay` to `mixnet.debug` section
- Moved `verloc` section from `mixnode.verloc` to top level
- Removed `mixnode` section
- Removed `entry_gateway` section to `gateway_tasks`
- Moved `authenticator` section from `gateway_tasks` (`entry_gateway`) to `service_providers` (`exit_gateway`)
- Renamed `exit_gateway` section to `service_providers`
- Moved top level `authenticator` section to `service_providers` so that it'd live alongside NR and IPR
- Added general `debug` section
- Added `metrics` section
- [Better date serialization](https://github.com/nymtech/nym/pull/5207): Proper date serialization for NS API session stats
- [Restore Location fields](https://github.com/nymtech/nym/pull/5208): restore `latitude` and `longitude` fields
- [Derive serialize for UserAgent](https://github.com/nymtech/nym/pull/5210)
- [Change sqlite journal mode to WAL](https://github.com/nymtech/nym/pull/5213)
- [Shipping raw metrics to PG](https://github.com/nymtech/nym/pull/5216)
- [Extend raw ws fd for gateway client](https://github.com/nymtech/nym/pull/5218)
- [Add fd callback to client core](https://github.com/nymtech/nym/pull/5230)
- [TicketType derive Hash and Eq](https://github.com/nymtech/nym/pull/5233): It's useful to keep `TicketType` in maps, which require `Hash`. Also derive `Eq` since it's useful.
- [Extend swagger docs](https://github.com/nymtech/nym/pull/5235)
- [Add FromStr impl for UserAgent](https://github.com/nymtech/nym/pull/5236): Add `FromStr` implementation for `UserAgent` to make it easier to pass in custom user agent in vpn clients as a CLI argument.
- [Remove unneeded async function annotation](https://github.com/nymtech/nym/pull/5246)
- [Add control messages to `GatewayTransciver`](https://github.com/nymtech/nym/pull/5247)
<AccordionTemplate name={<TestingSteps/>}>
**Review and Testing: Forget Me Implementation**
- Validated the encryption and delivery of `ForgetMe` control messages to the gateway
**Testing: MixTrafficController Integration**
- Verified that the `MixTrafficController` invokes `ForgetMe` logic correctly during shutdown
- Tested behaviour for gateway transceiver failures while sending control messages
**Testing: Gateway Storage Updates**
- Confirmed successful deletion of client data (e.g., inbox messages, bandwidth allocations) from persistent storage
</AccordionTemplate>
- [Add conversion unit tests for auth msg](https://github.com/nymtech/nym/pull/5251)
- [Update TS bindings](https://github.com/nymtech/nym/pull/5255)
- [Removed legacy socks5 listener](https://github.com/nymtech/nym/pull/5259)
- [Add PATCH support to `nym-http-api-client`](https://github.com/nymtech/nym/pull/5260): Add `PATCH` support to `nym-http-api-client` crate
- [Wireguard metrics](https://github.com/nymtech/nym/pull/5278): With this PR on each peer controller update the following global metrics information are also updated:
- total bytes tx
- total bytes rx
- current active peers
- total peers registered
- The former two are exposed with REST endpoints `/api/v1/metrics/wireguard-stats`, while the rest will be accessible via prometheus (soon ™️ ). The wireguard stats are also logged to the console (assuming they're non-zero)
- [Add close to credential storage](https://github.com/nymtech/nym/pull/5283): Add close method to credential storage
<AccordionTemplate name={<TestingSteps/>}>
1. **Review File: `common/credential-storage/src/backends/sqlite.rs`**
- Verified addition of `close` method for the SQLite backend
2. **Review File: `common/credential-storage/src/ephemeral_storage.rs`**
- Confirmed addition of `close` method for ephemeral storage with no action required
3. **Review File: `common/credential-storage/src/persistent_storage/mod.rs`**
- Ensured `close` method integration for persistent storage
4. **Review File: `common/credential-storage/src/storage.rs`**
- Verified updates to the `Storage` trait to include `close` and `cleanup_expired` methods
</AccordionTemplate>
- [Cherry picked \#5286](https://github.com/nymtech/nym/pull/5287)
<AccordionTemplate name={<TestingSteps/>}>
1. **Review File: `common/network-defaults/src/constants.rs`**
- Confirmed updated `mixnet_vpn` constants were added.
2. **Review File: `service-providers/ip-packet-router/src/constants.rs`**
- Checked replacement of legacy `TUN_*` constants with new `mixnet_vpn` constants.
- Validated alignment of routing traffic configurations.
3. **Review File: `service-providers/ip-packet-router/src/ip_packet_router.rs`**
- Ensured new `nym_network_defaults::constants::mixnet_vpn` constants replaced old references.
- Verified `TunDeviceConfig` consistency.
4. **Review File: `service-providers/ip-packet-router/src/util/generate_new_ip.rs`**
- Confirmed substitution of `TUN_DEVICE_*` constants with `NYM_TUN_DEVICE_*` constants.
- Tested functionality for generating random IPs within subnet.
</AccordionTemplate>
- [Expand `nym-node` prometheus metrics](https://github.com/nymtech/nym/pull/5298): This PR undusts the `/api/v1/metrics/prometheus` and introduces the following **37** new data points:
<AccordionTemplate name="New data points">
- mixnet:
- ingress:
- `nym_node_mixnet_ingress_forward_hop_packets_received`
- `nym_node_mixnet_ingress_final_hop_packets_received`
- `nym_node_mixnet_ingress_malformed_packets_received`
- `nym_node_mixnet_ingress_excessive_delay_packets`
- `nym_node_mixnet_ingress_forward_hop_packets_dropped`
- `nym_node_mixnet_ingress_final_hop_packets_dropped`
- `nym_node_mixnet_ingress_forward_hop_packets_received_rate`
- `nym_node_mixnet_ingress_final_hop_packets_received_rate`
- `nym_node_mixnet_ingress_malformed_packets_received_rate`
- `nym_node_mixnet_ingress_excessive_delay_packets_rate`
- `nym_node_mixnet_ingress_forward_hop_packets_dropped_rate`
- `nym_node_mixnet_ingress_final_hop_packets_dropped_rate`
- egress:
- `nym_node_mixnet_egress_stored_on_disk_final_hop_packets`
- `nym_node_mixnet_egress_forward_hop_packets_sent`
- `nym_node_mixnet_egress_ack_packets_sent`
- `nym_node_mixnet_egress_forward_hop_packets_dropped`
- `nym_node_mixnet_egress_forward_hop_packets_sent_rate`
- `nym_node_mixnet_egress_ack_packets_sent_rate`
- `nym_node_mixnet_egress_forward_hop_packets_dropped_rate`
- client sessions
- `nym_node_entry_client_sessions_unique_users`
- `nym_node_entry_client_sessions_sessions_started`
- `nym_node_entry_client_sessions_finished_sessions`
- `nym_node_entry_client_sessions_durations_{TYP}` (histogram), for example `nym_node_entry_client_sessions_durations_vpn`
- wireguard:
- `nym_node_wireguard_bytes_rx`
- `nym_node_wireguard_bytes_tx`
- `nym_node_wireguard_bytes_total_peers`
- `nym_node_wireguard_bytes_active_peers`
- `nym_node_wireguard_bytes_rx_rate`
- `nym_node_wireguard_bytes_tx_rate`
- network
- `nym_node_network_active_ingress_mixnet_connections`
- `nym_node_network_active_ingress_web_socket_connections`
- `nym_node_network_active_egress_mixnet_connections`
- process
- `nym_node_process_forward_hop_packets_being_delayed`
- `nym_node_process_packet_forwarder_queue_size`
- `nym_node_process_topology_query_resolution_latency` (histogram)
- `nym_node_process_final_hop_packets_pending_delivery`
- `nym_node_process_forward_hop_packets_pending_delivery`
</AccordionTemplate>
- [Amend 250gb limit](https://github.com/nymtech/nym/pull/5313): Change bandwidth cap to 250gb
- [Warn users if node is run in exit mode only](https://github.com/nymtech/nym/pull/5320): Throws a warning if node is run in "exit" mode only as by default, this will **NOT** enable entry capabilities, i.e. opening the websocket. thus making it ineligible for rewarded set selection (and rewards)
- [Reduce log severity for number of packets being delayed](https://github.com/nymtech/nym/pull/5321)
- [Apply 1.84 linter suggestions](https://github.com/nymtech/nym/pull/5330)
- [Readjusted --mode behaviour to fix the regression](https://github.com/nymtech/nym/pull/5331)
- [Legacy alert](https://github.com/nymtech/nym/pull/5346): alert moved into `nav` components
### Bugfix
- [Fix overflow](https://github.com/nymtech/nym/pull/5184)
- [Fix overflow again](https://github.com/nymtech/nym/pull/5204)
- [Make sure to update timestamp of last batch verification to prevent double redemption](https://github.com/nymtech/nym/pull/5239)
- [Make sure to apply gateway score filtering when choosing initial node](https://github.com/nymtech/nym/pull/5256)
- [Fixed client session histogram buckets](https://github.com/nymtech/nym/pull/5316)
- [Contract version assignment](https://github.com/nymtech/nym/pull/5318): This PR fixes updates to current nym-node version as well as introduces migration to fix the existing state of the mainnet contract
- [Make sure refresh data key matches bond info](https://github.com/nymtech/nym/pull/5329): This is to forbid operators from reusing the same underlying identity key for multiple nodes by overwriting the describe data. the reported key has to always match what the node has bonded with (and the contract enforces uniqueness)
## Archived Changelog
To allow reading through older changelogs, we store them below sorted by years.
@@ -2,7 +2,7 @@
## Nym Network
To see different stats about Nym Network live, we recommend you to visit [Nym Harbourmaster](https://harbourmaster.nymtech.net) and dynamic [Nym token page](https://nymtech.net/about/token.
To see different stats about Nym Network live, we recommend you to visit [Nym Harbourmaster](https://harbourmaster.nymtech.net) and dynamic [Nym token page](https://nymtech.net/about/token).
### Is there an explorer for Nym Mixnet?
@@ -12,7 +12,7 @@ Yes, there are..
* [Nym Explorer](https://explorer.nymtech.net/)
* [Sandbox testnet](https://sandbox-explorer.nymtech.net/)
* [Nym Harbourmaster](https://harbourmaster.nymtech.net)
* [Nym Harbourmaster](https://harbourmaster.nymtech.net)
**Built by community**
@@ -43,5 +43,3 @@ At this point the most crucial component needed are [Exit Gateways](../nodes/nym
### Are Nym Nodes whitelisted?
Nope, anyone can run a Nym Node. whether your node is chosen to mix is purely reliant on the node's performance and reputation (self stake + delegations).
+12 -7
View File
@@ -2,6 +2,7 @@ import { Callout } from 'nextra/components';
import { Steps } from 'nextra/components';
import { Tabs } from 'nextra/components';
import NymNodeSpecs from 'components/operators/snippets/nym-node-specs.mdx';
import TermsConditions from 'components/operators/snippets/tc-info.mdx';
# Nym Nodes Operator Guides
@@ -25,21 +26,25 @@ Reserve 45-120 minutes for the initial setup and configuration (depends on your
Outdated nodes are never selected for routing/mixing packets, resulting in not receiving any rewards. You can read more on our [Tokenomics page](tokenomics/mixnet-rewards.mdx) to understand the selection and rewards logic.
<TermsConditions />
Accepting T&Cs is done via a flag `--accept-operator-terms-and-conditions` added explicitly to `nym-node run` command every time. Detailed info and proper syntax is provided on the [setup page](nodes/nym-node/setup#terms--conditions).
## Steps for Nym Node Operators
This is a summary of all needed steps for node operators to setup and configure a `nym-node` and register it to Nym Network:
1. **Start with [Preliminary Steps](preliminary-steps.mdx), preparing:**
- [VPS](preliminary-steps/vps-setup.mdx)
- [Nym wallet](preliminary-steps/wallet-preparation/mdx)
1. **Start with [Preliminary Steps](nodes/preliminary-steps.mdx), preparing:**
- [VPS](nodes/preliminary-steps/vps-setup.mdx)
- [Nym wallet](nodes/preliminary-steps/wallet-preparation)
2. **[Setup](nym-node/setup.mdx) the node**
2. **[Setup](nodes/nym-node/setup.mdx) the node**
3. **[Configure](nym-node/configuration.mdx) the node and (optionally) automation, Wireguard, WSS, reverse proxy ...**
3. **[Configure](nodes/nym-node/configuration.mdx) the node and (optionally) automation, Wireguard, WSS, reverse proxy ...**
4. **[Run](nym-node/setup.mdx#initialise--run) the node or [the service](nym-node/configuration.md#systemd)**
4. **[Run](nodes/nym-node/setup.mdx#initialise--run) the node or [the service](nodes/nym-node/configuration.md#systemd)**
5. **[Bond](nym-node/bonding.mdx) the node to the Nym API, using Nym wallet**
5. **[Bond](nodes/nym-node/bonding.mdx) the node to the Nym API, using Nym wallet**
Make sure to follow the steps thoroughly, in case you find any point difficult don't hesitate to ask in our [Operators channel](https://matrix.to/#/#operators:nymtech.chat).
@@ -1,8 +1,8 @@
import { VarInfo } from 'components/variable-info.tsx'
import { VarInfo } from 'components/variable-info.tsx';
import {Callout} from 'nextra/components';
# Nym Node
NYM NODE is a tool for running a node within the Nym network. Nym Nodes containing functionality such as `mixnode`, `entry-gateway` and `exit-gateway` are fundamental components of Nym Mixnet architecture. Nym Nodes are ran by decentralised node operators.
To setup any type of Nym Node, start with either building [Nym's platform](../binaries/building-nym.mdx) from source or download [pre-compiled binaries](../binaries/pre-built-binaries.mdx) on the [configured server (VPS)](preliminary-steps/vps-setup.mdx) where you want to run the node. Your Nym Node will need to be bonded before it can be run. We recommend most users use the [Nym desktop wallet](preliminary-steps/wallet-preparation.mdx) for this.
@@ -30,6 +30,10 @@ Any new bonded node will provide only the bare minimum information: host, identi
**Every operator has to make sure that their nodes [self-described endpoint works](nodes/performance-and-testing/node-api-check#basic-api-usage), otherwise the node will be un-routable and thus won't get any rewards!**
<Callout type="warning" emoji="⚠️">
**Reveal your menominc phrase only in areas out of surveillance of other people and never share it with others. Nym team will never ask you for your mnemonic phrase - in case you were asked by someone it's a scam, do *not* reply to it!**
</Callout>
## Bond via the Desktop wallet (recommended)
You can bond your `nym-node` via the Desktop wallet.
@@ -150,3 +154,48 @@ Versions older than `nym-wallet v 1.2.15` will not allow bonding new nodes.
## Bond via the CLI (power users)
If you want to bond your Mix Node via the CLI, then check out the [relevant section in the Nym CLI](../../../developers/tools/nym-cli/usage#usage) docs.
## Fund `nym-node` Client Nyx Account
<Callout type="info">
This is not relevant for operators running exclusively `mixnode` functionality. For any type of gateway functionality this is a preparation requirement for the upcoming [ticket rewarding](../../tokenomics/mixnet-rewards#roadmap).
</ Callout>
Every `nym-node` client contains a mnemonic of a Nyx account, generated with node initialisation (first `run` command creating all configuration and data files). This mnemonic is located in `$HOME/.nym/nym-nodes/<ID>/data/cosmos_mnemonic`. **This is *not* the same account as the one used for bondng!**
This client account will be used for the process of redemption of tickets collected by nodes running as `entry-gateway` and `exit-gateway` as the redemption requires gateway to create a multisig proposal on the chain for which the client (node) needs to pay transaction fee.
Giving the low transaction cost on Cosmos, funding your client Nyx account with 25 NYM tokens should be more than enough. To do so, follow these steps:
<Steps>
###### 1. Get your `nym-node` client Nyx account mnemonic phrase
- Make sure your screen is not exposed to other people or recording devices
- To store sensitive credentials use audited and open source password managers, like [KeePassXC](https://keepassxc.org/)
- To print out your node client mnemonic phrase, run:
```sh
cat $HOME/.nym/nym-nodes/<ID>/data/cosmos_mnemonic
```
```sh
# for example
# cat $HOME/.nym/nym-nodes/default-nym-node/data/cosmos_mnemonic
```
- **Alternatively:** You can use `scp` command to copy the file `cosmos_mnemonic` remotely. If this is your preference, use this command:
```sh
scp <USER>@<HOST>:.nym/nym-nodes/<ID>/data/cosmos_mnemonic <LOCAL_TARGET_PATH>
```
- Copy this phrase and save it to your password manager
###### 2. Get the address of your client Nyx account using desktop wallet
- Open desktop wallet and choose to sign in with mnemonic
- Use the phrase from step 1
- Open `Receive` tab and copy Nym account address
- We recommend operators to store this address for future funding
###### 3. Fund the client Nyx account
- Open wallet with Nym tokens and send a minimum of 25 NYM to the address copied in the previous step
- In case you don't have any spare NYM, you can send tokens from any exchange directly to the address copied in the previous step
</ Steps>
Now your `nym-node` client can use inbuilt Nyx account to create a multisig proposal on chain and redeem user tickets.
@@ -7,22 +7,25 @@ import BuildInfo from 'components/outputs/command-outputs/nym-node-build-info.md
import NymNodeHelp from 'components/outputs/command-outputs/nym-node-help.md';
import NymNodeRunHelp from 'components/outputs/command-outputs/nym-node-run-help.md';
import { AccordionTemplate } from 'components/accordion-template.tsx';
import TermsConditions from 'components/operators/snippets/tc-info.mdx';
# Nym Node Setup & Run
This documentation page provides a guide on how to set up and run a [NYM NODE](../nym-node.mdx), along with explanations of available flags, commands, and examples.
<VarInfo/ >
## Current version
```sh
nym-node
Binary Name: nym-node
Build Timestamp: 2024-12-18T10:18:42.978852430Z
Build Version: 1.2.1
Commit SHA: 8d5a41a790e96ae5e821964865affaa7d3343eab
Commit Date: 2024-12-18T11:07:49.000000000+01:00
Build Timestamp: 2025-01-15T09:50:54.404428047Z
Build Version: 1.3.0
Commit SHA: c202e2d598fabda5fc16a6c1e110255857a2b1ca
Commit Date: 2025-01-15T10:27:39.000000000+01:00
Commit Branch: HEAD
rustc Version: 1.83.0
rustc Version: 1.84.0
rustc Channel: stable
cargo Profile: release
```
@@ -31,52 +34,39 @@ cargo Profile: release
<BuildInfo />
*/}
## Summary
## Functionality (mode)
<Callout type="info">
From `nym-node v1.3.0` operators can choose multiple functionalities for their `nym-node` binary (flagged as `--mode`).
<VarInfo/ >
**However, the clients are yet to be developed to be able to make a proper selection for multi-mode nodes and therefore we ask operators to sign only one functionality to `--mode` option at a time. Please chose out of: `mixnode` or `entry-gateway` or `exit-gateway`.**
To run a new node, you can simply execute the `nym-node` command without any flags. By default, the node will set necessary configurations. If you later decide to change a setting, you can use the `-w` flag.
We are developing a design where operators can enable multiple modes, and let the Nym API to position the node according the network's needs in the beginning of each epoch.
</Callout>
The most crucial aspect of running the node is specifying the `--mode`. At the moment it can be only one of three: `mixnode`, `entry-gateway`, and `exit-gateway`.
Nym Node has three functionalities in the network: `entry-gateway`, `mixnode` and `exit-gateway`.
Currently the `nym-node` binary can only be run in a single `--mode` at any one time. In the future however, operators will be able to specify multiple modes that a single `nym-node` binary can run. Our goal is to have as many nodes as possible enabling multiple modes, and allow the Nym API to position the node according the network's needs in the beginning of each epoch.
- **Entry Gateway (`--mode entry-gateway`)**: A the node to which local client connects. It checks the bandwidth allowance, using [zk-nyms](../../../network/cryptography/zk-nym) and either sends [Sphinx packets](../../../network/cryptography/sphinx) through the mixnet or directly to Exit Gateway in case of dVPN (2-hop) routing. This node also recieves replies and sends them back to users local client.
Every `exit-gateway` mode is basically an `entry-gateway` with NR (Network Requester) and IPR (IP Packet Router) enabled. This means that every `exit-gateway` is automatically seen as an `entry-gateway` but not the opposite.
- **Mixnode (`--mode mixnode`)**: Nodes organized in three layers, randmoly selected every epoch (60 minutes), mixing Sphinx packets, adding a slight latency to defend users agains time correlation attacks and sending them further to the next layer or to the Exit Gateway
Gateway operators can check out the node performance, connectivity and much more in our new tool [harbourmaster.nymtech.net](https://harbourmaster.nymtech.net/).
- **Exit Gateway (`--mode exit-gateway`)**: The final node in the mixnet. It puts all packets together and using inbuilt Network requester and IP packet router, it sends traffic to the open internet. This node also recieves replies and sends them back to the user client.
To determine which mode your node is running, you can check the `:8080/api/v1/roles` endpoint. For example:
```sh
# sustitude <IPv4_ADDRESS> or <HOSTNAME> with the one corresponding to your node
# for http
http://<IPv4_ADDRESS>:8080/api/v1/roles
# or
http://<IPv4_ADDRESS>/api/v1/roles
<Callout type="warning">
Exit Gateway is the only node routing data directly to the open internet. Therefore it exposes IP of operators server (VPS) to abuse complains. Before you decide to run an Exit Gateway, please read our [Community Counsel pages](../../community-counsel/exit-gateway) containing more information and some legal content.
</Callout>
# for reversed proxy/WSS
https://<HOSTNAME>/api/v1/roles
```
Everything essential for each mode exists on `nym-node` by default. For instance, if you run a Mixnode, you'll find that a NR (Network Requester) and IPR (IP Packet Router) addresses exist, but they will be ignored in `mixnode` mode.
Everything necessary will exist on your node by default. For instance, if you're running a mixnode, you'll find that a NR (Network Requester) and IPR (IP Packet Router) address exist, but they will be ignored in `mixnode` mode.
Note that every `exit-gateway` mode is basically an `entry-gateway` with NR (Network Requester) and IPR (IP Packet Router) enabled. This means that every `exit-gateway` can work as an `entry-gateway` but not the opposite.
For more information about available endpoints and their status, you can refer to:
```sh
# sustitude <IPv4_ADDRESS> or <HOSTNAME> with the one corresponding to your node
# for http
http://<IPv4_ADDRESS>:8080/api/v1/swagger/#/
# or
http://<IPv4_ADDRESS>/api/v1/swagger/#/
## Command & Examples
# for reversed proxy/WSS
https://<HOSTNAME>/api/v1/swagger/#/
```
## Usage
**`nym-node` introduces a default human readible ID (local only) `default-nym-node`, which is used if there is not an explicit custom `--id <ID>` specified. All configuration is stored in `~/.nym/nym-nodes/default-nym-node/config/config.toml` or `~/.nym/nym-nodes/<ID>/config/config.toml` respectively.**
### Help Command
There are a few changes from the individual binaries used in the past. For example by default `run` command does `init` function as well, local node `--id` will be set by default unless specified otherwise etcetera.
There are a few changes from the individual binaries used in the past. For example by default `run` command does initialisation function as well, local node `--id` will be set by default (1default-nym-node`) unless specified otherwise.
<Callout type="info" emoji="️">
You can always use `--help` flag to see the commands or arguments associated with a given command.
@@ -96,13 +86,7 @@ To list all available flags for each command, run `./nym-node <COMMAND> --help`
The Wireguard flags currently have limited functionality. From version `1.1.6` ([`v2024.9-topdeck`](https://github.com/nymtech/nym/releases/tag/nym-binaries-v2024.9-topdeck)) wireguard is available and recommended to be switched on for nodes running as Gateways. Keep in mind that this option needs a bit of a special [configuration](configuration.md#wireguard-setup).
</Callout>
### Terms & Conditions
<Callout type="info" emoji="️">
From `nym-node` version `1.1.3` onward is required to accept [**Operators Terms & Conditions**](https://nymtech.net/terms-and-conditions/operators/v1.0.0) in order to be part of the active set. Make sure to read them before you add the flag.
</Callout>
There has been a long ongoing discussion whether and how to apply Terms and Conditions for Nym network operators, with an aim to stay aligned with the philosophy of Free Software and provide legal defense for both node operators and Nym developers. To understand better the reasoning behind this decision, you can listen to the first [Nym Operator Town Hall](https://www.youtube.com/live/7hwb8bAZIuc?si=3mQ2ed7AyUA1SsCp&t=915) introducing the T&Cs or to [Operator AMA with CEO Harry Halpin](https://www.youtube.com/watch?v=yIN-zYQw0I0) from June 4th, 2024, explaining pros and cons of T&Cs implementation.
<TermsConditions />
Accepting T&Cs is done via a flag `--accept-operator-terms-and-conditions` added explicitly to `nym-node run` command every time. If you use [systemd](configuration.md#systemd) automation, add the flag to your service file's `ExecStart` line.
@@ -126,14 +110,6 @@ curl -X 'GET' \
}
```
### Commands & Examples
**`nym-node` introduces a default human readible ID (local only) `default-nym-node`, which is used if there is not an explicit custom `--id <ID>` specified. All configuration is stored in `~/.nym/nym-nodes/default-nym-node/config/config.toml` or `~/.nym/nym-nodes/<ID>/config/config.toml` respectively.**
<Callout type="info" emoji="️">
All commands with more options listed below include `--accept-operator-terms-and-conditions` flag, read [Terms & Conditions](#terms--conditions) chapter above before executing these commands.
</Callout>
#### Essential Parameters & Variables
Running a `nym-node` in a `mixnode` mode requires less configuration than a full `exit-gateway` setup, we recommend operators to still follow through with all documented [configuration](configuration.md). Before you scroll down to syntax examples for the mode of your choice please familiarise yourself with the essential [paramters and variables](../../variables.mdx) convention we use in the guide.
@@ -143,13 +119,13 @@ To prevent over-flooding of our documentation we cannot provide with every singl
</Callout>
### Initialise & Run
## Setup & Run
When we use `run` command the node will do `init` as well, unless we specify with a flag `--deny-init`. Below are some examples of initialising and running `nym-node` with different modes (`--mode`) like `mixnode`, `entry-gateway`, `exit-gateway`.
When we use `run` command for the first time the node will initialise all essential configuration and data files (unless specified with a flag `--deny-init`) stored at `$HOME/.nym/nym-nodes/<ID>` where the most important is the `config.toml` file stored at `$HOME/.nym/nym-nodes/<ID>/config/`. Below are some examples of initialising and running `nym-node` with different modes (`--mode`) like `mixnode`, `entry-gateway`, `exit-gateway`.
Please keep in mind that currently you can run only one functionality (`--mode`) per a `nym-node` instance. We are yet to finalise implement the multi-functionality solution under one node bonded to one Nyx account. Every `exit-gateway` can function as `entry-gateway` by default, not vice versa.
Please keep in mind that currently we ask operators to run only one functionality (`--mode`) at a time.
There is a simple default command to initialise and run your node: `./nym-node run --mode <MODE>`, however there quite a few parameters to be configured. When `nym-node` gets to be `run`, these parameters are read by the binary from the configuration file located at `.nym/nym-nodes/<ID>/config/config.toml`.
There is a simple default command to initialise and run your node: `./nym-node run --mode <MODE>`, however there quite a few parameters to be configured.
If an operator specifies any paramteres with optional flags alongside `run` command, these parameters passed in the option will take place over the ones in `config.toml` but they will not overwrite them by default. To overwrite them with the values passed with `run` command, a flag `-w` (`--write-changes`) must be added.
@@ -165,7 +141,7 @@ Alternatively operators can just open a text editor and change these values manu
In such case, you can `run` a node to initalise it or try if everything works, but then stop the proces and paste your entire `run` command syntax (below) to the `ExecStart` line of your `/etc/systemd/system/nym-node.service` and start the node as a [service](configuration.md#following-steps-for-nym-nodes-running-as-systemd-service).
</Callout>
### Migrate
## Migrate
<Callout type="warning">
**Legacy binaries `nym-mixnode` and `nym-gateway` had been deprecated, [`nym-node`](../nym-node.mdx) is the only binary to use for `gateway` or `mixnode` functionalities!**
@@ -186,7 +162,35 @@ Make sure to use `--deny-init` flag to prevent initialisation of a new node.
**After you upgraded your node to the latest release of `nym-node`, make sure that you also follow [the steps to migrate your node in the Mixnet smart contract](bonding#migrate-to-nym-node-in-mixnet-smart-contract), othewise your node will never receive any rewards.**
### Next steps
## Functionality & Performance Check
We have a chapter called [Performance Monitoring & Testing](../nodes/performance-and-testing) including much more information and tooling. If you want to just quickly check your nodes performance, connectivity and much more, visit [harbourmaster.nymtech.net](https://harbourmaster.nymtech.net/).
For more information about available endpoints and their status, you can refer to:
```sh
# sustitude <IPv4_ADDRESS> or <HOSTNAME> with the one corresponding to your node
# for http
http://<IPv4_ADDRESS>:8080/api/v1/swagger/#/
# or
http://<IPv4_ADDRESS>/api/v1/swagger/#/
# for reversed proxy/WSS
https://<HOSTNAME>/api/v1/swagger/#/
```
For example to determine which mode your node is running, you can check the `:8080/api/v1/roles` endpoint. For example:
```sh
# sustitude <IPv4_ADDRESS> or <HOSTNAME> with the one corresponding to your node
# for http
http://<IPv4_ADDRESS>:8080/api/v1/roles
# or
http://<IPv4_ADDRESS>/api/v1/roles
# for reversed proxy/WSS
https://<HOSTNAME>/api/v1/roles
```
## Next steps
If there are any problems checkout the troubleshooting section or report an issue.
@@ -4,7 +4,7 @@
There are a couple of steps that need completing before starting to set up your `nym-node`:
1. **[Prepare your wallet](preliminary-steps/wallet-preparation.mdx):** [desktop](https://nym.com/download/wallet) or [CLI](../../developers/tools/nym-cli/commands.mdx).
1. **[Prepare your wallet](preliminary-steps/wallet-preparation.mdx):** [desktop](https://nym.com/wallet) or [CLI](../../developers/tools/nym-cli/commands.mdx).
2. **[Requisition and setup a VPS](preliminary-steps/vps-setup.mdx)** (Virtual Private Server)
Make sure to follow these steps carefully as it prevents a lot of troubleshooting later on.
@@ -2,7 +2,7 @@
## Mainnet
Head to our [website](https://nym.com/download/wallet) and download Nym wallet for your operating system.
Head to our [website](https://nym.com/wallet) and download Nym wallet for your operating system.
{/*
@@ -47,7 +47,7 @@ curl -o sandbox.env -L https://raw.githubusercontent.com/nymtech/nym/develop/env
- In case you downloaded `sandbox.env` to same directory, `<PATH>` is not needed
###### 3. Bond your node to Nym Sandbox environment
- Open [Nym Wallet](https://nym.com/download/wallet) and switch to testnet
- Open [Nym Wallet](https://nym.com/wallet) and switch to testnet
- Go to [faucet.nymtech.net](https://faucet.nymtech.net) and aquire 101 testnet NYM tokens
- Follow the steps on the [bonding page](nodes/nym-node/bonding.mdx)
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "explorer-api"
version = "1.1.44"
version = "1.1.45"
edition = "2021"
license.workspace = true
+1 -1
View File
@@ -4,7 +4,7 @@
[package]
name = "nym-api"
license = "GPL-3.0"
version = "1.1.48"
version = "1.1.49"
authors.workspace = true
edition = "2021"
rust-version.workspace = true
+6 -7
View File
@@ -12,7 +12,8 @@ use js_sys::Promise;
use std::sync::Arc;
use wasm_bindgen::prelude::*;
use wasm_bindgen_futures::future_to_promise;
use wasm_storage::{IdbVersionChangeEvent, WasmStorage};
use wasm_storage::RawDbResult;
use wasm_storage::{Build, Database, VersionChangeEvent, WasmStorage};
use wasm_utils::check_promise_result;
use wasm_utils::error::{PromisableResult, PromisableResultError};
use zeroize::Zeroizing;
@@ -33,8 +34,8 @@ pub struct ExtensionStorage {
}
#[allow(clippy::type_complexity)]
fn db_migration() -> Box<dyn Fn(&IdbVersionChangeEvent) -> Result<(), JsValue>> {
Box::new(|evt: &IdbVersionChangeEvent| -> Result<(), JsValue> {
fn db_migration() -> Box<dyn Fn(VersionChangeEvent, Database) -> RawDbResult<()>> {
Box::new(|evt: VersionChangeEvent, db: Database| -> RawDbResult<()> {
// Even if the web-sys bindings expose the version as a f64, the IndexedDB API
// works with an unsigned integer.
// See <https://github.com/rustwasm/wasm-bindgen/issues/1149>
@@ -42,9 +43,7 @@ fn db_migration() -> Box<dyn Fn(&IdbVersionChangeEvent) -> Result<(), JsValue>>
if old_version < 1 {
// migrating to version 1
let db = evt.db();
db.create_object_store(v1::MNEMONICS_STORE)?;
db.create_object_store(v1::MNEMONICS_STORE).build()?;
}
Ok(())
@@ -122,7 +121,7 @@ impl ExtensionStorage {
.map_err(Into::into)
}
async fn get_all_mnemonic_keys_async(&self) -> Result<js_sys::Array, ExtensionStorageError> {
async fn get_all_mnemonic_keys_async(&self) -> Result<Vec<JsValue>, ExtensionStorageError> {
self.inner
.get_all_keys(v1::MNEMONICS_STORE)
.await
+2 -1
View File
@@ -3,7 +3,7 @@
[package]
name = "nym-node"
version = "1.3.1"
version = "1.4.0"
authors.workspace = true
repository.workspace = true
homepage.workspace = true
@@ -16,6 +16,7 @@ license = "GPL-3.0"
[dependencies]
async-trait = { workspace = true }
anyhow.workspace = true
arc-swap = { workspace = true }
bip39 = { workspace = true, features = ["zeroize"] }
bs58.workspace = true
celes = { workspace = true } # country codes
+1 -1
View File
@@ -11,13 +11,13 @@ license.workspace = true
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
base64 = { workspace = true }
celes = { workspace = true } # country codes
humantime = { workspace = true }
humantime-serde = { workspace = true }
schemars = { workspace = true, features = ["preserve_order"] }
serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true }
strum = { workspace = true, features = ["derive"] }
time = { workspace = true, features = ["serde", "formatting", "parsing"] }
thiserror = { workspace = true }
+7 -3
View File
@@ -11,16 +11,16 @@ use async_trait::async_trait;
use nym_bin_common::build_information::BinaryBuildInformationOwned;
use nym_http_api_client::{ApiClient, HttpClientError};
use super::v1::gateway::models::Wireguard;
use super::v1::metrics::models::SessionStats;
use crate::api::v1::authenticator::models::Authenticator;
use crate::api::v1::health::models::NodeHealth;
use crate::api::v1::ip_packet_router::models::IpPacketRouter;
use crate::api::v1::network_requester::exit_policy::models::UsedExitPolicy;
use crate::api::v1::network_requester::models::NetworkRequester;
use crate::api::v1::node_load::models::NodeLoad;
pub use nym_http_api_client::Client;
use super::v1::gateway::models::Wireguard;
use super::v1::metrics::models::SessionStats;
pub type NymNodeApiClientError = HttpClientError<ErrorResponse>;
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
@@ -30,6 +30,10 @@ pub trait NymNodeApiClientExt: ApiClient {
self.get_json_from(routes::api::v1::health_absolute()).await
}
async fn get_node_load(&self) -> Result<NodeLoad, NymNodeApiClientError> {
self.get_json_from(routes::api::v1::load_absolute()).await
}
async fn get_host_information(&self) -> Result<SignedHostInformation, NymNodeApiClientError> {
self.get_json_from(routes::api::v1::host_info_absolute())
.await
@@ -9,3 +9,4 @@ pub mod metrics;
pub mod mixnode;
pub mod network_requester;
pub mod node;
pub mod node_load;
@@ -0,0 +1,4 @@
// Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
pub mod models;
@@ -0,0 +1,79 @@
// Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use strum::{Display, EnumString};
#[derive(
Display,
Default,
Serialize,
Deserialize,
Clone,
Copy,
Debug,
EnumString,
PartialEq,
Eq,
JsonSchema,
PartialOrd,
)]
#[serde(rename_all = "snake_case")]
#[strum(serialize_all = "snake_case")]
#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
pub enum Load {
#[default]
Unknown,
// order of the variants matter as we've derived `PartialOrd` on them
Negligible, // 0 - 0.1
Low, // 0.1 - 0.3
Medium, // 0.3 - 0.6
High, // 0.6 - 0.8
VeryHigh, // 0.8 - 0.95
AtCapacity, // >= 0.95
}
impl Load {
// returns load of one tier higher
pub fn increment(&self) -> Self {
match self {
Self::Unknown => Self::Unknown,
Self::Negligible => Self::Low,
Self::Low => Self::Medium,
Self::Medium => Self::High,
Self::High => Self::VeryHigh,
Self::VeryHigh => Self::AtCapacity,
Self::AtCapacity => Self::AtCapacity,
}
}
}
impl From<f64> for Load {
fn from(value: f64) -> Self {
if value == 0. || value.is_nan() || value.is_infinite() {
Self::Unknown
} else if value <= 0.1 {
Self::Negligible
} else if value <= 0.3 {
Self::Low
} else if value <= 0.6 {
Self::Medium
} else if value <= 0.8 {
Self::High
} else if value <= 0.95 {
Self::VeryHigh
} else {
Self::AtCapacity
}
}
}
#[derive(Serialize, Deserialize, Debug, Clone, Copy, JsonSchema)]
#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
pub struct NodeLoad {
pub total: Load,
pub machine: Load,
pub network: Load,
}
+2
View File
@@ -35,6 +35,7 @@ pub mod routes {
pub const NODE_DESCRIPTION: &str = "/description";
pub const AUXILIARY: &str = "/auxiliary-details";
pub const HEALTH: &str = "/health";
pub const LOAD: &str = "/load";
pub const SWAGGER: &str = "/swagger";
pub const GATEWAY: &str = "/gateway";
@@ -46,6 +47,7 @@ pub mod routes {
// define helper functions to get absolute routes
absolute_route!(health_absolute, v1_absolute(), HEALTH);
absolute_route!(load_absolute, v1_absolute(), LOAD);
absolute_route!(roles_absolute, v1_absolute(), ROLES);
absolute_route!(build_info_absolute, v1_absolute(), BUILD_INFO);
absolute_route!(host_info_absolute, v1_absolute(), HOST_INFO);
+6 -6
View File
@@ -101,7 +101,7 @@ impl HostArgs {
#[derive(clap::Args, Debug)]
pub(crate) struct HttpArgs {
/// Socket address this node will use for binding its http API.
/// default: `0.0.0.0:8080`
/// default: `[::]:8080`
#[clap(
long,
env = NYMNODE_HTTP_BIND_ADDRESS_ARG
@@ -181,7 +181,7 @@ impl HttpArgs {
#[derive(clap::Args, Debug)]
pub(crate) struct MixnetArgs {
/// Address this node will bind to for listening for mixnet packets
/// default: `0.0.0.0:1789`
/// default: `[::]:1789`
#[clap(
long,
env = NYMNODE_MIXNET_BIND_ADDRESS_ARG
@@ -258,7 +258,7 @@ pub(crate) struct WireguardArgs {
pub(crate) wireguard_enabled: Option<bool>,
/// Socket address this node will use for binding its wireguard interface.
/// default: `0.0.0.0:51822`
/// default: `[::]:51822`
#[clap(
long,
env = NYMNODE_WG_BIND_ADDRESS_ARG
@@ -315,7 +315,7 @@ impl WireguardArgs {
#[derive(clap::Args, Debug)]
pub(crate) struct VerlocArgs {
/// Socket address this node will use for binding its verloc API.
/// default: `0.0.0.0:1790`
/// default: `[::]:1790`
#[clap(
long,
env = NYMNODE_VERLOC_BIND_ADDRESS_ARG
@@ -377,7 +377,7 @@ impl MetricsArgs {
#[derive(clap::Args, Debug, Zeroize, ZeroizeOnDrop)]
pub(crate) struct EntryGatewayArgs {
/// Socket address this node will use for binding its client websocket API.
/// default: `0.0.0.0:9000`
/// default: `[::]:9000`
#[clap(
long,
env = NYMNODE_ENTRY_BIND_ADDRESS_ARG
@@ -431,7 +431,7 @@ impl EntryGatewayArgs {
mut section: config::GatewayTasksConfig,
) -> config::GatewayTasksConfig {
if let Some(bind_address) = self.entry_bind_address {
section.bind_address = bind_address
section.ws_bind_address = bind_address
}
if let Some(ws_port) = self.announce_ws_port {
section.announce_ws_port = Some(ws_port)
+5 -5
View File
@@ -3,7 +3,7 @@
use crate::config::persistence::GatewayTasksPaths;
use nym_config::defaults::{DEFAULT_CLIENT_LISTENING_PORT, TICKETBOOK_VALIDITY_DAYS};
use nym_config::helpers::inaddr_any;
use nym_config::helpers::in6addr_any_init;
use nym_config::serde_helpers::de_maybe_port;
use serde::{Deserialize, Serialize};
use std::net::SocketAddr;
@@ -22,8 +22,8 @@ pub struct GatewayTasksConfig {
pub enforce_zk_nyms: bool,
/// Socket address this node will use for binding its client websocket API.
/// default: `0.0.0.0:9000`
pub bind_address: SocketAddr,
/// default: `[::]:9000`
pub ws_bind_address: SocketAddr,
/// Custom announced port for listening for websocket client traffic.
/// If unspecified, the value from the `bind_address` will be used instead
@@ -97,7 +97,7 @@ pub struct ZkNymTicketHandlerDebug {
impl ZkNymTicketHandlerDebug {
pub const DEFAULT_REVOCATION_BANDWIDTH_PENALTY: f32 = 10.0;
pub const DEFAULT_PENDING_POLLER: Duration = Duration::from_secs(300);
pub const DEFAULT_MINIMUM_API_QUORUM: f32 = 0.8;
pub const DEFAULT_MINIMUM_API_QUORUM: f32 = 0.7;
pub const DEFAULT_MINIMUM_REDEMPTION_TICKETS: usize = 100;
// use min(4/5 of max validity, validity - 1), but making sure it's no greater than 1 day
@@ -188,7 +188,7 @@ impl GatewayTasksConfig {
GatewayTasksConfig {
storage_paths: GatewayTasksPaths::new(data_dir),
enforce_zk_nyms: false,
bind_address: SocketAddr::new(inaddr_any(), DEFAULT_WS_PORT),
ws_bind_address: SocketAddr::new(in6addr_any_init(), DEFAULT_WS_PORT),
announce_ws_port: None,
announce_wss_port: None,
debug: Default::default(),
+1 -1
View File
@@ -13,7 +13,7 @@ fn ephemeral_gateway_config(config: &Config) -> nym_gateway::config::Config {
nym_gateway::config::Config::new(
nym_gateway::config::Gateway {
enforce_zk_nyms: config.gateway_tasks.enforce_zk_nyms,
websocket_bind_address: config.gateway_tasks.bind_address,
websocket_bind_address: config.gateway_tasks.ws_bind_address,
nym_api_urls: config.mixnet.nym_api_urls.clone(),
nyxd_urls: config.mixnet.nyxd_urls.clone(),
},
+18 -8
View File
@@ -13,7 +13,7 @@ use nym_config::defaults::{
WG_TUN_DEVICE_IP_ADDRESS_V6,
};
use nym_config::defaults::{WG_TUN_DEVICE_NETMASK_V4, WG_TUN_DEVICE_NETMASK_V6};
use nym_config::helpers::inaddr_any;
use nym_config::helpers::{in6addr_any_init, inaddr_any};
use nym_config::serde_helpers::de_maybe_port;
use nym_config::serde_helpers::de_maybe_stringified;
use nym_config::{
@@ -444,7 +444,7 @@ pub struct Host {
#[serde(deny_unknown_fields)]
pub struct Http {
/// Socket address this node will use for binding its http API.
/// default: `0.0.0.0:8080`
/// default: `[::]:8080`
pub bind_address: SocketAddr,
/// Path to assets directory of custom landing page of this node.
@@ -470,17 +470,27 @@ pub struct Http {
/// This option is superseded by `expose_system_hardware`
/// default: true
pub expose_crypto_hardware: bool,
/// Specify the cache ttl of the node load.
/// default: 30s
#[serde(with = "humantime_serde")]
pub node_load_cache_ttl: Duration,
}
impl Http {
pub const DEFAULT_NODE_LOAD_CACHE_TTL: Duration = Duration::from_secs(30);
}
impl Default for Http {
fn default() -> Self {
Http {
bind_address: SocketAddr::new(inaddr_any(), DEFAULT_HTTP_PORT),
bind_address: SocketAddr::new(in6addr_any_init(), DEFAULT_HTTP_PORT),
landing_page_assets_path: None,
access_token: None,
expose_system_info: true,
expose_system_hardware: true,
expose_crypto_hardware: true,
node_load_cache_ttl: Self::DEFAULT_NODE_LOAD_CACHE_TTL,
}
}
}
@@ -490,7 +500,7 @@ impl Default for Http {
#[serde(deny_unknown_fields)]
pub struct Mixnet {
/// Address this node will bind to for listening for mixnet packets
/// default: `0.0.0.0:1789`
/// default: `[::]:1789`
pub bind_address: SocketAddr,
/// If applicable, custom port announced in the self-described API that other clients and nodes
@@ -584,7 +594,7 @@ impl Default for Mixnet {
};
Mixnet {
bind_address: SocketAddr::new(inaddr_any(), DEFAULT_MIXNET_PORT),
bind_address: SocketAddr::new(in6addr_any_init(), DEFAULT_MIXNET_PORT),
announce_port: None,
nym_api_urls,
nyxd_urls,
@@ -597,7 +607,7 @@ impl Default for Mixnet {
#[serde(deny_unknown_fields)]
pub struct Verloc {
/// Socket address this node will use for binding its verloc API.
/// default: `0.0.0.0:1790`
/// default: `[::]:1790`
pub bind_address: SocketAddr,
/// If applicable, custom port announced in the self-described API that other clients and nodes
@@ -618,7 +628,7 @@ impl Verloc {
impl Default for Verloc {
fn default() -> Self {
Verloc {
bind_address: SocketAddr::new(inaddr_any(), Self::DEFAULT_VERLOC_PORT),
bind_address: SocketAddr::new(in6addr_any_init(), Self::DEFAULT_VERLOC_PORT),
announce_port: None,
debug: Default::default(),
}
@@ -687,7 +697,7 @@ pub struct Wireguard {
pub enabled: bool,
/// Socket address this node will use for binding its wireguard interface.
/// default: `0.0.0.0:51822`
/// default: `[::]:51822`
pub bind_address: SocketAddr,
/// Private IPv4 address of the wireguard gateway.
+2
View File
@@ -7,6 +7,7 @@ mod old_config_v3;
mod old_config_v4;
mod old_config_v5;
mod old_config_v6;
mod old_config_v7;
pub use old_config_v1::try_upgrade_config_v1;
pub use old_config_v2::try_upgrade_config_v2;
@@ -14,3 +15,4 @@ pub use old_config_v3::try_upgrade_config_v3;
pub use old_config_v4::try_upgrade_config_v4;
pub use old_config_v5::try_upgrade_config_v5;
pub use old_config_v6::try_upgrade_config_v6;
pub use old_config_v7::try_upgrade_config_v7;
@@ -3,11 +3,6 @@
#![allow(dead_code)]
use crate::config::authenticator::{Authenticator, AuthenticatorDebug};
use crate::config::gateway_tasks::ZkNymTicketHandlerDebug;
use crate::config::service_providers::{
IpPacketRouter, IpPacketRouterDebug, NetworkRequester, NetworkRequesterDebug,
};
use crate::config::*;
use crate::error::NymNodeError;
use celes::Country;
@@ -23,6 +18,7 @@ use nym_config::{
serde_helpers::{de_maybe_port, de_maybe_stringified},
};
use nym_config::{parse_urls, read_config_from_toml_file};
use old_configs::old_config_v7::*;
use persistence::*;
use serde::{Deserialize, Serialize};
use std::env;
@@ -85,13 +81,13 @@ pub enum NodeModeV6 {
ExitGateway,
}
impl From<NodeModeV6> for NodeModes {
impl From<NodeModeV6> for NodeModesV7 {
fn from(config: NodeModeV6) -> Self {
match config {
NodeModeV6::Mixnode => *NodeModes::default().with_mixnode(),
NodeModeV6::EntryGateway => *NodeModes::default().with_entry(),
NodeModeV6::Mixnode => *NodeModesV7::default().with_mixnode(),
NodeModeV6::EntryGateway => *NodeModesV7::default().with_entry(),
// in old version exit implied entry
NodeModeV6::ExitGateway => *NodeModes::default().with_entry().with_exit(),
NodeModeV6::ExitGateway => *NodeModesV7::default().with_entry().with_exit(),
}
}
}
@@ -953,7 +949,7 @@ impl ConfigV6 {
pub async fn try_upgrade_config_v6<P: AsRef<Path>>(
path: P,
prev_config: Option<ConfigV6>,
) -> Result<Config, NymNodeError> {
) -> Result<ConfigV7, NymNodeError> {
debug!("attempting to load v6 config...");
let old_cfg = if let Some(prev_config) = prev_config {
@@ -962,22 +958,22 @@ pub async fn try_upgrade_config_v6<P: AsRef<Path>>(
ConfigV6::read_from_path(&path)?
};
let cfg = Config {
let cfg = ConfigV7 {
save_path: old_cfg.save_path,
id: old_cfg.id,
modes: old_cfg.mode.into(),
host: Host {
host: HostV7 {
public_ips: old_cfg.host.public_ips,
hostname: old_cfg.host.hostname,
location: old_cfg.host.location,
},
mixnet: Mixnet {
mixnet: MixnetV7 {
bind_address: old_cfg.mixnet.bind_address,
announce_port: old_cfg.mixnet.announce_port,
nym_api_urls: old_cfg.mixnet.nym_api_urls,
nyxd_urls: old_cfg.mixnet.nyxd_urls,
debug: MixnetDebug {
maximum_forward_packet_delay: MixnetDebug::DEFAULT_MAXIMUM_FORWARD_PACKET_DELAY,
debug: MixnetDebugV7 {
maximum_forward_packet_delay: MixnetDebugV7::DEFAULT_MAXIMUM_FORWARD_PACKET_DELAY,
packet_forwarding_initial_backoff: old_cfg
.mixnet
.debug
@@ -991,8 +987,8 @@ pub async fn try_upgrade_config_v6<P: AsRef<Path>>(
unsafe_disable_noise: old_cfg.mixnet.debug.unsafe_disable_noise,
},
},
storage_paths: NymNodePaths {
keys: KeysPaths {
storage_paths: NymNodePathsV7 {
keys: KeysPathsV7 {
private_ed25519_identity_key_file: old_cfg
.storage_paths
.keys
@@ -1020,7 +1016,7 @@ pub async fn try_upgrade_config_v6<P: AsRef<Path>>(
},
description: old_cfg.storage_paths.description,
},
http: Http {
http: HttpV7 {
bind_address: old_cfg.http.bind_address,
landing_page_assets_path: old_cfg.http.landing_page_assets_path,
access_token: old_cfg.http.access_token,
@@ -1028,10 +1024,10 @@ pub async fn try_upgrade_config_v6<P: AsRef<Path>>(
expose_system_hardware: old_cfg.http.expose_system_hardware,
expose_crypto_hardware: old_cfg.http.expose_crypto_hardware,
},
verloc: Verloc {
verloc: VerlocV7 {
bind_address: old_cfg.mixnode.verloc.bind_address,
announce_port: old_cfg.mixnode.verloc.announce_port,
debug: VerlocDebug {
debug: VerlocDebugV7 {
packets_per_node: old_cfg.mixnode.verloc.debug.packets_per_node,
connection_timeout: old_cfg.mixnode.verloc.debug.connection_timeout,
packet_timeout: old_cfg.mixnode.verloc.debug.packet_timeout,
@@ -1041,7 +1037,7 @@ pub async fn try_upgrade_config_v6<P: AsRef<Path>>(
retry_timeout: old_cfg.mixnode.verloc.debug.retry_timeout,
},
},
wireguard: Wireguard {
wireguard: WireguardV7 {
enabled: old_cfg.wireguard.enabled,
bind_address: old_cfg.wireguard.bind_address,
private_ipv4: old_cfg.wireguard.private_ipv4,
@@ -1049,7 +1045,7 @@ pub async fn try_upgrade_config_v6<P: AsRef<Path>>(
announced_port: old_cfg.wireguard.announced_port,
private_network_prefix_v4: old_cfg.wireguard.private_network_prefix_v4,
private_network_prefix_v6: old_cfg.wireguard.private_network_prefix_v6,
storage_paths: WireguardPaths {
storage_paths: WireguardPathsV7 {
private_diffie_hellman_key_file: old_cfg
.wireguard
.storage_paths
@@ -1060,8 +1056,8 @@ pub async fn try_upgrade_config_v6<P: AsRef<Path>>(
.public_diffie_hellman_key_file,
},
},
gateway_tasks: GatewayTasksConfig {
storage_paths: GatewayTasksPaths {
gateway_tasks: GatewayTasksConfigV7 {
storage_paths: GatewayTasksPathsV7 {
clients_storage: old_cfg.entry_gateway.storage_paths.clients_storage,
stats_storage: old_cfg.entry_gateway.storage_paths.stats_storage,
cosmos_mnemonic: old_cfg.entry_gateway.storage_paths.cosmos_mnemonic,
@@ -1070,9 +1066,9 @@ pub async fn try_upgrade_config_v6<P: AsRef<Path>>(
bind_address: old_cfg.entry_gateway.bind_address,
announce_ws_port: old_cfg.entry_gateway.announce_ws_port,
announce_wss_port: old_cfg.entry_gateway.announce_wss_port,
debug: gateway_tasks::Debug {
debug: GatewayTasksConfigDebugV7 {
message_retrieval_limit: old_cfg.entry_gateway.debug.message_retrieval_limit,
zk_nym_tickets: ZkNymTicketHandlerDebug {
zk_nym_tickets: ZkNymTicketHandlerDebugV7 {
revocation_bandwidth_penalty: old_cfg
.entry_gateway
.debug
@@ -1098,11 +1094,11 @@ pub async fn try_upgrade_config_v6<P: AsRef<Path>>(
..Default::default()
},
},
service_providers: ServiceProvidersConfig {
storage_paths: ServiceProvidersPaths {
service_providers: ServiceProvidersConfigV7 {
storage_paths: ServiceProvidersPathsV7 {
clients_storage: old_cfg.exit_gateway.storage_paths.clients_storage,
stats_storage: old_cfg.exit_gateway.storage_paths.stats_storage,
network_requester: NetworkRequesterPaths {
network_requester: NetworkRequesterPathsV7 {
private_ed25519_identity_key_file: old_cfg
.exit_gateway
.storage_paths
@@ -1139,7 +1135,7 @@ pub async fn try_upgrade_config_v6<P: AsRef<Path>>(
.network_requester
.gateway_registrations,
},
ip_packet_router: IpPacketRouterPaths {
ip_packet_router: IpPacketRouterPathsV7 {
private_ed25519_identity_key_file: old_cfg
.exit_gateway
.storage_paths
@@ -1176,7 +1172,7 @@ pub async fn try_upgrade_config_v6<P: AsRef<Path>>(
.ip_packet_router
.gateway_registrations,
},
authenticator: AuthenticatorPaths {
authenticator: AuthenticatorPathsV7 {
private_ed25519_identity_key_file: old_cfg
.exit_gateway
.storage_paths
@@ -1216,8 +1212,8 @@ pub async fn try_upgrade_config_v6<P: AsRef<Path>>(
},
open_proxy: old_cfg.exit_gateway.open_proxy,
upstream_exit_policy_url: old_cfg.exit_gateway.upstream_exit_policy_url,
network_requester: NetworkRequester {
debug: NetworkRequesterDebug {
network_requester: NetworkRequesterV7 {
debug: NetworkRequesterDebugV7 {
enabled: old_cfg.exit_gateway.network_requester.debug.enabled,
disable_poisson_rate: old_cfg
.exit_gateway
@@ -1227,8 +1223,8 @@ pub async fn try_upgrade_config_v6<P: AsRef<Path>>(
client_debug: old_cfg.exit_gateway.network_requester.debug.client_debug,
},
},
ip_packet_router: IpPacketRouter {
debug: IpPacketRouterDebug {
ip_packet_router: IpPacketRouterV7 {
debug: IpPacketRouterDebugV7 {
enabled: old_cfg.exit_gateway.ip_packet_router.debug.enabled,
disable_poisson_rate: old_cfg
.exit_gateway
@@ -1238,19 +1234,19 @@ pub async fn try_upgrade_config_v6<P: AsRef<Path>>(
client_debug: old_cfg.exit_gateway.ip_packet_router.debug.client_debug,
},
},
authenticator: Authenticator {
debug: AuthenticatorDebug {
authenticator: AuthenticatorV7 {
debug: AuthenticatorDebugV7 {
enabled: old_cfg.authenticator.debug.enabled,
disable_poisson_rate: old_cfg.authenticator.debug.disable_poisson_rate,
client_debug: old_cfg.authenticator.debug.client_debug,
},
},
debug: service_providers::Debug {
debug: ServiceProvidersConfigDebugV7 {
message_retrieval_limit: old_cfg.exit_gateway.debug.message_retrieval_limit,
},
},
metrics: Default::default(),
logging: LoggingSettings {},
logging: LoggingSettingsV7 {},
debug: Default::default(),
};
Ok(cfg)
File diff suppressed because it is too large Load Diff
-1
View File
@@ -30,7 +30,6 @@ pub struct ServiceProvidersConfig {
#[serde(default)]
pub debug: Debug,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct Debug {
+6 -6
View File
@@ -46,7 +46,7 @@ location = '{{ host.location }}'
[mixnet]
# Address this node will bind to for listening for mixnet packets
# default: `0.0.0.0:1789`
# default: `[::]:1789`
bind_address = '{{ mixnet.bind_address }}'
# If applicable, custom port announced in the self-described API that other clients and nodes
@@ -95,7 +95,7 @@ public_x25519_noise_key_file = '{{ storage_paths.keys.public_x25519_noise_key_fi
[http]
# Socket address this node will use for binding its http API.
# default: `0.0.0.0:8080`
# default: `[::]:8080`
bind_address = '{{ http.bind_address }}'
# Path to assets directory of custom landing page of this node
@@ -126,7 +126,7 @@ expose_crypto_hardware = {{ http.expose_crypto_hardware }}
enabled = {{ wireguard.enabled }}
# Socket address this node will use for binding its wireguard interface.
# default: `0.0.0.0:51822`
# default: `[::]:51822`
bind_address = '{{ wireguard.bind_address }}'
# Private IP address of the wireguard gateway.
@@ -161,7 +161,7 @@ public_diffie_hellman_key_file = '{{ wireguard.storage_paths.public_diffie_hellm
[verloc]
# Socket address this node will use for binding its verloc API.
# default: `0.0.0.0:1790`
# default: `[::]:1790`
bind_address = '{{ verloc.bind_address }}'
# If applicable, custom port announced in the self-described API that other clients and nodes
@@ -179,8 +179,8 @@ announce_port ={{#if verloc.announce_port }} {{ verloc.announce_port }} {{else}}
enforce_zk_nyms = {{ gateway_tasks.enforce_zk_nyms }}
# Socket address this node will use for binding its client websocket API.
# default: `0.0.0.0:9000`
bind_address = '{{ gateway_tasks.bind_address }}'
# default: `[::]:9000`
ws_bind_address = '{{ gateway_tasks.ws_bind_address }}'
# Custom announced port for listening for websocket client traffic.
# If unspecified, the value from the `bind_address` will be used instead
+2 -1
View File
@@ -14,7 +14,8 @@ async fn try_upgrade_config(path: &Path) -> Result<(), NymNodeError> {
let cfg = try_upgrade_config_v3(path, cfg).await.ok();
let cfg = try_upgrade_config_v4(path, cfg).await.ok();
let cfg = try_upgrade_config_v5(path, cfg).await.ok();
match try_upgrade_config_v6(path, cfg).await {
let cfg = try_upgrade_config_v6(path, cfg).await.ok();
match try_upgrade_config_v7(path, cfg).await {
Ok(cfg) => cfg.save(),
Err(e) => {
tracing::error!("Failed to finish upgrade - {e}");
@@ -72,7 +72,7 @@ pub(crate) fn get_system_info(
system_name: System::name(),
kernel_version: System::kernel_version(),
os_version: System::os_version(),
cpu_arch: System::cpu_arch(),
cpu_arch: Some(System::cpu_arch()),
hardware,
}
}
@@ -14,8 +14,8 @@ use nym_node_requests::api::v1::health::models::NodeHealth;
tag = "Health",
responses(
(status = 200, content(
(Vec<NodeHealth> = "application/json"),
(Vec<NodeHealth> = "application/yaml")
(NodeHealth = "application/json"),
(NodeHealth = "application/yaml")
), description = "the api is available and healthy")
),
params(OutputParams)
@@ -0,0 +1,33 @@
// Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
use crate::node::http::state::AppState;
use axum::extract::{Query, State};
use nym_http_api_common::{FormattedResponse, OutputParams};
use nym_node_requests::api::v1::node_load::models::NodeLoad;
/// Returns current relative load this node.
#[utoipa::path(
get,
path = "/load",
context_path = "/api/v1",
tag = "Node",
responses(
(status = 200, content(
(NodeLoad = "application/json"),
(NodeLoad = "application/yaml")
), description = "current node load")
),
params(OutputParams)
)]
pub(crate) async fn root_load(
Query(output): Query<OutputParams>,
State(state): State<AppState>,
) -> NodeLoadResponse {
let output = output.output.unwrap_or_default();
let load = state.cached_load.current_load();
output.to_response(load)
}
pub type NodeLoadResponse = FormattedResponse<NodeLoad>;
@@ -10,6 +10,7 @@ pub mod authenticator;
pub mod gateway;
pub mod health;
pub mod ip_packet_router;
pub mod load;
pub mod metrics;
pub mod mixnode;
pub mod network_requester;
@@ -30,6 +31,7 @@ pub struct Config {
pub(super) fn routes(config: Config) -> Router<AppState> {
Router::new()
.route(v1::HEALTH, get(health::root_health))
.route(v1::LOAD, get(load::root_load))
.nest(v1::METRICS, metrics::routes(config.metrics))
.nest(v1::GATEWAY, gateway::routes(config.gateway))
.nest(v1::MIXNODE, mixnode::routes(config.mixnode))
@@ -24,6 +24,7 @@ use utoipa_swagger_ui::SwaggerUi;
api::v1::metrics::verloc::verloc_stats,
api::v1::metrics::prometheus::prometheus_metrics,
api::v1::health::root_health,
api::v1::load::root_load,
api::v1::gateway::root::root_gateway,
api::v1::gateway::client_interfaces::client_interfaces,
api::v1::gateway::client_interfaces::mixnet_websockets,
@@ -38,6 +39,8 @@ use utoipa_swagger_ui::SwaggerUi;
nym_http_api_common::OutputParams,
api_requests::v1::health::models::NodeHealth,
api_requests::v1::health::models::NodeStatus,
api_requests::v1::node_load::models::NodeLoad,
api_requests::v1::node_load::models::Load,
api_requests::v1::node::models::BinaryBuildInformationOwned,
api_requests::v1::node::models::HostInformation,
api_requests::v1::node::models::HostKeys,
+209
View File
@@ -0,0 +1,209 @@
// Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
use arc_swap::ArcSwap;
use nym_node_requests::api::v1::node_load::models::{Load, NodeLoad};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use std::time::Duration;
use sysinfo::{CpuRefreshKind, MemoryRefreshKind, Networks, System};
use time::OffsetDateTime;
use tracing::debug;
#[derive(Clone)]
pub struct CachedNodeLoad {
ttl: Duration,
being_updated: Arc<AtomicBool>,
inner: Arc<ArcSwap<CachedNodeLoadInner>>,
}
impl CachedNodeLoad {
pub(crate) fn new(ttl: Duration) -> Self {
CachedNodeLoad {
ttl,
being_updated: Arc::new(Default::default()),
inner: Arc::new(ArcSwap::new(Arc::new(CachedNodeLoadInner::initial()))),
}
}
pub(crate) fn current_load(&self) -> NodeLoad {
let now = OffsetDateTime::now_utc();
let inner = self.inner.load();
if inner.timestamp + self.ttl < now {
// new
let already_being_updated = self.being_updated.swap(true, Ordering::SeqCst);
if already_being_updated {
// use the 'stale' entry because it is already being updated by another thread
inner.load
} else {
self.update_cache()
}
} else {
inner.load
}
}
fn update_cache(&self) -> NodeLoad {
let old = self.inner.load();
let current_load = CachedNodeLoadInner::update(&old);
let load = current_load.load;
self.inner.store(Arc::new(current_load));
self.being_updated.store(false, Ordering::SeqCst);
load
}
}
pub struct CachedNodeLoadInner {
timestamp: OffsetDateTime,
last_transmitted: u64,
last_received: u64,
load: NodeLoad,
}
struct RawUsage {
load_per_cpu: f64,
memory_usage: f64,
swap_usage: f64,
eth_transmitted: u64,
eth_received: u64,
total_swap: u64,
}
impl RawUsage {
fn current() -> RawUsage {
let mut system = sysinfo::System::new();
let networks = Networks::new_with_refreshed_list();
system.refresh_memory_specifics(MemoryRefreshKind::everything());
system.refresh_cpu_specifics(CpuRefreshKind::nothing());
let average_load = System::load_average();
let cpu_count = system.cpus().len();
let load_per_cpu = average_load.five / cpu_count as f64;
let total_memory = system.total_memory();
let used_memory = system.used_memory();
let memory_usage = used_memory as f64 / total_memory as f64;
let total_swap = system.total_swap();
let used_swap = system.free_swap();
let swap_usage = used_swap as f64 / total_swap as f64;
let mut eth_transmitted = 0;
let mut eth_received = 0;
// we're only interested in interfaces with 'eth' or 'en' prefix
// (that's a very weak assumption, but that's just first iteration of this endpoint)
for (interface, data) in networks.list() {
if interface.starts_with("eth") || interface.starts_with("en") {
eth_transmitted += data.total_transmitted();
eth_received += data.total_received();
}
}
debug!(average_load = ?average_load, memory_usage=memory_usage, swap_usage = swap_usage, "current load");
RawUsage {
load_per_cpu,
memory_usage,
swap_usage,
eth_transmitted,
eth_received,
total_swap,
}
}
}
impl CachedNodeLoadInner {
pub fn initial() -> CachedNodeLoadInner {
let timestamp = OffsetDateTime::now_utc();
let raw_usage = RawUsage::current();
let mut base_load = Load::from(raw_usage.load_per_cpu);
let memory_load = Load::from(raw_usage.memory_usage);
// if memory load is of higher tier, increment the base load by one level
// (i.e. for example from 'Low' to 'Medium')
if memory_load > base_load {
base_load = base_load.increment();
}
if raw_usage.total_swap > 1024 * 1024 * 1024 {
// same with swap
let swap_load = Load::from(raw_usage.swap_usage);
if swap_load > base_load {
base_load = base_load.increment();
}
}
CachedNodeLoadInner {
timestamp,
last_transmitted: raw_usage.eth_transmitted,
last_received: raw_usage.eth_received,
load: NodeLoad {
total: base_load,
machine: base_load,
network: Load::Unknown,
},
}
}
pub fn update(previous: &Self) -> CachedNodeLoadInner {
let timestamp = OffsetDateTime::now_utc();
let raw_usage = RawUsage::current();
let time_delta = (timestamp - previous.timestamp).as_seconds_f64();
let tx_delta = raw_usage.eth_transmitted - previous.last_transmitted;
let rx_delta = raw_usage.eth_received - previous.last_received;
let tx_bs = tx_delta as f64 / time_delta;
let rx_bs = rx_delta as f64 / time_delta;
// currently we consider value of 1Gbps to be maximum load
// in the future we should allow specifying custom sizes of network cards
// (Gbps = Bytes/s * 0.000000008)
let tx_gbps = tx_bs * 0.000000008;
let rx_gbps = rx_bs * 0.000000008;
let network_load = Load::from(tx_gbps.max(rx_gbps));
debug!(tx_gbps = tx_gbps, rx_gbps = rx_gbps, "network load");
let mut base_load = Load::from(raw_usage.load_per_cpu);
let memory_load = Load::from(raw_usage.memory_usage);
// if memory load is of higher tier, increment the base load by one level
// (i.e. for example from 'Low' to 'Medium')
if memory_load > base_load {
base_load = base_load.increment();
}
if raw_usage.total_swap > 1024 * 1024 * 1024 {
// same with swap
let swap_load = Load::from(raw_usage.swap_usage);
if swap_load > base_load {
base_load = base_load.increment();
}
}
let total_load = if base_load > network_load {
base_load
} else {
base_load.increment()
};
CachedNodeLoadInner {
timestamp,
last_transmitted: raw_usage.eth_transmitted,
last_received: raw_usage.eth_received,
load: NodeLoad {
total: total_load,
machine: base_load,
network: network_load,
},
}
}
}
+11 -1
View File
@@ -1,29 +1,39 @@
// Copyright 2023-2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
use crate::node::http::state::load::CachedNodeLoad;
use crate::node::http::state::metrics::MetricsAppState;
use nym_node_metrics::NymNodeMetrics;
use nym_verloc::measurements::SharedVerlocStats;
use std::time::Duration;
use tokio::time::Instant;
pub mod load;
pub mod metrics;
#[derive(Clone)]
pub struct AppState {
pub(crate) startup_time: Instant,
pub(crate) cached_load: CachedNodeLoad,
pub(crate) metrics: MetricsAppState,
}
impl AppState {
#[allow(clippy::new_without_default)]
pub fn new(metrics: NymNodeMetrics, verloc: SharedVerlocStats) -> Self {
pub fn new(
metrics: NymNodeMetrics,
verloc: SharedVerlocStats,
load_cache_ttl: Duration,
) -> Self {
AppState {
// is it 100% accurate?
// no.
// does it have to be?
// also no.
startup_time: Instant::now(),
cached_load: CachedNodeLoad::new(load_cache_ttl),
metrics: MetricsAppState { metrics, verloc },
}
}
+3 -1
View File
@@ -5,7 +5,7 @@ use crate::node::mixnet::SharedData;
use nym_task::ShutdownToken;
use std::net::SocketAddr;
use tokio::task::JoinHandle;
use tracing::{error, info, trace};
use tracing::{debug, error, info, trace};
pub(crate) struct Listener {
bind_address: SocketAddr,
@@ -39,12 +39,14 @@ impl Listener {
biased;
_ = self.shutdown.cancelled() => {
trace!("mixnet listener: received shutdown");
break
}
connection = tcp_listener.accept() => {
self.shared_data.try_handle_connection(connection);
}
}
}
debug!("mixnet socket listener: Exiting");
}
pub(crate) fn start(mut self) -> JoinHandle<()> {
+8 -4
View File
@@ -560,7 +560,7 @@ impl NymNode {
.config
.gateway_tasks
.announce_ws_port
.unwrap_or(self.config.gateway_tasks.bind_address.port());
.unwrap_or(self.config.gateway_tasks.ws_bind_address.port());
Ok(nym_topology::RoutingNode {
node_id: u32::MAX,
@@ -606,7 +606,7 @@ impl NymNode {
if self.modes().entry {
info!(
"starting the clients websocket... on {}",
self.config.gateway_tasks.bind_address
self.config.gateway_tasks.ws_bind_address
);
let websocket = gateway_tasks_builder
.build_websocket_listener(active_clients_store.clone())
@@ -711,7 +711,7 @@ impl NymNode {
.config
.gateway_tasks
.announce_ws_port
.unwrap_or(self.config.gateway_tasks.bind_address.port()),
.unwrap_or(self.config.gateway_tasks.ws_bind_address.port()),
wss_port: self.config.gateway_tasks.announce_wss_port,
});
let gateway_details = api_requests::v1::gateway::models::Gateway {
@@ -785,7 +785,11 @@ impl NymNode {
config.api.v1_config.node.roles.ip_packet_router_enabled = true;
}
let app_state = AppState::new(self.metrics.clone(), self.verloc_stats.clone());
let app_state = AppState::new(
self.metrics.clone(),
self.verloc_stats.clone(),
self.config.http.node_load_cache_ttl,
);
Ok(NymNodeRouter::new(config, app_state)
.build_server(&self.config.http.bind_address)
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "nym-validator-rewarder"
version = "0.2.0"
version = "0.2.1"
authors.workspace = true
repository.workspace = true
homepage.workspace = true
+59 -37
View File
@@ -806,19 +806,19 @@ version = "0.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32560304ab4c365791fd307282f76637213d8083c1a98490c35159cd67852237"
dependencies = [
"prost",
"prost 0.12.3",
"prost-types",
"tendermint-proto 0.34.0",
]
[[package]]
name = "cosmos-sdk-proto"
version = "0.22.0-pre"
source = "git+https://github.com/cosmos/cosmos-rust?rev=4b1332e6d8258ac845cef71589c8d362a669675a#4b1332e6d8258ac845cef71589c8d362a669675a"
version = "0.26.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "462e1f6a8e005acc8835d32d60cbd7973ed65ea2a8d8473830e675f050956427"
dependencies = [
"prost",
"prost-types",
"tendermint-proto 0.37.0",
"prost 0.13.4",
"tendermint-proto 0.40.1",
]
[[package]]
@@ -843,11 +843,12 @@ dependencies = [
[[package]]
name = "cosmrs"
version = "0.17.0-pre"
source = "git+https://github.com/cosmos/cosmos-rust?rev=4b1332e6d8258ac845cef71589c8d362a669675a#4b1332e6d8258ac845cef71589c8d362a669675a"
version = "0.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "210fbe6f98594963b46cc980f126a9ede5db9a3848ca65b71303bebdb01afcd9"
dependencies = [
"bip32",
"cosmos-sdk-proto 0.22.0-pre",
"cosmos-sdk-proto 0.26.1",
"ecdsa",
"eyre",
"k256",
@@ -856,7 +857,7 @@ dependencies = [
"serde_json",
"signature",
"subtle-encoding",
"tendermint 0.37.0",
"tendermint 0.40.1",
"tendermint-rpc",
"thiserror 1.0.64",
]
@@ -3072,7 +3073,7 @@ name = "nym-api-requests"
version = "0.1.0"
dependencies = [
"bs58",
"cosmrs 0.17.0-pre",
"cosmrs 0.21.0",
"cosmwasm-std",
"ecdsa",
"getset",
@@ -3090,7 +3091,7 @@ dependencies = [
"serde",
"serde_json",
"sha2 0.10.8",
"tendermint 0.37.0",
"tendermint 0.40.1",
"thiserror 1.0.64",
"time",
"utoipa",
@@ -3328,7 +3329,6 @@ name = "nym-node-requests"
version = "0.1.0"
dependencies = [
"async-trait",
"base64 0.22.1",
"celes",
"humantime 2.1.0",
"humantime-serde",
@@ -3340,6 +3340,7 @@ dependencies = [
"schemars",
"serde",
"serde_json",
"strum 0.26.3",
"thiserror 1.0.64",
"time",
"utoipa",
@@ -3405,7 +3406,7 @@ name = "nym-types"
version = "1.0.0"
dependencies = [
"base64 0.22.1",
"cosmrs 0.17.0-pre",
"cosmrs 0.21.0",
"cosmwasm-std",
"eyre",
"hmac",
@@ -3438,7 +3439,7 @@ dependencies = [
"bip32",
"bip39",
"colored 2.0.4",
"cosmrs 0.17.0-pre",
"cosmrs 0.21.0",
"cosmwasm-std",
"cw-controllers",
"cw-utils",
@@ -3463,7 +3464,7 @@ dependencies = [
"nym-network-defaults",
"nym-serde-helpers",
"nym-vesting-contract-common",
"prost",
"prost 0.13.4",
"reqwest 0.12.4",
"serde",
"serde_json",
@@ -3546,7 +3547,7 @@ dependencies = [
"bip39",
"cfg-if",
"colored 2.0.4",
"cosmrs 0.17.0-pre",
"cosmrs 0.21.0",
"cosmwasm-std",
"dirs 4.0.0",
"dotenvy",
@@ -4186,7 +4187,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "146c289cda302b98a28d40c8b3b90498d6e526dd24ac2ecea73e4e491685b94a"
dependencies = [
"bytes",
"prost-derive",
"prost-derive 0.12.3",
]
[[package]]
name = "prost"
version = "0.13.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c0fef6c4230e4ccf618a35c59d7ede15dea37de8427500f50aff708806e42ec"
dependencies = [
"bytes",
"prost-derive 0.13.4",
]
[[package]]
@@ -4202,13 +4213,26 @@ dependencies = [
"syn 2.0.96",
]
[[package]]
name = "prost-derive"
version = "0.13.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "157c5a9d7ea5c2ed2d9fb8f495b64759f7816c7eaea54ba3978f0d63000162e3"
dependencies = [
"anyhow",
"itertools 0.13.0",
"proc-macro2",
"quote",
"syn 2.0.96",
]
[[package]]
name = "prost-types"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "193898f59edcf43c26227dcd4c8427f00d99d61e95dcde58dabd49fa291d470e"
dependencies = [
"prost",
"prost 0.12.3",
]
[[package]]
@@ -5628,7 +5652,7 @@ dependencies = [
"k256",
"num-traits",
"once_cell",
"prost",
"prost 0.12.3",
"prost-types",
"ripemd",
"serde",
@@ -5646,9 +5670,9 @@ dependencies = [
[[package]]
name = "tendermint"
version = "0.37.0"
version = "0.40.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "954496fbc9716eb4446cdd6d00c071a3e2f22578d62aa03b40c7e5b4fda3ed42"
checksum = "d9703e34d940c2a293804752555107f8dbe2b84ec4c6dd5203831235868105d2"
dependencies = [
"bytes",
"digest 0.10.7",
@@ -5659,8 +5683,7 @@ dependencies = [
"k256",
"num-traits",
"once_cell",
"prost",
"prost-types",
"prost 0.13.4",
"ripemd",
"serde",
"serde_bytes",
@@ -5670,21 +5693,21 @@ dependencies = [
"signature",
"subtle 2.5.0",
"subtle-encoding",
"tendermint-proto 0.37.0",
"tendermint-proto 0.40.1",
"time",
"zeroize",
]
[[package]]
name = "tendermint-config"
version = "0.37.0"
version = "0.40.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f84b11b57d20ee4492a1452faff85f5c520adc36ca9fe5e701066935255bb89f"
checksum = "89cc3ea9a39b7ee34eefcff771cc067ecaa0c988c1c5ac08defd878471a06f76"
dependencies = [
"flex-error",
"serde",
"serde_json",
"tendermint 0.37.0",
"tendermint 0.40.1",
"toml 0.8.19",
"url",
]
@@ -5699,7 +5722,7 @@ dependencies = [
"flex-error",
"num-derive",
"num-traits",
"prost",
"prost 0.12.3",
"prost-types",
"serde",
"serde_bytes",
@@ -5709,14 +5732,13 @@ dependencies = [
[[package]]
name = "tendermint-proto"
version = "0.37.0"
version = "0.40.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc87024548c7f3da479885201e3da20ef29e85a3b13d04606b380ac4c7120d87"
checksum = "9ae9e1705aa0fa5ecb2c6aa7fb78c2313c4a31158ea5f02048bf318f849352eb"
dependencies = [
"bytes",
"flex-error",
"prost",
"prost-types",
"prost 0.13.4",
"serde",
"serde_bytes",
"subtle-encoding",
@@ -5725,9 +5747,9 @@ dependencies = [
[[package]]
name = "tendermint-rpc"
version = "0.37.0"
version = "0.40.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dfdc2281e271277fda184d96d874a6fe59f569b130b634289257baacfc95aa85"
checksum = "835a52aa504c63ec05519e31348d3f4ba2fe79493c588e2cad5323d5e81b161a"
dependencies = [
"async-trait",
"bytes",
@@ -5744,9 +5766,9 @@ dependencies = [
"serde_json",
"subtle 2.5.0",
"subtle-encoding",
"tendermint 0.37.0",
"tendermint 0.40.1",
"tendermint-config",
"tendermint-proto 0.37.0",
"tendermint-proto 0.40.1",
"thiserror 1.0.64",
"time",
"tokio",
+1 -1
View File
@@ -50,7 +50,7 @@ base64 = "0.13"
zeroize = { version = "1.5", features = ["zeroize_derive", "serde"] }
cosmwasm-std = "1.3.0"
cosmrs = { git = "https://github.com/cosmos/cosmos-rust", rev = "4b1332e6d8258ac845cef71589c8d362a669675a" }
cosmrs = { version = "0.21.0" }
nym-node-requests = { path = "../../nym-node/nym-node-requests" }
nym-validator-client = { path = "../../common/client-libs/validator-client" }
+4 -4
View File
@@ -3,7 +3,7 @@
[package]
name = "nyx-chain-watcher"
version = "0.1.8"
version = "0.1.9"
authors.workspace = true
repository.workspace = true
homepage.workspace = true
@@ -27,15 +27,15 @@ nym-node-requests = { path = "../nym-node/nym-node-requests", features = [
"openapi",
] }
nym-validator-client = { path = "../common/client-libs/validator-client" }
nyxd-scraper = {path = "../common/nyxd-scraper"}
reqwest = {workspace= true, features = ["rustls-tls"]}
nyxd-scraper = { path = "../common/nyxd-scraper" }
reqwest = { workspace = true, features = ["rustls-tls"] }
rocket = { workspace = true }
schemars = { workspace = true }
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 = { version = "0.3.37" }
tokio = { workspace = true, features = ["process", "rt-multi-thread"] }
tokio-util = { workspace = true }
tracing = { workspace = true }
+6 -7
View File
@@ -25,7 +25,7 @@ use nym_client_core::client::{
};
use nym_client_core::config::{DebugConfig, StatsReporting};
use nym_client_core::error::ClientCoreError;
use nym_client_core::init::helpers::current_gateways;
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_client_core::ForgetMe;
@@ -489,7 +489,7 @@ where
user_chosen_gateway: &str,
) -> Result<bool> {
let storage = self.storage.gateway_details_store();
// Stricly speaking, `set_active_gateway` does this check internally as well, but since the
// Strictly speaking, `set_active_gateway` does this check internally as well, but since the
// error is boxed away and we're using a generic storage, it's not so easy to match on it.
// This function is at least less likely to fail on something unrelated to the existence of
// the gateway in the set of registered gateways
@@ -512,15 +512,14 @@ where
let user_agent = self.user_agent.clone();
let topology_cfg = &self.config.debug_config.topology;
let mut rng = OsRng;
let available_gateways = current_gateways(
let available_gateways = gateways_for_init(
&mut rng,
&nym_api_endpoints,
user_agent,
self.config
.debug_config
.topology
.minimum_gateway_performance,
topology_cfg.minimum_gateway_performance,
topology_cfg.ignore_ingress_epoch_role,
)
.await?;
@@ -632,7 +632,7 @@ impl MixnetListener {
}
} else {
// If the client is not connected, just drop the packet silently
log::info!("dropping packet from mixnet: no registered client for packet with source: {src_addr}");
log::debug!("dropping packet from mixnet: no registered client for packet with source: {src_addr}");
Ok(None)
}
}
@@ -4,7 +4,7 @@
[package]
name = "nym-network-requester"
license = "GPL-3.0"
version = "1.1.47"
version = "1.1.48"
authors.workspace = true
edition.workspace = true
rust-version = "1.70"
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "nym-cli"
version = "1.1.46"
version = "1.1.47"
authors.workspace = true
edition = "2021"
license.workspace = true
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "nymvisor"
version = "0.1.11"
version = "0.1.12"
authors.workspace = true
repository.workspace = true
homepage.workspace = true
+1
View File
@@ -217,6 +217,7 @@ impl NymClientBuilder {
&self.config.base.client.nym_api_urls,
bin_info!().into(),
self.config.base.debug.topology.minimum_gateway_performance,
self.config.base.debug.topology.ignore_ingress_epoch_role,
&client_store,
)
.await?;
+1
View File
@@ -156,6 +156,7 @@ impl MixFetchClientBuilder {
&self.config.base.client.nym_api_urls,
bin_info!().into(),
self.config.base.debug.topology.minimum_gateway_performance,
self.config.base.debug.topology.ignore_ingress_epoch_role,
&client_store,
)
.await?;