Compare commits
18 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d5c598729b | |||
| 7eb764cd5a | |||
| 854128ee21 | |||
| 6cd59124a2 | |||
| d5cc31b7f0 | |||
| ea6f009c01 | |||
| 5881f6b6aa | |||
| aafddc78d1 | |||
| 29a0e8620c | |||
| 800016f682 | |||
| 6151f15e7e | |||
| 5e6a945eef | |||
| aec23a4f83 | |||
| 3d563ece79 | |||
| f24a0dc8ae | |||
| 50fbdb4f0b | |||
| d445a26999 | |||
| 30294062af |
@@ -9,7 +9,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Install Dependencies (Linux)
|
||||
run: sudo apt-get update && sudo apt-get install -y build-essential curl wget libssl-dev libudev-dev squashfs-tools protobuf-compiler git
|
||||
run: sudo apt-get update && sudo apt-get install -y build-essential curl wget libssl-dev libudev-dev squashfs-tools protobuf-compiler
|
||||
- name: Install rsync
|
||||
run: sudo apt-get install rsync
|
||||
- uses: rlespinasse/github-slug-action@v3.x
|
||||
@@ -30,24 +30,9 @@ jobs:
|
||||
- name: Remove existing Nym config directory (`~/.nym/`)
|
||||
run: cd documentation && ./remove_existing_config.sh
|
||||
continue-on-error: false
|
||||
# This is the original flow
|
||||
# - name: Build all projects in documentation/ & move to ~/dist/docs/
|
||||
# run: cd documentation && ./build_all_to_dist.sh
|
||||
|
||||
# This is a workaround replacement which builds on the last working commit b332a6b55668f60988e36961f3f62a794ba82ddb and then on current branch
|
||||
- name: Save current branch to ~/current_branch
|
||||
run: git rev-parse --abbrev-ref HEAD > ~/current_branch
|
||||
- name: Git pull & switch to b332a6b55668f60988e36961f3f62a794ba82ddb
|
||||
run: git pull && git checkout b332a6b55668f60988e36961f3f62a794ba82ddb
|
||||
- name: Build all projects in documentation/ & move to ~/dist/docs/ from b332a6b55668f60988e36961f3f62a794ba82ddb
|
||||
- name: Build all projects in documentation/ & move to ~/dist/docs/
|
||||
run: cd documentation && ./build_all_to_dist.sh
|
||||
|
||||
- name: Switch to current branch
|
||||
run: git checkout $echo "$(cat ~/current_branch)"
|
||||
- name: Build all projects in documentation/ & move to ~/dist/docs/ on current branch
|
||||
run: cd documentation && ./build_all_to_dist.sh && rm ~/current_branch
|
||||
|
||||
# End of replacemet
|
||||
continue-on-error: false
|
||||
|
||||
- name: Post process
|
||||
run: cd documentation && ./post_process.sh
|
||||
|
||||
@@ -13,7 +13,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Install Dependencies (Linux)
|
||||
run: sudo apt-get update && sudo apt-get install -y build-essential curl wget libssl-dev libudev-dev squashfs-tools protobuf-compiler git
|
||||
run: sudo apt-get update && sudo apt-get install -y build-essential curl wget libssl-dev libudev-dev squashfs-tools protobuf-compiler
|
||||
- name: Install rsync
|
||||
run: sudo apt-get install rsync
|
||||
- uses: rlespinasse/github-slug-action@v3.x
|
||||
@@ -34,25 +34,9 @@ jobs:
|
||||
- name: Remove existing Nym config directory (`~/.nym/`)
|
||||
run: cd documentation && ./remove_existing_config.sh
|
||||
continue-on-error: false
|
||||
|
||||
# This is the original flow
|
||||
# - name: Build all projects in documentation/ & move to ~/dist/docs/
|
||||
# run: cd documentation && ./build_all_to_dist.sh
|
||||
|
||||
# This is a workaround replacement which builds on the last working commit b332a6b55668f60988e36961f3f62a794ba82ddb and then on current branch
|
||||
- name: Save current branch to ~/current_branch
|
||||
run: git rev-parse --abbrev-ref HEAD > ~/current_branch
|
||||
- name: Git pull & switch to b332a6b55668f60988e36961f3f62a794ba82ddb
|
||||
run: git pull && git checkout b332a6b55668f60988e36961f3f62a794ba82ddb
|
||||
- name: Build all projects in documentation/ & move to ~/dist/docs/ from b332a6b55668f60988e36961f3f62a794ba82ddb
|
||||
- name: Build all projects in documentation/ & move to ~/dist/docs/
|
||||
run: cd documentation && ./build_all_to_dist.sh
|
||||
|
||||
- name: Switch to current branch
|
||||
run: git checkout $echo "$(cat ~/current_branch)"
|
||||
- name: Build all projects in documentation/ & move to ~/dist/docs/ on current branch
|
||||
run: cd documentation && ./build_all_to_dist.sh && rm ~/current_branch
|
||||
|
||||
# End of replacemet
|
||||
continue-on-error: false
|
||||
|
||||
- name: Deploy branch to CI www
|
||||
continue-on-error: true
|
||||
|
||||
@@ -30,7 +30,6 @@ jobs:
|
||||
mixnode_hash: ${{ steps.binary-hashes.outputs.mixnode_hash }}
|
||||
gateway_hash: ${{ steps.binary-hashes.outputs.gateway_hash }}
|
||||
nymvisor_hash: ${{ steps.binary-hashes.outputs.nymvisor_hash }}
|
||||
nymnode_hash: ${{ steps.binary-hashes.outputs.nymnode_hash }}
|
||||
socks5_hash: ${{ steps.binary-hashes.outputs.socks5_hash }}
|
||||
netreq_hash: ${{ steps.binary-hashes.outputs.netreq_hash }}
|
||||
cli_hash: ${{ steps.binary-hashes.outputs.cli_hash }}
|
||||
@@ -39,7 +38,6 @@ jobs:
|
||||
mixnode_version: ${{ steps.binary-versions.outputs.mixnode_version }}
|
||||
gateway_version: ${{ steps.binary-versions.outputs.gateway_version }}
|
||||
nymvisor_version: ${{ steps.binary-versions.outputs.nymvisor_version }}
|
||||
nymnode_version: ${{ steps.binary-versions.outputs.nymnode_version }}
|
||||
socks5_version: ${{ steps.binary-versions.outputs.socks5_version }}
|
||||
netreq_version: ${{ steps.binary-versions.outputs.netreq_version }}
|
||||
cli_version: ${{ steps.binary-versions.outputs.cli_version }}
|
||||
@@ -83,7 +81,6 @@ jobs:
|
||||
target/release/nym-network-statistics
|
||||
target/release/nym-cli
|
||||
target/release/nymvisor
|
||||
target/release/nym-node
|
||||
retention-days: 30
|
||||
|
||||
- id: create-release
|
||||
@@ -102,7 +99,6 @@ jobs:
|
||||
target/release/nym-network-statistics
|
||||
target/release/nym-cli
|
||||
target/release/nymvisor
|
||||
target/release/nym-node
|
||||
|
||||
push-release-data-client:
|
||||
if: ${{ (startsWith(github.ref, 'refs/tags/nym-binaries-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
|
||||
|
||||
@@ -102,18 +102,6 @@ jobs:
|
||||
nym-wallet/target/release/bundle/dmg/*.dmg
|
||||
nym-wallet/target/release/bundle/macos/*.app.tar.gz*
|
||||
|
||||
- name: Deploy artifacts to CI www
|
||||
continue-on-error: true
|
||||
uses: easingthemes/ssh-deploy@main
|
||||
env:
|
||||
SSH_PRIVATE_KEY: ${{ secrets.CI_WWW_SSH_PRIVATE_KEY }}
|
||||
ARGS: "-avzr"
|
||||
SOURCE: "nym-wallet/target/release/bundle/macos/nym-wallet.app.tar.gz"
|
||||
REMOTE_HOST: ${{ secrets.CI_WWW_REMOTE_HOST }}
|
||||
REMOTE_USER: ${{ secrets.CI_WWW_REMOTE_USER }}
|
||||
TARGET: ${{ secrets.CI_WWW_REMOTE_TARGET }}/builds/${{ github.ref_name }}/nym-wallet
|
||||
EXCLUDE: "/dist/, /node_modules/"
|
||||
|
||||
push-release-data:
|
||||
if: ${{ (startsWith(github.ref, 'refs/tags/nym-wallet-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
|
||||
uses: ./.github/workflows/release-calculate-hash.yml
|
||||
|
||||
@@ -77,18 +77,6 @@ jobs:
|
||||
nym-wallet/target/release/bundle/appimage/*.AppImage
|
||||
nym-wallet/target/release/bundle/appimage/*.AppImage.tar.gz*
|
||||
|
||||
- name: Deploy artifacts to CI www
|
||||
continue-on-error: true
|
||||
uses: easingthemes/ssh-deploy@main
|
||||
env:
|
||||
SSH_PRIVATE_KEY: ${{ secrets.CI_WWW_SSH_PRIVATE_KEY }}
|
||||
ARGS: "-avzr"
|
||||
SOURCE: "nym-wallet/target/release/bundle/appimage/nym-wallet*.AppImage.tar.gz"
|
||||
REMOTE_HOST: ${{ secrets.CI_WWW_REMOTE_HOST }}
|
||||
REMOTE_USER: ${{ secrets.CI_WWW_REMOTE_USER }}
|
||||
TARGET: ${{ secrets.CI_WWW_REMOTE_TARGET }}/builds/${{ github.ref_name }}/nym-wallet
|
||||
EXCLUDE: "/dist/, /node_modules/"
|
||||
|
||||
push-release-data:
|
||||
if: ${{ (startsWith(github.ref, 'refs/tags/nym-wallet-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
|
||||
uses: ./.github/workflows/release-calculate-hash.yml
|
||||
|
||||
@@ -97,18 +97,6 @@ jobs:
|
||||
nym-wallet/target/release/bundle/msi/*.msi
|
||||
nym-wallet/target/release/bundle/msi/*.msi.zip*
|
||||
|
||||
- name: Deploy artifacts to CI www
|
||||
continue-on-error: true
|
||||
uses: easingthemes/ssh-deploy@main
|
||||
env:
|
||||
SSH_PRIVATE_KEY: ${{ secrets.CI_WWW_SSH_PRIVATE_KEY }}
|
||||
ARGS: "-avzr"
|
||||
SOURCE: "nym-wallet/target/release/bundle/msi/nym-wallet_1.*.msi"
|
||||
REMOTE_HOST: ${{ secrets.CI_WWW_REMOTE_HOST }}
|
||||
REMOTE_USER: ${{ secrets.CI_WWW_REMOTE_USER }}
|
||||
TARGET: ${{ secrets.CI_WWW_REMOTE_TARGET }}/builds/${{ github.ref_name }}/nym-wallet
|
||||
EXCLUDE: "/dist/, /node_modules/"
|
||||
|
||||
push-release-data:
|
||||
if: ${{ (startsWith(github.ref, 'refs/tags/nym-wallet-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
|
||||
uses: ./.github/workflows/release-calculate-hash.yml
|
||||
|
||||
@@ -4,20 +4,6 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [2024.3-eclipse] (2024-04-22)
|
||||
|
||||
- Initial release of the first iteration of the Nym Node
|
||||
- Improvements to gateway functionality
|
||||
- IPR development
|
||||
- Removal of allow list in favour of implementing an exit policy
|
||||
- Explorer delegation: enables direct delegation to nodes via the Nym Explorer
|
||||
|
||||
|
||||
## [2024.2-fast-and-furious] (2024-03-25)
|
||||
|
||||
- Internal testing pre-release
|
||||
|
||||
|
||||
## [2024.1-marabou] (2024-02-15)
|
||||
|
||||
**New Features:**
|
||||
|
||||
Generated
+111
-218
@@ -543,10 +543,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3b829e4e32b91e643de6eafe82b1d90675f5874230191a4ffbc1b336dec4d6bf"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"axum-core 0.3.4",
|
||||
"axum-core",
|
||||
"bitflags 1.3.2",
|
||||
"bytes",
|
||||
"futures-util",
|
||||
"headers",
|
||||
"http 0.2.9",
|
||||
"http-body 0.4.5",
|
||||
"hyper 0.14.27",
|
||||
@@ -558,44 +559,14 @@ dependencies = [
|
||||
"pin-project-lite 0.2.13",
|
||||
"rustversion",
|
||||
"serde",
|
||||
"sync_wrapper 0.1.2",
|
||||
"tower",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "axum"
|
||||
version = "0.7.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3a6c9af12842a67734c9a2e355436e5d03b22383ed60cf13cd0c18fbfe3dcbcf"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"axum-core 0.4.3",
|
||||
"bytes",
|
||||
"futures-util",
|
||||
"http 1.1.0",
|
||||
"http-body 1.0.0",
|
||||
"http-body-util",
|
||||
"hyper 1.3.1",
|
||||
"hyper-util",
|
||||
"itoa",
|
||||
"matchit",
|
||||
"memchr",
|
||||
"mime",
|
||||
"percent-encoding",
|
||||
"pin-project-lite 0.2.13",
|
||||
"rustversion",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_path_to_error",
|
||||
"serde_urlencoded",
|
||||
"sync_wrapper 1.0.1",
|
||||
"sync_wrapper",
|
||||
"tokio",
|
||||
"tower",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -615,50 +586,6 @@ dependencies = [
|
||||
"tower-service",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "axum-core"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a15c63fd72d41492dc4f497196f5da1fb04fb7529e631d73630d1b491e47a2e3"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"bytes",
|
||||
"futures-util",
|
||||
"http 1.1.0",
|
||||
"http-body 1.0.0",
|
||||
"http-body-util",
|
||||
"mime",
|
||||
"pin-project-lite 0.2.13",
|
||||
"rustversion",
|
||||
"sync_wrapper 0.1.2",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "axum-extra"
|
||||
version = "0.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0be6ea09c9b96cb5076af0de2e383bd2bc0c18f827cf1967bdd353e0b910d733"
|
||||
dependencies = [
|
||||
"axum 0.7.5",
|
||||
"axum-core 0.4.3",
|
||||
"bytes",
|
||||
"futures-util",
|
||||
"headers",
|
||||
"http 1.1.0",
|
||||
"http-body 1.0.0",
|
||||
"http-body-util",
|
||||
"mime",
|
||||
"pin-project-lite 0.2.13",
|
||||
"serde",
|
||||
"tower",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
version = "0.3.69"
|
||||
@@ -704,12 +631,6 @@ version = "0.21.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ba43ea6f343b788c8764558649e08df62f86c6ef251fdaeb1ffd010a9ae50a2"
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.22.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
|
||||
|
||||
[[package]]
|
||||
name = "base64ct"
|
||||
version = "1.6.0"
|
||||
@@ -2626,7 +2547,7 @@ checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
|
||||
|
||||
[[package]]
|
||||
name = "explorer-api"
|
||||
version = "1.1.34"
|
||||
version = "1.1.33"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"clap 4.4.7",
|
||||
@@ -2648,7 +2569,7 @@ dependencies = [
|
||||
"rand 0.8.5",
|
||||
"rand_pcg 0.3.1",
|
||||
"rand_seeder",
|
||||
"reqwest 0.12.4",
|
||||
"reqwest",
|
||||
"rocket",
|
||||
"rocket_cors",
|
||||
"rocket_okapi",
|
||||
@@ -3282,14 +3203,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "headers"
|
||||
version = "0.4.0"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "322106e6bd0cba2d5ead589ddb8150a13d7c4217cf80d7c4f682ca994ccc6aa9"
|
||||
checksum = "06683b93020a07e3dbcf5f8c0f6d40080d725bea7936fc01ad345c01b97dc270"
|
||||
dependencies = [
|
||||
"base64 0.21.4",
|
||||
"bytes",
|
||||
"headers-core",
|
||||
"http 1.1.0",
|
||||
"http 0.2.9",
|
||||
"httpdate",
|
||||
"mime",
|
||||
"sha1",
|
||||
@@ -3297,11 +3218,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "headers-core"
|
||||
version = "0.3.0"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "54b4a22553d4242c49fddb9ba998a99962b5cc6f22cb5a3482bec22522403ce4"
|
||||
checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429"
|
||||
dependencies = [
|
||||
"http 1.1.0",
|
||||
"http 0.2.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3483,9 +3404,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "http-range-header"
|
||||
version = "0.4.1"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08a397c49fec283e3d6211adbe480be95aae5f304cfb923e9970e08956d5168a"
|
||||
checksum = "add0ab9360ddbd88cfeb3bd9574a1d85cfdfa14db10b3e21d3700dbc4328758f"
|
||||
|
||||
[[package]]
|
||||
name = "httparse"
|
||||
@@ -3560,9 +3481,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "hyper"
|
||||
version = "1.3.1"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fe575dd17d0862a9a33781c8c4696a55c320909004a67a00fb286ba8b1bc496d"
|
||||
checksum = "186548d73ac615b32a73aafe38fb4f56c0d340e110e5a200bcadbaf2e199263a"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-channel",
|
||||
@@ -3575,7 +3496,6 @@ dependencies = [
|
||||
"pin-project-lite 0.2.13",
|
||||
"smallvec",
|
||||
"tokio",
|
||||
"want",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3587,7 +3507,7 @@ dependencies = [
|
||||
"futures-util",
|
||||
"http 0.2.9",
|
||||
"hyper 0.14.27",
|
||||
"rustls 0.21.11",
|
||||
"rustls 0.21.10",
|
||||
"tokio",
|
||||
"tokio-rustls 0.24.1",
|
||||
]
|
||||
@@ -3611,17 +3531,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca38ef113da30126bbff9cd1705f9273e15d45498615d138b0c20279ac7a76aa"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-channel",
|
||||
"futures-util",
|
||||
"http 1.1.0",
|
||||
"http-body 1.0.0",
|
||||
"hyper 1.3.1",
|
||||
"hyper 1.2.0",
|
||||
"pin-project-lite 0.2.13",
|
||||
"socket2 0.5.4",
|
||||
"tokio",
|
||||
"tower",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3889,7 +3805,7 @@ dependencies = [
|
||||
"socket2 0.5.4",
|
||||
"widestring",
|
||||
"windows-sys 0.48.0",
|
||||
"winreg 0.50.0",
|
||||
"winreg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -5108,7 +5024,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-api"
|
||||
version = "1.1.37"
|
||||
version = "1.1.35"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@@ -5161,7 +5077,7 @@ dependencies = [
|
||||
"rand 0.8.5",
|
||||
"rand_chacha 0.2.2",
|
||||
"rand_chacha 0.3.1",
|
||||
"reqwest 0.12.4",
|
||||
"reqwest",
|
||||
"rocket",
|
||||
"rocket_cors",
|
||||
"rocket_okapi",
|
||||
@@ -5197,7 +5113,6 @@ dependencies = [
|
||||
"schemars",
|
||||
"serde",
|
||||
"tendermint",
|
||||
"time",
|
||||
"ts-rs",
|
||||
]
|
||||
|
||||
@@ -5270,7 +5185,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-cli"
|
||||
version = "1.1.35"
|
||||
version = "1.1.34"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"base64 0.13.1",
|
||||
@@ -5351,7 +5266,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-client"
|
||||
version = "1.1.34"
|
||||
version = "1.1.33"
|
||||
dependencies = [
|
||||
"bs58 0.5.0",
|
||||
"clap 4.4.7",
|
||||
@@ -5399,7 +5314,7 @@ dependencies = [
|
||||
"gloo-timers",
|
||||
"http-body-util",
|
||||
"humantime-serde",
|
||||
"hyper 1.3.1",
|
||||
"hyper 1.2.0",
|
||||
"hyper-util",
|
||||
"log",
|
||||
"nym-bandwidth-controller",
|
||||
@@ -5605,6 +5520,30 @@ dependencies = [
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nym-credential-client-wasm"
|
||||
version = "1.3.0-rc.0"
|
||||
dependencies = [
|
||||
"bip39",
|
||||
"js-sys",
|
||||
"nym-bandwidth-controller",
|
||||
"nym-bin-common",
|
||||
"nym-credential-storage",
|
||||
"nym-credentials",
|
||||
"nym-credentials-interface",
|
||||
"nym-network-defaults",
|
||||
"nym-validator-client",
|
||||
"serde",
|
||||
"serde-wasm-bindgen",
|
||||
"thiserror",
|
||||
"tsify",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-futures",
|
||||
"wasm-bindgen-test",
|
||||
"wasm-utils",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nym-credential-storage"
|
||||
version = "0.1.0"
|
||||
@@ -5733,7 +5672,7 @@ dependencies = [
|
||||
name = "nym-exit-policy"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"reqwest 0.12.4",
|
||||
"reqwest",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
@@ -5759,7 +5698,7 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"log",
|
||||
"nym-explorer-api-requests",
|
||||
"reqwest 0.12.4",
|
||||
"reqwest",
|
||||
"serde",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
@@ -5768,7 +5707,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-gateway"
|
||||
version = "1.1.35"
|
||||
version = "1.1.33"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@@ -5841,9 +5780,7 @@ dependencies = [
|
||||
"nym-validator-client",
|
||||
"rand 0.7.3",
|
||||
"serde",
|
||||
"si-scale",
|
||||
"thiserror",
|
||||
"time",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
"tokio-tungstenite",
|
||||
@@ -5894,7 +5831,7 @@ name = "nym-http-api-client"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"reqwest 0.12.4",
|
||||
"reqwest",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
@@ -5907,7 +5844,7 @@ dependencies = [
|
||||
name = "nym-http-api-common"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"axum 0.7.5",
|
||||
"axum",
|
||||
"bytes",
|
||||
"mime",
|
||||
"serde",
|
||||
@@ -5996,7 +5933,7 @@ dependencies = [
|
||||
"nym-wireguard",
|
||||
"nym-wireguard-types",
|
||||
"rand 0.8.5",
|
||||
"reqwest 0.12.4",
|
||||
"reqwest",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tap",
|
||||
@@ -6063,10 +6000,10 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-mixnode"
|
||||
version = "1.1.37"
|
||||
version = "1.1.35"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"axum 0.7.5",
|
||||
"axum",
|
||||
"bs58 0.5.0",
|
||||
"clap 4.4.7",
|
||||
"colored",
|
||||
@@ -6177,12 +6114,14 @@ dependencies = [
|
||||
"schemars",
|
||||
"serde",
|
||||
"thiserror",
|
||||
"tsify",
|
||||
"url",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nym-network-requester"
|
||||
version = "1.1.34"
|
||||
version = "1.1.33"
|
||||
dependencies = [
|
||||
"addr",
|
||||
"anyhow",
|
||||
@@ -6218,7 +6157,7 @@ dependencies = [
|
||||
"publicsuffix",
|
||||
"rand 0.7.3",
|
||||
"regex",
|
||||
"reqwest 0.12.4",
|
||||
"reqwest",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sqlx",
|
||||
@@ -6234,7 +6173,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-network-statistics"
|
||||
version = "1.1.34"
|
||||
version = "1.1.33"
|
||||
dependencies = [
|
||||
"dirs 4.0.0",
|
||||
"log",
|
||||
@@ -6251,7 +6190,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-node"
|
||||
version = "1.1.0"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bip39",
|
||||
@@ -6259,7 +6198,6 @@ dependencies = [
|
||||
"cargo_metadata",
|
||||
"celes",
|
||||
"clap 4.4.7",
|
||||
"colored",
|
||||
"cupid",
|
||||
"humantime-serde",
|
||||
"ipnetwork 0.16.0",
|
||||
@@ -6295,14 +6233,12 @@ dependencies = [
|
||||
name = "nym-node-http-api"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"axum 0.7.5",
|
||||
"axum-extra",
|
||||
"axum",
|
||||
"colored",
|
||||
"dashmap",
|
||||
"fastrand 2.0.1",
|
||||
"headers",
|
||||
"hmac 0.12.1",
|
||||
"hyper 1.3.1",
|
||||
"hyper 0.14.27",
|
||||
"ipnetwork 0.16.0",
|
||||
"nym-crypto",
|
||||
"nym-http-api-common",
|
||||
@@ -6337,7 +6273,6 @@ dependencies = [
|
||||
"nym-exit-policy",
|
||||
"nym-http-api-client",
|
||||
"nym-wireguard-types",
|
||||
"rand_chacha 0.2.2",
|
||||
"schemars",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@@ -6482,7 +6417,7 @@ dependencies = [
|
||||
"parking_lot 0.12.1",
|
||||
"pretty_env_logger",
|
||||
"rand 0.7.3",
|
||||
"reqwest 0.12.4",
|
||||
"reqwest",
|
||||
"tap",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
@@ -6524,7 +6459,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-socks5-client"
|
||||
version = "1.1.34"
|
||||
version = "1.1.33"
|
||||
dependencies = [
|
||||
"bs58 0.5.0",
|
||||
"clap 4.4.7",
|
||||
@@ -6577,7 +6512,7 @@ dependencies = [
|
||||
"nym-validator-client",
|
||||
"pin-project",
|
||||
"rand 0.7.3",
|
||||
"reqwest 0.12.4",
|
||||
"reqwest",
|
||||
"schemars",
|
||||
"serde",
|
||||
"tap",
|
||||
@@ -6794,7 +6729,7 @@ version = "1.0.1"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"log",
|
||||
"reqwest 0.12.4",
|
||||
"reqwest",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sqlx",
|
||||
@@ -6883,7 +6818,7 @@ dependencies = [
|
||||
"nym-mixnet-contract-common",
|
||||
"nym-validator-client",
|
||||
"nym-vesting-contract-common",
|
||||
"reqwest 0.12.4",
|
||||
"reqwest",
|
||||
"schemars",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@@ -6933,7 +6868,7 @@ dependencies = [
|
||||
"nym-service-provider-directory-common",
|
||||
"nym-vesting-contract-common",
|
||||
"prost 0.12.1",
|
||||
"reqwest 0.12.4",
|
||||
"reqwest",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha2 0.9.9",
|
||||
@@ -7064,7 +6999,7 @@ dependencies = [
|
||||
"nym-bin-common",
|
||||
"nym-config",
|
||||
"nym-task",
|
||||
"reqwest 0.12.4",
|
||||
"reqwest",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha2 0.10.8",
|
||||
@@ -7085,8 +7020,7 @@ dependencies = [
|
||||
"cosmrs 0.15.0 (git+https://github.com/jstuczyn/cosmos-rust?branch=nym-temp/all-validator-features)",
|
||||
"eyre",
|
||||
"futures",
|
||||
"humantime 2.1.0",
|
||||
"serde",
|
||||
"nym-bin-common",
|
||||
"sha2 0.10.8",
|
||||
"sqlx",
|
||||
"tendermint",
|
||||
@@ -8405,7 +8339,7 @@ dependencies = [
|
||||
"once_cell",
|
||||
"percent-encoding",
|
||||
"pin-project-lite 0.2.13",
|
||||
"rustls 0.21.11",
|
||||
"rustls 0.21.10",
|
||||
"rustls-native-certs",
|
||||
"rustls-pemfile",
|
||||
"serde",
|
||||
@@ -8414,41 +8348,6 @@ dependencies = [
|
||||
"system-configuration",
|
||||
"tokio",
|
||||
"tokio-rustls 0.24.1",
|
||||
"tower-service",
|
||||
"url",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-futures",
|
||||
"web-sys",
|
||||
"winreg 0.50.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "reqwest"
|
||||
version = "0.12.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "566cafdd92868e0939d3fb961bd0dc25fcfaaed179291093b3d43e6b3150ea10"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"bytes",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"http 1.1.0",
|
||||
"http-body 1.0.0",
|
||||
"http-body-util",
|
||||
"hyper 1.3.1",
|
||||
"hyper-util",
|
||||
"ipnet",
|
||||
"js-sys",
|
||||
"log",
|
||||
"mime",
|
||||
"once_cell",
|
||||
"percent-encoding",
|
||||
"pin-project-lite 0.2.13",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_urlencoded",
|
||||
"sync_wrapper 0.1.2",
|
||||
"tokio",
|
||||
"tokio-socks",
|
||||
"tokio-util",
|
||||
"tower-service",
|
||||
@@ -8457,7 +8356,7 @@ dependencies = [
|
||||
"wasm-bindgen-futures",
|
||||
"wasm-streams",
|
||||
"web-sys",
|
||||
"winreg 0.52.0",
|
||||
"winreg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -8698,9 +8597,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rust-embed"
|
||||
version = "8.3.0"
|
||||
version = "6.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fb78f46d0066053d16d4ca7b898e9343bc3530f71c61d5ad84cd404ada068745"
|
||||
checksum = "a36224c3276f8c4ebc8c20f158eca7ca4359c8db89991c4925132aaaf6702661"
|
||||
dependencies = [
|
||||
"rust-embed-impl",
|
||||
"rust-embed-utils",
|
||||
@@ -8709,22 +8608,23 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rust-embed-impl"
|
||||
version = "8.3.0"
|
||||
version = "6.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b91ac2a3c6c0520a3fb3dd89321177c3c692937c4eb21893378219da10c44fc8"
|
||||
checksum = "49b94b81e5b2c284684141a2fb9e2a31be90638caf040bf9afbc5a0416afe1ac"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rust-embed-utils",
|
||||
"shellexpand",
|
||||
"syn 2.0.58",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rust-embed-utils"
|
||||
version = "8.3.0"
|
||||
version = "7.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "86f69089032567ffff4eada41c573fc43ff466c7db7c5688b2e7969584345581"
|
||||
checksum = "9d38ff6bf570dc3bb7100fce9f7b60c33fa71d80e88da3f2580df4ff2bdded74"
|
||||
dependencies = [
|
||||
"sha2 0.10.8",
|
||||
"walkdir",
|
||||
@@ -8823,9 +8723,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustls"
|
||||
version = "0.21.11"
|
||||
version = "0.21.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7fecbfb7b1444f477b345853b1fce097a2c6fb637b2bfb87e6bc5db0f043fae4"
|
||||
checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba"
|
||||
dependencies = [
|
||||
"log",
|
||||
"ring 0.17.4",
|
||||
@@ -9330,6 +9230,15 @@ dependencies = [
|
||||
"lazy_static",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shellexpand"
|
||||
version = "2.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ccc8076840c4da029af4f87e4e8daeb0fca6b87bbb02e10cb60b791450e11e4"
|
||||
dependencies = [
|
||||
"dirs 4.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "si-scale"
|
||||
version = "0.2.2"
|
||||
@@ -9842,12 +9751,6 @@ version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160"
|
||||
|
||||
[[package]]
|
||||
name = "sync_wrapper"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394"
|
||||
|
||||
[[package]]
|
||||
name = "synstructure"
|
||||
version = "0.12.6"
|
||||
@@ -10018,7 +9921,7 @@ dependencies = [
|
||||
"getrandom 0.2.10",
|
||||
"peg",
|
||||
"pin-project",
|
||||
"reqwest 0.11.22",
|
||||
"reqwest",
|
||||
"semver 1.0.22",
|
||||
"serde",
|
||||
"serde_bytes",
|
||||
@@ -10219,7 +10122,7 @@ version = "0.24.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081"
|
||||
dependencies = [
|
||||
"rustls 0.21.11",
|
||||
"rustls 0.21.10",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
@@ -10280,7 +10183,7 @@ checksum = "212d5dcb2a1ce06d81107c3d0ffa3121fe974b73f068c8282cb1c32328113b6c"
|
||||
dependencies = [
|
||||
"futures-util",
|
||||
"log",
|
||||
"rustls 0.21.11",
|
||||
"rustls 0.21.10",
|
||||
"rustls-native-certs",
|
||||
"tokio",
|
||||
"tokio-rustls 0.24.1",
|
||||
@@ -10380,7 +10283,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3082666a3a6433f7f511c7192923fa1fe07c69332d3c6a2e6bb040b569199d5a"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"axum 0.6.20",
|
||||
"axum",
|
||||
"base64 0.21.4",
|
||||
"bytes",
|
||||
"futures-core",
|
||||
@@ -10423,16 +10326,16 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tower-http"
|
||||
version = "0.5.2"
|
||||
version = "0.4.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e9cd434a998747dd2c4276bc96ee2e0c7a2eadf3cae88e52be55a05fa9053f5"
|
||||
checksum = "61c5bb1d698276a2443e5ecfabc1008bf15a36c12e6a7176e7bf089ea9131140"
|
||||
dependencies = [
|
||||
"bitflags 2.4.1",
|
||||
"bytes",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"http 1.1.0",
|
||||
"http-body 1.0.0",
|
||||
"http-body-util",
|
||||
"http 0.2.9",
|
||||
"http-body 0.4.5",
|
||||
"http-range-header",
|
||||
"httpdate",
|
||||
"mime",
|
||||
@@ -10714,7 +10617,7 @@ dependencies = [
|
||||
"httparse",
|
||||
"log",
|
||||
"rand 0.8.5",
|
||||
"rustls 0.21.11",
|
||||
"rustls 0.21.10",
|
||||
"sha1",
|
||||
"thiserror",
|
||||
"url",
|
||||
@@ -10930,9 +10833,9 @@ checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
|
||||
|
||||
[[package]]
|
||||
name = "utoipa"
|
||||
version = "4.2.0"
|
||||
version = "3.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "272ebdfbc99111033031d2f10e018836056e4d2c8e2acda76450ec7974269fa7"
|
||||
checksum = "d82b1bc5417102a73e8464c686eef947bdfb99fcdfc0a4f228e81afa9526470a"
|
||||
dependencies = [
|
||||
"indexmap 2.0.2",
|
||||
"serde",
|
||||
@@ -10942,9 +10845,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "utoipa-gen"
|
||||
version = "4.2.0"
|
||||
version = "3.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d3c9f4d08338c1bfa70dde39412a040a884c6f318b3d09aaaf3437a1e52027fc"
|
||||
checksum = "05d96dcd6fc96f3df9b3280ef480770af1b7c5d14bc55192baa9b067976d920c"
|
||||
dependencies = [
|
||||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
@@ -10955,11 +10858,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "utoipa-swagger-ui"
|
||||
version = "6.0.0"
|
||||
version = "3.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b39868d43c011961e04b41623e050aedf2cc93652562ff7935ce0f819aaf2da"
|
||||
checksum = "84614caa239fb25b2bb373a52859ffd94605ceb256eeb1d63436325cf81e3653"
|
||||
dependencies = [
|
||||
"axum 0.7.5",
|
||||
"axum",
|
||||
"mime_guess",
|
||||
"regex",
|
||||
"rust-embed",
|
||||
@@ -11162,7 +11065,6 @@ name = "wasm-client-core"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"console_error_panic_hook",
|
||||
"js-sys",
|
||||
"nym-bandwidth-controller",
|
||||
"nym-client-core",
|
||||
@@ -11207,9 +11109,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-streams"
|
||||
version = "0.4.0"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b65dc4c90b63b118468cf747d8bf3566c1913ef60be765b5730ead9e0a3ba129"
|
||||
checksum = "b4609d447824375f43e1ffbc051b50ad8f4b3ae8219680c94452ea05eb240ac7"
|
||||
dependencies = [
|
||||
"futures-util",
|
||||
"js-sys",
|
||||
@@ -11237,6 +11139,7 @@ dependencies = [
|
||||
name = "wasm-utils"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"console_error_panic_hook",
|
||||
"futures",
|
||||
"getrandom 0.2.10",
|
||||
"gloo-net",
|
||||
@@ -11822,16 +11725,6 @@ dependencies = [
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winreg"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a277a57398d4bfa075df44f501a17cfdf8542d224f0d36095a2adc7aee4ef0a5"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "with_builtin_macros"
|
||||
version = "0.0.3"
|
||||
|
||||
+12
-7
@@ -122,6 +122,7 @@ members = [
|
||||
# "wasm/full-nym-wasm",
|
||||
"wasm/mix-fetch",
|
||||
"wasm/node-tester",
|
||||
"wasm/credentials"
|
||||
]
|
||||
|
||||
default-members = [
|
||||
@@ -160,8 +161,7 @@ license = "Apache-2.0"
|
||||
[workspace.dependencies]
|
||||
anyhow = "1.0.71"
|
||||
async-trait = "0.1.68"
|
||||
axum = "0.7.5"
|
||||
axum-extra = "0.9.3"
|
||||
axum = "0.6.20"
|
||||
base64 = "0.21.4"
|
||||
bs58 = "0.5.0"
|
||||
bip39 = { version = "2.0.0", features = ["zeroize"] }
|
||||
@@ -172,16 +172,15 @@ dotenvy = "0.15.6"
|
||||
futures = "0.3.28"
|
||||
generic-array = "0.14.7"
|
||||
getrandom = "0.2.10"
|
||||
headers = "0.4.0"
|
||||
humantime-serde = "1.1.1"
|
||||
hyper = "1.3.1"
|
||||
hyper = "0.14.27"
|
||||
k256 = "0.13"
|
||||
lazy_static = "1.4.0"
|
||||
log = "0.4"
|
||||
once_cell = "1.7.2"
|
||||
parking_lot = "0.12.1"
|
||||
rand = "0.8.5"
|
||||
reqwest = { version = "0.12.4", default-features = false }
|
||||
reqwest = { version = "0.11.22", default-features = false }
|
||||
schemars = "0.8.1"
|
||||
serde = "1.0.152"
|
||||
serde_json = "1.0.91"
|
||||
@@ -195,8 +194,8 @@ tokio-tungstenite = { version = "0.20.1" }
|
||||
tracing = "0.1.37"
|
||||
tungstenite = { version = "0.20.1", default-features = false }
|
||||
ts-rs = "7.0.0"
|
||||
utoipa = "4.2.0"
|
||||
utoipa-swagger-ui = "6.0.0"
|
||||
utoipa = "3.5.0"
|
||||
utoipa-swagger-ui = "3.1.5"
|
||||
url = "2.4"
|
||||
zeroize = "1.6.0"
|
||||
|
||||
@@ -237,6 +236,12 @@ tendermint-rpc = "0.34" # same version as used by cosmrs
|
||||
prost = "0.12"
|
||||
|
||||
# wasm-related dependencies
|
||||
|
||||
# The `console_error_panic_hook` crate provides better debugging of panics by
|
||||
# logging them with `console.error`. This is great for development, but requires
|
||||
# all the `std::fmt` and `std::panicking` infrastructure, so isn't great for
|
||||
# code size when deploying.
|
||||
console_error_panic_hook = "0.1.7"
|
||||
gloo-utils = "0.1.7"
|
||||
js-sys = "0.3.63"
|
||||
serde-wasm-bindgen = "0.5.0"
|
||||
|
||||
@@ -103,6 +103,7 @@ sdk-wasm: sdk-wasm-build sdk-wasm-test sdk-wasm-lint
|
||||
sdk-wasm-build:
|
||||
$(MAKE) -C nym-browser-extension/storage wasm-pack
|
||||
$(MAKE) -C wasm/client
|
||||
$(MAKE) -C wasm/credentials
|
||||
$(MAKE) -C wasm/node-tester
|
||||
$(MAKE) -C wasm/mix-fetch
|
||||
#$(MAKE) -C wasm/full-nym-wasm
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "nym-client"
|
||||
version = "1.1.34"
|
||||
version = "1.1.33"
|
||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"]
|
||||
description = "Implementation of the Nym Client"
|
||||
edition = "2021"
|
||||
|
||||
@@ -8,7 +8,5 @@ use nym_client_core::cli_helpers::client_import_credential::{
|
||||
};
|
||||
|
||||
pub(crate) async fn execute(args: CommonClientImportCredentialArgs) -> Result<(), ClientError> {
|
||||
import_credential::<CliNativeClient, _>(args).await?;
|
||||
println!("successfully imported credential!");
|
||||
Ok(())
|
||||
import_credential::<CliNativeClient, _>(args).await
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "nym-socks5-client"
|
||||
version = "1.1.34"
|
||||
version = "1.1.33"
|
||||
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"
|
||||
|
||||
@@ -10,7 +10,5 @@ use nym_client_core::cli_helpers::client_import_credential::{
|
||||
pub(crate) async fn execute(
|
||||
args: CommonClientImportCredentialArgs,
|
||||
) -> Result<(), Socks5ClientError> {
|
||||
import_credential::<CliSocks5Client, _>(args).await?;
|
||||
println!("successfully imported credential!");
|
||||
Ok(())
|
||||
import_credential::<CliSocks5Client, _>(args).await
|
||||
}
|
||||
|
||||
@@ -17,13 +17,17 @@ use zeroize::Zeroizing;
|
||||
|
||||
pub mod state;
|
||||
|
||||
pub async fn deposit<C>(client: &C, amount: Coin) -> Result<State, BandwidthControllerError>
|
||||
pub async fn deposit<C>(
|
||||
client: &C,
|
||||
amount: impl Into<Coin>,
|
||||
) -> Result<State, BandwidthControllerError>
|
||||
where
|
||||
C: CoconutBandwidthSigningClient + Sync,
|
||||
{
|
||||
let mut rng = OsRng;
|
||||
let signing_key = identity::PrivateKey::new(&mut rng);
|
||||
let encryption_key = encryption::PrivateKey::new(&mut rng);
|
||||
let amount = amount.into();
|
||||
|
||||
let tx_hash = client
|
||||
.deposit(
|
||||
|
||||
@@ -18,7 +18,6 @@ pub mod acquire;
|
||||
pub mod error;
|
||||
mod utils;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct BandwidthController<C, St> {
|
||||
storage: St,
|
||||
client: C,
|
||||
|
||||
@@ -3,7 +3,7 @@ name = "nym-client-core"
|
||||
version = "1.1.15"
|
||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
|
||||
edition = "2021"
|
||||
rust-version = "1.70"
|
||||
rust-version = "1.66"
|
||||
license.workspace = true
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
@@ -48,7 +48,7 @@ nym-validator-client = { path = "../client-libs/validator-client", default-featu
|
||||
nym-task = { path = "../task" }
|
||||
nym-credential-storage = { path = "../credential-storage" }
|
||||
nym-network-defaults = { path = "../network-defaults" }
|
||||
nym-client-core-config-types = { path = "./config-types", features = ["disk-persistence"] }
|
||||
nym-client-core-config-types = { path = "./config-types", features = ["disk-persistence"]}
|
||||
nym-client-core-surb-storage = { path = "./surb-storage" }
|
||||
nym-client-core-gateways-storage = { path = "./gateways-storage" }
|
||||
|
||||
|
||||
@@ -8,12 +8,3 @@ use thiserror::Error;
|
||||
pub struct ConfigUpgradeFailure {
|
||||
pub current_version: String,
|
||||
}
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum InvalidTrafficModeFailure {
|
||||
#[error("attempted to set medium toggle traffic mode with fast mode flag")]
|
||||
MediumToggleWithFastMode,
|
||||
|
||||
#[error("attempted to set medium toggle traffic mode with no cover flag")]
|
||||
MediumToggleWithNoCover,
|
||||
}
|
||||
|
||||
@@ -56,7 +56,6 @@ const DEFAULT_MAXIMUM_REPLY_SURB_AGE: Duration = Duration::from_secs(12 * 60 * 6
|
||||
// 24 hours
|
||||
const DEFAULT_MAXIMUM_REPLY_KEY_AGE: Duration = Duration::from_secs(24 * 60 * 60);
|
||||
|
||||
use crate::error::InvalidTrafficModeFailure;
|
||||
pub use nym_country_group::CountryGroup;
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, PartialEq, Serialize)]
|
||||
@@ -128,56 +127,6 @@ impl Config {
|
||||
self
|
||||
}
|
||||
|
||||
// TODO: this should be refactored properly
|
||||
// as of 12.09.23 the below is true (not sure how this comment will rot in the future)
|
||||
// medium_toggle:
|
||||
// - sets secondary packet size to 16kb
|
||||
// - disables poisson distribution of the main traffic stream
|
||||
// - sets the cover traffic stream to 1 packet / 5s (on average)
|
||||
// - disables per hop delay
|
||||
//
|
||||
// fastmode (to be renamed to `fast-poisson`):
|
||||
// - sets average per hop delay to 10ms
|
||||
// - sets the cover traffic stream to 1 packet / 2000s (on average); for all intents and purposes it disables the stream
|
||||
// - sets the poisson distribution of the main traffic stream to 4ms, i.e. 250 packets / s on average
|
||||
//
|
||||
// no_cover:
|
||||
// - disables poisson distribution of the main traffic stream
|
||||
// - disables the secondary cover traffic stream
|
||||
#[doc(hidden)]
|
||||
pub fn try_apply_traffic_modes(
|
||||
&mut self,
|
||||
disable_poisson_process: bool,
|
||||
medium_toggle: bool,
|
||||
fast_mode: bool,
|
||||
no_cover: bool,
|
||||
) -> Result<(), InvalidTrafficModeFailure> {
|
||||
if disable_poisson_process {
|
||||
self.set_no_poisson_process()
|
||||
}
|
||||
|
||||
if medium_toggle {
|
||||
if fast_mode {
|
||||
return Err(InvalidTrafficModeFailure::MediumToggleWithFastMode);
|
||||
}
|
||||
if no_cover {
|
||||
return Err(InvalidTrafficModeFailure::MediumToggleWithNoCover);
|
||||
}
|
||||
|
||||
self.set_experimental_medium_toggle();
|
||||
}
|
||||
|
||||
if fast_mode {
|
||||
self.set_high_default_traffic_volume()
|
||||
}
|
||||
|
||||
if no_cover {
|
||||
self.set_no_cover_traffic();
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn set_high_default_traffic_volume(&mut self) {
|
||||
self.debug.traffic.average_packet_delay = Duration::from_millis(10);
|
||||
// basically don't really send cover messages
|
||||
@@ -187,15 +136,6 @@ impl Config {
|
||||
self.debug.traffic.message_sending_average_delay = Duration::from_millis(4);
|
||||
}
|
||||
|
||||
/// Enable medium mixnet traffic, for experiments only.
|
||||
/// This includes things like disabling cover traffic, no per hop delays, etc.
|
||||
#[doc(hidden)]
|
||||
pub fn set_experimental_medium_toggle(&mut self) {
|
||||
self.set_no_cover_traffic_with_keepalive();
|
||||
self.set_no_per_hop_delays();
|
||||
self.debug.traffic.secondary_packet_size = Some(PacketSize::ExtendedPacket16);
|
||||
}
|
||||
|
||||
pub fn with_disabled_poisson_process(mut self, disabled: bool) -> Self {
|
||||
if disabled {
|
||||
self.set_no_poisson_process()
|
||||
|
||||
@@ -201,7 +201,7 @@ where
|
||||
log::debug!("Setting up gateway");
|
||||
match setup {
|
||||
GatewaySetup::MustLoad { gateway_id } => {
|
||||
log::debug!("GatewaySetup::MustLoad with id: {gateway_id:?}");
|
||||
log::trace!("GatewaySetup::MustLoad with id: {gateway_id:?}");
|
||||
use_loaded_gateway_details(key_store, details_store, gateway_id).await
|
||||
}
|
||||
GatewaySetup::New {
|
||||
@@ -209,7 +209,7 @@ where
|
||||
available_gateways,
|
||||
wg_tun_address,
|
||||
} => {
|
||||
log::debug!("GatewaySetup::New with spec: {specification:?}");
|
||||
log::trace!("GatewaySetup::New with spec: {specification:?}");
|
||||
setup_new_gateway(
|
||||
key_store,
|
||||
details_store,
|
||||
@@ -224,7 +224,7 @@ where
|
||||
gateway_details,
|
||||
client_keys: managed_keys,
|
||||
} => {
|
||||
log::debug!("GatewaySetup::ReuseConnection");
|
||||
log::trace!("GatewaySetup::ReuseConnection");
|
||||
Ok(reuse_gateway_connection(
|
||||
authenticated_ephemeral_client,
|
||||
*gateway_details,
|
||||
|
||||
@@ -16,8 +16,6 @@ thiserror = { workspace = true }
|
||||
url = { workspace = true }
|
||||
rand = { version = "0.7.3", features = ["wasm-bindgen"] }
|
||||
tokio = { version = "1.24.1", features = ["macros"] }
|
||||
si-scale = "0.2.2"
|
||||
time.workspace = true
|
||||
|
||||
# internal
|
||||
nym-bandwidth-controller = { path = "../../bandwidth-controller" }
|
||||
|
||||
@@ -79,7 +79,6 @@ impl GatewayConfig {
|
||||
}
|
||||
|
||||
// TODO: this should be refactored into a state machine that keeps track of its authentication state
|
||||
#[derive(Debug)]
|
||||
pub struct GatewayClient<C, St = EphemeralCredentialStorage> {
|
||||
authenticated: bool,
|
||||
disabled_credentials_mode: bool,
|
||||
@@ -442,7 +441,7 @@ impl<C, St> GatewayClient<C, St> {
|
||||
}
|
||||
|
||||
debug_assert!(self.connection.is_available());
|
||||
log::debug!("Registering gateway");
|
||||
log::trace!("Registering gateway");
|
||||
|
||||
// it's fine to instantiate it here as it's only used once (during authentication or registration)
|
||||
// and putting it into the GatewayClient struct would be a hassle
|
||||
@@ -494,7 +493,6 @@ impl<C, St> GatewayClient<C, St> {
|
||||
if !self.connection.is_established() {
|
||||
return Err(GatewayClientError::ConnectionNotEstablished);
|
||||
}
|
||||
log::debug!("Authenticating with gateway");
|
||||
|
||||
// it's fine to instantiate it here as it's only used once (during authentication or registration)
|
||||
// and putting it into the GatewayClient struct would be a hassle
|
||||
@@ -530,7 +528,6 @@ impl<C, St> GatewayClient<C, St> {
|
||||
self.authenticated = status;
|
||||
self.bandwidth_remaining = bandwidth_remaining;
|
||||
self.negotiated_protocol = protocol_version;
|
||||
log::debug!("authenticated: {status}, bandwidth remaining: {bandwidth_remaining}");
|
||||
Ok(())
|
||||
}
|
||||
ServerResponse::Error { message } => Err(GatewayClientError::GatewayError(message)),
|
||||
@@ -543,11 +540,10 @@ impl<C, St> GatewayClient<C, St> {
|
||||
&mut self,
|
||||
) -> Result<Arc<SharedKeys>, GatewayClientError> {
|
||||
if self.authenticated {
|
||||
debug!("Already authenticated");
|
||||
return if let Some(shared_key) = &self.shared_key {
|
||||
Ok(Arc::clone(shared_key))
|
||||
} else {
|
||||
Err(GatewayClientError::AuthenticationFailureWithPreexistingSharedKey)
|
||||
Err(GatewayClientError::AuthenticationFailure)
|
||||
};
|
||||
}
|
||||
|
||||
@@ -853,7 +849,6 @@ impl<C, St> GatewayClient<C, St> {
|
||||
// type alias for an ease of use
|
||||
pub type InitGatewayClient = GatewayClient<InitOnly>;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct InitOnly;
|
||||
|
||||
impl GatewayClient<InitOnly, EphemeralCredentialStorage> {
|
||||
|
||||
@@ -71,9 +71,6 @@ pub enum GatewayClientError {
|
||||
#[error("Authentication failure")]
|
||||
AuthenticationFailure,
|
||||
|
||||
#[error("Authentication failure with preexisting shared key")]
|
||||
AuthenticationFailureWithPreexistingSharedKey,
|
||||
|
||||
#[error("Timed out")]
|
||||
Timeout,
|
||||
|
||||
|
||||
@@ -10,14 +10,9 @@ use futures::stream::{SplitSink, SplitStream};
|
||||
use futures::{SinkExt, StreamExt};
|
||||
use log::*;
|
||||
use nym_gateway_requests::registration::handshake::SharedKeys;
|
||||
use nym_gateway_requests::ServerResponse;
|
||||
use nym_task::TaskClient;
|
||||
use si_scale::helpers::bibytes2;
|
||||
use std::os::raw::c_int as RawFd;
|
||||
use std::sync::atomic::{AtomicI64, Ordering};
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use time::OffsetDateTime;
|
||||
use tungstenite::Message;
|
||||
|
||||
#[cfg(unix)]
|
||||
@@ -53,22 +48,6 @@ pub(crate) fn ws_fd(_conn: &WsConn) -> Option<RawFd> {
|
||||
None
|
||||
}
|
||||
|
||||
// disgusting? absolutely, but does the trick for now
|
||||
static LAST_LOGGED_BANDWIDTH_TS: AtomicI64 = AtomicI64::new(0);
|
||||
|
||||
fn maybe_log_bandwidth(remaining: i64) {
|
||||
// SAFETY: this value is always populated with valid timestamps
|
||||
let last =
|
||||
OffsetDateTime::from_unix_timestamp(LAST_LOGGED_BANDWIDTH_TS.load(Ordering::Relaxed))
|
||||
.unwrap();
|
||||
let now = OffsetDateTime::now_utc();
|
||||
if last + Duration::from_secs(10) < now {
|
||||
log::info!("remaining bandwidth: {}", bibytes2(remaining as f64));
|
||||
LAST_LOGGED_BANDWIDTH_TS.store(now.unix_timestamp(), Ordering::Relaxed)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct PartiallyDelegated {
|
||||
sink_half: SplitSink<WsConn, Message>,
|
||||
delegated_stream: (SplitStreamReceiver, oneshot::Sender<()>),
|
||||
@@ -76,10 +55,7 @@ pub(crate) struct PartiallyDelegated {
|
||||
}
|
||||
|
||||
impl PartiallyDelegated {
|
||||
fn recover_received_plaintexts(
|
||||
ws_msgs: Vec<Message>,
|
||||
shared_key: &SharedKeys,
|
||||
) -> Result<Vec<Vec<u8>>, GatewayClientError> {
|
||||
fn recover_received_plaintexts(ws_msgs: Vec<Message>, shared_key: &SharedKeys) -> Vec<Vec<u8>> {
|
||||
let mut plaintexts = Vec::with_capacity(ws_msgs.len());
|
||||
for ws_msg in ws_msgs {
|
||||
match ws_msg {
|
||||
@@ -97,32 +73,15 @@ impl PartiallyDelegated {
|
||||
// TODO: those can return the "send confirmations" - perhaps it should be somehow worked around?
|
||||
Message::Text(text) => {
|
||||
trace!(
|
||||
"received a text message - probably a response to some previous query! - {text}",
|
||||
"received a text message - probably a response to some previous query! - {}",
|
||||
text
|
||||
);
|
||||
match ServerResponse::try_from(text)
|
||||
.map_err(|_| GatewayClientError::MalformedResponse)?
|
||||
{
|
||||
ServerResponse::Send {
|
||||
remaining_bandwidth,
|
||||
} => maybe_log_bandwidth(remaining_bandwidth),
|
||||
ServerResponse::Error { message } => {
|
||||
error!("gateway failure: {message}");
|
||||
return Err(GatewayClientError::GatewayError(message));
|
||||
}
|
||||
other => {
|
||||
warn!(
|
||||
"received illegal message of type {} in an authenticated client",
|
||||
other.name()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
_ => continue,
|
||||
}
|
||||
}
|
||||
Ok(plaintexts)
|
||||
plaintexts
|
||||
}
|
||||
|
||||
fn route_socket_messages(
|
||||
@@ -130,7 +89,7 @@ impl PartiallyDelegated {
|
||||
packet_router: &PacketRouter,
|
||||
shared_key: &SharedKeys,
|
||||
) -> Result<(), GatewayClientError> {
|
||||
let plaintexts = Self::recover_received_plaintexts(ws_msgs, shared_key)?;
|
||||
let plaintexts = Self::recover_received_plaintexts(ws_msgs, shared_key);
|
||||
packet_router.route_received(plaintexts)
|
||||
}
|
||||
|
||||
@@ -170,8 +129,7 @@ impl PartiallyDelegated {
|
||||
};
|
||||
|
||||
if let Err(err) = Self::route_socket_messages(ws_msgs, &packet_router, shared_key.as_ref()) {
|
||||
log::error!("Route socket messages failed: {err}");
|
||||
break Err(err)
|
||||
log::warn!("Route socket messages failed: {err}");
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -263,7 +221,6 @@ impl PartiallyDelegated {
|
||||
// we can either have the stream itself or an option to re-obtain it
|
||||
// by notifying the future owning it to finish the execution and awaiting the result
|
||||
// which should be almost immediate (or an invalid state which should never, ever happen)
|
||||
#[derive(Debug)]
|
||||
pub(crate) enum SocketState {
|
||||
Available(Box<WsConn>),
|
||||
PartiallyDelegated(PartiallyDelegated),
|
||||
|
||||
@@ -44,7 +44,7 @@ pub enum NyxdError {
|
||||
#[error("{0} is not a valid tx hash")]
|
||||
InvalidTxHash(String),
|
||||
|
||||
#[error("Tendermint RPC request failed - {0}")]
|
||||
#[error("Tendermint RPC request failed: {0}")]
|
||||
TendermintErrorRpc(#[from] TendermintRpcError),
|
||||
|
||||
#[error("tendermint library failure: {0}")]
|
||||
@@ -56,22 +56,22 @@ pub enum NyxdError {
|
||||
#[error("Failed when attempting to deserialize data ({0})")]
|
||||
DeserializationError(String),
|
||||
|
||||
#[error("Failed when attempting to encode our protobuf data - {0}")]
|
||||
#[error("Failed when attempting to encode our protobuf data: {0}")]
|
||||
ProtobufEncodingError(#[from] prost::EncodeError),
|
||||
|
||||
#[error("Failed to decode our protobuf data - {0}")]
|
||||
#[error("Failed to decode our protobuf data: {0}")]
|
||||
ProtobufDecodingError(#[from] prost::DecodeError),
|
||||
|
||||
#[error("Account {0} does not exist on the chain")]
|
||||
#[error("Account '{0}' does not exist on the chain")]
|
||||
NonExistentAccountError(AccountId),
|
||||
|
||||
#[error("Failed on json serialization/deserialization - {0}")]
|
||||
#[error("Failed on json serialization/deserialization: {0}")]
|
||||
SerdeJsonError(#[from] serde_json::Error),
|
||||
|
||||
#[error("Account {0} is not a valid account address")]
|
||||
#[error("Account '{0}' is not a valid account address")]
|
||||
MalformedAccountAddress(String),
|
||||
|
||||
#[error("Account {0} has an invalid associated public key")]
|
||||
#[error("Account '{0}' has an invalid associated public key")]
|
||||
InvalidPublicKey(AccountId),
|
||||
|
||||
#[error("Queried contract (code_id: {0}) did not have any code information attached")]
|
||||
@@ -86,7 +86,7 @@ pub enum NyxdError {
|
||||
#[error("Block has an invalid height (either negative or larger than i64::MAX")]
|
||||
InvalidHeight,
|
||||
|
||||
#[error("Failed to compress provided wasm code - {0}")]
|
||||
#[error("Failed to compress provided wasm code: {0}")]
|
||||
WasmCompressionError(io::Error),
|
||||
|
||||
#[error("Logs returned from the validator were malformed")]
|
||||
|
||||
@@ -109,7 +109,8 @@ trait TendermintRpcErrorMap {
|
||||
|
||||
impl TendermintRpcErrorMap for reqwest::Error {
|
||||
fn into_rpc_err(self) -> Error {
|
||||
todo!()
|
||||
// that's not the best error converion, but it's better than a panic
|
||||
Error::client_internal(self.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -148,10 +148,6 @@ pub async fn execute(args: Args, client: SigningClient) -> anyhow::Result<()> {
|
||||
bail!("the provided free pass request has too long expiry (expiry is set to on {expiration_date})")
|
||||
}
|
||||
|
||||
if expiration_date < now {
|
||||
bail!("the provided free pass expiry is set in the past!")
|
||||
}
|
||||
|
||||
// issuance start
|
||||
block_until_coconut_is_available(&client).await?;
|
||||
|
||||
|
||||
@@ -1,354 +0,0 @@
|
||||
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use std::cmp::Ordering;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::fs;
|
||||
use std::fs::OpenOptions;
|
||||
|
||||
use clap::Parser;
|
||||
use comfy_table::Table;
|
||||
use csv::WriterBuilder;
|
||||
use log::info;
|
||||
use nym_mixnet_contract_common::ExecuteMsg;
|
||||
use nym_mixnet_contract_common::ExecuteMsg::{DelegateToMixnode, UndelegateFromMixnode};
|
||||
|
||||
use nym_mixnet_contract_common::PendingEpochEventKind::{Delegate, Undelegate};
|
||||
use nym_validator_client::nyxd::contract_traits::{NymContractsProvider, PagedMixnetQueryClient};
|
||||
use nym_validator_client::nyxd::Coin;
|
||||
|
||||
use crate::context::SigningClient;
|
||||
use crate::utils::pretty_coin;
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
pub struct Args {
|
||||
#[clap(long)]
|
||||
pub memo: Option<String>,
|
||||
|
||||
#[clap(
|
||||
long,
|
||||
help = "Input csv files with delegation amounts. Format: (mixID, amount(in NYM))"
|
||||
)]
|
||||
pub input: String,
|
||||
|
||||
#[clap(
|
||||
long,
|
||||
help = "An output file path (CSV format) to create or append a log of results to"
|
||||
)]
|
||||
pub output: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct InputFileRow {
|
||||
pub mix_id: String,
|
||||
pub amount: Coin,
|
||||
}
|
||||
#[derive(Debug)]
|
||||
pub struct InputFileReader {
|
||||
pub rows: Vec<InputFileRow>,
|
||||
}
|
||||
|
||||
impl InputFileReader {
|
||||
pub fn new(path: &str) -> Result<InputFileReader, anyhow::Error> {
|
||||
let file_contents = fs::read_to_string(path)?;
|
||||
let mut rows = Vec::new();
|
||||
let mut mix_id_set = HashSet::new();
|
||||
|
||||
for line in file_contents
|
||||
.lines()
|
||||
.map(str::trim)
|
||||
.filter(|line| !line.is_empty())
|
||||
{
|
||||
let tokens: Vec<_> = line.split(',').collect();
|
||||
if tokens.len() != 2 {
|
||||
anyhow::bail!("Incorrect format: {}", line);
|
||||
}
|
||||
let mix_id = tokens[0].trim().to_string();
|
||||
let input_amount = tokens[1]
|
||||
.trim()
|
||||
.parse::<u128>()
|
||||
.map_err(|_| anyhow::anyhow!("'{}' has an invalid amount", line))?;
|
||||
|
||||
let micro_nym_amount = input_amount * 1_000_000;
|
||||
|
||||
if !mix_id_set.insert(mix_id.clone()) {
|
||||
anyhow::bail!("Duplicate mix_id found: {}", mix_id);
|
||||
}
|
||||
|
||||
rows.push(InputFileRow {
|
||||
mix_id,
|
||||
amount: Coin {
|
||||
amount: micro_nym_amount,
|
||||
denom: "unym".to_string(),
|
||||
},
|
||||
});
|
||||
}
|
||||
Ok(InputFileReader { rows })
|
||||
}
|
||||
}
|
||||
|
||||
fn write_to_csv(
|
||||
output_details: Vec<[String; 3]>,
|
||||
output_file: Option<String>,
|
||||
) -> Result<(), anyhow::Error> {
|
||||
if let Some(file_path) = output_file {
|
||||
// Determine if the file exists and is not empty
|
||||
let file_exists = fs::metadata(&file_path)
|
||||
.map(|metadata| metadata.len() > 0)
|
||||
.unwrap_or(false);
|
||||
|
||||
// Open the file for appending or creation
|
||||
let file = OpenOptions::new()
|
||||
.append(true)
|
||||
.create(true)
|
||||
.open(&file_path)?;
|
||||
|
||||
if !file_exists {
|
||||
let mut wtr = csv::Writer::from_writer(&file);
|
||||
wtr.write_record(["Operation", "Transaction Hash", "Timestamp"])?;
|
||||
wtr.flush()?;
|
||||
}
|
||||
|
||||
let mut wtr = WriterBuilder::new()
|
||||
.has_headers(!file_exists)
|
||||
.from_writer(file);
|
||||
|
||||
// Write the details to the CSV file
|
||||
for detail in output_details {
|
||||
wtr.write_record(&detail)?;
|
||||
}
|
||||
wtr.flush()?;
|
||||
info!("All operations saved to output file");
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn fetch_delegation_data(
|
||||
client: &SigningClient,
|
||||
) -> Result<HashMap<String, Coin>, anyhow::Error> {
|
||||
let address = client.address();
|
||||
// Fetch all delegations for the user
|
||||
let delegations = match client.get_all_delegator_delegations(&address).await {
|
||||
Ok(delegations) => delegations,
|
||||
Err(e) => {
|
||||
anyhow::bail!("Error fetching delegations: {}", e)
|
||||
}
|
||||
};
|
||||
|
||||
// Build a map to make it easier to handle delegation data
|
||||
let mut existing_delegation_map: HashMap<String, Coin> = HashMap::new();
|
||||
let mut pending_delegation_map: HashMap<String, Coin> = HashMap::new();
|
||||
|
||||
for delegation in delegations {
|
||||
existing_delegation_map
|
||||
.insert(delegation.mix_id.to_string(), Coin::from(delegation.amount));
|
||||
}
|
||||
|
||||
// Look for pending delegate / undelegate events which might be of interest to us
|
||||
let pending_events = match client.get_all_pending_epoch_events().await {
|
||||
Ok(events) => events,
|
||||
Err(e) => {
|
||||
anyhow::bail!("Error fetching pending epoch events: {}", e);
|
||||
}
|
||||
};
|
||||
|
||||
for event in pending_events {
|
||||
match event.event.kind {
|
||||
// If a pending undelegate tx is found, remove it from delegation map
|
||||
Undelegate { owner, mix_id, .. } => {
|
||||
if owner == address.as_ref()
|
||||
&& existing_delegation_map.contains_key(&mix_id.to_string())
|
||||
{
|
||||
existing_delegation_map.remove(&mix_id.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
// If a pending delegation event is found, gather them to consolidate later
|
||||
Delegate {
|
||||
owner,
|
||||
mix_id,
|
||||
amount,
|
||||
..
|
||||
} => {
|
||||
if owner == address.as_ref() {
|
||||
let mut amount = Coin::from(amount);
|
||||
if let Some(pending_record) = pending_delegation_map.get(&mix_id.to_string()) {
|
||||
amount.amount += pending_record.amount;
|
||||
}
|
||||
pending_delegation_map.insert(mix_id.to_string(), amount);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
}
|
||||
|
||||
// Consolidate pending events into delegation map
|
||||
for (mix_id, amount) in pending_delegation_map {
|
||||
existing_delegation_map
|
||||
.entry(mix_id)
|
||||
.and_modify(|e| e.amount += amount.amount)
|
||||
.or_insert(amount);
|
||||
}
|
||||
|
||||
Ok(existing_delegation_map)
|
||||
}
|
||||
|
||||
pub async fn delegate_to_multiple_mixnodes(args: Args, client: SigningClient) {
|
||||
let records = match InputFileReader::new(&args.input) {
|
||||
Ok(records) => records,
|
||||
Err(e) => {
|
||||
println!("Error reading input file: {}", e);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let existing_delegation_map = fetch_delegation_data(&client)
|
||||
.await
|
||||
.expect("Could not fetch existing delegations");
|
||||
|
||||
let mut delegation_table = Table::new();
|
||||
let mut undelegation_table = Table::new();
|
||||
let mut delegation_msgs: Vec<(ExecuteMsg, Vec<Coin>)> = Vec::new();
|
||||
let mut undelegation_msgs: Vec<(ExecuteMsg, Vec<Coin>)> = Vec::new();
|
||||
|
||||
delegation_table.set_header(["Mix ID", "Input Amount", "Adjusted Amount"]);
|
||||
undelegation_table.set_header(["Mix ID"]);
|
||||
|
||||
for row in &records.rows {
|
||||
let input_amount = row.amount.amount;
|
||||
let existing_delegation_amount = existing_delegation_map
|
||||
.get(&row.mix_id)
|
||||
.map_or(0, |coin| coin.amount);
|
||||
|
||||
match existing_delegation_amount.cmp(&input_amount) {
|
||||
Ordering::Equal => continue, // No action needed if amounts are equal
|
||||
|
||||
Ordering::Less => {
|
||||
// Delegate the difference if the existing delegation is less
|
||||
let difference = Coin {
|
||||
amount: input_amount - existing_delegation_amount,
|
||||
denom: row.amount.denom.clone(),
|
||||
};
|
||||
let mix_id = row.mix_id.clone().parse::<u32>().unwrap();
|
||||
delegation_msgs.push((DelegateToMixnode { mix_id }, vec![difference.clone()]));
|
||||
delegation_table.add_row(&[
|
||||
row.mix_id.clone(),
|
||||
pretty_coin(&row.amount),
|
||||
pretty_coin(&difference),
|
||||
]);
|
||||
}
|
||||
|
||||
Ordering::Greater => {
|
||||
let mix_id = row.mix_id.clone().parse::<u32>().unwrap();
|
||||
let coins: Vec<Coin> = vec![];
|
||||
undelegation_msgs.push((UndelegateFromMixnode { mix_id }, coins));
|
||||
undelegation_table.add_row(&[row.mix_id.clone()]);
|
||||
|
||||
if row.amount.amount > 0 {
|
||||
delegation_msgs.push((DelegateToMixnode { mix_id }, vec![row.amount.clone()]));
|
||||
delegation_table.add_row(&[
|
||||
row.mix_id.clone(),
|
||||
pretty_coin(&row.amount),
|
||||
pretty_coin(&row.amount),
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if delegation_msgs.is_empty() && undelegation_msgs.is_empty() {
|
||||
println!("Nothing to do. Delegations are up-to-date!");
|
||||
return;
|
||||
}
|
||||
|
||||
if !undelegation_msgs.is_empty() {
|
||||
println!("Undelegation records : \n{}\n\n", undelegation_table);
|
||||
}
|
||||
|
||||
if !delegation_msgs.is_empty() {
|
||||
println!("Delegation records : \n{}\n\n", delegation_table);
|
||||
}
|
||||
|
||||
let ans = inquire::Confirm::new("Do you want to continue with the shown operations?")
|
||||
.with_default(false)
|
||||
.with_help_message("You must confirm before the transactions are signed")
|
||||
.prompt();
|
||||
|
||||
if let Err(e) = ans {
|
||||
info!("Aborting, {}...", e);
|
||||
return;
|
||||
}
|
||||
|
||||
if let Ok(false) = ans {
|
||||
info!("Aborting:: User denied proceeding with signing!");
|
||||
return;
|
||||
}
|
||||
|
||||
let mut output_details: Vec<[String; 3]> = Vec::new();
|
||||
let now = time::OffsetDateTime::now_utc();
|
||||
let now = now
|
||||
.format(&time::format_description::well_known::Rfc3339)
|
||||
.unwrap();
|
||||
|
||||
let mixnet_contract = client
|
||||
.mixnet_contract_address()
|
||||
.expect("mixnet contract address is not available");
|
||||
|
||||
// Execute all undelegation transactions
|
||||
if !undelegation_msgs.is_empty() {
|
||||
let res = client
|
||||
.execute_multiple(
|
||||
mixnet_contract,
|
||||
undelegation_msgs.clone(),
|
||||
None,
|
||||
format!(
|
||||
"Undelegate from {} nodes via nym-cli",
|
||||
undelegation_msgs.len()
|
||||
),
|
||||
)
|
||||
.await
|
||||
.expect("Could not undelegate!");
|
||||
|
||||
println!(
|
||||
"Undelegation transaction successful : {}",
|
||||
res.transaction_hash
|
||||
);
|
||||
output_details.push([
|
||||
"Undelegate".to_string(),
|
||||
res.transaction_hash.to_string(),
|
||||
now.clone(),
|
||||
]);
|
||||
}
|
||||
|
||||
// Execute all delegation delegations
|
||||
if !delegation_msgs.is_empty() {
|
||||
let res = client
|
||||
.execute_multiple(
|
||||
mixnet_contract,
|
||||
delegation_msgs,
|
||||
None,
|
||||
format!(
|
||||
"Delegatation to {} nodes via nym-cli",
|
||||
undelegation_msgs.len()
|
||||
),
|
||||
)
|
||||
.await
|
||||
.expect("Could not delegate");
|
||||
|
||||
println!(
|
||||
"Delegation transaction successful : {}",
|
||||
res.transaction_hash
|
||||
);
|
||||
output_details.push([
|
||||
"Delegate".to_string(),
|
||||
res.transaction_hash.to_string(),
|
||||
now.clone(),
|
||||
]);
|
||||
}
|
||||
|
||||
if args.output.is_some() {
|
||||
if let Err(e) = write_to_csv(output_details, args.output) {
|
||||
info!("Failed to write to CSV, {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,6 @@ use clap::{Args, Subcommand};
|
||||
pub mod rewards;
|
||||
|
||||
pub mod delegate_to_mixnode;
|
||||
pub mod delegate_to_multiple_mixnodes;
|
||||
pub mod query_for_delegations;
|
||||
pub mod undelegate_from_mixnode;
|
||||
pub mod vesting_delegate_to_mixnode;
|
||||
@@ -27,8 +26,6 @@ pub enum MixnetDelegatorsCommands {
|
||||
Rewards(rewards::MixnetDelegatorsReward),
|
||||
/// Delegate to a mixnode
|
||||
Delegate(delegate_to_mixnode::Args),
|
||||
/// Perform bulk delegations from an input file
|
||||
DelegateMulti(delegate_to_multiple_mixnodes::Args),
|
||||
/// Undelegate from a mixnode
|
||||
Undelegate(undelegate_from_mixnode::Args),
|
||||
/// Delegate to a mixnode with locked tokens
|
||||
|
||||
@@ -328,8 +328,4 @@ impl EpochState {
|
||||
pub fn is_dealing_exchange(&self) -> bool {
|
||||
matches!(self, EpochState::DealingExchange { .. })
|
||||
}
|
||||
|
||||
pub fn is_waiting_initialisation(&self) -> bool {
|
||||
matches!(self, EpochState::WaitingInitialisation)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ license.workspace = true
|
||||
|
||||
[dependencies]
|
||||
async-trait = { workspace = true }
|
||||
|
||||
log = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
tokio = { workspace = true, features = ["sync"]}
|
||||
@@ -26,4 +25,4 @@ features = [ "rt-multi-thread", "net", "signal", "fs" ]
|
||||
|
||||
[build-dependencies]
|
||||
sqlx = { workspace = true, features = ["runtime-tokio-rustls", "sqlite", "macros", "migrate"] }
|
||||
tokio = { version = "1.24.1", features = ["rt-multi-thread", "macros"] }
|
||||
tokio = { workspace = true, features = ["rt-multi-thread", "macros"] }
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
/*
|
||||
* Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
ALTER TABLE coconut_credentials
|
||||
RENAME TO old_coconut_credentials;
|
||||
|
||||
CREATE TABLE coconut_credentials
|
||||
(
|
||||
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||
|
||||
-- introduce a way for us to introduce breaking changes in serialization
|
||||
serialization_revision INTEGER NOT NULL,
|
||||
|
||||
-- the best we can do without enums
|
||||
credential_type TEXT CHECK ( credential_type IN ('BandwidthVoucher', 'FreeBandwidthPass') ) NOT NULL,
|
||||
credential_data BLOB NOT NULL UNIQUE,
|
||||
epoch_id INTEGER NOT NULL,
|
||||
|
||||
-- this field is only really applicable to free passes
|
||||
expired BOOLEAN NOT NULL
|
||||
);
|
||||
|
||||
ALTER TABLE credential_usage
|
||||
RENAME TO old_credential_usage;
|
||||
|
||||
-- for bandwidth vouchers there's going to be only a single entry; for freepasses there can be as many as there are gateways
|
||||
CREATE TABLE credential_usage
|
||||
(
|
||||
credential_id INTEGER NOT NULL REFERENCES coconut_credentials (id),
|
||||
gateway_id_bs58 TEXT NOT NULL,
|
||||
|
||||
-- no matter credential type, we can't spend the same credential with the same gateway multiple times
|
||||
UNIQUE (credential_id, gateway_id_bs58)
|
||||
);
|
||||
|
||||
INSERT INTO coconut_credentials
|
||||
SELECT *
|
||||
FROM old_coconut_credentials;
|
||||
|
||||
|
||||
INSERT INTO credential_usage
|
||||
SELECT *
|
||||
FROM old_credential_usage;
|
||||
|
||||
DROP TABLE old_coconut_credentials;
|
||||
DROP TABLE old_credential_usage;
|
||||
@@ -33,6 +33,12 @@ impl CoconutCredentialManager {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn take_credentials(self) -> Vec<StoredIssuedCredential> {
|
||||
let mut inner = self.inner.write().await;
|
||||
inner.credential_usage = Vec::new();
|
||||
std::mem::take(&mut inner.credentials)
|
||||
}
|
||||
|
||||
pub async fn insert_issued_credential(
|
||||
&self,
|
||||
credential_type: String,
|
||||
|
||||
@@ -44,7 +44,7 @@ impl CoconutCredentialManager {
|
||||
r#"
|
||||
SELECT *
|
||||
FROM coconut_credentials
|
||||
WHERE coconut_credentials.credential_type == "FreeBandwidthPass" AND coconut_credentials.expired = false
|
||||
WHERE coconut_credentials.credential_type == "FreeBandwidthPass"
|
||||
AND NOT EXISTS (SELECT 1
|
||||
FROM credential_usage
|
||||
WHERE credential_usage.credential_id = coconut_credentials.id
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use std::fmt::{self, Debug, Formatter};
|
||||
|
||||
use crate::backends::memory::CoconutCredentialManager;
|
||||
use crate::error::StorageError;
|
||||
use crate::models::{StorableIssuedCredential, StoredIssuedCredential};
|
||||
@@ -17,6 +15,12 @@ pub struct EphemeralStorage {
|
||||
coconut_credential_manager: CoconutCredentialManager,
|
||||
}
|
||||
|
||||
impl EphemeralStorage {
|
||||
pub async fn take_credentials(self) -> Vec<StoredIssuedCredential> {
|
||||
self.coconut_credential_manager.take_credentials().await
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for EphemeralStorage {
|
||||
fn default() -> Self {
|
||||
EphemeralStorage {
|
||||
@@ -25,12 +29,6 @@ impl Default for EphemeralStorage {
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for EphemeralStorage {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "EphemeralStorage")
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Storage for EphemeralStorage {
|
||||
type StorageError = StorageError;
|
||||
|
||||
@@ -3,19 +3,6 @@
|
||||
|
||||
use zeroize::{Zeroize, ZeroizeOnDrop};
|
||||
|
||||
// #[derive(Clone)]
|
||||
// pub struct CoconutCredential {
|
||||
// #[allow(dead_code)]
|
||||
// pub id: i64,
|
||||
// pub voucher_value: String,
|
||||
// pub voucher_info: String,
|
||||
// pub serial_number: String,
|
||||
// pub binding_number: String,
|
||||
// pub signature: String,
|
||||
// pub epoch_id: String,
|
||||
// pub consumed: bool,
|
||||
// }
|
||||
|
||||
#[cfg_attr(not(target_arch = "wasm32"), derive(sqlx::FromRow))]
|
||||
#[derive(Zeroize, ZeroizeOnDrop, Clone)]
|
||||
pub struct StoredIssuedCredential {
|
||||
|
||||
@@ -8,8 +8,8 @@ use std::str::FromStr;
|
||||
use thiserror::Error;
|
||||
|
||||
pub use nym_coconut::{
|
||||
aggregate_signature_shares_and_verify, aggregate_verification_keys, blind_sign, hash_to_scalar,
|
||||
keygen, prepare_blind_sign, prove_bandwidth_credential, verify_credential, Attribute, Base58,
|
||||
aggregate_signature_shares, aggregate_verification_keys, blind_sign, hash_to_scalar, keygen,
|
||||
prepare_blind_sign, prove_bandwidth_credential, verify_credential, Attribute, Base58,
|
||||
BlindSignRequest, BlindedSerialNumber, BlindedSignature, Bytable, CoconutError, KeyPair,
|
||||
Parameters, PrivateAttribute, PublicAttribute, SecretKey, Signature, SignatureShare,
|
||||
VerificationKey, VerifyCredentialRequest,
|
||||
|
||||
@@ -10,19 +10,18 @@ use crate::coconut::bandwidth::{
|
||||
use crate::coconut::utils::scalar_serde_helper;
|
||||
use crate::error::Error;
|
||||
use nym_credentials_interface::{
|
||||
aggregate_signature_shares_and_verify, hash_to_scalar, prepare_blind_sign, Attribute,
|
||||
BlindedSerialNumber, BlindedSignature, Parameters, PrivateAttribute, PublicAttribute,
|
||||
Signature, SignatureShare, VerificationKey,
|
||||
aggregate_signature_shares, hash_to_scalar, prepare_blind_sign, Attribute, BlindedSerialNumber,
|
||||
BlindedSignature, Parameters, PrivateAttribute, PublicAttribute, Signature, SignatureShare,
|
||||
VerificationKey,
|
||||
};
|
||||
use nym_crypto::asymmetric::{encryption, identity};
|
||||
use nym_validator_client::nym_api::EpochId;
|
||||
use nym_validator_client::nyxd::{Coin, Hash};
|
||||
use nym_validator_client::signing::AccountData;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use time::OffsetDateTime;
|
||||
use zeroize::{Zeroize, ZeroizeOnDrop};
|
||||
|
||||
pub use nym_validator_client::nyxd::{Coin, Hash};
|
||||
|
||||
#[derive(Zeroize, ZeroizeOnDrop, Serialize, Deserialize)]
|
||||
pub enum BandwidthCredentialIssuanceDataVariant {
|
||||
Voucher(BandwidthVoucherIssuanceData),
|
||||
@@ -280,7 +279,7 @@ impl IssuanceBandwidthCredential {
|
||||
attributes.extend_from_slice(&private_attributes);
|
||||
attributes.extend_from_slice(&public_attributes);
|
||||
|
||||
aggregate_signature_shares_and_verify(params, verification_key, &attributes, shares)
|
||||
aggregate_signature_shares(params, verification_key, &attributes, shares)
|
||||
.map_err(Error::SignatureAggregationError)
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ use crate::coconut::utils::scalar_serde_helper;
|
||||
use crate::error::Error;
|
||||
use nym_api_requests::coconut::BlindSignRequestBody;
|
||||
use nym_credentials_interface::{
|
||||
hash_to_scalar, Attribute, BlindSignRequest, BlindedSignature, CredentialType, PublicAttribute,
|
||||
hash_to_scalar, Attribute, BlindSignRequest, BlindedSignature, PublicAttribute,
|
||||
};
|
||||
use nym_crypto::asymmetric::{encryption, identity};
|
||||
use nym_validator_client::nyxd::{Coin, Hash};
|
||||
@@ -123,10 +123,6 @@ impl BandwidthVoucherIssuanceData {
|
||||
&self.value_prehashed
|
||||
}
|
||||
|
||||
pub fn typ() -> CredentialType {
|
||||
CredentialType::Voucher
|
||||
}
|
||||
|
||||
pub fn tx_hash(&self) -> Hash {
|
||||
self.deposit_tx_hash
|
||||
}
|
||||
|
||||
@@ -17,3 +17,11 @@ schemars = { workspace = true, features = ["preserve_order"] }
|
||||
serde = { workspace = true, features = ["derive"]}
|
||||
thiserror = { workspace = true }
|
||||
url = { workspace = true }
|
||||
|
||||
# 'wasm-serde-types' feature
|
||||
tsify = { workspace = true, features = ["js"], optional = true }
|
||||
wasm-bindgen = { workspace = true, optional = true }
|
||||
|
||||
[features]
|
||||
default = []
|
||||
wasm-serde-types = ["tsify", "wasm-bindgen"]
|
||||
@@ -11,39 +11,96 @@ use std::{
|
||||
ffi::OsStr,
|
||||
ops::Not,
|
||||
};
|
||||
use url::Url;
|
||||
pub use url::{ParseError as UrlParseError, Url};
|
||||
|
||||
#[cfg(feature = "wasm-serde-types")]
|
||||
use tsify::Tsify;
|
||||
|
||||
#[cfg(feature = "wasm-serde-types")]
|
||||
use wasm_bindgen::prelude::wasm_bindgen;
|
||||
|
||||
pub mod mainnet;
|
||||
pub mod var_names;
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize, JsonSchema)]
|
||||
#[cfg_attr(feature = "wasm-serde-types", derive(Tsify))]
|
||||
#[cfg_attr(feature = "wasm-serde-types", tsify(into_wasm_abi, from_wasm_abi))]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct ChainDetails {
|
||||
#[serde(alias = "bech32_account_prefix")]
|
||||
pub bech32_account_prefix: String,
|
||||
|
||||
#[serde(alias = "mix_denom")]
|
||||
pub mix_denom: DenomDetailsOwned,
|
||||
|
||||
#[serde(alias = "stake_denom")]
|
||||
pub stake_denom: DenomDetailsOwned,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Deserialize, Eq, Hash, PartialEq, Serialize, JsonSchema)]
|
||||
#[cfg_attr(feature = "wasm-serde-types", derive(Tsify))]
|
||||
#[cfg_attr(feature = "wasm-serde-types", tsify(into_wasm_abi, from_wasm_abi))]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct NymContracts {
|
||||
#[cfg_attr(feature = "wasm-serde-types", tsify(optional))]
|
||||
#[serde(alias = "mixnet_contract_address")]
|
||||
pub mixnet_contract_address: Option<String>,
|
||||
|
||||
#[cfg_attr(feature = "wasm-serde-types", tsify(optional))]
|
||||
#[serde(alias = "vesting_contract_address")]
|
||||
pub vesting_contract_address: Option<String>,
|
||||
|
||||
#[cfg_attr(feature = "wasm-serde-types", tsify(optional))]
|
||||
#[serde(alias = "coconut_bandwidth_contract_address")]
|
||||
pub coconut_bandwidth_contract_address: Option<String>,
|
||||
|
||||
#[cfg_attr(feature = "wasm-serde-types", tsify(optional))]
|
||||
#[serde(alias = "group_contract_address")]
|
||||
pub group_contract_address: Option<String>,
|
||||
|
||||
#[cfg_attr(feature = "wasm-serde-types", tsify(optional))]
|
||||
#[serde(alias = "multisig_contract_address")]
|
||||
pub multisig_contract_address: Option<String>,
|
||||
|
||||
#[cfg_attr(feature = "wasm-serde-types", tsify(optional))]
|
||||
#[serde(alias = "coconut_dkg_contract_address")]
|
||||
pub coconut_dkg_contract_address: Option<String>,
|
||||
|
||||
#[cfg_attr(feature = "wasm-serde-types", tsify(optional))]
|
||||
#[serde(alias = "ephemera_contract_address")]
|
||||
pub ephemera_contract_address: Option<String>,
|
||||
|
||||
#[cfg_attr(feature = "wasm-serde-types", tsify(optional))]
|
||||
#[serde(alias = "service_provider_directory_contract_address")]
|
||||
pub service_provider_directory_contract_address: Option<String>,
|
||||
|
||||
#[cfg_attr(feature = "wasm-serde-types", tsify(optional))]
|
||||
#[serde(alias = "name_service_contract_address")]
|
||||
pub name_service_contract_address: Option<String>,
|
||||
}
|
||||
|
||||
// I wanted to use the simpler `NetworkDetails` name, but there's a clash
|
||||
// with `NetworkDetails` defined in all.rs...
|
||||
#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize, JsonSchema)]
|
||||
#[cfg_attr(feature = "wasm-serde-types", derive(Tsify))]
|
||||
#[cfg_attr(feature = "wasm-serde-types", tsify(into_wasm_abi, from_wasm_abi))]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct NymNetworkDetails {
|
||||
#[serde(alias = "network_name")]
|
||||
pub network_name: String,
|
||||
|
||||
#[serde(alias = "chain_details")]
|
||||
pub chain_details: ChainDetails,
|
||||
|
||||
pub endpoints: Vec<ValidatorDetails>,
|
||||
|
||||
pub contracts: NymContracts,
|
||||
|
||||
#[cfg_attr(feature = "wasm-serde-types", tsify(optional))]
|
||||
#[serde(alias = "explorer_api")]
|
||||
pub explorer_api: Option<String>,
|
||||
}
|
||||
|
||||
@@ -316,10 +373,17 @@ impl DenomDetails {
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Hash, Clone, PartialEq, Eq, JsonSchema)]
|
||||
#[cfg_attr(feature = "wasm-serde-types", derive(Tsify))]
|
||||
#[cfg_attr(feature = "wasm-serde-types", tsify(into_wasm_abi, from_wasm_abi))]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct DenomDetailsOwned {
|
||||
pub base: String,
|
||||
|
||||
pub display: String,
|
||||
|
||||
// i.e. display_amount * 10^display_exponent = base_amount
|
||||
#[serde(alias = "display_exponent")]
|
||||
pub display_exponent: u32,
|
||||
}
|
||||
|
||||
@@ -344,14 +408,24 @@ impl DenomDetailsOwned {
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize, JsonSchema)]
|
||||
#[cfg_attr(feature = "wasm-serde-types", derive(Tsify))]
|
||||
#[cfg_attr(feature = "wasm-serde-types", tsify(into_wasm_abi, from_wasm_abi))]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[serde(deny_unknown_fields)]
|
||||
#[non_exhaustive]
|
||||
pub struct ValidatorDetails {
|
||||
// it is assumed those values are always valid since they're being provided in our defaults file
|
||||
#[serde(alias = "nyxd_url")]
|
||||
pub nyxd_url: String,
|
||||
//
|
||||
|
||||
#[cfg_attr(feature = "wasm-serde-types", tsify(optional))]
|
||||
#[serde(alias = "websocket_url")]
|
||||
pub websocket_url: Option<String>,
|
||||
|
||||
// Right now api_url is optional as we are not running the api reliably on all validators
|
||||
// however, later on it should be a mandatory field
|
||||
#[cfg_attr(feature = "wasm-serde-types", tsify(optional))]
|
||||
#[serde(alias = "api_url")]
|
||||
pub api_url: Option<String>,
|
||||
// TODO: I'd argue this one should also have a field like `gas_price` since its a validator-specific setting
|
||||
}
|
||||
@@ -373,16 +447,26 @@ impl ValidatorDetails {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn try_nyxd_url(&self) -> Result<Url, url::ParseError> {
|
||||
self.nyxd_url.parse()
|
||||
}
|
||||
|
||||
pub fn nyxd_url(&self) -> Url {
|
||||
self.nyxd_url
|
||||
.parse()
|
||||
self.try_nyxd_url()
|
||||
.expect("the provided nyxd url is invalid!")
|
||||
}
|
||||
|
||||
pub fn try_api_url(&self) -> Option<Result<Url, url::ParseError>> {
|
||||
self.api_url.as_ref().map(|url| url.parse())
|
||||
}
|
||||
|
||||
pub fn api_url(&self) -> Option<Url> {
|
||||
self.api_url
|
||||
.as_ref()
|
||||
.map(|url| url.parse().expect("the provided api url is invalid!"))
|
||||
self.try_api_url()
|
||||
.map(|url| url.expect("the provided api url is invalid!"))
|
||||
}
|
||||
|
||||
pub fn try_websocket_url(&self) -> Option<Result<Url, url::ParseError>> {
|
||||
self.websocket_url.as_ref().map(|url| url.parse())
|
||||
}
|
||||
|
||||
pub fn websocket_url(&self) -> Option<Url> {
|
||||
|
||||
@@ -6,10 +6,10 @@ use criterion::{criterion_group, criterion_main, Criterion};
|
||||
use ff::Field;
|
||||
use group::{Curve, Group};
|
||||
use nym_coconut::{
|
||||
aggregate_signature_shares_and_verify, aggregate_verification_keys, blind_sign,
|
||||
prepare_blind_sign, prove_bandwidth_credential, random_scalars_refs, setup, ttp_keygen,
|
||||
verify_credential, verify_partial_blind_signature, Attribute, BlindedSignature, Parameters,
|
||||
Signature, SignatureShare, VerificationKey,
|
||||
aggregate_signature_shares, aggregate_verification_keys, blind_sign, prepare_blind_sign,
|
||||
prove_bandwidth_credential, random_scalars_refs, setup, ttp_keygen, verify_credential,
|
||||
verify_partial_blind_signature, Attribute, BlindedSignature, Parameters, Signature,
|
||||
SignatureShare, VerificationKey,
|
||||
};
|
||||
use rand::seq::SliceRandom;
|
||||
use std::ops::Neg;
|
||||
@@ -99,7 +99,7 @@ fn unblind_and_aggregate(
|
||||
let mut attributes = vec![];
|
||||
attributes.extend_from_slice(private_attributes);
|
||||
attributes.extend_from_slice(public_attributes);
|
||||
aggregate_signature_shares_and_verify(
|
||||
aggregate_signature_shares(
|
||||
params,
|
||||
verification_key,
|
||||
&attributes,
|
||||
|
||||
@@ -4,18 +4,14 @@
|
||||
#![warn(clippy::expect_used)]
|
||||
#![warn(clippy::unwrap_used)]
|
||||
|
||||
pub use bls12_381::Scalar;
|
||||
pub use elgamal::elgamal_keygen;
|
||||
pub use elgamal::ElGamalKeyPair;
|
||||
pub use elgamal::PublicKey;
|
||||
pub use error::CoconutError;
|
||||
pub use scheme::aggregation::aggregate_key_shares;
|
||||
pub use scheme::aggregation::aggregate_signature_shares;
|
||||
pub use scheme::aggregation::aggregate_signature_shares_and_verify;
|
||||
pub use scheme::aggregation::aggregate_verification_keys;
|
||||
pub use scheme::issuance::blind_sign;
|
||||
pub use scheme::issuance::prepare_blind_sign;
|
||||
pub use scheme::issuance::sign;
|
||||
pub use scheme::issuance::verify_partial_blind_signature;
|
||||
pub use scheme::issuance::BlindSignRequest;
|
||||
pub use scheme::keygen::keygen;
|
||||
@@ -23,19 +19,16 @@ pub use scheme::keygen::ttp_keygen;
|
||||
pub use scheme::keygen::KeyPair;
|
||||
pub use scheme::keygen::SecretKey;
|
||||
pub use scheme::keygen::VerificationKey;
|
||||
pub use scheme::keygen::VerificationKeyShare;
|
||||
pub use scheme::setup::setup;
|
||||
pub use scheme::setup::Parameters;
|
||||
pub use scheme::verification::check_vk_pairing;
|
||||
pub use scheme::verification::prove_bandwidth_credential;
|
||||
pub use scheme::verification::verify;
|
||||
pub use scheme::verification::verify_credential;
|
||||
pub use scheme::verification::BlindedSerialNumber;
|
||||
pub use scheme::verification::VerifyCredentialRequest;
|
||||
pub use scheme::BlindedSignature;
|
||||
pub use scheme::Signature;
|
||||
pub use scheme::SignatureShare;
|
||||
pub use scheme::SignerIndex;
|
||||
pub use traits::Base58;
|
||||
pub use traits::Bytable;
|
||||
pub use utils::hash_to_scalar;
|
||||
|
||||
@@ -12,7 +12,7 @@ use crate::error::{CoconutError, Result};
|
||||
use crate::scheme::verification::check_bilinear_pairing;
|
||||
use crate::scheme::{PartialSignature, Signature, SignatureShare, SignerIndex, VerificationKey};
|
||||
use crate::utils::perform_lagrangian_interpolation_at_origin;
|
||||
use crate::{Attribute, Parameters, VerificationKeyShare};
|
||||
use crate::{Attribute, Parameters};
|
||||
|
||||
pub(crate) trait Aggregatable: Sized {
|
||||
fn aggregate(aggregatable: &[Self], indices: Option<&[SignerIndex]>) -> Result<Self>;
|
||||
@@ -80,23 +80,7 @@ pub fn aggregate_verification_keys(
|
||||
Aggregatable::aggregate(keys, indices)
|
||||
}
|
||||
|
||||
pub fn aggregate_key_shares(shares: &[VerificationKeyShare]) -> Result<VerificationKey> {
|
||||
let (keys, indices): (Vec<_>, Vec<_>) = shares
|
||||
.iter()
|
||||
.map(|share| (share.key.clone(), share.index))
|
||||
.unzip();
|
||||
|
||||
aggregate_verification_keys(&keys, Some(&indices))
|
||||
}
|
||||
|
||||
pub fn aggregate_signatures(
|
||||
signatures: &[PartialSignature],
|
||||
indices: Option<&[SignerIndex]>,
|
||||
) -> Result<Signature> {
|
||||
Aggregatable::aggregate(signatures, indices)
|
||||
}
|
||||
|
||||
pub fn aggregate_signatures_and_verify(
|
||||
params: &Parameters,
|
||||
verification_key: &VerificationKey,
|
||||
attributes: &[&Attribute],
|
||||
@@ -104,7 +88,11 @@ pub fn aggregate_signatures_and_verify(
|
||||
indices: Option<&[SignerIndex]>,
|
||||
) -> Result<Signature> {
|
||||
// aggregate the signature
|
||||
let signature = aggregate_signatures(signatures, indices)?;
|
||||
|
||||
let signature = match Aggregatable::aggregate(signatures, indices) {
|
||||
Ok(res) => res,
|
||||
Err(err) => return Err(err),
|
||||
};
|
||||
|
||||
// Verify the signature
|
||||
let alpha = verification_key.alpha;
|
||||
@@ -128,16 +116,7 @@ pub fn aggregate_signatures_and_verify(
|
||||
Ok(signature)
|
||||
}
|
||||
|
||||
pub fn aggregate_signature_shares(shares: &[SignatureShare]) -> Result<Signature> {
|
||||
let (signatures, indices): (Vec<_>, Vec<_>) = shares
|
||||
.iter()
|
||||
.map(|share| (*share.signature(), share.index()))
|
||||
.unzip();
|
||||
|
||||
aggregate_signatures(&signatures, Some(&indices))
|
||||
}
|
||||
|
||||
pub fn aggregate_signature_shares_and_verify(
|
||||
pub fn aggregate_signature_shares(
|
||||
params: &Parameters,
|
||||
verification_key: &VerificationKey,
|
||||
attributes: &[&Attribute],
|
||||
@@ -148,7 +127,7 @@ pub fn aggregate_signature_shares_and_verify(
|
||||
.map(|share| (*share.signature(), share.index()))
|
||||
.unzip();
|
||||
|
||||
aggregate_signatures_and_verify(
|
||||
aggregate_signatures(
|
||||
params,
|
||||
verification_key,
|
||||
attributes,
|
||||
@@ -231,7 +210,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn signature_aggregation_works_for_any_subset_of_signatures() {
|
||||
let params = Parameters::new(2).unwrap();
|
||||
let mut params = Parameters::new(2).unwrap();
|
||||
random_scalars_refs!(attributes, params, 2);
|
||||
|
||||
let keypairs = ttp_keygen(¶ms, 3, 5).unwrap();
|
||||
@@ -248,12 +227,12 @@ mod tests {
|
||||
|
||||
let sigs = sks
|
||||
.iter()
|
||||
.map(|sk| sign(¶ms, sk, &attributes).unwrap())
|
||||
.map(|sk| sign(&mut params, sk, &attributes).unwrap())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// aggregating (any) threshold works
|
||||
let aggr_vk_1 = aggregate_verification_keys(&vks[..3], Some(&[1, 2, 3])).unwrap();
|
||||
let aggr_sig1 = aggregate_signatures_and_verify(
|
||||
let aggr_sig1 = aggregate_signatures(
|
||||
¶ms,
|
||||
&aggr_vk_1,
|
||||
&attributes,
|
||||
@@ -263,7 +242,7 @@ mod tests {
|
||||
.unwrap();
|
||||
|
||||
let aggr_vk_2 = aggregate_verification_keys(&vks[2..], Some(&[3, 4, 5])).unwrap();
|
||||
let aggr_sig2 = aggregate_signatures_and_verify(
|
||||
let aggr_sig2 = aggregate_signatures(
|
||||
¶ms,
|
||||
&aggr_vk_1,
|
||||
&attributes,
|
||||
@@ -279,7 +258,7 @@ mod tests {
|
||||
|
||||
// aggregating threshold+1 works
|
||||
let aggr_vk_more = aggregate_verification_keys(&vks[1..], Some(&[2, 3, 4, 5])).unwrap();
|
||||
let aggr_more = aggregate_signatures_and_verify(
|
||||
let aggr_more = aggregate_signatures(
|
||||
¶ms,
|
||||
&aggr_vk_more,
|
||||
&attributes,
|
||||
@@ -291,7 +270,7 @@ mod tests {
|
||||
|
||||
// aggregating all
|
||||
let aggr_vk_all = aggregate_verification_keys(&vks, Some(&[1, 2, 3, 4, 5])).unwrap();
|
||||
let aggr_all = aggregate_signatures_and_verify(
|
||||
let aggr_all = aggregate_signatures(
|
||||
¶ms,
|
||||
&aggr_vk_all,
|
||||
&attributes,
|
||||
@@ -303,7 +282,7 @@ mod tests {
|
||||
|
||||
// not taking enough points (threshold was 3) should fail
|
||||
let aggr_vk_not_enough = aggregate_verification_keys(&vks[..2], Some(&[1, 2])).unwrap();
|
||||
let aggr_not_enough = aggregate_signatures_and_verify(
|
||||
let aggr_not_enough = aggregate_signatures(
|
||||
¶ms,
|
||||
&aggr_vk_not_enough,
|
||||
&attributes,
|
||||
@@ -315,7 +294,7 @@ mod tests {
|
||||
|
||||
// taking wrong index should fail
|
||||
let aggr_vk_bad = aggregate_verification_keys(&vks[2..], Some(&[1, 2, 3])).unwrap();
|
||||
assert!(aggregate_signatures_and_verify(
|
||||
assert!(aggregate_signatures(
|
||||
¶ms,
|
||||
&aggr_vk_bad,
|
||||
&attributes,
|
||||
@@ -351,14 +330,9 @@ mod tests {
|
||||
.unzip();
|
||||
|
||||
let aggr_vk_all = aggregate_verification_keys(&vks, None).unwrap();
|
||||
assert!(aggregate_signatures_and_verify(
|
||||
¶ms,
|
||||
&aggr_vk_all,
|
||||
&attributes,
|
||||
&signatures,
|
||||
None
|
||||
)
|
||||
.is_err());
|
||||
assert!(
|
||||
aggregate_signatures(¶ms, &aggr_vk_all, &attributes, &signatures, None).is_err()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -378,15 +352,11 @@ mod tests {
|
||||
.unzip();
|
||||
let aggr_vk_all = aggregate_verification_keys(&vks, None).unwrap();
|
||||
|
||||
assert!(aggregate_signatures_and_verify(
|
||||
¶ms,
|
||||
&aggr_vk_all,
|
||||
&attributes,
|
||||
&signatures,
|
||||
Some(&[])
|
||||
)
|
||||
.is_err());
|
||||
assert!(aggregate_signatures_and_verify(
|
||||
assert!(
|
||||
aggregate_signatures(¶ms, &aggr_vk_all, &attributes, &signatures, Some(&[]))
|
||||
.is_err()
|
||||
);
|
||||
assert!(aggregate_signatures(
|
||||
¶ms,
|
||||
&aggr_vk_all,
|
||||
&attributes,
|
||||
@@ -413,7 +383,7 @@ mod tests {
|
||||
.unzip();
|
||||
let aggr_vk_all = aggregate_verification_keys(&vks, None).unwrap();
|
||||
|
||||
assert!(aggregate_signatures_and_verify(
|
||||
assert!(aggregate_signatures(
|
||||
¶ms,
|
||||
&aggr_vk_all,
|
||||
&attributes,
|
||||
|
||||
@@ -13,8 +13,9 @@ use crate::scheme::setup::Parameters;
|
||||
use crate::scheme::BlindedSignature;
|
||||
use crate::scheme::SecretKey;
|
||||
use crate::Attribute;
|
||||
/// Creates a Coconut Signature under a given secret key on a set of public attributes only.
|
||||
#[cfg(test)]
|
||||
use crate::Signature;
|
||||
|
||||
// TODO: possibly completely remove those two functions.
|
||||
// They only exist to have a simpler and smaller code snippets to test
|
||||
// basic functionalities.
|
||||
@@ -157,10 +158,6 @@ impl BlindSignRequest {
|
||||
)
|
||||
}
|
||||
|
||||
pub fn verify_commitment_hash(&self, public_attributes: &[&Attribute]) -> bool {
|
||||
self.commitment_hash == compute_hash(self.commitment, public_attributes)
|
||||
}
|
||||
|
||||
pub fn get_commitment_hash(&self) -> G1Projective {
|
||||
self.commitment_hash
|
||||
}
|
||||
@@ -429,9 +426,9 @@ pub fn verify_partial_blind_signature(
|
||||
.into()
|
||||
}
|
||||
|
||||
/// Creates a Coconut Signature under a given secret key on a set of public attributes only.
|
||||
#[cfg(test)]
|
||||
pub fn sign(
|
||||
params: &Parameters,
|
||||
params: &mut Parameters,
|
||||
secret_key: &SecretKey,
|
||||
public_attributes: &[&Attribute],
|
||||
) -> Result<Signature> {
|
||||
|
||||
@@ -151,6 +151,10 @@ impl Base58 for SecretKey {}
|
||||
// TODO: perhaps change points to affine representation
|
||||
// to make verification slightly more efficient?
|
||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||
#[cfg_attr(
|
||||
feature = "key-zeroize",
|
||||
derive(zeroize::Zeroize, zeroize::ZeroizeOnDrop)
|
||||
)]
|
||||
pub struct VerificationKey {
|
||||
// TODO add gen2 as per the paper or imply it from the fact library is using bls381?
|
||||
pub(crate) alpha: G2Projective,
|
||||
@@ -407,23 +411,12 @@ impl Bytable for VerificationKey {
|
||||
|
||||
impl Base58 for VerificationKey {}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct VerificationKeyShare {
|
||||
pub key: VerificationKey,
|
||||
pub index: SignerIndex,
|
||||
}
|
||||
|
||||
impl From<(VerificationKey, SignerIndex)> for VerificationKeyShare {
|
||||
fn from(value: (VerificationKey, SignerIndex)) -> Self {
|
||||
VerificationKeyShare {
|
||||
key: value.0,
|
||||
index: value.1,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[cfg_attr(test, derive(PartialEq, Eq, Clone))]
|
||||
#[cfg_attr(
|
||||
feature = "key-zeroize",
|
||||
derive(zeroize::Zeroize, zeroize::ZeroizeOnDrop)
|
||||
)]
|
||||
pub struct KeyPair {
|
||||
secret_key: SecretKey,
|
||||
verification_key: VerificationKey,
|
||||
@@ -432,12 +425,6 @@ pub struct KeyPair {
|
||||
pub index: Option<SignerIndex>,
|
||||
}
|
||||
|
||||
impl From<KeyPair> for (SecretKey, VerificationKey) {
|
||||
fn from(value: KeyPair) -> Self {
|
||||
(value.secret_key, value.verification_key)
|
||||
}
|
||||
}
|
||||
|
||||
impl PemStorableKeyPair for KeyPair {
|
||||
type PrivatePemKey = SecretKey;
|
||||
type PublicPemKey = VerificationKey;
|
||||
@@ -474,13 +461,6 @@ impl KeyPair {
|
||||
&self.verification_key
|
||||
}
|
||||
|
||||
pub fn to_verification_key_share(&self) -> Option<VerificationKeyShare> {
|
||||
self.index.map(|index| VerificationKeyShare {
|
||||
key: self.verification_key.clone(),
|
||||
index,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn to_bytes(&self) -> Vec<u8> {
|
||||
// Schema is coconutkeypair[14]|secret_key_len[8]|secret_key[secret_key_len]|verification_key_len[8]|verification_key[verification_key_len]|signer_index[8] - optional
|
||||
self.to_byte_vec()
|
||||
|
||||
@@ -70,11 +70,6 @@ impl Signature {
|
||||
&self.1
|
||||
}
|
||||
|
||||
pub fn randomise_simple(&self, params: &Parameters) -> Signature {
|
||||
let r = params.random_scalar();
|
||||
Signature(self.0 * r, self.1 * r)
|
||||
}
|
||||
|
||||
pub fn randomise(&self, params: &Parameters) -> (Signature, Scalar) {
|
||||
let r = params.random_scalar();
|
||||
let r_prime = params.random_scalar();
|
||||
@@ -196,7 +191,7 @@ impl BlindedSignature {
|
||||
&self,
|
||||
partial_verification_key: &VerificationKey,
|
||||
pedersen_commitments_openings: &[Scalar],
|
||||
) -> Signature {
|
||||
) -> Result<Signature> {
|
||||
// parse the signature
|
||||
let h = &self.0;
|
||||
let c = &self.1;
|
||||
@@ -209,7 +204,7 @@ impl BlindedSignature {
|
||||
|
||||
let unblinded_c = c - blinding_removers;
|
||||
|
||||
Signature(*h, unblinded_c)
|
||||
Ok(Signature(*h, unblinded_c))
|
||||
}
|
||||
|
||||
pub fn unblind_and_verify(
|
||||
@@ -221,7 +216,7 @@ impl BlindedSignature {
|
||||
commitment_hash: &G1Projective,
|
||||
pedersen_commitments_openings: &[Scalar],
|
||||
) -> Result<Signature> {
|
||||
let unblinded = self.unblind(partial_verification_key, pedersen_commitments_openings);
|
||||
let unblinded = self.unblind(partial_verification_key, pedersen_commitments_openings)?;
|
||||
unblinded.verify(
|
||||
params,
|
||||
partial_verification_key,
|
||||
@@ -245,7 +240,6 @@ impl BlindedSignature {
|
||||
}
|
||||
|
||||
// perhaps this should take signature by reference? we'll see how it goes
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct SignatureShare {
|
||||
signature: Signature,
|
||||
index: SignerIndex,
|
||||
@@ -282,9 +276,7 @@ impl SignatureShare {
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::hash_to_scalar;
|
||||
use crate::scheme::aggregation::{
|
||||
aggregate_signatures_and_verify, aggregate_verification_keys,
|
||||
};
|
||||
use crate::scheme::aggregation::{aggregate_signatures, aggregate_verification_keys};
|
||||
use crate::scheme::issuance::{blind_sign, compute_hash, prepare_blind_sign, sign};
|
||||
use crate::scheme::keygen::{keygen, ttp_keygen};
|
||||
use crate::scheme::verification::{prove_bandwidth_credential, verify, verify_credential};
|
||||
@@ -426,13 +418,13 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn verification_on_two_public_attributes() {
|
||||
let params = Parameters::new(2).unwrap();
|
||||
let mut params = Parameters::new(2).unwrap();
|
||||
random_scalars_refs!(attributes, params, 2);
|
||||
|
||||
let keypair1 = keygen(¶ms);
|
||||
let keypair2 = keygen(¶ms);
|
||||
let sig1 = sign(¶ms, keypair1.secret_key(), &attributes).unwrap();
|
||||
let sig2 = sign(¶ms, keypair2.secret_key(), &attributes).unwrap();
|
||||
let sig1 = sign(&mut params, keypair1.secret_key(), &attributes).unwrap();
|
||||
let sig2 = sign(&mut params, keypair2.secret_key(), &attributes).unwrap();
|
||||
|
||||
assert!(verify(
|
||||
¶ms,
|
||||
@@ -576,14 +568,9 @@ mod tests {
|
||||
attributes.extend_from_slice(&public_attributes);
|
||||
|
||||
let aggr_vk = aggregate_verification_keys(&vks[..2], Some(&[1, 2])).unwrap();
|
||||
let aggr_sig = aggregate_signatures_and_verify(
|
||||
¶ms,
|
||||
&aggr_vk,
|
||||
&attributes,
|
||||
&sigs[..2],
|
||||
Some(&[1, 2]),
|
||||
)
|
||||
.unwrap();
|
||||
let aggr_sig =
|
||||
aggregate_signatures(¶ms, &aggr_vk, &attributes, &sigs[..2], Some(&[1, 2]))
|
||||
.unwrap();
|
||||
|
||||
let theta = prove_bandwidth_credential(
|
||||
¶ms,
|
||||
@@ -603,14 +590,9 @@ mod tests {
|
||||
|
||||
// taking different subset of keys and credentials
|
||||
let aggr_vk = aggregate_verification_keys(&vks[1..], Some(&[2, 3])).unwrap();
|
||||
let aggr_sig = aggregate_signatures_and_verify(
|
||||
¶ms,
|
||||
&aggr_vk,
|
||||
&attributes,
|
||||
&sigs[1..],
|
||||
Some(&[2, 3]),
|
||||
)
|
||||
.unwrap();
|
||||
let aggr_sig =
|
||||
aggregate_signatures(¶ms, &aggr_vk, &attributes, &sigs[1..], Some(&[2, 3]))
|
||||
.unwrap();
|
||||
|
||||
let theta = prove_bandwidth_credential(
|
||||
¶ms,
|
||||
|
||||
@@ -10,7 +10,6 @@ use crate::error::{CoconutError, Result};
|
||||
use crate::utils::hash_g1;
|
||||
|
||||
/// System-wide parameters used for the protocol
|
||||
#[derive(Clone)]
|
||||
pub struct Parameters {
|
||||
/// Generator of the G1 group
|
||||
g1: G1Affine,
|
||||
|
||||
@@ -288,6 +288,7 @@ pub fn verify_credential(
|
||||
}
|
||||
|
||||
// Used in tests only
|
||||
#[cfg(test)]
|
||||
pub fn verify(
|
||||
params: &Parameters,
|
||||
verification_key: &VerificationKey,
|
||||
|
||||
@@ -75,12 +75,8 @@ pub fn theta_from_keys_and_attributes(
|
||||
attributes.extend_from_slice(public_attributes);
|
||||
|
||||
// Randomize credentials and generate any cryptographic material to verify them
|
||||
let signature = aggregate_signature_shares_and_verify(
|
||||
params,
|
||||
&verification_key,
|
||||
&attributes,
|
||||
&signature_shares,
|
||||
)?;
|
||||
let signature =
|
||||
aggregate_signature_shares(params, &verification_key, &attributes, &signature_shares)?;
|
||||
|
||||
// Generate cryptographic material to verify them
|
||||
let theta = prove_bandwidth_credential(
|
||||
|
||||
@@ -16,9 +16,7 @@ const_format = "0.2.32"
|
||||
cosmrs.workspace = true
|
||||
eyre = "0.6.9"
|
||||
futures.workspace = true
|
||||
humantime = "2.1.0"
|
||||
sha2 = "0.10.8"
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
sqlx = { workspace = true, features = ["runtime-tokio-rustls", "sqlite", "macros", "migrate", "time"] }
|
||||
tendermint.workspace = true
|
||||
tendermint-rpc = { workspace = true, features = ["websocket-client", "http-client"] }
|
||||
@@ -26,13 +24,13 @@ thiserror.workspace = true
|
||||
time = { workspace = true }
|
||||
tokio = { workspace = true, features = ["full"] }
|
||||
tokio-stream = "0.1.14"
|
||||
tokio-util = { version = "0.7.10", features = ["rt"] }
|
||||
tokio-util = { version = "0.7.10", features = ["rt"]}
|
||||
tracing.workspace = true
|
||||
url.workspace = true
|
||||
|
||||
|
||||
# TEMP
|
||||
#nym-bin-common = { path = "../bin-common", features = ["basic_tracing"]}
|
||||
nym-bin-common = { path = "../bin-common", features = ["basic_tracing"]}
|
||||
|
||||
|
||||
[build-dependencies]
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
# Nyxd Scraper
|
||||
|
||||
## Pruning
|
||||
|
||||
Similarly to cosmos-sdk, we incorporate pruning into our (scraped) chain data. We attempt to follow their strategies as
|
||||
closely as possible for convenience's sake. Therefore, the following are available:
|
||||
|
||||
### Strategies
|
||||
|
||||
The strategies are configured in `config.toml`, with the format `pruning = "<strategy>"` where the options are:
|
||||
|
||||
* `default`: only the last 362,880 states(approximately 3.5 weeks worth of state) are kept; pruning at 10 block
|
||||
intervals
|
||||
* `nothing`: all historic states will be saved, nothing will be deleted (i.e. archiving node)
|
||||
* `everything`: 2 latest states will be kept; pruning at 10 block intervals.
|
||||
* `custom`: allow pruning options to be manually specified through `pruning.keep_recent`, and `pruning.interval`
|
||||
|
||||
### Custom Pruning
|
||||
|
||||
These are applied if and only if the pruning strategy is `custom`:
|
||||
|
||||
* `pruning.keep_recent`: N means to keep all of the last N blocks
|
||||
* `pruning.interval`: N means to delete old block data from disk every Nth block.
|
||||
@@ -8,7 +8,6 @@ use crate::error::ScraperError;
|
||||
use crate::modules::{BlockModule, MsgModule, TxModule};
|
||||
use crate::rpc_client::RpcClient;
|
||||
use crate::storage::{persist_block, ScraperStorage};
|
||||
use crate::PruningOptions;
|
||||
use futures::StreamExt;
|
||||
use std::collections::{BTreeMap, HashSet, VecDeque};
|
||||
use std::ops::{Add, Range};
|
||||
@@ -19,10 +18,9 @@ use tokio::sync::Notify;
|
||||
use tokio::time::{interval_at, Instant};
|
||||
use tokio_stream::wrappers::UnboundedReceiverStream;
|
||||
use tokio_util::sync::CancellationToken;
|
||||
use tracing::{debug, error, info, instrument, trace, warn};
|
||||
use tracing::{debug, error, info, warn};
|
||||
|
||||
mod helpers;
|
||||
pub(crate) mod pruning;
|
||||
pub(crate) mod types;
|
||||
|
||||
const MISSING_BLOCKS_CHECK_INTERVAL: Duration = Duration::from_secs(30);
|
||||
@@ -42,11 +40,9 @@ impl PendingSync {
|
||||
}
|
||||
|
||||
pub struct BlockProcessor {
|
||||
pruning_options: PruningOptions,
|
||||
cancel: CancellationToken,
|
||||
synced: Arc<Notify>,
|
||||
last_processed_height: u32,
|
||||
last_pruned_height: u32,
|
||||
last_processed_at: Instant,
|
||||
pending_sync: PendingSync,
|
||||
queued_blocks: BTreeMap<u32, BlockToProcess>,
|
||||
@@ -66,7 +62,6 @@ pub struct BlockProcessor {
|
||||
|
||||
impl BlockProcessor {
|
||||
pub async fn new(
|
||||
pruning_options: PruningOptions,
|
||||
cancel: CancellationToken,
|
||||
synced: Arc<Notify>,
|
||||
incoming: UnboundedReceiver<BlockToProcess>,
|
||||
@@ -75,17 +70,11 @@ impl BlockProcessor {
|
||||
rpc_client: RpcClient,
|
||||
) -> Result<Self, ScraperError> {
|
||||
let last_processed = storage.get_last_processed_height().await?;
|
||||
let last_processed_height = last_processed.try_into().unwrap_or_default();
|
||||
|
||||
let last_pruned = storage.get_pruned_height().await?;
|
||||
let last_pruned_height = last_pruned.try_into().unwrap_or_default();
|
||||
|
||||
Ok(BlockProcessor {
|
||||
pruning_options,
|
||||
cancel,
|
||||
synced,
|
||||
last_processed_height,
|
||||
last_pruned_height,
|
||||
last_processed_height: last_processed.try_into().unwrap_or_default(),
|
||||
last_processed_at: Instant::now(),
|
||||
pending_sync: Default::default(),
|
||||
queued_blocks: Default::default(),
|
||||
@@ -142,17 +131,12 @@ impl BlockProcessor {
|
||||
}
|
||||
}
|
||||
|
||||
let commit_start = Instant::now();
|
||||
tx.commit()
|
||||
.await
|
||||
.map_err(|source| ScraperError::StorageTxCommitFailure { source })?;
|
||||
crate::storage::log_db_operation_time("committing processing tx", commit_start);
|
||||
|
||||
self.last_processed_height = full_info.block.header.height.value() as u32;
|
||||
self.last_processed_at = Instant::now();
|
||||
if let Err(err) = self.maybe_prune_storage().await {
|
||||
error!("failed to prune the storage: {err}");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -226,61 +210,6 @@ impl BlockProcessor {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[instrument(skip(self))]
|
||||
async fn prune_storage(&mut self) -> Result<(), ScraperError> {
|
||||
let keep_recent = self.pruning_options.strategy_keep_recent();
|
||||
let last_to_keep = self.last_processed_height - keep_recent;
|
||||
|
||||
info!(
|
||||
keep_recent,
|
||||
oldest_to_keep = last_to_keep,
|
||||
"pruning the storage"
|
||||
);
|
||||
|
||||
let lowest: u32 = self
|
||||
.storage
|
||||
.lowest_block_height()
|
||||
.await?
|
||||
.unwrap_or_default()
|
||||
.try_into()
|
||||
.unwrap_or_default();
|
||||
|
||||
let to_prune = last_to_keep.saturating_sub(lowest);
|
||||
match to_prune {
|
||||
v if v > 1000 => warn!("approximately {v} blocks worth of data will be pruned"),
|
||||
v if v > 100 => info!("approximately {v} blocks worth of data will be pruned"),
|
||||
0 => trace!("no blocks to prune"),
|
||||
v => debug!("approximately {v} blocks worth of data will be pruned"),
|
||||
}
|
||||
|
||||
if to_prune == 0 {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
self.storage
|
||||
.prune_storage(last_to_keep, self.last_processed_height)
|
||||
.await?;
|
||||
|
||||
self.last_pruned_height = self.last_processed_height;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn maybe_prune_storage(&mut self) -> Result<(), ScraperError> {
|
||||
debug!("checking for storage pruning");
|
||||
|
||||
if self.pruning_options.strategy.is_nothing() {
|
||||
trace!("the current pruning strategy is 'nothing'");
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let interval = self.pruning_options.strategy_interval();
|
||||
if self.last_pruned_height + interval <= self.last_processed_height {
|
||||
self.prune_storage().await?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn next_incoming(&mut self, block: BlockToProcess) {
|
||||
let height = block.height;
|
||||
|
||||
@@ -350,8 +279,6 @@ impl BlockProcessor {
|
||||
async fn startup_resync(&mut self) -> Result<(), ScraperError> {
|
||||
assert!(self.pending_sync.is_empty());
|
||||
|
||||
self.maybe_prune_storage().await?;
|
||||
|
||||
let latest_block = self.rpc_client.current_block_height().await? as u32;
|
||||
if latest_block > self.last_processed_height && self.last_processed_height != 0 {
|
||||
let request_range = self.last_processed_height + 1..latest_block + 1;
|
||||
|
||||
@@ -1,122 +0,0 @@
|
||||
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::error::ScraperError;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
pub const DEFAULT_PRUNING_KEEP_RECENT: u32 = 362880;
|
||||
pub const DEFAULT_PRUNING_INTERVAL: u32 = 10;
|
||||
pub const EVERYTHING_PRUNING_KEEP_RECENT: u32 = 2;
|
||||
pub const EVERYTHING_PRUNING_INTERVAL: u32 = 10;
|
||||
|
||||
/// We follow cosmos-sdk pruning strategies for convenience’s sake.
|
||||
#[derive(Debug, Default, Clone, Copy, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum PruningStrategy {
|
||||
/// 'Default' strategy defines a pruning strategy where the last 362880 heights are
|
||||
/// kept where to-be pruned heights are pruned at every 10th height.
|
||||
/// The last 362880 heights are kept(approximately 3.5 weeks worth of state) assuming the typical
|
||||
/// block time is 6s. If these values do not match the applications' requirements, use the "custom" option.
|
||||
#[default]
|
||||
Default,
|
||||
|
||||
/// 'Everything' strategy defines a pruning strategy where all committed heights are
|
||||
/// deleted, storing only the current height and last 2 states. To-be pruned heights are
|
||||
/// pruned at every 10th height.
|
||||
Everything,
|
||||
|
||||
/// 'Nothing' strategy defines a pruning strategy where all heights are kept on disk.
|
||||
Nothing,
|
||||
|
||||
/// 'Custom' strategy defines a pruning strategy where the user specifies the pruning.
|
||||
Custom,
|
||||
}
|
||||
|
||||
impl PruningStrategy {
|
||||
pub fn is_custom(&self) -> bool {
|
||||
matches!(self, PruningStrategy::Custom)
|
||||
}
|
||||
|
||||
pub fn is_nothing(&self) -> bool {
|
||||
matches!(self, PruningStrategy::Nothing)
|
||||
}
|
||||
|
||||
pub fn is_everything(&self) -> bool {
|
||||
matches!(self, PruningStrategy::Everything)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
|
||||
pub struct PruningOptions {
|
||||
/// keep_recent defines how many recent heights to keep on disk.
|
||||
pub keep_recent: u32,
|
||||
|
||||
/// interval defines the frequency of removing the pruned heights from the disk.
|
||||
pub interval: u32,
|
||||
|
||||
/// strategy defines the currently used kind of [PruningStrategy].
|
||||
pub strategy: PruningStrategy,
|
||||
}
|
||||
|
||||
impl PruningOptions {
|
||||
pub fn validate(&self) -> Result<(), ScraperError> {
|
||||
// if strategy is not set to custom, other options are meaningless since they won't be applied
|
||||
if !self.strategy.is_custom() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if self.interval == 0 {
|
||||
return Err(ScraperError::ZeroPruningInterval);
|
||||
}
|
||||
|
||||
if self.interval < EVERYTHING_PRUNING_INTERVAL {
|
||||
return Err(ScraperError::TooSmallPruningInterval {
|
||||
interval: self.interval,
|
||||
});
|
||||
}
|
||||
|
||||
if self.keep_recent < EVERYTHING_PRUNING_KEEP_RECENT {
|
||||
return Err(ScraperError::TooSmallKeepRecent {
|
||||
keep_recent: self.keep_recent,
|
||||
});
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn nothing() -> Self {
|
||||
PruningOptions {
|
||||
keep_recent: 0,
|
||||
interval: 0,
|
||||
strategy: PruningStrategy::Nothing,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn strategy_interval(&self) -> u32 {
|
||||
match self.strategy {
|
||||
PruningStrategy::Default => DEFAULT_PRUNING_INTERVAL,
|
||||
PruningStrategy::Everything => EVERYTHING_PRUNING_INTERVAL,
|
||||
PruningStrategy::Nothing => 0,
|
||||
PruningStrategy::Custom => self.interval,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn strategy_keep_recent(&self) -> u32 {
|
||||
match self.strategy {
|
||||
PruningStrategy::Default => DEFAULT_PRUNING_KEEP_RECENT,
|
||||
PruningStrategy::Everything => EVERYTHING_PRUNING_KEEP_RECENT,
|
||||
PruningStrategy::Nothing => 0,
|
||||
PruningStrategy::Custom => self.keep_recent,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for PruningOptions {
|
||||
fn default() -> Self {
|
||||
PruningOptions {
|
||||
keep_recent: DEFAULT_PRUNING_KEEP_RECENT,
|
||||
interval: DEFAULT_PRUNING_INTERVAL,
|
||||
strategy: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,6 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::block_processor::pruning::{
|
||||
EVERYTHING_PRUNING_INTERVAL, EVERYTHING_PRUNING_KEEP_RECENT,
|
||||
};
|
||||
use tendermint::Hash;
|
||||
use thiserror::Error;
|
||||
use tokio::sync::mpsc::error::SendError;
|
||||
@@ -125,15 +122,6 @@ pub enum ScraperError {
|
||||
"could not find validator information for {address}; the validator has signed a commit"
|
||||
)]
|
||||
MissingValidatorInfoCommitted { address: String },
|
||||
|
||||
#[error("pruning.interval must not be set to 0. If you want to disable pruning, select pruning.strategy = \"nothing\"")]
|
||||
ZeroPruningInterval,
|
||||
|
||||
#[error("pruning.interval must not be smaller than {}. got: {interval}. for most aggressive pruning, select pruning.strategy = \"everything\"", EVERYTHING_PRUNING_INTERVAL)]
|
||||
TooSmallPruningInterval { interval: u32 },
|
||||
|
||||
#[error("pruning.keep_recent must not be smaller than {}. got: {keep_recent}. for most aggressive pruning, select pruning.strategy = \"everything\"", EVERYTHING_PRUNING_KEEP_RECENT)]
|
||||
TooSmallKeepRecent { keep_recent: u32 },
|
||||
}
|
||||
|
||||
impl<T> From<SendError<T>> for ScraperError {
|
||||
|
||||
@@ -14,7 +14,6 @@ pub(crate) mod rpc_client;
|
||||
pub(crate) mod scraper;
|
||||
pub mod storage;
|
||||
|
||||
pub use block_processor::pruning::{PruningOptions, PruningStrategy};
|
||||
pub use modules::{BlockModule, MsgModule, TxModule};
|
||||
pub use scraper::{Config, NyxdScraper};
|
||||
pub use storage::models;
|
||||
|
||||
@@ -8,7 +8,6 @@ use crate::modules::{BlockModule, MsgModule, TxModule};
|
||||
use crate::rpc_client::RpcClient;
|
||||
use crate::scraper::subscriber::ChainSubscriber;
|
||||
use crate::storage::ScraperStorage;
|
||||
use crate::PruningOptions;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::mpsc::{channel, unbounded_channel};
|
||||
@@ -28,8 +27,6 @@ pub struct Config {
|
||||
pub rpc_url: Url,
|
||||
|
||||
pub database_path: PathBuf,
|
||||
|
||||
pub pruning_options: PruningOptions,
|
||||
}
|
||||
|
||||
pub struct NyxdScraperBuilder {
|
||||
@@ -57,7 +54,6 @@ impl NyxdScraperBuilder {
|
||||
processing_tx.clone(),
|
||||
);
|
||||
let mut block_processor = BlockProcessor::new(
|
||||
scraper.config.pruning_options,
|
||||
scraper.cancel_token.clone(),
|
||||
scraper.startup_sync.clone(),
|
||||
processing_rx,
|
||||
@@ -123,7 +119,6 @@ impl NyxdScraper {
|
||||
}
|
||||
|
||||
pub async fn new(config: Config) -> Result<Self, ScraperError> {
|
||||
config.pruning_options.validate()?;
|
||||
let storage = ScraperStorage::init(&config.database_path).await?;
|
||||
|
||||
Ok(NyxdScraper {
|
||||
@@ -165,7 +160,6 @@ impl NyxdScraper {
|
||||
processing_tx.clone(),
|
||||
);
|
||||
let block_processor = BlockProcessor::new(
|
||||
self.config.pruning_options,
|
||||
self.cancel_token.clone(),
|
||||
self.startup_sync.clone(),
|
||||
processing_rx,
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::storage::log_db_operation_time;
|
||||
use crate::storage::models::{CommitSignature, Validator};
|
||||
use sqlx::types::time::OffsetDateTime;
|
||||
use sqlx::{Executor, Sqlite};
|
||||
use tokio::time::Instant;
|
||||
use tracing::{instrument, trace};
|
||||
|
||||
#[derive(Clone)]
|
||||
@@ -27,36 +25,10 @@ impl StorageManager {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) async fn get_lowest_block(&self) -> Result<Option<i64>, sqlx::Error> {
|
||||
trace!("get_lowest_block");
|
||||
let start = Instant::now();
|
||||
|
||||
let maybe_record = sqlx::query!(
|
||||
r#"
|
||||
SELECT height
|
||||
FROM block
|
||||
ORDER BY height ASC
|
||||
LIMIT 1
|
||||
"#,
|
||||
)
|
||||
.fetch_optional(&self.connection_pool)
|
||||
.await?;
|
||||
log_db_operation_time("get_lowest_block", start);
|
||||
|
||||
if let Some(row) = maybe_record {
|
||||
Ok(row.height)
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) async fn get_first_block_height_after(
|
||||
&self,
|
||||
time: OffsetDateTime,
|
||||
) -> Result<Option<i64>, sqlx::Error> {
|
||||
trace!("get_first_block_height_after");
|
||||
let start = Instant::now();
|
||||
|
||||
let maybe_record = sqlx::query!(
|
||||
r#"
|
||||
SELECT height
|
||||
@@ -69,7 +41,6 @@ impl StorageManager {
|
||||
)
|
||||
.fetch_optional(&self.connection_pool)
|
||||
.await?;
|
||||
log_db_operation_time("get_first_block_height_after", start);
|
||||
|
||||
if let Some(row) = maybe_record {
|
||||
Ok(row.height)
|
||||
@@ -82,9 +53,6 @@ impl StorageManager {
|
||||
&self,
|
||||
time: OffsetDateTime,
|
||||
) -> Result<Option<i64>, sqlx::Error> {
|
||||
trace!("get_last_block_height_before");
|
||||
let start = Instant::now();
|
||||
|
||||
let maybe_record = sqlx::query!(
|
||||
r#"
|
||||
SELECT height
|
||||
@@ -97,7 +65,6 @@ impl StorageManager {
|
||||
)
|
||||
.fetch_optional(&self.connection_pool)
|
||||
.await?;
|
||||
log_db_operation_time("get_last_block_height_before", start);
|
||||
|
||||
if let Some(row) = maybe_record {
|
||||
Ok(row.height)
|
||||
@@ -112,9 +79,6 @@ impl StorageManager {
|
||||
start_height: i64,
|
||||
end_height: i64,
|
||||
) -> Result<i32, sqlx::Error> {
|
||||
trace!("get_signed_between");
|
||||
let start = Instant::now();
|
||||
|
||||
let count = sqlx::query!(
|
||||
r#"
|
||||
SELECT COUNT(*) as count FROM pre_commit
|
||||
@@ -130,7 +94,6 @@ impl StorageManager {
|
||||
.fetch_one(&self.connection_pool)
|
||||
.await?
|
||||
.count;
|
||||
log_db_operation_time("get_signed_between", start);
|
||||
|
||||
Ok(count)
|
||||
}
|
||||
@@ -140,10 +103,7 @@ impl StorageManager {
|
||||
consensus_address: &str,
|
||||
height: i64,
|
||||
) -> Result<Option<CommitSignature>, sqlx::Error> {
|
||||
trace!("get_precommit");
|
||||
let start = Instant::now();
|
||||
|
||||
let res = sqlx::query_as(
|
||||
sqlx::query_as(
|
||||
r#"
|
||||
SELECT * FROM pre_commit
|
||||
WHERE validator_address = ?
|
||||
@@ -153,20 +113,14 @@ impl StorageManager {
|
||||
.bind(consensus_address)
|
||||
.bind(height)
|
||||
.fetch_optional(&self.connection_pool)
|
||||
.await?;
|
||||
log_db_operation_time("get_precommit", start);
|
||||
|
||||
Ok(res)
|
||||
.await
|
||||
}
|
||||
|
||||
pub(crate) async fn get_block_validators(
|
||||
&self,
|
||||
height: i64,
|
||||
) -> Result<Vec<Validator>, sqlx::Error> {
|
||||
trace!("get_block_validators");
|
||||
let start = Instant::now();
|
||||
|
||||
let res = sqlx::query_as!(
|
||||
sqlx::query_as!(
|
||||
Validator,
|
||||
r#"
|
||||
SELECT * FROM validator
|
||||
@@ -179,28 +133,16 @@ impl StorageManager {
|
||||
height
|
||||
)
|
||||
.fetch_all(&self.connection_pool)
|
||||
.await?;
|
||||
log_db_operation_time("get_block_validators", start);
|
||||
|
||||
Ok(res)
|
||||
.await
|
||||
}
|
||||
|
||||
pub(crate) async fn get_validators(&self) -> Result<Vec<Validator>, sqlx::Error> {
|
||||
trace!("get_validators");
|
||||
let start = Instant::now();
|
||||
|
||||
let res = sqlx::query_as("SELECT * FROM validator")
|
||||
sqlx::query_as("SELECT * FROM validator")
|
||||
.fetch_all(&self.connection_pool)
|
||||
.await?;
|
||||
log_db_operation_time("get_validators", start);
|
||||
|
||||
Ok(res)
|
||||
.await
|
||||
}
|
||||
|
||||
pub(crate) async fn get_last_processed_height(&self) -> Result<i64, sqlx::Error> {
|
||||
trace!("get_last_processed_height");
|
||||
let start = Instant::now();
|
||||
|
||||
let maybe_record = sqlx::query!(
|
||||
r#"
|
||||
SELECT last_processed_height FROM metadata
|
||||
@@ -208,7 +150,6 @@ impl StorageManager {
|
||||
)
|
||||
.fetch_optional(&self.connection_pool)
|
||||
.await?;
|
||||
log_db_operation_time("get_last_processed_height", start);
|
||||
|
||||
if let Some(row) = maybe_record {
|
||||
Ok(row.last_processed_height)
|
||||
@@ -216,27 +157,6 @@ impl StorageManager {
|
||||
Ok(-1)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) async fn get_pruned_height(&self) -> Result<i64, sqlx::Error> {
|
||||
trace!("get_pruned_height");
|
||||
let start = Instant::now();
|
||||
|
||||
let maybe_record = sqlx::query!(
|
||||
r#"
|
||||
SELECT last_pruned_height FROM pruning
|
||||
"#
|
||||
)
|
||||
.fetch_optional(&self.connection_pool)
|
||||
.await?;
|
||||
|
||||
log_db_operation_time("get_pruned_height", start);
|
||||
|
||||
if let Some(row) = maybe_record {
|
||||
Ok(row.last_pruned_height)
|
||||
} else {
|
||||
Ok(-1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// make those generic over executor so that they could be performed over connection pool and a tx
|
||||
@@ -250,8 +170,7 @@ pub(crate) async fn insert_validator<'a, E>(
|
||||
where
|
||||
E: Executor<'a, Database = Sqlite>,
|
||||
{
|
||||
trace!("insert_validator");
|
||||
let start = Instant::now();
|
||||
trace!("insert validator");
|
||||
|
||||
sqlx::query!(
|
||||
r#"
|
||||
@@ -264,7 +183,6 @@ where
|
||||
)
|
||||
.execute(executor)
|
||||
.await?;
|
||||
log_db_operation_time("insert_validator", start);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -282,8 +200,7 @@ pub(crate) async fn insert_block<'a, E>(
|
||||
where
|
||||
E: Executor<'a, Database = Sqlite>,
|
||||
{
|
||||
trace!("insert_block");
|
||||
let start = Instant::now();
|
||||
trace!("insert block");
|
||||
|
||||
sqlx::query!(
|
||||
r#"
|
||||
@@ -300,7 +217,6 @@ where
|
||||
)
|
||||
.execute(executor)
|
||||
.await?;
|
||||
log_db_operation_time("insert_block", start);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -317,8 +233,7 @@ pub(crate) async fn insert_precommit<'a, E>(
|
||||
where
|
||||
E: Executor<'a, Database = Sqlite>,
|
||||
{
|
||||
trace!("insert_precommit");
|
||||
let start = Instant::now();
|
||||
trace!("insert precommit");
|
||||
|
||||
sqlx::query!(
|
||||
r#"
|
||||
@@ -334,7 +249,6 @@ where
|
||||
)
|
||||
.execute(executor)
|
||||
.await?;
|
||||
log_db_operation_time("insert_precommit", start);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -356,8 +270,7 @@ pub(crate) async fn insert_transaction<'a, E>(
|
||||
where
|
||||
E: Executor<'a, Database = Sqlite>,
|
||||
{
|
||||
trace!("insert_transaction");
|
||||
let start = Instant::now();
|
||||
trace!("insert transaction");
|
||||
|
||||
sqlx::query!(
|
||||
r#"
|
||||
@@ -385,7 +298,6 @@ where
|
||||
)
|
||||
.execute(executor)
|
||||
.await?;
|
||||
log_db_operation_time("insert_transaction", start);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -401,8 +313,7 @@ pub(crate) async fn insert_message<'a, E>(
|
||||
where
|
||||
E: Executor<'a, Database = Sqlite>,
|
||||
{
|
||||
trace!("insert_message");
|
||||
let start = Instant::now();
|
||||
trace!("insert message");
|
||||
|
||||
sqlx::query!(
|
||||
r#"
|
||||
@@ -419,7 +330,6 @@ where
|
||||
)
|
||||
.execute(executor)
|
||||
.await?;
|
||||
log_db_operation_time("insert_message", start);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -433,100 +343,10 @@ where
|
||||
E: Executor<'a, Database = Sqlite>,
|
||||
{
|
||||
trace!("update_last_processed");
|
||||
let start = Instant::now();
|
||||
|
||||
sqlx::query!("UPDATE metadata SET last_processed_height = ?", height)
|
||||
.execute(executor)
|
||||
.await?;
|
||||
log_db_operation_time("update_last_processed", start);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[instrument(skip(executor))]
|
||||
pub(crate) async fn update_last_pruned<'a, E>(height: i64, executor: E) -> Result<(), sqlx::Error>
|
||||
where
|
||||
E: Executor<'a, Database = Sqlite>,
|
||||
{
|
||||
trace!("update_last_pruned");
|
||||
let start = Instant::now();
|
||||
|
||||
sqlx::query!("UPDATE pruning SET last_pruned_height = ?", height)
|
||||
.execute(executor)
|
||||
.await?;
|
||||
log_db_operation_time("update_last_pruned", start);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) async fn prune_blocks<'a, E>(oldest_to_keep: i64, executor: E) -> Result<(), sqlx::Error>
|
||||
where
|
||||
E: Executor<'a, Database = Sqlite>,
|
||||
{
|
||||
trace!("prune_blocks");
|
||||
let start = Instant::now();
|
||||
|
||||
sqlx::query!("DELETE FROM block WHERE height < ?", oldest_to_keep)
|
||||
.execute(executor)
|
||||
.await?;
|
||||
log_db_operation_time("prune_blocks", start);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) async fn prune_pre_commits<'a, E>(
|
||||
oldest_to_keep: i64,
|
||||
executor: E,
|
||||
) -> Result<(), sqlx::Error>
|
||||
where
|
||||
E: Executor<'a, Database = Sqlite>,
|
||||
{
|
||||
trace!("prune_pre_commits");
|
||||
let start = Instant::now();
|
||||
|
||||
sqlx::query!("DELETE FROM pre_commit WHERE height < ?", oldest_to_keep)
|
||||
.execute(executor)
|
||||
.await?;
|
||||
log_db_operation_time("prune_pre_commits", start);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) async fn prune_transactions<'a, E>(
|
||||
oldest_to_keep: i64,
|
||||
executor: E,
|
||||
) -> Result<(), sqlx::Error>
|
||||
where
|
||||
E: Executor<'a, Database = Sqlite>,
|
||||
{
|
||||
trace!("prune_transactions");
|
||||
let start = Instant::now();
|
||||
|
||||
sqlx::query!(
|
||||
"DELETE FROM \"transaction\" WHERE height < ?",
|
||||
oldest_to_keep
|
||||
)
|
||||
.execute(executor)
|
||||
.await?;
|
||||
log_db_operation_time("prune_transactions", start);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) async fn prune_messages<'a, E>(
|
||||
oldest_to_keep: i64,
|
||||
executor: E,
|
||||
) -> Result<(), sqlx::Error>
|
||||
where
|
||||
E: Executor<'a, Database = Sqlite>,
|
||||
{
|
||||
trace!("prune_messages");
|
||||
let start = Instant::now();
|
||||
|
||||
sqlx::query!("DELETE FROM message WHERE height < ?", oldest_to_keep)
|
||||
.execute(executor)
|
||||
.await?;
|
||||
log_db_operation_time("prune_messages", start);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -5,8 +5,7 @@ use crate::block_processor::types::{FullBlockInformation, ParsedTransactionRespo
|
||||
use crate::error::ScraperError;
|
||||
use crate::storage::manager::{
|
||||
insert_block, insert_message, insert_precommit, insert_transaction, insert_validator,
|
||||
prune_blocks, prune_messages, prune_pre_commits, prune_transactions, update_last_processed,
|
||||
update_last_pruned, StorageManager,
|
||||
update_last_processed, StorageManager,
|
||||
};
|
||||
use crate::storage::models::{CommitSignature, Validator};
|
||||
use sqlx::types::time::OffsetDateTime;
|
||||
@@ -16,7 +15,6 @@ use std::path::Path;
|
||||
use tendermint::block::{Commit, CommitSig};
|
||||
use tendermint::Block;
|
||||
use tendermint_rpc::endpoint::validators;
|
||||
use tokio::time::Instant;
|
||||
use tracing::{debug, error, info, instrument, trace, warn};
|
||||
|
||||
mod helpers;
|
||||
@@ -30,19 +28,6 @@ pub struct ScraperStorage {
|
||||
pub(crate) manager: StorageManager,
|
||||
}
|
||||
|
||||
pub(crate) fn log_db_operation_time(op_name: &str, start_time: Instant) {
|
||||
let elapsed = start_time.elapsed();
|
||||
let formatted = humantime::format_duration(elapsed);
|
||||
|
||||
match elapsed.as_millis() {
|
||||
v if v > 10000 => error!("{op_name} took {formatted} to execute"),
|
||||
v if v > 1000 => warn!("{op_name} took {formatted} to execute"),
|
||||
v if v > 100 => info!("{op_name} took {formatted} to execute"),
|
||||
v if v > 10 => debug!("{op_name} took {formatted} to execute"),
|
||||
_ => trace!("{op_name} took {formatted} to execute"),
|
||||
}
|
||||
}
|
||||
|
||||
impl ScraperStorage {
|
||||
#[instrument]
|
||||
pub async fn init<P: AsRef<Path> + Debug>(database_path: P) -> Result<Self, ScraperError> {
|
||||
@@ -80,32 +65,6 @@ impl ScraperStorage {
|
||||
Ok(storage)
|
||||
}
|
||||
|
||||
#[instrument(skip(self))]
|
||||
pub async fn prune_storage(
|
||||
&self,
|
||||
oldest_to_keep: u32,
|
||||
current_height: u32,
|
||||
) -> Result<(), ScraperError> {
|
||||
let start = Instant::now();
|
||||
|
||||
let mut tx = self.begin_processing_tx().await?;
|
||||
|
||||
prune_messages(oldest_to_keep.into(), &mut tx).await?;
|
||||
prune_transactions(oldest_to_keep.into(), &mut tx).await?;
|
||||
prune_pre_commits(oldest_to_keep.into(), &mut tx).await?;
|
||||
prune_blocks(oldest_to_keep.into(), &mut tx).await?;
|
||||
update_last_pruned(current_height.into(), &mut tx).await?;
|
||||
|
||||
let commit_start = Instant::now();
|
||||
tx.commit()
|
||||
.await
|
||||
.map_err(|source| ScraperError::StorageTxCommitFailure { source })?;
|
||||
log_db_operation_time("committing pruning tx", commit_start);
|
||||
|
||||
log_db_operation_time("pruning storage", start);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[instrument(skip_all)]
|
||||
pub async fn begin_processing_tx(&self) -> Result<StorageTransaction, ScraperError> {
|
||||
debug!("starting storage tx");
|
||||
@@ -116,10 +75,6 @@ impl ScraperStorage {
|
||||
.map_err(|source| ScraperError::StorageTxBeginFailure { source })
|
||||
}
|
||||
|
||||
pub async fn lowest_block_height(&self) -> Result<Option<i64>, ScraperError> {
|
||||
Ok(self.manager.get_lowest_block().await?)
|
||||
}
|
||||
|
||||
pub async fn get_first_block_height_after(
|
||||
&self,
|
||||
time: OffsetDateTime,
|
||||
@@ -200,10 +155,6 @@ impl ScraperStorage {
|
||||
pub async fn get_last_processed_height(&self) -> Result<i64, ScraperError> {
|
||||
Ok(self.manager.get_last_processed_height().await?)
|
||||
}
|
||||
|
||||
pub async fn get_pruned_height(&self) -> Result<i64, ScraperError> {
|
||||
Ok(self.manager.get_pruned_height().await?)
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn persist_block(
|
||||
|
||||
@@ -474,10 +474,6 @@ impl TaskClient {
|
||||
self.mode.set_should_not_signal_on_drop();
|
||||
}
|
||||
|
||||
pub fn disarm(&mut self) {
|
||||
self.mark_as_success();
|
||||
}
|
||||
|
||||
pub fn send_we_stopped(&mut self, err: SentError) {
|
||||
if self.mode.is_dummy() {
|
||||
return;
|
||||
|
||||
@@ -205,10 +205,10 @@ impl<'a> TryFrom<&'a DescribedGateway> for Node {
|
||||
clients_ws_port: self_described.mixnet_websockets.ws_port,
|
||||
clients_wss_port: self_described.mixnet_websockets.wss_port,
|
||||
identity_key: identity::PublicKey::from_base58_string(
|
||||
&self_described.host_information.keys.ed25519,
|
||||
&self_described.host_information.keys.ed25519_identity,
|
||||
)?,
|
||||
sphinx_key: encryption::PublicKey::from_base58_string(
|
||||
&self_described.host_information.keys.x25519,
|
||||
&self_described.host_information.keys.x25519_sphinx,
|
||||
)?,
|
||||
version: self_described
|
||||
.build_information
|
||||
|
||||
@@ -159,7 +159,7 @@ impl TunDevice {
|
||||
"add",
|
||||
&format!("{}/{}", ipv6, netmaskv6),
|
||||
"dev",
|
||||
(tun.name()),
|
||||
&tun.name(),
|
||||
])
|
||||
.output()?;
|
||||
Ok(tun)
|
||||
|
||||
@@ -50,7 +50,7 @@ pub struct DelegationWithEverything {
|
||||
pub accumulated_by_delegates: Option<DecCoin>,
|
||||
pub accumulated_by_operator: Option<DecCoin>,
|
||||
pub block_height: u64,
|
||||
pub delegated_on_iso_datetime: Option<String>,
|
||||
pub delegated_on_iso_datetime: String,
|
||||
pub cost_params: Option<MixNodeCostParams>,
|
||||
pub avg_uptime_percent: Option<u8>,
|
||||
|
||||
@@ -60,8 +60,6 @@ pub struct DelegationWithEverything {
|
||||
pub uses_vesting_contract_tokens: bool,
|
||||
pub unclaimed_rewards: Option<DecCoin>,
|
||||
|
||||
pub errors: Option<String>,
|
||||
|
||||
// DEPRECATED, IF POSSIBLE TRY TO DISCONTINUE USE OF IT!
|
||||
pub pending_events: Vec<DelegationEvent>,
|
||||
pub mixnode_is_unbonding: Option<bool>,
|
||||
|
||||
@@ -37,11 +37,5 @@ wasm-utils = { path = "../utils" }
|
||||
wasm-storage = { path = "../storage" }
|
||||
|
||||
|
||||
# The `console_error_panic_hook` crate provides better debugging of panics by
|
||||
# logging them with `console.error`. This is great for development, but requires
|
||||
# all the `std::fmt` and `std::panicking` infrastructure, so isn't great for
|
||||
# code size when deploying.
|
||||
console_error_panic_hook = { version = "0.1", optional = true }
|
||||
|
||||
[features]
|
||||
default = ["console_error_panic_hook"]
|
||||
default = ["wasm-utils/console_error_panic_hook"]
|
||||
@@ -17,6 +17,12 @@ gloo-utils = { workspace = true }
|
||||
gloo-net = { version = "0.3.1", features = ["websocket"], optional = true }
|
||||
#gloo-net = { path = "../../../../gloo/crates/net", features = ["websocket"], optional = true }
|
||||
|
||||
# The `console_error_panic_hook` crate provides better debugging of panics by
|
||||
# logging them with `console.error`. This is great for development, but requires
|
||||
# all the `std::fmt` and `std::panicking` infrastructure, so isn't great for
|
||||
# code size when deploying.
|
||||
console_error_panic_hook = { workspace = true, optional = true }
|
||||
|
||||
# we don't want entire tokio-tungstenite, tungstenite itself is just fine - we just want message and error enums
|
||||
[dependencies.tungstenite]
|
||||
workspace = true
|
||||
@@ -29,6 +35,7 @@ optional = true
|
||||
|
||||
[features]
|
||||
default = ["sleep"]
|
||||
panic-hook = ["console_error_panic_hook"]
|
||||
sleep = ["web-sys", "web-sys/Window"]
|
||||
websocket = [
|
||||
"getrandom",
|
||||
|
||||
@@ -70,3 +70,15 @@ pub async fn sleep(ms: i32) -> Result<(), wasm_bindgen::JsValue> {
|
||||
js_fut.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
#[cfg(feature = "panic-hook")]
|
||||
pub fn set_panic_hook() {
|
||||
// When the `console_error_panic_hook` feature is enabled, we can call the
|
||||
// `set_panic_hook` function at least once during initialization, and then
|
||||
// we will get better error messages if our code ever panics.
|
||||
//
|
||||
// For more details see
|
||||
// https://github.com/rustwasm/console_error_panic_hook#readme
|
||||
console_error_panic_hook::set_once();
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ use futures::{Sink, Stream};
|
||||
use gloo_net::websocket::futures::WebSocket;
|
||||
use gloo_net::websocket::{Message, WebSocketError};
|
||||
use gloo_utils::errors::JsError;
|
||||
use std::fmt::{self, Formatter};
|
||||
use std::io;
|
||||
use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
@@ -78,12 +77,6 @@ impl Stream for JSWebsocket {
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for JSWebsocket {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "JSWebSocket")
|
||||
}
|
||||
}
|
||||
|
||||
impl Sink<WsMessage> for JSWebsocket {
|
||||
type Error = WsError;
|
||||
|
||||
|
||||
@@ -26,7 +26,6 @@ else
|
||||
echo "cleaning old book"
|
||||
rm -rf ./book/
|
||||
# build book
|
||||
# mdbook test || true
|
||||
mdbook build
|
||||
# check for destination, if ! then mkdir & check again else echo thumbs up
|
||||
if [ ! -d ../../dist/docs/$i ]; then
|
||||
|
||||
@@ -24,7 +24,7 @@ turn-off = false
|
||||
|
||||
[preprocessor.admonish]
|
||||
command = "mdbook-admonish"
|
||||
assets_version = "3.0.2" # do not edit: managed by `mdbook-admonish install`
|
||||
assets_version = "3.0.0" # do not edit: managed by `mdbook-admonish install`
|
||||
|
||||
# https://gitlab.com/tglman/mdbook-variables/
|
||||
[preprocessor.variables.variables]
|
||||
|
||||
@@ -1,4 +1,20 @@
|
||||
@charset "UTF-8";
|
||||
:root {
|
||||
--md-admonition-icon--admonish-note: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M20.71 7.04c.39-.39.39-1.04 0-1.41l-2.34-2.34c-.37-.39-1.02-.39-1.41 0l-1.84 1.83 3.75 3.75M3 17.25V21h3.75L17.81 9.93l-3.75-3.75L3 17.25z'/></svg>");
|
||||
--md-admonition-icon--admonish-abstract: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M17 9H7V7h10m0 6H7v-2h10m-3 6H7v-2h7M12 3a1 1 0 0 1 1 1 1 1 0 0 1-1 1 1 1 0 0 1-1-1 1 1 0 0 1 1-1m7 0h-4.18C14.4 1.84 13.3 1 12 1c-1.3 0-2.4.84-2.82 2H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V5a2 2 0 0 0-2-2z'/></svg>");
|
||||
--md-admonition-icon--admonish-info: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M13 9h-2V7h2m0 10h-2v-6h2m-1-9A10 10 0 0 0 2 12a10 10 0 0 0 10 10 10 10 0 0 0 10-10A10 10 0 0 0 12 2z'/></svg>");
|
||||
--md-admonition-icon--admonish-tip: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M17.66 11.2c-.23-.3-.51-.56-.77-.82-.67-.6-1.43-1.03-2.07-1.66C13.33 7.26 13 4.85 13.95 3c-.95.23-1.78.75-2.49 1.32-2.59 2.08-3.61 5.75-2.39 8.9.04.1.08.2.08.33 0 .22-.15.42-.35.5-.23.1-.47.04-.66-.12a.58.58 0 0 1-.14-.17c-1.13-1.43-1.31-3.48-.55-5.12C5.78 10 4.87 12.3 5 14.47c.06.5.12 1 .29 1.5.14.6.41 1.2.71 1.73 1.08 1.73 2.95 2.97 4.96 3.22 2.14.27 4.43-.12 6.07-1.6 1.83-1.66 2.47-4.32 1.53-6.6l-.13-.26c-.21-.46-.77-1.26-.77-1.26m-3.16 6.3c-.28.24-.74.5-1.1.6-1.12.4-2.24-.16-2.9-.82 1.19-.28 1.9-1.16 2.11-2.05.17-.8-.15-1.46-.28-2.23-.12-.74-.1-1.37.17-2.06.19.38.39.76.63 1.06.77 1 1.98 1.44 2.24 2.8.04.14.06.28.06.43.03.82-.33 1.72-.93 2.27z'/></svg>");
|
||||
--md-admonition-icon--admonish-success: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='m9 20.42-6.21-6.21 2.83-2.83L9 14.77l9.88-9.89 2.83 2.83L9 20.42z'/></svg>");
|
||||
--md-admonition-icon--admonish-question: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='m15.07 11.25-.9.92C13.45 12.89 13 13.5 13 15h-2v-.5c0-1.11.45-2.11 1.17-2.83l1.24-1.26c.37-.36.59-.86.59-1.41a2 2 0 0 0-2-2 2 2 0 0 0-2 2H8a4 4 0 0 1 4-4 4 4 0 0 1 4 4 3.2 3.2 0 0 1-.93 2.25M13 19h-2v-2h2M12 2A10 10 0 0 0 2 12a10 10 0 0 0 10 10 10 10 0 0 0 10-10c0-5.53-4.5-10-10-10z'/></svg>");
|
||||
--md-admonition-icon--admonish-warning: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M13 14h-2V9h2m0 9h-2v-2h2M1 21h22L12 2 1 21z'/></svg>");
|
||||
--md-admonition-icon--admonish-failure: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M20 6.91 17.09 4 12 9.09 6.91 4 4 6.91 9.09 12 4 17.09 6.91 20 12 14.91 17.09 20 20 17.09 14.91 12 20 6.91z'/></svg>");
|
||||
--md-admonition-icon--admonish-danger: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M11 15H6l7-14v8h5l-7 14v-8z'/></svg>");
|
||||
--md-admonition-icon--admonish-bug: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M14 12h-4v-2h4m0 6h-4v-2h4m6-6h-2.81a5.985 5.985 0 0 0-1.82-1.96L17 4.41 15.59 3l-2.17 2.17a6.002 6.002 0 0 0-2.83 0L8.41 3 7 4.41l1.62 1.63C7.88 6.55 7.26 7.22 6.81 8H4v2h2.09c-.05.33-.09.66-.09 1v1H4v2h2v1c0 .34.04.67.09 1H4v2h2.81c1.04 1.79 2.97 3 5.19 3s4.15-1.21 5.19-3H20v-2h-2.09c.05-.33.09-.66.09-1v-1h2v-2h-2v-1c0-.34-.04-.67-.09-1H20V8z'/></svg>");
|
||||
--md-admonition-icon--admonish-example: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M7 13v-2h14v2H7m0 6v-2h14v2H7M7 7V5h14v2H7M3 8V5H2V4h2v4H3m-1 9v-1h3v4H2v-1h2v-.5H3v-1h1V17H2m2.25-7a.75.75 0 0 1 .75.75c0 .2-.08.39-.21.52L3.12 13H5v1H2v-.92L4 11H2v-1h2.25z'/></svg>");
|
||||
--md-admonition-icon--admonish-quote: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M14 17h3l2-4V7h-6v6h3M6 17h3l2-4V7H5v6h3l-2 4z'/></svg>");
|
||||
--md-details-icon: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M8.59 16.58 13.17 12 8.59 7.41 10 6l6 6-6 6-1.41-1.42Z'/></svg>");
|
||||
}
|
||||
|
||||
:is(.admonition) {
|
||||
display: flow-root;
|
||||
margin: 1.5625em 0;
|
||||
@@ -55,8 +71,6 @@ a.admonition-anchor-link::before {
|
||||
padding-inline: 4.4rem 1.2rem;
|
||||
font-weight: 700;
|
||||
background-color: rgba(68, 138, 255, 0.1);
|
||||
print-color-adjust: exact;
|
||||
-webkit-print-color-adjust: exact;
|
||||
display: flex;
|
||||
}
|
||||
:is(.admonition-title, summary.admonition-title) p {
|
||||
@@ -72,8 +86,6 @@ html :is(.admonition-title, summary.admonition-title):last-child {
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
background-color: #448aff;
|
||||
print-color-adjust: exact;
|
||||
-webkit-print-color-adjust: exact;
|
||||
mask-image: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"></svg>');
|
||||
-webkit-mask-image: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"></svg>');
|
||||
mask-repeat: no-repeat;
|
||||
@@ -107,25 +119,6 @@ details[open].admonition > summary.admonition-title::after {
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
|
||||
:root {
|
||||
--md-details-icon: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M8.59 16.58 13.17 12 8.59 7.41 10 6l6 6-6 6-1.41-1.42Z'/></svg>");
|
||||
}
|
||||
|
||||
:root {
|
||||
--md-admonition-icon--admonish-note: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M20.71 7.04c.39-.39.39-1.04 0-1.41l-2.34-2.34c-.37-.39-1.02-.39-1.41 0l-1.84 1.83 3.75 3.75M3 17.25V21h3.75L17.81 9.93l-3.75-3.75L3 17.25z'/></svg>");
|
||||
--md-admonition-icon--admonish-abstract: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M17 9H7V7h10m0 6H7v-2h10m-3 6H7v-2h7M12 3a1 1 0 0 1 1 1 1 1 0 0 1-1 1 1 1 0 0 1-1-1 1 1 0 0 1 1-1m7 0h-4.18C14.4 1.84 13.3 1 12 1c-1.3 0-2.4.84-2.82 2H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V5a2 2 0 0 0-2-2z'/></svg>");
|
||||
--md-admonition-icon--admonish-info: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M13 9h-2V7h2m0 10h-2v-6h2m-1-9A10 10 0 0 0 2 12a10 10 0 0 0 10 10 10 10 0 0 0 10-10A10 10 0 0 0 12 2z'/></svg>");
|
||||
--md-admonition-icon--admonish-tip: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M17.66 11.2c-.23-.3-.51-.56-.77-.82-.67-.6-1.43-1.03-2.07-1.66C13.33 7.26 13 4.85 13.95 3c-.95.23-1.78.75-2.49 1.32-2.59 2.08-3.61 5.75-2.39 8.9.04.1.08.2.08.33 0 .22-.15.42-.35.5-.23.1-.47.04-.66-.12a.58.58 0 0 1-.14-.17c-1.13-1.43-1.31-3.48-.55-5.12C5.78 10 4.87 12.3 5 14.47c.06.5.12 1 .29 1.5.14.6.41 1.2.71 1.73 1.08 1.73 2.95 2.97 4.96 3.22 2.14.27 4.43-.12 6.07-1.6 1.83-1.66 2.47-4.32 1.53-6.6l-.13-.26c-.21-.46-.77-1.26-.77-1.26m-3.16 6.3c-.28.24-.74.5-1.1.6-1.12.4-2.24-.16-2.9-.82 1.19-.28 1.9-1.16 2.11-2.05.17-.8-.15-1.46-.28-2.23-.12-.74-.1-1.37.17-2.06.19.38.39.76.63 1.06.77 1 1.98 1.44 2.24 2.8.04.14.06.28.06.43.03.82-.33 1.72-.93 2.27z'/></svg>");
|
||||
--md-admonition-icon--admonish-success: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='m9 20.42-6.21-6.21 2.83-2.83L9 14.77l9.88-9.89 2.83 2.83L9 20.42z'/></svg>");
|
||||
--md-admonition-icon--admonish-question: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='m15.07 11.25-.9.92C13.45 12.89 13 13.5 13 15h-2v-.5c0-1.11.45-2.11 1.17-2.83l1.24-1.26c.37-.36.59-.86.59-1.41a2 2 0 0 0-2-2 2 2 0 0 0-2 2H8a4 4 0 0 1 4-4 4 4 0 0 1 4 4 3.2 3.2 0 0 1-.93 2.25M13 19h-2v-2h2M12 2A10 10 0 0 0 2 12a10 10 0 0 0 10 10 10 10 0 0 0 10-10c0-5.53-4.5-10-10-10z'/></svg>");
|
||||
--md-admonition-icon--admonish-warning: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M13 14h-2V9h2m0 9h-2v-2h2M1 21h22L12 2 1 21z'/></svg>");
|
||||
--md-admonition-icon--admonish-failure: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M20 6.91 17.09 4 12 9.09 6.91 4 4 6.91 9.09 12 4 17.09 6.91 20 12 14.91 17.09 20 20 17.09 14.91 12 20 6.91z'/></svg>");
|
||||
--md-admonition-icon--admonish-danger: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M11 15H6l7-14v8h5l-7 14v-8z'/></svg>");
|
||||
--md-admonition-icon--admonish-bug: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M14 12h-4v-2h4m0 6h-4v-2h4m6-6h-2.81a5.985 5.985 0 0 0-1.82-1.96L17 4.41 15.59 3l-2.17 2.17a6.002 6.002 0 0 0-2.83 0L8.41 3 7 4.41l1.62 1.63C7.88 6.55 7.26 7.22 6.81 8H4v2h2.09c-.05.33-.09.66-.09 1v1H4v2h2v1c0 .34.04.67.09 1H4v2h2.81c1.04 1.79 2.97 3 5.19 3s4.15-1.21 5.19-3H20v-2h-2.09c.05-.33.09-.66.09-1v-1h2v-2h-2v-1c0-.34-.04-.67-.09-1H20V8z'/></svg>");
|
||||
--md-admonition-icon--admonish-example: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M7 13v-2h14v2H7m0 6v-2h14v2H7M7 7V5h14v2H7M3 8V5H2V4h2v4H3m-1 9v-1h3v4H2v-1h2v-.5H3v-1h1V17H2m2.25-7a.75.75 0 0 1 .75.75c0 .2-.08.39-.21.52L3.12 13H5v1H2v-.92L4 11H2v-1h2.25z'/></svg>");
|
||||
--md-admonition-icon--admonish-quote: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M14 17h3l2-4V7h-6v6h3M6 17h3l2-4V7H5v6h3l-2 4z'/></svg>");
|
||||
}
|
||||
|
||||
:is(.admonition):is(.admonish-note) {
|
||||
border-color: #448aff;
|
||||
}
|
||||
|
||||
@@ -20,15 +20,19 @@
|
||||
# User Manuals
|
||||
|
||||
- [NymVPN alpha](nymvpn/intro.md)
|
||||
- [GUI](nymvpn/gui.md)
|
||||
- [Linux](nymvpn/gui-linux.md)
|
||||
- [MacOS](nymvpn/gui-mac.md)
|
||||
- [CLI](nymvpn/cli.md)
|
||||
|
||||
<!-- OUTDATED STUFF:
|
||||
- [Linux](nymvpn/cli-linux.md)
|
||||
- [MacOS](nymvpn/cli-mac.md)
|
||||
- [Troubleshooting](nymvpn/troubleshooting.md)
|
||||
- [NymVPN FAQ](nymvpn/faq.md)
|
||||
- [NymConnect X Monero](tutorials/monero.md)
|
||||
- [NymConnect X Matrix](tutorials/matrix.md)
|
||||
- [NymConnect X Telegram](tutorials/telegram.md)
|
||||
- [NymConnect X Electrum](tutorials/electrum.md)
|
||||
- [NymConnect X Firo wallet](tutorials/firo.md)
|
||||
-->
|
||||
|
||||
# Code Examples
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# NymVPN alpha CLI Guide
|
||||
# NymVPN alpha CLI: Guide for GNU/Linux
|
||||
|
||||
```admonish info
|
||||
NymVPN is an experimental software and it's for testing purposes only. All users testing the client are expected to sign GDPR Information Sheet and Consent Form (shared at the workshop) so we use their results to improve the client, and submit the form [*NymVPN User research*]({{nym_vpn_form_url}}) with the testing results.
|
||||
@@ -8,7 +8,7 @@ NymVPN is an experimental software and it's for testing purposes only. All users
|
||||
|
||||
> Any syntax in `<>` brackets is a user's/version unique variable. Exchange with a corresponding name without the `<>` brackets.
|
||||
|
||||
1. Open Github [releases page]({{nym_vpn_releases}}) and download the CLI latest binary for your system
|
||||
1. Open Github [releases page]({{nym_vpn_releases}}) and download the binary for Debian based Linux
|
||||
|
||||
2. Verify sha hash of your downloaded binary with the one listed on the [releases page]({{nym_vpn_releases}}). You can use a simple `shasum` command and compare strings (ie with Python) or run in the same directory the following command, exchanging `<SHA_STRING>` with the one of your binary, like in the example:
|
||||
```sh
|
||||
@@ -25,12 +25,17 @@ tar -xvf <BINARY>.tar.gz
|
||||
# tar -xvf nym-vpn-cli_<!-- cmdrun scripts/nym_vpn_cli_version.sh -->_ubuntu-22.04_x86_64.tar.gz
|
||||
```
|
||||
|
||||
4. Make executable:
|
||||
4. Make executable by running:
|
||||
```sh
|
||||
# make sure you are in the right sub-directory
|
||||
chmod u+x ./nym-vpn-cli
|
||||
```
|
||||
|
||||
5. Create Sandbox environment config file by saving [this](https://raw.githubusercontent.com/nymtech/nym/develop/envs/sandbox.env) as `sandbox.env` in the same directory as your NymVPN binaries by running:
|
||||
```sh
|
||||
curl -o sandbox.env -L https://raw.githubusercontent.com/nymtech/nym/develop/envs/sandbox.env
|
||||
```
|
||||
|
||||
## Run NymVPN
|
||||
|
||||
**For NymVPN to work, all other VPNs must be switched off!** At this alpha stage of NymVPN, the network connection (wifi) must be reconnected after or in between the testing rounds.
|
||||
@@ -42,7 +47,7 @@ Make sure your terminal is open in the same directory as your `nym-vpn-cli` bina
|
||||
```sh
|
||||
sudo ./nym-vpn-cli -c ./sandbox.env --entry-gateway-id <ENTRY_GATEWAY_ID> --exit-router-address <EXIT_ROUTER_ADDRESS> --enable-wireguard --private-key <PRIVATE_KEY> --wg-ip <WIREGUARD_IP>
|
||||
```
|
||||
3. To choose different Gateways, visit [explorer.nymtech.net/network-components/gateways](https://explorer.nymtech.net/network-components/gateways) and copy-paste an identity key of your choice
|
||||
3. To choose different Gateways, visit [nymvpn.com/en/alpha/api/gateways](https://nymvpn.com/en/alpha/api/gateways) and pick one
|
||||
4. See all possibilities in [command explanation](#cli-commands-and-options) section below
|
||||
|
||||
In case of errors, see [troubleshooting section](troubleshooting.md).
|
||||
@@ -51,16 +56,16 @@ In case of errors, see [troubleshooting section](troubleshooting.md).
|
||||
|
||||
The basic syntax of `nym-vpn-cli` is:
|
||||
```sh
|
||||
sudo ./nym-vpn-cli <--exit-router-address <EXIT_ROUTER_ADDRESS>|--exit-gateway-id <EXIT_GATEWAY_ID>|--exit-gateway-country <EXIT_GATEWAY_COUNTRY>>
|
||||
sudo ./nym-vpn-cli -c ./sandbox.env --entry-gateway-id <ENTRY_GATEWAY_ID> --exit-router-address <EXIT_ROUTER_ADDRESS> --enable-wireguard --private-key <PRIVATE_KEY> --wg-ip <WG_IP>
|
||||
```
|
||||
* To choose different Gateways, visit [nymvpn.com/en/alpha/api/gateways](https://explorer.nymtech.net/network-components/gateways)
|
||||
* To choose different Gateways, visit [nymvpn.com/en/alpha/api/gateways](https://nymvpn.com/en/alpha/api/gateways)
|
||||
* To see all possibilities run with `--help` flag:
|
||||
```sh
|
||||
./nym-vpn-cli --help
|
||||
```
|
||||
~~~admonish example collapsible=true title="Console output"
|
||||
```sh
|
||||
Usage: nym-vpn-cli [OPTIONS] <--exit-router-address <EXIT_ROUTER_ADDRESS>|--exit-gateway-id <EXIT_GATEWAY_ID>|--exit-gateway-country <EXIT_GATEWAY_COUNTRY>>
|
||||
Usage: nym-vpn-cli [OPTIONS]
|
||||
|
||||
Options:
|
||||
-c, --config-env-file <CONFIG_ENV_FILE>
|
||||
@@ -71,13 +76,11 @@ Options:
|
||||
Mixnet public ID of the entry gateway
|
||||
--entry-gateway-country <ENTRY_GATEWAY_COUNTRY>
|
||||
Auto-select entry gateway by country ISO
|
||||
--entry-gateway-low-latency
|
||||
Auto-select entry gateway by latency
|
||||
--exit-router-address <EXIT_ROUTER_ADDRESS>
|
||||
Mixnet recipient address
|
||||
--exit-gateway-id <EXIT_GATEWAY_ID>
|
||||
|
||||
--exit-gateway-country <EXIT_GATEWAY_COUNTRY>
|
||||
--exit-router-country <EXIT_ROUTER_COUNTRY>
|
||||
Mixnet recipient address
|
||||
--enable-wireguard
|
||||
Enable the wireguard traffic between the client and the entry gateway
|
||||
@@ -85,10 +88,8 @@ Options:
|
||||
Associated private key
|
||||
--wg-ip <WG_IP>
|
||||
The IP address of the wireguard interface used for the first hop to the entry gateway
|
||||
--nym-ipv4 <NYM_IPV4>
|
||||
The IPv4 address of the nym TUN device that wraps IP packets in sphinx packets
|
||||
--nym-ipv6 <NYM_IPV6>
|
||||
The IPv6 address of the nym TUN device that wraps IP packets in sphinx packets
|
||||
--nym-ip <NYM_IP>
|
||||
The IP address of the nym TUN device that wraps IP packets in sphinx packets
|
||||
--nym-mtu <NYM_MTU>
|
||||
The MTU of the nym TUN device that wraps IP packets in sphinx packets
|
||||
--disable-routing
|
||||
@@ -124,19 +125,3 @@ Here is a list of the options and their descriptions. Some are essential, some a
|
||||
- `--ip` is the IP address of the TUN device. That is the IP address of the local private network that is set up between local client and the Exit Gateway.
|
||||
- `--mtu`: The MTU of the TUN device. That is the max IP packet size of the local private network that is set up between local client and the Exit Gateway.
|
||||
- `--disable-routing`: Disable routing all traffic through the VPN TUN device.
|
||||
|
||||
## Testnet environment
|
||||
|
||||
If you want to run NymVPN CLI in Nym Sandbox environment, there are a few adjustments to be done:
|
||||
|
||||
1. Create Sandbox environment config file by saving [this](https://raw.githubusercontent.com/nymtech/nym/develop/envs/sandbox.env) as `sandbox.env` in the same directory as your NymVPN binaries by running:
|
||||
```sh
|
||||
curl -o sandbox.env -L https://raw.githubusercontent.com/nymtech/nym/develop/envs/sandbox.env
|
||||
```
|
||||
|
||||
1. Check available Gateways at [nymvpn.com/en/alpha/api/gateways](https://nymvpn.com/en/alpha/api/gateways)
|
||||
|
||||
2. Run with a flag `-c`
|
||||
```sh
|
||||
sudo ./nym-vpn-cli -c <PATH_TO>/sandbox.env <--exit-router-address <EXIT_ROUTER_ADDRESS>|--exit-gateway-id <EXIT_GATEWAY_ID>|--exit-gateway-country <EXIT_GATEWAY_COUNTRY>>
|
||||
```
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
# NymVPN Command Line Interface (CLI)
|
||||
|
||||
```admonish info
|
||||
Our alpha testing round is done with participants at live workshop events. This guide will not work for everyone, as the NymVPN source code is not yet publicly accessible. The alpha testing is done on Nym testnet Sandbox environment, this configuration is limited and will not work in the future.
|
||||
|
||||
**If you commit to test NymVPN alpha, please start with the [user research form]({{nym_vpn_form_url}}) where all the steps will be provided**. If you disagree with any of the conditions listed, please leave this page.
|
||||
```
|
||||
|
||||
Follow the simple [automated script](#automated-script-for-cli-installation) below to install and run NymVPN CLI. If you prefer to do a manual setup follow the steps in the guide for [Linux](cli-linux.md) or [MacOS](cli-mac.md).
|
||||
|
||||
Visit NymVPN alpha latest [release page]({{nym_vpn_releases}}) to check sha sums or download the binaries directly.
|
||||
|
||||
## Automated Script for CLI Installation
|
||||
|
||||
We wrote a [script](https://gist.github.com/serinko/d65450653d6bbafacbcee71c9cb8fb31) which does download of the CLI, sha256 verification, extraction, installation and configuration for Linux and MacOS users automatically following the steps below:
|
||||
|
||||
1. Open a terminal window in a directory where you want the script and NymVPN CLI binary be downloaded and run
|
||||
```sh
|
||||
curl -o execute-nym-vpn-cli-binary.sh -L https://gist.githubusercontent.com/tommyv1987/87267ded27e1eb7651aa9cc745ddf4af/raw/d39f98dbb36ccff761a7e940073388a6fe7b73fe/execute-nym-vpn-cli-binary.sh && chmod u+x execute-nym-vpn-cli-binary.sh && sudo -E ./execute-nym-vpn-cli-binary.sh
|
||||
```
|
||||
|
||||
2. Follow the prompts in the program
|
||||
|
||||
3. The script will automatically start the client. Make sure to **turn off any other VPNs** and follow the prompts:
|
||||
|
||||
* It prints a JSON view of existing Gateways and prompt you to:
|
||||
- *Make sure to use two different Gateways for entry and exit!*
|
||||
- `enter a gateway ID:` paste one of the values labeled with a key `"identityKey"` printed above (without `" "`)
|
||||
- `enter an exit address:` paste one of the values labeled with a key `"address"` printed above (without `" "`)
|
||||
- `do you want five hop or two hop?`: type `five` or `two`
|
||||
- `enable WireGuard? (yes/no):` if you chose yes, find your private key and wireguard IP [here](https://nymvpn.com/en/alpha)
|
||||
|
||||
To run `nym-vpn-cli` again, reconnect your wifi, move to the directory of your CLI binary `cd ~/nym-vpn-cli-dir` and follow the guide for [Linux](cli-linux.md#run-nymvpn) or [MacOS](cli-mac.md#run-nymvpn). If you find it too difficult, just run this script again - like in step \#3 above.
|
||||
|
||||
In case of errors check out the [troubleshooting](troubleshooting.md) section.
|
||||
@@ -1,177 +1,35 @@
|
||||
# NymVPN CLI Guide
|
||||
# NymVPN Command Line Interface (CLI)
|
||||
|
||||
```admonish info
|
||||
NymVPN is an experimental software and it's for testing purposes only. Anyone can submit a registration to the private alpha round on [nymvpn.com](https://nymvpn.com/en).
|
||||
Our alpha testing round is done with participants at live workshop events. This guide will not work for everyone, as the NymVPN source code is not yet publicly accessible. The alpha testing is done on Nym testnet Sandbox environment, this configuration is limited and will not work in the future.
|
||||
|
||||
**If you commit to test NymVPN alpha, please start with the [user research form]({{nym_vpn_form_url}}) where all the steps will be provided**. If you disagree with any of the conditions listed, please leave this page.
|
||||
```
|
||||
|
||||
## Overview
|
||||
Follow the simple [automated script](#automated-script-for-cli-installation) below to install and run NymVPN CLI. If you prefer to do a manual setup follow the steps in the guide for [Linux](cli-linux.md) or [MacOS](cli-mac.md).
|
||||
|
||||
The core binaries consist of:
|
||||
Visit NymVPN alpha latest [release page]({{nym_vpn_releases}}) to check sha sums or download the binaries directly.
|
||||
|
||||
- **`nym-vpn-cli`**: Basic commandline client for running the vpn. This runs in the foreground.
|
||||
## Automated Script for CLI Installation
|
||||
|
||||
- **`nym-vpnd`**: Daemon implementation of the vpn client that can run in the background and interacted with using `nym-vpnc`.
|
||||
We wrote a [script](https://gist.github.com/serinko/d65450653d6bbafacbcee71c9cb8fb31) which does download of the CLI, sha256 verification, extraction, installation and configuration for Linux and MacOS users automatically following the steps below:
|
||||
|
||||
- **`nym-vpnc`**: The commandline client used to interact with `nym-vpnd`.
|
||||
|
||||
|
||||
## Installation
|
||||
|
||||
> Any syntax in `<>` brackets is a user's/version unique variable. Exchange with a corresponding name without the `<>` brackets.
|
||||
|
||||
1. Open Github [releases page]({{nym_vpn_releases}}) and download the CLI latest binary for your system
|
||||
|
||||
2. Verify sha hash of your downloaded binary with the one listed on the [releases page]({{nym_vpn_releases}}). You can use a simple `shasum` command and compare strings (ie with Python) or run in the same directory the following command, exchanging `<SHA_STRING>` with the one of your binary, like in the example:
|
||||
1. Open a terminal window in a directory where you want the script and NymVPN CLI binary be downloaded and run
|
||||
```sh
|
||||
echo "<SHA_STRING>" | shasum -a 256 -c
|
||||
|
||||
# choose a correct one according to your binary, this is just an example
|
||||
# echo "0e4abb461e86b2c168577e0294112a3bacd3a24bf8565b49783bfebd9b530e23 nym-vpn-cli_<!-- cmdrun ../../../scripts/cmdrun/nym_vpn_cli_version.sh -->_ubuntu-22.04_amd64.tar.gz" | shasum -a 256 -c
|
||||
curl -o execute-nym-vpn-cli-binary.sh -L https://gist.githubusercontent.com/tommyv1987/87267ded27e1eb7651aa9cc745ddf4af/raw/d39f98dbb36ccff761a7e940073388a6fe7b73fe/execute-nym-vpn-cli-binary.sh && chmod u+x execute-nym-vpn-cli-binary.sh && sudo -E ./execute-nym-vpn-cli-binary.sh
|
||||
```
|
||||
|
||||
3. Extract files:
|
||||
```sh
|
||||
tar -xvf <BINARY>.tar.gz
|
||||
# for example
|
||||
# tar -xvf nym-vpn-cli_<!-- cmdrun ../../../scripts/cmdrun/nym_vpn_cli_version.sh -->_ubuntu-22.04_x86_64.tar.gz
|
||||
```
|
||||
2. Follow the prompts in the program
|
||||
|
||||
## Running
|
||||
3. The script will automatically start the client. Make sure to **turn off any other VPNs** and follow the prompts:
|
||||
|
||||
If you are running Debian/Ubuntu/PopOS or any other distributio supporting debian packages and systemd, see the [relevant section below](#debian-package-for-debianubuntupopos).
|
||||
* It prints a JSON view of existing Gateways and prompt you to:
|
||||
- *Make sure to use two different Gateways for entry and exit!*
|
||||
- `enter a gateway ID:` paste one of the values labeled with a key `"identityKey"` printed above (without `" "`)
|
||||
- `enter an exit address:` paste one of the values labeled with a key `"address"` printed above (without `" "`)
|
||||
- `do you want five hop or two hop?`: type `five` or `two`
|
||||
- `enable WireGuard? (yes/no):` if you chose yes, find your private key and wireguard IP [here](https://nymvpn.com/en/alpha)
|
||||
|
||||
### Daemon
|
||||
To run `nym-vpn-cli` again, reconnect your wifi, move to the directory of your CLI binary `cd ~/nym-vpn-cli-dir` and follow the guide for [Linux](cli-linux.md#run-nymvpn) or [MacOS](cli-mac.md#run-nymvpn). If you find it too difficult, just run this script again - like in step \#3 above.
|
||||
|
||||
Start the daemon with
|
||||
|
||||
```sh
|
||||
sudo -E ./nym-vpnd
|
||||
```
|
||||
|
||||
Then run
|
||||
|
||||
```sh
|
||||
./nym-vpnc status
|
||||
./nym-vpnc connect
|
||||
./nym-vpnc disconnect
|
||||
```
|
||||
|
||||
### CLI
|
||||
|
||||
An alternative to the daemon is to run the `nym-vpn-cli` commandline client that runs in the foreground.
|
||||
```sh
|
||||
./nym-vpn-cli run
|
||||
```
|
||||
|
||||
## Credentials
|
||||
|
||||
NymVPN uses [zkNym bandwidth credentials](https://nymtech.net/docs/bandwidth-credentials.html). Those can be imported as a file or base58 encoded string.
|
||||
|
||||
|
||||
```sh
|
||||
sudo -E ./nym-vpn-cli import-credential --credential-path </PATH/TO/freepass.nym>
|
||||
sudo -E ./nym-vpn-cli import-credential --credential-data "<STRING>"
|
||||
```
|
||||
|
||||
## Debian package for Debian/Ubuntu/PopOS
|
||||
|
||||
For linux platforms using deb packages and systemd, there are also debian packages.
|
||||
|
||||
```sh
|
||||
sudo apt install ./nym-vpnd_<!-- cmdrun ../../../scripts/cmdrun/nym_vpn_cli_version.sh -->-1_amd64.deb ./nym-vpnc_<!-- cmdrun ../../../scripts/cmdrun/nym_vpn_cli_version.sh -->-1_amd64.deb
|
||||
|
||||
# In case of error please substitute the correct version
|
||||
```
|
||||
|
||||
Installing the `nym-vpnd` deb package starts a `nym-vpnd.service`. Check that the daemon is running with
|
||||
```sh
|
||||
systemctl status nym-vpnd.service
|
||||
```
|
||||
and check its logs with
|
||||
```sh
|
||||
sudo journalctl -u nym-vpnd.service -f
|
||||
```
|
||||
To stop the background service
|
||||
```sh
|
||||
systemctl stop nym-vpnd.service
|
||||
```
|
||||
It will start again on startup, so disable with
|
||||
```sh
|
||||
systemctl disable nym-vpnd.service
|
||||
```
|
||||
|
||||
Interact with it with `nym-vpnc`
|
||||
```sh
|
||||
nym-vpnc status
|
||||
nym-vpnc connect
|
||||
nym-vpnc disconnect
|
||||
```
|
||||
|
||||
## Commands & Options
|
||||
|
||||
```admonish note
|
||||
Nym Exit Gateway functionality was implemented just recently and not all the Gateways are upgraded and ready to handle the VPN connections. If you want to make sure you are connecting to a Gateway with an embedded Network Requester, IP Packet Router and applied Nym exit policy, visit [harbourmaster.nymtech.net](https://harbourmaster.nymtech.net/) and search Gateways with all the functionalities enabled.
|
||||
```
|
||||
|
||||
The basic syntax of `nym-vpn-cli` is:
|
||||
```sh
|
||||
# choose only one conditional --argument listed in {brackets}
|
||||
sudo ./nym-vpn-cli { --exit-router-address <EXIT_ROUTER_ADDRESS>|--exit-gateway-id <EXIT_GATEWAY_ID>|--exit-gateway-country <EXIT_GATEWAY_COUNTRY> }
|
||||
```
|
||||
|
||||
To see all the possibilities run with `--help` flag:
|
||||
```sh
|
||||
./nym-vpn-cli --help
|
||||
```
|
||||
~~~admonish example collapsible=true title="Console output"
|
||||
```sh
|
||||
Usage: nym-vpn-cli [OPTIONS] <COMMAND>
|
||||
|
||||
Commands:
|
||||
run Run the client
|
||||
import-credential Import credential
|
||||
help Print this message or the help of the given subcommand(s)
|
||||
|
||||
Options:
|
||||
-c, --config-env-file <CONFIG_ENV_FILE> Path pointing to an env file describing the network
|
||||
--data-path <DATA_PATH> Path to the data directory of the mixnet client
|
||||
-h, --help Print help
|
||||
-V, --version Print version
|
||||
```
|
||||
~~~
|
||||
|
||||
Here is a list of the options and their descriptions. Some are essential, some are more technical and not needed to be adjusted by users.
|
||||
|
||||
**Fundamental commands and arguments**
|
||||
|
||||
- `--entry-gateway-id`: paste one of the values labeled with a key `"identityKey"` (without `" "`)
|
||||
- `--exit-gateway-id`: paste one of the values labeled with a key `"identityKey"` (without `" "`)
|
||||
- `--exit-router-address`: paste one of the values labeled with a key `"address"` (without `" "`)
|
||||
- `--enable-wireguard`: Enable the wireguard traffic between the client and the entry gateway. NymVPN uses Mullvad libraries for wrapping `wireguard-go` and to setup local routing rules to route all traffic to the TUN virtual network device
|
||||
- `--wg-ip`: The address of the wireguard interface, you can get it [here](https://nymvpn.com/en/alpha)
|
||||
- `--private-key`: get your private key for testing purposes [here](https://nymvpn.com/en/alpha)
|
||||
- `--enable-two-hop` is a faster setup where the traffic is routed from the client to Entry Gateway and directly to Exit Gateway (default is 5-hops)
|
||||
|
||||
**Advanced options**
|
||||
|
||||
- `-c` is a path to an enviroment config, like [`sandbox.env`](https://raw.githubusercontent.com/nymtech/nym/develop/envs/sandbox.env)
|
||||
- `--enable-poisson`: Enables process rate limiting of outbound traffic (disabled by default). It means that NymVPN client will send packets at a steady stream to the Entry Gateway. By default it's on average one sphinx packet per 20ms, but there is some randomness (poisson distribution). When there are no real data to fill the sphinx packets with, cover packets are generated instead.
|
||||
- `--ip` is the IP address of the TUN device. That is the IP address of the local private network that is set up between local client and the Exit Gateway.
|
||||
- `--mtu`: The MTU of the TUN device. That is the max IP packet size of the local private network that is set up between local client and the Exit Gateway.
|
||||
- `--disable-routing`: Disable routing all traffic through the VPN TUN device.
|
||||
|
||||
## Testnet environment
|
||||
|
||||
If you want to run NymVPN CLI in Nym Sandbox environment, there are a few adjustments to be done:
|
||||
|
||||
1. Create Sandbox environment config file by saving [this](https://raw.githubusercontent.com/nymtech/nym/develop/envs/sandbox.env) as `sandbox.env` in the same directory as your NymVPN binaries:
|
||||
```sh
|
||||
curl -o sandbox.env -L https://raw.githubusercontent.com/nymtech/nym/develop/envs/sandbox.env
|
||||
```
|
||||
|
||||
2. Check available Gateways at [nymvpn.com/en/alpha/api/gateways](https://nymvpn.com/en/alpha/api/gateways)
|
||||
|
||||
3. Run with a flag `-c`
|
||||
```sh
|
||||
sudo ./nym-vpn-cli -c <PATH_TO>/sandbox.env <--exit-router-address <EXIT_ROUTER_ADDRESS>|--exit-gateway-id <EXIT_GATEWAY_ID>|--exit-gateway-country <EXIT_GATEWAY_COUNTRY>>
|
||||
```
|
||||
In case of errors check out the [troubleshooting](troubleshooting.md) section.
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
# NymVPN - Desktop (GUI)
|
||||
|
||||
```admonish info
|
||||
Our alpha testing round is done with participants at live workshop events and the application in this stage may not work for everyone.
|
||||
Our alpha testing round is done with participants at live workshop events. This guide will not work for everyone, as the NymVPN source code is not yet publicly accessible. The alpha testing is done on Nym testnet Sandbox environment, this configuration is limited and will not work in the future.
|
||||
|
||||
**If you commit to test NymVPN alpha, please start with the [user research form]({{nym_vpn_form_url}}) where all the steps will be provided**. If you disagree with any of the conditions listed, please leave this page.
|
||||
```
|
||||
|
||||
This is a desktop (GUI) version of NymVPN client. A demo of how the application will look like for majority of day-to-day users.
|
||||
This is the alpha version of NymVPN desktop application (GUI). A demo of how the client will look like for majority of day-to-day users.
|
||||
|
||||
Follow the simple [automated script](#automated-script-for-gui-installation) below to install and run NymVPN GUI. If the script didn't work for your distribution or you prefer to do a manual setup follow the steps in the guide for [Linux](gui-linux.md) or [MacOS](gui-mac.md) .
|
||||
|
||||
@@ -14,12 +14,12 @@ Visit NymVPN alpha latest [release page]({{nym_vpn_releases}}) to check sha sums
|
||||
|
||||
## Linux AppImage Automated Installation Method
|
||||
|
||||
The latest releases contain `appimage.sh` script. This method makes the installation simple for Linux users who want to run NymVPN from AppImmage. Executing the command below will download the binary to `~/.local/bin` and verify the checksum:
|
||||
The latest releases contain `appimage.sh` script. This method makes the installation simple for Linux users who want to run NymVPN from AppImmage. Executing the command below will download the binary to `~/.local/bin` and verify the checksum.
|
||||
```sh
|
||||
curl -fsSL https://github.com/nymtech/nym-vpn-client/releases/download/nym-vpn-desktop-v<!-- cmdrun scripts/nym_vpn_desktop_version.sh -->/appimage.sh | bash
|
||||
```
|
||||
|
||||
Run with the command:
|
||||
Run with the command
|
||||
```sh
|
||||
sudo -E ~/.local/bin/nym-vpn.appimage
|
||||
```
|
||||
|
||||
@@ -2,12 +2,21 @@
|
||||
|
||||
<div style="padding:56.25% 0 0 0;position:relative;"><iframe src="https://player.vimeo.com/video/897010658?h=1f55870fe6&badge=0&autopause=0&player_id=0&app_id=58479" frameborder="0" allow="autoplay; fullscreen; picture-in-picture" style="position:absolute;top:0;left:0;width:100%;height:100%;" title="NYMVPN alpha demo 37C3"></iframe></div><script src="https://player.vimeo.com/api/player.js"></script>
|
||||
|
||||
**NymVPN alpha** is a client that uses [Nym Mixnet](https://nymtech.net) to anonymise all of a user's internet traffic through either a 5-hop mixnet (for a full network privacy) or the faster 2-hop decentralised VPN (with some extra features).
|
||||
**Nym proudly presents NymVPN alpha** - a client that uses [Nym Mixnet](https://nymtech.net) to anonymise all of a user's internet traffic through either a 5-hop mixnet (for a full network privacy) or the faster 2-hop decentralised VPN (with some extra features).
|
||||
|
||||
|
||||
**You are invited to take part in the alpha testing** of this new application. Register for private testing round at [nymvpn.com](https://nymvpn.com/en), that will grant you access to the [download page](https://nymvpn.com/download). Visit [NymVPN Support & FAQ](https://nymvpn.com/en/support) or join the [NymVPN matrix channel](https://matrix.to/#/#NymVPN:nymtech.chat) if you have any questions, comments or blockers.
|
||||
**You are invited to take part in the alpha testing** of this new application. The following pages provide a how-to guide, explaining steps to install and run NymVPN [CLI](cli.md) and [GUI](gui.md) on the Sandbox testnet environment.
|
||||
|
||||
Checkout the [release page](https://github.com/nymtech/nym-vpn-client/releases) for available binaries.
|
||||
**Here is how**
|
||||
|
||||
1. Go to the NymVPN [testers form]({{nym_vpn_form_url}})
|
||||
2. Please consent to the GDPR so we can use the results
|
||||
3. To test the GUI, [go here](gui.md)
|
||||
4. To test the CLI, [go here](cli.md)
|
||||
5. Fill and submit the [form!]({{nym_vpn_form_url}})
|
||||
6. Join the [NymVPN matrix channel](https://matrix.to/#/#NymVPN:nymtech.chat) if you have any questions, comments or blockers
|
||||
|
||||
***NymVPN alpha testing will last from 15th of January - 15th of February.***
|
||||
|
||||
*NOTE: NymVPN alpha is experimental software for testing purposes only.*
|
||||
|
||||
@@ -28,7 +37,16 @@ client ───► Gateway ──┘ mix │ mix ┌─►mix ───►
|
||||
mix └─►mix──┘ mix
|
||||
```
|
||||
|
||||
Users can switch to 2-hop only mode, which is a faster but less private option. In this mode traffic is only sent between the two Gateways, and is not passed between Mix Nodes. It uses Mixnet Sphinx packets with shorter, fixed routes, which improve latency, but doesn't offer the same level of protection as the 5 hop mode.
|
||||
<!-- TO BE IMPLEMENTED:
|
||||
Users can switch to 2-hop only mode, which is a faster but less private option. In this mode traffic is only sent between the two Gateways, and is not passed between Mix Nodes. The client than use two wireguard tunnels with the entry and exit gateway, the Exit Gateway one being tunnelled itself through the entry gateway tunnel. NymVPN uses Mullvad libraries for wrapping `wireguard-go` and to setup local routing rules to route all traffic to the TUN virtual network device.
|
||||
-->
|
||||
Users can switch to 2-hop only mode, which is a faster but less private option. In this mode traffic is only sent between the two Gateways, and is not passed between Mix Nodes.
|
||||
|
||||
The client can optionally do the first hop (local client to Entry Gateway) using Wireguard. NymVPN uses Mullvad libraries for wrapping `wireguard-go` and to setup local routing rules to route all traffic to the TUN virtual network device.
|
||||
|
||||
## NymVPN Resources & Guides
|
||||
|
||||
* [NymVPN webpage](https://nymvpn.com)
|
||||
* [Alpha release page]({{nym_vpn_releases}})
|
||||
* [NymVPN application (GUI) guide](gui.md)
|
||||
* [NymVPN Command Line Interface (CLI) guide](cli.md)
|
||||
* [Troubleshooting](troubleshooting.md)
|
||||
* [NymVPN FAQ](faq.md)
|
||||
* [NymVPN matrix channel](https://matrix.to/#/#NymVPN:nymtech.chat)
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
#!/bin/bash
|
||||
|
||||
release_url="https://api.github.com/repos/nymtech/nym-vpn-client/releases"
|
||||
current_cli_version=$(curl -s $release_url | jq -r '.[].tag_name' | grep '^nym-vpn-cli-' | sort -Vr | head -n 1 | awk -F'-v' '{print $NF}')
|
||||
current_cli_version=$(curl -s $release_url | jq -r '.[].tag_name' | grep '^nym-vpn-cli-v' | sort -Vr | head -n 1 | awk -F'-v' '{print $NF}')
|
||||
|
||||
echo "${current_cli_version}"
|
||||
@@ -2,14 +2,6 @@
|
||||
|
||||
Below are listed some points which may need to be addressed when testing NymVPN alpha. If you crashed into any errors which are not listed, please contact us at the testing workshop or in the NymVPN [Matrix channel](https://matrix.to/#/#NymVPN:nymtech.chat).
|
||||
|
||||
#### NymVPN attempts to connect to sandbox testnet
|
||||
|
||||
If you testing the latest versions and you correctly expect the client to run over the mainnet, but it listens to `https://sandbox-nym-api1.nymtech.net`, it's probably because of your previous configuration.
|
||||
|
||||
Check your `config.toml` either in the directory from which you run your client or in `~/.config/nym-vpn/` and remove `sandbox.env` from the config file and folder.
|
||||
|
||||
If the problem persists (probably due to some locally cache) download [`mainnet.env`](https://github.com/nymtech/nym/blob/master/envs/mainnet.env) and save it to the same directory.
|
||||
|
||||
#### Running GUI failed due to `TOML parse error`
|
||||
|
||||
If you see this error when running NymVPN alpha desktop, it's because the older versions needed entry location in `config.toml` configuration file. From `v0.0.3` the entry location is selected directly by the user in the application. This error is due to an old `app-data.toml` config in your computer.
|
||||
|
||||
@@ -25,7 +25,7 @@ turn-off = true
|
||||
|
||||
[preprocessor.admonish]
|
||||
command = "mdbook-admonish"
|
||||
assets_version = "3.0.2" # do not edit: managed by `mdbook-admonish install`
|
||||
assets_version = "3.0.0" # do not edit: managed by `mdbook-admonish install`
|
||||
|
||||
# https://gitlab.com/tglman/mdbook-variables/
|
||||
[preprocessor.variables.variables]
|
||||
|
||||
@@ -1,4 +1,20 @@
|
||||
@charset "UTF-8";
|
||||
:root {
|
||||
--md-admonition-icon--admonish-note: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M20.71 7.04c.39-.39.39-1.04 0-1.41l-2.34-2.34c-.37-.39-1.02-.39-1.41 0l-1.84 1.83 3.75 3.75M3 17.25V21h3.75L17.81 9.93l-3.75-3.75L3 17.25z'/></svg>");
|
||||
--md-admonition-icon--admonish-abstract: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M17 9H7V7h10m0 6H7v-2h10m-3 6H7v-2h7M12 3a1 1 0 0 1 1 1 1 1 0 0 1-1 1 1 1 0 0 1-1-1 1 1 0 0 1 1-1m7 0h-4.18C14.4 1.84 13.3 1 12 1c-1.3 0-2.4.84-2.82 2H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V5a2 2 0 0 0-2-2z'/></svg>");
|
||||
--md-admonition-icon--admonish-info: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M13 9h-2V7h2m0 10h-2v-6h2m-1-9A10 10 0 0 0 2 12a10 10 0 0 0 10 10 10 10 0 0 0 10-10A10 10 0 0 0 12 2z'/></svg>");
|
||||
--md-admonition-icon--admonish-tip: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M17.66 11.2c-.23-.3-.51-.56-.77-.82-.67-.6-1.43-1.03-2.07-1.66C13.33 7.26 13 4.85 13.95 3c-.95.23-1.78.75-2.49 1.32-2.59 2.08-3.61 5.75-2.39 8.9.04.1.08.2.08.33 0 .22-.15.42-.35.5-.23.1-.47.04-.66-.12a.58.58 0 0 1-.14-.17c-1.13-1.43-1.31-3.48-.55-5.12C5.78 10 4.87 12.3 5 14.47c.06.5.12 1 .29 1.5.14.6.41 1.2.71 1.73 1.08 1.73 2.95 2.97 4.96 3.22 2.14.27 4.43-.12 6.07-1.6 1.83-1.66 2.47-4.32 1.53-6.6l-.13-.26c-.21-.46-.77-1.26-.77-1.26m-3.16 6.3c-.28.24-.74.5-1.1.6-1.12.4-2.24-.16-2.9-.82 1.19-.28 1.9-1.16 2.11-2.05.17-.8-.15-1.46-.28-2.23-.12-.74-.1-1.37.17-2.06.19.38.39.76.63 1.06.77 1 1.98 1.44 2.24 2.8.04.14.06.28.06.43.03.82-.33 1.72-.93 2.27z'/></svg>");
|
||||
--md-admonition-icon--admonish-success: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='m9 20.42-6.21-6.21 2.83-2.83L9 14.77l9.88-9.89 2.83 2.83L9 20.42z'/></svg>");
|
||||
--md-admonition-icon--admonish-question: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='m15.07 11.25-.9.92C13.45 12.89 13 13.5 13 15h-2v-.5c0-1.11.45-2.11 1.17-2.83l1.24-1.26c.37-.36.59-.86.59-1.41a2 2 0 0 0-2-2 2 2 0 0 0-2 2H8a4 4 0 0 1 4-4 4 4 0 0 1 4 4 3.2 3.2 0 0 1-.93 2.25M13 19h-2v-2h2M12 2A10 10 0 0 0 2 12a10 10 0 0 0 10 10 10 10 0 0 0 10-10c0-5.53-4.5-10-10-10z'/></svg>");
|
||||
--md-admonition-icon--admonish-warning: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M13 14h-2V9h2m0 9h-2v-2h2M1 21h22L12 2 1 21z'/></svg>");
|
||||
--md-admonition-icon--admonish-failure: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M20 6.91 17.09 4 12 9.09 6.91 4 4 6.91 9.09 12 4 17.09 6.91 20 12 14.91 17.09 20 20 17.09 14.91 12 20 6.91z'/></svg>");
|
||||
--md-admonition-icon--admonish-danger: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M11 15H6l7-14v8h5l-7 14v-8z'/></svg>");
|
||||
--md-admonition-icon--admonish-bug: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M14 12h-4v-2h4m0 6h-4v-2h4m6-6h-2.81a5.985 5.985 0 0 0-1.82-1.96L17 4.41 15.59 3l-2.17 2.17a6.002 6.002 0 0 0-2.83 0L8.41 3 7 4.41l1.62 1.63C7.88 6.55 7.26 7.22 6.81 8H4v2h2.09c-.05.33-.09.66-.09 1v1H4v2h2v1c0 .34.04.67.09 1H4v2h2.81c1.04 1.79 2.97 3 5.19 3s4.15-1.21 5.19-3H20v-2h-2.09c.05-.33.09-.66.09-1v-1h2v-2h-2v-1c0-.34-.04-.67-.09-1H20V8z'/></svg>");
|
||||
--md-admonition-icon--admonish-example: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M7 13v-2h14v2H7m0 6v-2h14v2H7M7 7V5h14v2H7M3 8V5H2V4h2v4H3m-1 9v-1h3v4H2v-1h2v-.5H3v-1h1V17H2m2.25-7a.75.75 0 0 1 .75.75c0 .2-.08.39-.21.52L3.12 13H5v1H2v-.92L4 11H2v-1h2.25z'/></svg>");
|
||||
--md-admonition-icon--admonish-quote: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M14 17h3l2-4V7h-6v6h3M6 17h3l2-4V7H5v6h3l-2 4z'/></svg>");
|
||||
--md-details-icon: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M8.59 16.58 13.17 12 8.59 7.41 10 6l6 6-6 6-1.41-1.42Z'/></svg>");
|
||||
}
|
||||
|
||||
:is(.admonition) {
|
||||
display: flow-root;
|
||||
margin: 1.5625em 0;
|
||||
@@ -55,8 +71,6 @@ a.admonition-anchor-link::before {
|
||||
padding-inline: 4.4rem 1.2rem;
|
||||
font-weight: 700;
|
||||
background-color: rgba(68, 138, 255, 0.1);
|
||||
print-color-adjust: exact;
|
||||
-webkit-print-color-adjust: exact;
|
||||
display: flex;
|
||||
}
|
||||
:is(.admonition-title, summary.admonition-title) p {
|
||||
@@ -72,8 +86,6 @@ html :is(.admonition-title, summary.admonition-title):last-child {
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
background-color: #448aff;
|
||||
print-color-adjust: exact;
|
||||
-webkit-print-color-adjust: exact;
|
||||
mask-image: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"></svg>');
|
||||
-webkit-mask-image: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"></svg>');
|
||||
mask-repeat: no-repeat;
|
||||
@@ -107,25 +119,6 @@ details[open].admonition > summary.admonition-title::after {
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
|
||||
:root {
|
||||
--md-details-icon: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M8.59 16.58 13.17 12 8.59 7.41 10 6l6 6-6 6-1.41-1.42Z'/></svg>");
|
||||
}
|
||||
|
||||
:root {
|
||||
--md-admonition-icon--admonish-note: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M20.71 7.04c.39-.39.39-1.04 0-1.41l-2.34-2.34c-.37-.39-1.02-.39-1.41 0l-1.84 1.83 3.75 3.75M3 17.25V21h3.75L17.81 9.93l-3.75-3.75L3 17.25z'/></svg>");
|
||||
--md-admonition-icon--admonish-abstract: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M17 9H7V7h10m0 6H7v-2h10m-3 6H7v-2h7M12 3a1 1 0 0 1 1 1 1 1 0 0 1-1 1 1 1 0 0 1-1-1 1 1 0 0 1 1-1m7 0h-4.18C14.4 1.84 13.3 1 12 1c-1.3 0-2.4.84-2.82 2H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V5a2 2 0 0 0-2-2z'/></svg>");
|
||||
--md-admonition-icon--admonish-info: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M13 9h-2V7h2m0 10h-2v-6h2m-1-9A10 10 0 0 0 2 12a10 10 0 0 0 10 10 10 10 0 0 0 10-10A10 10 0 0 0 12 2z'/></svg>");
|
||||
--md-admonition-icon--admonish-tip: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M17.66 11.2c-.23-.3-.51-.56-.77-.82-.67-.6-1.43-1.03-2.07-1.66C13.33 7.26 13 4.85 13.95 3c-.95.23-1.78.75-2.49 1.32-2.59 2.08-3.61 5.75-2.39 8.9.04.1.08.2.08.33 0 .22-.15.42-.35.5-.23.1-.47.04-.66-.12a.58.58 0 0 1-.14-.17c-1.13-1.43-1.31-3.48-.55-5.12C5.78 10 4.87 12.3 5 14.47c.06.5.12 1 .29 1.5.14.6.41 1.2.71 1.73 1.08 1.73 2.95 2.97 4.96 3.22 2.14.27 4.43-.12 6.07-1.6 1.83-1.66 2.47-4.32 1.53-6.6l-.13-.26c-.21-.46-.77-1.26-.77-1.26m-3.16 6.3c-.28.24-.74.5-1.1.6-1.12.4-2.24-.16-2.9-.82 1.19-.28 1.9-1.16 2.11-2.05.17-.8-.15-1.46-.28-2.23-.12-.74-.1-1.37.17-2.06.19.38.39.76.63 1.06.77 1 1.98 1.44 2.24 2.8.04.14.06.28.06.43.03.82-.33 1.72-.93 2.27z'/></svg>");
|
||||
--md-admonition-icon--admonish-success: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='m9 20.42-6.21-6.21 2.83-2.83L9 14.77l9.88-9.89 2.83 2.83L9 20.42z'/></svg>");
|
||||
--md-admonition-icon--admonish-question: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='m15.07 11.25-.9.92C13.45 12.89 13 13.5 13 15h-2v-.5c0-1.11.45-2.11 1.17-2.83l1.24-1.26c.37-.36.59-.86.59-1.41a2 2 0 0 0-2-2 2 2 0 0 0-2 2H8a4 4 0 0 1 4-4 4 4 0 0 1 4 4 3.2 3.2 0 0 1-.93 2.25M13 19h-2v-2h2M12 2A10 10 0 0 0 2 12a10 10 0 0 0 10 10 10 10 0 0 0 10-10c0-5.53-4.5-10-10-10z'/></svg>");
|
||||
--md-admonition-icon--admonish-warning: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M13 14h-2V9h2m0 9h-2v-2h2M1 21h22L12 2 1 21z'/></svg>");
|
||||
--md-admonition-icon--admonish-failure: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M20 6.91 17.09 4 12 9.09 6.91 4 4 6.91 9.09 12 4 17.09 6.91 20 12 14.91 17.09 20 20 17.09 14.91 12 20 6.91z'/></svg>");
|
||||
--md-admonition-icon--admonish-danger: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M11 15H6l7-14v8h5l-7 14v-8z'/></svg>");
|
||||
--md-admonition-icon--admonish-bug: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M14 12h-4v-2h4m0 6h-4v-2h4m6-6h-2.81a5.985 5.985 0 0 0-1.82-1.96L17 4.41 15.59 3l-2.17 2.17a6.002 6.002 0 0 0-2.83 0L8.41 3 7 4.41l1.62 1.63C7.88 6.55 7.26 7.22 6.81 8H4v2h2.09c-.05.33-.09.66-.09 1v1H4v2h2v1c0 .34.04.67.09 1H4v2h2.81c1.04 1.79 2.97 3 5.19 3s4.15-1.21 5.19-3H20v-2h-2.09c.05-.33.09-.66.09-1v-1h2v-2h-2v-1c0-.34-.04-.67-.09-1H20V8z'/></svg>");
|
||||
--md-admonition-icon--admonish-example: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M7 13v-2h14v2H7m0 6v-2h14v2H7M7 7V5h14v2H7M3 8V5H2V4h2v4H3m-1 9v-1h3v4H2v-1h2v-.5H3v-1h1V17H2m2.25-7a.75.75 0 0 1 .75.75c0 .2-.08.39-.21.52L3.12 13H5v1H2v-.92L4 11H2v-1h2.25z'/></svg>");
|
||||
--md-admonition-icon--admonish-quote: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M14 17h3l2-4V7h-6v6h3M6 17h3l2-4V7H5v6h3l-2 4z'/></svg>");
|
||||
}
|
||||
|
||||
:is(.admonition):is(.admonish-note) {
|
||||
border-color: #448aff;
|
||||
}
|
||||
|
||||
@@ -13,12 +13,12 @@ declare -a plugins=("admonish" "linkcheck" "last-changed" "theme" "variables" "c
|
||||
|
||||
# install mdbook + plugins
|
||||
install_mdbook_deps() {
|
||||
printf "\ninstalling mdbook..."
|
||||
# installing mdbook with only specific features for speed
|
||||
printf "\ninstalling mdbook..."
|
||||
# installing mdbook with only specific features for speed
|
||||
# cargo install mdbook --no-default-features --features search --vers "^$MINOR_VERSION"
|
||||
cargo install mdbook --vers "^$MINOR_VERSION"
|
||||
|
||||
printf "\ninstalling plugins..."
|
||||
printf "\ninstalling plugins..."
|
||||
for i in "${plugins[@]}"
|
||||
do
|
||||
cargo install mdbook-$i
|
||||
@@ -41,13 +41,13 @@ install_mdbook_deps() {
|
||||
# uninstall mdbook + plugins
|
||||
uninstall_mdbook_deps() {
|
||||
# mdbook
|
||||
printf "\nuninstalling existing mdbook installation...\n"
|
||||
cargo uninstall mdbook
|
||||
# check it worked
|
||||
printf "\nuninstalling existing mdbook installation...\n"
|
||||
cargo uninstall mdbook
|
||||
# check it worked
|
||||
if [ $? -ne 0 ]; then
|
||||
printf "\nsomething went wrong, exiting"
|
||||
exit 1
|
||||
else
|
||||
else
|
||||
printf "\nmdbook deleted\n"
|
||||
fi
|
||||
|
||||
@@ -57,10 +57,10 @@ uninstall_mdbook_deps() {
|
||||
do
|
||||
cargo uninstall mdbook-$i
|
||||
# check it worked
|
||||
if [ $? -ne 0 ]; then
|
||||
if [ $? -ne 0 ]; then
|
||||
printf "\nsomething went wrong, exiting"
|
||||
exit 1
|
||||
else
|
||||
else
|
||||
printf "\nmdbook-$i deleted\n"
|
||||
fi
|
||||
done
|
||||
@@ -71,10 +71,10 @@ main() {
|
||||
printf "mdbook already installed (located at: $(which mdbook))"
|
||||
uninstall_mdbook_deps;
|
||||
install_mdbook_deps;
|
||||
else
|
||||
else
|
||||
printf "mdbook not installed"
|
||||
install_mdbook_deps;
|
||||
fi
|
||||
}
|
||||
|
||||
main;
|
||||
main;
|
||||
|
||||
@@ -24,7 +24,7 @@ turn-off = true
|
||||
|
||||
[preprocessor.admonish]
|
||||
command = "mdbook-admonish"
|
||||
assets_version = "3.0.2" # do not edit: managed by `mdbook-admonish install`
|
||||
assets_version = "3.0.0" # do not edit: managed by `mdbook-admonish install`
|
||||
|
||||
# https://gitlab.com/tglman/mdbook-variables/
|
||||
[preprocessor.variables.variables]
|
||||
|
||||
@@ -1,4 +1,20 @@
|
||||
@charset "UTF-8";
|
||||
:root {
|
||||
--md-admonition-icon--admonish-note: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M20.71 7.04c.39-.39.39-1.04 0-1.41l-2.34-2.34c-.37-.39-1.02-.39-1.41 0l-1.84 1.83 3.75 3.75M3 17.25V21h3.75L17.81 9.93l-3.75-3.75L3 17.25z'/></svg>");
|
||||
--md-admonition-icon--admonish-abstract: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M17 9H7V7h10m0 6H7v-2h10m-3 6H7v-2h7M12 3a1 1 0 0 1 1 1 1 1 0 0 1-1 1 1 1 0 0 1-1-1 1 1 0 0 1 1-1m7 0h-4.18C14.4 1.84 13.3 1 12 1c-1.3 0-2.4.84-2.82 2H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V5a2 2 0 0 0-2-2z'/></svg>");
|
||||
--md-admonition-icon--admonish-info: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M13 9h-2V7h2m0 10h-2v-6h2m-1-9A10 10 0 0 0 2 12a10 10 0 0 0 10 10 10 10 0 0 0 10-10A10 10 0 0 0 12 2z'/></svg>");
|
||||
--md-admonition-icon--admonish-tip: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M17.66 11.2c-.23-.3-.51-.56-.77-.82-.67-.6-1.43-1.03-2.07-1.66C13.33 7.26 13 4.85 13.95 3c-.95.23-1.78.75-2.49 1.32-2.59 2.08-3.61 5.75-2.39 8.9.04.1.08.2.08.33 0 .22-.15.42-.35.5-.23.1-.47.04-.66-.12a.58.58 0 0 1-.14-.17c-1.13-1.43-1.31-3.48-.55-5.12C5.78 10 4.87 12.3 5 14.47c.06.5.12 1 .29 1.5.14.6.41 1.2.71 1.73 1.08 1.73 2.95 2.97 4.96 3.22 2.14.27 4.43-.12 6.07-1.6 1.83-1.66 2.47-4.32 1.53-6.6l-.13-.26c-.21-.46-.77-1.26-.77-1.26m-3.16 6.3c-.28.24-.74.5-1.1.6-1.12.4-2.24-.16-2.9-.82 1.19-.28 1.9-1.16 2.11-2.05.17-.8-.15-1.46-.28-2.23-.12-.74-.1-1.37.17-2.06.19.38.39.76.63 1.06.77 1 1.98 1.44 2.24 2.8.04.14.06.28.06.43.03.82-.33 1.72-.93 2.27z'/></svg>");
|
||||
--md-admonition-icon--admonish-success: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='m9 20.42-6.21-6.21 2.83-2.83L9 14.77l9.88-9.89 2.83 2.83L9 20.42z'/></svg>");
|
||||
--md-admonition-icon--admonish-question: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='m15.07 11.25-.9.92C13.45 12.89 13 13.5 13 15h-2v-.5c0-1.11.45-2.11 1.17-2.83l1.24-1.26c.37-.36.59-.86.59-1.41a2 2 0 0 0-2-2 2 2 0 0 0-2 2H8a4 4 0 0 1 4-4 4 4 0 0 1 4 4 3.2 3.2 0 0 1-.93 2.25M13 19h-2v-2h2M12 2A10 10 0 0 0 2 12a10 10 0 0 0 10 10 10 10 0 0 0 10-10c0-5.53-4.5-10-10-10z'/></svg>");
|
||||
--md-admonition-icon--admonish-warning: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M13 14h-2V9h2m0 9h-2v-2h2M1 21h22L12 2 1 21z'/></svg>");
|
||||
--md-admonition-icon--admonish-failure: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M20 6.91 17.09 4 12 9.09 6.91 4 4 6.91 9.09 12 4 17.09 6.91 20 12 14.91 17.09 20 20 17.09 14.91 12 20 6.91z'/></svg>");
|
||||
--md-admonition-icon--admonish-danger: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M11 15H6l7-14v8h5l-7 14v-8z'/></svg>");
|
||||
--md-admonition-icon--admonish-bug: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M14 12h-4v-2h4m0 6h-4v-2h4m6-6h-2.81a5.985 5.985 0 0 0-1.82-1.96L17 4.41 15.59 3l-2.17 2.17a6.002 6.002 0 0 0-2.83 0L8.41 3 7 4.41l1.62 1.63C7.88 6.55 7.26 7.22 6.81 8H4v2h2.09c-.05.33-.09.66-.09 1v1H4v2h2v1c0 .34.04.67.09 1H4v2h2.81c1.04 1.79 2.97 3 5.19 3s4.15-1.21 5.19-3H20v-2h-2.09c.05-.33.09-.66.09-1v-1h2v-2h-2v-1c0-.34-.04-.67-.09-1H20V8z'/></svg>");
|
||||
--md-admonition-icon--admonish-example: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M7 13v-2h14v2H7m0 6v-2h14v2H7M7 7V5h14v2H7M3 8V5H2V4h2v4H3m-1 9v-1h3v4H2v-1h2v-.5H3v-1h1V17H2m2.25-7a.75.75 0 0 1 .75.75c0 .2-.08.39-.21.52L3.12 13H5v1H2v-.92L4 11H2v-1h2.25z'/></svg>");
|
||||
--md-admonition-icon--admonish-quote: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M14 17h3l2-4V7h-6v6h3M6 17h3l2-4V7H5v6h3l-2 4z'/></svg>");
|
||||
--md-details-icon: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M8.59 16.58 13.17 12 8.59 7.41 10 6l6 6-6 6-1.41-1.42Z'/></svg>");
|
||||
}
|
||||
|
||||
:is(.admonition) {
|
||||
display: flow-root;
|
||||
margin: 1.5625em 0;
|
||||
@@ -55,8 +71,6 @@ a.admonition-anchor-link::before {
|
||||
padding-inline: 4.4rem 1.2rem;
|
||||
font-weight: 700;
|
||||
background-color: rgba(68, 138, 255, 0.1);
|
||||
print-color-adjust: exact;
|
||||
-webkit-print-color-adjust: exact;
|
||||
display: flex;
|
||||
}
|
||||
:is(.admonition-title, summary.admonition-title) p {
|
||||
@@ -72,8 +86,6 @@ html :is(.admonition-title, summary.admonition-title):last-child {
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
background-color: #448aff;
|
||||
print-color-adjust: exact;
|
||||
-webkit-print-color-adjust: exact;
|
||||
mask-image: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"></svg>');
|
||||
-webkit-mask-image: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"></svg>');
|
||||
mask-repeat: no-repeat;
|
||||
@@ -107,25 +119,6 @@ details[open].admonition > summary.admonition-title::after {
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
|
||||
:root {
|
||||
--md-details-icon: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M8.59 16.58 13.17 12 8.59 7.41 10 6l6 6-6 6-1.41-1.42Z'/></svg>");
|
||||
}
|
||||
|
||||
:root {
|
||||
--md-admonition-icon--admonish-note: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M20.71 7.04c.39-.39.39-1.04 0-1.41l-2.34-2.34c-.37-.39-1.02-.39-1.41 0l-1.84 1.83 3.75 3.75M3 17.25V21h3.75L17.81 9.93l-3.75-3.75L3 17.25z'/></svg>");
|
||||
--md-admonition-icon--admonish-abstract: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M17 9H7V7h10m0 6H7v-2h10m-3 6H7v-2h7M12 3a1 1 0 0 1 1 1 1 1 0 0 1-1 1 1 1 0 0 1-1-1 1 1 0 0 1 1-1m7 0h-4.18C14.4 1.84 13.3 1 12 1c-1.3 0-2.4.84-2.82 2H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V5a2 2 0 0 0-2-2z'/></svg>");
|
||||
--md-admonition-icon--admonish-info: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M13 9h-2V7h2m0 10h-2v-6h2m-1-9A10 10 0 0 0 2 12a10 10 0 0 0 10 10 10 10 0 0 0 10-10A10 10 0 0 0 12 2z'/></svg>");
|
||||
--md-admonition-icon--admonish-tip: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M17.66 11.2c-.23-.3-.51-.56-.77-.82-.67-.6-1.43-1.03-2.07-1.66C13.33 7.26 13 4.85 13.95 3c-.95.23-1.78.75-2.49 1.32-2.59 2.08-3.61 5.75-2.39 8.9.04.1.08.2.08.33 0 .22-.15.42-.35.5-.23.1-.47.04-.66-.12a.58.58 0 0 1-.14-.17c-1.13-1.43-1.31-3.48-.55-5.12C5.78 10 4.87 12.3 5 14.47c.06.5.12 1 .29 1.5.14.6.41 1.2.71 1.73 1.08 1.73 2.95 2.97 4.96 3.22 2.14.27 4.43-.12 6.07-1.6 1.83-1.66 2.47-4.32 1.53-6.6l-.13-.26c-.21-.46-.77-1.26-.77-1.26m-3.16 6.3c-.28.24-.74.5-1.1.6-1.12.4-2.24-.16-2.9-.82 1.19-.28 1.9-1.16 2.11-2.05.17-.8-.15-1.46-.28-2.23-.12-.74-.1-1.37.17-2.06.19.38.39.76.63 1.06.77 1 1.98 1.44 2.24 2.8.04.14.06.28.06.43.03.82-.33 1.72-.93 2.27z'/></svg>");
|
||||
--md-admonition-icon--admonish-success: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='m9 20.42-6.21-6.21 2.83-2.83L9 14.77l9.88-9.89 2.83 2.83L9 20.42z'/></svg>");
|
||||
--md-admonition-icon--admonish-question: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='m15.07 11.25-.9.92C13.45 12.89 13 13.5 13 15h-2v-.5c0-1.11.45-2.11 1.17-2.83l1.24-1.26c.37-.36.59-.86.59-1.41a2 2 0 0 0-2-2 2 2 0 0 0-2 2H8a4 4 0 0 1 4-4 4 4 0 0 1 4 4 3.2 3.2 0 0 1-.93 2.25M13 19h-2v-2h2M12 2A10 10 0 0 0 2 12a10 10 0 0 0 10 10 10 10 0 0 0 10-10c0-5.53-4.5-10-10-10z'/></svg>");
|
||||
--md-admonition-icon--admonish-warning: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M13 14h-2V9h2m0 9h-2v-2h2M1 21h22L12 2 1 21z'/></svg>");
|
||||
--md-admonition-icon--admonish-failure: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M20 6.91 17.09 4 12 9.09 6.91 4 4 6.91 9.09 12 4 17.09 6.91 20 12 14.91 17.09 20 20 17.09 14.91 12 20 6.91z'/></svg>");
|
||||
--md-admonition-icon--admonish-danger: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M11 15H6l7-14v8h5l-7 14v-8z'/></svg>");
|
||||
--md-admonition-icon--admonish-bug: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M14 12h-4v-2h4m0 6h-4v-2h4m6-6h-2.81a5.985 5.985 0 0 0-1.82-1.96L17 4.41 15.59 3l-2.17 2.17a6.002 6.002 0 0 0-2.83 0L8.41 3 7 4.41l1.62 1.63C7.88 6.55 7.26 7.22 6.81 8H4v2h2.09c-.05.33-.09.66-.09 1v1H4v2h2v1c0 .34.04.67.09 1H4v2h2.81c1.04 1.79 2.97 3 5.19 3s4.15-1.21 5.19-3H20v-2h-2.09c.05-.33.09-.66.09-1v-1h2v-2h-2v-1c0-.34-.04-.67-.09-1H20V8z'/></svg>");
|
||||
--md-admonition-icon--admonish-example: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M7 13v-2h14v2H7m0 6v-2h14v2H7M7 7V5h14v2H7M3 8V5H2V4h2v4H3m-1 9v-1h3v4H2v-1h2v-.5H3v-1h1V17H2m2.25-7a.75.75 0 0 1 .75.75c0 .2-.08.39-.21.52L3.12 13H5v1H2v-.92L4 11H2v-1h2.25z'/></svg>");
|
||||
--md-admonition-icon--admonish-quote: url("data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M14 17h3l2-4V7h-6v6h3M6 17h3l2-4V7H5v6h3l-2 4z'/></svg>");
|
||||
}
|
||||
|
||||
:is(.admonition):is(.admonish-note) {
|
||||
border-color: #448aff;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
# Summary
|
||||
|
||||
- [Introduction](introduction.md)
|
||||
- [Changelog](changelog.md)
|
||||
|
||||
# Binaries
|
||||
|
||||
@@ -13,17 +12,13 @@
|
||||
|
||||
# Operators Guides
|
||||
|
||||
- [Preliminary Steps](nodes/preliminary-steps.md)
|
||||
- [Nym Wallet Preparation](nodes/wallet-preparation.md)
|
||||
- [VPS Setup](nodes/vps-setup.md)
|
||||
- [Nym Node](nodes/nym-node.md)
|
||||
- [Setup & Run](nodes/setup.md)
|
||||
- [Configuration](nodes/configuration.md)
|
||||
- [WSS & Reversed Proxy](nodes/proxy-configuration.md)
|
||||
- [Bonding](nodes/bonding.md)
|
||||
- [Mixnet Nodes Setup](nodes/setup-guides.md)
|
||||
- [Preliminary Steps](preliminary-steps.md)
|
||||
- [Mix Node](nodes/mix-node-setup.md)
|
||||
- [Gateway](nodes/gateway-setup.md)
|
||||
- [Network Requester](nodes/network-requester-setup.md)
|
||||
- [Nyx Validator Setup](nodes/validator-setup.md)
|
||||
- [Nym API Setup](nodes/nym-api.md)
|
||||
- [Validator & API Configuration](nodes/nyx-configuration.md)
|
||||
- [Maintenance](nodes/maintenance.md)
|
||||
- [Manual Node Upgrade](nodes/manual-upgrade.md)
|
||||
- [Automatic Node Upgrade: Nymvisor Setup and Usage](nodes/nymvisor-upgrade.md)
|
||||
@@ -33,12 +28,12 @@
|
||||
- [Prometheus & Grafana](testing/prometheus-grafana.md)
|
||||
- [ExploreNYM scripts](testing/explorenym-scripts.md)
|
||||
<!-- - [Run in a Docker](testing/docker-monitor.md) -->
|
||||
|
||||
# Troubleshooting
|
||||
|
||||
- [VPS Setup](troubleshooting/vps-isp.md)
|
||||
- [Nym Node](troubleshooting/nodes.md)
|
||||
- [Validators](troubleshooting/validators.md)
|
||||
- [Troubleshooting](nodes/troubleshooting.md)
|
||||
<!--
|
||||
- [Nym Nodes]()
|
||||
- [Validators]
|
||||
- [Binary]
|
||||
-->
|
||||
|
||||
# Token Economics
|
||||
|
||||
@@ -48,11 +43,10 @@
|
||||
|
||||
# FAQ
|
||||
|
||||
- [General Operators FAQ](faq/general-faq.md)
|
||||
- [Nym Nodes](faq/nym-nodes-faq.md)
|
||||
- [Nyx & Validators](faq/nyx-faq.md)
|
||||
- [Mix Nodes](faq/mixnodes-faq.md)
|
||||
- [Project Smoosh](faq/smoosh-faq.md)
|
||||
|
||||
# Community & Legal Forum
|
||||
# Legal Forum
|
||||
|
||||
- [Exit Gateway](legal/exit-gateway.md)
|
||||
- [Community Counsel](legal/community-counsel.md)
|
||||
@@ -62,19 +56,6 @@
|
||||
- [Landing Pages](legal/landing-pages.md)
|
||||
- [How to Add Info](legal/add-content.md)
|
||||
|
||||
---
|
||||
# Archive
|
||||
|
||||
- [Why archive?](archive/archive.md)
|
||||
- [Mixnet Nodes Setup](archive/nodes/setup-guides.md)
|
||||
- [Preliminary Steps](archive/nodes/initial-steps.md)
|
||||
- [Mix Node](archive/nodes/mix-node-setup.md)
|
||||
- [Gateway](archive/nodes/gateway-setup.md)
|
||||
- [Network Requester](archive/nodes/network-requester-setup.md)
|
||||
- [FAQ: Mix Nodes](archive/faq/mixnodes-faq.md)
|
||||
- [FAQ: Project Smoosh](archive/faq/smoosh-faq.md)
|
||||
|
||||
|
||||
---
|
||||
# Misc.
|
||||
- [Code of Conduct](coc.md)
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
# Archived Pages
|
||||
|
||||
This section contains old but still relevant pages/guides, archived for backwards compatibility. The content of the pages is not updated. See the top of every page informing you about the last time of update.
|
||||
|
||||
Pages listed in archive section will eventually be terminated as they will become completely irrelevant with time.
|
||||
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
# Node Setup Guides
|
||||
|
||||
```admonish warning
|
||||
**This is an archived page for backwards compatibility. The content of this page is not updated since April 19th 2024. Eventually this page will be terminated!**
|
||||
```
|
||||
|
||||
To setup any type of Nym's node, start with building [Nym's platform](../../binaries/building-nym.md) on the machine (VPS) where you want to run the node. Nodes will need to be bond to Nym's wallet, setup one [here](https://nymtech.net/docs/wallet/desktop-wallet.html).
|
||||
|
||||
This section contains setup guides for the following node types:
|
||||
* [Mix Node](mix-node-setup.md)
|
||||
* [Gateway](gateway-setup.md)
|
||||
* [Network Requester](network-requester-setup.md)
|
||||
* [Validator](../../nodes/validator-setup.md)
|
||||
|
||||
|
||||
@@ -54,14 +54,16 @@ cargo build --release # build your binaries with **mainnet** configuration
|
||||
|
||||
Quite a bit of stuff gets built. The key working parts are:
|
||||
|
||||
* [Nym Node](../nodes/nym-node.md): `nym-node`
|
||||
* [Validator](../nodes/validator-setup.md)
|
||||
* [mix node](../nodes/mix-node-setup.md): `nym-mixnode`
|
||||
* [gateway node](../nodes/gateway-setup.md): `nym-gateway`
|
||||
* [websocket client](https://nymtech.net/docs/clients/websocket-client.html): `nym-client`
|
||||
* [socks5 client](https://nymtech.net/docs/clients/socks5-client.html): `nym-socks5-client`
|
||||
* [webassembly client](https://nymtech.net/docs/clients/webassembly-client.html): `webassembly-client`
|
||||
* [network requester](../nodes/network-requester-setup.md): `nym-network-requester`
|
||||
* [nym-cli tool](https://nymtech.net/docs/tools/nym-cli.html): `nym-cli`
|
||||
* [nym-api](../nodes/nym-api.md): `nym-api`
|
||||
* [nymvisor](../nodes/nymvisor-upgrade.md): `nymvisor`
|
||||
|
||||
[//]: # (* [nymvisor](../nodes/nymvisor-upgrade.md): `nymvisor`)
|
||||
|
||||
The repository also contains Typescript applications which aren't built in this process. These can be built by following the instructions on their respective docs pages.
|
||||
* [Nym Wallet](https://nymtech.net/docs/wallet/desktop-wallet.html)
|
||||
|
||||
@@ -28,5 +28,7 @@ Now you can use your binary, initialise and run your Nym Node. Follow the guide
|
||||
|
||||
**Node setup and usage guides:**
|
||||
|
||||
* [Nym Nodes](../nodes/nym-node.md)
|
||||
* [Mix nodes](../nodes/mix-node-setup.md)
|
||||
* [Gateways](../nodes/gateway-setup.md)
|
||||
* [Network requesters](../nodes/network-requester-setup.md)
|
||||
* [Validators](../nodes/validator-setup.md)
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
# Changelog
|
||||
|
||||
This page displays a full list of all the changes during our release cycle from [`v2024.3-eclipse`](https://github.com/nymtech/nym/blob/nym-binaries-v2024.3-eclipse/CHANGELOG.md) onwards. Operators can find here the newest updates together with links to relevant documentation. The list is sorted so that the newest changes appear first.
|
||||
|
||||
## `v2024.4-nutella`
|
||||
|
||||
- [Merged PRs](https://github.com/nymtech/nym/milestone/59?closed=1)
|
||||
- [`nym-node`](nodes/nym-node.md) version `1.1.1`
|
||||
- This release also contains: `nym-gateway` and `nym-network-requester` binaries
|
||||
- core improvements on nym-node configuration
|
||||
- Nym wallet changes:
|
||||
- Adding `nym-node` command to bonding screens
|
||||
- Fixed the delegation issues with fixing RPC
|
||||
- [Network configuration](nodes/configuration.md#connectivity-test-and-configuration) section updates, in particular for `--mode mixnode` operators
|
||||
- [VPS IPv6 troubleshooting](troubleshooting/vps-isp.md#ipv6-troubleshooting) updates
|
||||
|
||||
## `v2024.3-eclipse`
|
||||
|
||||
- Release [Changelog.md](https://github.com/nymtech/nym/blob/nym-binaries-v2024.3-eclipse/CHANGELOG.md)
|
||||
- [`nym-node`](nodes/nym-node.md) initial release
|
||||
- New tool for monitoring Gateways performance [harbourmaster.nymtech.net](https://harbourmaster.nymtech.net)
|
||||
- New versioning `1.1.0+nymnode` mainly for internal migration testing, not essential for operational use. We aim to correct this in a future release to ensure mixnodes feature correctly in the main API
|
||||
- New [VPS specs & configuration](nodes/vps-setup.md) page
|
||||
- New [configuration page](nodes/configuration.md) with [connectivity setup guide](nodes/configuration.md#connectivity-test-and-configuration) - a new requirement for `exit-gateway`
|
||||
- API endpoints redirection: Nym-mixnode and nym-gateway endpoints will eventually be deprecated; due to this, their endpoints will be redirected to new routes once the `nym-node` has been migrated and is running
|
||||
|
||||
**API endpoints redirection**
|
||||
|
||||
| Previous endpoint | New endpoint |
|
||||
| --- | --- |
|
||||
| `http://<IP>:8000/stats` | `http://<IP>:8000/api/v1/metrics/mixing` |
|
||||
| `http://<IP>:8000/hardware` | `http://<IP>:8000/api/v1/system-info` |
|
||||
| `http://<IP>:8000/description` | `http://<IP>:8000/api/v1/description` |
|
||||
@@ -1,42 +0,0 @@
|
||||
# General Operators FAQ
|
||||
|
||||
## Nym Mixnet
|
||||
|
||||
To see different stats about Nym Mixnet live, we recommend you to visit [status.notrustverify.ch](https://status.notrustverify.ch/d/CW3L7dVVk/nym-mixnet?orgId=1) built by [No Trust Verify](https://notrustverify.ch/) crew, one of the squads within Nym core community.
|
||||
|
||||
<iframe src="https://status.notrustverify.ch/d-solo/CW3L7dVVk/nym-mixnet?orgId=1&from=1702215592419&to=1704807592419&panelId=12" width="800" height="400" frameborder="0"></iframe>
|
||||
|
||||
|
||||
### Is there an explorer for Nym Mixnet?
|
||||
|
||||
Yes, there are several places, some are built by Nym core community:
|
||||
|
||||
* [Nym Explorer](https://explorer.nymtech.net/)
|
||||
* [Guru Explorer](https://mixnet.explorers.guru/)
|
||||
* [ExploreNYM](https://explorenym.net/)
|
||||
|
||||
### Which VPS providers would you recommend?
|
||||
|
||||
Consider in which jurisdiction you reside and where do you want to run a Mix Node. Do you want to pay by crypto or not and what are the other important particularities for your case? We always recommend operators to try to choose smaller and decentralised VPS providers over the most known ones controlling a majority of the internet. We receive some good feedback on these: Linode, Gandi, Flokinet and Exoscale. Do your own research and share with the community.
|
||||
|
||||
### Why is a node setup on a self-hosted machine so tricky?
|
||||
|
||||
We don't recommend this setup because it's really difficult to get a static IP and route IPv6 traffic.
|
||||
|
||||
### What's the Sphinx packet size?
|
||||
|
||||
The sizes are shown in the configs [here](https://github.com/nymtech/nym/blob/1ba6444e722e7757f1175a296bed6e31e25b8db8/common/nymsphinx/params/src/packet_sizes.rs#L12) (default is the one clients use, the others are for research purposes, not to be used in production as this would fragment the anonymity set). More info can be found [here](https://github.com/nymtech/nym/blob/4844ac953a12b29fa27688609ec193f1d560c996/common/nymsphinx/anonymous-replies/src/reply_surb.rs#L80).
|
||||
|
||||
### Why a Mix Node and a Gateway cannot be bonded with the same wallet?
|
||||
|
||||
Because of the way the smart contract works we keep it one-node one-address at the moment.
|
||||
|
||||
### Which nodes are the most needed to be setup to strengthen Nym infrastructure and which ones bring rewards?
|
||||
|
||||
Ath this point the most crutial component needed are [Exit Gateways](../legal/exit-gateway.md).
|
||||
|
||||
### Are Nym Nodes whitelisted?
|
||||
|
||||
Nope, anyone can run a Nym Node. whether your node is chosen to mix is purely reliant on the node's performance and reputation (self stake + delegations).
|
||||
|
||||
|
||||
+2
-5
@@ -1,9 +1,5 @@
|
||||
# Frequently Asked Questions
|
||||
|
||||
```admonish warning
|
||||
**This is an archived page for backwards compatibility. The content of this page is not updated since April 19th 2024. Eventually this page will be terminated!**
|
||||
```
|
||||
|
||||
## Nym Mixnet
|
||||
|
||||
To see different stats about Nym Mixnet live, we recommend you to visit [status.notrustverify.ch](https://status.notrustverify.ch/d/CW3L7dVVk/nym-mixnet?orgId=1) built by [No Trust Verify](https://notrustverify.ch/) crew, one of the squads within Nym core community.
|
||||
@@ -36,6 +32,7 @@ The rewarded nodes are the nodes which will receive some rewards by the end of t
|
||||
|
||||
2. Standby: Bottom *N* nodes of the rewarded set, they don't mix data from the clients but are used for testing. Their reward is smaller.
|
||||
|
||||
|
||||
For more detailed calculation, read our blog post [Nym Token Economics update](https://blog.nymtech.net/nym-token-economics-update-fedff0ed5267). More info on staking can be found [here](https://blog.nymtech.net/staking-in-nym-introducing-mainnet-mixmining-f9bb1cbc7c36). And [here](https://blog.nymtech.net/want-to-stake-in-nym-here-is-how-to-choose-a-mix-node-to-delegate-nym-to-c3b862add165) is more info on how to choose a Mix Node for delegation. And finally an [update](https://blog.nymtech.net/quarterly-token-economic-parameter-update-b2862948710f) on token economics from July 2023.
|
||||
|
||||
<iframe src="https://status.notrustverify.ch/d-solo/CW3L7dVVk/nym-mixnet?orgId=1&from=1703074829887&to=1705666829887&panelId=31" width="850" height="400" frameborder="0"></iframe>
|
||||
@@ -60,7 +57,7 @@ Because of the way the smart contract works we keep it one-node one-address at t
|
||||
|
||||
### Which nodes are the most needed to be setup to strengthen Nym infrastructure and which ones bring rewards?
|
||||
|
||||
Ath this point the most crutial component needed are [Exit Gateways](../../legal/exit-gateway.md).
|
||||
Ath this point the most crutial component needed are [Exit Gateways](../legal/exit-gateway.md).
|
||||
|
||||
### Are Mix Nodes whitelisted?
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
# Nym Nodes related Frequently Asked Questions
|
||||
|
||||
### What determines the rewards when running a `nym-node --mode mixnode`?
|
||||
|
||||
The stake required for a Mix Node to achieve maximum rewards is called Mix Node saturation point. This is calculated from the staking supply (all circulating supply + part of unlocked tokens). The target level of staking is to have 40% of the staking supply locked in Mix Nodes.
|
||||
|
||||
The node stake saturation point, which we denote by Nsat, is given by the stake supply, target level of staking divided between the rewarded nodes.
|
||||
|
||||
This design ensures the nodes aim to have a same size of stake (reputation) which can be done by delegation staking, as well as it secures a whale prevention and decentralization of staking, as any higher level of delegated $NYM than Nsat per node results in worsening reward ratio. On the contrary, the more Mix Nodes are active, the lower is Nsat. The equilibrium is reached when the staked tokens are delegated equally across the active Mix nodes and that's our basis for this incentive system.
|
||||
|
||||
<!--
|
||||
<iframe src="https://status.notrustverify.ch/d-solo/CW3L7dVVk/nym-mixnet?orgId=1&from=1703074760986&to=1705666760986&panelId=5" width="800" height="400" frameborder="0"></iframe>
|
||||
-->
|
||||
|
||||
The rewarded nodes are the nodes which will receive some rewards by the end of the given epoch. These can be separated further separated into:
|
||||
|
||||
1. Active: Top *N* nodes of the rewarded set (currently all of them but this can change), these are nodes which are used by the clients and mix packets.
|
||||
|
||||
2. Standby: Bottom *N* nodes of the rewarded set, they don't mix data from the clients but are used for testing. Their reward is smaller.
|
||||
|
||||
|
||||
For more detailed calculation, read our blog post [Nym Token Economics update](https://blog.nymtech.net/nym-token-economics-update-fedff0ed5267). More info on staking can be found [here](https://blog.nymtech.net/staking-in-nym-introducing-mainnet-mixmining-f9bb1cbc7c36). And [here](https://blog.nymtech.net/want-to-stake-in-nym-here-is-how-to-choose-a-mix-node-to-delegate-nym-to-c3b862add165) is more info on how to choose a Mix Node for delegation. And finally an [update](https://blog.nymtech.net/quarterly-token-economic-parameter-update-b2862948710f) on token economics from July 2023.
|
||||
|
||||
<!--
|
||||
<iframe src="https://status.notrustverify.ch/d-solo/CW3L7dVVk/nym-mixnet?orgId=1&from=1703074829887&to=1705666829887&panelId=31" width="850" height="400" frameborder="0"></iframe>
|
||||
-->
|
||||
|
||||
<iframe src="https://dashboard.notrustverify.ch/d-solo/l71MWkX7k/ntv-mixnode?orgId=1&from=1710949572440&to=1713537972440&panelId=18" width="850" height="400" frameborder="0"></iframe>
|
||||
|
||||
*More graphs and stats at [stats.notrustverify.ch](https://status.notrustverify.ch/d/CW3L7dVVk/nym-mixnet?orgId=1&from=1703074861988&to=1705666862004).*
|
||||
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
## Validators and tokens
|
||||
|
||||
### What's the difference between NYM and uNYM?
|
||||
|
||||
1 NYM = 1 000 000 uNYM
|
||||
|
||||
<!--- Commenting for now as NYX is not publicly out yet
|
||||
### What's the difference between NYM and NYX?
|
||||
--->
|
||||
|
||||
### Why some Nyx blockchain operations take one hour and others are instant?
|
||||
|
||||
This is based on the definition in [Nym's CosmWasm](https://github.com/nymtech/nym/tree/develop/common/cosmwasm-smart-contracts) smart contracts code.
|
||||
|
||||
Whatever is defined as [a pending epoch event](https://github.com/nymtech/nym/blob/b07627d57e075b6de35b4b1a84927578c3172811/common/cosmwasm-smart-contracts/mixnet-contract/src/pending_events.rs#L35-L103) will get resolved at the end of the current epoch.
|
||||
|
||||
And whatever is defined as [a pending interval event](https://github.com/nymtech/nym/blob/b07627d57e075b6de35b4b1a84927578c3172811/common/cosmwasm-smart-contracts/mixnet-contract/src/pending_events.rs#L145-L172) will get resolved at the end of the current interval.
|
||||
|
||||
### Can I run a validator?
|
||||
|
||||
We are currently working towards building up a closed set of reputable validators. You can ask us for coins to get in, but please don't be offended if we say no - validators are part of our system's core security and we are starting out with people we already know or who have a solid reputation.
|
||||
|
||||
### Why is validator set entry whitelisted?
|
||||
|
||||
We understand that the early days of the Nyx blockchain will face possible vulnerabilities in terms of size - easy to disrupt or halt the chain if a malicious party entered with a large portion of stake. Besides that, there are some legal issues we need to address before we can distribute the validator set in a fully permissions fashion.
|
||||
|
||||
### Why does Nym do airdrops?
|
||||
|
||||
It is part of ensuring decentralisation - we need to avoid a handful of people having too much control over the token and market. Of course ideally people will stake the tokens and contribute to the project at this stage. We run surveys to better understand what people are doing with their tokens and what usability issues there are for staking. Any feedback is appreciated as it helps us improve all aspects of using the token and participating in the ecosystem.
|
||||
+28
-22
@@ -1,32 +1,37 @@
|
||||
# Project Smoosh - FAQ
|
||||
|
||||
```admonish warning
|
||||
**This is an archived page for backwards compatibility. We have switched to [`nym-node` binary](../../nodes/nym-node.md), please [migrate](../../nodes/setup.md#migrate) your nodes. The content of this page is not updated since April 26th 2024. Eventually this page will be terminated!**
|
||||
```
|
||||
|
||||
> We aim on purpose to make minimal changes to reward scheme and software. We're just 'smooshing' together stuff we already debugged and know works.
|
||||
> -- Harry Halpin, Nym CEO
|
||||
> We aim on purpose to make minimal changes to reward scheme and software. We're just 'smooshing' together stuff we already debugged and know works.
|
||||
> -- Harry Halpin, Nym CEO
|
||||
|
||||
<br>
|
||||
|
||||
This page refer to the changes which are planned to take place over Q3 and Q4 2023. As this is a transition period in the beginning (Q3 2023) the [Mix Nodes FAQ page](mixnodes-faq.md) holds more answers to the current setup as project Smoosh refers to the eventual setup. As project Smoosh gets progressively implemented the answers on this page will become to be more relevant to the current state and eventually this FAQ page will be merged with the still relevant parts of the main Mix Nodes FAQ page.
|
||||
This page refer to the changes which are planned to take place over Q3 and Q4 2023. As this is a transition period in the beginning (Q3 2023) the [Mix Nodes FAQ page](mixnodes-faq.md) holds more answers to the current setup as project Smoosh refers to the eventual setup. As project Smoosh gets progressively implemented the answers on this page will become to be more relevant to the current state and eventually this FAQ page will be merged with the still relevant parts of the main Mix Nodes FAQ page.
|
||||
|
||||
If any questions are not answered or it's not clear for you in which stage project Smoosh is right now, please reach out in Node Operators [Matrix room](https://matrix.to/#/#operators:nymtech.chat).
|
||||
|
||||
## Overview
|
||||
|
||||
### What is project Smoosh?
|
||||
|
||||
As we shared in our blog post article [*What does it take to build the wolds most powerful VPN*](https://blog.nymtech.net/what-does-it-take-to-build-the-worlds-most-powerful-vpn-d351a76ec4e6), project Smoosh is:
|
||||
|
||||
> A nick-name by CTO Dave Hrycyszyn and Chief Scientist Claudia Diaz for the work they are currently doing to “smoosh” Nym Nodes so that the same operator can serve alternately as Mix Node, Gateway or VPN node. This requires careful calibration of the Nym token economics, for example, only nodes with the highest reputation for good quality service will be in the VPN set and have the chance to earn higher rewards.
|
||||
> By simplifying the components, adding VPN features and supporting new node operators, the aim is to widen the geographical coverage of nodes and have significant redundancy, meaning plenty of operators to be able to meet demand. This requires strong token economic incentives as well as training and support for new node operators.
|
||||
|
||||
## Technical Questions
|
||||
|
||||
### What are the changes?
|
||||
|
||||
Project Smoosh will have four steps, please follow the table below to track the dynamic progress:
|
||||
|
||||
| **Step** | **Status** |
|
||||
| :--- | :--- |
|
||||
| **1.** Combine the `nym-gateway` and `nym-network-requester` into one binary | ✅ done |
|
||||
| **2.** Create [Exit Gateway](../../legal/exit-gateway.md): Take the `nym-gateway` binary including `nym-network-requester` combined in \#1 and switch from [`allowed.list`](https://nymtech.net/.wellknown/network-requester/standard-allowed-list.txt) to a new [exit policy](https://nymtech.net/.wellknown/network-requester/exit-policy.txt) | ✅ done |
|
||||
| **3.** Combine all the nodes in the Nym Mixnet into one binary, that is `nym-mixnode`, `nym-gateway` (entry and exit) and `nym-network-requester`. | ✅ done |
|
||||
| **4.** Adjust reward scheme to incentivise and reward Exit Gateways as a part of `nym-node` binary, implementing [zkNym credentials](https://youtu.be/nLmdsZ1BsQg?t=1717). | 🛠️ in progress |
|
||||
| **5.** Implement multiple node functionalities into one `nym-node` connected to one Nyx account. | 🛠️ in progress |
|
||||
| **Step** | **Status** |
|
||||
| :--- | :--- |
|
||||
| **1.** Combine the `nym-gateway` and `nym-network-requester` into one binary | ✅ done |
|
||||
| **2.** Create [Exit Gateway](../legal/exit-gateway.md): Take the `nym-gateway` binary including `nym-network-requester` combined in \#1 and switch from [`allowed.list`](https://nymtech.net/.wellknown/network-requester/standard-allowed-list.txt) to a new [exit policy](https://nymtech.net/.wellknown/network-requester/exit-policy.txt) | ✅ done |
|
||||
| **3.** Combine all the nodes in the Nym Mixnet into one binary, that is `nym-mixnode`, `nym-gateway` (entry and exit) and `nym-network-requester`. | 🛠️ in progress |
|
||||
| **4.** Adjust reward scheme to incentivise and reward Exit Gateways as a part of `nym-node` binary, implementing [zkNym credentials](https://youtu.be/nLmdsZ1BsQg?t=1717). | 🛠️ in progress |
|
||||
|
||||
These steps will be staggered over time - period of several months, and will be implemented one by one with enough time to take in feedback and fix bugs in between.
|
||||
These steps will be staggered over time - period of several months, and will be implemented one by one with enough time to take in feedback and fix bugs in between.
|
||||
Generally, the software will be the same, just instead of multiple binaries, there will be one Nym Node (`nym-node`) binary. Delegations will remain on as they are now, per our token economics (staking, saturation etc)
|
||||
|
||||
### What does it mean for Nym nodes operators?
|
||||
@@ -39,7 +44,7 @@ We are exploring two potential methods for implementing binary functionality in
|
||||
|
||||
### Where can I read more about the Exit Gateway setup?
|
||||
|
||||
We created an [entire page](../../legal/exit-gateway.md) about the technical and legal questions around Exit Gateway.
|
||||
We created an [entire page](../legal/exit-gateway.md) about the technical and legal questions around Exit Gateway.
|
||||
|
||||
### What is the change from allow list to deny list?
|
||||
|
||||
@@ -52,8 +57,8 @@ Follow the dynamic progress of exit policy implementation on Gateways below:
|
||||
| **Step** | **Status** |
|
||||
| :--- | :--- |
|
||||
| **1.** By default the [exit policy](https://nymtech.net/.wellknown/network-requester/exit-policy.txt) filtering is disabled and the [`allowed.list`](https://nymtech.net/.wellknown/network-requester/standard-allowed-list.txt) filtering is going to continue be used. This is to prevent operators getting surprised by upgrading their Gateways (or Network Requesters) and suddenly be widely open to the internet. To enable the new exit policy, operators must use `--with-exit-policy` flag or modify the `config.toml` file. | ✅ done |
|
||||
| **2.** The exit policy is part of the Gateway setup by default. To disable this exit policy, operators must use `--disable-exit-policy` flag. | ✅ done |
|
||||
| **3.** The exit policy is the only option. The `allowed.list` is completely removed. | ✅ done |
|
||||
| **2.** The exit policy is part of the Gateway setup by default. To disable this exit policy, operators must use `--disable-exit-policy` flag. | 🛠️ in progress |
|
||||
| **3.** The exit policy is the only option. The `allowed.list` is completely removed. | 🛠️ in progress |
|
||||
|
||||
Keep in mind the table above only relates to changes happening on Gateways. For the Project Smoosh progress refer to the [table above](./smoosh-faq.md#what-are-the-changes). Whether Exit Gateway functionality will be optional or mandatory part of every active Nym Node depends on the chosen [design](./smoosh-faq.md#what-does-it-mean-for-nym-nodes-operators).
|
||||
|
||||
@@ -81,9 +86,9 @@ This depends on [design](./smoosh-faq.md#what-does-it-mean-for-nym-nodes-operato
|
||||
|
||||
As each operator can choose what roles their nodes provide, the nodes which work as open Gateways will have higher rewards because they are the most important to keep up and stable. Besides that the operators of Gateways may be exposed to more complication and possible legal risks.
|
||||
|
||||
The nodes which are initialized to run as Mix Nodes and Gateways will be chosen to be on top of the active set before the ones working only as a Mix Node.
|
||||
The nodes which are initialized to run as Mix Nodes and Gateways will be chosen to be on top of the active set before the ones working only as a Mix Node.
|
||||
|
||||
I case we go with \#2, all nodes active in the epoch will be rewarded proportionally according their work.
|
||||
I case we go with \#2, all nodes active in the epoch will be rewarded proportionally according their work.
|
||||
|
||||
In either way, Nym will share all the specifics beforehand.
|
||||
|
||||
@@ -103,6 +108,7 @@ From an operator standpoint, it shall just be a standard Nym upgrade, a new opti
|
||||
|
||||
### Are there any legal concerns for the operators?
|
||||
|
||||
So far the general line is that running a Gateway is not illegal (unless you are in Iran, China, and a few other places) and due to encryption/mixing less risky than running a normal VPN node. For Mix Nodes, it's very safe as they have "no idea" what packets they are mixing.
|
||||
So far the general line is that running a Gateway is not illegal (unless you are in Iran, China, and a few other places) and due to encryption/mixing less risky than running a normal VPN node. For Mix Nodes, it's very safe as they have "no idea" what packets they are mixing.
|
||||
|
||||
There are several legal questions and analysis to be made for different jurisdictions. To be able to share resources and findings between the operators themselves we created a [Community Legal Forum](../legal/exit-gateway.md).
|
||||
|
||||
There are several legal questions and analysis to be made for different jurisdictions. To be able to share resources and findings between the operators themselves we created a [Community Legal Forum](../../legal/exit-gateway.md).
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 21 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 20 KiB |
@@ -1,45 +1,25 @@
|
||||
# Introduction
|
||||
|
||||
This is Nym's Operators guide, containing information and setup guides for the various pieces of Nym Mixnet infrastructure and Nyx blockchain validators.
|
||||
This is Nym's Operators guide, containing information and setup guides for the various pieces of Nym Mixnet infrastructure (Mix Node, Gateway and Network Requester) and Nyx blockchain validators.
|
||||
|
||||
```
|
||||
┌─►mix──┐ mix mix
|
||||
│ │
|
||||
Entry │ │ Exit
|
||||
client ───► Gateway ──┘ mix │ mix ┌─►mix ───► Gateway ───► internet
|
||||
│ │
|
||||
│ │
|
||||
mix └─►mix──┘ mix
|
||||
```
|
||||
|
||||
If you are new to Nym and want to learn about the Mixnet, explore kickstart options and demos, learn how to integrate with the network, and follow developer tutorials check out the [Developer Portal](https://nymtech.net/developers/).
|
||||
If you are new to Nym and want to learn about the mixnet, explore kickstart options and demos, learn how to integrate with the network, and follow developer tutorials check out the [Developer Portal](https://nymtech.net/developers/).
|
||||
|
||||
If you want to dive deeper into Nym's architecture, clients, nodes, and SDK examples visit the [technical docs](https://nymtech.net/docs/).
|
||||
|
||||
|
||||
## Popular pages
|
||||
|
||||
**Binary Information**
|
||||
|
||||
* [Building Nym](binaries/building-nym.md)
|
||||
* [Pre-built Binaries](binaries/pre-built-binaries.md)
|
||||
|
||||
**Node setup and usage guides:**
|
||||
|
||||
* [Nym Node](nodes/nym-node.md)
|
||||
* [Nymvisor](nodes/nymvisor-upgrade.md)
|
||||
* [Mix nodes](nodes/mix-node-setup.md)
|
||||
* [Gateways](nodes/gateway-setup.md)
|
||||
* [Network requesters](nodes/network-requester-setup.md)
|
||||
* [Validators](nodes/validator-setup.md)
|
||||
* [Nym API Setup](nodes/nym-api.md)
|
||||
|
||||
**Maintenance, troubleshooting and FAQ**
|
||||
|
||||
* [FAQ](faq/nym-nodes-faq.md)
|
||||
* [Maintenance](nodes/maintenance.md)
|
||||
* [Troubleshooting](troubleshooting/nodes.md)
|
||||
|
||||
**Community Legal Forum**
|
||||
|
||||
* [Exit Gateway](legal/exit-gateway.md)
|
||||
* [Community Counsel](legal/community-counsel.md)
|
||||
* [How to Add Info](legal/add-content.md)
|
||||
* [Troubleshooting](nodes/troubleshooting.md)
|
||||
* [FAQ](faq/mixnodes-faq.md)
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ This page is a part of Nym Community Legal Forum and its content is composed by
|
||||
|
||||
This document presents an initiative to further support Nym’s mission of allowing privacy for everyone everywhere. This would be achieved with the support of Nym node operators operating Gateways and opening these to any online service. Such setup needs a **clear policy**, one which will remain the **same for all operators** running Nym nodes. The [proposed **Exit policy**](https://nymtech.net/.wellknown/network-requester/exit-policy.txt) is a combination of two existing safeguards: [Tor Null ‘deny’ list](https://tornull.org/) and [Tor reduced policy](https://tornull.org/tor-reduced-reduced-exit-policy.php).
|
||||
|
||||
All the technical changes on the side of Nym nodes - ***Project Smoosh*** - are described in the [FAQ section](../archive/faq/smoosh-faq.md).
|
||||
All the technical changes on the side of Nym nodes - ***Project Smoosh*** - are described in the [FAQ section](../faq/smoosh-faq.md).
|
||||
|
||||
```admonish warning
|
||||
Nym core team cannot provide comprehensive legal advice across all jurisdictions. Knowledge and experience with the legalities are being built up with the help of our counsel and with you, the community of Nym node operators. We encourage Nym node operators to join the operator channels ([Element](https://matrix.to/#/#operators:nymtech.chat), [Discord](https://discord.com/invite/nym), [Telegram](https://t.me/nymchan_help_chat)) to share best practices and experiences.
|
||||
|
||||
@@ -10,4 +10,360 @@ Exit Gateway landing page is a great and transparent way to prevent possible tro
|
||||
|
||||
## Avril 14th Exit Gateways
|
||||
|
||||
Visit [Reversed Proxy: Avril 14th Exit Gateways Guide](../nodes/proxy-configuration.md#reversed-proxy-avril-14th-exit-gateways-guide) and follow the guide to setup your landing page.
|
||||
The following snippet needs be modified as described below according to the public identity that you may want to show on this public notice, i.e. your graphics and your email.
|
||||
It would allow you to serve it as a landing page resembling the one proposed by [Tor](https://gitlab.torproject.org/tpo/core/tor/-/raw/HEAD/contrib/operator-tools/tor-exit-notice.html) but with all the changes needed to adhere to the Nym's operators case.
|
||||
|
||||
[Avril 14th](https://avril14th.org/) is a team of professionals and optimistic realists eager to contribute to a future of privacy, decentralization and connectivity.
|
||||
|
||||
When done with the customization needs as described below, you'll need to upload the file and reference it as the `landing_page_assets_path` on the `[http]` section of the config.toml file:
|
||||
```
|
||||
landing_page_assets_path = '<PATH_TO_YOUR_CUSTOM_FILE>'
|
||||
```
|
||||
|
||||
### HTML file customization
|
||||
|
||||
- add your favicon logo on the line:
|
||||
```
|
||||
<link rel="icon" type="image/png" href="">
|
||||
```
|
||||
|
||||
and your header logo on the line:
|
||||
```
|
||||
<img class="logo" src="<FIXME>">
|
||||
```
|
||||
|
||||
by either setting the URl to the image (if you're hosting it publicly, i.e. on your web server)
|
||||
```
|
||||
href="<PATH_TO_YOUR_PUBLIC_URL>"
|
||||
```
|
||||
and
|
||||
```
|
||||
src="<PATH_TO_YOUR_PUBLIC_URL>"
|
||||
|
||||
```
|
||||
**or** by adding the image inline as base64 encoded image
|
||||
```
|
||||
href="href="data:image/x-icon;base64,AAABAAMA....""
|
||||
```
|
||||
and
|
||||
```
|
||||
src="href="data:image/x-icon;base64,AAABAAMA....""
|
||||
```
|
||||
|
||||
|
||||
- add the email address you're willing to use for being contacted.
|
||||
```
|
||||
<a href="mailto:>FIXME>">maintainer</a>
|
||||
```
|
||||
|
||||
- If you're running the node within the US check the sections marked as FIXME, add your DNS name and uncomment those.
|
||||
***
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en-US">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>This is a NYM Exit Gateway</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="icon" type="image/png" href="">
|
||||
<style>
|
||||
:root {
|
||||
font-family: Consolas, "Ubuntu Mono", Menlo, "DejaVu Sans Mono", monospace;
|
||||
}
|
||||
:root{
|
||||
--background-color: #121726;
|
||||
--text-color: #f2f2f2;
|
||||
--link-color: #fb6e4e;
|
||||
}
|
||||
html{
|
||||
background: var(--background-color);
|
||||
}
|
||||
body{
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
padding-left: 5vw;
|
||||
padding-right: 5vw;
|
||||
max-width: 1000px;
|
||||
}
|
||||
h1{
|
||||
font-size: 55px;
|
||||
text-align: center;
|
||||
color: var(--title-color)
|
||||
}
|
||||
p{
|
||||
color: var(--text-color);
|
||||
}
|
||||
p, a{
|
||||
font-size: 20px;
|
||||
}
|
||||
a{
|
||||
color: var(--link-color);
|
||||
text-decoration: none;
|
||||
}
|
||||
a:hover{
|
||||
filter: brightness(.8);
|
||||
text-decoration: underline;
|
||||
}
|
||||
.links{
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-evenly;
|
||||
}
|
||||
.links > a{
|
||||
margin: 10px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
</style>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<h1>This is a NYM Exit Gateway</h1>
|
||||
<p style="text-align:center">
|
||||
<img class="logo" src="<FIXME>">
|
||||
</p>
|
||||
|
||||
<p>
|
||||
You are most likely accessing this website because you've had some issue with
|
||||
the traffic coming from this IP. This router is part of the <a
|
||||
href="https://nymtech.net/">NYM project</a>, which is
|
||||
dedicated to <a href="https://nymtech.net/about/mission">create</a> outstanding
|
||||
privacy software that is legally compliant without sacrificing integrity or
|
||||
having any backdoors.
|
||||
This router IP should be generating no other traffic, unless it has been
|
||||
compromised.</p>
|
||||
|
||||
<p>
|
||||
The Nym mixnet is operated by a decentralised community of node operators
|
||||
and stakers. The Nym mixnet is trustless, meaning that no parts of the system
|
||||
nor its operators have access to information that might compromise the privacy
|
||||
of users. Nym software enacts a strict principle of data minimisation and has
|
||||
no back doors. The Nym mixnet works by encrypting packets in several layers
|
||||
and relaying those through a multi-layered network called a mixnet, eventually
|
||||
letting the traffic exit the Nym mixnet through an exit gateway like this one.
|
||||
This design makes it very hard for a service to know which user is connecting to it,
|
||||
since it can only see the IP-address of the Nym exit gateway:</p>
|
||||
|
||||
<p style="text-align:center;margin:40px 0">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="500" viewBox="0 0 490.28 293.73" style="width:100%;max-width:600px">
|
||||
<desc>Illustration showing how a user might connect to a service through the Nym network. The user first sends their data through three daisy-chained encrypted Nym nodes that exist on three different continents. Then the last Nym node in the chain connects to the target service over the normal internet.</desc>
|
||||
<defs>
|
||||
<style>
|
||||
.t{
|
||||
fill: var(--text-color);
|
||||
stroke: var(--text-color);
|
||||
}
|
||||
</style>
|
||||
</defs>
|
||||
<path fill="#6fc8b7" d="M257.89 69.4c-6.61-6.36-10.62-7.73-18.36-8.62-7.97-1.83-20.06-7.99-24.17-.67-3.29 5.85-18.2 12.3-16.87 2.08.92-7.03 11.06-13.28 17-17.37 8.69-5.99 24.97-2.87 26.1-10.28 1.04-6.86-8.33-13.22-8.55-2.3-.38 12.84-19.62 2.24-8.73-6.2 8.92-6.9 16.05-9.02 25.61-6.15 12.37 4.83 25.58-2.05 33.73-.71 12.37-2.01 24.69-5.25 37.39-3.96 13 .43 24.08-.14 37.06.63 9.8 1.58 16.5 2.87 26.37 3.6 6.6.48 17.68-.82 24.3 1.9 8.3 4.24.44 10.94-6.89 11.8-8.79 1.05-23.59-1.19-26.6 1.86-5.8 7.41 10.75 5.68 11.27 14.54.57 9.45-5.42 9.38-8.72 16-2.7 4.2.3 13.93-1.18 18.45-1.85 5.64-19.64 4.47-14.7 14.4 4.16 8.34 1.17 19.14-10.33 12.02-5.88-3.65-9.85-22.04-15.66-21.9-11.06.27-11.37 13.18-12.7 17.52-1.3 4.27-3.79 2.33-6-.63-3.54-4.76-7.75-14.22-12.01-17.32-6.12-4.46-10.75-1.17-15.55 2.83-5.63 4.69-8.78 7.82-7.46 16.5.78 9.1-12.9 15.84-14.98 24.09-2.61 10.32-2.57 22.12-8.81 31.47-4 5.98-14.03 20.12-21.27 14.97-7.5-5.34-7.22-14.6-9.56-23.08-2.5-9.02.6-17.35-2.57-26.2-2.45-6.82-6.23-14.54-13.01-13.24-6.5.92-15.08 1.38-19.23-2.97-5.65-5.93-6-10.1-6.61-18.56 1.65-6.94 5.79-12.64 10.38-18.63 3.4-4.42 17.45-10.39 25.26-7.83 10.35 3.38 17.43 10.5 28.95 8.57 3.12-.53 9.14-4.65 7.1-6.62zm-145.6 37.27c-4.96-1.27-11.57 1.13-11.8 6.94-1.48 5.59-4.82 10.62-5.8 16.32.56 6.42 4.34 12.02 8.18 16.97 3.72 3.85 8.58 7.37 9.3 13.1 1.24 5.88 1.6 11.92 2.28 17.87.34 9.37.95 19.67 7.29 27.16 4.26 3.83 8.4-2.15 6.52-6.3-.54-4.54-.6-9.11 1.01-13.27 4.2-6.7 7.32-10.57 12.44-16.64 5.6-7.16 12.74-11.75 14-20.9.56-4.26 5.72-13.86 1.7-16.72-3.14-2.3-15.83-4-18.86-6.49-2.36-1.71-3.86-9.2-9.86-12.07-4.91-3.1-10.28-6.73-16.4-5.97zm11.16-49.42c6.13-2.93 10.58-4.77 14.61-10.25 3.5-4.28 2.46-12.62-2.59-15.45-7.27-3.22-13.08 5.78-18.81 8.71-5.96 4.2-12.07-5.48-6.44-10.6 5.53-4.13.38-9.2-5.66-8.48-6.12.8-12.48-1.45-18.6-1.73-5.3-.7-10.13-1-15.45-1.37-5.37-.05-16.51-2.23-25.13.87-5.42 1.79-12.5 5.3-16.73 9.06-4.85 4.2.2 7.56 5.54 7.45 5.3-.22 16.8-5.36 20.16.98 3.68 8.13-5.82 18.29-5.2 26.69.1 6.2 3.37 11 4.74 16.98 1.62 5.94 6.17 10.45 10 15.14 4.7 5.06 13.06 6.3 19.53 8.23 7.46.14 3.34-9.23 3.01-14.11 1.77-7.15 8.49-7.82 12.68-13.5 7.14-7.72 16.41-13.4 24.34-18.62zM190.88 3.1c-4.69 0-13.33.04-18.17-.34-7.65.12-13.1-.62-19.48-1.09-3.67.39-9.09 3.34-5.28 7.04 3.8.94 7.32 4.92 7.1 9.31 1.32 4.68 1.2 11.96 6.53 13.88 4.76-.2 7.12-7.6 11.93-8.25 6.85-2.05 12.5-4.58 17.87-9.09 2.48-2.76 7.94-6.38 5.26-10.33-1.55-1.31-2.18-.64-5.76-1.13zm178.81 157.37c-2.66 10.08-5.88 24.97 9.4 15.43 7.97-5.72 12.58-2.02 17.47 1.15.5.43 2.65 9.2 7.19 8.53 5.43-2.1 11.55-5.1 14.96-11.2 2.6-4.62 3.6-12.39 2.76-13.22-3.18-3.43-6.24-11.03-7.7-15.1-.76-2.14-2.24-2.6-2.74-.4-2.82 12.85-6.04 1.22-10.12-.05-8.2-1.67-29.62 7.17-31.22 14.86z"/>
|
||||
<g fill="none">
|
||||
<path stroke="#cf63a6" stroke-linecap="round" stroke-width="2.76" d="M135.2 140.58c61.4-3.82 115.95-118.83 151.45-103.33"/>
|
||||
<path stroke="#cf63a6" stroke-linecap="round" stroke-width="2.76" d="M74.43 46.66c38.15 8.21 64.05 42.26 60.78 93.92M286.65 37.25c-9.6 39.44-3.57 57.12-35.64 91.98"/>
|
||||
<path stroke="#e4c101" stroke-dasharray="9.06,2.265" stroke-width="2.27" d="M397.92 162.52c-31.38 1.26-90.89-53.54-148.3-36.17"/>
|
||||
<path stroke="#cf63a6" stroke-linecap="round" stroke-width="2.77" d="M17.6 245.88c14.35 0 14.4.05 28-.03"/>
|
||||
<path stroke="#e3bf01" stroke-dasharray="9.06,2.265" stroke-width="2.27" d="M46.26 274.14c-17.52-.12-16.68.08-30.34.07"/>
|
||||
</g>
|
||||
<g transform="translate(120.8 -35.81)">
|
||||
<circle cx="509.78" cy="68.74" r="18.12" fill="#240a3b" transform="translate(-93.3 38.03) scale(.50637)"/>
|
||||
<circle cx="440.95" cy="251.87" r="18.12" fill="#240a3b" transform="translate(-93.3 38.03) scale(.50637)"/>
|
||||
<circle cx="212.62" cy="272.19" r="18.12" fill="#240a3b" transform="translate(-93.3 38.03) scale(.50637)"/>
|
||||
<circle cx="92.12" cy="87.56" r="18.12" fill="#240a3b" transform="translate(-93.3 38.03) scale(.50637)"/>
|
||||
<circle cx="730.88" cy="315.83" r="18.12" fill="#67727b" transform="translate(-93.3 38.03) scale(.50637)"/>
|
||||
<circle cx="-102.85" cy="282.18" r="9.18" fill="#240a3b"/>
|
||||
<circle cx="-102.85" cy="309.94" r="9.18" fill="#67727b"/>
|
||||
</g>
|
||||
<g class="t">
|
||||
<text xml:space="preserve" x="-24.76" y="10.37" stroke-width=".26" font-size="16.93" font-weight="700" style="line-height:1.25" transform="translate(27.79 2.5)" word-spacing="0"><tspan x="-24.76" y="10.37">The user</tspan></text>
|
||||
<text xml:space="preserve" x="150.63" y="196.62" stroke-width=".26" font-size="16.93" font-weight="700" style="line-height:1.25" transform="translate(27.79 2.5)" word-spacing="0"><tspan x="150.63" y="196.62">This server</tspan></text>
|
||||
<text xml:space="preserve" x="346.39" y="202.63" stroke-width=".26" font-size="16.93" font-weight="700" style="line-height:1.25" transform="translate(27.79 2.5)" word-spacing="0"><tspan x="346.39" y="202.63">Your service</tspan></text>
|
||||
<text xml:space="preserve" x="34.52" y="249.07" stroke-width=".26" font-size="16.93" font-weight="700" style="line-height:1.25" transform="translate(27.79 2.5)" word-spacing="0"><tspan x="34.52" y="249.07">Nym network link</tspan></text>
|
||||
<text xml:space="preserve" x="34.13" y="276.05" stroke-width=".26" font-size="16.93" font-weight="700" style="line-height:1.25" transform="translate(27.79 2.5)" word-spacing="0"><tspan x="34.13" y="276.05">Unencrypted link</tspan></text>
|
||||
<path fill="none" stroke-linecap="round" stroke-width="1.67" d="M222.6 184.1c-2.6-15.27 8.95-23.6 18.43-38.86m186.75 45.61c-.68-10.17-9.4-17.68-18.08-23.49"/>
|
||||
<path fill="none" stroke-linecap="round" stroke-width="1.67" d="M240.99 153.41c.35-3.41 1.19-6.17.04-8.17m-7.15 5.48c1.83-2.8 4.58-4.45 7.15-5.48"/>
|
||||
<path fill="none" stroke-linecap="round" stroke-width="1.67" d="M412.43 173.21c-2.2-3.15-2.54-3.85-2.73-5.85m0 0c2.46-.65 3.85.01 6.67 1.24M61.62 40.8C48.89 36.98 36.45 27.54 36.9 18.96M61.62 40.8c.05-2.58-3.58-4.8-5.25-5.26m-2.65 6.04c1.8.54 6.8 1.31 7.9-.78"/>
|
||||
<path fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.44" d="M1.22 229.4h247.74v63.1H1.22z"/>
|
||||
</g>
|
||||
</svg>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<a href="https://nymtech.net/about/mixnet">Read more about how Nym works.</a></p>
|
||||
|
||||
<p>
|
||||
Nym relies on a growing ecosystem of users, developers and researcher partners
|
||||
aligned with the mission to make sure Nym software is running, remains usable
|
||||
and solves real problems. While Nym is not designed for malicious computer
|
||||
users, it is true that they can use the network for malicious ends. This
|
||||
is largely because criminals and hackers have significantly better access to
|
||||
privacy and anonymity than do the regular users whom they prey upon. Criminals
|
||||
can and do build, sell, and trade far larger and more powerful networks than
|
||||
Nym on a daily basis. Thus, in the mind of this operator, the social need for
|
||||
easily accessible censorship-resistant private, anonymous communication trumps
|
||||
the risk of unskilled bad actors, who are almost always more easily uncovered
|
||||
by traditional police work than by extensive monitoring and surveillance anyway.</p>
|
||||
|
||||
<p>
|
||||
In terms of applicable law, the best way to understand Nym is to consider it a
|
||||
network of routers operating as common carriers, much like the Internet
|
||||
backbone. However, unlike the Internet backbone routers, Nym mixnodes do not
|
||||
contain identifiable routing information about the source of a packet and do
|
||||
mix the user internet traffic with that of other users, making communications
|
||||
private and protecting not just the user content but the metadata
|
||||
(user's IP address, who the user talks to, when, where, from what device and
|
||||
more) and no single Nym node can determine both the origin and destination
|
||||
of a given transmission.</p>
|
||||
|
||||
<p>
|
||||
As such, there is little the operator of this Exit Gateway can do to help you
|
||||
track the connection further. This Exit Gateway maintains no logs of any of the
|
||||
Nym mixnet traffic, so there is little that can be done to trace either legitimate or
|
||||
illegitimate traffic (or to filter one from the other). Attempts to
|
||||
seize this router will accomplish nothing.</p>
|
||||
|
||||
<!-- FIXME: US-Only section. Remove if you are a non-US operator -->
|
||||
<!--
|
||||
<p>
|
||||
Furthermore, this machine also serves as a carrier of email, which means that
|
||||
its contents are further protected under the ECPA. <a
|
||||
href="https://www.law.cornell.edu/uscode/text/18/2707">18
|
||||
USC 2707</a> explicitly allows for civil remedies ($1000/account
|
||||
<i>plus</i> legal fees)
|
||||
in the event of a seizure executed without good faith or probable cause (it
|
||||
should be clear at this point that traffic with an originating IP address of
|
||||
FIXME_DNS_NAME should not constitute probable cause to seize the
|
||||
machine). Similar considerations exist for 1st amendment content on this
|
||||
machine.</p>
|
||||
-->
|
||||
<!-- FIXME: May or may not be US-only. Some non-US tor nodes have in
|
||||
fact reported DMCA harassment... -->
|
||||
<!--
|
||||
<p>
|
||||
If you are a representative of a company who feels that this router is being
|
||||
used to violate the DMCA, please be aware that this machine does not host or
|
||||
contain any illegal content. Also be aware that network infrastructure
|
||||
maintainers are not liable for the type of content that passes over their
|
||||
equipment, in accordance with <a
|
||||
href="https://www.law.cornell.edu/uscode/text/17/512">DMCA
|
||||
"safe harbor" provisions</a>. In other words, you will have just as much luck
|
||||
sending a takedown notice to the Internet backbone providers.
|
||||
</p>
|
||||
-->
|
||||
|
||||
<p>To decentralise and enable privacy for a broad range of services, this
|
||||
Exit Gateway adopts an <a href="https://nymtech.net/.wellknown/network-requester/exit-policy.txt">Exit Policy</a>
|
||||
in accordance with the <a href="https://tornull.org/">Tor Null ‘deny’ list</a>
|
||||
and the <a href="https://tornull.org/tor-reduced-reduced-exit-policy.php">Tor reduced policy</a>,
|
||||
which are two established safeguards.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
That being said, if you still have a complaint about the router, you may email the
|
||||
<a href="mailto:>FIXME>">maintainer</a>. If complaints are related
|
||||
to a particular service that is being abused, the maintainer will submit that to the
|
||||
NYM Operators Community in order to add it to the Exit Policy cited above.
|
||||
If approved, that would prevent this router from allowing that traffic to exit through it.
|
||||
That can be done only on an IP+destination port basis, however. Common P2P ports are already blocked.</p>
|
||||
|
||||
<p>
|
||||
You also have the option of blocking this IP address and others on the Nym network if you so desire.
|
||||
The Nym project provides a <a href="https://explorer.nymtech.net/network-components/gateways">
|
||||
web service</a> to fetch a list of all IP addresses of Nym Gateway Exit nodes that allow exiting to a
|
||||
specified IP:port combination. Please be considerate when using these options.</p>
|
||||
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
***
|
||||
### Reverse proxy
|
||||
You may set up a [reverse proxy](https://www.nginx.com/resources/glossary/reverse-proxy-server/) in order to serve this landing page with proper SSL and DNS management, i.e. to resolve it to https://nym-exit.<YOUR_DOMAIN> or https://nym-readme.<YOUR_DOMAIN>.
|
||||
|
||||
The following assumes that you're owning a domain and that you've already set the Let's Encrypt certificates on your hosting, and you've copied those on your Gateway, i.e. copy the two Let's Encript pem files on your Gateway's home folder.
|
||||
Else you may obtain a Let's Encrypt certificate using a -[-certonly procedure](https://eff-certbot.readthedocs.io/en/latest/using.html#getting-certificates-and-choosing-plugins).
|
||||
|
||||
```
|
||||
sudo apt install nginx
|
||||
```
|
||||
If you're running your Gateway (you should...) exposing only the needed ports as listed [here](https://nymtech.net/operators/nodes/maintenance.html?highlight=port#ports), you need to add the Nginx service to your ufw configuration:
|
||||
```
|
||||
sudo ufw app list
|
||||
sudo ufw allow 'Nginx Full'
|
||||
sudo ufw reload
|
||||
```
|
||||
Disable the default Nginx landing page
|
||||
```
|
||||
sudo systemctl status nginx
|
||||
sudo unlink /etc/nginx/sites-enabled/default
|
||||
sudo systemctl restart nginx
|
||||
```
|
||||
Add your endpoint configuration to Nginx changing <YOUR_DOMAIN> occurrencies below with your domain name, including the top-level domain, i.e. *avril4th.org*
|
||||
|
||||
```
|
||||
sudo nano /etc/nginx/sites-available/nym-exit.<YOUR_DOMAIN>
|
||||
```
|
||||
|
||||
```
|
||||
server {
|
||||
listen 443 ssl http2;
|
||||
listen [::]:443 ssl http2;
|
||||
|
||||
server_name nym-exit.<YOUR_DOMAIN>;
|
||||
|
||||
ssl_certificate <PATH_TO>/fullchain.pem;
|
||||
ssl_certificate_key <PATH_TO>/privkey.pem;
|
||||
|
||||
access_log /var/log/nginx/access.log;
|
||||
error_log /var/log/nginx/error.log;
|
||||
|
||||
location / {
|
||||
proxy_pass http://127.0.0.1:8080;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
}
|
||||
}
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
|
||||
if ($host = nym-exit.<YOUR_DOMAIN>) {
|
||||
return 301 https://$host$request_uri;
|
||||
}
|
||||
|
||||
server_name <YOUR_DOMAIN> www.<YOUR_DOMAIN>;
|
||||
|
||||
return 301 https://<YOUR_DOMAIN>$request_uri;
|
||||
}
|
||||
```
|
||||
|
||||
```
|
||||
sudo ln -s /etc/nginx/sites-available/nym-exit.<YOUR_DOMAIN> /etc/nginx/sites-enabled/
|
||||
sudo nginx -t
|
||||
sudo systemctl restart nginx
|
||||
```
|
||||
|
||||
When done with the customization needs as described below, you'll need to upload the file and reference it as the `landing_page_assets_path` on the `[http]` section of the config.toml file that you'll find in the `~/.nym/gateways/<YOUR_GATEWAY_ID>/config/config.toml` file
|
||||
```
|
||||
nano ${HOME}/.nym/gateways/<YOUR_GATEWAY_ID>/config/config.toml
|
||||
```
|
||||
change
|
||||
```
|
||||
landing_page_assets_path = '<PATH_TO_YOUR_CUSTOM_FILE>'
|
||||
```
|
||||
|
||||
If you're running the Gateway as a service as described [here](https://nymtech.net/operators/nodes/maintenance.html#systemd) and [here](https://nymtech.net/operators/nodes/maintenance.html#following-steps-for-nym-nodes-running-as-systemd-service) you may just restart your service
|
||||
```
|
||||
service nym-gateway stop
|
||||
service nym-gateway start
|
||||
```
|
||||
and check for the page being served either checking the service logs
|
||||
```
|
||||
sudo journalctl -u nym-gateway.service | grep 8080
|
||||
```
|
||||
where you should read out
|
||||
```
|
||||
... Started NymNodeHTTPServer on 0.0.0.0:8080
|
||||
```
|
||||
or just point your browser to the URI which you set above, such as https://nym-exit.<YOUR_DOMAIN>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user