Compare commits
92 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ffbf5d8daf | |||
| 87d4cd5400 | |||
| 56fa743be3 | |||
| f6fa071d9d | |||
| 67920ab1bc | |||
| ddadd3c2e9 | |||
| bd31db24b5 | |||
| ca470ab757 | |||
| 561147573b | |||
| 314336a386 | |||
| 92efad3116 | |||
| 1907170e92 | |||
| 044c537a88 | |||
| 7b1a05acda | |||
| 8c7e9501e4 | |||
| c85be2b99b | |||
| 2a4fdc83c4 | |||
| 3445ec88a7 | |||
| c0fd0b7b47 | |||
| fbe4931745 | |||
| 430928d75a | |||
| 4fa3bd4b72 | |||
| 393bbc188e | |||
| 66637be98e | |||
| a6045b7956 | |||
| 93157f5308 | |||
| 24d714c642 | |||
| 6ac2d8939d | |||
| e58c53dd1a | |||
| 1b1373fb2f | |||
| fa0a681529 | |||
| 5ae9510933 | |||
| 927558be73 | |||
| 28c3e3bb6e | |||
| b485085a55 | |||
| 0e6b505d50 | |||
| e0cdb5978f | |||
| ae69ecea54 | |||
| 3bf7ff0870 | |||
| 87bc27daa1 | |||
| cf8910bb72 | |||
| d00fd92d9a | |||
| 21d5ecd4b4 | |||
| 505ba9c83d | |||
| c55499df37 | |||
| cdc8840868 | |||
| 1e17041d8a | |||
| d46c51a966 | |||
| 2f4e74d180 | |||
| 09feaf4fe1 | |||
| 032e990c37 | |||
| 4d7262e051 | |||
| 2a2ecab852 | |||
| f7c39397b3 | |||
| 2c47c932e8 | |||
| 21acab9857 | |||
| e18dd80b36 | |||
| 712fa519e9 | |||
| cf2afc6adf | |||
| 8318c7ff61 | |||
| e36d4f105d | |||
| 14f659337c | |||
| cc2d4c3376 | |||
| d8c3a3f738 | |||
| 7d561bff63 | |||
| 9daa2f6e98 | |||
| 74c3dbe169 | |||
| 8c4f2fde78 | |||
| e5efba2d45 | |||
| 02bfa9a7ab | |||
| cea6ac1d3e | |||
| 1ac262ec90 | |||
| 7c1fca8ce4 | |||
| f3ac17eb9d | |||
| 6296d09adf | |||
| 2ae81f6da0 | |||
| 1d5e8b62ac | |||
| 581cdd5bdf | |||
| e2e49e7136 | |||
| dff82f946f | |||
| ec61728654 | |||
| 61471e9058 | |||
| ed4fd84503 | |||
| cb4b0403b5 | |||
| da8e513627 | |||
| 3f6de8b10c | |||
| 1e01a8e633 | |||
| aaf3dca5b9 | |||
| f939cae3d9 | |||
| 1db61f800c | |||
| 5096c1e60e | |||
| 7e36595d8f |
@@ -0,0 +1,7 @@
|
||||
.git
|
||||
.github
|
||||
.gitignore
|
||||
**/node_modules
|
||||
**/target
|
||||
dist
|
||||
documentation
|
||||
@@ -62,6 +62,10 @@ jobs:
|
||||
echo 'RUSTFLAGS="--cfg tokio_unstable"' >> $GITHUB_ENV
|
||||
if: github.event_name == 'workflow_dispatch' && inputs.add_tokio_unstable == true
|
||||
|
||||
- name: Set CARGO_FEATURES
|
||||
run: |
|
||||
echo 'CARGO_FEATURES=--features wireguard' >> $GITHUB_ENV
|
||||
|
||||
- name: Install Rust stable
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
|
||||
@@ -73,27 +73,29 @@ jobs:
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: build
|
||||
# Enable wireguard by default on linux only
|
||||
args: --workspace --features wireguard
|
||||
|
||||
- name: Build all examples
|
||||
if: matrix.os == 'custom-linux'
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: build
|
||||
args: --workspace --examples
|
||||
args: --workspace --examples --features wireguard
|
||||
|
||||
- name: Run all tests
|
||||
if: matrix.os == 'custom-linux'
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: test
|
||||
args: --workspace
|
||||
args: --workspace --features wireguard
|
||||
|
||||
- name: Run expensive tests
|
||||
if: (github.ref == 'refs/heads/develop' || github.event.pull_request.base.ref == 'develop' || github.event.pull_request.base.ref == 'master') && matrix.os == 'custom-linux'
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: test
|
||||
args: --workspace -- --ignored
|
||||
args: --workspace --features wireguard -- --ignored
|
||||
|
||||
- name: Annotate with clippy checks
|
||||
if: matrix.os == 'custom-linux'
|
||||
@@ -101,10 +103,10 @@ jobs:
|
||||
continue-on-error: true
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
args: --workspace
|
||||
args: --workspace --features wireguard
|
||||
|
||||
- name: Clippy
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: clippy
|
||||
args: --workspace --all-targets -- -D warnings
|
||||
args: --workspace --all-targets --features wireguard -- -D warnings
|
||||
|
||||
@@ -51,6 +51,10 @@ jobs:
|
||||
echo 'RUSTFLAGS="--cfg tokio_unstable"' >> $GITHUB_ENV
|
||||
if: github.event_name == 'workflow_dispatch' && inputs.add_tokio_unstable == true
|
||||
|
||||
- name: Set CARGO_FEATURES
|
||||
run: |
|
||||
echo 'CARGO_FEATURES=--features wireguard' >> $GITHUB_ENV
|
||||
|
||||
- name: Install Rust stable
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
|
||||
+4
-1
@@ -48,4 +48,7 @@ foxyfox.env
|
||||
|
||||
.next
|
||||
ppa-private-key.b64
|
||||
ppa-private-key.asc
|
||||
ppa-private-key.asc
|
||||
nym-network-monitor/topology.json
|
||||
nym-network-monitor/__pycache__
|
||||
nym-network-monitor/*.key
|
||||
@@ -4,38 +4,6 @@ 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
+309
-84
@@ -332,12 +332,29 @@ 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"
|
||||
@@ -544,7 +561,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "93f2635620bf0b9d4576eb7bb9a38a55df78bd1205d26fa994b25911a69f212f"
|
||||
dependencies = [
|
||||
"bitcoin_hashes",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"rand_core 0.6.4",
|
||||
"serde",
|
||||
"unicode-normalization",
|
||||
@@ -985,6 +1002,15 @@ 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"
|
||||
@@ -1840,6 +1866,7 @@ dependencies = [
|
||||
"lock_api",
|
||||
"once_cell",
|
||||
"parking_lot_core 0.9.10",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2166,6 +2193,16 @@ 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"
|
||||
@@ -2189,6 +2226,19 @@ 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"
|
||||
@@ -2222,7 +2272,7 @@ checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
|
||||
|
||||
[[package]]
|
||||
name = "explorer-api"
|
||||
version = "1.1.39"
|
||||
version = "1.1.38"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"clap 4.5.7",
|
||||
@@ -2241,8 +2291,8 @@ dependencies = [
|
||||
"nym-validator-client",
|
||||
"okapi",
|
||||
"pretty_env_logger",
|
||||
"rand",
|
||||
"rand_pcg",
|
||||
"rand 0.8.5",
|
||||
"rand_pcg 0.3.1",
|
||||
"rand_seeder",
|
||||
"reqwest 0.12.4",
|
||||
"rocket",
|
||||
@@ -2379,6 +2429,12 @@ 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"
|
||||
@@ -2441,6 +2497,12 @@ 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"
|
||||
@@ -3321,7 +3383,7 @@ version = "1.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"autocfg 1.3.0",
|
||||
"hashbrown 0.12.3",
|
||||
"serde",
|
||||
]
|
||||
@@ -3736,7 +3798,7 @@ version = "0.4.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"autocfg 1.3.0",
|
||||
"scopeguard",
|
||||
]
|
||||
|
||||
@@ -3863,7 +3925,7 @@ version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"autocfg 1.3.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3933,7 +3995,7 @@ dependencies = [
|
||||
"nym-ordered-buffer",
|
||||
"nym-service-providers-common",
|
||||
"nym-socks5-requests",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"serde",
|
||||
"serde-wasm-bindgen 0.6.5",
|
||||
"thiserror",
|
||||
@@ -4149,7 +4211,7 @@ version = "0.2.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"autocfg 1.3.0",
|
||||
"libm",
|
||||
]
|
||||
|
||||
@@ -4180,7 +4242,7 @@ checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3"
|
||||
|
||||
[[package]]
|
||||
name = "nym-api"
|
||||
version = "1.1.43"
|
||||
version = "1.1.42"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@@ -4229,12 +4291,13 @@ dependencies = [
|
||||
"nym-sphinx",
|
||||
"nym-task",
|
||||
"nym-topology",
|
||||
"nym-types",
|
||||
"nym-validator-client",
|
||||
"nym-vesting-contract-common",
|
||||
"okapi",
|
||||
"pin-project",
|
||||
"rand",
|
||||
"rand_chacha",
|
||||
"rand 0.8.5",
|
||||
"rand_chacha 0.3.1",
|
||||
"reqwest 0.12.4",
|
||||
"rocket",
|
||||
"rocket_cors",
|
||||
@@ -4320,7 +4383,7 @@ dependencies = [
|
||||
"nym-types",
|
||||
"nym-wireguard",
|
||||
"nym-wireguard-types",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
@@ -4337,7 +4400,7 @@ dependencies = [
|
||||
"bincode",
|
||||
"nym-sphinx",
|
||||
"nym-wireguard-types",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"serde",
|
||||
]
|
||||
|
||||
@@ -4355,7 +4418,7 @@ dependencies = [
|
||||
"nym-ecash-time",
|
||||
"nym-network-defaults",
|
||||
"nym-validator-client",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"thiserror",
|
||||
"url",
|
||||
"zeroize",
|
||||
@@ -4401,7 +4464,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-cli"
|
||||
version = "1.1.41"
|
||||
version = "1.1.40"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"base64 0.13.1",
|
||||
@@ -4429,12 +4492,11 @@ name = "nym-cli-commands"
|
||||
version = "1.0.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"base64 0.21.7",
|
||||
"base64 0.13.1",
|
||||
"bip39",
|
||||
"bs58 0.5.1",
|
||||
"cfg-if",
|
||||
"clap 4.5.7",
|
||||
"colored",
|
||||
"comfy-table 6.2.0",
|
||||
"cosmrs 0.17.0-pre",
|
||||
"cosmwasm-std",
|
||||
@@ -4467,21 +4529,21 @@ dependencies = [
|
||||
"nym-types",
|
||||
"nym-validator-client",
|
||||
"nym-vesting-contract-common",
|
||||
"rand",
|
||||
"rand 0.6.5",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tap",
|
||||
"thiserror",
|
||||
"time",
|
||||
"tokio",
|
||||
"toml 0.8.14",
|
||||
"toml 0.5.11",
|
||||
"url",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nym-client"
|
||||
version = "1.1.40"
|
||||
version = "1.1.39"
|
||||
dependencies = [
|
||||
"bs58 0.5.1",
|
||||
"clap 4.5.7",
|
||||
@@ -4504,7 +4566,7 @@ dependencies = [
|
||||
"nym-task",
|
||||
"nym-topology",
|
||||
"nym-validator-client",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tap",
|
||||
@@ -4555,7 +4617,8 @@ dependencies = [
|
||||
"nym-task",
|
||||
"nym-topology",
|
||||
"nym-validator-client",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"rand_chacha 0.3.1",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha2 0.10.8",
|
||||
@@ -4635,7 +4698,7 @@ dependencies = [
|
||||
"nym-bin-common",
|
||||
"nym-node-tester-utils",
|
||||
"nym-node-tester-wasm",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"serde",
|
||||
"serde-wasm-bindgen 0.6.5",
|
||||
"serde_json",
|
||||
@@ -4672,8 +4735,8 @@ dependencies = [
|
||||
"itertools 0.13.0",
|
||||
"nym-dkg",
|
||||
"nym-pemstore",
|
||||
"rand",
|
||||
"rand_chacha",
|
||||
"rand 0.8.5",
|
||||
"rand_chacha 0.3.1",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"sha2 0.9.9",
|
||||
@@ -4719,7 +4782,7 @@ dependencies = [
|
||||
"itertools 0.12.1",
|
||||
"nym-network-defaults",
|
||||
"nym-pemstore",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"rayon",
|
||||
"serde",
|
||||
"sha2 0.9.9",
|
||||
@@ -4813,7 +4876,7 @@ dependencies = [
|
||||
"nym-ecash-time",
|
||||
"nym-network-defaults",
|
||||
"nym-validator-client",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"serde",
|
||||
"thiserror",
|
||||
"time",
|
||||
@@ -4828,7 +4891,7 @@ dependencies = [
|
||||
"nym-compact-ecash",
|
||||
"nym-ecash-time",
|
||||
"nym-network-defaults",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"serde",
|
||||
"strum 0.25.0",
|
||||
"thiserror",
|
||||
@@ -4851,8 +4914,8 @@ dependencies = [
|
||||
"hmac",
|
||||
"nym-pemstore",
|
||||
"nym-sphinx-types",
|
||||
"rand",
|
||||
"rand_chacha",
|
||||
"rand 0.8.5",
|
||||
"rand_chacha 0.3.1",
|
||||
"serde",
|
||||
"serde_bytes",
|
||||
"subtle-encoding",
|
||||
@@ -4874,8 +4937,8 @@ dependencies = [
|
||||
"lazy_static",
|
||||
"nym-contracts-common",
|
||||
"nym-pemstore",
|
||||
"rand",
|
||||
"rand_chacha",
|
||||
"rand 0.8.5",
|
||||
"rand_chacha 0.3.1",
|
||||
"rand_core 0.6.4",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
@@ -5005,7 +5068,7 @@ dependencies = [
|
||||
"nym-wireguard",
|
||||
"nym-wireguard-types",
|
||||
"once_cell",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"si-scale",
|
||||
@@ -5040,7 +5103,7 @@ dependencies = [
|
||||
"nym-sphinx",
|
||||
"nym-task",
|
||||
"nym-validator-client",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"serde",
|
||||
"si-scale",
|
||||
"thiserror",
|
||||
@@ -5069,8 +5132,7 @@ dependencies = [
|
||||
"nym-crypto",
|
||||
"nym-pemstore",
|
||||
"nym-sphinx",
|
||||
"nym-task",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
@@ -5170,7 +5232,7 @@ name = "nym-inclusion-probability"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"log",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
@@ -5183,7 +5245,7 @@ dependencies = [
|
||||
"nym-bin-common",
|
||||
"nym-crypto",
|
||||
"nym-sphinx",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"serde",
|
||||
"thiserror",
|
||||
"time",
|
||||
@@ -5220,7 +5282,7 @@ dependencies = [
|
||||
"nym-types",
|
||||
"nym-wireguard",
|
||||
"nym-wireguard-types",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"reqwest 0.12.4",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@@ -5277,7 +5339,7 @@ dependencies = [
|
||||
"humantime-serde",
|
||||
"log",
|
||||
"nym-contracts-common",
|
||||
"rand_chacha",
|
||||
"rand_chacha 0.3.1",
|
||||
"schemars",
|
||||
"serde",
|
||||
"serde-json-wasm",
|
||||
@@ -5320,7 +5382,7 @@ dependencies = [
|
||||
"nym-topology",
|
||||
"nym-types",
|
||||
"nym-validator-client",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sysinfo 0.27.8",
|
||||
@@ -5353,7 +5415,7 @@ dependencies = [
|
||||
"nym-sphinx-types",
|
||||
"nym-task",
|
||||
"nym-validator-client",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"serde",
|
||||
"thiserror",
|
||||
"time",
|
||||
@@ -5388,9 +5450,39 @@ 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.41"
|
||||
version = "1.1.40"
|
||||
dependencies = [
|
||||
"addr",
|
||||
"anyhow",
|
||||
@@ -5423,7 +5515,7 @@ dependencies = [
|
||||
"nym-types",
|
||||
"pretty_env_logger",
|
||||
"publicsuffix",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"regex",
|
||||
"reqwest 0.12.4",
|
||||
"serde",
|
||||
@@ -5441,7 +5533,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-node"
|
||||
version = "1.1.7"
|
||||
version = "1.1.6"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bip39",
|
||||
@@ -5470,7 +5562,7 @@ dependencies = [
|
||||
"nym-types",
|
||||
"nym-wireguard",
|
||||
"nym-wireguard-types",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"semver 1.0.23",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@@ -5504,7 +5596,7 @@ dependencies = [
|
||||
"nym-task",
|
||||
"nym-wireguard",
|
||||
"nym-wireguard-types",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
"time",
|
||||
@@ -5531,7 +5623,7 @@ dependencies = [
|
||||
"nym-exit-policy",
|
||||
"nym-http-api-client",
|
||||
"nym-wireguard-types",
|
||||
"rand_chacha",
|
||||
"rand_chacha 0.3.1",
|
||||
"schemars",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@@ -5552,7 +5644,8 @@ dependencies = [
|
||||
"nym-sphinx-params",
|
||||
"nym-task",
|
||||
"nym-topology",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"rand_chacha 0.3.1",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
@@ -5567,7 +5660,7 @@ dependencies = [
|
||||
"futures",
|
||||
"js-sys",
|
||||
"nym-node-tester-utils",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"serde",
|
||||
"serde-wasm-bindgen 0.6.5",
|
||||
"thiserror",
|
||||
@@ -5626,7 +5719,7 @@ dependencies = [
|
||||
"fastrand 2.1.0",
|
||||
"getrandom",
|
||||
"log",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"rayon",
|
||||
"sphinx-packet",
|
||||
"thiserror",
|
||||
@@ -5675,7 +5768,7 @@ dependencies = [
|
||||
"nym-validator-client",
|
||||
"parking_lot 0.12.3",
|
||||
"pretty_env_logger",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"reqwest 0.12.4",
|
||||
"tap",
|
||||
"thiserror",
|
||||
@@ -5715,7 +5808,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-socks5-client"
|
||||
version = "1.1.40"
|
||||
version = "1.1.39"
|
||||
dependencies = [
|
||||
"bs58 0.5.1",
|
||||
"clap 4.5.7",
|
||||
@@ -5735,7 +5828,7 @@ dependencies = [
|
||||
"nym-sphinx",
|
||||
"nym-topology",
|
||||
"nym-validator-client",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tap",
|
||||
@@ -5768,7 +5861,7 @@ dependencies = [
|
||||
"nym-task",
|
||||
"nym-validator-client",
|
||||
"pin-project",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"reqwest 0.12.4",
|
||||
"schemars",
|
||||
"serde",
|
||||
@@ -5794,7 +5887,7 @@ dependencies = [
|
||||
"nym-credential-storage",
|
||||
"nym-crypto",
|
||||
"nym-socks5-client-core",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"safer-ffi",
|
||||
"serde",
|
||||
"tokio",
|
||||
@@ -5836,6 +5929,7 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"log",
|
||||
"nym-crypto",
|
||||
"nym-metrics",
|
||||
"nym-mixnet-contract-common",
|
||||
"nym-sphinx-acknowledgements",
|
||||
"nym-sphinx-addressing",
|
||||
@@ -5848,7 +5942,8 @@ dependencies = [
|
||||
"nym-sphinx-routing",
|
||||
"nym-sphinx-types",
|
||||
"nym-topology",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"rand_chacha 0.3.1",
|
||||
"rand_distr",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
@@ -5866,7 +5961,7 @@ dependencies = [
|
||||
"nym-sphinx-routing",
|
||||
"nym-sphinx-types",
|
||||
"nym-topology",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"serde",
|
||||
"thiserror",
|
||||
"zeroize",
|
||||
@@ -5878,7 +5973,7 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"nym-crypto",
|
||||
"nym-sphinx-types",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"serde",
|
||||
"thiserror",
|
||||
]
|
||||
@@ -5894,8 +5989,8 @@ dependencies = [
|
||||
"nym-sphinx-routing",
|
||||
"nym-sphinx-types",
|
||||
"nym-topology",
|
||||
"rand",
|
||||
"rand_chacha",
|
||||
"rand 0.8.5",
|
||||
"rand_chacha 0.3.1",
|
||||
"serde",
|
||||
"thiserror",
|
||||
"wasm-bindgen",
|
||||
@@ -5905,12 +6000,17 @@ 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",
|
||||
"rand 0.8.5",
|
||||
"serde",
|
||||
"thiserror",
|
||||
"utoipa",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -5926,7 +6026,7 @@ dependencies = [
|
||||
"nym-sphinx-routing",
|
||||
"nym-sphinx-types",
|
||||
"nym-topology",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
@@ -5988,7 +6088,7 @@ dependencies = [
|
||||
"argon2",
|
||||
"generic-array 0.14.7",
|
||||
"getrandom",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
@@ -6023,7 +6123,8 @@ dependencies = [
|
||||
"nym-sphinx-addressing",
|
||||
"nym-sphinx-routing",
|
||||
"nym-sphinx-types",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"reqwest 0.12.4",
|
||||
"semver 0.11.0",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@@ -6147,7 +6248,7 @@ dependencies = [
|
||||
"nym-task",
|
||||
"nym-validator-client",
|
||||
"nyxd-scraper",
|
||||
"rand_chacha",
|
||||
"rand_chacha 0.3.1",
|
||||
"serde",
|
||||
"serde_with",
|
||||
"sha2 0.10.8",
|
||||
@@ -6220,13 +6321,12 @@ name = "nym-wireguard-types"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"base64 0.21.7",
|
||||
"dashmap",
|
||||
"hmac",
|
||||
"log",
|
||||
"nym-config",
|
||||
"nym-crypto",
|
||||
"nym-network-defaults",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha2 0.10.8",
|
||||
@@ -6237,7 +6337,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nymvisor"
|
||||
version = "0.1.6"
|
||||
version = "0.1.5"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bytes",
|
||||
@@ -6436,7 +6536,7 @@ dependencies = [
|
||||
"once_cell",
|
||||
"opentelemetry_api",
|
||||
"percent-encoding",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
@@ -6661,6 +6761,16 @@ 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"
|
||||
@@ -6749,7 +6859,7 @@ version = "2.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"autocfg 1.3.0",
|
||||
"bitflags 1.3.2",
|
||||
"cfg-if",
|
||||
"concurrent-queue",
|
||||
@@ -7003,6 +7113,25 @@ 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"
|
||||
@@ -7010,10 +7139,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"rand_chacha",
|
||||
"rand_chacha 0.3.1",
|
||||
"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"
|
||||
@@ -7024,6 +7163,21 @@ 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"
|
||||
@@ -7046,7 +7200,60 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32cb0b9bc82b0a0876c2dd994a7e7a2683d3e7390ca40e6886785ef0c7e3ee31"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
"rand",
|
||||
"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",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -7067,6 +7274,15 @@ 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"
|
||||
@@ -7087,6 +7303,15 @@ 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"
|
||||
@@ -7344,7 +7569,7 @@ dependencies = [
|
||||
"num_cpus",
|
||||
"parking_lot 0.12.3",
|
||||
"pin-project-lite",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"ref-cast",
|
||||
"rocket_codegen",
|
||||
"rocket_http",
|
||||
@@ -8117,7 +8342,7 @@ version = "0.4.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"autocfg 1.3.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -8188,7 +8413,7 @@ dependencies = [
|
||||
"hmac",
|
||||
"lioness",
|
||||
"log",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"rand_distr",
|
||||
"sha2 0.10.8",
|
||||
"subtle 2.5.0",
|
||||
@@ -8732,7 +8957,7 @@ dependencies = [
|
||||
"getrandom",
|
||||
"peg",
|
||||
"pin-project",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"reqwest 0.11.27",
|
||||
"semver 1.0.23",
|
||||
"serde",
|
||||
@@ -8786,7 +9011,7 @@ dependencies = [
|
||||
"nym-pemstore",
|
||||
"nym-validator-client",
|
||||
"nym-vesting-contract-common",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sqlx",
|
||||
@@ -9186,7 +9411,7 @@ dependencies = [
|
||||
"indexmap 1.9.3",
|
||||
"pin-project",
|
||||
"pin-project-lite",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"slab",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
@@ -9452,7 +9677,7 @@ dependencies = [
|
||||
"http 0.2.12",
|
||||
"httparse",
|
||||
"log",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"rustls 0.21.12",
|
||||
"sha1",
|
||||
"thiserror",
|
||||
@@ -9473,7 +9698,7 @@ dependencies = [
|
||||
"http 1.1.0",
|
||||
"httparse",
|
||||
"log",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"rustls 0.22.4",
|
||||
"rustls-pki-types",
|
||||
"sha1",
|
||||
@@ -9893,7 +10118,7 @@ dependencies = [
|
||||
"nym-task",
|
||||
"nym-topology",
|
||||
"nym-validator-client",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"serde",
|
||||
"serde-wasm-bindgen 0.6.5",
|
||||
"thiserror",
|
||||
@@ -10528,7 +10753,7 @@ dependencies = [
|
||||
"nym-credentials",
|
||||
"nym-crypto",
|
||||
"nym-http-api-client",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"reqwest 0.12.4",
|
||||
"serde",
|
||||
"thiserror",
|
||||
|
||||
+3
-1
@@ -14,7 +14,6 @@ panic = "abort"
|
||||
opt-level = 3
|
||||
|
||||
[workspace]
|
||||
|
||||
resolver = "2"
|
||||
members = [
|
||||
"clients/native",
|
||||
@@ -94,6 +93,7 @@ members = [
|
||||
"common/wasm/utils",
|
||||
"common/wireguard",
|
||||
"common/wireguard-types",
|
||||
"documentation/autodoc",
|
||||
"explorer-api",
|
||||
"explorer-api/explorer-api-requests",
|
||||
"explorer-api/explorer-client",
|
||||
@@ -106,6 +106,7 @@ 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",
|
||||
@@ -159,6 +160,7 @@ 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,6 +1,6 @@
|
||||
[package]
|
||||
name = "nym-client"
|
||||
version = "1.1.40"
|
||||
version = "1.1.39"
|
||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"]
|
||||
description = "Implementation of the Nym Client"
|
||||
edition = "2021"
|
||||
|
||||
@@ -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.mark_as_success();
|
||||
task_client.disarm();
|
||||
|
||||
let ws_stream = match accept_async(socket).await {
|
||||
Ok(ws_stream) => ws_stream,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "nym-socks5-client"
|
||||
version = "1.1.40"
|
||||
version = "1.1.39"
|
||||
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,9 +2,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::error::BandwidthControllerError;
|
||||
use crate::utils::{
|
||||
get_aggregate_verification_key, get_coin_index_signatures, get_expiration_date_signatures,
|
||||
};
|
||||
use crate::utils::{get_coin_index_signatures, get_expiration_date_signatures};
|
||||
use log::info;
|
||||
use nym_credential_storage::storage::Storage;
|
||||
use nym_credentials::ecash::bandwidth::IssuanceTicketBook;
|
||||
@@ -57,7 +55,7 @@ where
|
||||
))
|
||||
}
|
||||
|
||||
pub async fn query_and_persist_required_global_data<S>(
|
||||
pub async fn query_and_persist_required_global_signatures<S>(
|
||||
storage: &S,
|
||||
epoch_id: EpochId,
|
||||
expiration_date: Date,
|
||||
@@ -67,10 +65,6 @@ 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?;
|
||||
|
||||
@@ -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, VerificationKeyAuth,
|
||||
AnnotatedCoinIndexSignature, AnnotatedExpirationDateSignature, NymPayInfo, VerificationKeyAuth,
|
||||
};
|
||||
use nym_ecash_time::Date;
|
||||
use nym_validator_client::nym_api::EpochId;
|
||||
@@ -165,9 +165,7 @@ impl<C, St: Storage> BandwidthController<C, St> {
|
||||
.get_coin_index_signatures(epoch_id, &mut api_clients)
|
||||
.await?;
|
||||
|
||||
let pay_info = retrieved_ticketbook
|
||||
.ticketbook
|
||||
.generate_pay_info(provider_pk);
|
||||
let pay_info = NymPayInfo::generate(provider_pk);
|
||||
|
||||
let spend_request = retrieved_ticketbook.ticketbook.prepare_for_spending(
|
||||
&verification_key,
|
||||
|
||||
@@ -19,6 +19,7 @@ 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.mark_as_success();
|
||||
shutdown.disarm();
|
||||
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.mark_as_success();
|
||||
shutdown.disarm();
|
||||
} 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::info!("{}", rates.summary());
|
||||
log::debug!("{}", 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::info!(
|
||||
log::debug!(
|
||||
"mix packet retransmissions/real mix packets: {}/{}",
|
||||
delta.retransmissions_queued,
|
||||
delta.real_packets_queued,
|
||||
|
||||
@@ -453,6 +453,7 @@ 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,13 +474,6 @@ 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");
|
||||
|
||||
@@ -46,13 +46,34 @@ const MEASUREMENTS: usize = 3;
|
||||
const CONN_TIMEOUT: Duration = Duration::from_millis(1500);
|
||||
const PING_TIMEOUT: Duration = Duration::from_millis(1000);
|
||||
|
||||
struct GatewayWithLatency<'a> {
|
||||
gateway: &'a gateway::Node,
|
||||
// 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,
|
||||
latency: Duration,
|
||||
}
|
||||
|
||||
impl<'a> GatewayWithLatency<'a> {
|
||||
fn new(gateway: &'a gateway::Node, latency: Duration) -> Self {
|
||||
impl<'a, G: ConnectableGateway> GatewayWithLatency<'a, G> {
|
||||
fn new(gateway: &'a G, latency: Duration) -> Self {
|
||||
GatewayWithLatency { gateway, latency }
|
||||
}
|
||||
}
|
||||
@@ -130,11 +151,14 @@ async fn connect(endpoint: &str) -> Result<WsConn, ClientCoreError> {
|
||||
JSWebsocket::new(endpoint).map_err(|_| ClientCoreError::GatewayJsConnectionFailure)
|
||||
}
|
||||
|
||||
async fn measure_latency(gateway: &gateway::Node) -> Result<GatewayWithLatency, ClientCoreError> {
|
||||
async fn measure_latency<G>(gateway: &G) -> Result<GatewayWithLatency<G>, ClientCoreError>
|
||||
where
|
||||
G: ConnectableGateway,
|
||||
{
|
||||
let addr = gateway.clients_address();
|
||||
trace!(
|
||||
"establishing connection to {} ({addr})...",
|
||||
gateway.identity_key,
|
||||
gateway.identity(),
|
||||
);
|
||||
let mut stream = connect(&addr).await?;
|
||||
|
||||
@@ -177,7 +201,7 @@ async fn measure_latency(gateway: &gateway::Node) -> Result<GatewayWithLatency,
|
||||
let count = results.len() as u64;
|
||||
if count == 0 {
|
||||
return Err(ClientCoreError::NoGatewayMeasurements {
|
||||
identity: gateway.identity_key.to_base58_string(),
|
||||
identity: gateway.identity().to_base58_string(),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -187,11 +211,11 @@ async fn measure_latency(gateway: &gateway::Node) -> Result<GatewayWithLatency,
|
||||
Ok(GatewayWithLatency::new(gateway, avg))
|
||||
}
|
||||
|
||||
pub async fn choose_gateway_by_latency<R: Rng>(
|
||||
pub async fn choose_gateway_by_latency<'a, R: Rng, G: ConnectableGateway + Clone>(
|
||||
rng: &mut R,
|
||||
gateways: &[gateway::Node],
|
||||
gateways: &[G],
|
||||
must_use_tls: bool,
|
||||
) -> Result<gateway::Node, ClientCoreError> {
|
||||
) -> Result<G, ClientCoreError> {
|
||||
let gateways = filter_by_tls(gateways, must_use_tls)?;
|
||||
|
||||
info!(
|
||||
@@ -223,21 +247,19 @@ pub async fn choose_gateway_by_latency<R: Rng>(
|
||||
|
||||
info!(
|
||||
"chose gateway {} with average latency of {:?}",
|
||||
chosen.gateway.identity_key, chosen.latency
|
||||
chosen.gateway.identity(),
|
||||
chosen.latency
|
||||
);
|
||||
|
||||
Ok(chosen.gateway.clone())
|
||||
}
|
||||
|
||||
fn filter_by_tls(
|
||||
gateways: &[gateway::Node],
|
||||
fn filter_by_tls<G: ConnectableGateway>(
|
||||
gateways: &[G],
|
||||
must_use_tls: bool,
|
||||
) -> Result<Vec<&gateway::Node>, ClientCoreError> {
|
||||
) -> Result<Vec<&G>, ClientCoreError> {
|
||||
if must_use_tls {
|
||||
let filtered = gateways
|
||||
.iter()
|
||||
.filter(|g| g.clients_wss_port.is_some())
|
||||
.collect::<Vec<_>>();
|
||||
let filtered = gateways.iter().filter(|g| g.is_wss()).collect::<Vec<_>>();
|
||||
|
||||
if filtered.is_empty() {
|
||||
return Err(ClientCoreError::NoWssGateways);
|
||||
|
||||
@@ -417,8 +417,6 @@ impl<C, St> GatewayClient<C, St> {
|
||||
self.local_identity.as_ref(),
|
||||
self.gateway_identity,
|
||||
self.cfg.bandwidth.require_tickets,
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
self.task_client.clone(),
|
||||
)
|
||||
.await
|
||||
.map_err(GatewayClientError::RegistrationFailure),
|
||||
|
||||
@@ -70,8 +70,8 @@ impl PacketRouter {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn mark_as_success(&mut self) {
|
||||
self.shutdown.mark_as_success();
|
||||
pub fn disarm(&mut self) {
|
||||
self.shutdown.disarm();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -113,8 +113,8 @@ impl PartiallyDelegatedRouter {
|
||||
let return_res = match ret {
|
||||
Err(err) => self.stream_return.send(Err(err)),
|
||||
Ok(_) => {
|
||||
self.packet_router.mark_as_success();
|
||||
task_client.mark_as_success();
|
||||
self.packet_router.disarm();
|
||||
task_client.disarm();
|
||||
self.stream_return.send(Ok(split_stream))
|
||||
}
|
||||
};
|
||||
|
||||
@@ -90,4 +90,6 @@ 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,5 +49,7 @@ 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,7 +1,6 @@
|
||||
// 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;
|
||||
@@ -10,6 +9,7 @@ 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,8 +21,7 @@ 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.
|
||||
#[deprecated]
|
||||
pub fn find_attribute_in_logs<'a>(
|
||||
pub fn find_attribute<'a>(
|
||||
logs: &'a [Log],
|
||||
event_type: &str,
|
||||
attribute_key: &str,
|
||||
@@ -36,7 +35,6 @@ pub fn find_attribute_in_logs<'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,24 +1,12 @@
|
||||
// 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> {
|
||||
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 event = tx.tx_result.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
|
||||
@@ -28,23 +16,3 @@ pub fn find_event_attribute(
|
||||
})?;
|
||||
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
|
||||
|
||||
@@ -7,10 +7,9 @@ license.workspace = true
|
||||
|
||||
[dependencies]
|
||||
anyhow = { workspace = true }
|
||||
base64 = { workspace = true }
|
||||
base64 = "0.13.0"
|
||||
bip39 = { workspace = true }
|
||||
bs58 = { workspace = true }
|
||||
colored = { workspace = true }
|
||||
comfy-table = { workspace = true }
|
||||
cfg-if = { workspace = true }
|
||||
clap = { workspace = true, features = ["derive"] }
|
||||
@@ -22,13 +21,13 @@ humantime-serde = { workspace = true }
|
||||
inquire = { workspace = true }
|
||||
k256 = { workspace = true, features = ["ecdsa", "sha256"] }
|
||||
log = { workspace = true }
|
||||
rand = { workspace = true, features = ["std"] }
|
||||
rand = {version = "0.6", 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 = { workspace = true }
|
||||
tokio = { workspace = true, features = ["sync"]}
|
||||
toml = "0.5.6"
|
||||
url = { workspace = true }
|
||||
tap = { workspace = true }
|
||||
zeroize = { workspace = true }
|
||||
|
||||
+5
-13
@@ -9,17 +9,9 @@ use nym_credential_storage::initialise_persistent_storage;
|
||||
use nym_id::import_credential;
|
||||
use std::fs;
|
||||
use std::path::PathBuf;
|
||||
use std::str::FromStr;
|
||||
|
||||
#[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)
|
||||
}
|
||||
fn parse_encoded_credential_data(raw: &str) -> bs58::decode::Result<Vec<u8>> {
|
||||
bs58::decode(raw).into_vec()
|
||||
}
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
@@ -30,8 +22,8 @@ pub struct Args {
|
||||
pub(crate) client_config: PathBuf,
|
||||
|
||||
/// Explicitly provide the encoded credential data (as base58)
|
||||
#[clap(long, group = "cred_data")]
|
||||
pub(crate) credential_data: Option<CredentialDataWrapper>,
|
||||
#[clap(long, group = "cred_data", value_parser = parse_encoded_credential_data)]
|
||||
pub(crate) credential_data: Option<Vec<u8>>,
|
||||
|
||||
/// Specifies the path to file containing binary credential data
|
||||
#[clap(long, group = "cred_data")]
|
||||
@@ -60,7 +52,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.0,
|
||||
Some(data) => data,
|
||||
None => {
|
||||
// SAFETY: one of those arguments must have been set
|
||||
fs::read(args.credential_path.unwrap())?
|
||||
+5
-47
@@ -9,9 +9,6 @@ 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)]
|
||||
@@ -21,20 +18,12 @@ pub struct Args {
|
||||
pub(crate) ticketbook_type: TicketType,
|
||||
|
||||
/// Config file of the client that is supposed to use the credential.
|
||||
#[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>,
|
||||
#[clap(long)]
|
||||
pub(crate) client_config: PathBuf,
|
||||
}
|
||||
|
||||
async fn issue_client_ticketbook(
|
||||
cfg: PathBuf,
|
||||
typ: TicketType,
|
||||
client: SigningClient,
|
||||
) -> anyhow::Result<()> {
|
||||
let loaded = CommonConfigsWrapper::try_load(cfg)?;
|
||||
pub async fn execute(args: Args, client: SigningClient) -> anyhow::Result<()> {
|
||||
let loaded = CommonConfigsWrapper::try_load(args.client_config)?;
|
||||
|
||||
if let Ok(id) = loaded.try_get_id() {
|
||||
println!("loaded config file for client '{id}'");
|
||||
@@ -59,40 +48,9 @@ async fn issue_client_ticketbook(
|
||||
&client,
|
||||
&persistent_storage,
|
||||
&private_id_key.to_bytes(),
|
||||
typ,
|
||||
args.ticketbook_type,
|
||||
)
|
||||
.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,7 +3,6 @@
|
||||
|
||||
use clap::{Args, Subcommand};
|
||||
|
||||
pub mod generate_ticket;
|
||||
pub mod import_ticket_book;
|
||||
pub mod issue_ticket_book;
|
||||
pub mod recover_ticket_book;
|
||||
@@ -20,5 +19,4 @@ pub enum EcashCommands {
|
||||
IssueTicketBook(issue_ticket_book::Args),
|
||||
RecoverTicketBook(recover_ticket_book::Args),
|
||||
ImportTicketBook(import_ticket_book::Args),
|
||||
GenerateTicket(generate_ticket::Args),
|
||||
}
|
||||
@@ -1,178 +0,0 @@
|
||||
// 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(())
|
||||
}
|
||||
@@ -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,11 +10,7 @@ pub struct Args {
|
||||
}
|
||||
|
||||
pub fn decode_mixnode_key(args: Args) {
|
||||
use base64::{engine::general_purpose::STANDARD, Engine as _};
|
||||
|
||||
let b64_decoded = STANDARD
|
||||
.decode(args.key)
|
||||
.expect("failed to decode base64 string");
|
||||
let b64_decoded = base64::decode(args.key).expect("failed to decode base64 string");
|
||||
let b58_encoded = bs58::encode(&b64_decoded).into_string();
|
||||
|
||||
println!("{b58_encoded}")
|
||||
|
||||
+6
-43
@@ -6,14 +6,14 @@ use clap::Parser;
|
||||
use cosmwasm_std::Uint128;
|
||||
use log::info;
|
||||
use nym_mixnet_contract_common::{MixNodeCostParams, Percent};
|
||||
use nym_validator_client::nyxd::contract_traits::{MixnetQueryClient, MixnetSigningClient};
|
||||
use nym_validator_client::nyxd::contract_traits::MixnetSigningClient;
|
||||
use nym_validator_client::nyxd::CosmWasmCoin;
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
pub struct Args {
|
||||
#[clap(
|
||||
long,
|
||||
help = "input your profit margin as follows; (so it would be 20, rather than 0.2)"
|
||||
help = "input your profit margin as follows; (so it would be 10, rather than 0.1)"
|
||||
)]
|
||||
pub profit_margin_percent: Option<u8>,
|
||||
|
||||
@@ -27,48 +27,11 @@ pub struct Args {
|
||||
pub async fn update_cost_params(args: Args, client: SigningClient) {
|
||||
let denom = client.current_chain_details().mix_denom.base.as_str();
|
||||
|
||||
fn convert_to_percent(value: u64) -> Percent {
|
||||
Percent::from_percentage_value(value).expect("Invalid value")
|
||||
}
|
||||
|
||||
let default_profit_margin: Percent = convert_to_percent(20);
|
||||
|
||||
let mixownership_response = match client.get_owned_mixnode(&client.address()).await {
|
||||
Ok(response) => response,
|
||||
Err(_) => {
|
||||
eprintln!("Failed to obtain owned mixnode");
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let mix_id = match mixownership_response.mixnode_details {
|
||||
Some(details) => details.bond_information.mix_id,
|
||||
None => {
|
||||
eprintln!("Failed to obtain mixnode details");
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let rewarding_response = match client.get_mixnode_rewarding_details(mix_id).await {
|
||||
Ok(details) => details,
|
||||
Err(_) => {
|
||||
eprintln!("Failed to obtain rewarding details");
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let profit_margin_percent = rewarding_response
|
||||
.rewarding_details
|
||||
.map(|rd| rd.cost_params.profit_margin_percent)
|
||||
.unwrap_or(default_profit_margin);
|
||||
|
||||
let profit_margin_value = args
|
||||
.profit_margin_percent
|
||||
.map(|pm| convert_to_percent(pm as u64))
|
||||
.unwrap_or(profit_margin_percent);
|
||||
|
||||
let cost_params = MixNodeCostParams {
|
||||
profit_margin_percent: profit_margin_value,
|
||||
profit_margin_percent: Percent::from_percentage_value(
|
||||
args.profit_margin_percent.unwrap_or(10) as u64,
|
||||
)
|
||||
.unwrap(),
|
||||
interval_operating_cost: CosmWasmCoin {
|
||||
denom: denom.into(),
|
||||
amount: Uint128::new(args.interval_operating_cost.unwrap_or(40_000_000)),
|
||||
|
||||
@@ -3,7 +3,9 @@
|
||||
|
||||
use crate::errors::{Error, Result};
|
||||
use log::*;
|
||||
use nym_bandwidth_controller::acquire::{get_ticket_book, query_and_persist_required_global_data};
|
||||
use nym_bandwidth_controller::acquire::{
|
||||
get_ticket_book, query_and_persist_required_global_signatures,
|
||||
};
|
||||
use nym_client_core::config::disk_persistence::CommonClientPaths;
|
||||
use nym_config::DEFAULT_DATA_DIR;
|
||||
use nym_credential_storage::persistent_storage::PersistentStorage;
|
||||
@@ -43,10 +45,14 @@ 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 alongside the master verification key
|
||||
// before attempting the deposit
|
||||
query_and_persist_required_global_data(storage, epoch_id, ticketbook_expiration, apis.clone())
|
||||
.await?;
|
||||
// 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?;
|
||||
|
||||
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, NymPayInfo, PayInfo, SecretKeyUser, TicketType,
|
||||
CoinIndexSignature, ExpirationDateSignature, PayInfo, SecretKeyUser, TicketType,
|
||||
VerificationKeyAuth, Wallet, WalletSignatures,
|
||||
};
|
||||
use nym_ecash_time::EcashTime;
|
||||
@@ -114,10 +114,6 @@ 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,
|
||||
|
||||
@@ -24,7 +24,6 @@ zeroize = { workspace = true }
|
||||
nym-crypto = { path = "../crypto" }
|
||||
nym-pemstore = { path = "../pemstore" }
|
||||
nym-sphinx = { path = "../nymsphinx" }
|
||||
nym-task = { path = "../task" }
|
||||
|
||||
nym-credentials = { path = "../credentials" }
|
||||
nym-credentials-interface = { path = "../credentials-interface" }
|
||||
|
||||
@@ -25,7 +25,6 @@ impl<'a> ClientHandshake<'a> {
|
||||
identity: &'a nym_crypto::asymmetric::identity::KeyPair,
|
||||
gateway_pubkey: identity::PublicKey,
|
||||
expects_credential_usage: bool,
|
||||
#[cfg(not(target_arch = "wasm32"))] shutdown: nym_task::TaskClient,
|
||||
) -> Self
|
||||
where
|
||||
S: Stream<Item = WsItem> + Sink<WsMessage> + Unpin + Send + 'a,
|
||||
@@ -36,8 +35,6 @@ impl<'a> ClientHandshake<'a> {
|
||||
identity,
|
||||
Some(gateway_pubkey),
|
||||
expects_credential_usage,
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
shutdown,
|
||||
);
|
||||
|
||||
ClientHandshake {
|
||||
|
||||
@@ -25,8 +25,6 @@ pub enum HandshakeError {
|
||||
MalformedRequest,
|
||||
#[error("sent request was malformed")]
|
||||
HandshakeFailure,
|
||||
#[error("received shutdown")]
|
||||
ReceivedShutdown,
|
||||
|
||||
#[error("timed out waiting for a handshake message")]
|
||||
Timeout,
|
||||
|
||||
@@ -8,7 +8,6 @@ use futures::future::BoxFuture;
|
||||
use futures::task::{Context, Poll};
|
||||
use futures::{Future, Sink, Stream};
|
||||
use nym_crypto::asymmetric::encryption;
|
||||
use nym_task::TaskClient;
|
||||
use rand::{CryptoRng, RngCore};
|
||||
use std::pin::Pin;
|
||||
use tungstenite::Message as WsMessage;
|
||||
@@ -23,12 +22,11 @@ impl<'a> GatewayHandshake<'a> {
|
||||
ws_stream: &'a mut S,
|
||||
identity: &'a nym_crypto::asymmetric::identity::KeyPair,
|
||||
received_init_payload: Vec<u8>,
|
||||
shutdown: TaskClient,
|
||||
) -> Self
|
||||
where
|
||||
S: Stream<Item = WsItem> + Sink<WsMessage> + Unpin + Send + 'a,
|
||||
{
|
||||
let mut state = State::new(rng, ws_stream, identity, None, true, shutdown);
|
||||
let mut state = State::new(rng, ws_stream, identity, None, true);
|
||||
GatewayHandshake {
|
||||
handshake_future: Box::pin(async move {
|
||||
// If any step along the way failed (that are non-network related),
|
||||
|
||||
@@ -8,8 +8,6 @@ use self::gateway::GatewayHandshake;
|
||||
pub use self::shared_key::{SharedKeySize, SharedKeys};
|
||||
use futures::{Sink, Stream};
|
||||
use nym_crypto::asymmetric::identity;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
use nym_task::TaskClient;
|
||||
use rand::{CryptoRng, RngCore};
|
||||
use tungstenite::{Error as WsError, Message as WsMessage};
|
||||
|
||||
@@ -33,7 +31,6 @@ pub async fn client_handshake<'a, S>(
|
||||
identity: &'a identity::KeyPair,
|
||||
gateway_pubkey: identity::PublicKey,
|
||||
expects_credential_usage: bool,
|
||||
#[cfg(not(target_arch = "wasm32"))] shutdown: TaskClient,
|
||||
) -> Result<SharedKeys, HandshakeError>
|
||||
where
|
||||
S: Stream<Item = WsItem> + Sink<WsMessage> + Unpin + Send + 'a,
|
||||
@@ -44,8 +41,6 @@ where
|
||||
identity,
|
||||
gateway_pubkey,
|
||||
expects_credential_usage,
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
shutdown,
|
||||
)
|
||||
.await
|
||||
}
|
||||
@@ -56,12 +51,11 @@ pub async fn gateway_handshake<'a, S>(
|
||||
ws_stream: &'a mut S,
|
||||
identity: &'a identity::KeyPair,
|
||||
received_init_payload: Vec<u8>,
|
||||
shutdown: TaskClient,
|
||||
) -> Result<SharedKeys, HandshakeError>
|
||||
where
|
||||
S: Stream<Item = WsItem> + Sink<WsMessage> + Unpin + Send + 'a,
|
||||
{
|
||||
GatewayHandshake::new(rng, ws_stream, identity, received_init_payload, shutdown).await
|
||||
GatewayHandshake::new(rng, ws_stream, identity, received_init_payload).await
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -13,8 +13,6 @@ use nym_crypto::{
|
||||
symmetric::stream_cipher,
|
||||
};
|
||||
use nym_sphinx::params::{GatewayEncryptionAlgorithm, GatewaySharedKeyHkdfAlgorithm};
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
use nym_task::TaskClient;
|
||||
use rand::{CryptoRng, RngCore};
|
||||
use tracing::log::*;
|
||||
|
||||
@@ -50,10 +48,6 @@ pub(crate) struct State<'a, S> {
|
||||
// this field is really out of place here, however, we need to propagate this information somehow
|
||||
// in order to establish correct protocol for backwards compatibility reasons
|
||||
expects_credential_usage: bool,
|
||||
|
||||
// channel to receive shutdown signal
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
shutdown: TaskClient,
|
||||
}
|
||||
|
||||
impl<'a, S> State<'a, S> {
|
||||
@@ -63,7 +57,6 @@ impl<'a, S> State<'a, S> {
|
||||
identity: &'a identity::KeyPair,
|
||||
remote_pubkey: Option<identity::PublicKey>,
|
||||
expects_credential_usage: bool,
|
||||
#[cfg(not(target_arch = "wasm32"))] shutdown: TaskClient,
|
||||
) -> Self {
|
||||
let ephemeral_keypair = encryption::KeyPair::new(rng);
|
||||
State {
|
||||
@@ -73,8 +66,6 @@ impl<'a, S> State<'a, S> {
|
||||
remote_pubkey,
|
||||
derived_shared_keys: None,
|
||||
expects_credential_usage,
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
shutdown,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -208,73 +199,43 @@ impl<'a, S> State<'a, S> {
|
||||
self.remote_pubkey = Some(remote_pubkey)
|
||||
}
|
||||
|
||||
fn on_wg_msg(msg: Option<WsItem>) -> Result<Option<Vec<u8>>, HandshakeError> {
|
||||
let Some(msg) = msg else {
|
||||
return Err(HandshakeError::ClosedStream);
|
||||
};
|
||||
async fn _receive_handshake_message(&mut self) -> Result<Vec<u8>, HandshakeError>
|
||||
where
|
||||
S: Stream<Item = WsItem> + Unpin,
|
||||
{
|
||||
loop {
|
||||
let Some(msg) = self.ws_stream.next().await else {
|
||||
return Err(HandshakeError::ClosedStream);
|
||||
};
|
||||
|
||||
let Ok(msg) = msg else {
|
||||
return Err(HandshakeError::NetworkError);
|
||||
};
|
||||
match msg {
|
||||
WsMessage::Text(ref ws_msg) => {
|
||||
match types::RegistrationHandshake::from_str(ws_msg) {
|
||||
Ok(reg_handshake_msg) => {
|
||||
match reg_handshake_msg {
|
||||
// hehe, that's a bit disgusting that the type system requires we explicitly ignore the
|
||||
// protocol_version field that we actually never attach at this point
|
||||
// yet another reason for the overdue refactor
|
||||
types::RegistrationHandshake::HandshakePayload { data, .. } => {
|
||||
Ok(Some(data))
|
||||
}
|
||||
types::RegistrationHandshake::HandshakeError { message } => {
|
||||
Err(HandshakeError::RemoteError(message))
|
||||
}
|
||||
let Ok(msg) = msg else {
|
||||
return Err(HandshakeError::NetworkError);
|
||||
};
|
||||
|
||||
match msg {
|
||||
WsMessage::Text(ref ws_msg) => {
|
||||
match types::RegistrationHandshake::from_str(ws_msg) {
|
||||
Ok(reg_handshake_msg) => {
|
||||
return match reg_handshake_msg {
|
||||
// hehe, that's a bit disgusting that the type system requires we explicitly ignore the
|
||||
// protocol_version field that we actually never attach at this point
|
||||
// yet another reason for the overdue refactor
|
||||
types::RegistrationHandshake::HandshakePayload { data, .. } => {
|
||||
Ok(data)
|
||||
}
|
||||
types::RegistrationHandshake::HandshakeError { message } => {
|
||||
Err(HandshakeError::RemoteError(message))
|
||||
}
|
||||
};
|
||||
}
|
||||
Err(_) => {
|
||||
error!("Received a non-handshake message during the registration handshake! It's getting dropped. The received content was: '{msg}'");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
Err(_) => {
|
||||
error!("Received a non-handshake message during the registration handshake! It's getting dropped. The received content was: '{msg}'");
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
_ => error!("Received non-text message during registration handshake"),
|
||||
}
|
||||
_ => {
|
||||
error!("Received non-text message during registration handshake");
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
async fn _receive_handshake_message(&mut self) -> Result<Vec<u8>, HandshakeError>
|
||||
where
|
||||
S: Stream<Item = WsItem> + Unpin,
|
||||
{
|
||||
loop {
|
||||
tokio::select! {
|
||||
biased;
|
||||
_ = self.shutdown.recv() => return Err(HandshakeError::ReceivedShutdown),
|
||||
msg = self.ws_stream.next() => {
|
||||
let Some(ret) = Self::on_wg_msg(msg)? else {
|
||||
continue;
|
||||
};
|
||||
return Ok(ret);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
async fn _receive_handshake_message(&mut self) -> Result<Vec<u8>, HandshakeError>
|
||||
where
|
||||
S: Stream<Item = WsItem> + Unpin,
|
||||
{
|
||||
loop {
|
||||
let msg = self.ws_stream.next().await;
|
||||
let Some(ret) = Self::on_wg_msg(msg)? else {
|
||||
continue;
|
||||
};
|
||||
return Ok(ret);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,8 +10,8 @@ license.workspace = true
|
||||
|
||||
[dependencies]
|
||||
async-trait = { workspace = true }
|
||||
bincode = { workspace = true }
|
||||
defguard_wireguard_rs = { workspace = true }
|
||||
bincode = { workspace = true, optional = true }
|
||||
defguard_wireguard_rs = { workspace = true, optional = true }
|
||||
log = { workspace = true }
|
||||
sqlx = { workspace = true, features = [
|
||||
"runtime-tokio-rustls",
|
||||
@@ -36,3 +36,6 @@ sqlx = { workspace = true, features = [
|
||||
"macros",
|
||||
"migrate",
|
||||
] }
|
||||
|
||||
[features]
|
||||
wireguard = ["defguard_wireguard_rs", "bincode"]
|
||||
|
||||
@@ -22,9 +22,10 @@ use tracing::{debug, error};
|
||||
pub mod bandwidth;
|
||||
pub mod error;
|
||||
mod inboxes;
|
||||
pub(crate) mod models;
|
||||
pub mod models;
|
||||
mod shared_keys;
|
||||
mod tickets;
|
||||
#[cfg(feature = "wireguard")]
|
||||
mod wireguard_peers;
|
||||
|
||||
#[async_trait]
|
||||
@@ -216,6 +217,7 @@ pub trait Storage: Send + Sync {
|
||||
///
|
||||
/// * `peer`: wireguard peer data to be stored
|
||||
/// * `suspended`: if peer exists, but it's currently suspended
|
||||
#[cfg(feature = "wireguard")]
|
||||
async fn insert_wireguard_peer(
|
||||
&self,
|
||||
peer: &defguard_wireguard_rs::host::Peer,
|
||||
@@ -227,12 +229,14 @@ pub trait Storage: Send + Sync {
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `peer_public_key`: wireguard public key of the peer to be retrieved.
|
||||
#[cfg(feature = "wireguard")]
|
||||
async fn get_wireguard_peer(
|
||||
&self,
|
||||
peer_public_key: &str,
|
||||
) -> Result<Option<WireguardPeer>, StorageError>;
|
||||
|
||||
/// Retrieves all wireguard peers.
|
||||
#[cfg(feature = "wireguard")]
|
||||
async fn get_all_wireguard_peers(&self) -> Result<Vec<WireguardPeer>, StorageError>;
|
||||
|
||||
/// Remove a wireguard peer from the storage.
|
||||
@@ -240,6 +244,7 @@ pub trait Storage: Send + Sync {
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `peer_public_key`: wireguard public key of the peer to be removed.
|
||||
#[cfg(feature = "wireguard")]
|
||||
async fn remove_wireguard_peer(&self, peer_public_key: &str) -> Result<(), StorageError>;
|
||||
}
|
||||
|
||||
@@ -250,6 +255,7 @@ pub struct PersistentStorage {
|
||||
inbox_manager: InboxManager,
|
||||
bandwidth_manager: BandwidthManager,
|
||||
ticket_manager: TicketStorageManager,
|
||||
#[cfg(feature = "wireguard")]
|
||||
wireguard_peer_manager: wireguard_peers::WgPeerManager,
|
||||
}
|
||||
|
||||
@@ -294,6 +300,7 @@ impl PersistentStorage {
|
||||
|
||||
// the cloning here are cheap as connection pool is stored behind an Arc
|
||||
Ok(PersistentStorage {
|
||||
#[cfg(feature = "wireguard")]
|
||||
wireguard_peer_manager: wireguard_peers::WgPeerManager::new(connection_pool.clone()),
|
||||
shared_key_manager: SharedKeysManager::new(connection_pool.clone()),
|
||||
inbox_manager: InboxManager::new(connection_pool.clone(), message_retrieval_limit),
|
||||
@@ -613,6 +620,7 @@ impl Storage for PersistentStorage {
|
||||
Ok(self.ticket_manager.get_epoch_signers(epoch_id).await?)
|
||||
}
|
||||
|
||||
#[cfg(feature = "wireguard")]
|
||||
async fn insert_wireguard_peer(
|
||||
&self,
|
||||
peer: &defguard_wireguard_rs::host::Peer,
|
||||
@@ -624,6 +632,7 @@ impl Storage for PersistentStorage {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(feature = "wireguard")]
|
||||
async fn get_wireguard_peer(
|
||||
&self,
|
||||
peer_public_key: &str,
|
||||
@@ -635,11 +644,13 @@ impl Storage for PersistentStorage {
|
||||
Ok(peer)
|
||||
}
|
||||
|
||||
#[cfg(feature = "wireguard")]
|
||||
async fn get_all_wireguard_peers(&self) -> Result<Vec<WireguardPeer>, StorageError> {
|
||||
let ret = self.wireguard_peer_manager.retrieve_all_peers().await?;
|
||||
Ok(ret)
|
||||
}
|
||||
|
||||
#[cfg(feature = "wireguard")]
|
||||
async fn remove_wireguard_peer(&self, peer_public_key: &str) -> Result<(), StorageError> {
|
||||
self.wireguard_peer_manager
|
||||
.remove_peer(peer_public_key)
|
||||
|
||||
@@ -72,6 +72,7 @@ impl TryFrom<UnverifiedTicketData> for ClientTicket {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "wireguard")]
|
||||
#[derive(Debug, Clone, FromRow)]
|
||||
pub struct WireguardPeer {
|
||||
pub public_key: String,
|
||||
@@ -86,6 +87,7 @@ pub struct WireguardPeer {
|
||||
pub suspended: bool,
|
||||
}
|
||||
|
||||
#[cfg(feature = "wireguard")]
|
||||
impl From<defguard_wireguard_rs::host::Peer> for WireguardPeer {
|
||||
fn from(value: defguard_wireguard_rs::host::Peer) -> Self {
|
||||
WireguardPeer {
|
||||
@@ -118,6 +120,7 @@ impl From<defguard_wireguard_rs::host::Peer> for WireguardPeer {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "wireguard")]
|
||||
impl TryFrom<WireguardPeer> for defguard_wireguard_rs::host::Peer {
|
||||
type Error = crate::error::StorageError;
|
||||
|
||||
|
||||
@@ -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.mark_as_success();
|
||||
handler_shutdown_listener.disarm();
|
||||
|
||||
tokio::select! {
|
||||
socket = listener.accept() => {
|
||||
|
||||
@@ -245,7 +245,7 @@ impl VerlocMeasurer {
|
||||
}
|
||||
|
||||
let mut shutdown_listener = self.shutdown_listener.clone().named("VerlocMeasurement");
|
||||
shutdown_listener.mark_as_success();
|
||||
shutdown_listener.disarm();
|
||||
|
||||
for chunk in nodes_to_test.chunks(self.config.tested_nodes_batch_size) {
|
||||
let mut chunk_results = Vec::with_capacity(chunk.len());
|
||||
|
||||
@@ -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.mark_as_success();
|
||||
shutdown_listener.disarm();
|
||||
|
||||
let mut conn = match tokio::time::timeout(
|
||||
self.connection_timeout,
|
||||
|
||||
@@ -17,8 +17,8 @@ pub const MIXNET_CONTRACT_ADDRESS: &str =
|
||||
"n17srjznxl9dvzdkpwpw24gg668wc73val88a6m5ajg6ankwvz9wtst0cznr";
|
||||
pub const VESTING_CONTRACT_ADDRESS: &str =
|
||||
"n1nc5tatafv6eyq7llkr2gv50ff9e22mnf70qgjlv737ktmt4eswrq73f2nw";
|
||||
pub const ECASH_CONTRACT_ADDRESS: &str =
|
||||
"n1r7s6aksyc6pqardx88k3rkgfagwvj4z4zum9mmz2sfk3zm2mha0sd4dnun";
|
||||
|
||||
pub const ECASH_CONTRACT_ADDRESS: &str = "";
|
||||
pub const GROUP_CONTRACT_ADDRESS: &str =
|
||||
"n1e2zq4886zzewpvpucmlw8v9p7zv692f6yck4zjzxh699dkcmlrfqk2knsr";
|
||||
pub const MULTISIG_CONTRACT_ADDRESS: &str =
|
||||
|
||||
@@ -9,11 +9,12 @@ 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" }
|
||||
|
||||
@@ -294,4 +294,8 @@ impl<R: CryptoRng + Rng> FragmentPreparer for NodeTester<R> {
|
||||
fn average_ack_delay(&self) -> Duration {
|
||||
self.average_ack_delay
|
||||
}
|
||||
|
||||
fn nonce(&self) -> i32 {
|
||||
1
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ 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" }
|
||||
@@ -27,10 +28,13 @@ 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
|
||||
@@ -43,5 +47,13 @@ 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",
|
||||
]
|
||||
|
||||
@@ -13,7 +13,14 @@ 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,6 +3,8 @@
|
||||
|
||||
use crate::ChunkingError;
|
||||
use nym_sphinx_params::{SerializedFragmentIdentifier, FRAG_ID_LEN};
|
||||
use serde::Serialize;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
use std::fmt::{self, Debug, Formatter};
|
||||
|
||||
@@ -58,7 +60,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)]
|
||||
#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Ord, PartialOrd, Serialize)]
|
||||
pub struct FragmentIdentifier {
|
||||
set_id: i32,
|
||||
fragment_position: u8,
|
||||
@@ -75,6 +77,10 @@ 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);
|
||||
|
||||
@@ -125,6 +131,10 @@ 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.
|
||||
@@ -216,6 +226,10 @@ 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()
|
||||
@@ -297,8 +311,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)]
|
||||
pub(crate) struct FragmentHeader {
|
||||
#[derive(PartialEq, Clone, Debug, Serialize, ToSchema)]
|
||||
pub 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.
|
||||
@@ -324,6 +338,20 @@ pub(crate) 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.
|
||||
|
||||
@@ -1,9 +1,16 @@
|
||||
// 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;
|
||||
|
||||
@@ -22,6 +29,118 @@ 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::ChunkingError;
|
||||
use crate::{fragment_received, ChunkingError};
|
||||
use log::*;
|
||||
use std::collections::HashMap;
|
||||
|
||||
@@ -66,6 +66,12 @@ 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())
|
||||
@@ -104,6 +110,8 @@ 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?
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
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;
|
||||
@@ -11,12 +12,14 @@ 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};
|
||||
use rand::{CryptoRng, Rng, SeedableRng};
|
||||
use rand_chacha::ChaCha20Rng;
|
||||
|
||||
use std::time::Duration;
|
||||
|
||||
@@ -49,6 +52,7 @@ 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;
|
||||
@@ -192,9 +196,18 @@ 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 => {
|
||||
@@ -228,10 +241,8 @@ 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(self.rng(), hops, packet_recipient.gateway())?;
|
||||
let route = topology.random_route_to_gateway(&mut rng, hops, destination)?;
|
||||
let destination = packet_recipient.as_sphinx_destination();
|
||||
|
||||
// including set of delays
|
||||
@@ -313,6 +324,8 @@ 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>
|
||||
@@ -325,12 +338,15 @@ 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,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -454,6 +470,10 @@ 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.mark_as_success();
|
||||
shutdown_listener.disarm();
|
||||
|
||||
let connection_id = Self::generate_random();
|
||||
|
||||
@@ -294,7 +294,7 @@ impl SocksClient {
|
||||
.shutdown()
|
||||
.await
|
||||
.map_err(|source| SocksProxyError::SocketShutdownFailure { source })?;
|
||||
self.shutdown_listener.mark_as_success();
|
||||
self.shutdown_listener.disarm();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -172,6 +172,6 @@ where
|
||||
trace!("{} - inbound closed", connection_id);
|
||||
shutdown_notify.notify_one();
|
||||
|
||||
shutdown_listener.mark_as_success();
|
||||
shutdown_listener.disarm();
|
||||
reader
|
||||
}
|
||||
|
||||
@@ -148,7 +148,7 @@ where
|
||||
}
|
||||
|
||||
pub fn into_inner(mut self) -> (TcpStream, ConnectionReceiver) {
|
||||
self.shutdown_listener.mark_as_success();
|
||||
self.shutdown_listener.disarm();
|
||||
(
|
||||
self.socket.take().unwrap(),
|
||||
self.mix_receiver.take().unwrap(),
|
||||
|
||||
@@ -60,7 +60,7 @@ pub(super) async fn run_outbound(
|
||||
|
||||
loop {
|
||||
select! {
|
||||
connection_message = &mut mix_receiver.next() => {
|
||||
connection_message = 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.mark_as_success();
|
||||
shutdown_listener.disarm();
|
||||
(writer, mix_receiver)
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
use futures::{future::pending, FutureExt, SinkExt, StreamExt};
|
||||
use log::{log, Level};
|
||||
use std::future::Future;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::{error::Error, time::Duration};
|
||||
use tokio::sync::{
|
||||
@@ -367,6 +368,17 @@ impl TaskClient {
|
||||
self.named(name)
|
||||
}
|
||||
|
||||
pub async fn run_future<Fut, T>(&mut self, fut: Fut) -> Option<T>
|
||||
where
|
||||
Fut: Future<Output = T>,
|
||||
{
|
||||
tokio::select! {
|
||||
biased;
|
||||
_ = self.recv() => None,
|
||||
res = fut => Some(res)
|
||||
}
|
||||
}
|
||||
|
||||
// Create a dummy that will never report that we should shutdown.
|
||||
pub fn dummy() -> TaskClient {
|
||||
let (_notify_tx, notify_rx) = watch::channel(());
|
||||
@@ -458,12 +470,8 @@ 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 mark_as_success(&mut self) {
|
||||
self.mode.set_should_not_signal_on_drop();
|
||||
}
|
||||
|
||||
pub fn disarm(&mut self) {
|
||||
self.mark_as_success();
|
||||
self.mode.set_should_not_signal_on_drop();
|
||||
}
|
||||
|
||||
pub fn send_we_stopped(&mut self, err: SentError) {
|
||||
|
||||
@@ -5,7 +5,6 @@ edition = { workspace = true }
|
||||
authors = { workspace = true }
|
||||
license = { workspace = true }
|
||||
repository = { workspace = true }
|
||||
readme = { workspace = true }
|
||||
homepage = { workspace = true }
|
||||
documentation = { workspace = true }
|
||||
|
||||
@@ -15,9 +14,10 @@ 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 = "0.11"
|
||||
semver = { version = "0.11" }
|
||||
|
||||
# 'serializable' feature
|
||||
serde = { workspace = true, features = ["derive"], optional = true }
|
||||
@@ -28,20 +28,22 @@ 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 }
|
||||
|
||||
@@ -49,4 +51,5 @@ 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", "nym-config", "serde_json"]
|
||||
serializable = ["serde", "serde_json"]
|
||||
outfox = []
|
||||
|
||||
@@ -51,4 +51,16 @@ 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),
|
||||
}
|
||||
|
||||
@@ -6,7 +6,9 @@
|
||||
|
||||
use crate::filter::VersionFilterable;
|
||||
pub use error::NymTopologyError;
|
||||
use log::{debug, warn};
|
||||
use log::{debug, info, warn};
|
||||
use mix::Node;
|
||||
use nym_config::defaults::var_names::NYM_API;
|
||||
use nym_mixnet_contract_common::mixnode::MixNodeDetails;
|
||||
use nym_mixnet_contract_common::{GatewayBond, IdentityKeyRef, MixId};
|
||||
use nym_sphinx_addressing::nodes::NodeIdentity;
|
||||
@@ -116,13 +118,40 @@ impl Display for NetworkAddress {
|
||||
|
||||
pub type MixLayer = u8;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, Default)]
|
||||
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 }
|
||||
}
|
||||
@@ -270,7 +299,7 @@ impl NymTopology {
|
||||
&self,
|
||||
rng: &mut R,
|
||||
num_mix_hops: u8,
|
||||
) -> Result<Vec<SphinxNode>, NymTopologyError>
|
||||
) -> Result<Vec<Node>, NymTopologyError>
|
||||
where
|
||||
R: Rng + CryptoRng + ?Sized,
|
||||
{
|
||||
@@ -295,12 +324,32 @@ impl NymTopology {
|
||||
let random_mix = layer_mixes
|
||||
.choose(rng)
|
||||
.ok_or(NymTopologyError::EmptyMixLayer { layer })?;
|
||||
route.push(random_mix.into());
|
||||
route.push(random_mix.clone());
|
||||
}
|
||||
|
||||
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>(
|
||||
@@ -321,6 +370,7 @@ 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())
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ version = "1.0.0"
|
||||
description = "Nym common types"
|
||||
authors.workspace = true
|
||||
edition = "2021"
|
||||
rust-version = "1.58"
|
||||
rust-version.workspace = true
|
||||
license.workspace = true
|
||||
|
||||
[dependencies]
|
||||
|
||||
@@ -11,6 +11,7 @@ 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;
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
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(×tamp.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)
|
||||
}
|
||||
}
|
||||
@@ -30,13 +30,9 @@ workspace = true
|
||||
optional = true
|
||||
|
||||
[features]
|
||||
default = ["sleep", "console_error_panic_hook"]
|
||||
default = ["sleep"]
|
||||
sleep = ["web-sys", "web-sys/Window"]
|
||||
websocket = [
|
||||
"getrandom",
|
||||
"tungstenite",
|
||||
"gloo-net"
|
||||
]
|
||||
websocket = ["getrandom", "tungstenite", "gloo-net"]
|
||||
crypto = [
|
||||
"web-sys",
|
||||
"web-sys/Crypto",
|
||||
|
||||
@@ -12,7 +12,6 @@ license.workspace = true
|
||||
|
||||
[dependencies]
|
||||
base64 = { workspace = true }
|
||||
dashmap = { workspace = true }
|
||||
log = { workspace = true }
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
thiserror = { workspace = true }
|
||||
@@ -35,7 +34,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]
|
||||
|
||||
@@ -6,10 +6,17 @@ 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;
|
||||
|
||||
@@ -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 = DashMap<PeerPublicKey, RegistrationData>;
|
||||
pub type PrivateIPs = DashMap<IpAddr, Taken>;
|
||||
pub type PendingRegistrations = HashMap<PeerPublicKey, RegistrationData>;
|
||||
pub type PrivateIPs = HashMap<IpAddr, Taken>;
|
||||
|
||||
#[cfg(feature = "verify")]
|
||||
pub type HmacSha256 = Hmac<Sha256>;
|
||||
|
||||
@@ -23,7 +23,7 @@ x25519-dalek = { workspace = true }
|
||||
ip_network = { workspace = true }
|
||||
log.workspace = true
|
||||
nym-crypto = { path = "../crypto", features = ["asymmetric"] }
|
||||
nym-gateway-storage = { path = "../gateway-storage" }
|
||||
nym-gateway-storage = { path = "../gateway-storage", features = ["wireguard"] }
|
||||
nym-network-defaults = { path = "../network-defaults" }
|
||||
nym-task = { path = "../task" }
|
||||
nym-wireguard-types = { path = "../wireguard-types" }
|
||||
|
||||
@@ -84,6 +84,7 @@ 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>,
|
||||
@@ -95,7 +96,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 storage.get_all_wireguard_peers().await? {
|
||||
for storage_peer in all_peers {
|
||||
let suspended = storage_peer.suspended;
|
||||
let peer = Peer::try_from(storage_peer)?;
|
||||
if suspended {
|
||||
|
||||
@@ -5,19 +5,15 @@ 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, time::Duration};
|
||||
use std::{collections::HashMap, sync::Arc};
|
||||
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),
|
||||
@@ -50,6 +46,7 @@ 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> {
|
||||
@@ -64,19 +61,14 @@ impl<St: Storage> PeerController<St> {
|
||||
let timeout_check_interval = tokio_stream::wrappers::IntervalStream::new(
|
||||
tokio::time::interval(DEFAULT_PEER_TIMEOUT_CHECK),
|
||||
);
|
||||
let active_peers: HashMap<Key, Peer> = peers
|
||||
let active_peers = peers
|
||||
.into_iter()
|
||||
.map(|peer| (peer.public_key.clone(), peer))
|
||||
.collect();
|
||||
let suspended_peers: HashMap<Key, Peer> = suspended_peers
|
||||
let suspended_peers = 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,
|
||||
@@ -86,7 +78,8 @@ impl<St: Storage> PeerController<St> {
|
||||
timeout_check_interval,
|
||||
active_peers,
|
||||
suspended_peers,
|
||||
last_seen_bandwidth,
|
||||
last_seen_bandwidth: HashMap::new(),
|
||||
timeout_count: 0,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,11 +126,10 @@ impl<St: Storage> PeerController<St> {
|
||||
}
|
||||
|
||||
async fn check_peers(&mut self) -> Result<(), Error> {
|
||||
let reset_every: u32 = std::env::var("RESET_EVERY")
|
||||
.expect("RESET_EVERY should be set")
|
||||
.parse()
|
||||
.expect("RESET_EVERY should be a number");
|
||||
let reset = Utc::now().minute() % reset_every == 0;
|
||||
// Add 10 seconds to cover edge cases. At worst, we give ten free seconds worth of bandwidth
|
||||
// by resetting the bandwidth twice
|
||||
let reset = Utc::now().num_seconds_from_midnight() as u64
|
||||
<= DEFAULT_PEER_TIMEOUT_CHECK.as_secs() + 10;
|
||||
|
||||
if reset {
|
||||
for (_, peer) in self.suspended_peers.drain() {
|
||||
@@ -150,6 +142,15 @@ 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() {
|
||||
@@ -198,7 +199,6 @@ 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
|
||||
};
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
/autodoc-generated-markdown/*
|
||||
@@ -0,0 +1,13 @@
|
||||
[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
|
||||
@@ -0,0 +1,4 @@
|
||||
# `autodoc`
|
||||
|
||||
Command output documentation generator WIP
|
||||
|
||||
@@ -0,0 +1,261 @@
|
||||
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",
|
||||
format!("`{}`", last_word.unwrap())
|
||||
)?;
|
||||
writeln!(
|
||||
file,
|
||||
"\nThese docs are autogenerated by the `autodocs` script.
|
||||
\n**TODO add link**"
|
||||
)?;
|
||||
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",
|
||||
format!("`{}`", last_word.unwrap())
|
||||
)?;
|
||||
writeln!(
|
||||
file,
|
||||
"\nThese docs are autogenerated by the `autodocs` script.
|
||||
\n**TODO add link**"
|
||||
)?;
|
||||
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, "```")?;
|
||||
file.write_all(&output.stdout)?;
|
||||
writeln!(file, "```")?;
|
||||
|
||||
if !&output.stderr.is_empty() {
|
||||
debug!("stderr: {:#?}", String::from_utf8_lossy(&output.stderr));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -1,14 +1,6 @@
|
||||
# mdbook files
|
||||
book/
|
||||
|
||||
# Compiled assets
|
||||
.sass-cache
|
||||
_site
|
||||
|
||||
# Developing
|
||||
todo.md
|
||||
.idea
|
||||
|
||||
# OSX
|
||||
.DS_Store
|
||||
.next
|
||||
node_modules
|
||||
out
|
||||
|
||||
# the lock file will break Vercel because it may get committed from a machine with a different build architecture
|
||||
package-lock.json
|
||||
|
||||
@@ -1,42 +1,24 @@
|
||||
# Nym Documentation
|
||||
Documentation for the Nym privacy platform built using the [mdBook](https://rust-lang.github.io/mdBook/) docs framework.
|
||||
# Nym Docs v2
|
||||
|
||||
Documentation can be viewed at https://nymtech.net/docs
|
||||
New consolidated version of the nym docs.
|
||||
|
||||
## Contributing
|
||||
Contributions to our documentation are very welcome. Please work on your contribution in either a `feature/<feature-name>` or `chore/<chore-name>` branch from `master` and target your pull request at `master`.
|
||||
## Local development
|
||||
|
||||
Since these docs autogenerate command output and import docs from binaries in `target/release` on `build` make sure you're branching off of `master` when making your branch.
|
||||
```
|
||||
npm i
|
||||
npm run dev
|
||||
```
|
||||
|
||||
Changes merged to `master` will be autodeployed to the production site.
|
||||
Open http://localhost:3000 to browse the output that will hot-reload when you make changes.
|
||||
|
||||
### Contributing a new translation
|
||||
To contribute tranlsations in a new language, please get in touch via [Matrix](https://matrix.to/#/#general:nymtech.chat) or [Discord](https://nymtech.net/go/discord).
|
||||
## Build
|
||||
|
||||
### Variables
|
||||
There are some variables that are shared across the entire docs site, such as the current latest software version.
|
||||
```
|
||||
npm run build
|
||||
```
|
||||
|
||||
Variables are denoted in the `.md` files wrapped in `{{}}` (e.g `{{wallet_release_version}}`), and are located in the `book.toml` file under the `[preprocessor.variables.variables]` heading. If you are changing something like the software release version, minimum code versions in prerequisites, etc, **check in here first!**
|
||||
The static output will be in `./out`;
|
||||
|
||||
### Diagrams
|
||||
Most diagrams are simply ascii. Copies are kept in `/diagrams/` for ease of reproducability. Created using [textik](https://textik.com/#).
|
||||
## Template details
|
||||
|
||||
### Importing files and auto-generated command output
|
||||
|
||||
Example files are inserted as per normal with mdbook.
|
||||
|
||||
Some binary command outputs are generated using the [`cmdrun`](https://docs.rs/mdbook-cmdrun/latest/mdbook_cmdrun/) mdbook plugin.
|
||||
|
||||
## Building
|
||||
When working locally, it is recommended that you use `mdbook serve` to have a local version of the docs served on `localhost:3000`, with hot reloading on any changes made to files in the `src/` directory.
|
||||
|
||||
You can find other commands in the [mdBook CLI tool docs](https://rust-lang.github.io/mdBook/cli/index.html).
|
||||
|
||||
### I tried to edit files in `theme/` and they aren't taking effect / `mdbook serve` causes a looping reload on file changes after changing fields in `[preprocessor.theme]` config
|
||||
|
||||
Looping reload is a known issue with the `mdbook-theme` preprocessor used for the table of contents and layout of these docs. As outlined in the `mdbook-theme` [readme](https://github.com/zjp-CN/mdbook-theme#avoid-repeating-call-on-this-tool-when-mdbook-watch) one way to mitigate this is to set `turn-off = true` under `[preprocessor.theme]`. This means that `mdbook serve` or `mdbook watch` ignores changes to the `theme/` directory, which is the source of the looping reload. If you have changed or commented out this line, reintroduce it to remove the looping reload. If you are trying to edit the theme of the docs and want to apply the change, see [here](https://github.com/zjp-CN/mdbook-theme#avoid-repeating-call-on-this-tool-when-mdbook-watch) for more info on how to remove the block, change the theme, and reintroduce the block.
|
||||
|
||||
### Checking the mdBook version
|
||||
To check the version of mdBook installed on your system, you can use the `mdbook --version` command. This will print the version number of mdBook installed on your system in the terminal.
|
||||
|
||||
The latest release of the binary of the pre-compiled binaries can be found on [GitHub](https://github.com/rust-lang/mdBook/releases).
|
||||
This documentation was made with [Nextra](https://nextra.site) using the template from here https://github.com/shuding/nextra-docs-template.
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user