Compare commits

..

15 Commits

Author SHA1 Message Date
Jędrzej Stuczyński b2d77aedd3 added additional logs 2024-08-22 11:07:49 +01:00
Jędrzej Stuczyński 58dcf2171c make sure to always create available_bandwidth row for new clients 2024-08-22 10:47:22 +01:00
Bogdan-Ștefan Neacşu a6ad6c7d49 Sync last_seen_bandwidth immediately (#4774) 2024-08-21 14:17:01 +02:00
Jędrzej Stuczyński cbc977c491 Merge pull request #4773 from nymtech/feature/additional-ecash-nym-cli-utils
Feature/additional ecash nym cli utils
2024-08-21 09:36:47 +01:00
Jędrzej Stuczyński f40c05a34c fixed incorrect propagation of client_id in the sdk 2024-08-20 17:01:43 +01:00
Jędrzej Stuczyński 776443131e fixed full display being always printed 2024-08-20 16:57:18 +01:00
Bogdan-Ștefan Neacşu b5eab7f07f Better storage error logging (#4772)
* Better storage error logging

* Print without including error returned to clients
2024-08-20 17:49:27 +02:00
Jędrzej Stuczyński eeeb4b3246 fixed incorrect assertion when validating maximum time between redemption 2024-08-20 16:43:36 +01:00
Jędrzej Stuczyński e3e4dc6db9 added an utility nym-cli command to output binary representation of ecash tickets 2024-08-20 16:31:00 +01:00
Jędrzej Stuczyński 461b7bcfb7 updated sandbox.env 2024-08-20 15:25:40 +01:00
Jędrzej Stuczyński bbf0d06583 updated constants depending on all 30 days expiration 2024-08-20 12:54:42 +01:00
Jędrzej Stuczyński 6393d6093f changed parsing of 'credential_data' when importing ticketbooks 2024-08-20 11:31:07 +01:00
benedettadavico c0ea599913 update changelog and version bump 2024-08-19 10:32:21 +02:00
benedetta davico 16d09a35ba Merge pull request #4764 from nymtech/bugfix/post-050-dkg
bugfix: make sure DKG parses data out of events if logs are empty
2024-08-16 13:46:15 +02:00
Jędrzej Stuczyński e6c5eddbe5 bugfix: make sure DKG parse data out of events if logs are empty
this will be the case on post 0.50 chains
2024-08-16 11:56:48 +01:00
818 changed files with 1888 additions and 37666 deletions
-7
View File
@@ -1,7 +0,0 @@
.git
.github
.gitignore
**/node_modules
**/target
dist
documentation
@@ -1,10 +1,9 @@
name: ci-sdk-docs-typescript
on:
workflow_dispatch:
pull_request:
paths:
- "documentation/"
- "sdk/typescript/**"
- "wasm/**"
jobs:
@@ -29,7 +28,7 @@ jobs:
- name: Set up Go
uses: actions/setup-go@v4
with:
go-version: "1.20"
go-version: '1.20'
- name: Install wasm-pack
run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
@@ -37,7 +36,7 @@ jobs:
- name: Install wasm-opt
uses: ./.github/actions/install-wasm-opt
with:
version: "116"
version: '116'
- name: Build branch WASM packages
run: make sdk-wasm-build
+1 -4
View File
@@ -48,7 +48,4 @@ foxyfox.env
.next
ppa-private-key.b64
ppa-private-key.asc
nym-network-monitor/topology.json
nym-network-monitor/__pycache__
nym-network-monitor/*.key
ppa-private-key.asc
+32
View File
@@ -4,6 +4,38 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
## [Unreleased]
## [2024.10-caramello] (2024-08-19)
- bugfix: make sure DKG parses data out of events if logs are empty ([#4764])
- Fix clippy on rustc beta toolchain ([#4746])
- Fix clippy for beta toolchain ([#4742])
- Disable testnet-manager on non-unix ([#4741])
- Don't set NYM_VPN_API to default ([#4740])
- Update publish-nym-binaries.yml ([#4739])
- Update ci-build-upload-binaries.yml ([#4738])
- Add NYM_VPN_API to network config ([#4736])
- Re-export RecipientFormattingError in nym sdk ([#4735])
- Persist wireguard peers ([#4732])
- Fix tokio error in 1.39 ([#4730])
- Feature/vesting purge plus ranged cost params ([#4716])
- Fix (some) feature unification build failures ([#4681])
- Feature Compact Ecash : The One PR ([#4623])
[#4764]: https://github.com/nymtech/nym/pull/4764
[#4746]: https://github.com/nymtech/nym/pull/4746
[#4742]: https://github.com/nymtech/nym/pull/4742
[#4741]: https://github.com/nymtech/nym/pull/4741
[#4740]: https://github.com/nymtech/nym/pull/4740
[#4739]: https://github.com/nymtech/nym/pull/4739
[#4738]: https://github.com/nymtech/nym/pull/4738
[#4736]: https://github.com/nymtech/nym/pull/4736
[#4735]: https://github.com/nymtech/nym/pull/4735
[#4732]: https://github.com/nymtech/nym/pull/4732
[#4730]: https://github.com/nymtech/nym/pull/4730
[#4716]: https://github.com/nymtech/nym/pull/4716
[#4681]: https://github.com/nymtech/nym/pull/4681
[#4623]: https://github.com/nymtech/nym/pull/4623
## [2024.9-topdeck] (2024-07-26)
- chore: fix 1.80 lint issues ([#4731])
Generated
+83 -309
View File
@@ -332,29 +332,12 @@ dependencies = [
"winapi",
]
[[package]]
name = "autocfg"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0dde43e75fd43e8a1bf86103336bc699aa8d17ad1be60c76c0bdfd4828e19b78"
dependencies = [
"autocfg 1.3.0",
]
[[package]]
name = "autocfg"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
[[package]]
name = "autodoc"
version = "0.1.0"
dependencies = [
"env_logger 0.11.5",
"log",
]
[[package]]
name = "axum"
version = "0.6.20"
@@ -561,7 +544,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93f2635620bf0b9d4576eb7bb9a38a55df78bd1205d26fa994b25911a69f212f"
dependencies = [
"bitcoin_hashes",
"rand 0.8.5",
"rand",
"rand_core 0.6.4",
"serde",
"unicode-normalization",
@@ -1002,15 +985,6 @@ version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70"
[[package]]
name = "cloudabi"
version = "0.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
dependencies = [
"bitflags 1.3.2",
]
[[package]]
name = "colorchoice"
version = "1.0.1"
@@ -1866,7 +1840,6 @@ dependencies = [
"lock_api",
"once_cell",
"parking_lot_core 0.9.10",
"serde",
]
[[package]]
@@ -2193,16 +2166,6 @@ dependencies = [
"cfg-if",
]
[[package]]
name = "env_filter"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4f2c92ceda6ceec50f43169f9ee8424fe2db276791afde7b2cd8bc084cb376ab"
dependencies = [
"log",
"regex",
]
[[package]]
name = "env_logger"
version = "0.7.1"
@@ -2226,19 +2189,6 @@ dependencies = [
"regex",
]
[[package]]
name = "env_logger"
version = "0.11.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e13fa619b91fb2381732789fc5de83b45675e882f66623b7d8cb4f643017018d"
dependencies = [
"anstream",
"anstyle",
"env_filter",
"humantime 2.1.0",
"log",
]
[[package]]
name = "equivalent"
version = "1.0.1"
@@ -2272,7 +2222,7 @@ checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
[[package]]
name = "explorer-api"
version = "1.1.38"
version = "1.1.39"
dependencies = [
"chrono",
"clap 4.5.7",
@@ -2291,8 +2241,8 @@ dependencies = [
"nym-validator-client",
"okapi",
"pretty_env_logger",
"rand 0.8.5",
"rand_pcg 0.3.1",
"rand",
"rand_pcg",
"rand_seeder",
"reqwest 0.12.4",
"rocket",
@@ -2429,12 +2379,6 @@ dependencies = [
"windows-sys 0.52.0",
]
[[package]]
name = "fixedbitset"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
[[package]]
name = "flate2"
version = "1.0.30"
@@ -2497,12 +2441,6 @@ dependencies = [
"libc",
]
[[package]]
name = "fuchsia-cprng"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
[[package]]
name = "funty"
version = "2.0.0"
@@ -3383,7 +3321,7 @@ version = "1.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
dependencies = [
"autocfg 1.3.0",
"autocfg",
"hashbrown 0.12.3",
"serde",
]
@@ -3798,7 +3736,7 @@ version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17"
dependencies = [
"autocfg 1.3.0",
"autocfg",
"scopeguard",
]
@@ -3925,7 +3863,7 @@ version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a"
dependencies = [
"autocfg 1.3.0",
"autocfg",
]
[[package]]
@@ -3995,7 +3933,7 @@ dependencies = [
"nym-ordered-buffer",
"nym-service-providers-common",
"nym-socks5-requests",
"rand 0.8.5",
"rand",
"serde",
"serde-wasm-bindgen 0.6.5",
"thiserror",
@@ -4211,7 +4149,7 @@ version = "0.2.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
dependencies = [
"autocfg 1.3.0",
"autocfg",
"libm",
]
@@ -4242,7 +4180,7 @@ checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3"
[[package]]
name = "nym-api"
version = "1.1.42"
version = "1.1.43"
dependencies = [
"anyhow",
"async-trait",
@@ -4291,13 +4229,12 @@ dependencies = [
"nym-sphinx",
"nym-task",
"nym-topology",
"nym-types",
"nym-validator-client",
"nym-vesting-contract-common",
"okapi",
"pin-project",
"rand 0.8.5",
"rand_chacha 0.3.1",
"rand",
"rand_chacha",
"reqwest 0.12.4",
"rocket",
"rocket_cors",
@@ -4383,7 +4320,7 @@ dependencies = [
"nym-types",
"nym-wireguard",
"nym-wireguard-types",
"rand 0.8.5",
"rand",
"serde",
"serde_json",
"thiserror",
@@ -4400,7 +4337,7 @@ dependencies = [
"bincode",
"nym-sphinx",
"nym-wireguard-types",
"rand 0.8.5",
"rand",
"serde",
]
@@ -4418,7 +4355,7 @@ dependencies = [
"nym-ecash-time",
"nym-network-defaults",
"nym-validator-client",
"rand 0.8.5",
"rand",
"thiserror",
"url",
"zeroize",
@@ -4464,7 +4401,7 @@ dependencies = [
[[package]]
name = "nym-cli"
version = "1.1.40"
version = "1.1.41"
dependencies = [
"anyhow",
"base64 0.13.1",
@@ -4492,11 +4429,12 @@ name = "nym-cli-commands"
version = "1.0.0"
dependencies = [
"anyhow",
"base64 0.13.1",
"base64 0.21.7",
"bip39",
"bs58 0.5.1",
"cfg-if",
"clap 4.5.7",
"colored",
"comfy-table 6.2.0",
"cosmrs 0.17.0-pre",
"cosmwasm-std",
@@ -4529,21 +4467,21 @@ dependencies = [
"nym-types",
"nym-validator-client",
"nym-vesting-contract-common",
"rand 0.6.5",
"rand",
"serde",
"serde_json",
"tap",
"thiserror",
"time",
"tokio",
"toml 0.5.11",
"toml 0.8.14",
"url",
"zeroize",
]
[[package]]
name = "nym-client"
version = "1.1.39"
version = "1.1.40"
dependencies = [
"bs58 0.5.1",
"clap 4.5.7",
@@ -4566,7 +4504,7 @@ dependencies = [
"nym-task",
"nym-topology",
"nym-validator-client",
"rand 0.8.5",
"rand",
"serde",
"serde_json",
"tap",
@@ -4617,8 +4555,7 @@ dependencies = [
"nym-task",
"nym-topology",
"nym-validator-client",
"rand 0.8.5",
"rand_chacha 0.3.1",
"rand",
"serde",
"serde_json",
"sha2 0.10.8",
@@ -4698,7 +4635,7 @@ dependencies = [
"nym-bin-common",
"nym-node-tester-utils",
"nym-node-tester-wasm",
"rand 0.8.5",
"rand",
"serde",
"serde-wasm-bindgen 0.6.5",
"serde_json",
@@ -4735,8 +4672,8 @@ dependencies = [
"itertools 0.13.0",
"nym-dkg",
"nym-pemstore",
"rand 0.8.5",
"rand_chacha 0.3.1",
"rand",
"rand_chacha",
"serde",
"serde_derive",
"sha2 0.9.9",
@@ -4782,7 +4719,7 @@ dependencies = [
"itertools 0.12.1",
"nym-network-defaults",
"nym-pemstore",
"rand 0.8.5",
"rand",
"rayon",
"serde",
"sha2 0.9.9",
@@ -4876,7 +4813,7 @@ dependencies = [
"nym-ecash-time",
"nym-network-defaults",
"nym-validator-client",
"rand 0.8.5",
"rand",
"serde",
"thiserror",
"time",
@@ -4891,7 +4828,7 @@ dependencies = [
"nym-compact-ecash",
"nym-ecash-time",
"nym-network-defaults",
"rand 0.8.5",
"rand",
"serde",
"strum 0.25.0",
"thiserror",
@@ -4914,8 +4851,8 @@ dependencies = [
"hmac",
"nym-pemstore",
"nym-sphinx-types",
"rand 0.8.5",
"rand_chacha 0.3.1",
"rand",
"rand_chacha",
"serde",
"serde_bytes",
"subtle-encoding",
@@ -4937,8 +4874,8 @@ dependencies = [
"lazy_static",
"nym-contracts-common",
"nym-pemstore",
"rand 0.8.5",
"rand_chacha 0.3.1",
"rand",
"rand_chacha",
"rand_core 0.6.4",
"serde",
"serde_derive",
@@ -5068,7 +5005,7 @@ dependencies = [
"nym-wireguard",
"nym-wireguard-types",
"once_cell",
"rand 0.8.5",
"rand",
"serde",
"serde_json",
"si-scale",
@@ -5103,7 +5040,7 @@ dependencies = [
"nym-sphinx",
"nym-task",
"nym-validator-client",
"rand 0.8.5",
"rand",
"serde",
"si-scale",
"thiserror",
@@ -5132,7 +5069,7 @@ dependencies = [
"nym-crypto",
"nym-pemstore",
"nym-sphinx",
"rand 0.8.5",
"rand",
"serde",
"serde_json",
"thiserror",
@@ -5232,7 +5169,7 @@ name = "nym-inclusion-probability"
version = "0.1.0"
dependencies = [
"log",
"rand 0.8.5",
"rand",
"thiserror",
]
@@ -5245,7 +5182,7 @@ dependencies = [
"nym-bin-common",
"nym-crypto",
"nym-sphinx",
"rand 0.8.5",
"rand",
"serde",
"thiserror",
"time",
@@ -5282,7 +5219,7 @@ dependencies = [
"nym-types",
"nym-wireguard",
"nym-wireguard-types",
"rand 0.8.5",
"rand",
"reqwest 0.12.4",
"serde",
"serde_json",
@@ -5339,7 +5276,7 @@ dependencies = [
"humantime-serde",
"log",
"nym-contracts-common",
"rand_chacha 0.3.1",
"rand_chacha",
"schemars",
"serde",
"serde-json-wasm",
@@ -5382,7 +5319,7 @@ dependencies = [
"nym-topology",
"nym-types",
"nym-validator-client",
"rand 0.8.5",
"rand",
"serde",
"serde_json",
"sysinfo 0.27.8",
@@ -5415,7 +5352,7 @@ dependencies = [
"nym-sphinx-types",
"nym-task",
"nym-validator-client",
"rand 0.8.5",
"rand",
"serde",
"thiserror",
"time",
@@ -5450,39 +5387,9 @@ dependencies = [
"url",
]
[[package]]
name = "nym-network-monitor"
version = "0.1.0"
dependencies = [
"anyhow",
"axum 0.7.5",
"clap 4.5.7",
"dashmap",
"futures",
"log",
"nym-bin-common",
"nym-crypto",
"nym-network-defaults",
"nym-sdk",
"nym-sphinx",
"nym-topology",
"nym-types",
"nym-validator-client",
"petgraph",
"rand 0.8.5",
"rand_chacha 0.3.1",
"reqwest 0.12.4",
"serde",
"serde_json",
"tokio",
"tokio-util",
"utoipa",
"utoipa-swagger-ui",
]
[[package]]
name = "nym-network-requester"
version = "1.1.40"
version = "1.1.41"
dependencies = [
"addr",
"anyhow",
@@ -5515,7 +5422,7 @@ dependencies = [
"nym-types",
"pretty_env_logger",
"publicsuffix",
"rand 0.8.5",
"rand",
"regex",
"reqwest 0.12.4",
"serde",
@@ -5533,7 +5440,7 @@ dependencies = [
[[package]]
name = "nym-node"
version = "1.1.6"
version = "1.1.7"
dependencies = [
"anyhow",
"bip39",
@@ -5562,7 +5469,7 @@ dependencies = [
"nym-types",
"nym-wireguard",
"nym-wireguard-types",
"rand 0.8.5",
"rand",
"semver 1.0.23",
"serde",
"serde_json",
@@ -5596,7 +5503,7 @@ dependencies = [
"nym-task",
"nym-wireguard",
"nym-wireguard-types",
"rand 0.8.5",
"rand",
"serde_json",
"thiserror",
"time",
@@ -5623,7 +5530,7 @@ dependencies = [
"nym-exit-policy",
"nym-http-api-client",
"nym-wireguard-types",
"rand_chacha 0.3.1",
"rand_chacha",
"schemars",
"serde",
"serde_json",
@@ -5644,8 +5551,7 @@ dependencies = [
"nym-sphinx-params",
"nym-task",
"nym-topology",
"rand 0.8.5",
"rand_chacha 0.3.1",
"rand",
"serde",
"serde_json",
"thiserror",
@@ -5660,7 +5566,7 @@ dependencies = [
"futures",
"js-sys",
"nym-node-tester-utils",
"rand 0.8.5",
"rand",
"serde",
"serde-wasm-bindgen 0.6.5",
"thiserror",
@@ -5719,7 +5625,7 @@ dependencies = [
"fastrand 2.1.0",
"getrandom",
"log",
"rand 0.8.5",
"rand",
"rayon",
"sphinx-packet",
"thiserror",
@@ -5768,7 +5674,7 @@ dependencies = [
"nym-validator-client",
"parking_lot 0.12.3",
"pretty_env_logger",
"rand 0.8.5",
"rand",
"reqwest 0.12.4",
"tap",
"thiserror",
@@ -5808,7 +5714,7 @@ dependencies = [
[[package]]
name = "nym-socks5-client"
version = "1.1.39"
version = "1.1.40"
dependencies = [
"bs58 0.5.1",
"clap 4.5.7",
@@ -5828,7 +5734,7 @@ dependencies = [
"nym-sphinx",
"nym-topology",
"nym-validator-client",
"rand 0.8.5",
"rand",
"serde",
"serde_json",
"tap",
@@ -5861,7 +5767,7 @@ dependencies = [
"nym-task",
"nym-validator-client",
"pin-project",
"rand 0.8.5",
"rand",
"reqwest 0.12.4",
"schemars",
"serde",
@@ -5887,7 +5793,7 @@ dependencies = [
"nym-credential-storage",
"nym-crypto",
"nym-socks5-client-core",
"rand 0.8.5",
"rand",
"safer-ffi",
"serde",
"tokio",
@@ -5929,7 +5835,6 @@ version = "0.1.0"
dependencies = [
"log",
"nym-crypto",
"nym-metrics",
"nym-mixnet-contract-common",
"nym-sphinx-acknowledgements",
"nym-sphinx-addressing",
@@ -5942,8 +5847,7 @@ dependencies = [
"nym-sphinx-routing",
"nym-sphinx-types",
"nym-topology",
"rand 0.8.5",
"rand_chacha 0.3.1",
"rand",
"rand_distr",
"thiserror",
"tokio",
@@ -5961,7 +5865,7 @@ dependencies = [
"nym-sphinx-routing",
"nym-sphinx-types",
"nym-topology",
"rand 0.8.5",
"rand",
"serde",
"thiserror",
"zeroize",
@@ -5973,7 +5877,7 @@ version = "0.1.0"
dependencies = [
"nym-crypto",
"nym-sphinx-types",
"rand 0.8.5",
"rand",
"serde",
"thiserror",
]
@@ -5989,8 +5893,8 @@ dependencies = [
"nym-sphinx-routing",
"nym-sphinx-types",
"nym-topology",
"rand 0.8.5",
"rand_chacha 0.3.1",
"rand",
"rand_chacha",
"serde",
"thiserror",
"wasm-bindgen",
@@ -6000,17 +5904,12 @@ dependencies = [
name = "nym-sphinx-chunking"
version = "0.1.0"
dependencies = [
"dashmap",
"log",
"nym-crypto",
"nym-metrics",
"nym-sphinx-addressing",
"nym-sphinx-params",
"nym-sphinx-types",
"rand 0.8.5",
"serde",
"rand",
"thiserror",
"utoipa",
]
[[package]]
@@ -6026,7 +5925,7 @@ dependencies = [
"nym-sphinx-routing",
"nym-sphinx-types",
"nym-topology",
"rand 0.8.5",
"rand",
"thiserror",
]
@@ -6088,7 +5987,7 @@ dependencies = [
"argon2",
"generic-array 0.14.7",
"getrandom",
"rand 0.8.5",
"rand",
"serde",
"serde_json",
"thiserror",
@@ -6123,8 +6022,7 @@ dependencies = [
"nym-sphinx-addressing",
"nym-sphinx-routing",
"nym-sphinx-types",
"rand 0.8.5",
"reqwest 0.12.4",
"rand",
"semver 0.11.0",
"serde",
"serde_json",
@@ -6248,7 +6146,7 @@ dependencies = [
"nym-task",
"nym-validator-client",
"nyxd-scraper",
"rand_chacha 0.3.1",
"rand_chacha",
"serde",
"serde_with",
"sha2 0.10.8",
@@ -6321,12 +6219,13 @@ name = "nym-wireguard-types"
version = "0.1.0"
dependencies = [
"base64 0.21.7",
"dashmap",
"hmac",
"log",
"nym-config",
"nym-crypto",
"nym-network-defaults",
"rand 0.8.5",
"rand",
"serde",
"serde_json",
"sha2 0.10.8",
@@ -6337,7 +6236,7 @@ dependencies = [
[[package]]
name = "nymvisor"
version = "0.1.5"
version = "0.1.6"
dependencies = [
"anyhow",
"bytes",
@@ -6536,7 +6435,7 @@ dependencies = [
"once_cell",
"opentelemetry_api",
"percent-encoding",
"rand 0.8.5",
"rand",
"thiserror",
"tokio",
"tokio-stream",
@@ -6761,16 +6660,6 @@ dependencies = [
"sha2 0.10.8",
]
[[package]]
name = "petgraph"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db"
dependencies = [
"fixedbitset",
"indexmap 2.2.6",
]
[[package]]
name = "pin-project"
version = "1.1.5"
@@ -6859,7 +6748,7 @@ version = "2.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce"
dependencies = [
"autocfg 1.3.0",
"autocfg",
"bitflags 1.3.2",
"cfg-if",
"concurrent-queue",
@@ -7113,25 +7002,6 @@ version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09"
[[package]]
name = "rand"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca"
dependencies = [
"autocfg 0.1.8",
"libc",
"rand_chacha 0.1.1",
"rand_core 0.4.2",
"rand_hc",
"rand_isaac",
"rand_jitter",
"rand_os",
"rand_pcg 0.1.2",
"rand_xorshift",
"winapi",
]
[[package]]
name = "rand"
version = "0.8.5"
@@ -7139,20 +7009,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
dependencies = [
"libc",
"rand_chacha 0.3.1",
"rand_chacha",
"rand_core 0.6.4",
]
[[package]]
name = "rand_chacha"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef"
dependencies = [
"autocfg 0.1.8",
"rand_core 0.3.1",
]
[[package]]
name = "rand_chacha"
version = "0.3.1"
@@ -7163,21 +7023,6 @@ dependencies = [
"rand_core 0.6.4",
]
[[package]]
name = "rand_core"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
dependencies = [
"rand_core 0.4.2",
]
[[package]]
name = "rand_core"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc"
[[package]]
name = "rand_core"
version = "0.5.1"
@@ -7200,60 +7045,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32cb0b9bc82b0a0876c2dd994a7e7a2683d3e7390ca40e6886785ef0c7e3ee31"
dependencies = [
"num-traits",
"rand 0.8.5",
]
[[package]]
name = "rand_hc"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4"
dependencies = [
"rand_core 0.3.1",
]
[[package]]
name = "rand_isaac"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08"
dependencies = [
"rand_core 0.3.1",
]
[[package]]
name = "rand_jitter"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b"
dependencies = [
"libc",
"rand_core 0.4.2",
"winapi",
]
[[package]]
name = "rand_os"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071"
dependencies = [
"cloudabi",
"fuchsia-cprng",
"libc",
"rand_core 0.4.2",
"rdrand",
"winapi",
]
[[package]]
name = "rand_pcg"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44"
dependencies = [
"autocfg 0.1.8",
"rand_core 0.4.2",
"rand",
]
[[package]]
@@ -7274,15 +7066,6 @@ dependencies = [
"rand_core 0.6.4",
]
[[package]]
name = "rand_xorshift"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c"
dependencies = [
"rand_core 0.3.1",
]
[[package]]
name = "rayon"
version = "1.10.0"
@@ -7303,15 +7086,6 @@ dependencies = [
"crossbeam-utils",
]
[[package]]
name = "rdrand"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
dependencies = [
"rand_core 0.3.1",
]
[[package]]
name = "redox_syscall"
version = "0.2.16"
@@ -7569,7 +7343,7 @@ dependencies = [
"num_cpus",
"parking_lot 0.12.3",
"pin-project-lite",
"rand 0.8.5",
"rand",
"ref-cast",
"rocket_codegen",
"rocket_http",
@@ -8342,7 +8116,7 @@ version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67"
dependencies = [
"autocfg 1.3.0",
"autocfg",
]
[[package]]
@@ -8413,7 +8187,7 @@ dependencies = [
"hmac",
"lioness",
"log",
"rand 0.8.5",
"rand",
"rand_distr",
"sha2 0.10.8",
"subtle 2.5.0",
@@ -8957,7 +8731,7 @@ dependencies = [
"getrandom",
"peg",
"pin-project",
"rand 0.8.5",
"rand",
"reqwest 0.11.27",
"semver 1.0.23",
"serde",
@@ -9011,7 +8785,7 @@ dependencies = [
"nym-pemstore",
"nym-validator-client",
"nym-vesting-contract-common",
"rand 0.8.5",
"rand",
"serde",
"serde_json",
"sqlx",
@@ -9411,7 +9185,7 @@ dependencies = [
"indexmap 1.9.3",
"pin-project",
"pin-project-lite",
"rand 0.8.5",
"rand",
"slab",
"tokio",
"tokio-util",
@@ -9677,7 +9451,7 @@ dependencies = [
"http 0.2.12",
"httparse",
"log",
"rand 0.8.5",
"rand",
"rustls 0.21.12",
"sha1",
"thiserror",
@@ -9698,7 +9472,7 @@ dependencies = [
"http 1.1.0",
"httparse",
"log",
"rand 0.8.5",
"rand",
"rustls 0.22.4",
"rustls-pki-types",
"sha1",
@@ -10118,7 +9892,7 @@ dependencies = [
"nym-task",
"nym-topology",
"nym-validator-client",
"rand 0.8.5",
"rand",
"serde",
"serde-wasm-bindgen 0.6.5",
"thiserror",
@@ -10753,7 +10527,7 @@ dependencies = [
"nym-credentials",
"nym-crypto",
"nym-http-api-client",
"rand 0.8.5",
"rand",
"reqwest 0.12.4",
"serde",
"thiserror",
+1 -3
View File
@@ -14,6 +14,7 @@ panic = "abort"
opt-level = 3
[workspace]
resolver = "2"
members = [
"clients/native",
@@ -93,7 +94,6 @@ members = [
"common/wasm/utils",
"common/wireguard",
"common/wireguard-types",
"documentation/autodoc",
"explorer-api",
"explorer-api/explorer-api-requests",
"explorer-api/explorer-client",
@@ -106,7 +106,6 @@ members = [
"service-providers/common",
"service-providers/ip-packet-router",
"service-providers/network-requester",
"nym-network-monitor",
"nym-api",
"nym-browser-extension/storage",
"nym-api/nym-api-requests",
@@ -160,7 +159,6 @@ homepage = "https://nymtech.net"
documentation = "https://nymtech.net"
edition = "2021"
license = "Apache-2.0"
rust-version = "1.80"
[workspace.dependencies]
addr = "0.15.6"
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "nym-client"
version = "1.1.39"
version = "1.1.40"
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
@@ -422,7 +422,7 @@ impl Handler {
) {
// We don't want a crash in the connection handler to trigger a shutdown of the whole
// process.
task_client.disarm();
task_client.mark_as_success();
let ws_stream = match accept_async(socket).await {
Ok(ws_stream) => ws_stream,
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "nym-socks5-client"
version = "1.1.39"
version = "1.1.40"
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"
@@ -2,7 +2,9 @@
// SPDX-License-Identifier: Apache-2.0
use crate::error::BandwidthControllerError;
use crate::utils::{get_coin_index_signatures, get_expiration_date_signatures};
use crate::utils::{
get_aggregate_verification_key, get_coin_index_signatures, get_expiration_date_signatures,
};
use log::info;
use nym_credential_storage::storage::Storage;
use nym_credentials::ecash::bandwidth::IssuanceTicketBook;
@@ -55,7 +57,7 @@ where
))
}
pub async fn query_and_persist_required_global_signatures<S>(
pub async fn query_and_persist_required_global_data<S>(
storage: &S,
epoch_id: EpochId,
expiration_date: Date,
@@ -65,6 +67,10 @@ where
S: Storage,
<S as Storage>::StorageError: Send + Sync + 'static,
{
log::info!("Getting master verification key");
// this will also persist the key in the storage if was not there already
get_aggregate_verification_key(storage, epoch_id, apis.clone()).await?;
log::info!("Getting expiration date signatures");
// this will also persist the signatures in the storage if they were not there already
get_expiration_date_signatures(storage, epoch_id, expiration_date, apis.clone()).await?;
+4 -2
View File
@@ -16,7 +16,7 @@ use nym_credential_storage::models::RetrievedTicketbook;
use nym_credential_storage::storage::Storage;
use nym_credentials::ecash::bandwidth::CredentialSpendingData;
use nym_credentials_interface::{
AnnotatedCoinIndexSignature, AnnotatedExpirationDateSignature, NymPayInfo, VerificationKeyAuth,
AnnotatedCoinIndexSignature, AnnotatedExpirationDateSignature, VerificationKeyAuth,
};
use nym_ecash_time::Date;
use nym_validator_client::nym_api::EpochId;
@@ -165,7 +165,9 @@ impl<C, St: Storage> BandwidthController<C, St> {
.get_coin_index_signatures(epoch_id, &mut api_clients)
.await?;
let pay_info = NymPayInfo::generate(provider_pk);
let pay_info = retrieved_ticketbook
.ticketbook
.generate_pay_info(provider_pk);
let spend_request = retrieved_ticketbook.ticketbook.prepare_for_spending(
&verification_key,
-1
View File
@@ -19,7 +19,6 @@ futures = { workspace = true }
humantime-serde = { workspace = true }
log = { workspace = true }
rand = { workspace = true }
rand_chacha = { workspace = true }
serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true }
sha2 = { workspace = true }
@@ -455,7 +455,7 @@ where
Err(ClientCoreError::CustomGatewaySelectionExpected)
} else {
// and make sure to invalidate the task client so we wouldn't cause premature shutdown
shutdown.disarm();
shutdown.mark_as_success();
custom_gateway_transceiver.set_packet_router(packet_router)?;
Ok(custom_gateway_transceiver)
};
@@ -562,7 +562,7 @@ where
if topology_config.disable_refreshing {
// if we're not spawning the refresher, don't cause shutdown immediately
info!("The topology refesher is not going to be started");
shutdown.disarm();
shutdown.mark_as_success();
} else {
// don't spawn the refresher if we don't want to be refreshing the topology.
// only use the initial values obtained
@@ -458,7 +458,7 @@ impl PacketStatisticsControl {
fn report_rates(&self) {
if let Some((_, rates)) = self.rates.back() {
log::debug!("{}", rates.summary());
log::info!("{}", rates.summary());
log::debug!("{}", rates.detailed_summary());
}
}
@@ -486,7 +486,7 @@ impl PacketStatisticsControl {
// Check what the number of retransmissions was during the recording window
if let Some((_, start_stats)) = self.history.front() {
let delta = self.stats.clone() - start_stats.clone();
log::debug!(
log::info!(
"mix packet retransmissions/real mix packets: {}/{}",
delta.retransmissions_queued,
delta.real_packets_queued,
@@ -453,7 +453,6 @@ where
let mut pending_acks = Vec::with_capacity(fragments.len());
let mut real_messages = Vec::with_capacity(fragments.len());
debug!("Splitting message into {} fragments", fragments.len());
for fragment in fragments {
// we need to clone it because we need to keep it in memory in case we had to retransmit
// it. And then we'd need to recreate entire ACK again.
@@ -474,6 +474,13 @@ where
Poll::Ready(Some((real_messages, conn_id))) => {
log::trace!("handling real_messages: size: {}", real_messages.len());
// This is the last step in the pipeline where we know the type of the message, so
// lets count the number of retransmissions here.
if conn_id == TransmissionLane::Retransmission {
self.stats_tx
.report(PacketStatisticsEvent::RetransmissionQueued);
}
// First store what we got for the given connection id
self.transmission_buffer.store(&conn_id, real_messages);
let real_next = self.pop_next_message().expect("we just added one");
+18 -40
View File
@@ -46,34 +46,13 @@ const MEASUREMENTS: usize = 3;
const CONN_TIMEOUT: Duration = Duration::from_millis(1500);
const PING_TIMEOUT: Duration = Duration::from_millis(1000);
// The abstraction that some of these helpers use
pub trait ConnectableGateway {
fn identity(&self) -> &identity::PublicKey;
fn clients_address(&self) -> String;
fn is_wss(&self) -> bool;
}
impl ConnectableGateway for gateway::Node {
fn identity(&self) -> &identity::PublicKey {
self.identity()
}
fn clients_address(&self) -> String {
self.clients_address()
}
fn is_wss(&self) -> bool {
self.clients_wss_port.is_some()
}
}
struct GatewayWithLatency<'a, G: ConnectableGateway> {
gateway: &'a G,
struct GatewayWithLatency<'a> {
gateway: &'a gateway::Node,
latency: Duration,
}
impl<'a, G: ConnectableGateway> GatewayWithLatency<'a, G> {
fn new(gateway: &'a G, latency: Duration) -> Self {
impl<'a> GatewayWithLatency<'a> {
fn new(gateway: &'a gateway::Node, latency: Duration) -> Self {
GatewayWithLatency { gateway, latency }
}
}
@@ -151,14 +130,11 @@ async fn connect(endpoint: &str) -> Result<WsConn, ClientCoreError> {
JSWebsocket::new(endpoint).map_err(|_| ClientCoreError::GatewayJsConnectionFailure)
}
async fn measure_latency<G>(gateway: &G) -> Result<GatewayWithLatency<G>, ClientCoreError>
where
G: ConnectableGateway,
{
async fn measure_latency(gateway: &gateway::Node) -> Result<GatewayWithLatency, ClientCoreError> {
let addr = gateway.clients_address();
trace!(
"establishing connection to {} ({addr})...",
gateway.identity(),
gateway.identity_key,
);
let mut stream = connect(&addr).await?;
@@ -201,7 +177,7 @@ where
let count = results.len() as u64;
if count == 0 {
return Err(ClientCoreError::NoGatewayMeasurements {
identity: gateway.identity().to_base58_string(),
identity: gateway.identity_key.to_base58_string(),
});
}
@@ -211,11 +187,11 @@ where
Ok(GatewayWithLatency::new(gateway, avg))
}
pub async fn choose_gateway_by_latency<'a, R: Rng, G: ConnectableGateway + Clone>(
pub async fn choose_gateway_by_latency<R: Rng>(
rng: &mut R,
gateways: &[G],
gateways: &[gateway::Node],
must_use_tls: bool,
) -> Result<G, ClientCoreError> {
) -> Result<gateway::Node, ClientCoreError> {
let gateways = filter_by_tls(gateways, must_use_tls)?;
info!(
@@ -247,19 +223,21 @@ pub async fn choose_gateway_by_latency<'a, R: Rng, G: ConnectableGateway + Clone
info!(
"chose gateway {} with average latency of {:?}",
chosen.gateway.identity(),
chosen.latency
chosen.gateway.identity_key, chosen.latency
);
Ok(chosen.gateway.clone())
}
fn filter_by_tls<G: ConnectableGateway>(
gateways: &[G],
fn filter_by_tls(
gateways: &[gateway::Node],
must_use_tls: bool,
) -> Result<Vec<&G>, ClientCoreError> {
) -> Result<Vec<&gateway::Node>, ClientCoreError> {
if must_use_tls {
let filtered = gateways.iter().filter(|g| g.is_wss()).collect::<Vec<_>>();
let filtered = gateways
.iter()
.filter(|g| g.clients_wss_port.is_some())
.collect::<Vec<_>>();
if filtered.is_empty() {
return Err(ClientCoreError::NoWssGateways);
@@ -70,8 +70,8 @@ impl PacketRouter {
Ok(())
}
pub fn disarm(&mut self) {
self.shutdown.disarm();
pub fn mark_as_success(&mut self) {
self.shutdown.mark_as_success();
}
}
@@ -113,8 +113,8 @@ impl PartiallyDelegatedRouter {
let return_res = match ret {
Err(err) => self.stream_return.send(Err(err)),
Ok(_) => {
self.packet_router.disarm();
task_client.disarm();
self.packet_router.mark_as_success();
task_client.mark_as_success();
self.stream_return.send(Ok(split_stream))
}
};
@@ -90,6 +90,4 @@ default = ["http-client"]
http-client = ["cosmrs/rpc"]
generate-ts = []
contract-testing = ["nym-mixnet-contract-common/contract-testing"]
# Features below are added to make clippy happy, it seems like they're unused we should remove them
tendermint-rpc-http-client = ["tendermint-rpc/http-client"]
tendermint-rpc-websocket-client = ["tendermint-rpc/websocket-client"]
@@ -49,7 +49,5 @@ pub const COMPUTE_REWARD_ESTIMATION: &str = "compute-reward-estimation";
pub const AVG_UPTIME: &str = "avg_uptime";
pub const STAKE_SATURATION: &str = "stake-saturation";
pub const INCLUSION_CHANCE: &str = "inclusion-probability";
pub const SUBMIT_GATEWAY: &str = "submit-gateway-monitoring-results";
pub const SUBMIT_NODE: &str = "submit-node-monitoring-results";
pub const SERVICE_PROVIDERS: &str = "services";
@@ -1,6 +1,7 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::nyxd::cosmwasm_client::types::ExecuteResult;
use crate::nyxd::error::NyxdError;
use cosmrs::abci::TxMsgData;
use cosmrs::cosmwasm::MsgExecuteContractResponse;
@@ -9,7 +10,6 @@ use log::error;
use prost::bytes::Bytes;
use tendermint_rpc::endpoint::broadcast;
use crate::nyxd::cosmwasm_client::types::ExecuteResult;
pub use cosmrs::abci::MsgResponse;
pub fn parse_msg_responses(data: Bytes) -> Vec<MsgResponse> {
@@ -21,7 +21,8 @@ pub struct Log {
/// Searches in logs for the first event of the given event type and in that event
/// for the first attribute with the given attribute key.
pub fn find_attribute<'a>(
#[deprecated]
pub fn find_attribute_in_logs<'a>(
logs: &'a [Log],
event_type: &str,
attribute_key: &str,
@@ -35,6 +36,7 @@ pub fn find_attribute<'a>(
}
/// Search for the proposal id in the given log. It'll be in the LAST wasm event, with attribute key "proposal_id"
#[deprecated]
pub fn find_proposal_id(logs: &[Log]) -> Result<u64, NyxdError> {
let maybe_attributes = logs
.iter()
@@ -300,8 +300,8 @@ where
}
#[cfg(any(
feature = "tendermint-rpc-http-client",
feature = "tendermint-rpc-websocket-client"
feature = "tendermint-rpc/http-client",
feature = "tendermint-rpc/websocket-client"
))]
async fn wait_until_healthy<T>(&self, timeout: T) -> Result<(), Error>
where
@@ -1,12 +1,24 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::nyxd::cosmwasm_client::logs::Log;
use crate::nyxd::TxResponse;
use cosmrs::tendermint::abci;
pub use abci::Event;
// Searches in events for an event of the given event type which contains an
// attribute for with the given key.
pub fn find_tx_attribute(tx: &TxResponse, event_type: &str, attribute_key: &str) -> Option<String> {
let event = tx.tx_result.events.iter().find(|e| e.kind == event_type)?;
find_event_attribute(&tx.tx_result.events, event_type, attribute_key)
}
pub fn find_event_attribute(
events: &[Event],
event_type: &str,
attribute_key: &str,
) -> Option<String> {
let event = events.iter().find(|e| e.kind == event_type)?;
let attribute = event.attributes.iter().find(|&attr| {
if let Ok(key_str) = attr.key_str() {
key_str == attribute_key
@@ -16,3 +28,23 @@ pub fn find_tx_attribute(tx: &TxResponse, event_type: &str, attribute_key: &str)
})?;
Some(attribute.value_str().ok().map(|str| str.to_string())).flatten()
}
pub fn find_attribute_value_in_logs_or_events(
logs: &[Log],
events: &[Event],
event_type: &str,
attribute_key: &str,
) -> Option<String> {
// if logs are empty, i.e. we're using post 0.50 code, parse the events instead
if !logs.is_empty() {
#[allow(deprecated)]
return crate::nyxd::cosmwasm_client::logs::find_attribute_in_logs(
logs,
event_type,
attribute_key,
)
.map(|attr| attr.value.clone());
}
find_event_attribute(events, event_type, attribute_key)
}
@@ -820,8 +820,8 @@ where
}
#[cfg(any(
feature = "tendermint-rpc-http-client",
feature = "tendermint-rpc-websocket-client"
feature = "tendermint-rpc/http-client",
feature = "tendermint-rpc/websocket-client"
))]
async fn wait_until_healthy<T>(&self, timeout: T) -> Result<(), Error>
where
@@ -300,8 +300,8 @@ pub trait TendermintRpcClient {
}
#[cfg(any(
feature = "tendermint-rpc-http-client",
feature = "tendermint-rpc-websocket-client"
feature = "tendermint-rpc/http-client",
feature = "tendermint-rpc/websocket-client"
))]
/// Poll the `/health` endpoint until it returns a successful result or
/// the given `timeout` has elapsed.
@@ -518,8 +518,8 @@ mod non_wasm {
}
#[cfg(any(
feature = "tendermint-rpc-http-client",
feature = "tendermint-rpc-websocket-client"
feature = "tendermint-rpc/http-client",
feature = "tendermint-rpc/websocket-client"
))]
async fn wait_until_healthy<T>(&self, timeout: T) -> Result<(), Error>
where
+5 -4
View File
@@ -7,9 +7,10 @@ license.workspace = true
[dependencies]
anyhow = { workspace = true }
base64 = "0.13.0"
base64 = { workspace = true }
bip39 = { workspace = true }
bs58 = { workspace = true }
colored = { workspace = true }
comfy-table = { workspace = true }
cfg-if = { workspace = true }
clap = { workspace = true, features = ["derive"] }
@@ -21,13 +22,13 @@ humantime-serde = { workspace = true }
inquire = { workspace = true }
k256 = { workspace = true, features = ["ecdsa", "sha256"] }
log = { workspace = true }
rand = {version = "0.6", features = ["std"] }
rand = { workspace = true, features = ["std"] }
serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true }
thiserror = { workspace = true }
time = { workspace = true, features = ["parsing", "formatting"] }
tokio = { workspace = true, features = ["sync"]}
toml = "0.5.6"
tokio = { workspace = true, features = ["sync"] }
toml = { workspace = true }
url = { workspace = true }
tap = { workspace = true }
zeroize = { workspace = true }
@@ -0,0 +1,178 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::utils::CommonConfigsWrapper;
use anyhow::{anyhow, bail};
use clap::Parser;
use colored::Colorize;
use comfy_table::Table;
use nym_credential_storage::initialise_persistent_storage;
use nym_credential_storage::storage::Storage;
use nym_credentials::ecash::bandwidth::serialiser::VersionedSerialise;
use std::path::PathBuf;
#[derive(Debug, Parser)]
pub struct Args {
/// Specify the index of the ticket to retrieve from the ticketbook.
/// By default, the current unspent value is used.
#[clap(long, group = "output")]
pub(crate) ticket_index: Option<u64>,
/// Specify whether we should display payments for ALL available tickets
#[clap(long, group = "output")]
pub(crate) full: bool,
/// Base58-encoded identity of the provider (must be 32 bytes long)
#[clap(long)]
pub(crate) provider: String,
/// Config file of the client that is supposed to use the credential.
#[clap(long, group = "source")]
pub(crate) client_config: Option<PathBuf>,
/// Path to the dedicated credential storage database
#[clap(long, group = "source")]
pub(crate) credential_storage: Option<PathBuf>,
}
pub async fn execute(args: Args) -> anyhow::Result<()> {
let credentials_store = if let Some(explicit) = args.credential_storage {
explicit
} else {
// SAFETY: at least one of them MUST HAVE been specified
let cfg = args.client_config.unwrap();
let loaded = CommonConfigsWrapper::try_load(cfg)?;
if let Ok(id) = loaded.try_get_id() {
println!("loaded config file for client '{id}'");
}
let Ok(credentials_store) = loaded.try_get_credentials_store() else {
bail!("the loaded config does not have a credentials store information")
};
credentials_store
};
let decoded_provider = bs58::decode(&args.provider).into_vec()?;
if decoded_provider.len() != 32 {
bail!("the provided provider information is malformed")
}
let provider_arr: [u8; 32] = decoded_provider.try_into().unwrap();
let persistent_storage = initialise_persistent_storage(&credentials_store).await;
let Some(mut next_ticketbook) = persistent_storage
.get_next_unspent_usable_ticketbook(0)
.await?
else {
bail!(
"there are no valid ticketbooks in the storage at {}",
credentials_store.display()
)
};
let epoch_id = next_ticketbook.ticketbook.epoch_id();
let expiration_date = next_ticketbook.ticketbook.expiration_date();
let verification_key = persistent_storage
.get_master_verification_key(epoch_id)
.await?
.ok_or_else(|| {
anyhow!("ticketbook got incorrectly imported - the master verification key is missing")
})?;
let expiration_signatures = persistent_storage
.get_expiration_date_signatures(expiration_date)
.await?
.ok_or_else(|| {
anyhow!(
"ticketbook got incorrectly imported - the expiration date signatures are missing"
)
})?;
let coin_indices_signatures = persistent_storage
.get_coin_index_signatures(epoch_id)
.await?
.ok_or_else(|| {
anyhow!("ticketbook got incorrectly imported - the coin index signatures are missing")
})?;
let ticketbook_data = next_ticketbook.ticketbook.pack();
let next_ticket = args
.ticket_index
.unwrap_or(next_ticketbook.ticketbook.spent_tickets());
let pay_info = next_ticketbook.ticketbook.generate_pay_info(provider_arr);
println!("{}", "TICKETBOOK DATA:".bold());
println!("{}", bs58::encode(&ticketbook_data.data).into_string());
println!();
// display it only for a single ticket
if !args.full {
println!("attempting to generate payment for ticket {next_ticket}...");
println!();
next_ticketbook.ticketbook.update_spent_tickets(next_ticket);
let req = next_ticketbook.ticketbook.prepare_for_spending(
&verification_key,
pay_info.into(),
&coin_indices_signatures,
&expiration_signatures,
1,
)?;
let payment = req.payment;
println!("{}", format!("PAYMENT FOR TICKET {next_ticket}: ").bold());
println!("{}", bs58::encode(&payment.to_bytes()).into_string());
return Ok(());
}
println!(
"generating payment information for {} tickets. this might take a while!...",
next_ticketbook.ticketbook.params_total_tickets()
);
// otherwise generate all the payments
let last_spent = next_ticketbook.ticketbook.spent_tickets();
let mut table = Table::new();
table.set_header(vec!["index", "binary data", "spend status"]);
for i in 0..next_ticketbook.ticketbook.params_total_tickets() {
let status = if i < last_spent {
"SPENT".red()
} else {
"NOT SPENT".green()
};
next_ticketbook.ticketbook.update_spent_tickets(i);
let req = next_ticketbook.ticketbook.prepare_for_spending(
&verification_key,
pay_info.into(),
&coin_indices_signatures,
&expiration_signatures,
1,
)?;
let payment = req.payment;
let payment_bytes = payment.to_bytes();
let len = payment_bytes.len();
let display_size = 100;
let remaining = len - display_size;
table.add_row(vec![
i.to_string(),
format!(
"{}{remaining}bytes remaining",
bs58::encode(&payment_bytes[..display_size]).into_string()
),
status.to_string(),
]);
}
println!("{}", "AVAILABLE TICKETS".bold());
println!("{table}");
Ok(())
}
@@ -9,9 +9,17 @@ use nym_credential_storage::initialise_persistent_storage;
use nym_id::import_credential;
use std::fs;
use std::path::PathBuf;
use std::str::FromStr;
fn parse_encoded_credential_data(raw: &str) -> bs58::decode::Result<Vec<u8>> {
bs58::decode(raw).into_vec()
#[derive(Debug, Clone)]
pub struct CredentialDataWrapper(Vec<u8>);
impl FromStr for CredentialDataWrapper {
type Err = bs58::decode::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
bs58::decode(s).into_vec().map(CredentialDataWrapper)
}
}
#[derive(Debug, Parser)]
@@ -22,8 +30,8 @@ pub struct Args {
pub(crate) client_config: PathBuf,
/// Explicitly provide the encoded credential data (as base58)
#[clap(long, group = "cred_data", value_parser = parse_encoded_credential_data)]
pub(crate) credential_data: Option<Vec<u8>>,
#[clap(long, group = "cred_data")]
pub(crate) credential_data: Option<CredentialDataWrapper>,
/// Specifies the path to file containing binary credential data
#[clap(long, group = "cred_data")]
@@ -52,7 +60,7 @@ pub async fn execute(args: Args) -> anyhow::Result<()> {
let credentials_store = initialise_persistent_storage(credentials_store).await;
let raw_credential = match args.credential_data {
Some(data) => data,
Some(data) => data.0,
None => {
// SAFETY: one of those arguments must have been set
fs::read(args.credential_path.unwrap())?
@@ -9,6 +9,9 @@ use nym_credential_storage::initialise_persistent_storage;
use nym_credential_utils::utils;
use nym_credentials_interface::TicketType;
use nym_crypto::asymmetric::identity;
use rand::rngs::OsRng;
use rand::RngCore;
use std::fs::create_dir_all;
use std::path::PathBuf;
#[derive(Debug, Parser)]
@@ -18,12 +21,20 @@ pub struct Args {
pub(crate) ticketbook_type: TicketType,
/// Config file of the client that is supposed to use the credential.
#[clap(long)]
pub(crate) client_config: PathBuf,
#[clap(long, group = "output")]
pub(crate) client_config: Option<PathBuf>,
/// Path to the dedicated credential storage database
#[clap(long, group = "output")]
pub(crate) credential_storage: Option<PathBuf>,
}
pub async fn execute(args: Args, client: SigningClient) -> anyhow::Result<()> {
let loaded = CommonConfigsWrapper::try_load(args.client_config)?;
async fn issue_client_ticketbook(
cfg: PathBuf,
typ: TicketType,
client: SigningClient,
) -> anyhow::Result<()> {
let loaded = CommonConfigsWrapper::try_load(cfg)?;
if let Ok(id) = loaded.try_get_id() {
println!("loaded config file for client '{id}'");
@@ -48,9 +59,40 @@ pub async fn execute(args: Args, client: SigningClient) -> anyhow::Result<()> {
&client,
&persistent_storage,
&private_id_key.to_bytes(),
args.ticketbook_type,
typ,
)
.await?;
Ok(())
}
async fn issue_standalone_ticketbook(
credentials_store: PathBuf,
typ: TicketType,
client: SigningClient,
) -> anyhow::Result<()> {
println!("attempting to issue a standalone ticketbook");
let mut rng = OsRng;
let mut random_seed = [0u8; 32];
rng.fill_bytes(&mut random_seed);
if let Some(parent) = credentials_store.parent() {
create_dir_all(parent)?;
}
let persistent_storage = initialise_persistent_storage(credentials_store).await;
utils::issue_credential(&client, &persistent_storage, &random_seed, typ).await?;
Ok(())
}
pub async fn execute(args: Args, client: SigningClient) -> anyhow::Result<()> {
match (args.client_config, args.credential_storage) {
(Some(cfg), None) => issue_client_ticketbook(cfg, args.ticketbook_type, client).await,
(None, Some(storage)) => {
issue_standalone_ticketbook(storage, args.ticketbook_type, client).await
}
_ => unreachable!("clap should have made this branch impossible to reach!"),
}
}
@@ -3,6 +3,7 @@
use clap::{Args, Subcommand};
pub mod generate_ticket;
pub mod import_ticket_book;
pub mod issue_ticket_book;
pub mod recover_ticket_book;
@@ -19,4 +20,5 @@ pub enum EcashCommands {
IssueTicketBook(issue_ticket_book::Args),
RecoverTicketBook(recover_ticket_book::Args),
ImportTicketBook(import_ticket_book::Args),
GenerateTicket(generate_ticket::Args),
}
+1 -1
View File
@@ -1,7 +1,7 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
pub mod coconut;
pub mod context;
pub mod ecash;
pub mod utils;
pub mod validator;
@@ -10,7 +10,11 @@ pub struct Args {
}
pub fn decode_mixnode_key(args: Args) {
let b64_decoded = base64::decode(args.key).expect("failed to decode base64 string");
use base64::{engine::general_purpose::STANDARD, Engine as _};
let b64_decoded = STANDARD
.decode(args.key)
.expect("failed to decode base64 string");
let b58_encoded = bs58::encode(&b64_decoded).into_string();
println!("{b58_encoded}")
+5 -11
View File
@@ -3,9 +3,7 @@
use crate::errors::{Error, Result};
use log::*;
use nym_bandwidth_controller::acquire::{
get_ticket_book, query_and_persist_required_global_signatures,
};
use nym_bandwidth_controller::acquire::{get_ticket_book, query_and_persist_required_global_data};
use nym_client_core::config::disk_persistence::CommonClientPaths;
use nym_config::DEFAULT_DATA_DIR;
use nym_credential_storage::persistent_storage::PersistentStorage;
@@ -45,14 +43,10 @@ where
let apis = all_ecash_api_clients(client, epoch_id).await?;
let ticketbook_expiration = ecash_default_expiration_date();
// make sure we have all required coin indices and expiration date signatures before attempting the deposit
query_and_persist_required_global_signatures(
storage,
epoch_id,
ticketbook_expiration,
apis.clone(),
)
.await?;
// make sure we have all required coin indices and expiration date signatures alongside the master verification key
// before attempting the deposit
query_and_persist_required_global_data(storage, epoch_id, ticketbook_expiration, apis.clone())
.await?;
let issuance_data = nym_bandwidth_controller::acquire::make_deposit(
client,
@@ -6,7 +6,7 @@ use crate::ecash::bandwidth::CredentialSpendingData;
use crate::ecash::utils::ecash_today;
use crate::error::Error;
use nym_credentials_interface::{
CoinIndexSignature, ExpirationDateSignature, PayInfo, SecretKeyUser, TicketType,
CoinIndexSignature, ExpirationDateSignature, NymPayInfo, PayInfo, SecretKeyUser, TicketType,
VerificationKeyAuth, Wallet, WalletSignatures,
};
use nym_ecash_time::EcashTime;
@@ -114,6 +114,10 @@ impl IssuedTicketBook {
&self.signatures_wallet
}
pub fn generate_pay_info(&self, provider_pk: [u8; 32]) -> NymPayInfo {
NymPayInfo::generate(provider_pk)
}
pub fn prepare_for_spending<BI, BE>(
&mut self,
verification_key: &VerificationKeyAuth,
+5 -2
View File
@@ -37,10 +37,13 @@ impl BandwidthManager {
}
/// Creates a new bandwidth entry for the particular client.
pub(crate) async fn insert_new_client(&self, client_id: i64) -> Result<(), sqlx::Error> {
pub(crate) async fn insert_new_client_if_doesnt_exist(
&self,
client_id: i64,
) -> Result<(), sqlx::Error> {
// FIXME: hack; we need to change api slightly
sqlx::query!(
"INSERT INTO available_bandwidth(client_id, available, expiration) VALUES (?, 0, ?)",
"INSERT OR IGNORE INTO available_bandwidth(client_id, available, expiration) VALUES (?, 0, ?)",
client_id,
OffsetDateTime::UNIX_EPOCH,
)
+24 -2
View File
@@ -22,7 +22,7 @@ use tracing::{debug, error};
pub mod bandwidth;
pub mod error;
mod inboxes;
pub mod models;
pub(crate) mod models;
mod shared_keys;
mod tickets;
#[cfg(feature = "wireguard")]
@@ -35,6 +35,13 @@ pub trait Storage: Send + Sync {
client_address: DestinationAddressBytes,
) -> Result<i64, StorageError>;
/// Creates all relevant database entries for the newly registered client
async fn insert_new_client(
&self,
client_address: DestinationAddressBytes,
shared_keys: &SharedKeys,
) -> Result<i64, StorageError>;
/// Inserts provided derived shared keys into the database.
/// If keys previously existed for the provided client, they are overwritten with the new data.
///
@@ -322,6 +329,19 @@ impl Storage for PersistentStorage {
.await?)
}
async fn insert_new_client(
&self,
client_address: DestinationAddressBytes,
shared_keys: &SharedKeys,
) -> Result<i64, StorageError> {
let id = self.insert_shared_keys(client_address, shared_keys).await?;
self.bandwidth_manager
.insert_new_client_if_doesnt_exist(id)
.await?;
Ok(id)
}
async fn insert_shared_keys(
&self,
client_address: DestinationAddressBytes,
@@ -390,7 +410,9 @@ impl Storage for PersistentStorage {
}
async fn create_bandwidth_entry(&self, client_id: i64) -> Result<(), StorageError> {
self.bandwidth_manager.insert_new_client(client_id).await?;
self.bandwidth_manager
.insert_new_client_if_doesnt_exist(client_id)
.await?;
Ok(())
}
+1 -1
View File
@@ -57,7 +57,7 @@ impl PacketListener {
// 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();
handler_shutdown_listener.mark_as_success();
tokio::select! {
socket = listener.accept() => {
+1 -1
View File
@@ -245,7 +245,7 @@ impl VerlocMeasurer {
}
let mut shutdown_listener = self.shutdown_listener.clone().named("VerlocMeasurement");
shutdown_listener.disarm();
shutdown_listener.mark_as_success();
for chunk in nodes_to_test.chunks(self.config.tested_nodes_batch_size) {
let mut chunk_results = Vec::with_capacity(chunk.len());
+1 -1
View File
@@ -84,7 +84,7 @@ impl PacketSender {
tested_node: TestedNode,
) -> Result<VerlocMeasurement, RttError> {
let mut shutdown_listener = self.shutdown_listener.fork(tested_node.address.to_string());
shutdown_listener.disarm();
shutdown_listener.mark_as_success();
let mut conn = match tokio::time::timeout(
self.connection_timeout,
+1 -2
View File
@@ -9,12 +9,11 @@ license.workspace = true
[dependencies]
futures = { workspace = true }
rand = { workspace = true }
rand_chacha = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
thiserror = { workspace = true }
tokio = { workspace = true, features = ["macros"] }
tokio = { workspace = true, features = ["macros"]}
nym-crypto = { path = "../crypto", features = ["asymmetric"] }
nym-task = { path = "../task" }
-4
View File
@@ -294,8 +294,4 @@ impl<R: CryptoRng + Rng> FragmentPreparer for NodeTester<R> {
fn average_ack_delay(&self) -> Duration {
self.average_ack_delay
}
fn nonce(&self) -> i32 {
1
}
}
+3 -15
View File
@@ -11,7 +11,6 @@ repository = { workspace = true }
log = { workspace = true }
rand = { workspace = true }
rand_distr = { workspace = true }
rand_chacha = { workspace = true }
thiserror = { workspace = true }
nym-sphinx-acknowledgements = { path = "acknowledgements" }
@@ -28,13 +27,10 @@ nym-sphinx-types = { path = "types" }
# to separate crate?
nym-crypto = { path = "../crypto", version = "0.4.0" }
nym-topology = { path = "../topology" }
nym-metrics = { path = "../nym-metrics" }
[dev-dependencies]
nym-mixnet-contract-common = { path = "../cosmwasm-smart-contracts/mixnet-contract" }
nym-crypto = { path = "../crypto", version = "0.4.0", features = [
"asymmetric",
] }
nym-crypto = { path = "../crypto", version = "0.4.0", features = ["asymmetric"] }
# do not include this when compiling into wasm as it somehow when combined together with reqwest, it will require
# net2 via tokio-util -> tokio -> mio -> net2
@@ -47,13 +43,5 @@ features = ["sync"]
[features]
default = ["sphinx"]
sphinx = [
"nym-crypto/sphinx",
"nym-sphinx-params/sphinx",
"nym-sphinx-types/sphinx",
]
outfox = [
"nym-crypto/outfox",
"nym-sphinx-params/outfox",
"nym-sphinx-types/outfox",
]
sphinx = ["nym-crypto/sphinx", "nym-sphinx-params/sphinx", "nym-sphinx-types/sphinx"]
outfox = ["nym-crypto/outfox", "nym-sphinx-params/outfox", "nym-sphinx-types/outfox"]
-7
View File
@@ -13,14 +13,7 @@ repository = { workspace = true }
log = { workspace = true }
rand = { workspace = true }
thiserror = { workspace = true }
dashmap = { workspace = true, features = ["serde"] }
serde = { workspace = true, features = ["derive"] }
utoipa = { workspace = true }
nym-sphinx-addressing = { path = "../addressing" }
nym-sphinx-params = { path = "../params" }
nym-sphinx-types = { path = "../types" }
nym-metrics = { path = "../../nym-metrics" }
nym-crypto = { path = "../../crypto", version = "0.4.0", features = [
"asymmetric",
] }
+3 -31
View File
@@ -3,8 +3,6 @@
use crate::ChunkingError;
use nym_sphinx_params::{SerializedFragmentIdentifier, FRAG_ID_LEN};
use serde::Serialize;
use utoipa::ToSchema;
use std::fmt::{self, Debug, Formatter};
@@ -60,7 +58,7 @@ pub const COVER_FRAG_ID: FragmentIdentifier = FragmentIdentifier {
/// and u8 position of the `Fragment` in the set.
// TODO: this should really be redesigned, especially how cover and reply messages are really
// "abusing" this. They should work with it natively instead.
#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Ord, PartialOrd, Serialize)]
#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Ord, PartialOrd)]
pub struct FragmentIdentifier {
set_id: i32,
fragment_position: u8,
@@ -77,10 +75,6 @@ impl fmt::Display for FragmentIdentifier {
}
impl FragmentIdentifier {
pub fn set_id(&self) -> i32 {
self.set_id
}
pub fn to_bytes(self) -> SerializedFragmentIdentifier {
debug_assert_eq!(FRAG_ID_LEN, 5);
@@ -131,10 +125,6 @@ impl Debug for Fragment {
}
impl Fragment {
pub fn header(&self) -> FragmentHeader {
self.header.clone()
}
/// Tries to encapsulate provided payload slice and metadata into a `Fragment`.
/// It can fail if payload would not fully fit in a single `Fragment` or some of the metadata
/// is malformed or self-contradictory, for example if current_fragment > total_fragments.
@@ -226,10 +216,6 @@ impl Fragment {
}
}
pub fn seed(&self) -> i32 {
self.header().seed()
}
/// Gets the size of payload contained in this `Fragment`.
pub fn payload_size(&self) -> usize {
self.payload.len()
@@ -311,8 +297,8 @@ impl Fragment {
/// there is 7 bytes of overhead inside each sphinx packet sent
/// and for the longest messages, without upper bound, there is usually also only 7 bytes
/// of overhead apart from first and last fragments in each set that instead have 10 bytes of overhead.
#[derive(PartialEq, Clone, Debug, Serialize, ToSchema)]
pub struct FragmentHeader {
#[derive(PartialEq, Clone, Debug)]
pub(crate) struct FragmentHeader {
/// ID associated with `FragmentSet` to which this particular `Fragment` belongs.
/// Its value is restricted to (0, i32::MAX].
/// Note that it *excludes* 0, but *includes* i32::MAX.
@@ -338,20 +324,6 @@ pub struct FragmentHeader {
}
impl FragmentHeader {
pub fn seed(&self) -> i32 {
let mut seed = self.id;
seed = seed.wrapping_mul(self.total_fragments as i32);
seed = seed.wrapping_mul(self.current_fragment as i32);
seed
}
pub fn total_fragments(&self) -> u8 {
self.total_fragments
}
pub fn current_fragment(&self) -> u8 {
self.current_fragment
}
/// Tries to create a new `FragmentHeader` using provided metadata. Bunch of logical
/// checks are performed to see if the data is not self-contradictory,
/// for example if current_fragment > total_fragments.
-119
View File
@@ -1,16 +1,9 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use std::sync::LazyLock;
use crate::fragment::{linked_fragment_payload_max_len, unlinked_fragment_payload_max_len};
use dashmap::DashMap;
use fragment::{Fragment, FragmentHeader};
use nym_crypto::asymmetric::ed25519::PublicKey;
use serde::Serialize;
pub use set::split_into_sets;
use thiserror::Error;
use utoipa::ToSchema;
pub const MIN_PADDING_OVERHEAD: usize = 1;
@@ -29,118 +22,6 @@ pub mod fragment;
pub mod reconstruction;
pub mod set;
#[derive(Debug, Clone)]
pub struct FragmentMixParams {
destination: PublicKey,
hops: u8,
}
impl FragmentMixParams {
pub fn destination(&self) -> &PublicKey {
&self.destination
}
pub fn hops(&self) -> u8 {
self.hops
}
}
#[derive(Debug, Clone, Serialize, ToSchema)]
pub struct SentFragment {
header: FragmentHeader,
at: u64,
client_nonce: i32,
#[serde(skip)]
mixnet_params: FragmentMixParams,
}
impl SentFragment {
fn new(
header: FragmentHeader,
at: u64,
client_nonce: i32,
destination: PublicKey,
hops: u8,
) -> Self {
let mixnet_params = FragmentMixParams { destination, hops };
SentFragment {
header,
at,
client_nonce,
mixnet_params,
}
}
pub fn header(&self) -> FragmentHeader {
self.header.clone()
}
pub fn at(&self) -> u64 {
self.at
}
pub fn client_nonce(&self) -> i32 {
self.client_nonce
}
pub fn seed(&self) -> i32 {
self.header().seed().wrapping_mul(self.client_nonce())
}
pub fn mixnet_params(&self) -> FragmentMixParams {
self.mixnet_params.clone()
}
}
#[derive(Debug, Clone, Serialize, ToSchema)]
pub struct ReceivedFragment {
header: FragmentHeader,
at: u64,
}
impl ReceivedFragment {
fn new(header: FragmentHeader, at: u64) -> Self {
ReceivedFragment { header, at }
}
pub fn header(&self) -> FragmentHeader {
self.header.clone()
}
pub fn at(&self) -> u64 {
self.at
}
}
pub static FRAGMENTS_RECEIVED: LazyLock<DashMap<i32, Vec<ReceivedFragment>>> =
LazyLock::new(DashMap::new);
pub static FRAGMENTS_SENT: LazyLock<DashMap<i32, Vec<SentFragment>>> = LazyLock::new(DashMap::new);
#[macro_export]
macro_rules! now {
() => {
match std::time::SystemTime::now().duration_since(std::time::SystemTime::UNIX_EPOCH) {
Ok(n) => n.as_secs(),
Err(_) => 0,
}
};
}
pub fn fragment_received(fragment: &Fragment) {
let id = fragment.fragment_identifier().set_id();
let mut entry = FRAGMENTS_RECEIVED.entry(id).or_default();
let r = ReceivedFragment::new(fragment.header(), now!());
entry.push(r);
}
pub fn fragment_sent(fragment: &Fragment, client_nonce: i32, destination: PublicKey, hops: u8) {
let id = fragment.fragment_identifier().set_id();
let mut entry = FRAGMENTS_SENT.entry(id).or_default();
let s = SentFragment::new(fragment.header(), now!(), client_nonce, destination, hops);
entry.push(s);
}
/// The idea behind the process of chunking is to incur as little data overhead as possible due
/// to very computationally costly sphinx encapsulation procedure.
///
@@ -1,7 +1,7 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::fragment::Fragment;
use crate::{fragment_received, ChunkingError};
use crate::ChunkingError;
use log::*;
use std::collections::HashMap;
@@ -66,12 +66,6 @@ impl ReconstructionBuffer {
// if the set is complete.
debug_assert!(self.is_complete);
debug!(
"Got {} fragments for set id {}",
self.fragments.len(),
self.fragments[0].as_ref().unwrap().id()
);
self.fragments
.into_iter()
.map(|fragment| fragment.unwrap().extract_payload())
@@ -110,8 +104,6 @@ impl ReconstructionBuffer {
}
});
fragment_received(&fragment);
let fragment_index = fragment.current_fragment() as usize - 1;
if self.fragments[fragment_index].is_some() {
// TODO: what to do in that case? give up on the message? overwrite it? panic?
+4 -24
View File
@@ -3,7 +3,6 @@
use crate::message::{NymMessage, ACK_OVERHEAD, OUTFOX_ACK_OVERHEAD};
use crate::NymPayloadBuilder;
use log::debug;
use nym_crypto::asymmetric::encryption;
use nym_crypto::Digest;
use nym_sphinx_acknowledgements::surb_ack::SurbAck;
@@ -12,14 +11,12 @@ use nym_sphinx_addressing::clients::Recipient;
use nym_sphinx_addressing::nodes::NymNodeRoutingAddress;
use nym_sphinx_anonymous_replies::reply_surb::ReplySurb;
use nym_sphinx_chunking::fragment::{Fragment, FragmentIdentifier};
use nym_sphinx_chunking::fragment_sent;
use nym_sphinx_forwarding::packet::MixPacket;
use nym_sphinx_params::packet_sizes::PacketSize;
use nym_sphinx_params::{PacketType, ReplySurbKeyDigestAlgorithm, DEFAULT_NUM_MIX_HOPS};
use nym_sphinx_types::{Delay, NymPacket};
use nym_topology::{NymTopology, NymTopologyError};
use rand::{CryptoRng, Rng, SeedableRng};
use rand_chacha::ChaCha20Rng;
use rand::{CryptoRng, Rng};
use std::time::Duration;
@@ -52,7 +49,6 @@ pub trait FragmentPreparer {
type Rng: CryptoRng + Rng;
fn rng(&mut self) -> &mut Self::Rng;
fn nonce(&self) -> i32;
fn num_mix_hops(&self) -> u8;
fn average_packet_delay(&self) -> Duration;
fn average_ack_delay(&self) -> Duration;
@@ -196,18 +192,9 @@ pub trait FragmentPreparer {
packet_type: PacketType,
mix_hops: Option<u8>,
) -> Result<PreparedFragment, NymTopologyError> {
debug!("Preparing chunk for sending");
// each plain or repliable packet (i.e. not a reply) attaches an ephemeral public key so that the recipient
// could perform diffie-hellman with its own keys followed by a kdf to re-derive
// the packet encryption key
let seed = fragment.seed().wrapping_mul(self.nonce());
let mut rng = ChaCha20Rng::seed_from_u64(seed as u64);
let destination = packet_recipient.gateway();
let hops = mix_hops.unwrap_or(self.num_mix_hops());
fragment_sent(&fragment, self.nonce(), *destination, hops);
let non_reply_overhead = encryption::PUBLIC_KEY_SIZE;
let expected_plaintext = match packet_type {
PacketType::Outfox => {
@@ -241,8 +228,10 @@ pub trait FragmentPreparer {
};
// generate pseudorandom route for the packet
let hops = mix_hops.unwrap_or(self.num_mix_hops());
log::trace!("Preparing chunk for sending with {} mix hops", hops);
let route = topology.random_route_to_gateway(&mut rng, hops, destination)?;
let route =
topology.random_route_to_gateway(self.rng(), hops, packet_recipient.gateway())?;
let destination = packet_recipient.as_sphinx_destination();
// including set of delays
@@ -324,8 +313,6 @@ pub struct MessagePreparer<R> {
/// Number of mix hops each packet ('real' message, ack, reply) is expected to take.
/// Note that it does not include gateway hops.
num_mix_hops: u8,
nonce: i32,
}
impl<R> MessagePreparer<R>
@@ -338,15 +325,12 @@ where
average_packet_delay: Duration,
average_ack_delay: Duration,
) -> Self {
let mut rng = rng;
let nonce = rng.gen();
MessagePreparer {
rng,
sender_address,
average_packet_delay,
average_ack_delay,
num_mix_hops: DEFAULT_NUM_MIX_HOPS,
nonce,
}
}
@@ -470,10 +454,6 @@ impl<R: CryptoRng + Rng> FragmentPreparer for MessagePreparer<R> {
fn average_ack_delay(&self) -> Duration {
self.average_ack_delay
}
fn nonce(&self) -> i32 {
self.nonce
}
}
/*
@@ -218,7 +218,7 @@ impl SocksClient {
packet_type: Option<PacketType>,
) -> Self {
// If this task fails and exits, we don't want to send shutdown signal
shutdown_listener.disarm();
shutdown_listener.mark_as_success();
let connection_id = Self::generate_random();
@@ -294,7 +294,7 @@ impl SocksClient {
.shutdown()
.await
.map_err(|source| SocksProxyError::SocketShutdownFailure { source })?;
self.shutdown_listener.disarm();
self.shutdown_listener.mark_as_success();
Ok(())
}
@@ -172,6 +172,6 @@ where
trace!("{} - inbound closed", connection_id);
shutdown_notify.notify_one();
shutdown_listener.disarm();
shutdown_listener.mark_as_success();
reader
}
@@ -148,7 +148,7 @@ where
}
pub fn into_inner(mut self) -> (TcpStream, ConnectionReceiver) {
self.shutdown_listener.disarm();
self.shutdown_listener.mark_as_success();
(
self.socket.take().unwrap(),
self.mix_receiver.take().unwrap(),
@@ -60,7 +60,7 @@ pub(super) async fn run_outbound(
loop {
select! {
connection_message = mix_receiver.next() => {
connection_message = &mut mix_receiver.next() => {
if let Some(connection_message) = connection_message {
if deal_with_message(connection_message, &mut writer, &local_destination_address, &remote_source_address, connection_id).await {
break;
@@ -90,6 +90,6 @@ pub(super) async fn run_outbound(
trace!("{} - outbound closed", connection_id);
shutdown_notify.notify_one();
shutdown_listener.disarm();
shutdown_listener.mark_as_success();
(writer, mix_receiver)
}
+5 -1
View File
@@ -470,10 +470,14 @@ impl TaskClient {
// This listener should to *not* notify the ShutdownNotifier to shutdown when dropped. For
// example when we clone the listener for a task handling connections, we often want to drop
// without signal failure.
pub fn disarm(&mut self) {
pub fn mark_as_success(&mut self) {
self.mode.set_should_not_signal_on_drop();
}
pub fn disarm(&mut self) {
self.mark_as_success();
}
pub fn send_we_stopped(&mut self, err: SentError) {
if self.mode.is_dummy() {
return;
+8 -11
View File
@@ -5,6 +5,7 @@ edition = { workspace = true }
authors = { workspace = true }
license = { workspace = true }
repository = { workspace = true }
readme = { workspace = true }
homepage = { workspace = true }
documentation = { workspace = true }
@@ -14,10 +15,9 @@ documentation = { workspace = true }
bs58 = { workspace = true }
log = { workspace = true }
rand = { workspace = true }
reqwest = { workspace = true, features = ["json"] }
thiserror = { workspace = true }
async-trait = { workspace = true, optional = true }
semver = { version = "0.11" }
semver = "0.11"
# 'serializable' feature
serde = { workspace = true, features = ["derive"], optional = true }
@@ -28,22 +28,20 @@ tsify = { workspace = true, features = ["js"], optional = true }
wasm-bindgen = { workspace = true, optional = true }
## internal
nym-bin-common = { path = "../bin-common" }
nym-config = { path = "../config" }
nym-crypto = { path = "../crypto", features = ["sphinx", "outfox"] }
nym-mixnet-contract-common = { path = "../cosmwasm-smart-contracts/mixnet-contract" }
nym-sphinx-addressing = { path = "../nymsphinx/addressing" }
nym-sphinx-types = { path = "../nymsphinx/types", features = [
"sphinx",
"outfox",
] }
nym-sphinx-types = { path = "../nymsphinx/types", features = ["sphinx", "outfox"] }
nym-sphinx-routing = { path = "../nymsphinx/routing" }
nym-bin-common = { path = "../bin-common" }
# I'm not sure how to feel about pulling in this dependency here...
nym-api-requests = { path = "../../nym-api/nym-api-requests" }
# 'serializable' feature
nym-config = { path = "../config", optional = true }
# 'wasm-serde-types' feature
wasm-utils = { path = "../wasm/utils", default-features = false, optional = true }
@@ -51,5 +49,4 @@ wasm-utils = { path = "../wasm/utils", default-features = false, optional = true
default = ["provider-trait"]
provider-trait = ["async-trait"]
wasm-serde-types = ["tsify", "wasm-bindgen", "wasm-utils"]
serializable = ["serde", "serde_json"]
outfox = []
serializable = ["serde", "nym-config", "serde_json"]
-12
View File
@@ -51,16 +51,4 @@ pub enum NymTopologyError {
#[error("{0}")]
PacketError(#[from] NymPacketError),
#[error("{0}")]
ReqwestError(#[from] reqwest::Error),
#[error("{0}")]
MixnodeConversionError(#[from] crate::mix::MixnodeConversionError),
#[error("{0}")]
GatewayConversionError(#[from] crate::gateway::GatewayConversionError),
#[error("{0}")]
VarError(#[from] std::env::VarError),
}
+4 -54
View File
@@ -6,9 +6,7 @@
use crate::filter::VersionFilterable;
pub use error::NymTopologyError;
use log::{debug, info, warn};
use mix::Node;
use nym_config::defaults::var_names::NYM_API;
use log::{debug, warn};
use nym_mixnet_contract_common::mixnode::MixNodeDetails;
use nym_mixnet_contract_common::{GatewayBond, IdentityKeyRef, MixId};
use nym_sphinx_addressing::nodes::NodeIdentity;
@@ -118,40 +116,13 @@ impl Display for NetworkAddress {
pub type MixLayer = u8;
#[derive(Debug, Clone, Default)]
#[derive(Debug, Clone)]
pub struct NymTopology {
mixes: BTreeMap<MixLayer, Vec<mix::Node>>,
gateways: Vec<gateway::Node>,
}
impl NymTopology {
pub async fn new_from_env() -> Result<Self, NymTopologyError> {
let api_url = std::env::var(NYM_API)?;
info!("Generating topology from {}", api_url);
let mixnodes = reqwest::get(&format!("{}/v1/mixnodes", api_url))
.await?
.json::<Vec<MixNodeDetails>>()
.await?
.into_iter()
.map(|details| details.bond_information)
.map(mix::Node::try_from)
.filter(Result::is_ok)
.collect::<Result<Vec<_>, _>>()?;
let gateways = reqwest::get(&format!("{}/v1/gateways", api_url))
.await?
.json::<Vec<GatewayBond>>()
.await?
.into_iter()
.map(gateway::Node::try_from)
.filter(Result::is_ok)
.collect::<Result<Vec<_>, _>>()?;
let topology = NymTopology::new_unordered(mixnodes, gateways);
Ok(topology)
}
pub fn new(mixes: BTreeMap<MixLayer, Vec<mix::Node>>, gateways: Vec<gateway::Node>) -> Self {
NymTopology { mixes, gateways }
}
@@ -299,7 +270,7 @@ impl NymTopology {
&self,
rng: &mut R,
num_mix_hops: u8,
) -> Result<Vec<Node>, NymTopologyError>
) -> Result<Vec<SphinxNode>, NymTopologyError>
where
R: Rng + CryptoRng + ?Sized,
{
@@ -324,32 +295,12 @@ impl NymTopology {
let random_mix = layer_mixes
.choose(rng)
.ok_or(NymTopologyError::EmptyMixLayer { layer })?;
route.push(random_mix.clone());
route.push(random_mix.into());
}
Ok(route)
}
pub fn random_path_to_gateway<R>(
&self,
rng: &mut R,
num_mix_hops: u8,
gateway_identity: &NodeIdentity,
) -> Result<(Vec<mix::Node>, gateway::Node), NymTopologyError>
where
R: Rng + CryptoRng + ?Sized,
{
let gateway = self.get_gateway(gateway_identity).ok_or(
NymTopologyError::NonExistentGatewayError {
identity_key: gateway_identity.to_base58_string(),
},
)?;
let path = self.random_mix_route(rng, num_mix_hops)?;
Ok((path, gateway.clone()))
}
/// Tries to create a route to the specified gateway, such that it goes through mixnode on layer 1,
/// mixnode on layer2, .... mixnode on layer n and finally the target gateway
pub fn random_route_to_gateway<R>(
@@ -370,7 +321,6 @@ impl NymTopology {
Ok(self
.random_mix_route(rng, num_mix_hops)?
.into_iter()
.map(|node| SphinxNode::from(&node))
.chain(std::iter::once(gateway.into()))
.collect())
}
+1 -1
View File
@@ -4,7 +4,7 @@ version = "1.0.0"
description = "Nym common types"
authors.workspace = true
edition = "2021"
rust-version.workspace = true
rust-version = "1.58"
license.workspace = true
[dependencies]
-1
View File
@@ -11,7 +11,6 @@ pub mod gas;
pub mod gateway;
pub mod helpers;
pub mod mixnode;
pub mod monitoring;
pub mod pending_events;
pub mod transaction;
pub mod vesting;
-131
View File
@@ -1,131 +0,0 @@
use std::{collections::HashSet, sync::LazyLock, time::SystemTime};
use nym_crypto::asymmetric::identity::{PrivateKey, PublicKey, Signature};
use nym_mixnet_contract_common::MixId;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
static NETWORK_MONITORS: LazyLock<HashSet<String>> = LazyLock::new(|| {
let mut nm = HashSet::new();
nm.insert("5VsPyLbsBCq9PAMWmjKkToteVAKNabNqex6QwDf5fWzt".to_string());
nm
});
#[derive(Debug, Serialize, Deserialize, JsonSchema, Clone)]
pub struct NodeResult {
pub node_id: MixId,
pub identity: String,
pub reliability: u8,
}
#[derive(Debug, Serialize, Deserialize, JsonSchema, Clone)]
pub struct MixnodeResult {
pub mix_id: MixId,
pub identity: String,
pub owner: String,
pub reliability: u8,
}
impl MixnodeResult {
pub fn new(mix_id: MixId, identity: String, owner: String, reliability: u8) -> Self {
MixnodeResult {
mix_id,
identity,
owner,
reliability,
}
}
}
#[derive(Debug, Deserialize, Serialize, JsonSchema, Clone)]
pub struct GatewayResult {
pub identity: String,
pub owner: String,
pub reliability: u8,
pub mix_id: MixId,
}
impl GatewayResult {
pub fn new(identity: String, owner: String, reliability: u8) -> Self {
GatewayResult {
identity,
owner,
reliability,
mix_id: 0,
}
}
}
#[derive(Serialize, Deserialize, JsonSchema)]
#[serde(untagged)]
pub enum MonitorResults {
Mixnode(Vec<MixnodeResult>),
Gateway(Vec<GatewayResult>),
}
#[derive(Serialize, Deserialize, JsonSchema)]
pub struct MonitorMessage {
results: Vec<NodeResult>,
signature: String,
signer: String,
timestamp: i64,
}
impl MonitorMessage {
fn message_to_sign(results: &[NodeResult], timestamp: i64) -> Vec<u8> {
let mut msg = match serde_json::to_vec(results) {
Ok(msg) => msg,
Err(_) => Vec::new(),
};
msg.extend_from_slice(&timestamp.to_le_bytes());
msg
}
pub fn timely(&self) -> bool {
let now = SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH)
.expect("Time went backwards")
.as_secs() as i64;
now - self.timestamp < 5
}
pub fn new(results: Vec<NodeResult>, private_key: &PrivateKey) -> Self {
let timestamp = SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH)
.expect("Time went backwards")
.as_secs() as i64;
let msg = Self::message_to_sign(&results, timestamp);
let signature = private_key.sign(&msg);
let public_key = private_key.public_key();
MonitorMessage {
results,
signature: signature.to_base58_string(),
signer: public_key.to_base58_string(),
timestamp,
}
}
pub fn from_allowed(&self) -> bool {
NETWORK_MONITORS.contains(&self.signer)
}
pub fn results(&self) -> &[NodeResult] {
&self.results
}
pub fn verify(&self) -> bool {
let msg = Self::message_to_sign(&self.results, self.timestamp);
let signature = match Signature::from_base58_string(&self.signature) {
Ok(sig) => sig,
Err(_) => return false,
};
PublicKey::from_base58_string(&self.signer)
.map(|pk| pk.verify(msg, &signature).is_ok())
.unwrap_or(false)
}
}
+6 -2
View File
@@ -30,9 +30,13 @@ workspace = true
optional = true
[features]
default = ["sleep"]
default = ["sleep", "console_error_panic_hook"]
sleep = ["web-sys", "web-sys/Window"]
websocket = ["getrandom", "tungstenite", "gloo-net"]
websocket = [
"getrandom",
"tungstenite",
"gloo-net"
]
crypto = [
"web-sys",
"web-sys/Crypto",
+2 -1
View File
@@ -12,6 +12,7 @@ license.workspace = true
[dependencies]
base64 = { workspace = true }
dashmap = { workspace = true }
log = { workspace = true }
serde = { workspace = true, features = ["derive"] }
thiserror = { workspace = true }
@@ -34,7 +35,7 @@ x25519-dalek = { workspace = true, features = ["static_secrets"] }
[dev-dependencies]
rand = "0.8.5"
nym-crypto = { path = "../crypto", features = ["rand"] }
nym-crypto = { path = "../crypto", features = ["rand"]}
[features]
-7
View File
@@ -6,17 +6,10 @@ pub mod error;
pub mod public_key;
pub mod registration;
use std::time::Duration;
pub use config::Config;
pub use error::Error;
pub use public_key::PeerPublicKey;
pub use registration::{ClientMac, ClientMessage, GatewayClient, InitMessage, Nonce};
// To avoid any problems, keep this stale check time bigger (>2x) then the bandwidth cap
// reset time (currently that one is 24h, at UTC midnight)
pub const DEFAULT_PEER_TIMEOUT: Duration = Duration::from_secs(60 * 60 * 24 * 3); // 3 days
pub const DEFAULT_PEER_TIMEOUT_CHECK: Duration = Duration::from_secs(5); // 5 seconds
#[cfg(feature = "verify")]
pub use registration::HmacSha256;
+3 -3
View File
@@ -4,8 +4,8 @@
use crate::error::Error;
use crate::PeerPublicKey;
use base64::{engine::general_purpose, Engine};
use dashmap::DashMap;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::net::IpAddr;
use std::time::SystemTime;
use std::{fmt, ops::Deref, str::FromStr};
@@ -17,8 +17,8 @@ use nym_crypto::asymmetric::encryption::PrivateKey;
#[cfg(feature = "verify")]
use sha2::Sha256;
pub type PendingRegistrations = HashMap<PeerPublicKey, RegistrationData>;
pub type PrivateIPs = HashMap<IpAddr, Taken>;
pub type PendingRegistrations = DashMap<PeerPublicKey, RegistrationData>;
pub type PrivateIPs = DashMap<IpAddr, Taken>;
#[cfg(feature = "verify")]
pub type HmacSha256 = Hmac<Sha256>;
+1 -2
View File
@@ -84,7 +84,6 @@ pub struct WireguardData {
#[cfg(target_os = "linux")]
pub async fn start_wireguard<St: nym_gateway_storage::Storage + 'static>(
storage: St,
all_peers: Vec<nym_gateway_storage::models::WireguardPeer>,
task_client: nym_task::TaskClient,
wireguard_data: WireguardData,
control_tx: UnboundedSender<peer_controller::PeerControlResponse>,
@@ -96,7 +95,7 @@ pub async fn start_wireguard<St: nym_gateway_storage::Storage + 'static>(
let mut peers = vec![];
let mut suspended_peers = vec![];
for storage_peer in all_peers {
for storage_peer in storage.get_all_wireguard_peers().await? {
let suspended = storage_peer.suspended;
let peer = Peer::try_from(storage_peer)?;
if suspended {
+15 -16
View File
@@ -5,15 +5,19 @@ use chrono::{Timelike, Utc};
use defguard_wireguard_rs::{host::Peer, key::Key, WireguardInterfaceApi};
use nym_gateway_storage::Storage;
use nym_wireguard_types::registration::{RemainingBandwidthData, BANDWIDTH_CAP_PER_DAY};
use nym_wireguard_types::{DEFAULT_PEER_TIMEOUT, DEFAULT_PEER_TIMEOUT_CHECK};
use std::time::SystemTime;
use std::{collections::HashMap, sync::Arc};
use std::{collections::HashMap, sync::Arc, time::Duration};
use tokio::sync::mpsc;
use tokio_stream::{wrappers::IntervalStream, StreamExt};
use crate::error::Error;
use crate::WgApiWrapper;
// To avoid any problems, keep this stale check time bigger (>2x) then the bandwidth cap
// reset time (currently that one is 24h, at UTC midnight)
const DEFAULT_PEER_TIMEOUT: Duration = Duration::from_secs(60 * 60 * 24 * 3); // 3 days
const DEFAULT_PEER_TIMEOUT_CHECK: Duration = Duration::from_secs(60); // 1 minute
pub enum PeerControlRequest {
AddPeer(Peer),
RemovePeer(Key),
@@ -46,7 +50,6 @@ pub struct PeerController<St: Storage> {
active_peers: HashMap<Key, Peer>,
suspended_peers: HashMap<Key, Peer>,
last_seen_bandwidth: HashMap<Key, u64>,
timeout_count: u8,
}
impl<St: Storage> PeerController<St> {
@@ -61,14 +64,19 @@ impl<St: Storage> PeerController<St> {
let timeout_check_interval = tokio_stream::wrappers::IntervalStream::new(
tokio::time::interval(DEFAULT_PEER_TIMEOUT_CHECK),
);
let active_peers = peers
let active_peers: HashMap<Key, Peer> = peers
.into_iter()
.map(|peer| (peer.public_key.clone(), peer))
.collect();
let suspended_peers = suspended_peers
let suspended_peers: HashMap<Key, Peer> = suspended_peers
.into_iter()
.map(|peer| (peer.public_key.clone(), peer))
.collect();
let last_seen_bandwidth = active_peers
.iter()
.map(|(k, p)| (k.clone(), p.rx_bytes + p.tx_bytes))
.chain(suspended_peers.keys().map(|k| (k.clone(), 0)))
.collect();
PeerController {
storage,
@@ -78,8 +86,7 @@ impl<St: Storage> PeerController<St> {
timeout_check_interval,
active_peers,
suspended_peers,
last_seen_bandwidth: HashMap::new(),
timeout_count: 0,
last_seen_bandwidth,
}
}
@@ -142,15 +149,6 @@ impl<St: Storage> PeerController<St> {
.iter()
.map(|(key, peer)| (key.clone(), peer.rx_bytes + peer.tx_bytes))
.collect();
// Do in-memory updates of bandwidth every DEFAULT_PEER_TIMEOUT_CHECK
// and storage updates every 5 * DEFAULT_PEER_TIMEOUT_CHECK, because in-memory
// is more important for client query preciseness
self.timeout_count = self.timeout_count % 5 + 1;
if !reset && self.timeout_count < 5 {
return Ok(());
}
if reset {
self.active_peers = host.peers;
for peer in self.active_peers.values() {
@@ -199,6 +197,7 @@ impl<St: Storage> PeerController<St> {
log::error!("Could not configure peer: {:?}", e);
false
} else {
self.last_seen_bandwidth.insert(peer.public_key.clone(), peer.rx_bytes + peer.tx_bytes);
self.active_peers.insert(peer.public_key.clone(), peer);
true
};
+22 -18
View File
@@ -1,27 +1,30 @@
# Nym Docs v2
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).
# Documentation
## Doc projects
`docs/pages/` contains several subdirs, each hosting a subsection of the docs:
* `network` contains key concepts, cryptosystems, architecture.
* `developers` contains key concepts for developers, required architecture, and Rust/Typescript SDK docs.
* `operators` contains node setup and maintenance guides.
Each directory contains a readme with more information about running and contributing to the projects. Each is built with [`mdbook`](https://rust-lang.github.io/mdBook/index.html) - use `mdbook serve` to build and serve them (defaults to `localhost:3000`).
* `docs` contains technical documentation hosted at [https://nymtech.net/docs](https://nymtech.net/docs)
* `dev-portal` contains developer documentation hosted at [https://nymtech.net/developers](https://nymtech.net/developers)
* `operators` contains node setup and maintenance guides hosted at [https://nymtech.net/operators](https://nymtech.net/operators)
## Contribution
* If you wish to add to the documentation please create a PR against this repo, with a `patch` against `develop`.
> If you are looking for the Typescript SDK documentation located at [sdk.nymtech.net](https://sdk.nymtech.net) this can be found in `../sdk/typescript/docs/`
## Scripts
* There are several autogenerated command files for clients and binaries. These are generated with `generate:commands`, which runs the `autodoc` rust binary, moves the files to their required places, and then if there is an update, commits them to git. This is for remote deployments.
* TODO
## Contribution
* If you wish to add to the documentation please create a PR against this repo.
* If you are **adding a plugin dependency** make sure to also **add that to the list of plugins in `install_mdbook_deps.sh` line 12**.
### Autodoc
`autodoc` is a script that generates markdown files containing commands and their output (both command and `--help` output). For the moment the binaries and their commands are manually configured in the script.
## Scripts
* `bump_versions.sh` allows you to update the ~~`platform_release_version` and~~ `wallet_release_version` variable~~s~~ in the `book.toml` of each mdbook project at once. You can also optionally update the `minimum_rust_version` as well. Helpful for lazy-updating when cutting a new version of the docs.
## CI/CD
TODO
* The following scripts are used by the `ci-dev.yml` and `cd-dev.yml` scripts (located in `../.github/workflows/`):
* `build_all_to_dist.sh` is used for building all mdbook projects and moving the rendered html to `../dist/` to be rsynced with various servers.
* `install_mdbook_deps.sh` checks for an existing install of mdbook (and plugins), uninstalls them, and then installs them on a clean slate. This is to avoid weird dependency clashes if relying on an existing mdbook version.
* `post_process.sh` is used to post process CSS/image/href links for serving several mdbooks from a subdirectory.
* `removed_existing_config.sh` is used to check for existing nym client/node config files on the CI/CD server and remove it if it exists. This is to mitigate issues with `mdbook-cmdrun` where e.g. a node is already initialised, and the command fails.
## CI/CD
Deployment of the docs is partially automated and partially manual.
* `ci-docs.yml` will run on pushes to all branches **apart from `master`**
* `cd-docs.yml` must be run manually. This pushes to a staging branch which then must be manually promoted to production.
## Licensing and copyright information
This is a monorepo and components that make up Nym as a system are licensed individually, so for accurate information, please check individual files.
@@ -33,3 +36,4 @@ As a general approach, licensing is as follows this pattern:
* Nym applications and binaries are [GPL-3.0-only](https://www.gnu.org/licenses/)
* Used libraries and different components are [Apache 2.0](https://www.apache.org/licenses/LICENSE-2.0.html) or [MIT](https://mit-license.org/)
-1
View File
@@ -1 +0,0 @@
/autodoc-generated-markdown/*
-13
View File
@@ -1,13 +0,0 @@
[package]
name = "autodoc"
version = "0.1.0"
authors.workspace = true
repository.workspace = true
homepage.workspace = true
documentation.workspace = true
edition.workspace = true
license.workspace = true
[dependencies]
env_logger = "0.11.3"
log.workspace = true
-4
View File
@@ -1,4 +0,0 @@
# `autodoc`
Command output documentation generator WIP
-259
View File
@@ -1,259 +0,0 @@
use log::{debug, info};
use std::fs::File;
use std::io::{self, Write};
use std::process::{Command, Output};
use std::{fs, vec};
const WRITE_PATH: &str = "./autodoc-generated-markdown/";
fn main() -> io::Result<()> {
env_logger::init();
// TODO if this balloons write automated way of grabbing commands from crates.
let commands_with_subcommands = vec![
(
"../../target/release/nym-api",
vec!["init", "run", "build-info"],
),
(
"../../target/release/nym-client",
vec![
"init",
"run",
"import-credential",
"list-gateways",
"switch-gateway",
"build-info",
"completions",
"generate-fig-spec",
],
),
(
"../../target/release/nym-socks5-client",
vec![
"init",
"run",
"import-credential",
"list-gateways",
"add-gateway",
"build-info",
"completions",
"generate-fig-spec",
],
),
(
"../../target/release/nym-node",
vec![
"build-info",
"bonding-information",
"node-details",
"migrate",
"run",
"sign",
],
),
(
"../../target/release/nymvisor",
vec![
"init",
"run",
"build-info",
"daemon-build-info",
"add-upgrade",
"config",
],
),
];
let commands_with_subsubcommands = vec![(
"../../target/release/nym-cli",
vec![
(
"account",
vec!["create", "balance", "pub-key", "send", "send-multiple"],
),
("signature", vec!["sign", "verify"]),
(
"ecash",
vec![
"issue-ticket-book",
"recover-ticket-book",
"import-ticket-book",
],
),
(
"coconut",
vec![
"generate-freepass",
"issue-credentials",
"recover-credentials",
"import-credential",
],
),
("block", vec!["get", "time", "current-height"]),
(
"cosmwasm",
vec![
"upload",
"init",
"generate-init-message",
"migrate",
"execute",
],
),
("tx", vec!["get", "query"]),
(
"vesting-schedule",
vec!["create", "query", "vested-balance", "withdraw-vested"],
),
("mixnet", vec!["query", "delegators", "operators"]),
("generate-fig", vec![""]),
],
)];
for (main_command, subcommands) in commands_with_subcommands {
let last_word = get_last_word_from_filepath(main_command);
debug!("now running {last_word:#?}");
if !fs::metadata(WRITE_PATH)
.map(|metadata| metadata.is_dir())
.unwrap_or(false)
{
fs::create_dir_all(WRITE_PATH)?;
}
let mut file = File::create(format!("{}/{}-commands.md", WRITE_PATH, last_word.unwrap()))?;
writeln!(
file,
"# {} Binary Commands (Autogenerated)",
format!("`{}`", last_word.unwrap())
)?;
writeln!(
file,
"\nThese docs are autogenerated by the [`autodocs`](https://github.com/nymtech/nym/tree/max/new-docs-framework/documentation/autodoc) script."
)?;
let output = Command::new(main_command).arg("--help").output()?;
write_output_to_file(&mut file, output)?;
for subcommand in subcommands {
execute_command(&mut file, main_command, subcommand, None)?;
}
}
// nym-cli has subsubcommands so needs its own loop
for (main_command, subcommands) in &commands_with_subsubcommands {
let last_word = get_last_word_from_filepath(main_command);
debug!("now running {last_word:#?}");
let mut file = File::create(format!("{}/{}-commands.md", WRITE_PATH, last_word.unwrap()))?;
writeln!(
file,
"# {} Binary Commands (Autogenerated)",
format!("`{}`", last_word.unwrap())
)?;
writeln!(
file,
"\nThese docs are autogenerated by the [`autodocs`](https://github.com/nymtech/nym/tree/max/new-docs-framework/documentation/autodoc) script."
)?;
let output = Command::new(main_command).arg("--help").output()?;
write_output_to_file(&mut file, output)?;
for (subcommand, subsubcommands) in subcommands {
writeln!(file, "\n## `{}` ", subcommand)?;
let output = Command::new(main_command)
.arg(subcommand)
.arg("--help")
.output()?;
if !output.stdout.is_empty() {
write_output_to_file(&mut file, output)?;
} else {
debug!("empty stdout - nothing to write");
}
for subsubcommand in subsubcommands {
execute_command(&mut file, main_command, subcommand, Some(subsubcommand))?;
}
}
}
Ok(())
}
fn get_last_word_from_filepath(filepath: &str) -> Option<&str> {
let parts: Vec<&str> = filepath.split('/').collect();
parts.last().copied()
}
fn execute_command(
file: &mut File,
main_command: &str,
subcommand: &str,
subsubcommand: Option<&str>,
) -> io::Result<()> {
// checking for the nym-cli subsubcommands
if subsubcommand.is_some() {
writeln!(file, "\n### `{} {}`", subcommand, subsubcommand.unwrap())?;
info!("executing {} {} --help ", main_command, subcommand);
let output = Command::new(main_command)
.arg(subcommand)
.arg(subsubcommand.unwrap())
.arg("--help")
.output()?;
if !output.stdout.is_empty() {
write_output_to_file(file, output)?;
} else {
debug!("empty stdout - nothing to write");
}
// just subcommands
} else {
writeln!(file, "\n### `{}`", subcommand)?;
// execute help
let output = Command::new(main_command)
.arg(subcommand)
.arg("--help")
.output()?;
if !output.stdout.is_empty() {
write_output_to_file(file, output)?;
} else {
debug!("empty stdout - nothing to write");
}
// then execute w/out help: the majority of functions will fail since you're not passing
// required params but thats fine as we can just not render stderr into the final file.
//
// this check is basically checking for the rare commands (rn just one) that start a process with no params
// perhaps if this list grows we could just add a timeout and shunt the running and writing
// into a thread with a timeout or something but for right now its fine / thats overkill
if get_last_word_from_filepath(main_command).unwrap() == "nym-node"
|| get_last_word_from_filepath(main_command).unwrap() == "nym-api"
|| get_last_word_from_filepath(main_command).unwrap() == "nymvisor"
&& subcommand == "run"
{
info!("SKIPPING {} {}", main_command, subcommand);
} else {
info!("executing {} {}", main_command, subcommand);
let output = Command::new(main_command).arg(subcommand).output()?;
if !output.stdout.is_empty() {
writeln!(file, "Example output:")?;
write_output_to_file(file, output)?;
} else {
debug!("empty stdout - nothing to write");
if !&output.stderr.is_empty() {
debug!("stderr: {:#?}", String::from_utf8_lossy(&output.stderr));
}
}
}
}
Ok(())
}
fn write_output_to_file(file: &mut File, output: Output) -> io::Result<()> {
writeln!(file, "```sh")?;
file.write_all(&output.stdout)?;
writeln!(file, "```")?;
if !&output.stderr.is_empty() {
debug!("stderr: {:#?}", String::from_utf8_lossy(&output.stderr));
}
Ok(())
}
+51
View File
@@ -0,0 +1,51 @@
#!/usr/bin/env bash
set -o errexit
set -o nounset
set -o pipefail
# this is a script called by the github CI and CD workflows to build all 3 docs projects
# and move them to /dist/ in the root of the monorepo. They are rsynced to various servers
# from there by subsequent workflow tasks.
# array of project dirs
declare -a projects=("docs" "dev-portal" "operators")
# check you're calling from the right place
if [ $(pwd | awk -F/ '{print $NF}') != "documentation" ]
then
echo "failure: please run script from documentation/"
else
for i in "${projects[@]}"
do
# cd to project dir
cd "./$i" &&
# little sanity checks
echo $(pwd) && echo $(mdbook --version) &&
# clean old book
echo "cleaning old book"
rm -rf ./book/
# build book
# mdbook test || true
mdbook build
# check for destination, if ! then mkdir & check again else echo thumbs up
if [ ! -d ../../dist/docs/$i ]; then
echo "dest doesn't exist: creating dir"
mkdir -p ../../dist/docs/$i
fi
if [ -d ../../dist/docs/$i ]; then
echo "cp destination exists, all good"
fi
# clean old dist/$i
rm -rf ../../dist/docs/$i
# move newly rendered book/ to dist
rsync -r ./book/html/ ../../dist/docs/$i
# sanity check
ls -laF ../../dist/docs/
# cd back to ../documentation/
cd ../
done
# rename for server paths
rm -rf ../dist/docs/developers
mv ../dist/docs/dev-portal ../dist/docs/developers
fi
+45
View File
@@ -0,0 +1,45 @@
#!/usr/bin/env bash
set -o errexit
set -o nounset
set -o pipefail
# takes one manadatory arg and one optional arg: wallet release and minimum rust versions
# it then uses sed to bump them in the three book.toml files.
#
# e.g if the upcoming wallet release version was 1.2.9 you'd run this as:
# `./bump_versions.sh "1.2.9"`
#
# you can also set the minumum rust version by passing an optional additional argument:
# `./bump_versions.sh "1.2.9" "1.67"`
# array of project dirs
declare -a projects=("docs" "dev-portal" "operators")
# check number of args passed
if [ "$#" -lt 1 ] || [ "$#" -gt 2 ];
then
echo "failure: please pass at least 1 and at most 2 args: "
echo "./bump_version.sh <new wallet_release_version> [OPTIONAL]<new minimum_rust_version>"
exit 0
fi
# check you're calling from the right place
if [ $(pwd | awk -F/ '{print $NF}') != "documentation" ]
then
echo "failure: please run script from documentation/"
exit 0
else
## now loop through the above array sed-ing the variable values in the book.toml files
for i in "${projects[@]}"
do
# sed the vars in the book.toml file for each project
echo "setting wallet version in $i/"
sed -i 's/wallet_release_version =.*/wallet_release_version = "'$2'"/' "$i"/book.toml
if [ "$3" ]
then
echo "setting minimum rust version in $i/"
sed -i 's/minimum_rust_version = .*/minimum_rust_version = "'$3'"/' "$i"/book.toml
fi
done
fi
@@ -108,11 +108,3 @@ copy-js = true # include Javascript code for search
[output.linkcheck]
warning-policy = "warn"
[output.html.redirect]
"/faq/general-faq.html" = "https://nymtech.net/developers/faq/integrations-faq.html"
"/tutorials/simple-service-provider/user-client.html" = "https://nymtech.net/developers/examples/custom-services.html"
"/quickstart/socks-proxy.html" = "https://nymtech.net/developers/clients/socks5/setup.html"
"/tutorials/matrix.html" = "https://nymtech.net/developers/archive/nym-connect.html#matrix-element-via-nymconnect"
"/tutorials/monero.html" = "https://nymtech.net/developers/archive/nym-connect.html#monero-wallet-via-nymconnect"
"/tutorials/telegram.html" = "https://nymtech.net/developers/archive/nym-connect.html#telegram-via-nymconnect"
@@ -2,7 +2,7 @@
- [Introduction](introduction.md)
- [Clients Overview - Start Here!](clients-overview.md)
# SDKs
# SDKs
- [Rust SDK](sdk/rust/rust.md)
- [Message Types](sdk/rust/message-types.md)
- [Message Helpers](sdk/rust/message-helpers.md)
@@ -30,7 +30,7 @@
- [Using Your Client](clients/websocket/usage.md)
- [Examples](clients/websocket/examples.md)
- [Socks5 Client](clients/socks5-client.md)
- [Setup & Run](clients/socks5/setup.md)
- [Setup & Run](clients/socks5/setup.md)
- [Using Your Client](clients/socks5/usage.md)
- [Webassembly Client](clients/webassembly-client.md)
@@ -54,13 +54,8 @@
# User Manuals
- [NymVPN alpha](nymvpn/intro.md)
- [CLI](nymvpn/cli.md)
---
# Archive
- [NymConnect Setup](archive/nym-connect.md)
---
# Misc.
- [Code of Conduct](coc.md)
- [Licensing](licensing.md)
@@ -52,10 +52,10 @@ git checkout master # master branch has the latest release version: `develop` wi
cargo build --release # build your binaries with **mainnet** configuration
```
Quite a bit of stuff gets built. The key working parts for devs are the Client binaries and the CLI tool:
Quite a bit of stuff gets built. The key working parts for devs are the Client binaries and the CLI tool:
* [websocket client](../clients/websocket-client.md): `nym-client`
* [socks5 client](../clients/socks5-client.md): `nym-socks5-client`
* [nym-cli tool](https://nymtech.net/docs/tools/nym-cli.html): `nym-cli`
* [nym-cli tool](https://nymtech.net/docs/tools/nym-cli.md): `nym-cli`
> You cannot build from GitHub's .zip or .tar.gz archive files on the releases page - the Nym build scripts automatically include the current git commit hash in the built binary during compilation, so the build will fail if you use the archive code (which isn't a Git repository). Check the code out from github using `git clone` instead.
@@ -60,7 +60,7 @@ There are 2 pieces of software that work together to send SOCKS traffic through
The `nym-socks5-client` allows you to do the following from your local machine:
* Take a TCP data stream from a application that can send traffic via SOCKS5.
* Chop up the TCP stream into multiple Sphinx packets, assigning sequence numbers to them, while leaving the TCP connection open for more data
* Send the Sphinx packets through the Nym Network. Packets are shuffled and mixed as they transit the mixnet.
* Send the Sphinx packets through the mixnet to a [network requester](https://nymtech.net/operators/nodes/network-requester.md). Packets are shuffled and mixed as they transit the mixnet.
The `nym-network-requester` then reassembles the original TCP stream using the packets' sequence numbers, and make the intended request. It will then chop up the response into Sphinx packets and send them back through the mixnet to your `nym-socks5-client`. The application will then receive its data, without even noticing that it wasn't talking to a "normal" SOCKS5 proxy!
@@ -104,6 +104,8 @@ The `--use-reply-surbs` field denotes whether you wish to send [SURBs](https://n
The `--provider` field needs to be filled with the Nym address of a Network Requester that can make network requests on your behalf. If you don't want to [run your own](https://nymtech.net/operators/nodes/network-requester.md) you can select one from the [mixnet explorer](https://explorer.nymtech.net/network-components/service-providers) by copying its `Client ID` and using this as the value of the `--provider` flag. Alternatively, you could use [this list](https://harbourmaster.nymtech.net/).
Since the nodes on this list are the infrastructure for [Nymconnect](https://nymtech.net/developers/quickstart/nymconnect-gui.html) they will support all apps on the [default whitelist](https://nymtech.net/operators/nodes/network-requester.md#network-requester-whitelist): Keybase, Telegram, Electrum, Blockstream Green, and Helios.
#### Choosing a Gateway
By default - as in the example above - your client will choose a random gateway to connect to.
@@ -1,14 +1,9 @@
# Setup
# Setup
> `nym-socks5-client` now also supports SOCKS4 and SOCKS4A protocols as well as SOCKS5.
The Nym socks5 client allows you to proxy traffic from a desktop application through the mixnet, meaning you can send and receive information from remote application servers without leaking metadata which can be used to deanonymise you, even if you're using an encrypted application such as Signal.
```admonish info
Since the beginning of 2024 NymConnect is no longer maintained. Nym is developing a new client called [NymVPN](https://nymvpn.com), an application routing all users traffic thorugh the mixnet.
If users want to route their traffic through socks5 we advice to use this client. If you want to run deprecated NymConnect, visit [NymConnect archive page](../../archive/nym-connect.md) with setup and application examples.
```
## Setup and Run
### Download or compile socks5 client
@@ -43,3 +38,5 @@ Now your client is initialised, start it with the following:
```
./nym-socks5-client run --id <ID>
```
@@ -12,6 +12,4 @@ All of these code examples will do the following:
By varying the message content, you can easily build sophisticated service provider apps. For example, instead of printing the response received from the mixnet, your service provider might take some action on behalf of the user - perhaps initiating a network request, a blockchain transaction, or writing to a local data store.
<!-- THIS PAGE IS NOT WORKING AT THE MOMENT:
> You can find an example of building both frontend and service provider code with the websocket client in the [Simple Service Provider Tutorial](https://nymtech.net/developers/tutorials/simple-service-provider/simple-service-provider.html) in the Developer Portal.
-->
@@ -1,17 +1,17 @@
# Using Your Client
The Nym native client exposes a websocket interface that your code connects to. The **default** websocket port is `1977`, you can override that in the client config if you want.
Once you have a websocket connection, interacting with the client involves piping messages down the socket and listening for incoming messages.
Once you have a websocket connection, interacting with the client involves piping messages down the socket and listening for incoming messages.
# Message Requests
There are a number of message types that you can send up the websocket as defined [here](https://github.com/nymtech/nym/blob/develop/clients/native/websocket-requests/src/requests.rs):
# Message Requests
There are a number of message types that you can send up the websocket as defined [here](https://github.com/nymtech/nym/blob/develop/clients/native/websocket-requests/src/requests.rs):
```rust,noplayground
{{#include ../../../../../clients/native/websocket-requests/src/requests.rs:55:97}}
```
## Getting your own address
When you start your app, it is best practice to ask the native client to tell you what your own address is (from the generated configuration files <!--add link -->. If you are running a service, you need to do this in order to know what address to give others. In a client-side piece of code you can also use this as a test to make sure your websocket connection is running smoothly. To do this, send:
When you start your app, it is best practice to ask the native client to tell you what your own address is (from the generated configuration files - see [here](https://nymtech.net/docs/architecture/addressing-system.md) for more on Nym's addressing scheme). If you are running a service, you need to do this in order to know what address to give others. In a client-side piece of code you can also use this as a test to make sure your websocket connection is running smoothly. To do this, send:
```json
{
@@ -28,9 +28,9 @@ You'll receive a response of the format:
}
```
See [here](https://github.com/nymtech/nym/blob/93cc281abc2cc951023b51746fa6f2ead1f56c46/clients/native/examples/python-examples/websocket/textsend.py#L16C9-L16C9) for an example of this being used.
See [here](https://github.com/nymtech/nym/blob/93cc281abc2cc951023b51746fa6f2ead1f56c46/clients/native/examples/python-examples/websocket/textsend.py#L16C9-L16C9) for an example of this being used.
> Note that all the pieces of native client example code begin with printing the selfAddress. Examples exist for Rust, Go, Javascript, and Python.
> Note that all the pieces of native client example code begin with printing the selfAddress. Examples exist for Rust, Go, Javascript, and Python.
## Sending text
If you want to send text information through the mixnet, format a message like this one and poke it into the websocket:
@@ -58,33 +58,33 @@ In some applications, e.g. where people are chatting with friends who they know,
**If that fits your security model, good. However, will probably be the case that you want to send anonymous replies using Single Use Reply Blocks (SURBs)**.
You can read more about SURBs [here](https://nymtech.net/docs/architecture/traffic-flow.html#private-replies-using-surbs) but in short they are ways for the receiver of this message to anonymously reply to you - the sender - **without them having to know your client address**.
You can read more about SURBs [here](https://nymtech.net/docs/architecture/traffic-flow.md#private-replies-using-surbs) but in short they are ways for the receiver of this message to anonymously reply to you - the sender - **without them having to know your client address**.
Your client will send along a number of `replySurbs` to the recipient of the message. These are pre-addressed Sphinx packets that the recipient can write to the payload of (i.e. write response data to), but not view the final destination of. If the recipient is unable to fit the response data into the bucket of SURBs sent to it, it will use a SURB to request more SURBs be sent to it from your client.
```json
{
"type": "sendAnonymous",
"message": "something you want to keep secret",
"recipient": "71od3ZAupdCdxeFNg8sdonqfZTnZZy1E86WYKEjxD4kj@FWYoUrnKuXryysptnCZgUYRTauHq4FnEFu2QGn5LZWbm",
"message": "something you want to keep secret",
"recipient": "71od3ZAupdCdxeFNg8sdonqfZTnZZy1E86WYKEjxD4kj@FWYoUrnKuXryysptnCZgUYRTauHq4FnEFu2QGn5LZWbm",
"replySurbs": 20 // however many reply SURBs to send along with your message
}
```
See ['Replying to SURB Messages'](#replying-to-surb-messages) below for an example of how to deal with incoming messages that have SURBs attached.
See ['Replying to SURB Messages'](#replying-to-surb-messages) below for an example of how to deal with incoming messages that have SURBs attached.
Deciding on the amount of SURBs to generate and send along with outgoing messages depends on the expected size of the reply. You might want to send a lot of SURBs in order to make sure you get your response as quickly as possible (but accept the minor additional latency when sending, as your client has to generate and encrypt the packets), or you might just send a few (e.g. 20) and then if your response requires more SURBs, send them along, accepting the additional latency in getting your response.
Deciding on the amount of SURBs to generate and send along with outgoing messages depends on the expected size of the reply. You might want to send a lot of SURBs in order to make sure you get your response as quickly as possible (but accept the minor additional latency when sending, as your client has to generate and encrypt the packets), or you might just send a few (e.g. 20) and then if your response requires more SURBs, send them along, accepting the additional latency in getting your response.
## Sending binary data
You can also send bytes instead of JSON. For that you have to send a binary websocket frame containing a binary encoded
Nym [`ClientRequest`](https://github.com/nymtech/nym/blob/develop/clients/native/websocket-requests/src/requests.rs#L25) containing the same information.
> As a response the `native-client` will send a `ServerResponse` to be decoded. See [Message Responses](#message-responses) below for more.
> As a response the `native-client` will send a `ServerResponse` to be decoded. See [Message Responses](#message-responses) below for more.
You can find examples of sending and receiving binary data in the [code examples](https://github.com/nymtech/nym/tree/master/clients/native/examples), and an example project from the Nym community [BTC-BC](https://github.com/sgeisler/btcbc-rs/): Bitcoin transaction transmission via Nym, a client and service provider written in Rust.
## Replying to SURB messages
Each bucket of `replySURBs`, when received as part of an incoming message, has a unique session identifier, which **only identifies the bucket of pre-addressed packets**. This is necessary to make sure that your app is replying to the correct people with the information meant for them in a situation where multiple clients are sending requests to a single service.
Each bucket of `replySURBs`, when received as part of an incoming message, has a unique session identifier, which **only identifies the bucket of pre-addressed packets**. This is necessary to make sure that your app is replying to the correct people with the information meant for them in a situation where multiple clients are sending requests to a single service.
Constructing a reply with SURBs looks something like this (where `senderTag` was parsed from the incoming message)
@@ -107,9 +107,9 @@ Errors from the app's client, or from the gateway, will be sent down the websock
```
## LaneQueueLength
This is currently only used in the [Socks Client](../socks5-client.md) to keep track of the number of Sphinx packets waiting to be sent to the mixnet via being slotted amongst cover traffic. As this value becomes larger, the client signals to the application it should slow down the speed with which it writes to the proxy. This is to stop situations arising whereby an app connected to the client appears as if it has sent (e.g.) a bunch of messages and is awaiting a reply, when they in fact have not been sent through the mixnet yet.
This is currently only used in the [Socks Client](../socks5-client.md) to keep track of the number of Sphinx packets waiting to be sent to the mixnet via being slotted amongst cover traffic. As this value becomes larger, the client signals to the application it should slow down the speed with which it writes to the proxy. This is to stop situations arising whereby an app connected to the client appears as if it has sent (e.g.) a bunch of messages and is awaiting a reply, when they in fact have not been sent through the mixnet yet.
# Message Responses
# Message Responses
Responses to your messages are defined [here](https://github.com/nymtech/nym/blob/develop/clients/native/websocket-requests/src/responses.rs):
```rust,noplayground

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