Compare commits

...

62 Commits

Author SHA1 Message Date
mfahampshire 25b45a911c push to remote for cleanbuild 2025-01-24 11:37:55 +01:00
mfahampshire ffc72feb12 add temp warning 2025-01-17 15:24:25 +01:00
mfahampshire 0793133c95 Merge branch 'develop' of github.com:nymtech/nym into develop 2025-01-16 14:13:32 +01:00
benedetta davico 5c89d36140 Merge pull request #5359 from nymtech/release/2025.1-reeses
merge reeses patch to develop
2025-01-16 13:34:36 +01:00
benedetta davico 5ab164d229 Update Cargo.toml 2025-01-16 12:51:53 +01:00
Jędrzej Stuczyński 26538c5884 bugfix: only consider pre-existing peers for wg bytes metric (#5357) 2025-01-16 11:50:26 +00:00
Jędrzej Stuczyński adb248dbcc chore: refresh wasm sdk (#5353)
* make packet statistics wasm-compatible

* fixed possible overflow issue in delay controller

* updated wasm-client to be compatible with the current network

* applied same logic to mixfetch client

* removed dead imports

* updated versions
2025-01-15 17:11:17 +00:00
mfahampshire b1d10b41a4 Merge branch 'develop' of github.com:nymtech/nym into develop 2025-01-15 13:12:31 +01:00
Sachin Kamath fffec65cab NS API: add mixnet scraper (#5200)
* ns-api: add mixnode scraper

* clippy

* rebase
2025-01-15 13:12:11 +01:00
benedetta davico bb24004d46 Merge pull request #5352 from nymtech/merge/release/2025.1-reeses 2025-01-15 11:34:39 +01:00
Jędrzej Stuczyński c487eff7ca Merge branch 'release/2025.1-reeses' into develop 2025-01-15 10:18:45 +00:00
Jędrzej Stuczyński 5fa21c9aae chore: remove performed mixnet contract migration (#5350) 2025-01-15 10:06:04 +00:00
dependabot[bot] fd18aae0d6 build(deps): bump log in the patch-updates group across 1 directory (#5348)
Bumps the patch-updates group with 1 update in the / directory: [log](https://github.com/rust-lang/log).


Updates `log` from 0.4.22 to 0.4.25
- [Release notes](https://github.com/rust-lang/log/releases)
- [Changelog](https://github.com/rust-lang/log/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/log/compare/0.4.22...0.4.25)

---
updated-dependencies:
- dependency-name: log
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: patch-updates
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-15 10:01:25 +00:00
benedettadavico c202e2d598 adding changelog for reeses 2025-01-15 10:27:39 +01:00
mfahampshire b33708bbe6 Merge branch 'develop' of github.com:nymtech/nym into develop 2025-01-14 23:52:00 +01:00
mfahampshire 62d23cff9f removed old todos (#5349) 2025-01-14 16:37:30 +00:00
mfahampshire e454d71b78 Max/client pool (#5188)
* tcp conn tracker

* make default decay const

* first pass connpool

* err handling conpool start

* added notes for next features

* first version working

* first pass spin out client_pool

* cancel token

* logging change

* bump default decay time

* bugfix: make sure to apply gateway score filtering when choosing initial node

* add duplicate packets received to troubleshooting

* client_pool.rs mod

* client pool example

* clippy

* client pool example done

* added disconnect to client pool

* update mod file

* add cancel token disconnect fn

* comments

* comments

* add clone

* added disconnect thread

* update example files tcpproxy

* client pool docs

* remove comments for future ffi push + lower default pool size from 4 to 2

* comment on ffi

* update command help

* clone impl

* remove clone

* fix clippy

* fix clippy again

* fix test

* tweaked text grammar

* updated comment in example

* future is now

* cherry

* cherry

* fix borked rebase

* fix fmt

* wasm fix

---------

Co-authored-by: Jędrzej Stuczyński <jedrzej.stuczynski@gmail.com>
2025-01-14 16:11:47 +00:00
mfahampshire eea8ee589f removed old todos 2025-01-14 15:28:05 +01:00
huximaxi a7874add88 Merge pull request #5346 from nymtech/feture/legacy_alert
Feture/legacy alert
2025-01-14 15:00:49 +01:00
dependabot[bot] 0a47d5dcf8 build(deps): bump criterion from 0.4.0 to 0.5.1 (#4911)
Bumps [criterion](https://github.com/bheisler/criterion.rs) from 0.4.0 to 0.5.1.
- [Changelog](https://github.com/bheisler/criterion.rs/blob/master/CHANGELOG.md)
- [Commits](https://github.com/bheisler/criterion.rs/compare/0.4.0...0.5.1)

---
updated-dependencies:
- dependency-name: criterion
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-14 13:47:58 +00:00
RadekSabacky 3d84be22e2 + add releaseAlert component 2025-01-14 13:41:30 +01:00
dependabot[bot] 6ccbb30491 build(deps): bump http from 1.1.0 to 1.2.0 (#5228)
Bumps [http](https://github.com/hyperium/http) from 1.1.0 to 1.2.0.
- [Release notes](https://github.com/hyperium/http/releases)
- [Changelog](https://github.com/hyperium/http/blob/master/CHANGELOG.md)
- [Commits](https://github.com/hyperium/http/compare/v1.1.0...v1.2.0)

---
updated-dependencies:
- dependency-name: http
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-14 12:33:17 +00:00
dependabot[bot] 91c205f83a build(deps): bump the patch-updates group with 8 updates (#5336)
Bumps the patch-updates group with 8 updates:

| Package | From | To |
| --- | --- | --- |
| [async-trait](https://github.com/dtolnay/async-trait) | `0.1.84` | `0.1.85` |
| [clap](https://github.com/clap-rs/clap) | `4.5.23` | `4.5.26` |
| [clap_complete](https://github.com/clap-rs/clap) | `4.5.40` | `4.5.42` |
| [futures](https://github.com/rust-lang/futures-rs) | `0.3.30` | `0.3.31` |
| [pin-project](https://github.com/taiki-e/pin-project) | `1.1.7` | `1.1.8` |
| [pin-project-lite](https://github.com/taiki-e/pin-project-lite) | `0.2.15` | `0.2.16` |
| [serde_json](https://github.com/serde-rs/json) | `1.0.134` | `1.0.135` |
| [wasm-bindgen-test](https://github.com/rustwasm/wasm-bindgen) | `0.3.45` | `0.3.49` |


Updates `async-trait` from 0.1.84 to 0.1.85
- [Release notes](https://github.com/dtolnay/async-trait/releases)
- [Commits](https://github.com/dtolnay/async-trait/compare/0.1.84...0.1.85)

Updates `clap` from 4.5.23 to 4.5.26
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v4.5.23...clap_complete-v4.5.26)

Updates `clap_complete` from 4.5.40 to 4.5.42
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v4.5.40...clap_complete-v4.5.42)

Updates `futures` from 0.3.30 to 0.3.31
- [Release notes](https://github.com/rust-lang/futures-rs/releases)
- [Changelog](https://github.com/rust-lang/futures-rs/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/futures-rs/compare/0.3.30...0.3.31)

Updates `pin-project` from 1.1.7 to 1.1.8
- [Release notes](https://github.com/taiki-e/pin-project/releases)
- [Changelog](https://github.com/taiki-e/pin-project/blob/main/CHANGELOG.md)
- [Commits](https://github.com/taiki-e/pin-project/compare/v1.1.7...v1.1.8)

Updates `pin-project-lite` from 0.2.15 to 0.2.16
- [Release notes](https://github.com/taiki-e/pin-project-lite/releases)
- [Changelog](https://github.com/taiki-e/pin-project-lite/blob/main/CHANGELOG.md)
- [Commits](https://github.com/taiki-e/pin-project-lite/compare/v0.2.15...v0.2.16)

Updates `serde_json` from 1.0.134 to 1.0.135
- [Release notes](https://github.com/serde-rs/json/releases)
- [Commits](https://github.com/serde-rs/json/compare/v1.0.134...v1.0.135)

Updates `wasm-bindgen-test` from 0.3.45 to 0.3.49
- [Release notes](https://github.com/rustwasm/wasm-bindgen/releases)
- [Changelog](https://github.com/rustwasm/wasm-bindgen/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rustwasm/wasm-bindgen/commits)

---
updated-dependencies:
- dependency-name: async-trait
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: patch-updates
- dependency-name: clap
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: patch-updates
- dependency-name: clap_complete
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: patch-updates
- dependency-name: futures
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: patch-updates
- dependency-name: pin-project
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: patch-updates
- dependency-name: pin-project-lite
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: patch-updates
- dependency-name: serde_json
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: patch-updates
- dependency-name: wasm-bindgen-test
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: patch-updates
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-14 12:30:31 +00:00
dependabot[bot] 4a704e992a build(deps): bump tempfile from 3.14.0 to 3.15.0 (#5337)
Bumps [tempfile](https://github.com/Stebalien/tempfile) from 3.14.0 to 3.15.0.
- [Changelog](https://github.com/Stebalien/tempfile/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Stebalien/tempfile/compare/v3.14.0...v3.15.0)

---
updated-dependencies:
- dependency-name: tempfile
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-14 12:29:40 +00:00
dependabot[bot] 6c88c7df42 build(deps): bump ts-rs from 10.0.0 to 10.1.0 (#5338)
Bumps [ts-rs](https://github.com/Aleph-Alpha/ts-rs) from 10.0.0 to 10.1.0.
- [Release notes](https://github.com/Aleph-Alpha/ts-rs/releases)
- [Changelog](https://github.com/Aleph-Alpha/ts-rs/blob/main/CHANGELOG.md)
- [Commits](https://github.com/Aleph-Alpha/ts-rs/compare/v10.0.0...v10.1.0)

---
updated-dependencies:
- dependency-name: ts-rs
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-14 12:29:13 +00:00
dependabot[bot] 2a748fc968 build(deps): bump mikefarah/yq from 4.44.6 to 4.45.1 (#5342)
Bumps [mikefarah/yq](https://github.com/mikefarah/yq) from 4.44.6 to 4.45.1.
- [Release notes](https://github.com/mikefarah/yq/releases)
- [Changelog](https://github.com/mikefarah/yq/blob/master/release_notes.txt)
- [Commits](https://github.com/mikefarah/yq/compare/v4.44.6...v4.45.1)

---
updated-dependencies:
- dependency-name: mikefarah/yq
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-14 12:28:43 +00:00
RadekSabacky 25766dc0ec + add alert message into nav components 2025-01-14 13:22:31 +01:00
mfahampshire 07544d939e Max/docs gen update (#5333)
* update landing page icons

* new architecture diagram

* force dark theme

* new nyx consolidated page

* epoch page

* overhaul traffic flow + add diagram

* note on dvpn mode

* fix formatting of lists

* remove old todo
2025-01-14 11:25:06 +00:00
Jędrzej Stuczyński 102cd1033c feature: CancellationToken-based shutdowns (#5325)
* initial stub for ShutdownToken

* attempting to start using new ShutdownManager in NymNode

* migrated verloc tasks

* added custom shutdown signal registration

* integrated legacy task support

* migrated additional tasks inside nym-node

* removed import thats unused in wasm

* apply review comments

* windows fixes
2025-01-13 09:13:13 +00:00
Jędrzej Stuczyński 676e93a372 bugfix: make sure refresh data key matches bond info (#5329) 2025-01-10 14:52:52 +00:00
Jędrzej Stuczyński 5a6770e5e2 chore: readjusted --mode behaviour to fix the regression (#5331) 2025-01-10 13:17:03 +00:00
Jędrzej Stuczyński 529e8d49ee chore: apply 1.84 linter suggestions (#5330)
* chore: apply 1.84 linter suggestions

* updated wasm dependencies to fix the macro issue

* second batch of clippy fixes
2025-01-10 13:00:18 +00:00
mfahampshire 11d6ee2fdb update links readme (#5323) 2025-01-09 14:44:45 +00:00
mfahampshire d704c428fc update landing page colour highlight (#5322) 2025-01-09 14:44:21 +00:00
import this bca070c1bd [DOCs]: Readiness for nym-dot-com (#5319)
* url rewrites and redirects

* url rewrites and redirects
2025-01-09 14:44:12 +00:00
benedettadavico a94c035c0a correct the nym-node bumped version 2025-01-09 12:36:05 +01:00
Jędrzej Stuczyński 24480418f0 Bugfix/contract version assignment (#5318)
* fixed contract version being overwritten

* introduced migration to fix existing [mainnet] state

* updated contract schema

* updated testnet manager migrate msg code
2025-01-09 10:00:37 +00:00
Jędrzej Stuczyński 226c040a13 feature: periodically remove stale gateway messages (#5312)
* add timestamp to stored client messages

* removed dead code

* starting node task to remove old messages

* added log for number of removed messages

* debug log on task finishing
2025-01-09 09:03:19 +00:00
Jędrzej Stuczyński a46245ffe3 feat: warn users if node is run in exit mode only (#5320)
* added 'full-gateway' nymnode mode to enable both entry and exit at the same time

* warning for running node in exit mode only
2025-01-09 09:02:52 +00:00
Jędrzej Stuczyński 7c1c13e139 reduce log severity for number of packets being delayed (#5321) 2025-01-09 09:02:37 +00:00
Jędrzej Stuczyński 836a93cd96 fixed client session histogram buckets (#5316) 2025-01-08 10:26:40 +00:00
dependabot[bot] 3d2914b3e5 build(deps): bump the patch-updates group across 1 directory with 35 updates (#5310)
* build(deps): bump the patch-updates group across 1 directory with 35 updates

Bumps the patch-updates group with 33 updates in the / directory:

| Package | From | To |
| --- | --- | --- |
| [anyhow](https://github.com/dtolnay/anyhow) | `1.0.90` | `1.0.95` |
| [async-trait](https://github.com/dtolnay/async-trait) | `0.1.83` | `0.1.84` |
| [blake3](https://github.com/BLAKE3-team/BLAKE3) | `1.5.4` | `1.5.5` |
| [chrono](https://github.com/chronotope/chrono) | `0.4.38` | `0.4.39` |
| [clap](https://github.com/clap-rs/clap) | `4.5.20` | `4.5.23` |
| [clap_complete](https://github.com/clap-rs/clap) | `4.5.33` | `4.5.40` |
| [comfy-table](https://github.com/nukesor/comfy-table) | `7.1.1` | `7.1.3` |
| [console](https://github.com/console-rs/console) | `0.15.8` | `0.15.10` |
| [const_format](https://github.com/rodrimati1992/const_format_crates) | `0.2.33` | `0.2.34` |
| [csv](https://github.com/BurntSushi/rust-csv) | `1.3.0` | `1.3.1` |
| [flate2](https://github.com/rust-lang/flate2-rs) | `1.0.34` | `1.0.35` |
| [futures-util](https://github.com/rust-lang/futures-rs) | `0.3.30` | `0.3.31` |
| [hyper-util](https://github.com/hyperium/hyper-util) | `0.1.9` | `0.1.10` |
| [indicatif](https://github.com/console-rs/indicatif) | `0.17.8` | `0.17.9` |
| [moka](https://github.com/moka-rs/moka) | `0.12.8` | `0.12.10` |
| [pin-project](https://github.com/taiki-e/pin-project) | `1.1.6` | `1.1.7` |
| [pin-project-lite](https://github.com/taiki-e/pin-project-lite) | `0.2.14` | `0.2.15` |
| [quote](https://github.com/dtolnay/quote) | `1.0.37` | `1.0.38` |
| [semver](https://github.com/dtolnay/semver) | `1.0.23` | `1.0.24` |
| [serde](https://github.com/serde-rs/serde) | `1.0.215` | `1.0.217` |
| [serde_json](https://github.com/serde-rs/json) | `1.0.132` | `1.0.134` |
| [tar](https://github.com/alexcrichton/tar-rs) | `0.4.42` | `0.4.43` |
| [time](https://github.com/time-rs/time) | `0.3.36` | `0.3.37` |
| [tokio-stream](https://github.com/tokio-rs/tokio) | `0.1.16` | `0.1.17` |
| [tokio-util](https://github.com/tokio-rs/tokio) | `0.7.12` | `0.7.13` |
| [toml](https://github.com/toml-rs/toml) | `0.8.14` | `0.8.19` |
| [tracing](https://github.com/tokio-rs/tracing) | `0.1.40` | `0.1.41` |
| [tracing-subscriber](https://github.com/tokio-rs/tracing) | `0.3.18` | `0.3.19` |
| [url](https://github.com/servo/rust-url) | `2.5.2` | `2.5.4` |
| [wasm-bindgen-test](https://github.com/rustwasm/wasm-bindgen) | `0.3.43` | `0.3.45` |
| [js-sys](https://github.com/rustwasm/wasm-bindgen) | `0.3.72` | `0.3.76` |
| [wasm-bindgen-futures](https://github.com/rustwasm/wasm-bindgen) | `0.4.45` | `0.4.49` |
| [env_logger](https://github.com/rust-cli/env_logger) | `0.11.5` | `0.11.6` |



Updates `anyhow` from 1.0.90 to 1.0.95
- [Release notes](https://github.com/dtolnay/anyhow/releases)
- [Commits](https://github.com/dtolnay/anyhow/compare/1.0.90...1.0.95)

Updates `async-trait` from 0.1.83 to 0.1.84
- [Release notes](https://github.com/dtolnay/async-trait/releases)
- [Commits](https://github.com/dtolnay/async-trait/compare/0.1.83...0.1.84)

Updates `blake3` from 1.5.4 to 1.5.5
- [Release notes](https://github.com/BLAKE3-team/BLAKE3/releases)
- [Commits](https://github.com/BLAKE3-team/BLAKE3/compare/1.5.4...1.5.5)

Updates `chrono` from 0.4.38 to 0.4.39
- [Release notes](https://github.com/chronotope/chrono/releases)
- [Changelog](https://github.com/chronotope/chrono/blob/main/CHANGELOG.md)
- [Commits](https://github.com/chronotope/chrono/compare/v0.4.38...v0.4.39)

Updates `clap` from 4.5.20 to 4.5.23
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v4.5.20...clap_complete-v4.5.23)

Updates `clap_complete` from 4.5.33 to 4.5.40
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v4.5.33...clap_complete-v4.5.40)

Updates `comfy-table` from 7.1.1 to 7.1.3
- [Release notes](https://github.com/nukesor/comfy-table/releases)
- [Changelog](https://github.com/Nukesor/comfy-table/blob/main/CHANGELOG.md)
- [Commits](https://github.com/nukesor/comfy-table/compare/v7.1.1...v7.1.3)

Updates `console` from 0.15.8 to 0.15.10
- [Release notes](https://github.com/console-rs/console/releases)
- [Changelog](https://github.com/console-rs/console/blob/main/CHANGELOG.md)
- [Commits](https://github.com/console-rs/console/compare/0.15.8...0.15.10)

Updates `const_format` from 0.2.33 to 0.2.34
- [Release notes](https://github.com/rodrimati1992/const_format_crates/releases)
- [Changelog](https://github.com/rodrimati1992/const_format_crates/blob/master/Changelog.md)
- [Commits](https://github.com/rodrimati1992/const_format_crates/commits/0.2.34)

Updates `csv` from 1.3.0 to 1.3.1
- [Commits](https://github.com/BurntSushi/rust-csv/compare/1.3.0...1.3.1)

Updates `flate2` from 1.0.34 to 1.0.35
- [Release notes](https://github.com/rust-lang/flate2-rs/releases)
- [Changelog](https://github.com/rust-lang/flate2-rs/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/flate2-rs/compare/1.0.34...1.0.35)

Updates `futures-util` from 0.3.30 to 0.3.31
- [Release notes](https://github.com/rust-lang/futures-rs/releases)
- [Changelog](https://github.com/rust-lang/futures-rs/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/futures-rs/compare/0.3.30...0.3.31)

Updates `hyper-util` from 0.1.9 to 0.1.10
- [Release notes](https://github.com/hyperium/hyper-util/releases)
- [Changelog](https://github.com/hyperium/hyper-util/blob/master/CHANGELOG.md)
- [Commits](https://github.com/hyperium/hyper-util/compare/v0.1.9...v0.1.10)

Updates `indicatif` from 0.17.8 to 0.17.9
- [Release notes](https://github.com/console-rs/indicatif/releases)
- [Commits](https://github.com/console-rs/indicatif/compare/0.17.8...0.17.9)

Updates `moka` from 0.12.8 to 0.12.10
- [Changelog](https://github.com/moka-rs/moka/blob/main/CHANGELOG.md)
- [Commits](https://github.com/moka-rs/moka/compare/v0.12.8...v0.12.10)

Updates `pin-project` from 1.1.6 to 1.1.7
- [Release notes](https://github.com/taiki-e/pin-project/releases)
- [Changelog](https://github.com/taiki-e/pin-project/blob/main/CHANGELOG.md)
- [Commits](https://github.com/taiki-e/pin-project/compare/v1.1.6...v1.1.7)

Updates `pin-project-lite` from 0.2.14 to 0.2.15
- [Release notes](https://github.com/taiki-e/pin-project-lite/releases)
- [Changelog](https://github.com/taiki-e/pin-project-lite/blob/main/CHANGELOG.md)
- [Commits](https://github.com/taiki-e/pin-project-lite/compare/v0.2.14...v0.2.15)

Updates `quote` from 1.0.37 to 1.0.38
- [Release notes](https://github.com/dtolnay/quote/releases)
- [Commits](https://github.com/dtolnay/quote/compare/1.0.37...1.0.38)

Updates `semver` from 1.0.23 to 1.0.24
- [Release notes](https://github.com/dtolnay/semver/releases)
- [Commits](https://github.com/dtolnay/semver/compare/1.0.23...1.0.24)

Updates `serde` from 1.0.215 to 1.0.217
- [Release notes](https://github.com/serde-rs/serde/releases)
- [Commits](https://github.com/serde-rs/serde/compare/v1.0.215...v1.0.217)

Updates `serde_derive` from 1.0.215 to 1.0.217
- [Release notes](https://github.com/serde-rs/serde/releases)
- [Commits](https://github.com/serde-rs/serde/compare/v1.0.215...v1.0.217)

Updates `serde_json` from 1.0.132 to 1.0.134
- [Release notes](https://github.com/serde-rs/json/releases)
- [Commits](https://github.com/serde-rs/json/compare/v1.0.132...v1.0.134)

Updates `tar` from 0.4.42 to 0.4.43
- [Commits](https://github.com/alexcrichton/tar-rs/compare/0.4.42...0.4.43)

Updates `time` from 0.3.36 to 0.3.37
- [Release notes](https://github.com/time-rs/time/releases)
- [Changelog](https://github.com/time-rs/time/blob/main/CHANGELOG.md)
- [Commits](https://github.com/time-rs/time/compare/v0.3.36...v0.3.37)

Updates `tokio-stream` from 0.1.16 to 0.1.17
- [Release notes](https://github.com/tokio-rs/tokio/releases)
- [Commits](https://github.com/tokio-rs/tokio/compare/tokio-stream-0.1.16...tokio-stream-0.1.17)

Updates `tokio-util` from 0.7.12 to 0.7.13
- [Release notes](https://github.com/tokio-rs/tokio/releases)
- [Commits](https://github.com/tokio-rs/tokio/compare/tokio-util-0.7.12...tokio-util-0.7.13)

Updates `toml` from 0.8.14 to 0.8.19
- [Commits](https://github.com/toml-rs/toml/compare/toml-v0.8.14...toml-v0.8.19)

Updates `tracing` from 0.1.40 to 0.1.41
- [Release notes](https://github.com/tokio-rs/tracing/releases)
- [Commits](https://github.com/tokio-rs/tracing/compare/tracing-0.1.40...tracing-0.1.41)

Updates `tracing-subscriber` from 0.3.18 to 0.3.19
- [Release notes](https://github.com/tokio-rs/tracing/releases)
- [Commits](https://github.com/tokio-rs/tracing/compare/tracing-subscriber-0.3.18...tracing-subscriber-0.3.19)

Updates `url` from 2.5.2 to 2.5.4
- [Release notes](https://github.com/servo/rust-url/releases)
- [Commits](https://github.com/servo/rust-url/compare/v2.5.2...v2.5.4)

Updates `wasm-bindgen-test` from 0.3.43 to 0.3.45
- [Release notes](https://github.com/rustwasm/wasm-bindgen/releases)
- [Changelog](https://github.com/rustwasm/wasm-bindgen/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rustwasm/wasm-bindgen/commits)

Updates `js-sys` from 0.3.72 to 0.3.76
- [Release notes](https://github.com/rustwasm/wasm-bindgen/releases)
- [Changelog](https://github.com/rustwasm/wasm-bindgen/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rustwasm/wasm-bindgen/commits)

Updates `wasm-bindgen-futures` from 0.4.45 to 0.4.49
- [Release notes](https://github.com/rustwasm/wasm-bindgen/releases)
- [Changelog](https://github.com/rustwasm/wasm-bindgen/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rustwasm/wasm-bindgen/commits)

Updates `web-sys` from 0.3.72 to 0.3.76
- [Release notes](https://github.com/rustwasm/wasm-bindgen/releases)
- [Changelog](https://github.com/rustwasm/wasm-bindgen/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rustwasm/wasm-bindgen/commits)

Updates `env_logger` from 0.11.5 to 0.11.6
- [Release notes](https://github.com/rust-cli/env_logger/releases)
- [Changelog](https://github.com/rust-cli/env_logger/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rust-cli/env_logger/compare/v0.11.5...v0.11.6)

---
updated-dependencies:
- dependency-name: anyhow
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: patch-updates
- dependency-name: async-trait
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: patch-updates
- dependency-name: blake3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: patch-updates
- dependency-name: chrono
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: patch-updates
- dependency-name: clap
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: patch-updates
- dependency-name: clap_complete
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: patch-updates
- dependency-name: comfy-table
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: patch-updates
- dependency-name: console
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: patch-updates
- dependency-name: const_format
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: patch-updates
- dependency-name: csv
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: patch-updates
- dependency-name: flate2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: patch-updates
- dependency-name: futures-util
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: patch-updates
- dependency-name: hyper-util
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: patch-updates
- dependency-name: indicatif
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: patch-updates
- dependency-name: moka
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: patch-updates
- dependency-name: pin-project
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: patch-updates
- dependency-name: pin-project-lite
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: patch-updates
- dependency-name: quote
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: patch-updates
- dependency-name: semver
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: patch-updates
- dependency-name: serde
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: patch-updates
- dependency-name: serde_derive
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: patch-updates
- dependency-name: serde_json
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: patch-updates
- dependency-name: tar
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: patch-updates
- dependency-name: time
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: patch-updates
- dependency-name: tokio-stream
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: patch-updates
- dependency-name: tokio-util
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: patch-updates
- dependency-name: toml
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: patch-updates
- dependency-name: tracing
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: patch-updates
- dependency-name: tracing-subscriber
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: patch-updates
- dependency-name: url
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: patch-updates
- dependency-name: wasm-bindgen-test
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: patch-updates
- dependency-name: js-sys
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: patch-updates
- dependency-name: wasm-bindgen-futures
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: patch-updates
- dependency-name: web-sys
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: patch-updates
- dependency-name: env_logger
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: patch-updates
...

Signed-off-by: dependabot[bot] <support@github.com>

* Use expect in geodata test to give error message on failure

I keep hitting this error on CI, from what I think is network hickup.
But it's hard to tell form the log since the error is swallowed.

Explicitly unwrap the result so we get a more detailed error output

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Jon Häggblad <jon.haggblad@gmail.com>
2025-01-08 10:56:39 +01:00
Jon Häggblad 9b02de3e75 Use expect in geodata test to give error message on failure (#5314)
* Use expect in geodata test to give error message on failure

I keep hitting this error on CI, from what I think is network hickup.
But it's hard to tell form the log since the error is swallowed.

Explicitly unwrap the result so we get a more detailed error output

* Add nym-node-status-api to ci-build
2025-01-08 10:56:26 +01:00
benedettadavico b47a742dd0 update nym-node binary version 2025-01-08 10:37:48 +01:00
benedetta davico 6e14882246 Merge pull request #5315 from nymtech/release/2024.14-crunch-patched
Merge crunch patched to reeses
2025-01-08 10:35:54 +01:00
benedetta davico f3d8aba82c Merge pull request #5288 from nymtech/release/2024.14-crunch-patched
Merge patched crunch to develop
2025-01-08 10:34:12 +01:00
Tommy Verrall a7466a0e02 Merge pull request #5313 from nymtech/bugfix/append-gb-cap
amend 250gb limit
2025-01-08 09:50:04 +01:00
Tommy Verrall 78f45012db amend 250gb limit 2025-01-08 09:44:14 +01:00
benedettadavico f6a2f62ea9 bump versions of binaries 2025-01-08 09:28:48 +01:00
Jędrzej Stuczyński 3efeededc5 feature: expand nym-node prometheus metrics (#5298)
* fixed bearer auth for prometheus route

* basic prometheus metrics

* added rates on global values

* improved structure on the prometheus metrics

* added additional metrics for ingress websockets and egress mixnet connections

* some channel business metrics

* fixed metrics registration and added additional variants

* added counter for number of disk persisted packets

* counter for pending egress packets

* counter for pending egress forward packets

* clippy
2025-01-07 13:34:18 +00:00
Jędrzej Stuczyński c482350ec6 feature: wireguard metrics (#5278)
* experimental log

* introduce wireguard metrics updates

* add wireguard traffic rates to console logger

* missing import

* changed order of displayed values

* expose bytes information via rest endpoint

* clippy
2025-01-07 13:32:07 +00:00
import this 72a4a26c40 [DOCs/operators]: smooth operators (#5311)
* smooth minimum expectation

* simplify simplify

* quick fix

* feedback edits

* feedback edits

* feedback edits
2025-01-06 12:46:16 +00:00
import this 5d9b5a0d70 initialise minimum requirements page (#5304) 2025-01-06 10:50:43 +00:00
import this c070e4bfee [DOCs]: Fixes (#5299)
* correct url

* version fix
2025-01-06 10:50:31 +00:00
Bogdan-Ștefan Neacşu f7a7a8072f Move tun constants to network defaults (#5286) (#5287) 2024-12-18 16:23:18 +02:00
Jon Häggblad acd068e5ab Add close to credential storage (#5283)
* Add close method to credential storage

* wip
2024-12-18 12:37:16 +01:00
benedetta davico 8d5a41a790 Merge pull request #5277 from nymtech/feature/modify_changelog
Modify CHANGELOG
2024-12-18 11:07:49 +01:00
Bogdan-Ștefan Neacşu caa17d933c Add windows to CI builds (#5269)
* Add windows to CI builds

* Fix win build for node status api

* Fix win build for sdk

* Fix win build for cred proxy
2024-12-17 22:26:38 +01:00
Bogdan-Ștefan Neacşu 039b05cf7e Modify CHANGELOG 2024-12-17 18:59:49 +02:00
benedetta davico 37b10b59aa update changelog for nym-node v1.2.1 2024-12-17 17:54:18 +01:00
benedetta davico a9ede22bbd update nym-node version 2024-12-17 17:41:12 +01:00
Bogdan-Ștefan Neacşu b656003306 Expect that previously regitrated clients don't have v6 addr 2024-12-17 16:59:01 +02:00
273 changed files with 20585 additions and 37445 deletions
+7 -6
View File
@@ -9,15 +9,16 @@ on:
- 'gateway/**'
- 'integrations/**'
- 'mixnode/**'
- 'sdk/rust/**'
- 'sdk/lib/**'
- 'service-providers/**'
- 'nym-network-monitor/**'
- 'nym-api/**'
- 'nym-node/**'
- 'nym-outfox/**'
- 'nym-data-observatory/**'
- 'nym-network-monitor/**'
- 'nym-node/**'
- 'nym-node-status-api/**'
- 'nym-outfox/**'
- 'nym-validator-rewarder/**'
- 'sdk/lib/**'
- 'sdk/rust/**'
- 'service-providers/**'
- 'tools/**'
- 'wasm/**'
- 'Cargo.toml'
+1 -1
View File
@@ -26,7 +26,7 @@ jobs:
git config --global user.name "Lawrence Stalder"
- name: Get version from cargo.toml
uses: mikefarah/yq@v4.44.6
uses: mikefarah/yq@v4.45.1
id: get_version
with:
cmd: yq -oy '.package.version' ${{ env.WORKING_DIRECTORY }}/nym-credential-proxy/Cargo.toml
+1 -1
View File
@@ -26,7 +26,7 @@ jobs:
git config --global user.name "Lawrence Stalder"
- name: Get version from cargo.toml
uses: mikefarah/yq@v4.44.6
uses: mikefarah/yq@v4.45.1
id: get_version
with:
cmd: yq -oy '.package.version' ${{ env.WORKING_DIRECTORY }}/Cargo.toml
+1 -1
View File
@@ -26,7 +26,7 @@ jobs:
git config --global user.name "Lawrence Stalder"
- name: Get version from cargo.toml
uses: mikefarah/yq@v4.44.6
uses: mikefarah/yq@v4.45.1
id: get_version
with:
cmd: yq -oy '.package.version' ${{ env.WORKING_DIRECTORY }}/nym-network-monitor/Cargo.toml
@@ -31,7 +31,7 @@ jobs:
git config --global user.name "Lawrence Stalder"
- name: Get version from cargo.toml
uses: mikefarah/yq@v4.44.6
uses: mikefarah/yq@v4.45.1
id: get_version
with:
cmd: yq -oy '.package.version' ${{ env.WORKING_DIRECTORY }}/Cargo.toml
+1 -1
View File
@@ -26,7 +26,7 @@ jobs:
git config --global user.name "Lawrence Stalder"
- name: Get version from cargo.toml
uses: mikefarah/yq@v4.44.6
uses: mikefarah/yq@v4.45.1
id: get_version
with:
cmd: yq -oy '.package.version' ${{ env.WORKING_DIRECTORY }}/Cargo.toml
+1 -1
View File
@@ -26,7 +26,7 @@ jobs:
git config --global user.name "Lawrence Stalder"
- name: Get version from cargo.toml
uses: mikefarah/yq@v4.44.6
uses: mikefarah/yq@v4.45.1
id: get_version
with:
cmd: yq -oy '.package.version' ${{ env.WORKING_DIRECTORY }}/Cargo.toml
@@ -26,7 +26,7 @@ jobs:
git config --global user.name "Lawrence Stalder"
- name: Get version from cargo.toml
uses: mikefarah/yq@v4.44.6
uses: mikefarah/yq@v4.45.1
id: get_version
with:
cmd: yq -oy '.package.version' ${{ env.WORKING_DIRECTORY }}/Cargo.toml
@@ -26,7 +26,7 @@ jobs:
git config --global user.name "Lawrence Stalder"
- name: Get version from cargo.toml
uses: mikefarah/yq@v4.44.6
uses: mikefarah/yq@v4.45.1
id: get_version
with:
cmd: yq -oy '.package.version' ${{ env.WORKING_DIRECTORY }}/Cargo.toml
+85
View File
@@ -4,6 +4,91 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
## [Unreleased]
## [2025.1-reeses] (2025-01-15)
- Feture/legacy alert ([#5346])
- chore: readjusted --mode behaviour to fix the regression ([#5331])
- chore: apply 1.84 linter suggestions ([#5330])
- bugfix: make sure refresh data key matches bond info ([#5329])
- reduce log severity for number of packets being delayed ([#5321])
- feat: warn users if node is run in exit mode only ([#5320])
- Bugfix/contract version assignment ([#5318])
- fixed client session histogram buckets ([#5316])
- amend 250gb limit ([#5313])
- feature: expand nym-node prometheus metrics ([#5298])
- Cherry picked #5286 ([#5287])
- Add close to credential storage ([#5283])
- feature: wireguard metrics ([#5278])
- Add PATCH support to nym-http-api-client ([#5260])
- chore: removed legacy socks5 listener ([#5259])
- bugfix: make sure to apply gateway score filtering when choosing initial node ([#5256])
- Update TS bindings ([#5255])
- Add conversion unit tests for auth msg ([#5251])
- Add control messages to GatewayTransciver ([#5247])
- Remove unneeded async function annotation ([#5246])
- bugfix: make sure to update timestamp of last batch verification to prevent double redemption ([#5239])
- Add FromStr impl for UserAgent ([#5236])
- Extend swagger docs ([#5235])
- TicketType derive Hash and Eq ([#5233])
- Add fd callback to client core ([#5230])
- Extend raw ws fd for gateway client ([#5218])
- Shipping raw metrics to PG ([#5216])
- Change sqlite journal mode to WAL ([#5213])
- Derive serialize for UserAgent ([#5210])
- Restore Location fields ([#5208])
- better date serialization ([#5207])
- Fix overflow ([#5204])
- feature: hopefully final steps of the smoosh™️ ([#5201])
- Fix overflow ([#5184])
- NS API - Gateway stats scraping ([#5180])
- introduced initial internal commands for nym-cli: ecash key and request generation ([#5174])
- Move NS client to separate package under NS API ([#5171])
- build(deps): bump micromatch from 4.0.4 to 4.0.8 in /testnet-faucet ([#4813])
[#5346]: https://github.com/nymtech/nym/pull/5346
[#5331]: https://github.com/nymtech/nym/pull/5331
[#5330]: https://github.com/nymtech/nym/pull/5330
[#5329]: https://github.com/nymtech/nym/pull/5329
[#5321]: https://github.com/nymtech/nym/pull/5321
[#5320]: https://github.com/nymtech/nym/pull/5320
[#5318]: https://github.com/nymtech/nym/pull/5318
[#5316]: https://github.com/nymtech/nym/pull/5316
[#5313]: https://github.com/nymtech/nym/pull/5313
[#5298]: https://github.com/nymtech/nym/pull/5298
[#5287]: https://github.com/nymtech/nym/pull/5287
[#5283]: https://github.com/nymtech/nym/pull/5283
[#5278]: https://github.com/nymtech/nym/pull/5278
[#5260]: https://github.com/nymtech/nym/pull/5260
[#5259]: https://github.com/nymtech/nym/pull/5259
[#5256]: https://github.com/nymtech/nym/pull/5256
[#5255]: https://github.com/nymtech/nym/pull/5255
[#5251]: https://github.com/nymtech/nym/pull/5251
[#5247]: https://github.com/nymtech/nym/pull/5247
[#5246]: https://github.com/nymtech/nym/pull/5246
[#5239]: https://github.com/nymtech/nym/pull/5239
[#5236]: https://github.com/nymtech/nym/pull/5236
[#5235]: https://github.com/nymtech/nym/pull/5235
[#5233]: https://github.com/nymtech/nym/pull/5233
[#5230]: https://github.com/nymtech/nym/pull/5230
[#5218]: https://github.com/nymtech/nym/pull/5218
[#5216]: https://github.com/nymtech/nym/pull/5216
[#5213]: https://github.com/nymtech/nym/pull/5213
[#5210]: https://github.com/nymtech/nym/pull/5210
[#5208]: https://github.com/nymtech/nym/pull/5208
[#5207]: https://github.com/nymtech/nym/pull/5207
[#5204]: https://github.com/nymtech/nym/pull/5204
[#5201]: https://github.com/nymtech/nym/pull/5201
[#5184]: https://github.com/nymtech/nym/pull/5184
[#5180]: https://github.com/nymtech/nym/pull/5180
[#5174]: https://github.com/nymtech/nym/pull/5174
[#5171]: https://github.com/nymtech/nym/pull/5171
[#4813]: https://github.com/nymtech/nym/pull/4813
## [2024.14-crunch-patched] (2024-12-17)
- Fixes an issue to allow previously registred clients to connect to latest nym-nodes
- Fixes compatibility issues between nym-nodes and older clients
## [2024.14-crunch] (2024-12-11)
- Merge/release/2024.14-crunch ([#5242])
Generated
+967 -506
View File
File diff suppressed because it is too large Load Diff
+34 -36
View File
@@ -193,9 +193,9 @@ aes = "0.8.1"
aes-gcm = "0.10.1"
aes-gcm-siv = "0.11.1"
aead = "0.5.2"
anyhow = "1.0.90"
anyhow = "1.0.95"
argon2 = "0.5.0"
async-trait = "0.1.83"
async-trait = "0.1.85"
axum-client-ip = "0.6.1"
axum = "0.7.5"
axum-extra = "0.9.4"
@@ -204,7 +204,7 @@ bincode = "1.3.3"
bip39 = { version = "2.0.0", features = ["zeroize"] }
bit-vec = "0.7.0" # can we unify those?
bitvec = "1.0.0"
blake3 = "1.5.4"
blake3 = "1.5.5"
bloomfilter = "1.0.14"
bs58 = "0.5.1"
bytecodec = "0.4.15"
@@ -214,20 +214,20 @@ celes = "2.4.0"
cfg-if = "1.0.0"
chacha20 = "0.9.0"
chacha20poly1305 = "0.10.1"
chrono = "0.4.31"
chrono = "0.4.39"
cipher = "0.4.3"
clap = "4.5.20"
clap = "4.5.26"
clap_complete = "4.5"
clap_complete_fig = "4.5"
colored = "2.0"
comfy-table = "7.1.1"
console = "0.15.8"
comfy-table = "7.1.3"
console = "0.15.10"
console-subscriber = "0.1.1"
console_error_panic_hook = "0.1"
const-str = "0.5.6"
const_format = "0.2.33"
criterion = "0.4"
csv = "1.3.0"
const_format = "0.2.34"
criterion = "0.5"
csv = "1.3.1"
ctr = "0.9.1"
cupid = "0.6.1"
curve25519-dalek = "4.1"
@@ -244,8 +244,8 @@ etherparse = "0.13.0"
envy = "0.4"
eyre = "0.6.9"
fastrand = "2.1.1"
flate2 = "1.0.34"
futures = "0.3.28"
flate2 = "1.0.35"
futures = "0.3.31"
futures-util = "0.3"
generic-array = "0.14.7"
getrandom = "0.2.10"
@@ -264,7 +264,7 @@ humantime-serde = "1.1.1"
human-repr = "1.1.0"
hyper = "1.4.1"
hyper-util = "0.1"
indicatif = "0.17.8"
indicatif = "0.17.9"
inquire = "0.6.2"
ip_network = "0.4.1"
ipnetwork = "0.20"
@@ -289,7 +289,7 @@ parking_lot = "0.12.3"
pem = "0.8"
petgraph = "0.6.5"
pin-project = "1.1"
pin-project-lite = "0.2.14"
pin-project-lite = "0.2.16"
pretty_env_logger = "0.4.0"
publicsuffix = "2.2.3"
quote = "1"
@@ -307,11 +307,11 @@ rocket_cors = "0.6.0"
rocket_okapi = "0.8.0"
safer-ffi = "0.1.13"
schemars = "0.8.21"
semver = "1.0.23"
serde = "1.0.211"
semver = "1.0.24"
serde = "1.0.217"
serde_bytes = "0.11.15"
serde_derive = "1.0"
serde_json = "1.0.132"
serde_json = "1.0.135"
serde_json_path = "0.7.1"
serde_repr = "0.1"
serde_with = "3.9.0"
@@ -326,25 +326,25 @@ subtle-encoding = "0.5"
syn = "1"
sysinfo = "0.30.13"
tap = "1.0.1"
tar = "0.4.42"
tempfile = "3.14"
tar = "0.4.43"
tempfile = "3.15"
thiserror = "1.0.64"
time = "0.3.30"
time = "0.3.37"
tokio = "1.39"
tokio-stream = "0.1.16"
tokio-stream = "0.1.17"
tokio-test = "0.4.4"
tokio-tun = "0.11.5"
tokio-tungstenite = { version = "0.20.1" }
tokio-util = "0.7.12"
toml = "0.8.14"
tokio-util = "0.7.13"
toml = "0.8.19"
tower = "0.4.13"
tower-http = "0.5.2"
tracing = "0.1.37"
tracing = "0.1.41"
tracing-opentelemetry = "0.19.0"
tracing-subscriber = "0.3.16"
tracing-subscriber = "0.3.19"
tracing-tree = "0.2.2"
tracing-log = "0.2"
ts-rs = "10.0.0"
ts-rs = "10.1.0"
tungstenite = { version = "0.20.1", default-features = false }
url = "2.5"
utoipa = "5.2"
@@ -353,7 +353,7 @@ utoipauto = "0.2"
uuid = "*"
vergen = { version = "=8.3.1", default-features = false }
walkdir = "2"
wasm-bindgen-test = "0.3.43"
wasm-bindgen-test = "0.3.49"
x25519-dalek = "2.0.0"
zeroize = "1.6.0"
@@ -396,19 +396,17 @@ prost = { version = "0.12", default-features = false }
# wasm-related dependencies
gloo-utils = "0.2.0"
gloo-net = "0.5.0"
gloo-net = "0.6.0"
# use a separate branch due to feature unification failures
# this is blocked until the upstream removes outdates `wasm_bindgen` feature usage
# indexed_db_futures = "0.4.1"
indexed_db_futures = { git = "https://github.com/TiemenSch/rust-indexed-db", branch = "update-uuid" }
js-sys = "0.3.70"
# TODO: migrate to 0.6+
indexed_db_futures = "0.4.2"
js-sys = "0.3.76"
serde-wasm-bindgen = "0.6.5"
tsify = "0.4.5"
wasm-bindgen = "0.2.99"
wasm-bindgen-futures = "0.4.45"
wasmtimer = "0.2.0"
web-sys = "0.3.72"
wasm-bindgen-futures = "0.4.49"
wasmtimer = "0.4.1"
web-sys = "0.3.76"
# Profile settings for individual crates
+6 -6
View File
@@ -14,7 +14,7 @@ The platform is composed of multiple Rust crates. Top-level executable binary cr
* `nym-socks5-client` - a Socks5 proxy you can run on your machine and use with existing applications.
* `nym-explorer` - a (projected) block explorer and (existing) mixnet viewer.
* `nym-wallet` - a desktop wallet implemented using the [Tauri](https://tauri.studio/en/docs/about/intro) framework.
* `nym-cli` - a tool for interacting with the network from the CLI.
* `nym-cli` - a tool for interacting with the network from the CLI.
<!-- coming soon
* `nym-network-monitor` - sends packets through the full system to check that they are working as expected, and stores node uptime histories as the basis of a rewards system ("mixmining" or "proof-of-mixing").
-->
@@ -42,10 +42,10 @@ client ───► Gateway ──┘ mix │ mix ┌─►mix ───►
References for developers:
* [Dev Docs](https://nymtech.net/docs/developers)
* [SDKs](https://nymtech.net/docs/developers/rust)
* [Network Docs](https://nymtech.net/docs/network)
* [Release Cycle - git flow](https://nymtech.net/docs/operators/release-cycle)
* [Dev Docs](https://nym.com/docs/developers)
* [SDKs](https://nym.com/docs/developers/rust)
* [Network Docs](https://nym.com/docs/network)
* [Release Cycle - git flow](https://nym.com/docs/operators/release-cycle)
### Developer chat
@@ -66,4 +66,4 @@ As a general approach, licensing is as follows this pattern:
- libraries and components are Apache 2.0 or MIT
- documentation is Apache 2.0 or CC0-1.0
Nym Node Operators and Validators Temrs and Conditions can be found [here](https://nymtech.net/terms-and-conditions/operators/v1.0.0).
Nym Node Operators and Validators Temrs and Conditions can be found [here](https://nym.com/terms-and-conditions/operators/v1.0.0).
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "nym-client"
version = "1.1.45"
version = "1.1.46"
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.45"
version = "1.1.46"
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"
@@ -28,7 +28,7 @@ pub type HmacSha256 = Hmac<Sha256>;
pub type Nonce = u64;
pub type Taken = Option<SystemTime>;
pub const BANDWIDTH_CAP_PER_DAY: u64 = 1024 * 1024 * 1024; // 1 GB
pub const BANDWIDTH_CAP_PER_DAY: u64 = 250 * 1024 * 1024 * 1024; // 250 GB
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct IpPair {
@@ -472,6 +472,7 @@ where
.claim_initial_bandwidth()
.await
.map_err(gateway_failure)?;
gateway_client
.start_listening_for_mixnet_messages()
.map_err(gateway_failure)?;
@@ -9,10 +9,12 @@ use self::{
acknowledgement_control::AcknowledgementController, real_traffic_stream::OutQueueControl,
};
use crate::client::real_messages_control::message_handler::MessageHandler;
use crate::client::replies::reply_controller;
use crate::client::replies::reply_controller::{
ReplyController, ReplyControllerReceiver, ReplyControllerSender,
};
use crate::client::replies::reply_storage::CombinedReplyStorage;
use crate::config;
use crate::{
client::{
inbound_messages::InputMessageReceiver, mix_traffic::BatchMixMessageSender,
@@ -27,16 +29,13 @@ use nym_gateway_client::AcknowledgementReceiver;
use nym_sphinx::acknowledgements::AckKey;
use nym_sphinx::addressing::clients::Recipient;
use nym_sphinx::params::PacketType;
use nym_statistics_common::clients::ClientStatsSender;
use nym_task::connections::{ConnectionCommandReceiver, LaneQueueLengths};
use rand::{rngs::OsRng, CryptoRng, Rng};
use std::sync::Arc;
use crate::client::replies::reply_controller;
use crate::config;
pub(crate) use acknowledgement_control::{AckActionSender, Action};
use nym_statistics_common::clients::ClientStatsSender;
pub(crate) mod acknowledgement_control;
pub(crate) mod message_handler;
pub(crate) mod real_traffic_stream;
@@ -70,7 +70,10 @@ impl SendingDelayController {
lower_bound,
multiplier_elevated_counter: 0,
time_when_logged_about_elevated_multiplier: now
- Duration::from_secs(INTERVAL_BETWEEN_WARNING_ABOUT_ELEVATED_MULTIPLIER_SECS),
.checked_sub(Duration::from_secs(
INTERVAL_BETWEEN_WARNING_ABOUT_ELEVATED_MULTIPLIER_SECS,
))
.unwrap_or(now),
time_when_changed: now,
time_when_backpressure_detected: now,
}
@@ -16,14 +16,14 @@
#![warn(clippy::todo)]
#![warn(clippy::dbg_macro)]
use std::time::Duration;
use futures::StreamExt;
use nym_client_core_config_types::StatsReporting;
use nym_sphinx::addressing::Recipient;
use nym_statistics_common::clients::{
ClientStatsController, ClientStatsReceiver, ClientStatsSender,
};
use nym_task::connections::TransmissionLane;
use std::time::Duration;
use crate::{
client::inbound_messages::{InputMessage, InputMessageSender},
@@ -94,10 +94,32 @@ impl StatisticsControl {
async fn run_with_shutdown(&mut self, mut task_client: nym_task::TaskClient) {
log::debug!("Started StatisticsControl with graceful shutdown support");
let mut stats_report_interval =
tokio::time::interval(self.reporting_config.reporting_interval);
let mut local_report_interval = tokio::time::interval(LOCAL_REPORT_INTERVAL);
let mut snapshot_interval = tokio::time::interval(SNAPSHOT_INTERVAL);
#[cfg(not(target_arch = "wasm32"))]
let mut stats_report_interval = tokio_stream::wrappers::IntervalStream::new(
tokio::time::interval(self.reporting_config.reporting_interval),
);
#[cfg(not(target_arch = "wasm32"))]
let mut local_report_interval = tokio_stream::wrappers::IntervalStream::new(
tokio::time::interval(LOCAL_REPORT_INTERVAL),
);
#[cfg(not(target_arch = "wasm32"))]
let mut snapshot_interval =
tokio_stream::wrappers::IntervalStream::new(tokio::time::interval(SNAPSHOT_INTERVAL));
#[cfg(target_arch = "wasm32")]
let mut stats_report_interval = gloo_timers::future::IntervalStream::new(
self.reporting_config.reporting_interval.as_millis() as u32,
);
#[cfg(target_arch = "wasm32")]
let mut local_report_interval =
gloo_timers::future::IntervalStream::new(LOCAL_REPORT_INTERVAL.as_millis() as u32);
#[cfg(target_arch = "wasm32")]
let mut snapshot_interval =
gloo_timers::future::IntervalStream::new(SNAPSHOT_INTERVAL.as_millis() as u32);
loop {
tokio::select! {
@@ -108,16 +130,20 @@ impl StatisticsControl {
break;
}
},
_ = snapshot_interval.tick() => {
_ = snapshot_interval.next() => {
self.stats.snapshot();
}
_ = stats_report_interval.tick(), if self.reporting_config.enabled && self.reporting_config.provider_address.is_some() => {
// SAFTEY : this branch executes only if reporting is not none, so unwrapp is fine
#[allow(clippy::unwrap_used)]
self.report_stats(self.reporting_config.provider_address.unwrap()).await;
_ = stats_report_interval.next() => {
let Some(recipient) = self.reporting_config.provider_address else {
continue
};
if self.reporting_config.enabled {
self.report_stats(recipient).await;
}
}
_ = local_report_interval.tick() => {
_ = local_report_interval.next() => {
self.stats.local_report(&mut task_client);
}
_ = task_client.recv_with_delay() => {
+29 -1
View File
@@ -17,7 +17,7 @@ use nym_topology::node::RoutingNode;
use nym_validator_client::client::IdentityKey;
use nym_validator_client::nyxd::AccountId;
use serde::Serialize;
use std::fmt::Display;
use std::fmt::{Debug, Display};
use std::sync::Arc;
use time::OffsetDateTime;
use url::Url;
@@ -221,6 +221,34 @@ pub enum GatewaySetup {
},
}
impl Debug for GatewaySetup {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
GatewaySetup::MustLoad { gateway_id } => f
.debug_struct("GatewaySetup::MustLoad")
.field("gateway_id", gateway_id)
.finish(),
GatewaySetup::New {
specification,
available_gateways,
} => f
.debug_struct("GatewaySetup::New")
.field("specification", specification)
.field("available_gateways", available_gateways)
.field("gateways", specification)
.finish(),
GatewaySetup::ReuseConnection {
gateway_details, ..
} => f
.debug_struct("GatewaySetup::ReuseConnection")
.field("authenticated_ephemeral_client", &"***")
.field("gateway_details", gateway_details)
.field("client_keys", &"***")
.finish(),
}
}
}
impl GatewaySetup {
pub fn try_reuse_connection(init_res: InitialisationResult) -> Result<Self, ClientCoreError> {
if let Some(authenticated_ephemeral_client) = init_res.authenticated_ephemeral_client {
@@ -863,11 +863,4 @@ pub enum QueryMsg {
pub struct MigrateMsg {
pub unsafe_skip_state_updates: Option<bool>,
pub vesting_contract_address: Option<String>,
pub current_nym_node_semver: String,
#[serde(default)]
pub version_score_weights: OutdatedVersionWeights,
#[serde(default)]
pub version_score_params: VersionScoreFormulaParams,
}
-1
View File
@@ -11,7 +11,6 @@ license.workspace = true
[dependencies]
bincode = { workspace = true }
defguard_wireguard_rs = { workspace = true }
log = { workspace = true }
sqlx = { workspace = true, features = [
"runtime-tokio-rustls",
"sqlite",
@@ -0,0 +1,7 @@
/*
* Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
* SPDX-License-Identifier: GPL-3.0-only
*/
ALTER TABLE message_store
ADD COLUMN timestamp TIMESTAMP WITHOUT TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP;
+28 -39
View File
@@ -2,9 +2,11 @@
// SPDX-License-Identifier: GPL-3.0-only
use crate::models::StoredMessage;
use time::OffsetDateTime;
use tracing::debug;
#[derive(Clone)]
pub(crate) struct InboxManager {
pub struct InboxManager {
connection_pool: sqlx::SqlitePool,
/// Maximum number of messages that can be obtained from the database per operation.
/// It is used to prevent out of memory errors in the case of client receiving a lot of data while
@@ -71,44 +73,22 @@ impl InboxManager {
// get 1 additional message to check whether there will be more to grab
// next time
let limit = self.retrieval_limit + 1;
let mut res = if let Some(start_after) = start_after {
sqlx::query_as!(
StoredMessage,
r#"
SELECT
id as "id!",
client_address_bs58 as "client_address_bs58!",
content as "content!"
FROM message_store
WHERE client_address_bs58 = ? AND id > ?
ORDER BY id ASC
LIMIT ?;
"#,
client_address_bs58,
start_after,
limit
)
.fetch_all(&self.connection_pool)
.await?
} else {
sqlx::query_as!(
StoredMessage,
r#"
SELECT
id as "id!",
client_address_bs58 as "client_address_bs58!",
content as "content!"
FROM message_store
WHERE client_address_bs58 = ?
ORDER BY id ASC
LIMIT ?;
"#,
client_address_bs58,
limit
)
.fetch_all(&self.connection_pool)
.await?
};
let start_after = start_after.unwrap_or(-1);
let mut res: Vec<StoredMessage> = sqlx::query_as(
r#"
SELECT id, client_address_bs58, content, timestamp
FROM message_store
WHERE client_address_bs58 = ? AND id > ?
ORDER BY id ASC
LIMIT ?;
"#,
)
.bind(client_address_bs58)
.bind(start_after)
.bind(limit)
.fetch_all(&self.connection_pool)
.await?;
if res.len() > self.retrieval_limit as usize {
res.truncate(self.retrieval_limit as usize);
@@ -146,4 +126,13 @@ impl InboxManager {
.await?;
Ok(())
}
pub async fn remove_stale(&self, cutoff: OffsetDateTime) -> Result<(), sqlx::Error> {
let affected = sqlx::query!("DELETE FROM message_store WHERE timestamp < ?", cutoff)
.execute(&self.connection_pool)
.await?
.rows_affected();
debug!("Removed {affected} stale messages");
Ok(())
}
}
+2 -2
View File
@@ -3,7 +3,6 @@
use bandwidth::BandwidthManager;
use clients::{ClientManager, ClientType};
use inboxes::InboxManager;
use models::{
Client, PersistedBandwidth, PersistedSharedKeys, RedemptionProposal, StoredMessage,
VerifiedTicket, WireguardPeer,
@@ -31,6 +30,7 @@ mod tickets;
mod wireguard_peers;
pub use error::GatewayStorageError;
pub use inboxes::InboxManager;
// note that clone here is fine as upon cloning the same underlying pool will be used
#[derive(Clone)]
@@ -53,7 +53,7 @@ impl GatewayStorage {
&self.shared_key_manager
}
pub(crate) fn inbox_manager(&self) -> &InboxManager {
pub fn inbox_manager(&self) -> &InboxManager {
&self.inbox_manager
}
+2
View File
@@ -48,11 +48,13 @@ impl TryFrom<PersistedSharedKeys> for SharedGatewayKey {
}
}
#[derive(FromRow)]
pub struct StoredMessage {
pub id: i64,
#[allow(dead_code)]
pub client_address_bs58: String,
pub content: Vec<u8>,
pub timestamp: OffsetDateTime,
}
#[derive(Debug, Clone, FromRow)]
+2
View File
@@ -27,3 +27,5 @@ nym-credentials-interface = { path = "../credentials-interface" }
nym-metrics = { path = "../nym-metrics" }
nym-task = { path = "../task" }
[target."cfg(target_arch = \"wasm32\")".dependencies.wasmtimer]
workspace = true
@@ -3,10 +3,7 @@
use super::ClientStatsEvents;
use core::fmt;
use std::{
collections::VecDeque,
time::{Duration, Instant},
};
use std::{collections::VecDeque, time::Duration};
use nym_metrics::{inc, inc_by};
use serde::{Deserialize, Serialize};
@@ -18,6 +15,51 @@ use si_scale::helpers::bibytes2;
// Also, set it larger than the packet report interval so that we don't miss notable singular events
const RECORDING_WINDOW_MS: u64 = 2300;
#[derive(PartialOrd, PartialEq, Clone, Copy, Debug)]
struct Instant {
#[cfg(not(target_arch = "wasm32"))]
inner: std::time::Instant,
#[cfg(target_arch = "wasm32")]
inner: wasmtimer::std::Instant,
}
impl Instant {
#[cfg(not(target_arch = "wasm32"))]
fn inner(&self) -> &std::time::Instant {
&self.inner
}
#[cfg(target_arch = "wasm32")]
fn inner(&self) -> &wasmtimer::std::Instant {
&self.inner
}
#[cfg(not(target_arch = "wasm32"))]
fn now() -> Self {
Instant {
inner: std::time::Instant::now(),
}
}
#[cfg(target_arch = "wasm32")]
fn now() -> Self {
Instant {
inner: wasmtimer::std::Instant::now(),
}
}
fn checked_sub(&self, duration: Duration) -> Option<Instant> {
self.inner()
.checked_sub(duration)
.map(|inner| Instant { inner })
}
fn duration_since(&self, earlier: &Instant) -> Duration {
self.inner.duration_since(*earlier.inner())
}
}
#[derive(Default, Debug, Clone, Serialize, Deserialize)]
pub(crate) struct PacketStatistics {
// Sent
@@ -424,7 +466,11 @@ impl PacketStatisticsControl {
self.history.push_back((Instant::now(), self.stats.clone()));
// Filter out old ones
let recording_window = Instant::now() - Duration::from_millis(RECORDING_WINDOW_MS);
let now = Instant::now();
let recording_window = Instant::now()
.checked_sub(Duration::from_millis(RECORDING_WINDOW_MS))
.unwrap_or(now);
while self
.history
.front()
@@ -442,7 +488,7 @@ impl PacketStatisticsControl {
// Do basic averaging over the entire history, which just uses the first and last
if let Some((start, start_stats)) = self.history.front() {
let duration_secs = Instant::now().duration_since(*start).as_secs_f64();
let duration_secs = Instant::now().duration_since(start).as_secs_f64();
let delta = self.stats.clone() - start_stats.clone();
let rates = PacketRates::from(delta) / duration_secs;
Some(rates)
@@ -458,7 +504,10 @@ impl PacketStatisticsControl {
}
// Filter out old ones
let recording_window = Instant::now() - Duration::from_millis(RECORDING_WINDOW_MS);
let now = Instant::now();
let recording_window = now
.checked_sub(Duration::from_millis(RECORDING_WINDOW_MS))
.unwrap_or(now);
while self
.rates
.front()
+3
View File
@@ -8,10 +8,13 @@ license.workspace = true
repository.workspace = true
[dependencies]
cfg-if = { workspace = true }
futures = { workspace = true }
log = { workspace = true }
thiserror = { workspace = true }
tokio = { workspace = true, features = ["macros", "sync"] }
tokio-util = { workspace = true, features = ["rt"] }
tracing = { workspace = true }
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.tokio]
workspace = true
+366
View File
@@ -0,0 +1,366 @@
// Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::{TaskClient, TaskManager};
use futures::stream::FuturesUnordered;
use futures::StreamExt;
use std::future::Future;
use std::ops::Deref;
use std::pin::Pin;
use std::time::Duration;
use tokio::task::JoinSet;
use tokio::time::sleep;
use tokio_util::sync::{CancellationToken, DropGuard};
use tokio_util::task::TaskTracker;
use tracing::{debug, info, trace};
#[cfg(unix)]
use tokio::signal::unix::{signal, SignalKind};
pub const DEFAULT_MAX_SHUTDOWN_DURATION: Duration = Duration::from_secs(5);
pub fn token_name(name: &Option<String>) -> String {
name.clone().unwrap_or_else(|| "unknown".to_string())
}
// a wrapper around tokio's CancellationToken that adds optional `name` information to more easily
// track down sources of shutdown
#[derive(Debug, Default)]
pub struct ShutdownToken {
name: Option<String>,
inner: CancellationToken,
}
impl Clone for ShutdownToken {
fn clone(&self) -> Self {
// make sure to not accidentally overflow the stack if we keep cloning the handle
let name = if let Some(name) = &self.name {
if name != Self::OVERFLOW_NAME && name.len() < Self::MAX_NAME_LENGTH {
Some(format!("{name}-child"))
} else {
Some(Self::OVERFLOW_NAME.to_string())
}
} else {
None
};
ShutdownToken {
name,
inner: self.inner.clone(),
}
}
}
impl Deref for ShutdownToken {
type Target = CancellationToken;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl ShutdownToken {
const MAX_NAME_LENGTH: usize = 128;
const OVERFLOW_NAME: &'static str = "reached maximum ShutdownToken children name depth";
pub fn new(name: impl Into<String>) -> Self {
ShutdownToken {
name: Some(name.into()),
inner: CancellationToken::new(),
}
}
// Creates a ShutdownToken which will get cancelled whenever the current token gets cancelled.
// Unlike a cloned/forked ShutdownToken, cancelling a child token does not cancel the parent token.
#[must_use]
pub fn child_token<S: Into<String>>(&self, child_suffix: S) -> Self {
let suffix = child_suffix.into();
let child_name = if let Some(base) = &self.name {
format!("{base}-{suffix}")
} else {
format!("unknown-{suffix}")
};
ShutdownToken {
name: Some(child_name),
inner: self.inner.child_token(),
}
}
// Creates a clone of the ShutdownToken which will get cancelled whenever the current token gets cancelled, and vice versa.
#[must_use]
pub fn clone_with_suffix<S: Into<String>>(&self, child_suffix: S) -> Self {
let mut child = self.clone();
let suffix = child_suffix.into();
let child_name = if let Some(base) = &self.name {
format!("{base}-{suffix}")
} else {
format!("unknown-{suffix}")
};
child.name = Some(child_name);
child
}
// exposed method with the old name for easier migration
// it will eventually be removed so please try to use `.clone_with_suffix` instead
#[must_use]
pub fn fork<S: Into<String>>(&self, child_suffix: S) -> Self {
self.clone_with_suffix(child_suffix)
}
// exposed method with the old name for easier migration
// it will eventually be removed so please try to use `.clone().named(name)` instead
#[must_use]
pub fn fork_named<S: Into<String>>(&self, name: S) -> Self {
self.clone().named(name)
}
#[must_use]
pub fn named<S: Into<String>>(mut self, name: S) -> Self {
self.name = Some(name.into());
self
}
#[must_use]
pub fn add_suffix<S: Into<String>>(self, suffix: S) -> Self {
let suffix = suffix.into();
let name = if let Some(base) = &self.name {
format!("{base}-{suffix}")
} else {
format!("unknown-{suffix}")
};
self.named(name)
}
// Returned guard will cancel this token (and all its children) on drop unless disarmed.
pub fn drop_guard(self) -> ShutdownDropGuard {
ShutdownDropGuard {
name: self.name,
inner: self.inner.drop_guard(),
}
}
pub fn name(&self) -> String {
token_name(&self.name)
}
pub async fn run_until_cancelled<F>(&self, fut: F) -> Option<F::Output>
where
F: Future,
{
let res = self.inner.run_until_cancelled(fut).await;
trace!("'{}' got cancelled", self.name());
res
}
}
pub struct ShutdownDropGuard {
name: Option<String>,
inner: DropGuard,
}
impl Deref for ShutdownDropGuard {
type Target = DropGuard;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl ShutdownDropGuard {
pub fn disarm(self) -> ShutdownToken {
ShutdownToken {
name: self.name,
inner: self.inner.disarm(),
}
}
pub fn name(&self) -> String {
token_name(&self.name)
}
}
pub struct ShutdownManager {
pub root_token: ShutdownToken,
legacy_task_manager: Option<TaskManager>,
shutdown_signals: JoinSet<()>,
// the reason I'm not using a `JoinSet` is because it forces us to use futures with the same `::Output` type
tracker: TaskTracker,
max_shutdown_duration: Duration,
}
impl Deref for ShutdownManager {
type Target = TaskTracker;
fn deref(&self) -> &Self::Target {
&self.tracker
}
}
impl ShutdownManager {
pub fn new(root_token_name: impl Into<String>) -> Self {
let manager = ShutdownManager {
root_token: ShutdownToken::new(root_token_name),
legacy_task_manager: None,
shutdown_signals: Default::default(),
tracker: Default::default(),
max_shutdown_duration: Default::default(),
};
// we need to add an explicit watcher for the cancellation token being cancelled
// so that we could cancel all legacy tasks
let cancel_watcher = manager.root_token.clone();
manager.with_shutdown(async move { cancel_watcher.cancelled().await })
}
pub fn with_legacy_task_manager(mut self) -> Self {
let mut legacy_manager =
TaskManager::default().named(format!("{}-legacy", self.root_token.name()));
let mut legacy_error_rx = legacy_manager.task_return_error_rx();
let mut legacy_drop_rx = legacy_manager.task_drop_rx();
self.legacy_task_manager = Some(legacy_manager);
// add a task that listens for legacy task clients being dropped to trigger cancellation
self.with_shutdown(async move {
tokio::select! {
_ = legacy_error_rx.recv() => (),
_ = legacy_drop_rx.recv() => (),
}
info!("received legacy shutdown signal");
})
}
#[cfg(not(target_arch = "wasm32"))]
pub fn with_default_shutdown_signals(self) -> std::io::Result<Self> {
cfg_if::cfg_if! {
if #[cfg(unix)] {
self.with_interrupt_signal()
.with_terminate_signal()?
.with_quit_signal()
} else {
Ok(self.with_interrupt_signal())
}
}
}
#[must_use]
pub fn with_shutdown<F>(mut self, shutdown: F) -> Self
where
F: Future<Output = ()>,
F: Send + 'static,
{
let shutdown_token = self.root_token.clone();
self.shutdown_signals.spawn(async move {
shutdown.await;
info!("sending cancellation after receiving shutdown signal");
shutdown_token.cancel();
});
self
}
#[cfg(unix)]
pub fn with_shutdown_signal(self, signal_kind: SignalKind) -> std::io::Result<Self> {
let mut sig = signal(signal_kind)?;
Ok(self.with_shutdown(async move {
sig.recv().await;
}))
}
#[cfg(not(target_arch = "wasm32"))]
pub fn with_interrupt_signal(self) -> Self {
self.with_shutdown(async move {
let _ = tokio::signal::ctrl_c().await;
})
}
#[cfg(unix)]
pub fn with_terminate_signal(self) -> std::io::Result<Self> {
self.with_shutdown_signal(SignalKind::terminate())
}
#[cfg(unix)]
pub fn with_quit_signal(self) -> std::io::Result<Self> {
self.with_shutdown_signal(SignalKind::quit())
}
#[must_use]
pub fn with_shutdown_duration(mut self, duration: Duration) -> Self {
self.max_shutdown_duration = duration;
self
}
pub fn child_token<S: Into<String>>(&self, child_suffix: S) -> ShutdownToken {
self.root_token.child_token(child_suffix)
}
pub fn clone_token<S: Into<String>>(&self, child_suffix: S) -> ShutdownToken {
self.root_token.clone_with_suffix(child_suffix)
}
#[must_use]
pub fn subscribe_legacy<S: Into<String>>(&self, child_suffix: S) -> TaskClient {
// alternatively we could have set self.legacy_task_manager = Some(TaskManager::default());
// on demand if it wasn't unavailable, but then we'd have to use mutable reference
#[allow(clippy::expect_used)]
self.legacy_task_manager
.as_ref()
.expect("did not enable legacy shutdown support")
.subscribe_named(child_suffix)
}
async fn finish_shutdown(mut self) {
let mut wait_futures = FuturesUnordered::<Pin<Box<dyn Future<Output = ()>>>>::new();
// force shutdown via ctrl-c
wait_futures.push(Box::pin(async move {
#[cfg(not(target_arch = "wasm32"))]
let interrupt_future = tokio::signal::ctrl_c();
#[cfg(target_arch = "wasm32")]
let interrupt_future = futures::future::pending::<()>();
let _ = interrupt_future.await;
info!("received interrupt - forcing shutdown");
}));
// timeout
wait_futures.push(Box::pin(async move {
sleep(self.max_shutdown_duration).await;
info!("timeout reached, forcing shutdown");
}));
// graceful
wait_futures.push(Box::pin(async move {
self.tracker.wait().await;
debug!("migrated tasks successfully shutdown");
if let Some(legacy) = self.legacy_task_manager.as_mut() {
legacy.wait_for_graceful_shutdown().await;
debug!("legacy tasks successfully shutdown");
}
info!("all registered tasks successfully shutdown")
}));
wait_futures.next().await;
}
pub async fn wait_for_shutdown_signal(mut self) {
self.shutdown_signals.join_next().await;
if let Some(legacy_manager) = self.legacy_task_manager.as_mut() {
info!("attempting to shutdown legacy tasks");
let _ = legacy_manager.signal_shutdown();
}
info!("waiting for tasks to finish... (press ctrl-c to force)");
self.finish_shutdown().await;
}
}
+6 -3
View File
@@ -1,6 +1,7 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
pub mod cancellation;
pub mod connections;
pub mod event;
pub mod manager;
@@ -8,9 +9,11 @@ pub mod manager;
pub mod signal;
pub mod spawn;
pub use cancellation::{ShutdownDropGuard, ShutdownManager, ShutdownToken};
pub use event::{StatusReceiver, StatusSender, TaskStatus, TaskStatusEvent};
pub use manager::{TaskClient, TaskHandle, TaskManager};
#[cfg(not(target_arch = "wasm32"))]
pub use signal::wait_for_signal_and_error;
pub use spawn::{spawn, spawn_with_report_error};
pub use tokio_util::task::TaskTracker;
#[cfg(not(target_arch = "wasm32"))]
pub use signal::{wait_for_signal, wait_for_signal_and_error};
+20
View File
@@ -185,6 +185,19 @@ impl TaskManager {
}
}
// used for compatibility with the ShutdownManager
pub(crate) fn task_return_error_rx(&mut self) -> ErrorReceiver {
self.task_return_error_rx
.take()
.expect("unable to get error channel: attempt to wait twice?")
}
pub(crate) fn task_drop_rx(&mut self) -> ErrorReceiver {
self.task_drop_rx
.take()
.expect("unable to get task drop channel: attempt to wait twice?")
}
pub async fn wait_for_error(&mut self) -> Option<SentError> {
let mut error_rx = self
.task_return_error_rx
@@ -208,6 +221,13 @@ impl TaskManager {
}
}
pub(crate) async fn wait_for_graceful_shutdown(&mut self) {
if let Some(notify_rx) = self.notify_rx.take() {
drop(notify_rx);
}
self.notify_tx.closed().await
}
pub async fn wait_for_shutdown(&mut self) {
log::debug!("Waiting for shutdown");
if let Some(notify_rx) = self.notify_rx.take() {
+28 -53
View File
@@ -6,7 +6,7 @@ use crate::measurements::packet::{EchoPacket, ReplyPacket};
use bytes::{BufMut, BytesMut};
use futures::StreamExt;
use nym_crypto::asymmetric::identity;
use nym_task::TaskClient;
use nym_task::ShutdownToken;
use std::net::SocketAddr;
use std::sync::Arc;
use std::{io, process};
@@ -19,19 +19,19 @@ use tracing::{debug, error, info, trace, warn};
pub struct PacketListener {
address: SocketAddr,
connection_handler: Arc<ConnectionHandler>,
shutdown: TaskClient,
shutdown_token: ShutdownToken,
}
impl PacketListener {
pub fn new(
address: SocketAddr,
identity: Arc<identity::KeyPair>,
shutdown: TaskClient,
shutdown_token: ShutdownToken,
) -> Self {
PacketListener {
address,
connection_handler: Arc::new(ConnectionHandler { identity }),
shutdown,
shutdown_token,
}
}
}
@@ -51,26 +51,22 @@ impl PacketListener {
info!("Started listening for echo packets on {}", self.address);
let mut shutdown_listener = self.shutdown.clone();
while !shutdown_listener.is_shutdown() {
while !self.shutdown_token.is_cancelled() {
// cloning the arc as each accepted socket is handled in separate task
let connection_handler = Arc::clone(&self.connection_handler);
let mut handler_shutdown_listener = self.shutdown.clone();
handler_shutdown_listener.disarm();
tokio::select! {
socket = listener.accept() => {
match socket {
Ok((socket, remote_addr)) => {
debug!("New verloc connection from {}", remote_addr);
tokio::spawn(connection_handler.handle_connection(socket, remote_addr, handler_shutdown_listener));
debug!("New verloc connection from {remote_addr}");
let cancel = self.shutdown_token.child_token(format!("handler_{remote_addr}"));
tokio::spawn(async move { cancel.run_until_cancelled(connection_handler.handle_connection(socket, remote_addr)).await });
}
Err(err) => warn!("Failed to accept incoming connection - {err}"),
}
},
_ = shutdown_listener.recv() => {
_ = self.shutdown_token.cancelled() => {
trace!("PacketListener: Received shutdown");
}
}
@@ -88,50 +84,29 @@ impl ConnectionHandler {
packet.construct_reply(self.identity.private_key())
}
pub(crate) async fn handle_connection(
self: Arc<Self>,
conn: TcpStream,
remote: SocketAddr,
mut shutdown_listener: TaskClient,
) {
debug!("Starting connection handler for {:?}", remote);
pub(crate) async fn handle_connection(self: Arc<Self>, conn: TcpStream, remote: SocketAddr) {
debug!("Starting connection handler for {remote}");
let mut framed_conn = Framed::new(conn, EchoPacketCodec);
while !shutdown_listener.is_shutdown() {
tokio::select! {
biased;
_ = shutdown_listener.recv() => {
trace!("ConnectionHandler: Shutdown received");
while let Some(echo_packet) = framed_conn.next().await {
let reply_packet = match echo_packet {
Ok(echo_packet) => self.handle_echo_packet(echo_packet),
Err(err) => {
debug!(
"The socket connection got corrupted with error: {err}. Closing the socket"
);
return;
}
maybe_echo_packet = framed_conn.next() => {
// handle echo packet
let reply_packet = match maybe_echo_packet {
Some(Ok(echo_packet)) => self.handle_echo_packet(echo_packet),
Some(Err(err)) => {
debug!(
"The socket connection got corrupted with error: {err}. Closing the socket",
);
return;
}
None => {
debug!("The socket connection got terminated by the remote!");
return;
}
};
};
// write back the reply (note the lack of framing)
if let Err(err) = framed_conn
.get_mut()
.write_all(reply_packet.to_bytes().as_ref())
.await
{
debug!(
"Failed to write reply packet back to the sender - {}. Closing the socket on our end",
err
);
return;
}
},
// write back the reply (note the lack of framing)
if let Err(err) = framed_conn
.get_mut()
.write_all(reply_packet.to_bytes().as_ref())
.await
{
debug!("Failed to write reply packet back to the sender: {err}. Closing the socket on our end");
return;
}
}
}
+10 -13
View File
@@ -8,7 +8,7 @@ use crate::models::VerlocNodeResult;
use futures::stream::FuturesUnordered;
use futures::StreamExt;
use nym_crypto::asymmetric::identity;
use nym_task::TaskClient;
use nym_task::ShutdownToken;
use nym_validator_client::models::NymNodeDescription;
use nym_validator_client::NymApiClient;
use rand::prelude::SliceRandom;
@@ -23,7 +23,7 @@ pub struct VerlocMeasurer {
config: Config,
packet_sender: Arc<PacketSender>,
packet_listener: Arc<PacketListener>,
shutdown_listener: TaskClient,
shutdown_token: ShutdownToken,
state: SharedVerlocStats,
}
@@ -31,7 +31,7 @@ impl VerlocMeasurer {
pub fn new(
config: Config,
identity: Arc<identity::KeyPair>,
shutdown_listener: TaskClient,
shutdown_token: ShutdownToken,
) -> Self {
VerlocMeasurer {
packet_sender: Arc::new(PacketSender::new(
@@ -40,14 +40,14 @@ impl VerlocMeasurer {
config.packet_timeout,
config.connection_timeout,
config.delay_between_packets,
shutdown_listener.clone().named("VerlocPacketSender"),
shutdown_token.clone_with_suffix("packet_sender"),
)),
packet_listener: Arc::new(PacketListener::new(
config.listening_address,
Arc::clone(&identity),
shutdown_listener.clone().named("VerlocPacketListener"),
shutdown_token.clone_with_suffix("packet_listener"),
)),
shutdown_listener,
shutdown_token,
config,
state: SharedVerlocStats::default(),
}
@@ -69,9 +69,6 @@ impl VerlocMeasurer {
return MeasurementOutcome::Done;
}
let mut shutdown_listener = self.shutdown_listener.clone().named("VerlocMeasurement");
shutdown_listener.disarm();
for chunk in nodes_to_test.chunks(self.config.tested_nodes_batch_size) {
let mut chunk_results = Vec::with_capacity(chunk.len());
@@ -95,7 +92,7 @@ impl VerlocMeasurer {
.collect::<FuturesUnordered<_>>();
// exhaust the results
while !shutdown_listener.is_shutdown() {
while !self.shutdown_token.is_cancelled() {
tokio::select! {
measurement_result = measurement_chunk.next() => {
let Some(result) = measurement_result else {
@@ -120,7 +117,7 @@ impl VerlocMeasurer {
};
chunk_results.push(VerlocNodeResult::new(identity, measurement_result));
},
_ = shutdown_listener.recv() => {
_ = self.shutdown_token.cancelled() => {
trace!("Shutdown received while measuring");
return MeasurementOutcome::Shutdown;
}
@@ -155,7 +152,7 @@ impl VerlocMeasurer {
pub async fn run(&mut self) {
self.start_listening();
while !self.shutdown_listener.is_shutdown() {
while !self.shutdown_token.is_cancelled() {
info!("Starting verloc measurements");
// TODO: should we also measure gateways?
@@ -209,7 +206,7 @@ impl VerlocMeasurer {
tokio::select! {
_ = sleep(self.config.testing_interval) => {},
_ = self.shutdown_listener.recv() => {
_ = self.shutdown_token.cancelled() => {
trace!("Shutdown received while sleeping");
}
}
+6 -9
View File
@@ -5,7 +5,7 @@ use crate::error::VerlocError;
use crate::measurements::packet::{EchoPacket, ReplyPacket};
use crate::models::VerlocMeasurement;
use nym_crypto::asymmetric::ed25519;
use nym_task::TaskClient;
use nym_task::ShutdownToken;
use rand::{thread_rng, Rng};
use std::net::SocketAddr;
use std::sync::Arc;
@@ -45,7 +45,7 @@ pub struct PacketSender {
packet_timeout: Duration,
connection_timeout: Duration,
delay_between_packets: Duration,
shutdown_listener: TaskClient,
shutdown_token: ShutdownToken,
}
impl PacketSender {
@@ -55,7 +55,7 @@ impl PacketSender {
packet_timeout: Duration,
connection_timeout: Duration,
delay_between_packets: Duration,
shutdown_listener: TaskClient,
shutdown_token: ShutdownToken,
) -> Self {
PacketSender {
identity,
@@ -63,7 +63,7 @@ impl PacketSender {
packet_timeout,
connection_timeout,
delay_between_packets,
shutdown_listener,
shutdown_token,
}
}
@@ -83,9 +83,6 @@ impl PacketSender {
self: Arc<Self>,
tested_node: TestedNode,
) -> Result<VerlocMeasurement, VerlocError> {
let mut shutdown_listener = self.shutdown_listener.fork(tested_node.address.to_string());
shutdown_listener.disarm();
let mut conn = match tokio::time::timeout(
self.connection_timeout,
TcpStream::connect(tested_node.address),
@@ -148,7 +145,7 @@ impl PacketSender {
Ok(Ok(_)) => {}
}
},
_ = shutdown_listener.recv() => {
_ = self.shutdown_token.cancelled() => {
trace!("PacketSender: Received shutdown while sending");
return Err(VerlocError::ShutdownReceived);
},
@@ -190,7 +187,7 @@ impl PacketSender {
}
}
},
_ = shutdown_listener.recv() => {
_ = self.shutdown_token.cancelled() => {
trace!("PacketSender: Received shutdown while waiting for reply");
return Err(VerlocError::ShutdownReceived);
}
@@ -0,0 +1,3 @@
[build]
target = "wasm32-unknown-unknown"
target_arch = "wasm32"
+88 -2
View File
@@ -5,12 +5,15 @@ use crate::error::WasmCoreError;
use crate::storage::wasm_client_traits::WasmClientStorage;
use crate::storage::ClientStorage;
use js_sys::Promise;
use nym_client_core::client::base_client::storage::helpers::set_active_gateway;
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::types::GatewaySelectionSpecification;
use nym_client_core::init::{
self,
self, setup_gateway,
types::{GatewaySetup, InitialisationResult},
};
use nym_sphinx::addressing::clients::Recipient;
@@ -18,7 +21,7 @@ use nym_sphinx::anonymous_replies::requests::AnonymousSenderTag;
use nym_topology::wasm_helpers::WasmFriendlyNymTopology;
use nym_topology::{NymTopology, RoutingNode};
use nym_validator_client::client::IdentityKey;
use nym_validator_client::NymApiClient;
use nym_validator_client::{NymApiClient, UserAgent};
use rand::thread_rng;
use url::Url;
use wasm_bindgen::prelude::wasm_bindgen;
@@ -26,6 +29,7 @@ use wasm_bindgen_futures::future_to_promise;
use wasm_utils::error::PromisableResult;
pub use nym_credential_storage::ephemeral_storage::EphemeralStorage as EphemeralCredentialStorage;
use wasm_utils::console_log;
// don't get too excited about the name, under the hood it's just a big fat placeholder
// with no disk_persistence
@@ -134,6 +138,15 @@ pub async fn setup_gateway_from_api(
setup_gateway_wasm(client_store, force_tls, chosen_gateway, gateways).await
}
pub async fn current_gateways_wasm(
nym_apis: &[Url],
user_agent: Option<UserAgent>,
minimum_performance: u8,
) -> Result<Vec<RoutingNode>, ClientCoreError> {
let mut rng = thread_rng();
current_gateways(&mut rng, nym_apis, user_agent, minimum_performance).await
}
pub async fn setup_from_topology(
explicit_gateway: Option<IdentityKey>,
force_tls: bool,
@@ -143,3 +156,76 @@ pub async fn setup_from_topology(
let gateways = topology.entry_capable_nodes().cloned().collect::<Vec<_>>();
setup_gateway_wasm(client_store, force_tls, explicit_gateway, gateways).await
}
pub async fn generate_new_client_keys(store: &ClientStorage) -> Result<(), WasmCoreError> {
let mut rng = thread_rng();
init::generate_new_client_keys(&mut rng, store).await?;
Ok(())
}
pub async fn add_gateway(
preferred_gateway: Option<IdentityKey>,
latency_based_selection: Option<bool>,
force_tls: bool,
nym_apis: &[Url],
user_agent: UserAgent,
min_performance: u8,
storage: &ClientStorage,
) -> Result<(), WasmCoreError> {
let selection_spec = GatewaySelectionSpecification::new(
preferred_gateway.clone(),
latency_based_selection,
force_tls,
);
let preferred_gateway = preferred_gateway
.as_ref()
.map(|g| g.parse())
.transpose()
.map_err(|source| WasmCoreError::InvalidGatewayIdentity { source })?;
let registered_gateways = storage.all_gateways_identities().await.map_err(|source| {
ClientCoreError::GatewaysDetailsStoreError {
source: Box::new(source),
}
})?;
// if user provided gateway id (and we can't overwrite data), make sure we're not trying to register
// with a known gateway
if let Some(user_chosen) = preferred_gateway {
if registered_gateways.contains(&user_chosen) {
return Err(ClientCoreError::AlreadyRegistered {
gateway_id: user_chosen.to_base58_string(),
}
.into());
}
}
// 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?;
// since we're registering with a brand new gateway,
// make sure the list of available gateways doesn't overlap the list of known gateways
let available_gateways = available_gateways
.into_iter()
.filter(|g| !registered_gateways.contains(&g.identity()))
.collect::<Vec<_>>();
if available_gateways.is_empty() {
return Err(ClientCoreError::NoNewGatewaysAvailable.into());
}
let gateway_setup = GatewaySetup::New {
specification: selection_spec,
available_gateways,
};
let init_details = setup_gateway(gateway_setup, storage, storage).await?;
let gateway = init_details.gateway_id().to_base58_string();
set_active_gateway(storage, &gateway).await?;
console_log!("finished registration with gateway {gateway}");
Ok(())
}
@@ -128,8 +128,12 @@ impl GatewaysDetailsStore for ClientStorage {
}
async fn all_gateways(&self) -> Result<Vec<GatewayRegistration>, Self::StorageError> {
todo!()
// let identities = self.all
let identities = self.registered_gateways().await?;
let mut registered = Vec::with_capacity(identities.len());
for gateway_id in identities {
registered.push(self.load_gateway_details(&gateway_id).await?);
}
Ok(registered)
}
async fn has_gateway_details(&self, gateway_id: &str) -> Result<bool, Self::StorageError> {
@@ -59,6 +59,8 @@ impl ClientStorage {
db.create_object_store(v2::GATEWAY_REGISTRATIONS_ACTIVE_GATEWAY_STORE)?;
db.create_object_store(v2::GATEWAY_REGISTRATIONS_REGISTERED_GATEWAYS_STORE)?;
return Ok(());
}
// version 1 -> unimplemented migration
@@ -119,6 +119,15 @@ pub trait WasmClientStorage: BaseWasmStorage {
.map_err(Into::into)
}
async fn has_identity_key(&self) -> Result<bool, <Self as WasmClientStorage>::StorageError> {
self.has_value(
v1::KEYS_STORE,
JsValue::from_str(v1::ED25519_IDENTITY_KEYPAIR),
)
.await
.map_err(Into::into)
}
async fn store_identity_keypair(
&self,
keypair: &identity::KeyPair,
+3
View File
@@ -0,0 +1,3 @@
[build]
target = "wasm32-unknown-unknown"
target_arch = "wasm32"
+3
View File
@@ -0,0 +1,3 @@
[build]
target = "wasm32-unknown-unknown"
target_arch = "wasm32"
+18 -9
View File
@@ -267,18 +267,27 @@ impl PeerController {
}))
}
fn update_metrics(&self, new_host: &Host) {
async fn update_metrics(&self, new_host: &Host) {
let now = SystemTime::now();
const ACTIVITY_THRESHOLD: Duration = Duration::from_secs(60);
let old_host = self.host_information.read().await;
let total_peers = new_host.peers.len();
let mut active_peers = 0;
let mut total_rx = 0;
let mut total_tx = 0;
let mut new_rx = 0;
let mut new_tx = 0;
for peer in new_host.peers.values() {
total_rx += peer.rx_bytes;
total_tx += peer.tx_bytes;
for (peer_key, peer) in new_host.peers.iter() {
// only consider pre-existing peers,
// so that the value would always be increasing
if let Some(prior) = old_host.peers.get(peer_key) {
let delta_rx = peer.rx_bytes.saturating_sub(prior.rx_bytes);
let delta_tx = prior.tx_bytes.saturating_sub(prior.tx_bytes);
new_rx += delta_rx;
new_tx += delta_tx;
}
// if a peer hasn't performed a handshake in last minute,
// I think it's reasonable to assume it's no longer active
@@ -296,10 +305,10 @@ impl PeerController {
self.metrics.wireguard.update(
// if the conversion fails it means we're running not running on a 64bit system
// and that's a reason enough for this failure.
total_rx.try_into().expect(
new_rx.try_into().expect(
"failed to convert bytes from u64 to usize - are you running on non 64bit system?",
),
total_tx.try_into().expect(
new_tx.try_into().expect(
"failed to convert bytes from u64 to usize - are you running on non 64bit system?",
),
total_peers,
@@ -316,7 +325,7 @@ impl PeerController {
log::error!("Can't read wireguard kernel data");
continue;
};
self.update_metrics(&host);
self.update_metrics(&host).await;
*self.host_information.write().await = host;
}
+11 -11
View File
@@ -1,6 +1,6 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
version = 4
[[package]]
name = "aes"
@@ -1699,18 +1699,18 @@ dependencies = [
[[package]]
name = "semver"
version = "1.0.23"
version = "1.0.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b"
checksum = "3cb6eb87a131f756572d7fb904f6e7b68633f09cca868c5df1c4b8d1a694bbba"
dependencies = [
"serde",
]
[[package]]
name = "serde"
version = "1.0.214"
version = "1.0.217"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f55c3193aca71c12ad7890f1785d2b73e1b9f63a0bbc353c08ef26fe03fc56b5"
checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70"
dependencies = [
"serde_derive",
]
@@ -1735,9 +1735,9 @@ dependencies = [
[[package]]
name = "serde_derive"
version = "1.0.214"
version = "1.0.217"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de523f781f095e28fa605cdce0f8307e451cc0fd14e2eb4cd2e98a355b147766"
checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0"
dependencies = [
"proc-macro2",
"quote",
@@ -1965,9 +1965,9 @@ dependencies = [
[[package]]
name = "time"
version = "0.3.36"
version = "0.3.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885"
checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21"
dependencies = [
"deranged",
"itoa",
@@ -1988,9 +1988,9 @@ checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3"
[[package]]
name = "time-macros"
version = "0.2.18"
version = "0.2.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf"
checksum = "2834e6017e3e5e4b9834939793b282bc03b37a3336245fa820e35e233e2a85de"
dependencies = [
"num-conv",
"time-core",
@@ -464,10 +464,7 @@ pub fn instantiate_contracts(
mixnet_contract_address.clone(),
&nym_mixnet_contract_common::MigrateMsg {
vesting_contract_address: Some(vesting_contract_address.to_string()),
current_nym_node_semver: "1.1.10".to_string(),
version_score_weights: Default::default(),
unsafe_skip_state_updates: Some(true),
version_score_params: Default::default(),
},
mixnet_code_id,
)
@@ -3470,43 +3470,13 @@
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "MigrateMsg",
"type": "object",
"required": [
"current_nym_node_semver"
],
"properties": {
"current_nym_node_semver": {
"type": "string"
},
"unsafe_skip_state_updates": {
"type": [
"boolean",
"null"
]
},
"version_score_params": {
"default": {
"penalty": "0.995",
"penalty_scaling": "1.65"
},
"allOf": [
{
"$ref": "#/definitions/VersionScoreFormulaParams"
}
]
},
"version_score_weights": {
"default": {
"major": 100,
"minor": 10,
"patch": 1,
"prerelease": 1
},
"allOf": [
{
"$ref": "#/definitions/OutdatedVersionWeights"
}
]
},
"vesting_contract_address": {
"type": [
"string",
@@ -3514,63 +3484,7 @@
]
}
},
"additionalProperties": false,
"definitions": {
"Decimal": {
"description": "A fixed-point decimal value with 18 fractional digits, i.e. Decimal(1_000_000_000_000_000_000) == 1.0\n\nThe greatest possible value that can be represented is 340282366920938463463.374607431768211455 (which is (2^128 - 1) / 10^18)",
"type": "string"
},
"OutdatedVersionWeights": {
"description": "Defines weights for calculating numbers of versions behind the current release.",
"type": "object",
"required": [
"major",
"minor",
"patch",
"prerelease"
],
"properties": {
"major": {
"type": "integer",
"format": "uint32",
"minimum": 0.0
},
"minor": {
"type": "integer",
"format": "uint32",
"minimum": 0.0
},
"patch": {
"type": "integer",
"format": "uint32",
"minimum": 0.0
},
"prerelease": {
"type": "integer",
"format": "uint32",
"minimum": 0.0
}
},
"additionalProperties": false
},
"VersionScoreFormulaParams": {
"description": "Given the formula of version_score = penalty ^ (versions_behind_factor ^ penalty_scaling) define the relevant parameters",
"type": "object",
"required": [
"penalty",
"penalty_scaling"
],
"properties": {
"penalty": {
"$ref": "#/definitions/Decimal"
},
"penalty_scaling": {
"$ref": "#/definitions/Decimal"
}
},
"additionalProperties": false
}
}
"additionalProperties": false
},
"sudo": null,
"responses": {
+1 -87
View File
@@ -2,43 +2,13 @@
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "MigrateMsg",
"type": "object",
"required": [
"current_nym_node_semver"
],
"properties": {
"current_nym_node_semver": {
"type": "string"
},
"unsafe_skip_state_updates": {
"type": [
"boolean",
"null"
]
},
"version_score_params": {
"default": {
"penalty": "0.995",
"penalty_scaling": "1.65"
},
"allOf": [
{
"$ref": "#/definitions/VersionScoreFormulaParams"
}
]
},
"version_score_weights": {
"default": {
"major": 100,
"minor": 10,
"patch": 1,
"prerelease": 1
},
"allOf": [
{
"$ref": "#/definitions/OutdatedVersionWeights"
}
]
},
"vesting_contract_address": {
"type": [
"string",
@@ -46,61 +16,5 @@
]
}
},
"additionalProperties": false,
"definitions": {
"Decimal": {
"description": "A fixed-point decimal value with 18 fractional digits, i.e. Decimal(1_000_000_000_000_000_000) == 1.0\n\nThe greatest possible value that can be represented is 340282366920938463463.374607431768211455 (which is (2^128 - 1) / 10^18)",
"type": "string"
},
"OutdatedVersionWeights": {
"description": "Defines weights for calculating numbers of versions behind the current release.",
"type": "object",
"required": [
"major",
"minor",
"patch",
"prerelease"
],
"properties": {
"major": {
"type": "integer",
"format": "uint32",
"minimum": 0.0
},
"minor": {
"type": "integer",
"format": "uint32",
"minimum": 0.0
},
"patch": {
"type": "integer",
"format": "uint32",
"minimum": 0.0
},
"prerelease": {
"type": "integer",
"format": "uint32",
"minimum": 0.0
}
},
"additionalProperties": false
},
"VersionScoreFormulaParams": {
"description": "Given the formula of version_score = penalty ^ (versions_behind_factor ^ penalty_scaling) define the relevant parameters",
"type": "object",
"required": [
"penalty",
"penalty_scaling"
],
"properties": {
"penalty": {
"$ref": "#/definitions/Decimal"
},
"penalty_scaling": {
"$ref": "#/definitions/Decimal"
}
},
"additionalProperties": false
}
}
"additionalProperties": false
}
+7 -7
View File
@@ -602,18 +602,18 @@ pub fn query(
#[entry_point]
pub fn migrate(
mut deps: DepsMut<'_>,
env: Env,
deps: DepsMut<'_>,
_env: Env,
msg: MigrateMsg,
) -> Result<Response, MixnetContractError> {
set_build_information!(deps.storage)?;
cw2::ensure_from_older_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?;
let skip_state_updates = msg.unsafe_skip_state_updates.unwrap_or(false);
if !skip_state_updates {
crate::queued_migrations::add_config_score_params(deps.branch(), env, &msg)?;
}
// let skip_state_updates = msg.unsafe_skip_state_updates.unwrap_or(false);
//
// if !skip_state_updates {
//
// }
// due to circular dependency on contract addresses (i.e. mixnet contract requiring vesting contract address
// and vesting contract requiring the mixnet contract address), if we ever want to deploy any new fresh
@@ -34,9 +34,13 @@ impl NymNodeVersionHistory<'_> {
}
fn next_id(&self, storage: &mut dyn Storage) -> Result<u32, MixnetContractError> {
let next = self.id_counter.may_load(storage)?.unwrap_or_default();
self.id_counter.save(storage, &next)?;
Ok(next)
let id = self
.id_counter
.may_load(storage)?
.map(|current| current + 1)
.unwrap_or_default();
self.id_counter.save(storage, &id)?;
Ok(id)
}
pub fn current_version(
@@ -56,10 +60,10 @@ impl NymNodeVersionHistory<'_> {
pub fn insert_new(
&self,
storage: &mut dyn Storage,
entry: HistoricalNymNodeVersion,
entry: &HistoricalNymNodeVersion,
) -> Result<u32, MixnetContractError> {
let next_id = self.next_id(storage)?;
self.version_history.save(storage, next_id, &entry)?;
self.version_history.save(storage, next_id, entry)?;
Ok(next_id)
}
@@ -79,7 +83,7 @@ impl NymNodeVersionHistory<'_> {
// treat this as genesis
let genesis =
HistoricalNymNodeVersion::genesis(raw_semver.to_string(), env.block.height);
return self.insert_new(storage, genesis);
return self.insert_new(storage, &genesis);
};
let current_semver = current.version_information.semver_unchecked();
@@ -99,7 +103,7 @@ impl NymNodeVersionHistory<'_> {
introduced_at_height: env.block.height,
difference_since_genesis: diff,
};
self.insert_new(storage, entry)
self.insert_new(storage, &entry)
}
}
@@ -170,3 +174,218 @@ pub(crate) fn initialise_storage(
ADMIN.set(deps, Some(initial_admin))?;
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[cfg(test)]
mod nym_node_version_history {
use super::*;
use crate::support::tests::test_helpers::TestSetup;
use cosmwasm_std::testing::{mock_dependencies, mock_env};
#[test]
fn getting_current() -> anyhow::Result<()> {
// empty storage
let deps = mock_dependencies();
let storage = NymNodeVersionHistory::new();
assert!(storage.current_version(&deps.storage)?.is_none());
let mut test = TestSetup::new();
let zeroth = storage.current_version(test.storage())?.unwrap();
let manual_zeroth = storage.version_history.load(test.storage(), 0)?;
assert_eq!(zeroth.version_information, manual_zeroth);
// manually update the counter to make sure data is still read correctly
let dummy = HistoricalNymNodeVersion {
semver: "1.2.3".to_string(),
introduced_at_height: 1234,
difference_since_genesis: Default::default(),
};
storage.id_counter.save(test.storage_mut(), &123)?;
storage
.version_history
.save(test.storage_mut(), 123, &dummy)?;
let updated = storage.current_version(test.storage())?.unwrap();
assert_eq!(updated.version_information, dummy);
Ok(())
}
#[test]
fn inserting_new_entry() -> anyhow::Result<()> {
let mut test = TestSetup::new();
let storage = NymNodeVersionHistory::new();
let first = HistoricalNymNodeVersion {
semver: "1.1.1".to_string(),
introduced_at_height: 12,
difference_since_genesis: Default::default(),
};
let second = HistoricalNymNodeVersion {
semver: "1.1.2".to_string(),
introduced_at_height: 123,
difference_since_genesis: Default::default(),
};
let third = HistoricalNymNodeVersion {
semver: "1.1.3".to_string(),
introduced_at_height: 1234,
difference_since_genesis: Default::default(),
};
assert_eq!(storage.id_counter.load(test.storage())?, 0);
// id is correctly incremented for each case and no entry is overwritten
storage.insert_new(test.storage_mut(), &first)?;
assert_eq!(storage.id_counter.load(test.storage())?, 1);
storage.insert_new(test.storage_mut(), &second)?;
assert_eq!(storage.id_counter.load(test.storage())?, 2);
storage.insert_new(test.storage_mut(), &third)?;
assert_eq!(storage.id_counter.load(test.storage())?, 3);
assert_eq!(storage.version_history.load(test.storage(), 1)?, first);
assert_eq!(storage.version_history.load(test.storage(), 2)?, second);
assert_eq!(storage.version_history.load(test.storage(), 3)?, third);
Ok(())
}
#[test]
fn inserting_initial_semver() -> anyhow::Result<()> {
// empty storage
let mut deps = mock_dependencies();
let env = mock_env();
let storage = NymNodeVersionHistory::new();
assert!(storage
.id_counter
.may_load(deps.as_mut().storage)?
.is_none());
storage.try_insert_new(deps.as_mut().storage, &env, "1.1.1")?;
assert_eq!(storage.id_counter.load(deps.as_mut().storage)?, 0);
assert_eq!(
storage
.version_history
.load(deps.as_ref().storage, 0)?
.semver,
"1.1.1"
);
assert_eq!(
storage
.current_version(deps.as_ref().storage)?
.unwrap()
.version_information
.semver,
"1.1.1"
);
Ok(())
}
#[test]
fn inserting_second_semver() -> anyhow::Result<()> {
let mut test = TestSetup::new();
let env = test.env();
let storage = NymNodeVersionHistory::new();
// lower version
assert!(storage
.try_insert_new(test.storage_mut(), &env, "1.1.9")
.is_err());
assert!(storage
.try_insert_new(test.storage_mut(), &env, "1.0.1")
.is_err());
// malformed
assert!(storage
.try_insert_new(test.storage_mut(), &env, "1.0")
.is_err());
assert!(storage
.try_insert_new(test.storage_mut(), &env, "1.0bad")
.is_err());
assert!(storage
.try_insert_new(test.storage_mut(), &env, "foomp")
.is_err());
// patch
let mut test = TestSetup::new();
storage.try_insert_new(test.storage_mut(), &env, "1.1.11")?;
let current = storage
.current_version(test.storage_mut())?
.unwrap()
.version_information;
assert_eq!(current.semver, "1.1.11");
assert_eq!(current.difference_since_genesis.major, 0);
assert_eq!(current.difference_since_genesis.minor, 0);
assert_eq!(current.difference_since_genesis.patch, 1);
assert_eq!(current.difference_since_genesis.prerelease, 0);
// minor
let mut test = TestSetup::new();
storage.try_insert_new(test.storage_mut(), &env, "1.2.0")?;
let current = storage
.current_version(test.storage_mut())?
.unwrap()
.version_information;
assert_eq!(current.semver, "1.2.0");
assert_eq!(current.difference_since_genesis.major, 0);
assert_eq!(current.difference_since_genesis.minor, 1);
assert_eq!(current.difference_since_genesis.patch, 0);
assert_eq!(current.difference_since_genesis.prerelease, 0);
// minor alt.
let mut test = TestSetup::new();
storage.try_insert_new(test.storage_mut(), &env, "1.2.3")?;
let current = storage
.current_version(test.storage_mut())?
.unwrap()
.version_information;
assert_eq!(current.semver, "1.2.3");
assert_eq!(current.difference_since_genesis.major, 0);
assert_eq!(current.difference_since_genesis.minor, 1);
assert_eq!(current.difference_since_genesis.patch, 0);
assert_eq!(current.difference_since_genesis.prerelease, 0);
Ok(())
}
#[test]
fn inserting_subsequent_semver() -> anyhow::Result<()> {
let mut test = TestSetup::new();
let env = test.env();
let storage = NymNodeVersionHistory::new();
storage.try_insert_new(test.storage_mut(), &env, "1.2.0")?;
storage.try_insert_new(test.storage_mut(), &env, "1.2.1")?;
storage.try_insert_new(test.storage_mut(), &env, "1.2.3")?;
let current = storage
.current_version(test.storage_mut())?
.unwrap()
.version_information;
assert_eq!(current.semver, "1.2.3");
assert_eq!(current.difference_since_genesis.major, 0);
assert_eq!(current.difference_since_genesis.minor, 1);
assert_eq!(current.difference_since_genesis.patch, 3);
assert_eq!(current.difference_since_genesis.prerelease, 0);
storage.try_insert_new(test.storage_mut(), &env, "1.3.0")?;
let current = storage
.current_version(test.storage_mut())?
.unwrap()
.version_information;
assert_eq!(current.semver, "1.3.0");
assert_eq!(current.difference_since_genesis.major, 0);
assert_eq!(current.difference_since_genesis.minor, 2);
assert_eq!(current.difference_since_genesis.patch, 3);
assert_eq!(current.difference_since_genesis.prerelease, 0);
Ok(())
}
}
}
@@ -238,4 +238,446 @@ pub mod tests {
// let res = try_update_contract_settings(deps.as_mut(), info, new_params);
// assert_eq!(Err(MixnetContractError::ZeroActiveSet), res);
}
#[cfg(test)]
mod updating_current_nym_node_semver {
use super::*;
use crate::mixnet_contract_settings::queries::query_current_nym_node_version;
use crate::support::tests::test_helpers::TestSetup;
#[test]
fn is_restricted_to_the_admin() -> anyhow::Result<()> {
let mut test = TestSetup::new();
let not_admin = mock_info("not-admin", &[]);
let admin = mock_info(test.admin().as_ref(), &[]);
let env = test.env();
let res = try_update_current_nym_node_semver(
test.deps_mut(),
env,
not_admin,
"1.2.1".to_string(),
);
assert!(res.is_err());
let env = test.env();
let res = try_update_current_nym_node_semver(
test.deps_mut(),
env,
admin,
"1.2.1".to_string(),
);
assert!(res.is_ok());
Ok(())
}
#[test]
fn updates_current_semver_value() -> anyhow::Result<()> {
let mut test = TestSetup::new();
let res = query_current_nym_node_version(test.deps())?;
let initial = res.version.unwrap().version_information.semver;
// sanity check to make sure our contract init hasn't changed
assert_eq!(initial, "1.1.10");
let update = "1.2.0".to_string();
let env = test.env();
let sender = test.admin_sender();
try_update_current_nym_node_semver(test.deps_mut(), env, sender, update.clone())?;
let updated = query_current_nym_node_version(test.deps())?;
let version = updated.version.unwrap().version_information.semver;
assert_eq!(version, update);
Ok(())
}
#[cfg(test)]
mod semver_chain_updates {
use super::*;
use crate::mixnet_contract_settings::queries::query_nym_node_version_history_paged;
use mixnet_contract_common::{
HistoricalNymNodeVersion, HistoricalNymNodeVersionEntry, TotalVersionDifference,
};
fn test_setup_with_initial_checks() -> anyhow::Result<TestSetup> {
let test = TestSetup::new();
let res = query_current_nym_node_version(test.deps())?;
let initial = res.version.unwrap().version_information.semver;
// sanity check to make sure our contract init hasn't changed
assert_eq!(initial, "1.1.10");
let history = query_nym_node_version_history_paged(test.deps(), None, None)?;
assert_eq!(history.history.len(), 1);
Ok(test)
}
#[test]
fn single_patch() -> anyhow::Result<()> {
let mut test = test_setup_with_initial_checks()?;
let initial = query_current_nym_node_version(test.deps())?
.version
.unwrap();
let env = test.env();
let sender = test.admin_sender();
try_update_current_nym_node_semver(
test.deps_mut(),
env.clone(),
sender,
"1.1.11".to_string(),
)?;
let history =
query_nym_node_version_history_paged(test.deps(), None, None)?.history;
assert_eq!(history.len(), 2);
assert_eq!(history[0], initial);
assert_eq!(
history[1],
HistoricalNymNodeVersionEntry {
id: 1,
version_information: HistoricalNymNodeVersion {
semver: "1.1.11".to_string(),
introduced_at_height: env.block.height,
difference_since_genesis: TotalVersionDifference {
major: 0,
minor: 0,
patch: 1,
prerelease: 0,
},
},
}
);
Ok(())
}
#[test]
fn single_minor() -> anyhow::Result<()> {
let mut test = test_setup_with_initial_checks()?;
let initial = query_current_nym_node_version(test.deps())?
.version
.unwrap();
let env = test.env();
let sender = test.admin_sender();
try_update_current_nym_node_semver(
test.deps_mut(),
env.clone(),
sender,
"1.2.0".to_string(),
)?;
let history =
query_nym_node_version_history_paged(test.deps(), None, None)?.history;
assert_eq!(history.len(), 2);
assert_eq!(history[0], initial);
assert_eq!(
history[1],
HistoricalNymNodeVersionEntry {
id: 1,
version_information: HistoricalNymNodeVersion {
semver: "1.2.0".to_string(),
introduced_at_height: env.block.height,
difference_since_genesis: TotalVersionDifference {
major: 0,
minor: 1,
patch: 0,
prerelease: 0,
},
},
}
);
Ok(())
}
#[test]
fn multiple_patches() -> anyhow::Result<()> {
let mut test = test_setup_with_initial_checks()?;
let initial = query_current_nym_node_version(test.deps())?
.version
.unwrap();
let mut env = test.env();
let sender = test.admin_sender();
try_update_current_nym_node_semver(
test.deps_mut(),
env.clone(),
sender.clone(),
"1.1.11".to_string(),
)?;
env.block.height += 1;
try_update_current_nym_node_semver(
test.deps_mut(),
env.clone(),
sender.clone(),
"1.1.12".to_string(),
)?;
env.block.height += 1;
try_update_current_nym_node_semver(
test.deps_mut(),
env.clone(),
sender,
"1.1.13".to_string(),
)?;
let history =
query_nym_node_version_history_paged(test.deps(), None, None)?.history;
assert_eq!(history.len(), 4);
assert_eq!(history[0], initial);
assert_eq!(
history[1],
HistoricalNymNodeVersionEntry {
id: 1,
version_information: HistoricalNymNodeVersion {
semver: "1.1.11".to_string(),
introduced_at_height: env.block.height - 2,
difference_since_genesis: TotalVersionDifference {
major: 0,
minor: 0,
patch: 1,
prerelease: 0,
},
},
}
);
assert_eq!(
history[2],
HistoricalNymNodeVersionEntry {
id: 2,
version_information: HistoricalNymNodeVersion {
semver: "1.1.12".to_string(),
introduced_at_height: env.block.height - 1,
difference_since_genesis: TotalVersionDifference {
major: 0,
minor: 0,
patch: 2,
prerelease: 0,
},
},
}
);
assert_eq!(
history[3],
HistoricalNymNodeVersionEntry {
id: 3,
version_information: HistoricalNymNodeVersion {
semver: "1.1.13".to_string(),
introduced_at_height: env.block.height,
difference_since_genesis: TotalVersionDifference {
major: 0,
minor: 0,
patch: 3,
prerelease: 0,
},
},
}
);
Ok(())
}
#[test]
fn multiple_minors() -> anyhow::Result<()> {
let mut test = test_setup_with_initial_checks()?;
let initial = query_current_nym_node_version(test.deps())?
.version
.unwrap();
let mut env = test.env();
let sender = test.admin_sender();
try_update_current_nym_node_semver(
test.deps_mut(),
env.clone(),
sender.clone(),
"1.2.0".to_string(),
)?;
env.block.height += 1;
try_update_current_nym_node_semver(
test.deps_mut(),
env.clone(),
sender.clone(),
"1.3.0".to_string(),
)?;
env.block.height += 1;
try_update_current_nym_node_semver(
test.deps_mut(),
env.clone(),
sender,
"1.4.0".to_string(),
)?;
let history =
query_nym_node_version_history_paged(test.deps(), None, None)?.history;
assert_eq!(history.len(), 4);
assert_eq!(history[0], initial);
assert_eq!(
history[1],
HistoricalNymNodeVersionEntry {
id: 1,
version_information: HistoricalNymNodeVersion {
semver: "1.2.0".to_string(),
introduced_at_height: env.block.height - 2,
difference_since_genesis: TotalVersionDifference {
major: 0,
minor: 1,
patch: 0,
prerelease: 0,
},
},
}
);
assert_eq!(
history[2],
HistoricalNymNodeVersionEntry {
id: 2,
version_information: HistoricalNymNodeVersion {
semver: "1.3.0".to_string(),
introduced_at_height: env.block.height - 1,
difference_since_genesis: TotalVersionDifference {
major: 0,
minor: 2,
patch: 0,
prerelease: 0,
},
},
}
);
assert_eq!(
history[3],
HistoricalNymNodeVersionEntry {
id: 3,
version_information: HistoricalNymNodeVersion {
semver: "1.4.0".to_string(),
introduced_at_height: env.block.height,
difference_since_genesis: TotalVersionDifference {
major: 0,
minor: 3,
patch: 0,
prerelease: 0,
},
},
}
);
Ok(())
}
#[test]
fn mixed_multiple_updates() -> anyhow::Result<()> {
let mut test = test_setup_with_initial_checks()?;
let initial = query_current_nym_node_version(test.deps())?
.version
.unwrap();
let mut env = test.env();
let sender = test.admin_sender();
try_update_current_nym_node_semver(
test.deps_mut(),
env.clone(),
sender.clone(),
"1.2.0".to_string(),
)?;
env.block.height += 1;
try_update_current_nym_node_semver(
test.deps_mut(),
env.clone(),
sender.clone(),
"1.2.1".to_string(),
)?;
env.block.height += 1;
try_update_current_nym_node_semver(
test.deps_mut(),
env.clone(),
sender.clone(),
"1.2.3".to_string(),
)?;
env.block.height += 1;
try_update_current_nym_node_semver(
test.deps_mut(),
env.clone(),
sender,
"1.3.0".to_string(),
)?;
let history =
query_nym_node_version_history_paged(test.deps(), None, None)?.history;
assert_eq!(history.len(), 5);
assert_eq!(history[0], initial);
assert_eq!(
history[1],
HistoricalNymNodeVersionEntry {
id: 1,
version_information: HistoricalNymNodeVersion {
semver: "1.2.0".to_string(),
introduced_at_height: env.block.height - 3,
difference_since_genesis: TotalVersionDifference {
major: 0,
minor: 1,
patch: 0,
prerelease: 0,
},
},
}
);
assert_eq!(
history[2],
HistoricalNymNodeVersionEntry {
id: 2,
version_information: HistoricalNymNodeVersion {
semver: "1.2.1".to_string(),
introduced_at_height: env.block.height - 2,
difference_since_genesis: TotalVersionDifference {
major: 0,
minor: 1,
patch: 1,
prerelease: 0,
},
},
}
);
assert_eq!(
history[3],
HistoricalNymNodeVersionEntry {
id: 3,
version_information: HistoricalNymNodeVersion {
semver: "1.2.3".to_string(),
introduced_at_height: env.block.height - 1,
difference_since_genesis: TotalVersionDifference {
major: 0,
minor: 1,
patch: 3,
prerelease: 0,
},
},
}
);
assert_eq!(
history[4],
HistoricalNymNodeVersionEntry {
id: 4,
version_information: HistoricalNymNodeVersion {
semver: "1.3.0".to_string(),
introduced_at_height: env.block.height,
difference_since_genesis: TotalVersionDifference {
major: 0,
minor: 2,
patch: 3,
prerelease: 0,
},
},
}
);
Ok(())
}
}
}
}
-84
View File
@@ -1,86 +1,2 @@
// Copyright 2022-2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
mod config_score_params {
use crate::constants::CONTRACT_STATE_KEY;
use crate::mixnet_contract_settings::storage as mixnet_params_storage;
use crate::mixnet_contract_settings::storage::NymNodeVersionHistory;
use cosmwasm_std::{Addr, Coin, DepsMut, Env};
use cw_storage_plus::Item;
use mixnet_contract_common::error::MixnetContractError;
use mixnet_contract_common::{
ConfigScoreParams, ContractState, ContractStateParams, DelegationsParams, MigrateMsg,
OperatingCostRange, OperatorsParams, ProfitMarginRange,
};
use serde::{Deserialize, Serialize};
use std::str::FromStr;
pub(crate) fn add_config_score_params(
deps: DepsMut<'_>,
env: Env,
msg: &MigrateMsg,
) -> Result<(), MixnetContractError> {
if semver::Version::from_str(&msg.current_nym_node_semver).is_err() {
return Err(MixnetContractError::InvalidNymNodeSemver {
provided: msg.current_nym_node_semver.to_string(),
});
}
#[derive(Serialize, Deserialize)]
pub struct OldContractState {
pub owner: Option<Addr>,
pub rewarding_validator_address: Addr,
pub vesting_contract_address: Addr,
pub rewarding_denom: String,
pub params: OldContractStateParams,
}
#[derive(Serialize, Deserialize)]
pub struct OldContractStateParams {
pub minimum_delegation: Option<Coin>,
pub minimum_pledge: Coin,
#[serde(default)]
pub profit_margin: ProfitMarginRange,
#[serde(default)]
pub interval_operating_cost: OperatingCostRange,
}
const OLD_CONTRACT_STATE: Item<'_, OldContractState> = Item::new(CONTRACT_STATE_KEY);
let old_state = OLD_CONTRACT_STATE.load(deps.storage)?;
#[allow(deprecated)]
let new_state = ContractState {
owner: old_state.owner,
rewarding_validator_address: old_state.rewarding_validator_address,
vesting_contract_address: old_state.vesting_contract_address,
rewarding_denom: old_state.rewarding_denom,
params: ContractStateParams {
delegations_params: DelegationsParams {
minimum_delegation: old_state.params.minimum_delegation,
},
operators_params: OperatorsParams {
minimum_pledge: old_state.params.minimum_pledge,
profit_margin: old_state.params.profit_margin,
interval_operating_cost: old_state.params.interval_operating_cost,
},
config_score_params: ConfigScoreParams {
version_weights: msg.version_score_weights,
version_score_formula_params: msg.version_score_params,
},
},
};
mixnet_params_storage::CONTRACT_STATE.save(deps.storage, &new_state)?;
// initialise the version chain
NymNodeVersionHistory::new().try_insert_new(
deps.storage,
&env,
&msg.current_nym_node_semver,
)?;
Ok(())
}
}
pub(crate) use config_score_params::add_config_score_params;
+17 -1
View File
@@ -18,7 +18,7 @@ pub mod test_helpers {
};
use crate::interval::{pending_events, storage as interval_storage};
use crate::mixnet_contract_settings::storage::{
self as mixnet_params_storage, minimum_node_pledge,
self as mixnet_params_storage, minimum_node_pledge, ADMIN,
};
use crate::mixnet_contract_settings::storage::{rewarding_denom, rewarding_validator_address};
use crate::mixnodes::helpers::get_mixnode_details_by_id;
@@ -318,6 +318,10 @@ pub mod test_helpers {
compare_decimals(mix_info.delegates, subtotal, Some(epsilon))
}
pub fn admin(&self) -> Addr {
ADMIN.get(self.deps()).unwrap().unwrap()
}
pub fn random_address(&mut self) -> String {
format!("n1foomp{}", self.rng.next_u64())
}
@@ -330,6 +334,14 @@ pub mod test_helpers {
self.deps.as_mut()
}
pub fn storage(&self) -> &dyn Storage {
self.deps().storage
}
pub fn storage_mut(&mut self) -> &mut dyn Storage {
self.deps_mut().storage
}
pub fn env(&self) -> Env {
self.env.clone()
}
@@ -470,6 +482,10 @@ pub mod test_helpers {
.unwrap()
}
pub fn admin_sender(&self) -> MessageInfo {
mock_info(self.admin().as_ref(), &[])
}
pub fn owner(&self) -> MessageInfo {
self.owner.clone()
}
+1 -1
View File
@@ -9,5 +9,5 @@ edition.workspace = true
license.workspace = true
[dependencies]
env_logger = "0.11.3"
env_logger = "0.11.6"
log.workspace = true
+3 -2
View File
@@ -2,7 +2,7 @@
This is v2 of the nym docs, condensed from various mdbooks projects that we had previously.
These docs are hosted at [nymtech.net/docs](www.nymtech.net/docs).
These docs are hosted at [nym.com/docs](https://nym.com/docs).
## Doc projects
`docs/pages/` contains several subdirs, each hosting a subsection of the docs:
@@ -11,6 +11,7 @@ These docs are hosted at [nymtech.net/docs](www.nymtech.net/docs).
* `operators` contains node setup and maintenance guides.
## Local development
### Dependencies
Our `prebuild` script relies on the following:
- `python`
@@ -54,7 +55,7 @@ This is a monorepo and components that make up Nym as a system are licensed indi
As a general approach, licensing is as follows this pattern:
* <p xmlns:cc="http://creativecommons.org/ns#" xmlns:dct="http://purl.org/dc/terms/"><a property="dct:title" rel="cc:attributionURL" href="https://nymtech.net/docs">Nym Documentation</a> by <a rel="cc:attributionURL dct:creator" property="cc:attributionName" href="https://nymtech.net">Nym Technologies</a> is licensed under <a href="http://creativecommons.org/licenses/by-nc-sa/4.0/?ref=chooser-v1" target="_blank" rel="license noopener noreferrer" style="display:inline-block;">CC BY-NC-SA 4.0<img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;" src="https://mirrors.creativecommons.org/presskit/icons/cc.svg?ref=chooser-v1"><img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;" src="https://mirrors.creativecommons.org/presskit/icons/by.svg?ref=chooser-v1"><img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;" src="https://mirrors.creativecommons.org/presskit/icons/nc.svg?ref=chooser-v1"><img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;" src="https://mirrors.creativecommons.org/presskit/icons/sa.svg?ref=chooser-v1"></a></p>
* <p xmlns:cc="http://creativecommons.org/ns#" xmlns:dct="http://purl.org/dc/terms/"><a property="dct:title" rel="cc:attributionURL" href="https://nym.com/docs">Nym Documentation</a> by <a rel="cc:attributionURL dct:creator" property="cc:attributionName" href="https://nym.com">Nym Technologies</a> is licensed under <a href="http://creativecommons.org/licenses/by-nc-sa/4.0/?ref=chooser-v1" target="_blank" rel="license noopener noreferrer" style="display:inline-block;">CC BY-NC-SA 4.0<img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;" src="https://mirrors.creativecommons.org/presskit/icons/cc.svg?ref=chooser-v1"><img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;" src="https://mirrors.creativecommons.org/presskit/icons/by.svg?ref=chooser-v1"><img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;" src="https://mirrors.creativecommons.org/presskit/icons/nc.svg?ref=chooser-v1"><img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;" src="https://mirrors.creativecommons.org/presskit/icons/sa.svg?ref=chooser-v1"></a></p>
* Nym applications and binaries are [GPL-3.0-only](https://www.gnu.org/licenses/)
@@ -6,10 +6,14 @@ import { useTheme } from "@mui/material/styles";
import Image from "next/image";
import Link from "next/link";
import networkDocs from "../public/images/landing/network-docs.png";
import developerDocs from "../public/images/landing/developer-docs.png";
import sdkDocs from "../public/images/landing/sdk-docs.png";
import operatorGuide from "../public/images/landing/operator-guide.png";
// import networkDocs from "../public/images/landing/network-docs.png";
// import developerDocs from "../public/images/landing/developer-docs.png";
// import sdkDocs from "../public/images/landing/sdk-docs.png";
// import operatorGuide from "../public/images/landing/operator-guide.png";
import networkDocs from "../public/images/landing/Vector1.png";
import developerDocs from "../public/images/landing/Vector2.png";
import sdkDocs from "../public/images/landing/Vector3.png";
import operatorGuide from "../public/images/landing/Vector4.png";
export const LandingPage = () => {
const theme = useTheme();
const isTablet = useMediaQuery(theme.breakpoints.up("md"));
@@ -129,7 +133,7 @@ export const LandingPage = () => {
{square.description}
</Typography>
<Typography sx={{ color: "#ff6600", fontWeight: 600 }}>
<Typography sx={{ color: "#14E76F", fontWeight: 600 }}>
Open
</Typography>
</Box>
+1 -1
View File
@@ -9,7 +9,7 @@ import Stack from "@mui/material/Stack";
import Paper from "@mui/material/Paper";
import type { SetupMixFetchOps } from "@nymproject/mix-fetch-full-fat";
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,56 @@
import { MyTab } from 'components/generic-tabs.tsx';
import { Tabs } from 'nextra/components';
### VPS Hardware Specs
You will need to rent a VPS to run your node on. One key reason for this is that your node **must be able to send TCP data using both IPv4 and IPv6** (as other nodes you talk to may use either protocol). Therefore you will need a server with static IPv4 and IPv6!
Tor community created a very helpful table called [*Good Bad ISPs*](https://community.torproject.org/relay/community-resources/good-bad-isps/), you can use that one as a guideline for your choice of ISP for your VPS.
**Update:** Nym community started an ISP table called [*Where to host your nym node?*](../../community-counsel/isp-list.mdx), check it out and add your findings!
<div>
<Tabs items={[
<code>nym-node</code>,
<code>validator</code>,
]} defaultIndex="0">
<MyTab>
#### `nym-node`
Before we conclude the testing with exact results, these are the rough specs:
| **Hardware** | **Minimum Specification** |
| :--- | ---: |
| CPU Cores | 4 |
| Memory | 8 GB RAM |
| Storage | 80 GB |
| Connectivity | IPv4, IPv6, TCP/IP, UDP |
| Bandwidth | > 1Tb |
| Port speed | 1Gbps |
</MyTab>
<MyTab>
#### Nyx validator
The specification mentioned below is for running a full node alongside the nym-api. It is recommended to run `nym-api` and a full Nyx node on the same machine for optimum performance.
Bear in mind that credential signing is primarily CPU-bound, so choose the fastest CPU available to you.
##### Minimum Requirements
| Hardware | **Minimum Specification** |
|----------|--------------------------------------------|
| CPU | 8-cores, 2.8GHz base clock speed or higher |
| RAM | 16GB DDR4+ |
| Disk | 500 GiB+ NVMe SSD |
##### Recommended Requirements
| Hardware | **Minimum Specification** |
|----------|---------------------------------------------|
| CPU | 16-cores, 2.8GHz base clock speed or higher |
| RAM | 32GB DDR4+ |
| Disk | 1 TiB+ NVMe SSD |
</MyTab>
</Tabs>
</div>
@@ -1 +1 @@
804_560_131
805_903_308
@@ -1 +1 @@
1_020_023
1_022_821
@@ -1 +1 @@
402_280_065
402_951_654
@@ -1,7 +1,7 @@
| **Item** | **Description** | **Amount in NYM** |
|:-------------------|:------------------------------------------------------|--------------------:|
| Total Supply | Maximum amount of NYM token in existence | 1_000_000_000 |
| Mixmining Reserve | Tokens releasing for operators rewards | 195_439_368 |
| Mixmining Reserve | Tokens releasing for operators rewards | 194_096_191 |
| Vesting Tokens | Tokens locked outside of cicrulation for future claim | 500 |
| Circulating Supply | Amount of unlocked tokens | 804_560_131 |
| Stake Saturation | Optimal size of node self-bond + delegation | 1_020_023 |
| Circulating Supply | Amount of unlocked tokens | 805_903_308 |
| Stake Saturation | Optimal size of node self-bond + delegation | 1_022_821 |
@@ -1 +1 @@
Monday, December 23rd 2024, 11:36:26 UTC
Wednesday, January 8th 2025, 15:01:28 UTC
@@ -2,5 +2,5 @@ import { Callout } from 'nextra/components'
<Callout type="info" emoji="️">
Our documentation often refer to syntax annotated in `<>` brackets. We use this expression for variables that are unique to each user (like path, local moniker, versions etcetra).
Any syntax in `<>` brackets needs to be substituted with your correct name or version, without the `<>` brackets. If you are unsure, please check our table of essential [parameters and variables](https://nymtech.net/docs/operators/variables.html).
Any syntax in `<>` brackets needs to be substituted with your correct name or version, without the `<>` brackets. If you are unsure, please check our table of essential [parameters and variables](https://nym.com/docs/operators/variables).
</Callout>
+5 -7
View File
@@ -100,7 +100,7 @@ const config = {
},
{
source: "/docs/nodes/overview.html ",
destination: "/docs/network/architecture/mixnet/nodes",
destination: "/docs/network/architecture/mixnet#nym-nodes",
permanent: true,
basePath: false,
},
@@ -132,21 +132,19 @@ const config = {
},
{
source: "/docs/nyx/smart-contracts.html",
destination: "/docs/network/architecture/nyx/smart-contracts",
destination: "/docs/network/architecture/nyx#smart-contracts",
permanent: true,
basePath: false,
},
{
source: "/docs/nyx/mixnet-contract.html",
destination:
"/docs/network/architecture/nyx/smart-contracts/mixnet-contract",
destination: "/docs/network/architecture/nyx#mixnet-contract",
permanent: true,
basePath: false,
},
{
source: "/docs/nyx/vesting-contract.html",
destination:
"/docs/network/architecture/nyx/smart-contracts/vesting-contract",
destination: "/docs/network/architecture/nyx#vesting-contract",
permanent: true,
basePath: false,
},
@@ -631,7 +629,7 @@ const config = {
},
{
source: "/docs/network/architecture/nyx/smart-contracts/ecash",
destination: "/docs/network/architecture/nyx/smart-contracts/zknym",
destination: "/docs/network/architecture/nyx#zk-nym-contract",
permanent: true,
basePath: false,
},
+3 -3
View File
@@ -37,9 +37,9 @@
"@mui/material": "^5.14.8",
"@nextui-org/accordion": "^2.0.40",
"@nextui-org/react": "^2.4.8",
"@nymproject/contract-clients": ">=1.2.4-rc.2 || ^1",
"@nymproject/mix-fetch-full-fat": ">=1.2.4-rc.2 || ^1",
"@nymproject/sdk-full-fat": ">=1.2.4-rc.2 || ^1",
"@nymproject/contract-clients": ">=1.4.0-rc.0 || ^1",
"@nymproject/mix-fetch-full-fat": ">=1.4.0-rc.0 || ^1",
"@nymproject/sdk-full-fat": ">=1.4.0-rc.0 || ^1",
"@redocly/cli": "^1.25.15",
"@types/mdx": "^2.0.13",
"chain-registry": "^1.19.0",
@@ -1,38 +0,0 @@
# NymVPN alpha
<div style="padding:56.25% 0 0 0;position:relative;"><iframe src="https://player.vimeo.com/video/897010658?h=1f55870fe6&amp;badge=0&amp;autopause=0&amp;player_id=0&amp;app_id=58479" frameborder="0" allow="autoplay; fullscreen; picture-in-picture" style="position:absolute;top:0;left:0;width:100%;height:100%;" title="NYMVPN alpha demo 37C3"></iframe></div><script src="https://player.vimeo.com/api/player.js"></script>
```admonish tip title="web3summit testing"
**If you testing NymVPN CLI on Web3 Summit Berlin, visit our event page with all info tailored for the event: [nym-vpn-cli.sandbox.nymtech.net](https://nym-vpn-cli.sandbox.nymtech.net/).**
```
**NymVPN alpha** is a client that uses [Nym Mixnet](https://nymtech.net) to anonymise all of a user's internet traffic through either a 5-hop mixnet (for a full network privacy) or the faster 2-hop decentralised VPN (with some extra features).
**You are invited to take part in the alpha testing** of this new application. Register for private testing round at [nymvpn.com](https://nymvpn.com/en), that will grant you access to the [download page](https://nymvpn.com/download). Visit [NymVPN Support & FAQ](https://nymvpn.com/en/support) or join the [NymVPN matrix channel](https://matrix.to/#/#NymVPN:nymtech.chat) if you have any questions, comments or blockers.
Checkout the [release page](https://github.com/nymtech/nym-vpn-client/releases) for available binaries.
*NOTE: NymVPN alpha is experimental software for testing purposes only.*
## NymVPN Overview
To understand what's under the hood of NymVPN and the mixnet, we recommend interested developers to begin with [Nym network overview](https://nymtech.net/docs/architecture/network-overview.html) and the [Mixnet traffic flow](https://nymtech.net/docs/architecture/traffic-flow.html) pages.
The default setup of NymVPN is to run in 5-hop mode (mixnet):
```
┌─►mix──┐ mix mix
│ │
Entry │ │ Exit
client ───► Gateway ──┘ mix │ mix ┌─►mix ───► Gateway ───► internet
│ │
│ │
mix └─►mix──┘ mix
```
Users can switch to 2-hop only mode, which is a faster but less private option. In this mode traffic is only sent between the two Gateways, and is not passed between Mix Nodes. It uses Mixnet Sphinx packets with shorter, fixed routes, which improve latency, but doesn't offer the same level of protection as the 5 hop mode.
<!-- TO BE IMPLEMENTED:
Users can switch to 2-hop only mode, which is a faster but less private option. In this mode traffic is only sent between the two Gateways, and is not passed between Mix Nodes. The client than use two wireguard tunnels with the entry and exit gateway, the Exit Gateway one being tunnelled itself through the entry gateway tunnel. NymVPN uses Mullvad libraries for wrapping `wireguard-go` and to setup local routing rules to route all traffic to the TUN virtual network device.
-->
@@ -1,142 +0,0 @@
# NymVPN alpha CLI Guide
```admonish info
NymVPN is an experimental software and it's for testing purposes only. All users testing the client are expected to sign GDPR Information Sheet and Consent Form (shared at the workshop) so we use their results to improve the client, and submit the form [*NymVPN User research*]({{nym_vpn_form_url}}) with the testing results.
```
## Installation
> Any syntax in `<>` brackets is a user's/version unique variable. Exchange with a corresponding name without the `<>` brackets.
1. Open Github [releases page](https://github.com/nymtech/nym-vpn-client) and download the CLI latest binary for your system
2. Verify sha hash of your downloaded binary with the one listed on the [releases page](https://github.com/nymtech/nym-vpn-client). You can use a simple `shasum` command and compare strings (ie with Python) or run in the same directory the following command, exchanging `<SHA_STRING>` with the one of your binary, like in the example:
```sh
echo "<SHA_STRING>" | shasum -a 256 -c
# choose a correct one according to your binary, this is just an example
# echo "0e4abb461e86b2c168577e0294112a3bacd3a24bf8565b49783bfebd9b530e23 nym-vpn-cli_<!-- cmdrun scripts/nym_vpn_cli_version.sh -->_ubuntu-22.04_amd64.tar.gz" | shasum -a 256 -c
```
3. Extract files:
```sh
tar -xvf <BINARY>.tar.gz
# for example
# tar -xvf nym-vpn-cli_<!-- cmdrun scripts/nym_vpn_cli_version.sh -->_ubuntu-22.04_x86_64.tar.gz
```
4. Make executable:
```sh
# make sure you are in the right sub-directory
chmod u+x ./nym-vpn-cli
```
## Run NymVPN
**For NymVPN to work, all other VPNs must be switched off!** At this alpha stage of NymVPN, the network connection (wifi) must be reconnected after or in between the testing rounds.
Make sure your terminal is open in the same directory as your `nym-vpn-cli` binary.
1. Go to [nymvpn.com/en/alpha](https://nymvpn.com/en/alpha) to get the entire command with all the needed arguments' values and your wireguard private key for testing purposes
2. Run it as root with `sudo` - the command will look like this with specified arguments:
```sh
sudo ./nym-vpn-cli -c ./sandbox.env --entry-gateway-id <ENTRY_GATEWAY_ID> --exit-router-address <EXIT_ROUTER_ADDRESS> --enable-wireguard --private-key <PRIVATE_KEY> --wg-ip <WIREGUARD_IP>
```
3. To choose different Gateways, visit [explorer.nymtech.net/network-components/gateways](https://explorer.nymtech.net/network-components/gateways) and copy-paste an identity key of your choice
4. See all possibilities in [command explanation](#cli-commands-and-options) section below
In case of errors, see [troubleshooting section](troubleshooting.md).
### CLI Commands and Options
The basic syntax of `nym-vpn-cli` is:
```sh
sudo ./nym-vpn-cli <--exit-router-address <EXIT_ROUTER_ADDRESS>|--exit-gateway-id <EXIT_GATEWAY_ID>|--exit-gateway-country <EXIT_GATEWAY_COUNTRY>>
```
* To choose different Gateways, visit [nymvpn.com/en/alpha/api/gateways](https://explorer.nymtech.net/network-components/gateways)
* To see all possibilities run with `--help` flag:
```sh
./nym-vpn-cli --help
```
~~~admonish example collapsible=true title="Console output"
```sh
Usage: nym-vpn-cli [OPTIONS] <--exit-router-address <EXIT_ROUTER_ADDRESS>|--exit-gateway-id <EXIT_GATEWAY_ID>|--exit-gateway-country <EXIT_GATEWAY_COUNTRY>>
Options:
-c, --config-env-file <CONFIG_ENV_FILE>
Path pointing to an env file describing the network
--mixnet-client-path <MIXNET_CLIENT_PATH>
Path to the data directory of a previously initialised mixnet client, where the keys reside
--entry-gateway-id <ENTRY_GATEWAY_ID>
Mixnet public ID of the entry gateway
--entry-gateway-country <ENTRY_GATEWAY_COUNTRY>
Auto-select entry gateway by country ISO
--entry-gateway-low-latency
Auto-select entry gateway by latency
--exit-router-address <EXIT_ROUTER_ADDRESS>
Mixnet recipient address
--exit-gateway-id <EXIT_GATEWAY_ID>
--exit-gateway-country <EXIT_GATEWAY_COUNTRY>
Mixnet recipient address
--enable-wireguard
Enable the wireguard traffic between the client and the entry gateway
--private-key <PRIVATE_KEY>
Associated private key
--wg-ip <WG_IP>
The IP address of the wireguard interface used for the first hop to the entry gateway
--nym-ipv4 <NYM_IPV4>
The IPv4 address of the nym TUN device that wraps IP packets in sphinx packets
--nym-ipv6 <NYM_IPV6>
The IPv6 address of the nym TUN device that wraps IP packets in sphinx packets
--nym-mtu <NYM_MTU>
The MTU of the nym TUN device that wraps IP packets in sphinx packets
--disable-routing
Disable routing all traffic through the nym TUN device. When the flag is set, the nym TUN device will be created, but to route traffic through it you will need to do it manually, e.g. ping -Itun0
--enable-two-hop
Enable two-hop mixnet traffic. This means that traffic jumps directly from entry gateway to exit gateway
--enable-poisson-rate
Enable Poisson process rate limiting of outbound traffic
--disable-background-cover-traffic
Disable constant rate background loop cover traffic
-h, --help
Print help
-V, --version
Print version
```
~~~
Here is a list of the options and their descriptions. Some are essential, some are more technical and not needed to be adjusted by users.
**Fundamental commands and arguments**
- `-c` is a path to the [Sandbox config](https://raw.githubusercontent.com/nymtech/nym/develop/envs/sandbox.env) file saved as `sandbox.env`
- `--entry-gateway-id`: paste one of the values labeled with a key `"identityKey"` (without `" "`) from [here](https://nymvpn.com/en/alpha/api/gateways)
- `--exit-router-address`: paste one of the values labeled with a key `"address"` (without `" "`) from here [here](https://nymvpn.com/en/alpha/api/gateways)
- `--enable-wireguard`: Enable the wireguard traffic between the client and the entry gateway. NymVPN uses Mullvad libraries for wrapping `wireguard-go` and to setup local routing rules to route all traffic to the TUN virtual network device
- `--wg-ip`: The address of the wireguard interface, you can get it [here](https://nymvpn.com/en/alpha)
- `--private-key`: get your private key for testing purposes [here](https://nymvpn.com/en/alpha)
- `--enable-two-hop` is a faster setup where the traffic is routed from the client to Entry Gateway and directly to Exit Gateway (default is 5-hops)
**Advanced options**
- `--enable-poisson`: Enables process rate limiting of outbound traffic (disabled by default). It means that NymVPN client will send packets at a steady stream to the Entry Gateway. By default it's on average one sphinx packet per 20ms, but there is some randomness (poisson distribution). When there are no real data to fill the sphinx packets with, cover packets are generated instead.
- `--ip` is the IP address of the TUN device. That is the IP address of the local private network that is set up between local client and the Exit Gateway.
- `--mtu`: The MTU of the TUN device. That is the max IP packet size of the local private network that is set up between local client and the Exit Gateway.
- `--disable-routing`: Disable routing all traffic through the VPN TUN device.
## Testnet environment
If you want to run NymVPN CLI in Nym Sandbox environment, there are a few adjustments to be done:
1. Create Sandbox environment config file by saving [this](https://raw.githubusercontent.com/nymtech/nym/develop/envs/sandbox.env) as `sandbox.env` in the same directory as your NymVPN binaries by running:
```sh
curl -o sandbox.env -L https://raw.githubusercontent.com/nymtech/nym/develop/envs/sandbox.env
```
1. Check available Gateways at [nymvpn.com/en/alpha/api/gateways](https://nymvpn.com/en/alpha/api/gateways)
2. Run with a flag `-c`
```sh
sudo ./nym-vpn-cli -c <PATH_TO>/sandbox.env <--exit-router-address <EXIT_ROUTER_ADDRESS>|--exit-gateway-id <EXIT_GATEWAY_ID>|--exit-gateway-country <EXIT_GATEWAY_COUNTRY>>
```
@@ -1,123 +0,0 @@
# NymVPN alpha CLI: Guide for MacOS
```admonish info
NymVPN is an experimental software and it's for testing purposes only. All users testing the client are expected to sign GDPR Information Sheet and Consent Form (shared at the workshop) so we use their results to improve the client, and submit the form [*NymVPN User research*]({{nym_vpn_form_url}}) with the testing results.
```
## Preparation
> Any syntax in `<>` brackets is a user's/version unique variable. Exchange with a corresponding name without the `<>` brackets.
1. Open Github [releases page](https://github.com/nymtech/nym-vpn-client) and download the binary for MacOS
2. Verify sha hash of your downloaded binary with the one listed on the [releases page](https://github.com/nymtech/nym-vpn-client). You can use a simple `shasum` command and compare strings (ie with Python) or run in the same directory the following command, exchanging `<SHA_STRING>` with the one of your binary, like in the example:
```sh
echo "<SHA_STRING>" | shasum -a 256 -c
# choose a correct one according to your binary, this is just an example
# echo "96623ccc69bc4cc0e4e3e18528b6dae6be69f645d0a592d926a3158ce2d0c269 nym-vpn-cli_<!-- cmdrun scripts/nym_vpn_cli_version.sh -->_macos_x86_64.zip" | shasum -a 256 -c
```
3. Extract files:
```sh
tar -xvf <BINARY>
# for example
# tar -xvf nym-vpn-cli_<!-- cmdrun scripts/nym_vpn_cli_version.sh -->_macos_aarch64.tar.gz
```
4. Make executable by running:
```sh
# possibly you may have to cd into a sub-directory
chmod u+x ./nym-vpn-cli
```
5. Create Sandbox environment config file by saving [this](https://raw.githubusercontent.com/nymtech/nym/develop/envs/sandbox.env) as `sandbox.env` in the same directory as your NymVPN binaries by running:
```sh
curl -L "https://raw.githubusercontent.com/nymtech/nym/develop/envs/sandbox.env" -o sandbox.env
```
## Run NymVPN
**For NymVPN to work, all other VPNs must be switched off!** At this alpha stage of NymVPN, the network connection (wifi) must be reconnected after or in between the testing rounds.
Make sure your terminal is open in the same directory as your `nym-vpn-cli` binary.
1. Go to [nymvpn.com/en/alpha](https://nymvpn.com/en/alpha) to get the entire command with all the needed arguments' values and your wireguard private key for testing purposes
2. Run it as root with `sudo` - the command will look like this with specified arguments:
```sh
sudo ./nym-vpn-cli -c ./sandbox.env --entry-gateway-id <ENTRY_GATEWAY_ID> --exit-router-address <EXIT_ROUTER_ADDRESS> --enable-wireguard --private-key <PRIVATE_KEY> --wg-ip <WIREGUARD_IP>
```
3. To choose different Gateways, visit [nymvpn.com/en/alpha/api/gateways](https://nymvpn.com/en/alpha/api/gateways) and pick one
4. See all possibilities in [command explanation](#cli-commands-and-options) section below
In case of errors, see [troubleshooting section](troubleshooting.md).
### CLI Commands and Options
The basic syntax of `nym-vpn-cli` is:
```sh
sudo ./nym-vpn-cli -c ./sandbox.env --entry-gateway-id <ENTRY_GATEWAY_ID> --exit-router-address <EXIT_ROUTER_ADDRESS> --enable-wireguard --private-key <PRIVATE_KEY> --wg-ip <WG_IP>
```
* To choose different Gateways, visit [nymvpn.com/en/alpha/api/gateways](https://nymvpn.com/en/alpha/api/gateways)
* To see all possibilities run with `--help` flag:
```sh
./nym-vpn-cli --help
```
~~~admonish example collapsible=true title="Console output"
```sh
Usage: nym-vpn-cli [OPTIONS]
Options:
-c, --config-env-file <CONFIG_ENV_FILE>
Path pointing to an env file describing the network
--mixnet-client-path <MIXNET_CLIENT_PATH>
Path to the data directory of a previously initialised mixnet client, where the keys reside
--entry-gateway-id <ENTRY_GATEWAY_ID>
Mixnet public ID of the entry gateway
--entry-gateway-country <ENTRY_GATEWAY_COUNTRY>
Auto-select entry gateway by country ISO
--exit-router-address <EXIT_ROUTER_ADDRESS>
Mixnet recipient address
--exit-gateway-id <EXIT_GATEWAY_ID>
--exit-router-country <EXIT_ROUTER_COUNTRY>
Mixnet recipient address
--enable-wireguard
Enable the wireguard traffic between the client and the entry gateway
--private-key <PRIVATE_KEY>
Associated private key
--wg-ip <WG_IP>
The IP address of the wireguard interface used for the first hop to the entry gateway
--nym-ip <NYM_IP>
The IP address of the nym TUN device that wraps IP packets in sphinx packets
--nym-mtu <NYM_MTU>
The MTU of the nym TUN device that wraps IP packets in sphinx packets
--disable-routing
Disable routing all traffic through the nym TUN device. When the flag is set, the nym TUN device will be created, but to route traffic through it you will need to do it manually, e.g. ping -Itun0
--enable-two-hop
Enable two-hop mixnet traffic. This means that traffic jumps directly from entry gateway to exit gateway
--enable-poisson-rate
Enable Poisson process rate limiting of outbound traffic
--disable-background-cover-traffic
Disable constant rate background loop cover traffic
-h, --help
Print help
-V, --version
Print version
```
~~~
Here is a list of the options and their descriptions. Some are essential, some are more technical and not needed to be adjusted by users.
**Fundamental commands and arguments**
- `-c` is a path to the [Sandbox config](https://raw.githubusercontent.com/nymtech/nym/develop/envs/sandbox.env) file saved as `sandbox.env`
- `--entry-gateway-id`: paste one of the values labeled with a key `"identityKey"` (without `" "`) from [here](https://nymvpn.com/en/alpha/api/gateways)
- `--exit-router-address`: paste one of the values labeled with a key `"address"` (without `" "`) from here [here](https://nymvpn.com/en/alpha/api/gateways)
- `--enable-wireguard`: Enable the wireguard traffic between the client and the entry gateway. NymVPN uses Mullvad libraries for wrapping `wireguard-go` and to setup local routing rules to route all traffic to the TUN virtual network device
- `--wg-ip`: The address of the wireguard interface, you can get it [here](https://nymvpn.com/en/alpha)
- `--private-key`: get your private key for testing purposes [here](https://nymvpn.com/en/alpha)
- `--enable-two-hop` is a faster setup where the traffic is routed from the client to Entry Gateway and directly to Exit Gateway (default is 5-hops)
**Advanced options**
- `--enable-poisson`: Enables process rate limiting of outbound traffic (disabled by default). It means that NymVPN client will send packets at a steady stream to the Entry Gateway. By default it's on average one sphinx packet per 20ms, but there is some randomness (poisson distribution). When there are no real data to fill the sphinx packets with, cover packets are generated instead.
- `--ip` is the IP address of the TUN device. That is the IP address of the local private network that is set up between local client and the Exit Gateway.
- `--mtu`: The MTU of the TUN device. That is the max IP packet size of the local private network that is set up between local client and the Exit Gateway.
- `--disable-routing`: Disable routing all traffic through the VPN TUN device.
@@ -1,240 +0,0 @@
# NymVPN CLI Guide
```admonish tip title="web3summit testing"
**If you testing NymVPN CLI on Web3 Summit Berlin, visit our event page with all info tailored for the event: [nym-vpn-cli.sandbox.nymtech.net](https://nym-vpn-cli.sandbox.nymtech.net/).**
```
```admonish info
To download NymVPN desktop version, visit [nymvpn.com/en/download](https://nymvpn.com/en/download).
NymVPN is an experimental software and it's for testing purposes only. Anyone can submit a registration to the private alpha round on [nymvpn.com](https://nymvpn.com/en).
```
## Overview
The core binaries consist of:
- **`nym-vpn-cli`**: Basic commandline client for running the vpn. This runs in the foreground.
- **`nym-vpnd`**: Daemon implementation of the vpn client that can run in the background and interacted with using `nym-vpnc`.
- **`nym-vpnc`**: The commandline client used to interact with `nym-vpnd`.
## Installation
> Any syntax in `<>` brackets is a user's/version unique variable. Exchange with a corresponding name without the `<>` brackets.
1. Open Github [releases page](https://github.com/nymtech/nym-vpn-client) and download the CLI latest binary for your system (labelled as `nym-vpn-core`)
2. Verify sha hash of your downloaded binary with the one listed on the [releases page](https://github.com/nymtech/nym-vpn-client). You can use a simple `shasum` command and compare strings (ie with Python) or run in the same directory the following command, exchanging `<SHA_STRING>` with the one of your binary, like in the example:
```sh
echo "<SHA_STRING>" | shasum -a 256 -c
# choose a correct one according to your binary, this is just an example
# echo "0e4abb461e86b2c168577e0294112a3bacd3a24bf8565b49783bfebd9b530e23 nym-vpn-cli_<!-- cmdrun ../../../scripts/cmdrun/nym_vpn_cli_version.sh -->_ubuntu-22.04_amd64.tar.gz" | shasum -a 256 -c
```
3. Extract files:
```sh
tar -xvf <BINARY>.tar.gz
# for example
# tar -xvf nym-vpn-cli_<!-- cmdrun ../../../scripts/cmdrun/nym_vpn_cli_version.sh -->_ubuntu-22.04_x86_64.tar.gz
```
### Building From Source
NymVPN CLI can be built from source. This process is recommended for more advanced users as the installation may require different dependencies based on the operating system used.
Start by installing [Go](https://go.dev/doc/install) and [Rust](https://rustup.rs/) languages on your system and then follow these steps:
1. Clone NymVPN repository:
```sh
git clone https://github.com/nymtech/nym-vpn-client.git
```
2. Move to `nym-vpn-client` directory and compile `wireguard`:
```sh
cd nym-vpn-client
make build-wireguard
```
3. Compile NymVPN CLI
```sh
make build-nym-vpn-core
```
Now your NymVPN CLI is installed. Navigate to `nym-vpn-core/target/release` and use the commands the section below to run the client.
## Running
If you are running Debian/Ubuntu/PopOS or any other distributio supporting debian packages and systemd, see the [relevant section below](#debian-package-for-debianubuntupopos).
### Daemon
Start the daemon with
```sh
sudo -E ./nym-vpnd
```
Then run
```sh
./nym-vpnc status
./nym-vpnc connect
./nym-vpnc disconnect
```
### CLI
An alternative to the daemon is to run the `nym-vpn-cli` commandline client that runs in the foreground.
```sh
./nym-vpn-cli run
```
## Credentials
NymVPN uses [zkNym bandwidth credentials](https://nymtech.net/docs/bandwidth-credentials.html). Those can be imported as a file or base58 encoded string.
```sh
sudo -E ./nym-vpn-cli import-credential --credential-path </PATH/TO/freepass.nym>
sudo -E ./nym-vpn-cli import-credential --credential-data "<STRING>"
```
## Debian package for Debian/Ubuntu/PopOS
For linux platforms using deb packages and systemd, there are also debian packages.
```sh
sudo apt install ./nym-vpnd_<!-- cmdrun ../../../scripts/cmdrun/nym_vpn_cli_version.sh -->-1_amd64.deb ./nym-vpnc_<!-- cmdrun ../../../scripts/cmdrun/nym_vpn_cli_version.sh -->-1_amd64.deb
# In case of error please substitute the correct version
```
Installing the `nym-vpnd` deb package starts a `nym-vpnd.service`. Check that the daemon is running with
```sh
systemctl status nym-vpnd.service
```
and check its logs with
```sh
sudo journalctl -u nym-vpnd.service -f
```
To stop the background service
```sh
systemctl stop nym-vpnd.service
```
It will start again on startup, so disable with
```sh
systemctl disable nym-vpnd.service
```
Interact with it with `nym-vpnc`
```sh
nym-vpnc status
nym-vpnc connect
nym-vpnc disconnect
```
## Commands & Options
```admonish note
Nym Exit Gateway functionality was implemented just recently and not all the Gateways are upgraded and ready to handle the VPN connections. If you want to make sure you are connecting to a Gateway with an embedded Network Requester, IP Packet Router and applied Nym exit policy, visit [harbourmaster.nymtech.net](https://harbourmaster.nymtech.net/) and search Gateways with all the functionalities enabled.
```
The basic syntax of `nym-vpn-cli` is:
```sh
# choose only one conditional --argument listed in {brackets}
sudo ./nym-vpn-cli { --exit-router-address <EXIT_ROUTER_ADDRESS>|--exit-gateway-id <EXIT_GATEWAY_ID>|--exit-gateway-country <EXIT_GATEWAY_COUNTRY> }
```
To see all the possibilities run with `--help` flag:
```sh
./nym-vpn-cli --help
```
~~~admonish example collapsible=true title="nym-vpn-cli --help"
```sh
Usage: nym-vpn-cli [OPTIONS] <COMMAND>
Commands:
run Run the client
import-credential Import credential
help Print this message or the help of the given subcommand(s)
Options:
-c, --config-env-file <CONFIG_ENV_FILE> Path pointing to an env file describing the network
--data-path <DATA_PATH> Path to the data directory of the mixnet client
-h, --help Print help
-V, --version Print version
```
~~~
You can also run any command with `--help` flag to see a list of all options associated witht that command, the most important may be `run` command, like in this example.
~~~admonish example collapsible=true title="nym-vpn-cli run --help"
```sh
Run the client
Usage: nym-vpn-cli run [OPTIONS]
Options:
--entry-gateway-id <ENTRY_GATEWAY_ID>
Mixnet public ID of the entry gateway
--entry-gateway-country <ENTRY_GATEWAY_COUNTRY>
Auto-select entry gateway by country ISO
--entry-gateway-low-latency
Auto-select entry gateway by latency
--exit-router-address <EXIT_ROUTER_ADDRESS>
Mixnet recipient address
--exit-gateway-id <EXIT_GATEWAY_ID>
Mixnet public ID of the exit gateway
--exit-gateway-country <EXIT_GATEWAY_COUNTRY>
Auto-select exit gateway by country ISO
--wireguard-mode
Enable the wireguard mode
--nym-ipv4 <NYM_IPV4>
The IPv4 address of the nym TUN device that wraps IP packets in sphinx packets
--nym-ipv6 <NYM_IPV6>
The IPv6 address of the nym TUN device that wraps IP packets in sphinx packets
--nym-mtu <NYM_MTU>
The MTU of the nym TUN device that wraps IP packets in sphinx packets
--dns <DNS>
The DNS server to use
--disable-routing
Disable routing all traffic through the nym TUN device. When the flag is set, the nym TUN device will be created, but to route traffic through it you will need to do it manually, e.g. ping -Itun0
--enable-two-hop
Enable two-hop mixnet traffic. This means that traffic jumps directly from entry gateway to exit gateway
--enable-poisson-rate
Enable Poisson process rate limiting of outbound traffic
--disable-background-cover-traffic
Disable constant rate background loop cover traffic
--enable-credentials-mode
Enable credentials mode
--min-mixnode-performance <MIN_MIXNODE_PERFORMANCE>
Set the minimum performance level for mixnodes
-h, --help
Print help
```
~~~
## Testnet environment
If you want to run NymVPN CLI in Nym Sandbox environment, there are a few adjustments to be done:
1. Create Sandbox environment config file by saving [this](https://raw.githubusercontent.com/nymtech/nym/develop/envs/sandbox.env) as `sandbox.env` in the same directory as your NymVPN binaries:
```sh
curl -o sandbox.env -L https://raw.githubusercontent.com/nymtech/nym/develop/envs/sandbox.env
```
2. Check available Gateways at [Sandbox API](https://sandbox-nym-api1.nymtech.net/api/v1/gateways) or [Sandbox Swagger page](https://sandbox-nym-api1.nymtech.net/api/swagger/index.html)
3. Run with a flag `-c`
```sh
sudo ./nym-vpn-cli -c <PATH_TO>/sandbox.env <--exit-router-address <EXIT_ROUTER_ADDRESS>|--exit-gateway-id <EXIT_GATEWAY_ID>|--exit-gateway-country <EXIT_GATEWAY_COUNTRY>>
```
@@ -1,71 +0,0 @@
# Frequently Asked Questions
**NymVPN [*Support & FAQ page*](https://nymvpn.com/en/support)** contains all essential FAQs regarding the client. This page (below) is a source of additional information often seeked by users, operators and developers testing NymVPN.
If you interested to read more about Nym platform, you can have a look at [Nym general FAQ](https://nymtech.net/developers/faq/general-faq.html) and read through Nym's technical [documentation](https://nymtech.net/docs), [Developer Portal](https://nymtech.net/developers) and [Operators Guide](https://nymtech.net/operators).
## NymVPN
If this your first time hearing about NymVPN, make sure you visit [NymVPN webpage](https://nymvpn.com/en), the official NymVPN [support & FAQ page](https://nymvpn.com/en/support) and the proceed to the introduction and guide on how to [install, run and test](intro.md#nymvpn-guides) the client.
Below are some extra FAQs which came out during the previous alpha testing rounds.
### What's the difference between 2-hops and 5-hops
The default is 5-hops (including Entry and Exit Gateways), which means that the traffic goes from the local client to Entry Gateway -> through 3 layers of Mix Nodes -> to Exit Gateway -> internet. this option uses all the Nym Mixnet features for maximum privacy.
```
┌─►mix──┐ mix mix
│ │
Entry │ │ Exit
client ───► Gateway ──┘ mix │ mix ┌─►mix ───► Gateway ───► internet
│ │
│ │
mix └─►mix──┘ mix
```
The 2-hop option is going from the local client -> Entry Gateway -> directly to Exit Gateway -> internet. This option is good for operations demanding faster connection. Keep in mind that this setup by-passes the 3 layers of Mix Nodes. The anonymising features done by your local client like breaking data into same-size packets with inserting additional "dummy" ones to break the time and volume patterns is done in both options.
```
Entry Exit
client ───► Gateway ────► Gateway ───► internet
```
We highly recommend to read more about [Nym network overview](https://nymtech.net/docs/architecture/network-overview.html) and the [Mixnet traffic flow](https://nymtech.net/docs/architecture/traffic-flow.html).
### Why do I see different sizes of packets in my terminal log?
One of features of Nym Mixnet's clients is to break data into the same size packets called Sphinx, which is currently ~2kb. When running NymVPN, the data log shows payload sizes, which are the raw sizes of the IP packets, not Sphinx. The payload sizes will be capped by the configured MTU, which is set around 1500 bytes.
### What is 'poisson filter' about?
By default `--enable-poisson` is disabled and packets are sent from the local client to the Entry Gateway as quickly as possible. With the poisson process enabled the Nym client will send packets at a steady stream to the Entry Gateway. By default it's on average one sphinx packet per 20ms, but there is some randomness (poisson distribution). When there are no real data to fill the sphinx packets with, cover packets are generated instead.
Enabling the poisson filter is one of the key mechanisms to de-correlate input and output traffic to the Mixnet. The performance impact however is dramatic:
1 packer per 20ms is 50 packets / sec so ballpark 100kb/s.
For mobile clients that means constantly sending data eating up data allowance.
## Nym Mixnet Architecture and Rewards
We have a list of questions related to Nym Nodes and the incentives behind running them under [FAQ pages](https://nymtech.net/operators/faq/mixnodes-faq.html) in our [Operators Guide](https://nymtech.net/operators). For better knowledge about Nym architecture we recommend to read [Nym network overview](https://nymtech.net/docs/architecture/network-overview.html) and the [Mixnet traffic flow](https://nymtech.net/docs/architecture/traffic-flow.html) in our [technical documentation](https://nymtech.net/docs).
## Project Smoosh
Project Smoosh is a code name for a process in which different components of Nym Mixnet architecture get *smooshed* into one binary. Check out [Smoosh FAQ](https://nymtech.net/operators/faq/smoosh-faq.html) in Operators Guide to read more.
## Exit Gateway
Part of the the transition under code name [Project Smoosh](#project-smoosh) is a creation of [Nym Exit Gateway](https://nymtech.net/operators/legal/exit-gateway.html) functionality. The operators running Gateways would have to “open” their nodes to a wider range of online services, in a similar fashion to Tor exit relays. The main change will be to expand the original short [allowed.list](https://nymtech.net/.wellknown/network-requester/standard-allowed-list.txt) to a more permissive setup. An [exit policy](https://nymtech.net/.wellknown/network-requester/exit-policy.txt) will constrain the hosts that the users of the Nym VPN and Mixnet can connect to. This will be done in an effort to protect the operators, as Gateways will act both as SOCKS5 Network Requesters, and exit nodes for IP traffic from Nym VPN and Mixnet clients.
* Read more how the exit policy gets implemented [here](https://nymtech.net/operators/faq/smoosh-faq.html#how-will-the-exit-policy-be-implemented)
* Check out [Nym Operators Legal Forum](https://nymtech.net/operators/legal/exit-gateway.html)
* Do reach out to us with any experiences you may have running Tor Exit relays or legal findings and suggestions for Nym Exit Gateway operators
## Nym Integrations and SDKs
If you are a dev who is interested to integrate Nym, have a look on our SDK tutorials:
* [Rust SDKs](https://nymtech.net/developers/tutorials/cosmos-service/intro.html)
* [TypeScript SDKs](https://sdk.nymtech.net/)
* [Integration FAQ](https://nymtech.net/developers/faq/integrations-faq.html)
@@ -1,85 +0,0 @@
# NymVPN alpha - Desktop: Guide for GNU/Linux
<div style="padding:56.25% 0 0 0;position:relative;"><iframe src="https://player.vimeo.com/video/908221306?h=404b2bbdc8" style="position:absolute;top:0;left:0;width:100%;height:100%;" frameborder="0" allow="autoplay; fullscreen; picture-in-picture" allowfullscreen></iframe></div><script src="https://player.vimeo.com/api/player.js"></script>
```admonish info
NymVPN is an experimental software and it's for testing purposes only. All users testing the client are expected to sign GDPR Information Sheet and Consent Form (shared at the workshop) so we use their results to improve the client, and submit the form [*NymVPN User research*]({{nym_vpn_form_url}}) with the testing results.
```
## Preparation
> Any syntax in `<>` brackets is a user's/version unique variable. Exchange with a corresponding name without the `<>` brackets.
### Installation
1. Open Github [releases page](https://github.com/nymtech/nym-vpn-client) and download the binary for Debian based Linux
2. (Optional: if you don't want to check shasum, skip this point) Verify sha hash of your downloaded binary with the one listed on the [releases page](https://github.com/nymtech/nym-vpn-client). You can use a simple `shasum` command and compare strings (ie with Python) or run in the same directory the following command, exchanging `<SHA_STRING>` with the one of your binary, like in the example:
```sh
echo "<SHA_STRING>" | shasum -a 256 -c
# choose a correct one according to your binary, this is just an example
# echo "a5f91f20d587975e30b6a75d3a9e195234cf1269eac278139a5b9c39b039e807 nym-vpn-desktop_<!-- cmdrun scripts/nym_vpn_desktop_version.sh -->_ubuntu-22.04_x86_64.tar.gz" | shasum -a 256 -c
```
3. Extract files:
```sh
tar -xvf <BINARY>.tar.gz
# for example
# tar -xvf nym-vpn-desktop_<!-- cmdrun scripts/nym_vpn_desktop_version.sh -->_ubuntu-22.04_x86_64.tar.gz
```
4. If you prefer to run `.AppImage` make executable by running:
```sh
# make sure you cd into the right sub-directory after extraction
chmod u+x ./nym-vpn_<!-- cmdrun scripts/nym_vpn_desktop_version.sh -->_amd64.AppImage
```
5. If you prefer to use the `.deb` version for installation (works on Debian based Linux only), open terminal in the same directory and run:
```sh
# make sure you cd into the right sub-directory after extraction
sudo dpkg -i ./nym-vpn_<!-- cmdrun scripts/nym_vpn_desktop_version.sh -->_amd64.deb
# or
sudo apt-get install -f ./nym-vpn_<!-- cmdrun scripts/nym_vpn_desktop_version.sh -->_amd64.deb
```
<!--
NymVPN alpha version runs over Nym testnet (called sandbox), a little extra configuration is needed for the application to work.
### Configuration
To test NymVPN alpha we must create two configuration files: an environment config file `sandbox.env` and `config.toml` file pointing the application to run over the testnet environment.
6. Create a NymVPN config directory called `nym-vpn` in your `~/.config`, either manually or by a command:
```sh
mkdir $HOME/.config/nym-vpn/
```
7. Create the network testnet config: copy-paste [this](https://raw.githubusercontent.com/nymtech/nym/develop/envs/sandbox.env) and save as `sandbox.env` in the directory `~/.config/nym-vpn/` you just created. Aternatively do it by runnin a command
```sh
curl -o $HOME/.config/nym-vpn/sandbox.env -L https://raw.githubusercontent.com/nymtech/nym/develop/envs/sandbox.env
```
8. Create NymVPN main config file: copy-paste the line below and save it as `config.toml` in the same directory `~/.config/nym-vpn/`:
```toml
# change <USER> to your username
env_config_file = "/home/<USER>/.config/nym-vpn/sandbox.env"
```
-->
## Run NymVPN
**For NymVPN to work, all other VPNs must be switched off!** At this alpha stage of NymVPN, the network connection (wifi) must be reconnected after or in between the testing rounds.
In case you used `.deb` package and installed the client, you may be able to have a NymVPN application icon in your app menu. However this may not work as the application needs root permission.
Open terminal and run:
```sh
# .AppImage must be run from the same directory as the binary
sudo -E ./nym-vpn_<!-- cmdrun scripts/nym_vpn_desktop_version.sh -->_amd64.AppImage
# .deb installation shall be executable from anywhere as
sudo -E nym-vpn
```
In case of errors, see [troubleshooting section](troubleshooting.md).
@@ -1,65 +0,0 @@
# NymVPN alpha - Desktop: Guide for Mac OS
```admonish info
NymVPN is an experimental software and it's for testing purposes only. All users testing the client are expected to sign GDPR Information Sheet and Consent Form (shared at the workshop) so we use their results to improve the client, and submit the form [*NymVPN User research*]({{nym_vpn_form_url}}) with the testing results.
```
## Preparation
> Any syntax in `<>` brackets is a user's/version unique variable. Exchange with a corresponding name without the `<>` brackets.
### Installation
1. Open Github [releases page](https://github.com/nymtech/nym-vpn-client) and download the binary for your version of MacOS
2. Recommended (skip this point if you don't want to verify): Verify sha hash of your downloaded binary with the one listed on the [releases page](https://github.com/nymtech/nym-vpn-client). You can use a simple `shasum` command and compare strings (ie with Python) or run in the same directory the following command, exchanging `<SHA_STRING>` with the one of your binary, like in the example:
```sh
echo "<SHA_STRING>" | shasum -a 256 -c
# choose a correct one according to your binary, this is just an example
# echo "da4c0bf8e8b52658312d341fa3581954cfcb6efd516d9a448c76d042a454b5df nym-vpn-desktop_<!-- cmdrun scripts/nym_vpn_desktop_version.sh -->_macos_x86_64.zip" | shasum -a 256 -c
```
3. Extract the downloaded file manually or by a command:
```sh
tar -xvf <BINARY>.tar.gz
# for example
# tar -xvf nym-vpn-desktop_<!-- cmdrun scripts/nym_vpn_desktop_version.sh -->_macos_aarch64.tar.gz
```
4. Mount the `.dmg` image you extracted by double clicking on it and move it (drag it) to your `/Application` folder
<!--
NymVPN alpha version runs over Nym testnet (called sandbox), a little extra configuration is needed for the application to work.
### Configuration
To test NymVPN alpha we must create two configuration files: an environment config file `sandbox.env` and `config.toml` file pointing the application to run over the testnet environment.
5. Create testnet configuration file: Open a text editor, copy-paste [this](https://raw.githubusercontent.com/nymtech/nym/develop/envs/sandbox.env) and save it as `sandbox.env` in `/Applications/nym-vpn.app/Contents/MacOS/`. Alternatively use this command:
```sh
curl -L "https://raw.githubusercontent.com/nymtech/nym/develop/envs/sandbox.env" -o "/Applications/nym-vpn.app/Contents/MacOS/sandbox.env"
```
6. Create application configuration file: Open a text editor, copy-paste the line below and save as `config.toml` in the same directory `/Applications/nym-vpn.app/Contents/MacOS/`
```toml
env_config_file = "sandbox.env"
```
Alternatively do it by using this command:
```sh
echo "env_config_file = sandbox.env" > /Applications/nym-vpn.app/Contents/MacOS/config.toml
```
-->
## Run NymVPN
**For NymVPN to work, all other VPNs must be switched off!** At this alpha stage of NymVPN, the network connection (wifi) must be reconnected after or in between the testing rounds.
Run:
```sh
sudo /Applications/nym-vpn.app/Contents/MacOS/nym-vpn
# If it didn't start try to run with -E flag
sudo -E /Applications/nym-vpn.app/Contents/MacOS/nym-vpn
```
In case of errors check out the [troubleshooting](troubleshooting.md#running-gui-failed-due-to-toml-parse-error) section.
@@ -1,50 +0,0 @@
# NymVPN - Desktop (GUI)
```admonish info
Our alpha testing round is done with participants at live workshop events and the application in this stage may not work for everyone.
**If you commit to test NymVPN alpha, please start with the [user research form]({{nym_vpn_form_url}}) where all the steps will be provided**. If you disagree with any of the conditions listed, please leave this page.
```
This is a desktop (GUI) version of NymVPN client. A demo of how the application will look like for majority of day-to-day users.
Follow the simple [automated script](#automated-script-for-gui-installation) below to install and run NymVPN GUI. If the script didn't work for your distribution or you prefer to do a manual setup follow the steps in the guide for [Linux](gui-linux.md) or [MacOS](gui-mac.md) .
Visit NymVPN alpha latest [release page](https://github.com/nymtech/nym-vpn-client) to check sha sums or download the binaries directly.
## Linux AppImage Automated Installation Method
The latest releases contain `appimage.sh` script. This method makes the installation simple for Linux users who want to run NymVPN from AppImmage. Executing the command below will download the binary to `~/.local/bin` and verify the checksum:
```sh
curl -fsSL https://github.com/nymtech/nym-vpn-client/releases/download/nym-vpn-desktop-v<!-- cmdrun scripts/nym_vpn_desktop_version.sh -->/appimage.sh | bash
```
Run with the command:
```sh
sudo -E ~/.local/bin/nym-vpn.appimage
```
## Automated Script for GUI Installation (Linux and Mac)
We wrote a [script](https://gist.github.com/tommyv1987/7d210d4daa8f7abc61f9a696d0321f19) which does download of dependencies and the application, sha256 verification, extraction, installation and configuration for Linux and MacOS users automatically. Turn off all VPNs and follow the steps below.
1. Open a terminal window in a directory where you want the script to be downloaded and run
```sh
curl -o nym-vpn-desktop-install-run.sh -L https://gist.githubusercontent.com/tommyv1987/7d210d4daa8f7abc61f9a696d0321f19/raw/939ac8d0afed69f43739b9cf2e5728454ea2c437/nym-vpn-client-install-run.sh && chmod u+x nym-vpn-desktop-install-run.sh && sudo -E ./nym-vpn-desktop-install-run.sh
```
2. Follow the prompts in the program
To start the application again, reconnect your wifi and run
```sh
# Linux .AppImage
sudo -E ~/nym-vpn-latest/nym-vpn-desktop_<!-- cmdrun scripts/nym_vpn_desktop_version.sh -->_ubuntu-22.04_x86_64/nym-vpn_<!-- cmdrun scripts/nym_vpn_desktop_version.sh -->_amd64.AppImage
# Linux .deb
sudo -E nym-vpn
# MacOS
sudo -E $HOME/nym-vpn-latest/nym-vpn
```
In case of errors check out the [troubleshooting](troubleshooting.md#running-gui-failed-due-to-toml-parse-error) section.
@@ -1,209 +0,0 @@
# Testing NymVPN alpha
<div style="padding:56.25% 0 0 0;position:relative;"><iframe src="https://player.vimeo.com/video/908640440?h=0f7f6dfa53" style="position:absolute;top:0;left:0;width:100%;height:100%;" frameborder="0" allow="autoplay; fullscreen; picture-in-picture" allowfullscreen></iframe></div><script src="https://player.vimeo.com/api/player.js"></script>
```admonish info
NymVPN is an experimental software and it's for [testing](./testing.md) purposes only. All users testing the client are expected to sign GDPR Information Sheet and Consent Form (shared at the workshop) so we use their results to improve the client, and submit the form [*NymVPN User research*]({{nym_vpn_form_url}}) with the testing results.
```
> Before you get into testing NymVPN, make sure to go through the preparation steps for NymVPN [CLI](cli.md).
One of the main aims of NymVPN alpha release is testing; your results will help us to make NymVPN robust and stabilise both the client and the network through provided measurements.
## Steps to test NymVPN
> Any syntax in `<>` brackets is a user's/version unique variable. Exchange with a corresponding name without the `<>` brackets.
1. Create a directory called `nym-vpn-tests` and copy your `nym-vpn-cli` binary ([download here](https://github.com/nymtech/nym-vpn-client))
2. Copy or download [`sandbox.env`](https://raw.githubusercontent.com/nymtech/nym/develop/envs/sandbox.env) testnet config file to the same directory
```sh
curl -o sandbox.env -L https://raw.githubusercontent.com/nymtech/nym/develop/envs/sandbox.env
```
3. Copy the [block below](#testssh) and save it as `tests.sh` to the same folder
4. Open terminal in the same directory and make the script executable
```sh
chmod u+x ./tests.sh
```
5. Turn off any existing VPN's (including NymVPN instances), reconnect your wifi and run the `tests.sh` script
```sh
sudo ./tests.sh
````
6. In case of errors, see the [troubleshooting section](troubleshooting.md#missing-jq-error)
7. The script will print a JSON view of existing Gateways and prompt you to:
- *Make sure to use two different Gateways for entry and exit!*
- `enter a gateway ID:` paste one of the values labeled with a key `"identityKey"` printed above (without `" "`)
- `enter an exit address:` paste one of the values labeled with a key `"address"` printed above (without `" "`)
- `enable WireGuard? (yes/no):` if you chose yes, find your private key and wireguard IP [here](https://nymvpn.com/en/alpha)
8. Note that the testing script doesn't print many logs, in case of doubts you can check logs in the log file `temp_log.txt` located in the same directory.
9. The script shall run the tests and generate a folder called `tests_<LONG_STRING>` and files `perf_test_results.log` or `two_hop_perf_test_results.log` as well as some temp files. This is how the directory structure will look like:
```sh
nym-vpn-tests
├── tests.sh
├── nym-vpn-cli
├── sandbox.env
├── perf_test_results.log
├── tests_<LONG_STRING>
│   ├── api_response_times.txt
│   ├── download_time.txt
│   └── ping_results.txt
├── timeout
└── two_hop_perf_test_results.log
```
10. When the tests are finished, remove the `nym-vpn-cli` binary from the folder and compress the entire folder as `nym-vpn-tests.zip` (both of these can be done in your graphical environment)
11. Upload this compressed file to the [form]({{nym_vpn_form_url}}) drop field when prompted
#### tests.sh
This is the testing script which needs to be copied and saved as `tests.sh` to your `nym-vpn-tests` folder and then run from there as described [above](#steps-to-test-nymvpn).
```sh
#!/bin/bash
ENDPOINT="https://sandbox-nym-api1.nymtech.net/api/v1/gateways/described"
json_array=()
echo "🚀 🏎 - please be patient, i'm fetching you your entry points - 🚀 🏎 "
data=$(curl -s "$ENDPOINT" | jq -c '.[] | {host: .bond.gateway.host, hostname: .self_described.host_information.hostname, identity_key: .bond.gateway.identity_key, exitGateway: .self_described.ip_packet_router.address}')
while IFS= read -r entry; do
host=$(echo "$entry" | jq -r '.host')
hostname=$(echo "$entry" | jq -r '.hostname')
identity_key=$(echo "$entry" | jq -r '.identity_key')
exit_gateway_address=$(echo "$entry" | jq -r '.exitGateway // empty')
valid_ip=$(echo "$host")
if [ -n "$exit_gateway_address" ]; then
exit_gateway="{\"address\": \"${exit_gateway_address}\"}"
else
exit_gateway="{}"
fi
if [[ $valid_ip =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
country_info=$(curl -s "http://ipinfo.io/${valid_ip}/country" | tr -d '\n')
country_info_escaped=$(echo "$country_info" | tr -d '\n' | jq -aRs . | tr -d '"')
else
country_info_escaped=""
fi
json_object="{\"hostname\": \"${hostname}\", \"identityKey\": \"${identity_key}\", \"exitGateway\": ${exit_gateway}, \"location\": \"${country_info_escaped}\"}"
json_array+=("$json_object")
done < <(echo "$data")
if [ $? -ne 0 ]; then
echo "error fetching data from endpoint"
exit 1
fi
download_file() {
local file_url=$1
local output_file=$2
local time_file=$3
echo "starting download speed test..."
local start_time=$(date +%s)
if [[ "$OSTYPE" == "linux-gnu"* ]]; then
wget -O $output_file $file_url
elif [[ "$OSTYPE" == "darwin"* ]]; then
curl -o $output_file $file_url
fi
local end_time=$(date +%s)
local elapsed_time=$((end_time - start_time))
echo "download speed test completed in $elapsed_time seconds." >"$time_file"
}
if ! command -v jq &>/dev/null; then
echo "jq is not installed. Please install jq to proceed."
exit 1
fi
temp_log_file="temp_log.txt"
perform_tests() {
local gateway_id=$1
local exit_address=$2
local test_directory="tests_${gateway_id}_${exit_address}"
local file_url="http://ipv4.download.thinkbroadband.com/2MB.zip"
mkdir -p "$test_directory"
local ping_results_file="${test_directory}/ping_results.txt"
local download_time_file="${test_directory}/download_time.txt"
local api_response_file="${test_directory}/api_response_times.txt"
# ping test
echo "starting ping test..."
for site in google.com youtube.com facebook.com baidu.com wikipedia.org amazon.com twitter.com instagram.com yahoo.com ebay.com netflix.com; do
ping -c 4 $site >>"$ping_results_file"
done
echo "ping test completed. Results saved in $ping_results_file"
# download speed test
download_file $file_url /dev/null "$download_time_file"
# api test
local api_endpoint="https://validator.nymtech.net/api/v1/mixnodes"
local iterations=10
>"$api_response_file"
for i in $(seq 1 $iterations); do
local start_time=$(date +%s)
local response=$(curl -s -o /dev/null -w '%{http_code}' $api_endpoint)
local end_time=$(date +%s)
local elapsed_seconds=$((end_time - start_time))
local hours=$((elapsed_seconds / 3600))
local minutes=$(((elapsed_seconds % 3600) / 60))
local seconds=$((elapsed_seconds % 60))
local human_readable_time=$(printf "%02dh:%02dm:%02ds" $hours $minutes $seconds)
echo "iteration $i: response Time = ${human_readable_time}, status code = $response" >>"$api_response_file"
done
echo "api response test completed. Results saved in $api_response_file."
}
printf "%s\n" "${json_array[@]}" | jq -s .
read -p "enter a gateway ID: " identity_key
read -p "enter an exit address: " exit_address
while true; do
read -p "enable WireGuard? (yes/no): " enable_wireguard
enable_wireguard=$(echo "$enable_wireguard" | tr '[:upper:]' '[:lower:]')
case "$enable_wireguard" in
"yes")
read -p "enter your WireGuard private key: " priv_key
read -p "enter your WireGuard IP: " wg_ip
wireguard_options="--enable-wireguard --private-key $priv_key --wg-ip $wg_ip"
break
;;
"no")
wireguard_options=""
break
;;
*)
echo "invalid response. please enter 'yes' or 'no'."
;;
esac
done
sudo ./nym-vpn-cli -c sandbox.env --entry-gateway-id ${identity_key} --exit-router-address ${exit_address} --enable-two-hop $wireguard_options >"$temp_log_file" 2>&1 &
timeout=15
start_time=$(date +%s)
while true; do
current_time=$(date +%s)
if grep -q "received plain" "$temp_log_file"; then
echo "successful configuration with identity_key: $identity_key and exit address: $exit_address" >>perf_test_results.log
perform_tests "$identity_key" "$exit_address"
break
fi
if ((current_time - start_time > timeout)); then
echo "failed to connect with identity_key: $identity_key using the exit address: $exit_address" >>perf_test_results.log
break
fi
sleep 1
done
echo "terminating nym-vpn-cli..."
pkill -f './nym-vpn-cli'
sleep 5
rm -f "$temp_log_file"
```
@@ -9,7 +9,7 @@ At present, there are three Nym clients. These are built as standalone binaries
- the SOCKS5 client - most easily accessed via the [Rust SDK](./rust).
- the wasm (webassembly) client - most easily via the [Typescript SDK](./typescript).
> For information about the role that clients play within the Nym system and their role when communicating with the Mixnet, see the [Client network docs](../network/architecture/mixnet/clients).
> For information about the role that clients play within the Nym system and their role when communicating with the Mixnet, see the [Client network docs](../network/architecture/mixnet#nym-clients).
### The websocket client
This is a compiled program that can run on Linux, Mac OS X, and Windows machines. It can be run as a persistent process on a desktop or server machine. You can connect to it with **any language that supports websockets**.
@@ -2,7 +2,7 @@
As a general approach, licensing is as follows this pattern:
* <p xmlns:cc="http://creativecommons.org/ns#" xmlns:dct="http://purl.org/dc/terms/"><a property="dct:title" rel="cc:attributionURL" href="https://nymtech.net/docs">Nym Documentation</a> by <a rel="cc:attributionURL dct:creator" property="cc:attributionName" href="https://nymtech.net">Nym Technologies</a> is licensed under <a href="http://creativecommons.org/licenses/by-nc-sa/4.0/?ref=chooser-v1" target="_blank" rel="license noopener noreferrer" style="display:inline-block;">CC BY-NC-SA 4.0<img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;" src="https://mirrors.creativecommons.org/presskit/icons/cc.svg?ref=chooser-v1"><img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;" src="https://mirrors.creativecommons.org/presskit/icons/by.svg?ref=chooser-v1"><img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;" src="https://mirrors.creativecommons.org/presskit/icons/nc.svg?ref=chooser-v1"><img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;" src="https://mirrors.creativecommons.org/presskit/icons/sa.svg?ref=chooser-v1"></a></p>
* <p xmlns:cc="http://creativecommons.org/ns#" xmlns:dct="http://purl.org/dc/terms/"><a property="dct:title" rel="cc:attributionURL" href="https://nym.com/docs">Nym Documentation</a> by <a rel="cc:attributionURL dct:creator" property="cc:attributionName" href="https://nym.com">Nym Technologies</a> is licensed under <a href="http://creativecommons.org/licenses/by-nc-sa/4.0/?ref=chooser-v1" target="_blank" rel="license noopener noreferrer" style="display:inline-block;">CC BY-NC-SA 4.0<img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;" src="https://mirrors.creativecommons.org/presskit/icons/cc.svg?ref=chooser-v1"><img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;" src="https://mirrors.creativecommons.org/presskit/icons/by.svg?ref=chooser-v1"><img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;" src="https://mirrors.creativecommons.org/presskit/icons/nc.svg?ref=chooser-v1"><img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;" src="https://mirrors.creativecommons.org/presskit/icons/sa.svg?ref=chooser-v1"></a></p>
* Nym applications and binaries are [GPL-3.0-only](https://www.gnu.org/licenses/)
@@ -45,7 +45,7 @@ make
```
## Mnemonic Generation
Create an account at [nymvpn.com](nymvpn.com) to obtain your mnemonic.
Head to the mnemonic generator at [https://nym.com/account/create](https://nym.com/account/create) and obtain a mnemonic.
## Start the daemon
```sh
@@ -2,6 +2,3 @@
The Rust SDK allows developers building applications in Rust to import and interact with Nym clients as they would any other dependency, instead of running the client as a separate process on their machine.
Check the [development status](./rust/development-status) page to see the various modules that make up the SDK, and the [FFI](./rust/ffi) page for Go/C++ developers.
### Generate Crate Docs
In order to generate the crate docs run `cargo doc --open` from `nym/sdk/rust/nym-sdk/`
@@ -3,6 +3,7 @@
"development-status": "Development Status",
"mixnet": "Mixnet Module",
"tcpproxy": "TcpProxy Module",
"client-pool": "Client Pool",
"ffi": "FFI",
"tutorials": "Tutorials (Coming Soon)"
}
@@ -0,0 +1,7 @@
# Client Pool
We have a configurable-size Client Pool for processes that require multiple clients in quick succession (this is used by default by the [`TcpProxyClient`](./tcpproxy) for instance)
This will be useful for developers looking to build connection logic, or just are using raw SDK clients in a sitatuation where there are multiple connections with a lot of churn.
> You can find this code [here](https://github.com/nymtech/nym/blob/develop/sdk/rust/nym-sdk/examples/client_pool.rs)
@@ -0,0 +1,4 @@
{
"architecture": "Architecture",
"example": "Example"
}
@@ -0,0 +1,19 @@
# Client Pool Architecture
## Motivations
In situations where multiple connections are expected, and the number of connections can vary greatly, the Client Pool reduces time spent waiting for the creation of a Mixnet Client blocking your code sending traffic through the Mixnet. Instead, a configurable number of Clients can be generated and run in the background which can be very quickly grabbed, used, and disconnected.
The Pool can be simply run as a background process for the runtime of your program.
## Clients & Lifetimes
The Client Pool creates **ephemeral Mixnet Clients** which are used and then disconnected. Using the [`TcpProxy`](../tcpproxy) as an example, Clients are used for the lifetime of a single incoming TCP connection; after the TCP connection is closed, the Mixnet client is disconnected.
Clients are popped from the pool when in use, and another Client is created to take its place. If connections are coming in faster than Clients are replenished, you can instead generate an ephemeral Client on the fly, or wait; this is up to the developer to decide. You can see an example of this logic in the example on the next page.
## Runtime Loop
Aside from a few helper / getter functions and a graceful `disconnect_pool()`, the Client Pool is mostly made up of a very simple loop around some conditional logic making up `start()`:
- if the number of Clients in the pool is `< client_pool_reserve_number` (set on `new()`) then create more,
- if the number of Clients in the pool `== client_pool_reserve_number` (set on `new()`) then `sleep`,
- if `client_pool_reserve_number == 0` just `sleep`.
`disconnect_pool()` will cause this loop to `break` via cancellation token.
@@ -0,0 +1,100 @@
# Client Pool Example
> You can find this code [here](https://github.com/nymtech/nym/blob/develop/sdk/rust/nym-sdk/examples/client_pool.rs)
```rust
use anyhow::Result;
use nym_network_defaults::setup_env;
use nym_sdk::client_pool::ClientPool;
use nym_sdk::mixnet::{MixnetClientBuilder, NymNetworkDetails};
use tokio::signal::ctrl_c;
// This client pool is used internally by the TcpProxyClient but can also be used by the Mixnet module, in case you're quickly swapping clients in and out but won't want to use the TcpProxy module.
//
// Run with: cargo run --example client_pool -- ../../../envs/<NETWORK>.env
#[tokio::main]
async fn main() -> Result<()> {
nym_bin_common::logging::setup_logging();
setup_env(std::env::args().nth(1));
let conn_pool = ClientPool::new(2); // Start the Client Pool with 2 Clients always being kept in reserve
let client_maker = conn_pool.clone();
tokio::spawn(async move {
client_maker.start().await?;
Ok::<(), anyhow::Error>(())
});
println!("\n\nWaiting a few seconds to fill pool\n\n");
tokio::time::sleep(tokio::time::Duration::from_secs(10)).await;
let pool_clone_one = conn_pool.clone();
let pool_clone_two = conn_pool.clone();
tokio::spawn(async move {
let client_one = match pool_clone_one.get_mixnet_client().await {
Some(client) => {
println!("Grabbed client {} from pool", client.nym_address());
client
}
None => {
println!("Not enough clients in pool, creating ephemeral client");
let net = NymNetworkDetails::new_from_env();
let client = MixnetClientBuilder::new_ephemeral()
.network_details(net)
.build()?
.connect_to_mixnet()
.await?;
println!(
"Using {} for the moment, created outside of the connection pool",
client.nym_address()
);
client
}
};
let our_address = client_one.nym_address();
println!("\n\nClient 1: {our_address}\n\n");
client_one.disconnect().await;
tokio::time::sleep(tokio::time::Duration::from_secs(10)).await; // Emulate doing something
return Ok::<(), anyhow::Error>(());
});
tokio::spawn(async move {
let client_two = match pool_clone_two.get_mixnet_client().await {
Some(client) => {
println!("Grabbed client {} from pool", client.nym_address());
client
}
None => {
println!("Not enough clients in pool, creating ephemeral client");
let net = NymNetworkDetails::new_from_env();
let client = MixnetClientBuilder::new_ephemeral()
.network_details(net)
.build()?
.connect_to_mixnet()
.await?;
println!(
"Using {} for the moment, created outside of the connection pool",
client.nym_address()
);
client
}
};
let our_address = *client_two.nym_address();
println!("\n\nClient 2: {our_address}\n\n");
client_two.disconnect().await;
tokio::time::sleep(tokio::time::Duration::from_secs(10)).await; // Emulate doing something
return Ok::<(), anyhow::Error>(());
});
wait_for_ctrl_c(conn_pool).await?;
Ok(())
}
async fn wait_for_ctrl_c(pool: ClientPool) -> Result<()> {
println!("\n\nPress CTRL_C to disconnect pool\n\n");
ctrl_c().await?;
println!("CTRL_C received. Killing client pool");
pool.disconnect_pool().await;
Ok(())
}
```
@@ -7,9 +7,12 @@ In the future the SDK will be made up of several modules, each of which will all
|-----------|---------------------------------------------------------------------------------------|----------|
| Mixnet | Create / load clients & keypairs, subscribe to Mixnet events, send & receive messages | ✔️ |
| TcpProxy | Utilise the TcpProxyClient and TcpProxyServer abstractions for streaming | ✔️ |
| ClientPool| Create a pool of quickly useable Mixnet clients | ✔️ |
| Ecash | Create & verify Ecash credentials | ❌ |
| Validator | Sign & broadcast Nyx blockchain transactions, query the blockchain | ❌ |
The `Mixnet` module currently exposes the logic of two clients: the [websocket client](../clients/websocket), and the [socks client](../clients/socks5).
The `TcpProxy` module exposes functionality to set up client/server instances that expose a localhost TcpSocket to read/write to.
The `ClientPool` is a configurable pool of ephemeral clients which can be created as a background process and quickly grabbed.
@@ -22,7 +22,7 @@ The main functionality of exposed functions will be imported from `sdk/ffi/share
Furthermore, the `shared/` code makes sure that client access is thread-safe, and that client actions happen in blocking threads on the Rust side of the FFI boundary.
### Mixnet Module
## Mixnet Module
This is the basic mixnet component of the SDK, exposing client functionality with which people can build custom interfaces with the Mixnet. These functions are exposed to both Go and C/C++ via the `sdk/ffi/shared/` crate.
| `shared/lib.rs` function | Rust Function |
@@ -36,13 +36,13 @@ This is the basic mixnet component of the SDK, exposing client functionality wit
> We have also implemented `listen_for_incoming_internal()` which is a wrapper around the Mixnet client's `wait_for_messages()`. This is a helper method for listening out for and handling incoming messages.
#### Currently Unsupported Functionality
### Currently Unsupported Functionality
At the time of writing the following functionality is not exposed to the shared FFI library:
- `split_sender()`: the ability to [split a client into sender and receiver](./mixnet/examples/split-send) for concurrent send/receive.
- The use of [custom network topologies](./mixnet/examples/custom-topology).
- `Socks5::new()`: creation and use of the [socks5/4a/4 proxy client](./mixnet/examples/socks).
### TcpProxy Module
## TcpProxy Module
A connection abstraction which exposes a local TCP socket which developers are able to interact with basically as expected, being able to read/write to/from a bytestream, without really having to take into account the workings of the Mixnet/Sphinx/the [message-based](../concepts/messages) format of the underlying client.
<Callout type="info" emoji="️">
@@ -58,3 +58,6 @@ A connection abstraction which exposes a local TCP socket which developers are a
| `proxy_server_new_internal(upstream_address: &str, config_dir: &str, env: Option<String>)` | `NymProxyServer::new(upstream_address, config_dir, env)` |
| `proxy_server_run_internal()` | `NymProxyServer.run_with_shutdown()` |
| `proxy_server_address_internal()` | `NymProxyServer.nym_address()` |
## Client Pool
There are currently no FFI bindings for the Client Pool. This will be coming in the future. The bindings for the TcpProxy have been updated to be able to use the Client Pool under the hood, but the standalone Pool is not yet exposed to FFI.
@@ -29,7 +29,7 @@ async fn main() {
println!("Sending socks5-wrapped http request");
// Message should be sent through the mixnet, via socks5
// We don't expect to get anything, as there is no network requester on the other end
reqwest_client.get("https://nymtech.net").send().await.ok()
reqwest_client.get("https://nym.com").send().await.ok()
});
println!("Waiting for message");
@@ -112,3 +112,6 @@ Whether the `data` of a SURB request being empty is a feature or a bug is to be
You can find a few helper functions [here](./message-helpers.md) to help deal with this issue in the meantime.
> If you can think of a more succinct or different way of handling this do reach out - we're happy to hear other opinions
## Lots of `duplicate fragment received` messages
You might see a lot of `WARN` level logs about duplicate fragments in your logs, depending on the log level you're using. This occurs when a packet is retransmitted somewhere in the Mixnet, but then the original makes it to the destination client as well. This is not something to do with your client logic, but instead the state of the Mixnet.
@@ -1,4 +1,5 @@
{
"architecture": "Architecture",
"examples": "Examples"
"examples": "Examples",
"troubleshooting": "Troubleshooting"
}
@@ -13,7 +13,7 @@ The motivation behind the creation of the `TcpProxy` module is to allow develope
## Clients
Each of the sub-modules exposed by the `TcpProxy` deal with Nym clients in a different way.
- the `NymProxyClient` creates an ephemeral client per new TCP connection, which is closed according to the configurable timeout: we map one ephemeral client per TCP connection. This is to deal with multiple simultaneous streams. In the future, this will be superceded by a connection pool in order to speed up new connections.
- the `NymProxyClient` relies on the [`Client Pool`](../client-pool) to create clients and keep a certain number of them in reserve. If the amount of incoming TCP connections rises quicker than the Client Pool can create clients, or you have the pool size set to `0`, the `TcpProxyClient` creates an ephemeral client per new TCP connection, which is closed according to the configurable timeout: we map one ephemeral client per TCP connection. This is to deal with multiple simultaneous streams.
- the `NymProxyServer` has a single Nym client with a persistent identity.
## Framing
@@ -18,6 +18,8 @@ use tokio::net::TcpStream;
use tokio::signal;
use tokio_stream::StreamExt;
use tokio_util::codec;
use tokio_util::sync::CancellationToken;
use tracing_subscriber::{fmt, prelude::*, EnvFilter};
#[derive(Serialize, Deserialize, Debug)]
struct ExampleMessage {
@@ -26,6 +28,8 @@ struct ExampleMessage {
tcp_conn: i8,
}
// This example just starts off a bunch of Tcp connections on a loop to a remote endpoint: in this case the TcpListener behind the NymProxyServer instance on the echo server found in `nym/tools/echo-server/`. It pipes a few messages to it, logs the replies, and keeps track of the number of replies received per connection.
//
// To run:
// - run the echo server with `cargo run`
// - run this example with `cargo run --example tcp_proxy_multistream -- <ECHO_SERVER_NYM_ADDRESS> <ENV_FILE_PATH> <CLIENT_PORT>` e.g.
@@ -40,8 +44,13 @@ async fn main() -> anyhow::Result<()> {
// Nym client logging is very informative but quite verbose.
// The Message Decay related logging gives you an ideas of the internals of the proxy message ordering: you need to switch
// to DEBUG to see the contents of the msg buffer, sphinx packet chunking, etc.
tracing_subscriber::fmt()
.with_max_level(tracing::Level::INFO)
tracing_subscriber::registry()
.with(fmt::layer())
.with(
EnvFilter::new("info")
.add_directive("nym_sdk::client_pool=info".parse().unwrap())
.add_directive("nym_sdk::tcp_proxy_client=debug".parse().unwrap()),
)
.init();
let env_path = env::args().nth(2).expect("Env file not specified");
@@ -49,23 +58,42 @@ async fn main() -> anyhow::Result<()> {
let listen_port = env::args().nth(3).expect("Port not specified");
// Within the TcpProxyClient, individual client shutdown is triggered by the timeout.
// Within the TcpProxyClient, individual client shutdown is triggered by the timeout. The final argument is how many clients to keep in reserve in the client pool when running the TcpProxy.
let proxy_client =
tcp_proxy::NymProxyClient::new(server, "127.0.0.1", &listen_port, 45, Some(env)).await?;
tcp_proxy::NymProxyClient::new(server, "127.0.0.1", &listen_port, 45, Some(env), 2).await?;
// For our disconnect() logic below
let proxy_clone = proxy_client.clone();
tokio::spawn(async move {
proxy_client.run().await?;
Ok::<(), anyhow::Error>(())
});
let example_cancel_token = CancellationToken::new();
let client_cancel_token = example_cancel_token.clone();
let watcher_cancel_token = example_cancel_token.clone();
// Cancel listener thread
tokio::spawn(async move {
signal::ctrl_c().await?;
println!(":: CTRL_C received, shutting down + cleanup up proxy server config files");
watcher_cancel_token.cancel();
proxy_clone.disconnect().await;
Ok::<(), anyhow::Error>(())
});
println!("waiting for everything to be set up..");
tokio::time::sleep(tokio::time::Duration::from_secs(5)).await;
println!("done. sending bytes");
// In the info traces you will see the different session IDs being set up, one for each TcpStream.
for i in 0..4 {
for i in 0..8 {
let client_cancel_inner_token = client_cancel_token.clone();
if client_cancel_token.is_cancelled() {
break;
}
let conn_id = i;
println!("Starting TCP connection {}", conn_id);
let local_tcp_addr = format!("127.0.0.1:{}", listen_port.clone());
tokio::spawn(async move {
// Now the client and server proxies are running we can create and pipe traffic to/from
@@ -81,7 +109,10 @@ async fn main() -> anyhow::Result<()> {
// Lets just send a bunch of messages to the server with variable delays between them, with a message and tcp connection ids to keep track of ordering on the server side (for illustrative purposes **only**; keeping track of anonymous replies is handled by the proxy under the hood with Single Use Reply Blocks (SURBs); for this illustration we want some kind of app-level message id, but irl most of the time you'll probably be parsing on e.g. the incoming response type instead)
tokio::spawn(async move {
for i in 0..4 {
for i in 0..8 {
if client_cancel_inner_token.is_cancelled() {
break;
}
let mut rng = SmallRng::from_entropy();
let delay: f64 = rng.gen_range(2.5..5.0);
tokio::time::sleep(tokio::time::Duration::from_secs_f64(delay)).await;
@@ -96,12 +127,7 @@ async fn main() -> anyhow::Result<()> {
.write_all(&serialised)
.await
.expect("couldn't write to stream");
println!(
">> client sent {}: {} bytes on conn {}",
&i,
msg.message_bytes.len(),
&conn_id
);
println!(">> client sent msg {} on conn {}", &i, &conn_id);
}
Ok::<(), anyhow::Error>(())
});
@@ -113,17 +139,8 @@ async fn main() -> anyhow::Result<()> {
while let Some(Ok(bytes)) = framed_read.next().await {
match bincode::deserialize::<ExampleMessage>(&bytes) {
Ok(msg) => {
println!(
"<< client received {}: {} bytes on conn {}",
msg.message_id,
msg.message_bytes.len(),
msg.tcp_conn
);
reply_counter += 1;
println!(
"tcp connection {} replies received {}/4",
msg.tcp_conn, reply_counter
);
println!("<< conn {} received {}/8", msg.tcp_conn, reply_counter);
}
Err(e) => {
println!("<< client received something that wasn't an example message of {} bytes. error: {}", bytes.len(), e);
@@ -138,15 +155,12 @@ async fn main() -> anyhow::Result<()> {
tokio::time::sleep(tokio::time::Duration::from_secs_f64(delay)).await;
}
// Once timeout is passed, you can either wait for graceful shutdown or just hard stop it.
signal::ctrl_c().await?;
println!("CTRL+C received, shutting down");
Ok(())
}
// emulate a series of small messages followed by a closing larger one
fn gen_bytes_fixed(i: usize) -> Vec<u8> {
let amounts = [10, 15, 50, 1000];
let amounts = [10, 15, 50, 1000, 10, 15, 500, 2000];
let len = amounts[i];
let mut rng = rand::thread_rng();
(0..len).map(|_| rng.gen::<u8>()).collect()
@@ -21,6 +21,8 @@ use tokio::net::{TcpListener, TcpStream};
use tokio::signal;
use tokio_stream::StreamExt;
use tokio_util::codec;
use tokio_util::sync::CancellationToken;
use tracing_subscriber::{fmt, prelude::*, EnvFilter};
#[derive(Serialize, Deserialize, Debug)]
struct ExampleMessage {
@@ -28,7 +30,14 @@ struct ExampleMessage {
message_bytes: Vec<u8>,
}
// This is a basic example which opens a single TCP connection and writes a bunch of messages between a client and an echo
// server, so only uses a single session under the hood and doesn't really show off the message ordering capabilities; this is mainly
// just a quick introductory illustration on how:
// - the mixnet does message ordering
// - the NymProxyClient and NymProxyServer can be hooked into and used to communicate between two otherwise pretty vanilla TcpStreams
//
// For a more irl example checkout tcp_proxy_multistream.rs
//
// Run this with:
// `cargo run --example tcp_proxy_single_connection <SERVER_LISTEN_PORT> <ENV_FILE_PATH> <CLIENT_LISTEN_PATH>` e.g.
// `cargo run --example tcp_proxy_single_connection 8081 ../../../envs/canary.env 8080 `
@@ -39,8 +48,9 @@ async fn main() -> anyhow::Result<()> {
// Comment this out to just see println! statements from this example, as Nym client logging is very informative but quite verbose.
// The Message Decay related logging gives you an ideas of the internals of the proxy message ordering. To see the contents of the msg buffer, sphinx packet chunking, etc change the tracing::Level to DEBUG.
tracing_subscriber::fmt()
.with_max_level(tracing::Level::INFO)
tracing_subscriber::registry()
.with(fmt::layer())
.with(EnvFilter::new("nym_sdk::tcp_proxy=info"))
.init();
let server_port = env::args()
@@ -63,10 +73,14 @@ async fn main() -> anyhow::Result<()> {
// We'll run the instance with a long timeout since we're sending everything down the same Tcp connection, so should be using a single session.
// Within the TcpProxyClient, individual client shutdown is triggered by the timeout.
// The final argument is how many clients to keep in reserve in the client pool when running the TcpProxy.
let proxy_client =
tcp_proxy::NymProxyClient::new(*proxy_nym_addr, "127.0.0.1", &client_port, 60, Some(env))
tcp_proxy::NymProxyClient::new(*proxy_nym_addr, "127.0.0.1", &client_port, 5, Some(env), 1)
.await?;
// For our disconnect() logic below
let proxy_clone = proxy_client.clone();
tokio::spawn(async move {
proxy_server.run_with_shutdown().await?;
Ok::<(), anyhow::Error>(())
@@ -77,10 +91,28 @@ async fn main() -> anyhow::Result<()> {
Ok::<(), anyhow::Error>(())
});
let example_cancel_token = CancellationToken::new();
let server_cancel_token = example_cancel_token.clone();
let client_cancel_token = example_cancel_token.clone();
let watcher_cancel_token = example_cancel_token.clone();
// Cancel listener thread
tokio::spawn(async move {
signal::ctrl_c().await?;
println!(":: CTRL_C received, shutting down + cleanup up proxy server config files");
fs::remove_dir_all(conf_path)?;
watcher_cancel_token.cancel();
proxy_clone.disconnect().await;
Ok::<(), anyhow::Error>(())
});
// 'Server side' thread: echo back incoming as response to the messages sent in the 'client side' thread below
tokio::spawn(async move {
let listener = TcpListener::bind(upstream_tcp_addr).await?;
loop {
if server_cancel_token.is_cancelled() {
break;
}
let (socket, _) = listener.accept().await.unwrap();
let (read, mut write) = socket.into_split();
let codec = codec::BytesCodec::new();
@@ -118,9 +150,9 @@ async fn main() -> anyhow::Result<()> {
Ok::<(), anyhow::Error>(())
});
// Just wait for Nym clients to connect, TCP clients to bind, etc.
// Just wait for Nym clients to connect, TCP clients to bind, etc. If there isn't a client in the pool (or you started it with 0) already then the TcpProxyClient just spins up an ephemeral client itself.
println!("waiting for everything to be set up..");
tokio::time::sleep(tokio::time::Duration::from_secs(5)).await;
tokio::time::sleep(tokio::time::Duration::from_secs(10)).await;
println!("done. sending bytes");
// Now the client and server proxies are running we can create and pipe traffic to/from
@@ -140,6 +172,9 @@ async fn main() -> anyhow::Result<()> {
tokio::spawn(async move {
let mut rng = SmallRng::from_entropy();
for i in 0..10 {
if client_cancel_token.is_cancelled() {
break;
}
let random_bytes = gen_bytes_fixed(i as usize);
let msg = ExampleMessage {
message_id: i,
@@ -179,15 +214,12 @@ async fn main() -> anyhow::Result<()> {
}
}
// Once timeout is passed, you can either wait for graceful shutdown or just hard stop it.
signal::ctrl_c().await?;
println!(":: CTRL+C received, shutting down + cleanup up proxy server config files");
fs::remove_dir_all(conf_path)?;
Ok(())
}
fn gen_bytes_fixed(i: usize) -> Vec<u8> {
let amounts = vec![1, 10, 50, 100, 150, 200, 350, 500, 750, 1000];
// let amounts = vec![1, 10, 50, 100, 150, 200, 350, 500, 750, 1000];
let amounts = [158, 1088, 505, 1001, 150, 200, 3500, 500, 750, 100];
let len = amounts[i];
let mut rng = rand::thread_rng();
(0..len).map(|_| rng.gen::<u8>()).collect()
@@ -0,0 +1,4 @@
# Troubleshooting
## Lots of `duplicate fragment received` messages
You might see a lot of `WARN` level logs about duplicate fragments in your logs, depending on the log level you're using. This occurs when a packet is retransmitted somewhere in the Mixnet, but then the original makes it to the destination client as well. This is not something to do with your client logic, but instead the state of the Mixnet.
@@ -39,6 +39,8 @@ Options:
Listen port [default: 8080]
-e, --env-path <ENV_PATH>
Optional env filepath - if none is supplied then the proxy defaults to using mainnet else just use a path to one of the supplied files in envs/ e.g. ./envs/sandbox.env
--client-pool-reserve <CLIENT_POOL_RESERVE>
How many clients to have running in reserve for quick access by incoming connections [default: 2]
-h, --help
Print help
```
@@ -1,5 +1,11 @@
import { Callout } from 'nextra/components'
# Cosmos Kit
<Callout type="warning">
The Typescript SDK is currently undergoing maintenance: a network upgrade elsewhere has temporarily caused a problem. These docs are likely to change after we upgrade the SDK.
</Callout>
The wonderful people of Cosmology have made some [fantastic components](https://cosmoskit.com/) that can be used with
Nym. These include:
@@ -17,7 +23,7 @@ npm create vite@latest
During the environment setup, choose React and subsequently opt for Typescript if you want your application to function smoothly following this tutorial. Next, navigate to your application directory and run the following commands:
```bash
cd < YOUR_APP >
npm i
npm i
npm run dev
```
@@ -57,7 +63,7 @@ export default defineConfig({
Your components have to be wrapped into a [ChainProvider](https://docs.cosmoskit.com/chain-provider),
in order to use the `useChain('nyx')` hook. The nyx chain is provided in the 'chain-registry' NPM package by default.
Now, go to the `src` folder and open your `App.tsx` file to replace all the code with the following, which will allow you to connect and disconnect a Ledger or Keplr wallet to Nyx:
Now, go to the `src` folder and open your `App.tsx` file to replace all the code with the following, which will allow you to connect and disconnect a Ledger or Keplr wallet to Nyx:
```ts
import "./App.css";
@@ -68,7 +74,7 @@ import { wallets as ledger } from '@cosmos-kit/ledger';
import { wallets as keplr } from '@cosmos-kit/keplr';
import { AminoMsg, makeSignDoc } from '@cosmjs/amino';
import { MsgSend } from 'cosmjs-types/cosmos/bank/v1beta1/tx';
export const getDoc = (address: string) => {
const chainId = 'nyx';
const msg: AminoMsg = {
@@ -89,28 +95,28 @@ export const getDoc = (address: string) => {
const doc = makeSignDoc([msg], fee, chainId, memo, accountNumber, sequence);
return doc
};
function MyComponent() {
const {wallet, address, connect, disconnect, getOfflineSignerAmino } =
useChain('nyx');
React.useEffect(() => {
connect();
disconnect();
}, []);
const sign = async () => {
if (!address) return
const doc = getDoc(address);
return getOfflineSignerAmino().signAmino(address, doc);
};
return (
<div>
<div>
<div>
{wallet &&
<div>
<div>Connected to {wallet?.prettyName} </div>
{wallet &&
<div>
<div>Connected to {wallet?.prettyName} </div>
<div>Address: <code>{address}</code></div>
</div>}
</div>
@@ -126,7 +132,7 @@ function MyComponent() {
</div>
);
}
export default function App() {
const assetsFixedUp = React.useMemo(() => {
const nyx = assets.find((a) => a.chain_name === 'nyx');
@@ -139,7 +145,7 @@ export default function App() {
}
return assets;
}, [assets]);
return (
<ChainProvider
chains={[chains.find((c) => c.chain_id === 'nyx')!]}
@@ -149,10 +155,10 @@ export default function App() {
preferredSignType: () => 'amino',
}}
>
<MyComponent/>
</ChainProvider>
)
}
```
@@ -1,7 +1,9 @@
import { Callout } from 'nextra/components';
# `mixFetch`
<Callout type="warning">
The Typescript SDK is currently undergoing maintenance: a network upgrade elsewhere has temporarily caused a problem. These docs are likely to change after we upgrade the SDK.
</Callout>
An easy way to secure parts or all of your web app is to replace calls to [`fetch`](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch) with `mixFetch`:
MixFetch works the same as vanilla `fetch` as it's a proxied wrapper around the original function.
@@ -15,7 +17,7 @@ Sounds great, are there any catches? Well, there are a few (for now):
- For now, `mixFetch` cannot deal with concurrent requests with the same base URL.
Read [this article](https://blog.nymtech.net/mixfetch-like-the-fetch-api-but-via-the-mixnet-82acfd435c62) to learn more.
Read [this article](https://blog.nym.com/mixfetch-like-the-fetch-api-but-via-the-mixnet-82acfd435c62) to learn more.
<Callout type="info" emoji="️">
Right now Gateways are not required to run a Secure Websocket (WSS) listener, so only a subset of nodes running in Gateway mode have configured their nodes to do so.
@@ -35,9 +37,9 @@ curl -X 'GET' \
import type { SetupMixFetchOps } from '@nymproject/mix-fetch';
const mixFetchOptions: SetupMixFetchOps = {
preferredGateway: '6Gb7ftQdKveMjPyrxDXeAtfYAX7Zg5mVZHtnRC5MmZ1B', // with WSS
preferredGateway: '23A7CSaBSA2L67PWuFTPXUnYrCdyVcB7ATYsjUsfdftb', // with WSS
preferredNetworkRequester:
'8rRGWy54oC8drFL9DepMegBt2DLrsqQwCoHMXt9nsnTo.2XjCPVbb4FpQ9hNRcXwb9mTzEAVVk1zf1tcch3wdtNEA@6Gb7ftQdKveMjPyrxDXeAtfYAX7Zg5mVZHtnRC5MmZ1B',
'HuNL1pFprNSKW6jdqppibXP5KNKCNJxDh7ivpYcoULN9.C62NahRTUf6kqpNtDVHXoVriQr6yyaU5LtxdgpbsGrtA@23A7CSaBSA2L67PWuFTPXUnYrCdyVcB7ATYsjUsfdftb',
mixFetchOverride: {
requestTimeoutMs: 60_000,
},
@@ -90,9 +92,9 @@ import { mixFetch, SetupMixFetchOps } from '@nymproject/mix-fetch-full-fat';
import React from 'react';
const mixFetchOptions: SetupMixFetchOps = {
preferredGateway: '6Gb7ftQdKveMjPyrxDXeAtfYAX7Zg5mVZHtnRC5MmZ1B', // with WSS
preferredGateway: '23A7CSaBSA2L67PWuFTPXUnYrCdyVcB7ATYsjUsfdftb', // with WSS
preferredNetworkRequester:
'8rRGWy54oC8drFL9DepMegBt2DLrsqQwCoHMXt9nsnTo.2XjCPVbb4FpQ9hNRcXwb9mTzEAVVk1zf1tcch3wdtNEA@6Gb7ftQdKveMjPyrxDXeAtfYAX7Zg5mVZHtnRC5MmZ1B',
'HuNL1pFprNSKW6jdqppibXP5KNKCNJxDh7ivpYcoULN9.C62NahRTUf6kqpNtDVHXoVriQr6yyaU5LtxdgpbsGrtA@23A7CSaBSA2L67PWuFTPXUnYrCdyVcB7ATYsjUsfdftb',
mixFetchOverride: {
requestTimeoutMs: 60_000,
},
@@ -104,7 +106,7 @@ export function HttpGET() {
const [html, setHtml] = React.useState('');
async function get() {
//Make sure the URL is whitelisted (see 'standard allowed list') otherwise you will get a network requester filter check error
const response = await mixFetch('https://nymtech.net/favicon.svg', { mode: 'unsafe-ignore-cors' }, mixFetchOptions);
const response = await mixFetch('https://nym.com/favicon.svg', { mode: 'unsafe-ignore-cors' }, mixFetchOptions);
const text = await response.text();
console.log('response was', text);
setHtml(html);
@@ -1,7 +1,9 @@
import { Callout } from 'nextra/components'
# Mixnet Client
<Callout type="warning">
The Typescript SDK is currently undergoing maintenance: a network upgrade elsewhere has temporarily caused a problem. These docs are likely to change after we upgrade the SDK.
</Callout>
As you know by now, in order to send or receive messages over the mixnet, you'll need to use the [`SDK Client`](https://www.npmjs.com/package/@nymproject/sdk), which will allow you to create apps that can use the Nym mixnet and Coconut credentials.
This client is message based - it can only send a one-way message to another client's address.
@@ -1,7 +1,9 @@
import { Callout } from 'nextra/components'
# Nym Smart Contract Clients
<Callout type="warning">
The Typescript SDK is currently undergoing maintenance: a network upgrade elsewhere has temporarily caused a problem. These docs are likely to change after we upgrade the SDK.
</Callout>
As previously mentioned, to query or execute on any of the Nym contracts, you'll need to use one of the [`Contract Clients`](https://www.npmjs.com/package/@nymproject/contract-clients), which contains read-only query and signing clients for all of Nym's smart contracts.
##### Contract Clients list
@@ -29,14 +31,14 @@ npm create vite@latest
During the environment setup, choose React and subsequently opt for Typescript if you want your application to function smoothly following this tutorial. Next, navigate to your application directory and run the following commands:
```bash
cd < YOUR_APP >
npm i
npm i
npm run dev
```
##### Installation
Install the packages and their dependencies if you don't already have them:
```bash
npm install @nymproject/contract-clients @cosmjs/cosmwasm-stargate
npm install @nymproject/contract-clients @cosmjs/cosmwasm-stargate
```
## Query clients
@@ -143,7 +145,7 @@ import { SigningCosmWasmClient } from "@cosmjs/cosmwasm-stargate";
import { DirectSecp256k1HdWallet } from "@cosmjs/proto-signing";
import { GasPrice } from "@cosmjs/stargate";
import { settings } from "./settings";
export default function Exec() {
let signer: DirectSecp256k1HdWallet;
let signerMixnetClient: any;
@@ -153,7 +155,7 @@ export default function Exec() {
let nodeAddress: string;
let amountToSend: string;
let delegations: any;
async function ExecuteOnNyx() {
// Cosmos client
signer = await DirectSecp256k1HdWallet.fromMnemonic(settings.mnemonic, {
@@ -168,7 +170,7 @@ export default function Exec() {
);
// Save globally
cosmWasmSigningClient = cosmWasmClient;
// Nym client
const mixnetClient = new contracts.Mixnet.MixnetClient(
cosmWasmSigningClient,
@@ -177,9 +179,9 @@ export default function Exec() {
);
// Save globally
signerMixnetClient = mixnetClient;
}
// Get delegations
const getDelegations = async () => {
if (!signerMixnetClient) {
@@ -190,7 +192,7 @@ export default function Exec() {
});
delegations = delegationsObject;
};
// Make delegation
const doDelegation = async () => {
if (!signerMixnetClient) {
@@ -204,7 +206,7 @@ export default function Exec() {
);
console.log(res);
};
// Undelegate all
const doUndelegateAll = async () => {
for (const delegation of delegations.delegations) {
@@ -214,7 +216,7 @@ export default function Exec() {
);
}
};
// Sending tokens
const doSendTokens = async () => {
const memo = "test sending tokens";
@@ -227,10 +229,10 @@ export default function Exec() {
);
console.log(res);
};
ExecuteOnNyx();
setTimeout(() => getDelegations(), 1000);
return (
<div>
<p>Exec</p>
@@ -43,7 +43,7 @@ npm install @nymproject/sdk-full-fat
The Nyx blockchain is a general-purpose CosmWasm-enabled smart contract platform, and the home of the smart contracts which keep track of the mixnet, amongst others.
Further information about the chain can be found on the [Nyx blockchain explorer](https://nym.explorers.guru/).
Using the [Nym mixnet smart contract clients](../../network/architecture/nyx/smart-contracts), you will be able to query contract states or execute methods when providing a signing key.
Using the [Nym mixnet smart contract clients](../../network/architecture/nyx#smart-contracts), you will be able to query contract states or execute methods when providing a signing key.
*You can learn about our different methods to interact with the chain [here](../chain)*.
@@ -1,10 +1,15 @@
import "@interchain-ui/react/styles"
import { CosmosKit } from "../../../../components/cosmos-kit";
import { Callout } from 'nextra/components'
import FormattedCosmoskitExampleCode from '../../../../code-examples/sdk/typescript/cosmoskit-example-code.mdx';
# Cosmos Kit
import { Callout } from 'nextra/components'
<Callout type="warning">
The Typescript SDK is currently undergoing maintenance: a network upgrade elsewhere has temporarily caused a problem. These docs are likely to change after we upgrade the SDK.
</Callout>
Below is an example that uses [CosmosKit](https://cosmoskit.com/) to connect and sign a fake transaction with your [Keplr wallet](https://www.keplr.app/) or
[Ledger hardware wallet](https://www.ledger.com/) to this page:

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