Compare commits

..

1 Commits

Author SHA1 Message Date
benedetta davico 8dbcd7d07c TEMP gh runner fix 2024-12-03 10:28:27 +01:00
881 changed files with 18243 additions and 25383 deletions
+1
View File
@@ -4,3 +4,4 @@
**/node_modules
**/target
dist
documentation
@@ -21,7 +21,7 @@ jobs:
strategy:
fail-fast: false
matrix:
platform: [ arc-ubuntu-20.04 ]
platform: [ arc-ubuntu-22.04 ]
runs-on: ${{ matrix.platform }}
env:
+1 -2
View File
@@ -30,11 +30,10 @@ jobs:
strategy:
fail-fast: false
matrix:
os: [ arc-ubuntu-20.04, custom-windows-11, custom-runner-mac-m1 ]
os: [ arc-ubuntu-20.04, custom-runner-mac-m1 ]
runs-on: ${{ matrix.os }}
env:
CARGO_TERM_COLOR: always
IPINFO_API_TOKEN: ${{ secrets.IPINFO_API_TOKEN }}
steps:
- name: Install Dependencies (Linux)
run: sudo apt-get update && sudo apt-get -y install libwebkit2gtk-4.0-dev build-essential curl wget libssl-dev libgtk-3-dev libudev-dev squashfs-tools protobuf-compiler
-1
View File
@@ -15,7 +15,6 @@ jobs:
runs-on: ${{ matrix.os }}
env:
CARGO_TERM_COLOR: always
IPINFO_API_TOKEN: ${{ secrets.IPINFO_API_TOKEN }}
continue-on-error: true
steps:
- name: Check out repository code
@@ -56,6 +56,14 @@ jobs:
rustup target add aarch64-linux-android \
x86_64-linux-android
- name: Build lib nym-socks5-listener
working-directory: sdk/lib/socks5-listener/
env:
RELEASE: true
RUSTFLAGS: "-C link-args=-Wl,--hash-style=gnu"
# build for arm64 and x86_64
run: ./build-android.sh aarch64 x86_64
- name: Build APKs (unsigned)
working-directory: nym-connect/native/android
env:
+1 -1
View File
@@ -26,7 +26,7 @@ jobs:
git config --global user.name "Lawrence Stalder"
- name: Get version from cargo.toml
uses: mikefarah/yq@v4.44.6
uses: mikefarah/yq@v4.44.5
id: get_version
with:
cmd: yq -oy '.package.version' ${{ env.WORKING_DIRECTORY }}/nym-credential-proxy/Cargo.toml
+1 -1
View File
@@ -26,7 +26,7 @@ jobs:
git config --global user.name "Lawrence Stalder"
- name: Get version from cargo.toml
uses: mikefarah/yq@v4.44.6
uses: mikefarah/yq@v4.44.5
id: get_version
with:
cmd: yq -oy '.package.version' ${{ env.WORKING_DIRECTORY }}/Cargo.toml
+1 -1
View File
@@ -26,7 +26,7 @@ jobs:
git config --global user.name "Lawrence Stalder"
- name: Get version from cargo.toml
uses: mikefarah/yq@v4.44.6
uses: mikefarah/yq@v4.44.5
id: get_version
with:
cmd: yq -oy '.package.version' ${{ env.WORKING_DIRECTORY }}/nym-network-monitor/Cargo.toml
@@ -8,7 +8,7 @@ on:
description: Which gateway probe git ref to build the image with
env:
WORKING_DIRECTORY: "nym-node-status-api/nym-node-status-agent"
WORKING_DIRECTORY: "nym-node-status-agent"
CONTAINER_NAME: "node-status-agent"
jobs:
@@ -31,7 +31,7 @@ jobs:
git config --global user.name "Lawrence Stalder"
- name: Get version from cargo.toml
uses: mikefarah/yq@v4.44.6
uses: mikefarah/yq@v4.44.5
id: get_version
with:
cmd: yq -oy '.package.version' ${{ env.WORKING_DIRECTORY }}/Cargo.toml
@@ -58,4 +58,4 @@ jobs:
- name: BuildAndPushImageOnHarbor
run: |
docker build --build-arg GIT_REF=${{ github.event.inputs.gateway_probe_git_ref }} -f ${{ env.WORKING_DIRECTORY }}/Dockerfile . -t harbor.nymte.ch/nym/${{ env.CONTAINER_NAME }}:${{ steps.get_version.outputs.result }}-${{ steps.cleanup_gateway_probe_ref.outputs.git_ref }}
docker push harbor.nymte.ch/nym/${{ env.CONTAINER_NAME }} --all-tags
docker push harbor.nymte.ch/nym/${{ env.CONTAINER_NAME }} --all-tags
+2 -2
View File
@@ -3,7 +3,7 @@ on:
workflow_dispatch:
env:
WORKING_DIRECTORY: "nym-node-status-api/nym-node-status-api"
WORKING_DIRECTORY: "nym-node-status-api"
CONTAINER_NAME: "node-status-api"
jobs:
@@ -26,7 +26,7 @@ jobs:
git config --global user.name "Lawrence Stalder"
- name: Get version from cargo.toml
uses: mikefarah/yq@v4.44.6
uses: mikefarah/yq@v4.44.5
id: get_version
with:
cmd: yq -oy '.package.version' ${{ env.WORKING_DIRECTORY }}/Cargo.toml
+1 -1
View File
@@ -26,7 +26,7 @@ jobs:
git config --global user.name "Lawrence Stalder"
- name: Get version from cargo.toml
uses: mikefarah/yq@v4.44.6
uses: mikefarah/yq@v4.44.5
id: get_version
with:
cmd: yq -oy '.package.version' ${{ env.WORKING_DIRECTORY }}/Cargo.toml
@@ -1,55 +0,0 @@
name: Build and upload Nyx Chain Watcher container to harbor.nymte.ch
on:
workflow_dispatch:
env:
WORKING_DIRECTORY: "nyx-chain-watcher"
CONTAINER_NAME: "nyx-chain-watcher"
jobs:
build-container:
runs-on: arc-ubuntu-22.04-dind
steps:
- name: Login to Harbor
uses: docker/login-action@v3
with:
registry: harbor.nymte.ch
username: ${{ secrets.HARBOR_ROBOT_USERNAME }}
password: ${{ secrets.HARBOR_ROBOT_SECRET }}
- name: Checkout repo
uses: actions/checkout@v4
- name: Configure git identity
run: |
git config --global user.email "lawrence@nymtech.net"
git config --global user.name "Lawrence Stalder"
- name: Get version from cargo.toml
uses: mikefarah/yq@v4.44.6
id: get_version
with:
cmd: yq -oy '.package.version' ${{ env.WORKING_DIRECTORY }}/Cargo.toml
- name: Check if tag exists
run: |
if git rev-parse ${{ steps.get_version.outputs.value }} >/dev/null 2>&1; then
echo "Tag ${{ steps.get_version.outputs.value }} already exists"
fi
- name: Remove existing tag if exists
run: |
if git rev-parse ${{ env.WORKING_DIRECTORY }}-${{ steps.get_version.outputs.result }} >/dev/null 2>&1; then
git push --delete origin ${{ env.WORKING_DIRECTORY }}-${{ steps.get_version.outputs.result }}
git tag -d ${{ env.WORKING_DIRECTORY }}-${{ steps.get_version.outputs.result }}
fi
- name: Create tag
run: |
git tag -a ${{ env.WORKING_DIRECTORY }}-${{ steps.get_version.outputs.result }} -m "Version ${{ steps.get_version.outputs.result }}"
git push origin ${{ env.WORKING_DIRECTORY }}-${{ steps.get_version.outputs.result }}
- name: BuildAndPushImageOnHarbor
run: |
docker build -f ${{ env.WORKING_DIRECTORY }}/Dockerfile . -t harbor.nymte.ch/nym/${{ env.CONTAINER_NAME }}:${{ steps.get_version.outputs.result }} -t harbor.nymte.ch/nym/${{ env.CONTAINER_NAME }}:latest
docker push harbor.nymte.ch/nym/${{ env.CONTAINER_NAME }} --all-tags
@@ -26,10 +26,10 @@ jobs:
git config --global user.name "Lawrence Stalder"
- name: Get version from cargo.toml
uses: mikefarah/yq@v4.44.6
uses: mikefarah/yq@v4.44.5
id: get_version
with:
cmd: yq -oy '.package.version' ${{ env.WORKING_DIRECTORY }}/Cargo.toml
cmd: yq -oy '.package.version' ${{ env.WORKING_DIRECTORY }}/nym-credential-proxy/Cargo.toml
- name: Remove existing tag if exists
run: |
+1 -7
View File
@@ -51,10 +51,4 @@ ppa-private-key.b64
ppa-private-key.asc
nym-network-monitor/topology.json
nym-network-monitor/__pycache__
nym-network-monitor/*.key
nym-network-monitor/.envrc
nym-network-monitor/.envrc
*.sqlite
.build
nym-network-monitor/*.key
-142
View File
@@ -4,148 +4,6 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
## [Unreleased]
## [2024.14-crunch] (2024-12-11)
- Merge/release/2024.14-crunch ([#5242])
- bugfix: added explicit openapi servers to account for route prefixes ([#5237])
- Further config score adjustments ([#5225])
- feature: remve any filtering on node semver ([#5224])
- Backport #5218 ([#5220])
- Derive serialize for UserAgent (#5210) ([#5217])
- dont consider legacy nodes for rewarded set selection ([#5215])
- introduce UNSTABLE endpoints for returning network monitor run details ([#5214])
- Nmv2 add debug config ([#5212])
- nym-api NMv1 adjustments ([#5209])
- adjusted config score penalty calculation ([#5206])
- Fix backwards compat mac generation ([#5202])
- merge crunch into develop ([#5199])
- Update Security disclosure email, public key and policy ([#5195])
- Guard storage access with cache ([#5193])
- chore: apply 1.84 linter suggestions ([#5192])
- improvement: make internal gateway clients use the same topology cache ([#5191])
- Bugfix/credential proxy sequencing ([#5187])
- Add monitor_run and testing_route indexes ([#5182])
- Add indexes to monitor run and testing route ([#5181])
- bugfix: fixed nym-node config migrations (again) ([#5179])
- bugfix: use default value for verloc config when deserialising missing values ([#5177])
- Remove peers with no allowed ip from storage ([#5175])
- Move two minor jobs to free tier github hosted runners ([#5169])
- Add support for DELETE to nym-http-api-client ([#5166])
- Fix env var name ([#5165])
- Add strum::EnumIter for TicketType ([#5164])
- Add export_to_env to NymNetworkDetails ([#5162])
- bugfix: correctly expose ecash-related data on nym-api ([#5155])
- fix: validator-rewarder GH job ([#5151])
- build(deps): bump cross-spawn from 7.0.3 to 7.0.6 in /testnet-faucet ([#5150])
- build(deps): bump mikefarah/yq from 4.44.3 to 4.44.5 ([#5149])
- start session collection for exit gateways ([#5148])
- add version to clientStatsReport ([#5147])
- update serde_json_path due to compilation issue ([#5144])
- chore: remove standalone legacy mixnode/gateway binaries ([#5135])
- [Product Data] Set up country reporting from vpn-client ([#5134])
- removed ci-nym-api-tests.yml which was running outdated (and broken) tests ([#5133])
- CI: reduce jobs running on cluster ([#5132])
- [DOCS/operators]: Release changes v2024.13-magura & Tokenomics pages v1.0 ([#5128])
- NS Agent auth with NS API ([#5127])
- [Product Data] Config deserialization bug fix ([#5126])
- bugfix: don't send empty BankMsg in ecash contract ([#5121])
- [Product data] Data consumption with ecash ticket ([#5120])
- feat: add GH workflow for nym-validator-rewarder ([#5119])
- feat: add Dockerfile and add env vars for clap arguments ([#5118])
- feature: config score ([#5117])
- [Product Data] Add stats reporting configuration in client config ([#5115])
- Correct IPv6 address generation ([#5113])
- feature: rewarding for ticketbook issuance ([#5112])
- Add granular log on nym-node ([#5111])
- Send mixnet packet stats using task client ([#5109])
- Expose time range ([#5108])
- [Product Data] Client-side stats collection ([#5107])
- chore: ecash contract migration to remove unused 'redemption_gateway_share' ([#5104])
- [Product Data] Better unique user count on gateways ([#5084])
- feat: add nym node GH workflow ([#5080])
- IPv6 support for wireguard ([#5059])
- Node Status API ([#5050])
- Authenticator CLI client mode ([#5044])
- Integrate nym-credential-proxy into workspace ([#5027])
- [Product Data] Introduce data persistence on gateways ([#5022])
- Bump the patch-updates group across 1 directory with 10 updates ([#5011])
- build(deps): bump once_cell from 1.19.0 to 1.20.2 ([#4952])
- Create TaskStatusEvent trait instead of piggybacking on Error ([#4919])
- build(deps): bump lazy_static from 1.4.0 to 1.5.0 ([#4913])
- Sync code with .env in build.rs ([#4876])
- build(deps): bump axios from 1.6.0 to 1.7.5 in /nym-api/tests ([#4790])
- Bump elliptic from 6.5.4 to 6.5.7 in /testnet-faucet ([#4768])
[#5242]: https://github.com/nymtech/nym/pull/5242
[#5237]: https://github.com/nymtech/nym/pull/5237
[#5225]: https://github.com/nymtech/nym/pull/5225
[#5224]: https://github.com/nymtech/nym/pull/5224
[#5220]: https://github.com/nymtech/nym/pull/5220
[#5217]: https://github.com/nymtech/nym/pull/5217
[#5215]: https://github.com/nymtech/nym/pull/5215
[#5214]: https://github.com/nymtech/nym/pull/5214
[#5212]: https://github.com/nymtech/nym/pull/5212
[#5209]: https://github.com/nymtech/nym/pull/5209
[#5206]: https://github.com/nymtech/nym/pull/5206
[#5202]: https://github.com/nymtech/nym/pull/5202
[#5199]: https://github.com/nymtech/nym/pull/5199
[#5195]: https://github.com/nymtech/nym/pull/5195
[#5193]: https://github.com/nymtech/nym/pull/5193
[#5192]: https://github.com/nymtech/nym/pull/5192
[#5191]: https://github.com/nymtech/nym/pull/5191
[#5187]: https://github.com/nymtech/nym/pull/5187
[#5182]: https://github.com/nymtech/nym/pull/5182
[#5181]: https://github.com/nymtech/nym/pull/5181
[#5179]: https://github.com/nymtech/nym/pull/5179
[#5177]: https://github.com/nymtech/nym/pull/5177
[#5175]: https://github.com/nymtech/nym/pull/5175
[#5169]: https://github.com/nymtech/nym/pull/5169
[#5166]: https://github.com/nymtech/nym/pull/5166
[#5165]: https://github.com/nymtech/nym/pull/5165
[#5164]: https://github.com/nymtech/nym/pull/5164
[#5162]: https://github.com/nymtech/nym/pull/5162
[#5155]: https://github.com/nymtech/nym/pull/5155
[#5151]: https://github.com/nymtech/nym/pull/5151
[#5150]: https://github.com/nymtech/nym/pull/5150
[#5149]: https://github.com/nymtech/nym/pull/5149
[#5148]: https://github.com/nymtech/nym/pull/5148
[#5147]: https://github.com/nymtech/nym/pull/5147
[#5144]: https://github.com/nymtech/nym/pull/5144
[#5135]: https://github.com/nymtech/nym/pull/5135
[#5134]: https://github.com/nymtech/nym/pull/5134
[#5133]: https://github.com/nymtech/nym/pull/5133
[#5132]: https://github.com/nymtech/nym/pull/5132
[#5128]: https://github.com/nymtech/nym/pull/5128
[#5127]: https://github.com/nymtech/nym/pull/5127
[#5126]: https://github.com/nymtech/nym/pull/5126
[#5121]: https://github.com/nymtech/nym/pull/5121
[#5120]: https://github.com/nymtech/nym/pull/5120
[#5119]: https://github.com/nymtech/nym/pull/5119
[#5118]: https://github.com/nymtech/nym/pull/5118
[#5117]: https://github.com/nymtech/nym/pull/5117
[#5115]: https://github.com/nymtech/nym/pull/5115
[#5113]: https://github.com/nymtech/nym/pull/5113
[#5112]: https://github.com/nymtech/nym/pull/5112
[#5111]: https://github.com/nymtech/nym/pull/5111
[#5109]: https://github.com/nymtech/nym/pull/5109
[#5108]: https://github.com/nymtech/nym/pull/5108
[#5107]: https://github.com/nymtech/nym/pull/5107
[#5104]: https://github.com/nymtech/nym/pull/5104
[#5084]: https://github.com/nymtech/nym/pull/5084
[#5080]: https://github.com/nymtech/nym/pull/5080
[#5059]: https://github.com/nymtech/nym/pull/5059
[#5050]: https://github.com/nymtech/nym/pull/5050
[#5044]: https://github.com/nymtech/nym/pull/5044
[#5027]: https://github.com/nymtech/nym/pull/5027
[#5022]: https://github.com/nymtech/nym/pull/5022
[#5011]: https://github.com/nymtech/nym/pull/5011
[#4952]: https://github.com/nymtech/nym/pull/4952
[#4919]: https://github.com/nymtech/nym/pull/4919
[#4913]: https://github.com/nymtech/nym/pull/4913
[#4876]: https://github.com/nymtech/nym/pull/4876
[#4790]: https://github.com/nymtech/nym/pull/4790
[#4768]: https://github.com/nymtech/nym/pull/4768
## [2024.13-magura-drift] (2024-11-29)
- Optimised syncing bandwidth information to storage
Generated
+430 -315
View File
File diff suppressed because it is too large Load Diff
+19 -13
View File
@@ -61,6 +61,7 @@ members = [
"common/ip-packet-requests",
"common/ledger",
"common/mixnode-common",
"common/models",
"common/network-defaults",
"common/node-tester-utils",
"common/nonexhaustive-delayqueue",
@@ -98,15 +99,17 @@ members = [
"common/wasm/utils",
"common/wireguard",
"common/wireguard-types",
"documentation/autodoc",
# "documentation/autodoc",
"explorer-api",
"explorer-api/explorer-api-requests",
"explorer-api/explorer-client",
"gateway",
"integrations/bity",
"mixnode",
"sdk/ffi/cpp",
"sdk/ffi/go",
"sdk/ffi/shared",
"sdk/lib/socks5-listener",
"sdk/rust/nym-sdk",
"service-providers/authenticator",
"service-providers/common",
@@ -118,14 +121,13 @@ members = [
"nym-credential-proxy/nym-credential-proxy",
"nym-credential-proxy/nym-credential-proxy-requests",
"nym-credential-proxy/vpn-api-lib-wasm",
"nym-data-observatory",
"nym-network-monitor",
"nyx-chain-watcher",
"nym-node",
"nym-node/nym-node-http-api",
"nym-node/nym-node-requests",
"nym-node/nym-node-metrics",
"nym-node-status-api/nym-node-status-agent",
"nym-node-status-api/nym-node-status-api",
"nym-node-status-api/nym-node-status-client",
"nym-node-status-api",
"nym-node-status-agent",
"nym-outfox",
"nym-validator-rewarder",
"tools/echo-server",
@@ -148,21 +150,22 @@ members = [
"tools/internal/contract-state-importer/importer-contract",
"tools/internal/testnet-manager",
"tools/internal/testnet-manager/dkg-bypass-contract",
"common/verloc",
"tools/internal/mixnet-connectivity-check",
]
default-members = [
"clients/native",
"clients/socks5",
"common/models",
"explorer-api",
"gateway",
"mixnode",
"nym-api",
"nym-credential-proxy/nym-credential-proxy",
"nym-data-observatory",
"nym-node",
"nym-node-status-api/nym-node-status-agent",
"nym-node-status-api/nym-node-status-api",
"nym-node-status-api",
"nym-validator-rewarder",
"nyx-chain-watcher",
"nym-node-status-api",
"service-providers/authenticator",
"service-providers/ip-packet-router",
"service-providers/network-requester",
@@ -261,7 +264,6 @@ http-body-util = "0.1"
httpcodec = "0.2.3"
humantime = "2.1.0"
humantime-serde = "1.1.1"
human-repr = "1.1.0"
hyper = "1.4.1"
hyper-util = "0.1"
indicatif = "0.17.8"
@@ -405,7 +407,7 @@ indexed_db_futures = { git = "https://github.com/TiemenSch/rust-indexed-db", bra
js-sys = "0.3.70"
serde-wasm-bindgen = "0.6.5"
tsify = "0.4.5"
wasm-bindgen = "0.2.99"
wasm-bindgen = "0.2.95"
wasm-bindgen-futures = "0.4.45"
wasmtimer = "0.2.0"
web-sys = "0.3.72"
@@ -418,6 +420,10 @@ web-sys = "0.3.72"
[profile.dev.package.sqlx-macros]
opt-level = 3
[profile.release.package.nym-socks5-listener]
strip = true
codegen-units = 1
[profile.release.package.nym-client-wasm]
# lto = true
opt-level = 'z'
+10 -7
View File
@@ -14,7 +14,6 @@ The platform is composed of multiple Rust crates. Top-level executable binary cr
* `nym-socks5-client` - a Socks5 proxy you can run on your machine and use with existing applications.
* `nym-explorer` - a (projected) block explorer and (existing) mixnet viewer.
* `nym-wallet` - a desktop wallet implemented using the [Tauri](https://tauri.studio/en/docs/about/intro) framework.
* `nym-cli` - a tool for interacting with the network from the CLI.
<!-- coming soon
* `nym-network-monitor` - sends packets through the full system to check that they are working as expected, and stores node uptime histories as the basis of a rewards system ("mixmining" or "proof-of-mixing").
-->
@@ -36,20 +35,24 @@ client ───► Gateway ──┘ mix │ mix ┌─►mix ───►
### Building
* Platform build instructions are available on Nym [Operators Guide documentation](https://nymtech.net/operators/binaries/building-nym.html).
* Wallet build instructions are available [here](https://github.com/nymtech/nym/tree/master/nym-wallet#installation-prerequisites---linux--mac).
* Wallet build instructions are available on Nym [Technical docs](https://nymtech.net/docs/wallet/desktop-wallet.html).
### Developing
There's a [`sandbox.env`](https://github.com/nymtech/nym/envs/sandbox.env) file provided which you can rename to `.env` if you want convenient testing environment. Read more about sandbox environment in our [Operators Guide page](https://nymtech.net/operators/sandbox.html).
References for developers:
* [Dev Docs](https://nymtech.net/docs/developers)
* [SDKs](https://nymtech.net/docs/developers/rust)
* [Network Docs](https://nymtech.net/docs/network)
* [Release Cycle - git flow](https://nymtech.net/docs/operators/release-cycle)
* [Developers Portal](https://nymtech.net/developers)
* [Typescript SDKs](https://sdk.nymtech.net/)
* [Technical Documentation - Nym network overview](https://nymtech.net/docs/)
* [Release Cycle - git flow](https://nymtech.net/operators/release-cycle.html)
### Developer chat
You can chat to us in the #dev channel on [Matrix](https://matrix.to/#/#dev:nymtech.chat) or on the [Nym Forum](https://forum.nymtech.net).
You can chat to us in two places:
* The #dev channel on [Matrix](https://matrix.to/#/#dev:nymtech.chat)
* The various developer channels on [Discord](https://nymtech.net/go/discord)
### Tokenomics & Rewards
+56 -68
View File
@@ -3,23 +3,37 @@ Critical bug or security issue 💥
If you're here because you're trying to figure out how to notify us of a security issue, send us a PGP encrypted email to:
```
security@nym.com
security@nymte.ch
```
Encrypted with our public key which is available below in plain text and also on keyservers:
```
sec rsa4096/7C3C727F05090550 2023-10-30 [SC] [expire : 2026-10-29]
pub rsa4096 2023-10-30 [SC] [expire : 2026-10-29]
24B2592E801A5AAA8666C8BA7C3C727F05090550
uid [ ultime ] Security Nym Technologies <security@nym.com>
ssb rsa4096/ACD0FBD79DC70ACC 2023-10-30 [E] [expire : 2026-10-29]
uid [ ultime ] Security Nym Technologies <security@nymte.ch>
sub rsa4096 2023-10-30 [E] [expire : 2026-10-29]
```
The fingerprint of the key is on the second line above.
If you need to chat __urgently__ to our team for a __critical__ security issue:
go to Matrix, and alert the core engineers with a private direct message:
Jedrzej Stuczynski @jstuczyn:nymtech.chat
Mark Sinclair @mark:nymtech.chat
Raphaël Walther @raphael:nymtech.chat
Please avoid opening public issues on GitHub that contain information about a potential security vulnerability as this makes it difficult to reduce the impact and harm of valid security issues.
If you don't know what Matrix is, you can follow this documentation to create an account on this federation of instant messaging servers:
[Matrix for Instant Messaging](https://matrix.org/docs/chat_basics/matrix-for-im/)
```
-----BEGIN PGP PUBLIC KEY BLOCK-----
@@ -34,69 +48,43 @@ vMFUIzBMHOPXH16036zGyFMC1esRd2qqil4b9KtLgCOkrD1VgpjcveoA0VyMJCN6
LmKTrVjwjjDMxby+d49BolRWGnCofXozXwvNQx+CYv8M2WPErTpyYoofYFtpqr7A
fIufc/e0+um3zoGIbHejrhsbuH9Qf+MKsI+Ng93bdDtjeHz6MEgAlsTm0qeizYpj
IyKZIObPmfvrAm08hFZ8JnGk+XuooF36XWbJYjCCy0bOyMw1r7ZG99TcSwARAQAB
tCxTZWN1cml0eSBOeW0gVGVjaG5vbG9naWVzIDxzZWN1cml0eUBueW0uY29tPokC
VAQTAQoAPhYhBCSyWS6AGlqqhmbIunw8cn8FCQVQBQJnSd5VAhsDBQkFo5qABQsJ
CAcDBRUKCQgLBRYCAwEAAh4BAheAAAoJEHw8cn8FCQVQPPIP/ipGz2zLAjE2dSE3
VcqOvras0DfqIL9HDm26Dg6QO2D/4YRntw0RqVyuy+zFnRUm+RZCKLPLUzbQ9Wjb
G/Og5ttQVYQMu5eKu7OMvXkrbRo3teZFU+8IL08zIW6pyf9haxO6YMhLRy6cLYwW
0EYC6Qzn5gz3kI7VkI8fWfs2Dk4XEV3D+SVtBoF6KRxMXT6HZvpzoMSEJZBoNj8S
jw0TF8TFUQf49jUQbIHumukMswolrHi8a5ej8DSfNwSgz+Tt8oh5lu01kyUJiHn7
nuHaY4Y9cHUVAOSwq/hovG52+ZE1r3aiswvle/B19o9pKeWWVvacSptGxDQagBtQ
igoNLdRvY0XN2TEyX9pOHR0AoVOxtIW11CpkKuDbQG9vPwovqJ2L6+Fh3pzHYzcI
2GIShNm/Z2SZBiUqbljJe9H4UAT/aHgMINkEG8qzUKwO42MA5HJT7YbHTR17/QSF
Il5dhneRzmSbNcW2rdRwx/BmzrcsFJfqCt4JG/WDF293xSOjhFqQYvU4gCO+OB7o
KXjX907XXDjS2KEJ71OGqVfk/P7BqEfQNfrLtb02TyXJAPQXHhybv23c4E7zUs9V
lMjNizzxYB96uwJb0LAB2ijzEwoP91uGT2tFjk6F08x2QiArmXUdgrv44b39Stia
gJS0GYKqSzyr10xHhUuDA+GKYtcitC1TZWN1cml0eSBOeW0gVGVjaG5vbG9naWVz
IDxzZWN1cml0eUBueW10ZS5jaD6JAjYEMAEKACAWIQQkslkugBpaqoZmyLp8PHJ/
BQkFUAUCZ0nftQIdIAAKCRB8PHJ/BQkFUFHDEACtyNuUEjKCLAT5mSfow85PjFgo
o8kHjQr/IIQ7ZbBOHeJJcrxDuypssiLh5XUjF3x5BiBfZ6vCxSb81RRwsDMp0mA1
qzv9G8sgW0HTQUnZ9oH6CYut2NgzAnQpmuacrunm9Zy0FJ3ejbmwUY/NqK6gJkle
66duHKhAy7DWjj7amd0C8bPDR+PA44fI3MezDHkQNaauKZTRqd1TqH8Qk5PAl4cB
o5gVzeZh/U7/usvtGhazAIUF5BqK6bTmDnYopg+2x8jjwrG4+08GrttZkNjBLXeA
Y/2U064yMz12LPv01qqAFdZ+coRy/ps/gOQTz34/VeW0CFy7TMqs4t3vSBWTqU7w
hnw/qj6cM33fdxctj6KDgJSCkZdx2fvwXgxiPqUa5+j9FlFBeD5RDAl6g6t8N1/K
Xca+zNYuSZgc297q1D+mtSD1C7uJNPxoAl+Bv5KNKpsjfQ+m04++CIFtGyX22aCA
h2/tHwQZIXhOiMAKOoupidDVDhgxtCJ3Ps416xL0sTZfsPfg+j1Uv/Em9pzPClEl
fX6+1O4DdSyZUQ4VsjMu/H5W/NQdbHgmqFrxQ6WX/0s5GMwO6GMDiPe8sOrwz9wD
WYtyjafxXOHEZ1OjYX5gr7bGaG4oKc2btTJN0B3Phg4dStnHCNjEYccxuV3507fj
HnNotkpXF2nGLxy+PYkCVAQTAQoAPhYhBCSyWS6AGlqqhmbIunw8cn8FCQVQBQJl
P16XAhsDBQkFo5qABQsJCAcDBRUKCQgLBRYCAwEAAh4BAheAAAoJEHw8cn8FCQVQ
vt0P/3M7ve4jlVH5JbE8WYlb71Cw+JBtVG8bA1m6ty2ZDazY97S8dEQsV6oPmhi9
LHYt6q7civ7Of8LeQMyQ2zjShtIvqMIGIs+TERjQmrM8z2NmvsSO+WJtZXd/oPGi
hEioTJ83nsjc4EaWpkTQzHuxC4JyBq7wLvQMX3nZCEpTBcLZyamYModUQSiKjXEZ
IPh1CEZqkIHfZFAa2do4Z8A71x6U0y9KrQun5onF4AKZYVjlPj/Lv0k9xPm9Kz/I
QhGZof9+famLBoUGwiqAckkzE7fvjQ/WEXyPspZShSh+4VoQAscGkSmNZM6Px6PX
CYWW77kX6NJWhzvzVZtlle7Thw4FecZOiDNLEykF71O0tvbzN3pbMWi0LbkpMjem
eAzNexAYsks7C+hkqJIsWM9GODWvChuYHdDcnZbkZhK96JrQIOxkY/6DzsZVV/+g
PYOOlrrzHJVjAhh4DpPcM11LvuoeJG4aJLiRZfJWMOo4gJuhHi4K+3T3OWQG4sN1
NapZgBFS9mO2OzjD86Wt2sEjcDzy2Lx9GV1ho2m7XswTWKWk3jjIqgm2qJZzdOKy
Tx5gt/HpzsVAXc+tG9qavsVm+EWxgwvkJ40UdMTM3pjeOMo3/rQO8J+h1adYUrjt
PGSXxQBcZjZb0HR9apDBRWvy4u4zLIyIpt6i5+LusY6PoAwSuQINBGU/XpcBEADw
UaYPkne0zUE4zWeInFklN0Jq7MS3ESgEvRG6oYGRHxTb2xEzoPC7ONTs/CxwWcFo
bJT55TvcbAaQfejMV8W2WViFCuE/+SQ37SsQ7leL6dH7gkIVGqt/eclcAA9+KSxR
Eynx6vV1Q5jb97VlKgu1L6fNSK9XwJ8T6mCP/li0bA8L4pgcsBOQqQwQsKttbhQ7
TpVY6pCy+vqSK9e4lBAt0QAykGUAOZcUbjkOY8pDOwFZSC9PDIbLctfSfKzxyCl7
H0EfyGGvTVCYbI/jr2w3dw2u0W67xTpECyIIP/yaUG4PcRARTlIXSVzuQIgIBmT7
ASWZeeKYSLRM5ixvPqT3SW16JxfvSsD0Y17Ijvof5VI5i9amRHBokCBR3OsAzWj1
IcBKr5xnqcPzk5mKhCQNYzr5D6x/ah6fSomecaZSv3eQkgLQ8h2CtdGu2I195FrV
n8fQuZETLIQygWJWK+fPW9WTzk6rpJ/eW1TC+YPO64k62ynZCnr7HpKef/Ipq4ji
5/gJ//ApRyHivoHCCDkPDj2TLuXCWcAuKjgYhWgYukt5/3fBagOangqXKHdk9/ac
HRT3W7dsdFSjub4PtAn3xzIq2osvOODuzMZ/rSkhY1ZGxp1hBPdtKdzKeqScCM5X
cEK/Hr+K+yemP/9CNhEe2+JQBxDUMEHpQLqrbcUizQARAQABiQI8BBgBCgAmFiEE
JLJZLoAaWqqGZsi6fDxyfwUJBVAFAmU/XpcCGwwFCQWjmoAACgkQfDxyfwUJBVDO
6Q/+IvGM7FP5Sk9H/9ymsNVIuQ/ikXlubDfpTTuO+qlL78pNezGKJCV599Fps6k0
tx34rW55q/K32ecjAce0dL2Qz0DsMHDcuekRteSLjpAMIIjqeIaKOUs4R4Baqehz
Aw1NPTnBVWAK07cNA/YyhIJyoelcMKG87Kvl3nGNgtUmGVy0gxKiZxXMavKOSc+7
RiP9OQL/hz6bzplZBQMeowdAi6IR6e9vrb8Xhzk4khFk8SfvTB112SAm4lTd4d0e
ue6EKSMIL3cZAZsaPTdmqizrr33LqGY94PdTkhS/y6PBlhUIK4ObyAl+undHpYt9
5l4r1aZNUGkLOwODd9WFLCY6TqmnwMCrX8N6/fJGQWCAITIYrpz1v5rQJEGdyXx7
lDRBAjM2JL+4TFA/eH4Qsmzc/Qws/7oVaE1SvLT2feWdaSvWFj6/UzQYDFt92/+2
wI3U+r9VATP4JOperJp+1aV04dbDoeH6C3DFweMbgwE6s7mggJDeWHaEbBDnxwOB
lhIr84aAn0GCAWXUJwzS4YLT9NEIjXO3/jL7t59JlAxmQejtUL/cwVunaFw16Olb
4HFW7ApO6cW9YrdMuGqxKVDnLKGpyGih6mwUer1uiwoWMskLTW6msG/WuKeg1247
LjcVvJLsk9FGykA03RGILakxtZ0TRlNBoWrq08iDTnymOqI=
=QPTf
tC1TZWN1cml0eSBOeW0gVGVjaG5vbG9naWVzIDxzZWN1cml0eUBueW10ZS5jaD6J
AlQEEwEKAD4WIQQkslkugBpaqoZmyLp8PHJ/BQkFUAUCZT9elwIbAwUJBaOagAUL
CQgHAwUVCgkICwUWAgMBAAIeAQIXgAAKCRB8PHJ/BQkFUL7dD/9zO73uI5VR+SWx
PFmJW+9QsPiQbVRvGwNZurctmQ2s2Pe0vHRELFeqD5oYvSx2Lequ3Ir+zn/C3kDM
kNs40obSL6jCBiLPkxEY0JqzPM9jZr7EjvlibWV3f6DxooRIqEyfN57I3OBGlqZE
0Mx7sQuCcgau8C70DF952QhKUwXC2cmpmDKHVEEoio1xGSD4dQhGapCB32RQGtna
OGfAO9celNMvSq0Lp+aJxeACmWFY5T4/y79JPcT5vSs/yEIRmaH/fn2piwaFBsIq
gHJJMxO3740P1hF8j7KWUoUofuFaEALHBpEpjWTOj8ej1wmFlu+5F+jSVoc781Wb
ZZXu04cOBXnGTogzSxMpBe9TtLb28zd6WzFotC25KTI3pngMzXsQGLJLOwvoZKiS
LFjPRjg1rwobmB3Q3J2W5GYSveia0CDsZGP+g87GVVf/oD2Djpa68xyVYwIYeA6T
3DNdS77qHiRuGiS4kWXyVjDqOICboR4uCvt09zlkBuLDdTWqWYARUvZjtjs4w/Ol
rdrBI3A88ti8fRldYaNpu17ME1ilpN44yKoJtqiWc3Tisk8eYLfx6c7FQF3PrRva
mr7FZvhFsYML5CeNFHTEzN6Y3jjKN/60DvCfodWnWFK47Txkl8UAXGY2W9B0fWqQ
wUVr8uLuMyyMiKbeoufi7rGOj6AMErkCDQRlP16XARAA8FGmD5J3tM1BOM1niJxZ
JTdCauzEtxEoBL0RuqGBkR8U29sRM6DwuzjU7PwscFnBaGyU+eU73GwGkH3ozFfF
tllYhQrhP/kkN+0rEO5Xi+nR+4JCFRqrf3nJXAAPfiksURMp8er1dUOY2/e1ZSoL
tS+nzUivV8CfE+pgj/5YtGwPC+KYHLATkKkMELCrbW4UO06VWOqQsvr6kivXuJQQ
LdEAMpBlADmXFG45DmPKQzsBWUgvTwyGy3LX0nys8cgpex9BH8hhr01QmGyP469s
N3cNrtFuu8U6RAsiCD/8mlBuD3EQEU5SF0lc7kCICAZk+wElmXnimEi0TOYsbz6k
90lteicX70rA9GNeyI76H+VSOYvWpkRwaJAgUdzrAM1o9SHASq+cZ6nD85OZioQk
DWM6+Q+sf2oen0qJnnGmUr93kJIC0PIdgrXRrtiNfeRa1Z/H0LmREyyEMoFiVivn
z1vVk85Oq6Sf3ltUwvmDzuuJOtsp2Qp6+x6Snn/yKauI4uf4Cf/wKUch4r6Bwgg5
Dw49ky7lwlnALio4GIVoGLpLef93wWoDmp4Klyh3ZPf2nB0U91u3bHRUo7m+D7QJ
98cyKtqLLzjg7szGf60pIWNWRsadYQT3bSncynqknAjOV3BCvx6/ivsnpj//QjYR
HtviUAcQ1DBB6UC6q23FIs0AEQEAAYkCPAQYAQoAJhYhBCSyWS6AGlqqhmbIunw8
cn8FCQVQBQJlP16XAhsMBQkFo5qAAAoJEHw8cn8FCQVQzukP/iLxjOxT+UpPR//c
prDVSLkP4pF5bmw36U07jvqpS+/KTXsxiiQleffRabOpNLcd+K1ueavyt9nnIwHH
tHS9kM9A7DBw3LnpEbXki46QDCCI6niGijlLOEeAWqnocwMNTT05wVVgCtO3DQP2
MoSCcqHpXDChvOyr5d5xjYLVJhlctIMSomcVzGryjknPu0Yj/TkC/4c+m86ZWQUD
HqMHQIuiEenvb62/F4c5OJIRZPEn70wdddkgJuJU3eHdHrnuhCkjCC93GQGbGj03
Zqos6699y6hmPeD3U5IUv8ujwZYVCCuDm8gJfrp3R6WLfeZeK9WmTVBpCzsDg3fV
hSwmOk6pp8DAq1/Dev3yRkFggCEyGK6c9b+a0CRBncl8e5Q0QQIzNiS/uExQP3h+
ELJs3P0MLP+6FWhNUry09n3lnWkr1hY+v1M0GAxbfdv/tsCN1Pq/VQEz+CTqXqya
ftWldOHWw6Hh+gtwxcHjG4MBOrO5oICQ3lh2hGwQ58cDgZYSK/OGgJ9BggFl1CcM
0uGC0/TRCI1zt/4y+7efSZQMZkHo7VC/3MFbp2hcNejpW+BxVuwKTunFvWK3TLhq
sSlQ5yyhqchooepsFHq9bosKFjLJC01uprBv1rinoNduOy43FbyS7JPRRspANN0R
iC2pMbWdE0ZTQaFq6tPIg058pjqi
=nqgX
-----END PGP PUBLIC KEY BLOCK-----
```
+28 -1
View File
@@ -3,10 +3,13 @@
use crate::commands::try_load_current_config;
use crate::{
client::SocketClient,
client::{config::Config, SocketClient},
commands::{override_config, OverrideConfig},
error::ClientError,
};
use clap::Args;
use log::*;
use nym_bin_common::version_checker::is_minor_version_compatible;
use nym_client_core::cli_helpers::client_run::CommonClientRunArgs;
use std::error::Error;
use std::net::IpAddr;
@@ -45,12 +48,36 @@ impl From<Run> for OverrideConfig {
}
}
// this only checks compatibility between config the binary. It does not take into consideration
// network version. It might do so in the future.
fn version_check(cfg: &Config) -> bool {
let binary_version = env!("CARGO_PKG_VERSION");
let config_version = &cfg.base.client.version;
if binary_version == config_version {
true
} else {
warn!("The native-client binary has different version than what is specified in config file! {} and {}", binary_version, config_version);
if is_minor_version_compatible(binary_version, config_version) {
info!("but they are still semver compatible. However, consider running the `upgrade` command");
true
} else {
error!("and they are semver incompatible! - please run the `upgrade` command before attempting `run` again");
false
}
}
}
pub(crate) async fn execute(args: Run) -> Result<(), Box<dyn Error + Send + Sync>> {
eprintln!("Starting client {}...", args.common_args.id);
let mut config = try_load_current_config(&args.common_args.id).await?;
config = override_config(config, OverrideConfig::from(args.clone()));
if !version_check(&config) {
error!("failed the local version check");
return Err(Box::new(ClientError::FailedLocalVersionCheck));
}
SocketClient::new(config, args.common_args.custom_mixnet)
.run_socket_forever()
.await
+3
View File
@@ -17,6 +17,9 @@ pub enum ClientError {
#[error("Failed to validate the loaded config")]
ConfigValidationFailure,
#[error("Failed local version check, client and config mismatch")]
FailedLocalVersionCheck,
#[error("Attempted to start the client in invalid socket mode")]
InvalidSocketMode,
+33 -1
View File
@@ -2,8 +2,14 @@
// SPDX-License-Identifier: Apache-2.0
use crate::commands::try_load_current_config;
use crate::commands::{override_config, OverrideConfig};
use crate::config::Config;
use crate::{
commands::{override_config, OverrideConfig},
error::Socks5ClientError,
};
use clap::Args;
use log::*;
use nym_bin_common::version_checker::is_minor_version_compatible;
use nym_client_core::cli_helpers::client_run::CommonClientRunArgs;
use nym_client_core::client::base_client::storage::OnDiskPersistent;
use nym_client_core::client::topology_control::geo_aware_provider::CountryGroup;
@@ -76,12 +82,38 @@ fn validate_country_group(s: &str) -> Result<CountryGroup, String> {
}
}
// this only checks compatibility between config the binary. It does not take into consideration
// network version. It might do so in the future.
fn version_check(cfg: &Config) -> bool {
let binary_version = env!("CARGO_PKG_VERSION");
let config_version = &cfg.core.base.client.version;
if binary_version == config_version {
true
} else {
warn!(
"The socks5-client binary has different version than what is specified in config file! {binary_version} and {config_version}",
);
if is_minor_version_compatible(binary_version, config_version) {
info!("but they are still semver compatible. However, consider running the `upgrade` command");
true
} else {
error!("and they are semver incompatible! - please run the `upgrade` command before attempting `run` again");
false
}
}
}
pub(crate) async fn execute(args: Run) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
eprintln!("Starting client {}...", args.common_args.id);
let mut config = try_load_current_config(&args.common_args.id).await?;
config = override_config(config, OverrideConfig::from(args.clone()));
if !version_check(&config) {
error!("failed the local version check");
return Err(Box::new(Socks5ClientError::FailedLocalVersionCheck));
}
let storage =
OnDiskPersistent::from_paths(config.storage_paths.common_paths, &config.core.base.debug)
.await?;
+3
View File
@@ -14,6 +14,9 @@ pub enum Socks5ClientError {
#[error("Failed to validate the loaded config")]
ConfigValidationFailure,
#[error("Failed local version check, client and config mismatch")]
FailedLocalVersionCheck,
#[error("Fail to bind address")]
FailToBindAddress,
-1
View File
@@ -8,7 +8,6 @@ pub mod v3;
pub mod v4;
mod error;
mod util;
pub use error::Error;
pub use v4 as latest;
-71
View File
@@ -1,71 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
#[cfg(test)]
pub(crate) mod tests {
pub(crate) const CREDENTIAL_BYTES: [u8; 1245] = [
0, 0, 4, 133, 96, 179, 223, 185, 136, 23, 213, 166, 59, 203, 66, 69, 209, 181, 227, 254,
16, 102, 98, 237, 59, 119, 170, 111, 31, 194, 51, 59, 120, 17, 115, 229, 79, 91, 11, 139,
154, 2, 212, 23, 68, 70, 167, 3, 240, 54, 224, 171, 221, 1, 69, 48, 60, 118, 119, 249, 123,
35, 172, 227, 131, 96, 232, 209, 187, 123, 4, 197, 102, 90, 96, 45, 125, 135, 140, 99, 1,
151, 17, 131, 143, 157, 97, 107, 139, 232, 212, 87, 14, 115, 253, 255, 166, 167, 186, 43,
90, 96, 173, 105, 120, 40, 10, 163, 250, 224, 214, 200, 178, 4, 160, 16, 130, 59, 76, 193,
39, 240, 3, 101, 141, 209, 183, 226, 186, 207, 56, 210, 187, 7, 164, 240, 164, 205, 37, 81,
184, 214, 193, 195, 90, 205, 238, 225, 195, 104, 12, 123, 203, 57, 233, 243, 215, 145, 195,
196, 57, 38, 125, 172, 18, 47, 63, 165, 110, 219, 180, 40, 58, 116, 92, 254, 160, 98, 48,
92, 254, 232, 107, 184, 80, 234, 60, 160, 235, 249, 76, 41, 38, 165, 28, 40, 136, 74, 48,
166, 50, 245, 23, 201, 140, 101, 79, 93, 235, 128, 186, 146, 126, 180, 134, 43, 13, 186,
19, 195, 48, 168, 201, 29, 216, 95, 176, 198, 132, 188, 64, 39, 212, 150, 32, 52, 53, 38,
228, 199, 122, 226, 217, 75, 40, 191, 151, 48, 164, 242, 177, 79, 14, 122, 105, 151, 85,
88, 199, 162, 17, 96, 103, 83, 178, 128, 9, 24, 30, 74, 108, 241, 85, 240, 166, 97, 241,
85, 199, 11, 198, 226, 234, 70, 107, 145, 28, 208, 114, 51, 12, 234, 108, 101, 202, 112,
48, 185, 22, 159, 67, 109, 49, 27, 149, 90, 109, 32, 226, 112, 7, 201, 208, 209, 104, 31,
97, 134, 204, 145, 27, 181, 206, 181, 106, 32, 110, 136, 115, 249, 201, 111, 5, 245, 203,
71, 121, 169, 126, 151, 178, 236, 59, 221, 195, 48, 135, 115, 6, 50, 227, 74, 97, 107, 107,
213, 90, 2, 203, 154, 138, 47, 128, 52, 134, 128, 224, 51, 65, 240, 90, 8, 55, 175, 180,
178, 204, 206, 168, 110, 51, 57, 189, 169, 48, 169, 136, 121, 99, 51, 170, 178, 214, 74, 1,
96, 151, 167, 25, 173, 180, 171, 155, 10, 55, 142, 234, 190, 113, 90, 79, 80, 244, 71, 166,
30, 235, 113, 150, 133, 1, 218, 17, 109, 111, 223, 24, 216, 177, 41, 2, 204, 65, 221, 212,
207, 236, 144, 6, 65, 224, 55, 42, 1, 1, 161, 134, 118, 127, 111, 220, 110, 127, 240, 71,
223, 129, 12, 93, 20, 220, 60, 56, 71, 146, 184, 95, 132, 69, 28, 56, 53, 192, 213, 22,
119, 230, 152, 225, 182, 188, 163, 219, 37, 175, 247, 73, 14, 247, 38, 72, 243, 1, 48, 131,
59, 8, 13, 96, 143, 185, 127, 241, 161, 217, 24, 149, 193, 40, 16, 30, 202, 151, 28, 119,
240, 153, 101, 156, 61, 193, 72, 245, 199, 181, 12, 231, 65, 166, 67, 142, 121, 207, 202,
58, 197, 113, 188, 248, 42, 124, 105, 48, 161, 241, 55, 209, 36, 194, 27, 63, 233, 144,
189, 85, 117, 234, 9, 139, 46, 31, 206, 114, 95, 131, 29, 240, 13, 81, 142, 140, 133, 33,
30, 41, 141, 37, 80, 217, 95, 221, 76, 115, 86, 201, 165, 51, 252, 9, 28, 209, 1, 48, 150,
74, 248, 212, 187, 222, 66, 210, 3, 200, 19, 217, 171, 184, 42, 148, 53, 150, 57, 50, 6,
227, 227, 62, 49, 42, 148, 148, 157, 82, 191, 58, 24, 34, 56, 98, 120, 89, 105, 176, 85,
15, 253, 241, 41, 153, 195, 136, 1, 48, 142, 126, 213, 101, 223, 79, 133, 230, 105, 38,
161, 149, 2, 21, 136, 150, 42, 72, 218, 85, 146, 63, 223, 58, 108, 186, 183, 248, 62, 20,
47, 34, 113, 160, 177, 204, 181, 16, 24, 212, 224, 35, 84, 51, 168, 56, 136, 11, 1, 48,
135, 242, 62, 149, 230, 178, 32, 224, 119, 26, 234, 163, 237, 224, 114, 95, 112, 140, 170,
150, 96, 125, 136, 221, 180, 78, 18, 11, 12, 184, 2, 198, 217, 119, 43, 69, 4, 172, 109,
55, 183, 40, 131, 172, 161, 88, 183, 101, 1, 48, 173, 216, 22, 73, 42, 255, 211, 93, 249,
87, 159, 115, 61, 91, 55, 130, 17, 216, 60, 34, 122, 55, 8, 244, 244, 153, 151, 57, 5, 144,
178, 55, 249, 64, 211, 168, 34, 148, 56, 89, 92, 203, 70, 124, 219, 152, 253, 165, 0, 32,
203, 116, 63, 7, 240, 222, 82, 86, 11, 149, 167, 72, 224, 55, 190, 66, 201, 65, 168, 184,
96, 47, 194, 241, 168, 124, 7, 74, 214, 250, 37, 76, 32, 218, 69, 122, 103, 215, 145, 169,
24, 212, 229, 168, 106, 10, 144, 31, 13, 25, 178, 242, 250, 106, 159, 40, 48, 163, 165, 61,
130, 57, 146, 4, 73, 32, 254, 233, 125, 135, 212, 29, 111, 4, 177, 114, 15, 210, 170, 82,
108, 110, 62, 166, 81, 209, 106, 176, 156, 14, 133, 242, 60, 127, 120, 242, 28, 97, 0, 1,
32, 103, 93, 109, 89, 240, 91, 1, 84, 150, 50, 206, 157, 203, 49, 220, 120, 234, 175, 234,
150, 126, 225, 94, 163, 164, 199, 138, 114, 62, 99, 106, 112, 1, 32, 171, 40, 220, 82, 241,
203, 76, 146, 111, 139, 182, 179, 237, 182, 115, 75, 128, 201, 107, 43, 214, 0, 135, 217,
160, 68, 150, 232, 144, 114, 237, 98, 32, 30, 134, 232, 59, 93, 163, 253, 244, 13, 202, 52,
147, 168, 83, 121, 123, 95, 21, 210, 209, 225, 223, 143, 49, 10, 205, 238, 1, 22, 83, 81,
70, 1, 32, 26, 76, 6, 234, 160, 50, 139, 102, 161, 232, 155, 106, 130, 171, 226, 210, 233,
178, 85, 247, 71, 123, 55, 53, 46, 67, 148, 137, 156, 207, 208, 107, 1, 32, 102, 31, 4, 98,
110, 156, 144, 61, 229, 140, 198, 84, 196, 238, 128, 35, 131, 182, 137, 125, 241, 95, 69,
131, 170, 27, 2, 144, 75, 72, 242, 102, 3, 32, 121, 80, 45, 173, 56, 65, 218, 27, 40, 251,
197, 32, 169, 104, 123, 110, 90, 78, 153, 166, 38, 9, 129, 228, 99, 8, 1, 116, 142, 233,
162, 69, 32, 216, 169, 159, 116, 95, 12, 63, 176, 195, 6, 183, 123, 135, 75, 61, 112, 106,
83, 235, 176, 41, 27, 248, 48, 71, 165, 170, 12, 92, 103, 103, 81, 32, 58, 74, 75, 145,
192, 94, 153, 69, 80, 128, 241, 3, 16, 117, 192, 86, 161, 103, 44, 174, 211, 196, 182, 124,
55, 11, 107, 142, 49, 88, 6, 41, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0, 37, 139, 240, 0, 0,
0, 0, 0, 0, 0, 1,
];
pub(crate) const RECIPIENT: &str = "CytBseW6yFXUMzz4SGAKdNLGR7q3sJLLYxyBGvutNEQV.4QXYyEVc5fUDjmmi8PrHN9tdUFV4PCvSJE1278cHyvoe@4sBbL1ngf1vtNqykydQKTFh26sQCw888GpUqvPvyNB4f";
}
@@ -29,7 +29,7 @@ pub type Taken = Option<SystemTime>;
pub const BANDWIDTH_CAP_PER_DAY: u64 = 1024 * 1024 * 1024; // 1 GB
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct InitMessage {
/// Base64 encoded x25519 public key
pub pub_key: PeerPublicKey,
@@ -41,7 +41,7 @@ impl InitMessage {
}
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct FinalMessage {
/// Gateway client data
pub gateway_client: GatewayClient,
@@ -50,28 +50,28 @@ pub struct FinalMessage {
pub credential: Option<CredentialSpendingData>,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct RegistrationData {
pub nonce: u64,
pub gateway_data: GatewayClient,
pub wg_port: u16,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct RegistredData {
pub pub_key: PeerPublicKey,
pub private_ip: IpAddr,
pub wg_port: u16,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct RemainingBandwidthData {
pub available_bandwidth: i64,
}
/// Client that wants to register sends its PublicKey bytes mac digest encrypted with a DH shared secret.
/// Gateway/Nym node can then verify pub_key payload using the same process
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct GatewayClient {
/// Base64 encoded x25519 public key
pub pub_key: PeerPublicKey,
@@ -147,7 +147,7 @@ impl GatewayClient {
// TODO: change the inner type into generic array of size HmacSha256::OutputSize
// TODO2: rely on our internal crypto/hmac
#[derive(Debug, Clone, PartialEq)]
#[derive(Debug, Clone)]
pub struct ClientMac(Vec<u8>);
impl fmt::Display for ClientMac {
@@ -87,7 +87,7 @@ impl AuthenticatorRequest {
}
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[derive(Clone, Debug, Serialize, Deserialize)]
pub enum AuthenticatorRequestData {
Initial(InitMessage),
Final(Box<FinalMessage>),
@@ -100,28 +100,28 @@ impl AuthenticatorResponse {
}
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[derive(Clone, Debug, Serialize, Deserialize)]
pub enum AuthenticatorResponseData {
PendingRegistration(PendingRegistrationResponse),
Registered(RegisteredResponse),
RemainingBandwidth(RemainingBandwidthResponse),
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct PendingRegistrationResponse {
pub request_id: u64,
pub reply_to: Recipient,
pub reply: RegistrationData,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct RegisteredResponse {
pub request_id: u64,
pub reply_to: Recipient,
pub reply: RegistredData,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct RemainingBandwidthResponse {
pub request_id: u64,
pub reply_to: Recipient,
@@ -19,24 +19,6 @@ impl From<v2::request::AuthenticatorRequest> for v3::request::AuthenticatorReque
}
}
impl TryFrom<v3::request::AuthenticatorRequest> for v2::request::AuthenticatorRequest {
type Error = crate::Error;
fn try_from(
authenticator_request: v3::request::AuthenticatorRequest,
) -> Result<Self, Self::Error> {
Ok(Self {
protocol: Protocol {
version: 2,
service_provider_type: ServiceProviderType::Authenticator,
},
data: authenticator_request.data.try_into()?,
reply_to: authenticator_request.reply_to,
request_id: authenticator_request.request_id,
})
}
}
impl From<v2::request::AuthenticatorRequestData> for v3::request::AuthenticatorRequestData {
fn from(authenticator_request_data: v2::request::AuthenticatorRequestData) -> Self {
match authenticator_request_data {
@@ -53,29 +35,6 @@ impl From<v2::request::AuthenticatorRequestData> for v3::request::AuthenticatorR
}
}
impl TryFrom<v3::request::AuthenticatorRequestData> for v2::request::AuthenticatorRequestData {
type Error = crate::Error;
fn try_from(
authenticator_request_data: v3::request::AuthenticatorRequestData,
) -> Result<Self, Self::Error> {
match authenticator_request_data {
v3::request::AuthenticatorRequestData::Initial(init_msg) => Ok(
v2::request::AuthenticatorRequestData::Initial(init_msg.into()),
),
v3::request::AuthenticatorRequestData::Final(gw_client) => Ok(
v2::request::AuthenticatorRequestData::Final(gw_client.into()),
),
v3::request::AuthenticatorRequestData::QueryBandwidth(pub_key) => Ok(
v2::request::AuthenticatorRequestData::QueryBandwidth(pub_key),
),
v3::request::AuthenticatorRequestData::TopUpBandwidth(_) => Err(
Self::Error::Conversion("no top up bandwidth variant in v2".to_string()),
),
}
}
}
impl From<v2::registration::InitMessage> for v3::registration::InitMessage {
fn from(init_msg: v2::registration::InitMessage) -> Self {
Self {
@@ -84,14 +43,6 @@ impl From<v2::registration::InitMessage> for v3::registration::InitMessage {
}
}
impl From<v3::registration::InitMessage> for v2::registration::InitMessage {
fn from(init_msg: v3::registration::InitMessage) -> Self {
Self {
pub_key: init_msg.pub_key,
}
}
}
impl From<Box<v2::registration::FinalMessage>> for Box<v3::registration::FinalMessage> {
fn from(gw_client: Box<v2::registration::FinalMessage>) -> Self {
Box::new(v3::registration::FinalMessage {
@@ -101,15 +52,6 @@ impl From<Box<v2::registration::FinalMessage>> for Box<v3::registration::FinalMe
}
}
impl From<Box<v3::registration::FinalMessage>> for Box<v2::registration::FinalMessage> {
fn from(gw_client: Box<v3::registration::FinalMessage>) -> Self {
Box::new(v2::registration::FinalMessage {
gateway_client: gw_client.gateway_client.into(),
credential: gw_client.credential,
})
}
}
impl From<v2::registration::GatewayClient> for v3::registration::GatewayClient {
fn from(gw_client: v2::registration::GatewayClient) -> Self {
Self {
@@ -151,10 +93,7 @@ impl TryFrom<v3::response::AuthenticatorResponse> for v2::response::Authenticato
Ok(Self {
data: authenticator_response.data.try_into()?,
reply_to: authenticator_response.reply_to,
protocol: Protocol {
version: 2,
service_provider_type: authenticator_response.protocol.service_provider_type,
},
protocol: authenticator_response.protocol,
})
}
}
@@ -162,10 +101,7 @@ impl TryFrom<v3::response::AuthenticatorResponse> for v2::response::Authenticato
impl From<v2::response::AuthenticatorResponse> for v3::response::AuthenticatorResponse {
fn from(value: v2::response::AuthenticatorResponse) -> Self {
Self {
protocol: Protocol {
version: 3,
service_provider_type: value.protocol.service_provider_type,
},
protocol: value.protocol,
data: value.data.into(),
reply_to: value.reply_to,
}
@@ -334,511 +270,3 @@ impl From<v2::registration::RemainingBandwidthData> for v3::registration::Remain
}
}
}
#[cfg(test)]
mod tests {
use std::{net::IpAddr, str::FromStr};
use nym_credentials_interface::CredentialSpendingData;
use nym_crypto::asymmetric::encryption::PrivateKey;
use nym_sphinx::addressing::Recipient;
use nym_wireguard_types::PeerPublicKey;
use x25519_dalek::PublicKey;
use super::*;
use crate::util::tests::{CREDENTIAL_BYTES, RECIPIENT};
#[test]
fn upgrade_initial_req() {
let pub_key = PeerPublicKey::new(PublicKey::from([0; 32]));
let reply_to = Recipient::try_from_base58_string(RECIPIENT).unwrap();
let (msg, _) = v2::request::AuthenticatorRequest::new_initial_request(
v2::registration::InitMessage::new(pub_key),
reply_to,
);
let upgraded_msg = v3::request::AuthenticatorRequest::from(msg);
assert_eq!(
upgraded_msg.protocol,
Protocol {
version: 3,
service_provider_type: ServiceProviderType::Authenticator
}
);
assert_eq!(
upgraded_msg.data,
v3::request::AuthenticatorRequestData::Initial(v3::registration::InitMessage {
pub_key
})
);
}
#[test]
fn downgrade_initial_req() {
let pub_key = PeerPublicKey::new(PublicKey::from([0; 32]));
let reply_to = Recipient::try_from_base58_string(RECIPIENT).unwrap();
let (msg, _) = v3::request::AuthenticatorRequest::new_initial_request(
v3::registration::InitMessage::new(pub_key),
reply_to,
);
let downgraded_msg = v2::request::AuthenticatorRequest::try_from(msg).unwrap();
assert_eq!(
downgraded_msg.protocol,
Protocol {
version: 2,
service_provider_type: ServiceProviderType::Authenticator
}
);
assert_eq!(
downgraded_msg.data,
v2::request::AuthenticatorRequestData::Initial(v2::registration::InitMessage {
pub_key
})
);
}
#[test]
fn upgrade_final_req() {
let mut rng = rand::thread_rng();
let local_secret = PrivateKey::new(&mut rng);
let remote_secret = x25519_dalek::StaticSecret::random_from_rng(&mut rng);
let private_ip = IpAddr::from_str("10.10.10.10").unwrap();
let nonce = 42;
let gateway_client = v2::registration::GatewayClient::new(
&local_secret,
(&remote_secret).into(),
private_ip,
nonce,
);
let credential = Some(CredentialSpendingData::try_from_bytes(&CREDENTIAL_BYTES).unwrap());
let final_message = v2::registration::FinalMessage {
gateway_client,
credential: credential.clone(),
};
let reply_to = Recipient::try_from_base58_string(RECIPIENT).unwrap();
let (msg, _) =
v2::request::AuthenticatorRequest::new_final_request(final_message, reply_to);
let upgraded_msg = v3::request::AuthenticatorRequest::from(msg);
assert_eq!(
upgraded_msg.protocol,
Protocol {
version: 3,
service_provider_type: ServiceProviderType::Authenticator
}
);
assert_eq!(
upgraded_msg.data,
v3::request::AuthenticatorRequestData::Final(Box::new(
v3::registration::FinalMessage {
gateway_client: v3::registration::GatewayClient::new(
&local_secret,
(&remote_secret).into(),
private_ip,
nonce,
),
credential
}
))
);
}
#[test]
fn downgrade_final_req() {
let mut rng = rand::thread_rng();
let local_secret = PrivateKey::new(&mut rng);
let remote_secret = x25519_dalek::StaticSecret::random_from_rng(&mut rng);
let private_ip = IpAddr::from_str("10.10.10.10").unwrap();
let nonce = 42;
let gateway_client = v3::registration::GatewayClient::new(
&local_secret,
(&remote_secret).into(),
private_ip,
nonce,
);
let credential = Some(CredentialSpendingData::try_from_bytes(&CREDENTIAL_BYTES).unwrap());
let final_message = v3::registration::FinalMessage {
gateway_client,
credential: credential.clone(),
};
let reply_to = Recipient::try_from_base58_string(RECIPIENT).unwrap();
let (msg, _) =
v3::request::AuthenticatorRequest::new_final_request(final_message, reply_to);
let upgraded_msg = v2::request::AuthenticatorRequest::try_from(msg).unwrap();
assert_eq!(
upgraded_msg.protocol,
Protocol {
version: 2,
service_provider_type: ServiceProviderType::Authenticator
}
);
assert_eq!(
upgraded_msg.data,
v2::request::AuthenticatorRequestData::Final(Box::new(
v2::registration::FinalMessage {
gateway_client: v2::registration::GatewayClient::new(
&local_secret,
(&remote_secret).into(),
private_ip,
nonce,
),
credential
}
))
);
}
#[test]
fn upgrade_query_req() {
let pub_key = PeerPublicKey::new(PublicKey::from([0; 32]));
let reply_to = Recipient::try_from_base58_string(RECIPIENT).unwrap();
let (msg, _) = v2::request::AuthenticatorRequest::new_query_request(pub_key, reply_to);
let upgraded_msg = v3::request::AuthenticatorRequest::from(msg);
assert_eq!(
upgraded_msg.protocol,
Protocol {
version: 3,
service_provider_type: ServiceProviderType::Authenticator
}
);
assert_eq!(
upgraded_msg.data,
v3::request::AuthenticatorRequestData::QueryBandwidth(pub_key)
);
}
#[test]
fn downgrade_query_req() {
let pub_key = PeerPublicKey::new(PublicKey::from([0; 32]));
let reply_to = Recipient::try_from_base58_string(RECIPIENT).unwrap();
let (msg, _) = v3::request::AuthenticatorRequest::new_query_request(pub_key, reply_to);
let downgraded_msg = v2::request::AuthenticatorRequest::try_from(msg).unwrap();
assert_eq!(
downgraded_msg.protocol,
Protocol {
version: 2,
service_provider_type: ServiceProviderType::Authenticator
}
);
assert_eq!(
downgraded_msg.data,
v2::request::AuthenticatorRequestData::QueryBandwidth(pub_key)
);
}
#[test]
fn downgrade_topup_req() {
let pub_key = PeerPublicKey::new(PublicKey::from([0; 32]));
let credential = CredentialSpendingData::try_from_bytes(&CREDENTIAL_BYTES).unwrap();
let top_up_message = v3::topup::TopUpMessage {
pub_key,
credential,
};
let reply_to = Recipient::try_from_base58_string(RECIPIENT).unwrap();
let (msg, _) =
v3::request::AuthenticatorRequest::new_topup_request(top_up_message, reply_to);
assert!(v2::request::AuthenticatorRequest::try_from(msg).is_err());
}
#[test]
fn upgrade_pending_reg_resp() {
let mut rng = rand::thread_rng();
let local_secret = PrivateKey::new(&mut rng);
let remote_secret = x25519_dalek::StaticSecret::random_from_rng(&mut rng);
let private_ip = IpAddr::from_str("10.10.10.10").unwrap();
let nonce = 42;
let wg_port = 51822;
let gateway_data = v2::registration::GatewayClient::new(
&local_secret,
(&remote_secret).into(),
private_ip,
nonce,
);
let registration_data = v2::registration::RegistrationData {
nonce,
gateway_data,
wg_port,
};
let request_id = 123;
let reply_to = Recipient::try_from_base58_string(RECIPIENT).unwrap();
let msg = v2::response::AuthenticatorResponse::new_pending_registration_success(
registration_data,
request_id,
reply_to,
);
let upgraded_msg = v3::response::AuthenticatorResponse::from(msg);
assert_eq!(
upgraded_msg.protocol,
Protocol {
version: 3,
service_provider_type: ServiceProviderType::Authenticator
}
);
assert_eq!(
upgraded_msg.data,
v3::response::AuthenticatorResponseData::PendingRegistration(
v3::response::PendingRegistrationResponse {
request_id,
reply_to,
reply: v3::registration::RegistrationData {
nonce,
gateway_data: v3::registration::GatewayClient::new(
&local_secret,
(&remote_secret).into(),
private_ip,
nonce,
),
wg_port,
}
}
)
);
}
#[test]
fn downgrade_pending_reg_resp() {
let mut rng = rand::thread_rng();
let local_secret = PrivateKey::new(&mut rng);
let remote_secret = x25519_dalek::StaticSecret::random_from_rng(&mut rng);
let private_ip = IpAddr::from_str("10.10.10.10").unwrap();
let nonce = 42;
let wg_port = 51822;
let gateway_data = v3::registration::GatewayClient::new(
&local_secret,
(&remote_secret).into(),
private_ip,
nonce,
);
let registration_data = v3::registration::RegistrationData {
nonce,
gateway_data,
wg_port,
};
let request_id = 123;
let reply_to = Recipient::try_from_base58_string(RECIPIENT).unwrap();
let msg = v3::response::AuthenticatorResponse::new_pending_registration_success(
registration_data,
request_id,
reply_to,
);
let downgraded_msg = v2::response::AuthenticatorResponse::try_from(msg).unwrap();
assert_eq!(
downgraded_msg.protocol,
Protocol {
version: 2,
service_provider_type: ServiceProviderType::Authenticator
}
);
assert_eq!(
downgraded_msg.data,
v2::response::AuthenticatorResponseData::PendingRegistration(
v2::response::PendingRegistrationResponse {
request_id,
reply_to,
reply: v2::registration::RegistrationData {
nonce,
gateway_data: v2::registration::GatewayClient::new(
&local_secret,
(&remote_secret).into(),
private_ip,
nonce,
),
wg_port,
}
}
)
);
}
#[test]
fn upgrade_registered_resp() {
let pub_key = PeerPublicKey::new(PublicKey::from([0; 32]));
let private_ip = IpAddr::from_str("10.10.10.10").unwrap();
let wg_port = 51822;
let registred_data = v2::registration::RegistredData {
pub_key,
private_ip,
wg_port,
};
let request_id = 123;
let reply_to = Recipient::try_from_base58_string(RECIPIENT).unwrap();
let msg = v2::response::AuthenticatorResponse::new_registered(
registred_data,
reply_to,
request_id,
);
let upgraded_msg = v3::response::AuthenticatorResponse::from(msg);
assert_eq!(
upgraded_msg.protocol,
Protocol {
version: 3,
service_provider_type: ServiceProviderType::Authenticator
}
);
assert_eq!(
upgraded_msg.data,
v3::response::AuthenticatorResponseData::Registered(v3::response::RegisteredResponse {
request_id,
reply_to,
reply: v3::registration::RegistredData {
wg_port,
pub_key,
private_ip
}
})
);
}
#[test]
fn downgrade_registered_resp() {
let pub_key = PeerPublicKey::new(PublicKey::from([0; 32]));
let private_ip = IpAddr::from_str("10.10.10.10").unwrap();
let wg_port = 51822;
let registred_data = v3::registration::RegistredData {
pub_key,
private_ip,
wg_port,
};
let request_id = 123;
let reply_to = Recipient::try_from_base58_string(RECIPIENT).unwrap();
let msg = v3::response::AuthenticatorResponse::new_registered(
registred_data,
reply_to,
request_id,
);
let downgraded_msg = v2::response::AuthenticatorResponse::try_from(msg).unwrap();
assert_eq!(
downgraded_msg.protocol,
Protocol {
version: 2,
service_provider_type: ServiceProviderType::Authenticator
}
);
assert_eq!(
downgraded_msg.data,
v2::response::AuthenticatorResponseData::Registered(v2::response::RegisteredResponse {
request_id,
reply_to,
reply: v2::registration::RegistredData {
wg_port,
pub_key,
private_ip
}
})
);
}
#[test]
fn upgrade_remaining_bandwidth_resp() {
let available_bandwidth = 42;
let remaining_bandwidth_data = Some(v2::registration::RemainingBandwidthData {
available_bandwidth,
});
let request_id = 123;
let reply_to = Recipient::try_from_base58_string(RECIPIENT).unwrap();
let msg = v2::response::AuthenticatorResponse::new_remaining_bandwidth(
remaining_bandwidth_data,
reply_to,
request_id,
);
let upgraded_msg = v3::response::AuthenticatorResponse::from(msg);
assert_eq!(
upgraded_msg.protocol,
Protocol {
version: 3,
service_provider_type: ServiceProviderType::Authenticator
}
);
assert_eq!(
upgraded_msg.data,
v3::response::AuthenticatorResponseData::RemainingBandwidth(
v3::response::RemainingBandwidthResponse {
request_id,
reply_to,
reply: Some(v3::registration::RemainingBandwidthData {
available_bandwidth,
})
}
)
);
}
#[test]
fn downgrade_remaining_bandwidth_resp() {
let available_bandwidth = 42;
let remaining_bandwidth_data = Some(v3::registration::RemainingBandwidthData {
available_bandwidth,
});
let request_id = 123;
let reply_to = Recipient::try_from_base58_string(RECIPIENT).unwrap();
let msg = v3::response::AuthenticatorResponse::new_remaining_bandwidth(
remaining_bandwidth_data,
reply_to,
request_id,
);
let downgraded_msg = v2::response::AuthenticatorResponse::try_from(msg).unwrap();
assert_eq!(
downgraded_msg.protocol,
Protocol {
version: 2,
service_provider_type: ServiceProviderType::Authenticator
}
);
assert_eq!(
downgraded_msg.data,
v2::response::AuthenticatorResponseData::RemainingBandwidth(
v2::response::RemainingBandwidthResponse {
request_id,
reply_to,
reply: Some(v2::registration::RemainingBandwidthData {
available_bandwidth,
})
}
)
);
}
#[test]
fn downgrade_topup_resp() {
let available_bandwidth = 42;
let remaining_bandwidth_data = v3::registration::RemainingBandwidthData {
available_bandwidth,
};
let request_id = 123;
let reply_to = Recipient::try_from_base58_string(RECIPIENT).unwrap();
let msg = v3::response::AuthenticatorResponse::new_topup_bandwidth(
remaining_bandwidth_data,
reply_to,
request_id,
);
assert!(v2::response::AuthenticatorResponse::try_from(msg).is_err());
}
}
@@ -29,7 +29,7 @@ pub type Taken = Option<SystemTime>;
pub const BANDWIDTH_CAP_PER_DAY: u64 = 250 * 1024 * 1024 * 1024; // 250 GB
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct InitMessage {
/// Base64 encoded x25519 public key
pub pub_key: PeerPublicKey,
@@ -41,7 +41,7 @@ impl InitMessage {
}
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct FinalMessage {
/// Gateway client data
pub gateway_client: GatewayClient,
@@ -50,28 +50,28 @@ pub struct FinalMessage {
pub credential: Option<CredentialSpendingData>,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct RegistrationData {
pub nonce: u64,
pub gateway_data: GatewayClient,
pub wg_port: u16,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct RegistredData {
pub pub_key: PeerPublicKey,
pub private_ip: IpAddr,
pub wg_port: u16,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct RemainingBandwidthData {
pub available_bandwidth: i64,
}
/// Client that wants to register sends its PublicKey bytes mac digest encrypted with a DH shared secret.
/// Gateway/Nym node can then verify pub_key payload using the same process
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct GatewayClient {
/// Base64 encoded x25519 public key
pub pub_key: PeerPublicKey,
@@ -147,7 +147,7 @@ impl GatewayClient {
// TODO: change the inner type into generic array of size HmacSha256::OutputSize
// TODO2: rely on our internal crypto/hmac
#[derive(Debug, Clone, PartialEq)]
#[derive(Debug, Clone)]
pub struct ClientMac(Vec<u8>);
impl fmt::Display for ClientMac {
@@ -106,7 +106,7 @@ impl AuthenticatorRequest {
}
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[derive(Clone, Debug, Serialize, Deserialize)]
pub enum AuthenticatorRequestData {
Initial(InitMessage),
Final(Box<FinalMessage>),
@@ -120,7 +120,7 @@ impl AuthenticatorResponse {
}
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[derive(Clone, Debug, Serialize, Deserialize)]
pub enum AuthenticatorResponseData {
PendingRegistration(PendingRegistrationResponse),
Registered(RegisteredResponse),
@@ -128,28 +128,28 @@ pub enum AuthenticatorResponseData {
TopUpBandwidth(TopUpBandwidthResponse),
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct PendingRegistrationResponse {
pub request_id: u64,
pub reply_to: Recipient,
pub reply: RegistrationData,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct RegisteredResponse {
pub request_id: u64,
pub reply_to: Recipient,
pub reply: RegistredData,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct RemainingBandwidthResponse {
pub request_id: u64,
pub reply_to: Recipient,
pub reply: Option<RemainingBandwidthData>,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct TopUpBandwidthResponse {
pub request_id: u64,
pub reply_to: Recipient,
@@ -5,7 +5,7 @@ use nym_credentials_interface::CredentialSpendingData;
use nym_wireguard_types::PeerPublicKey;
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct TopUpMessage {
/// Base64 encoded x25519 public key
pub pub_key: PeerPublicKey,
+104 -609
View File
@@ -3,82 +3,37 @@
use nym_service_provider_requests_common::{Protocol, ServiceProviderType};
use crate::{v3, v4};
use crate::{v2, v3, v4};
impl TryFrom<v3::request::AuthenticatorRequest> for v4::request::AuthenticatorRequest {
type Error = crate::Error;
fn try_from(
authenticator_request: v3::request::AuthenticatorRequest,
) -> Result<Self, Self::Error> {
Ok(Self {
impl From<v3::request::AuthenticatorRequest> for v4::request::AuthenticatorRequest {
fn from(authenticator_request: v3::request::AuthenticatorRequest) -> Self {
Self {
protocol: Protocol {
version: 4,
service_provider_type: ServiceProviderType::Authenticator,
},
data: authenticator_request.data.try_into()?,
data: authenticator_request.data.into(),
reply_to: authenticator_request.reply_to,
request_id: authenticator_request.request_id,
})
}
}
impl TryFrom<v4::request::AuthenticatorRequest> for v3::request::AuthenticatorRequest {
type Error = crate::Error;
fn try_from(
authenticator_request: v4::request::AuthenticatorRequest,
) -> Result<Self, Self::Error> {
Ok(Self {
protocol: Protocol {
version: 3,
service_provider_type: ServiceProviderType::Authenticator,
},
data: authenticator_request.data.try_into()?,
reply_to: authenticator_request.reply_to,
request_id: authenticator_request.request_id,
})
}
}
impl TryFrom<v3::request::AuthenticatorRequestData> for v4::request::AuthenticatorRequestData {
type Error = crate::Error;
fn try_from(
authenticator_request_data: v3::request::AuthenticatorRequestData,
) -> Result<Self, Self::Error> {
match authenticator_request_data {
v3::request::AuthenticatorRequestData::Initial(init_msg) => Ok(
v4::request::AuthenticatorRequestData::Initial(init_msg.into()),
),
v3::request::AuthenticatorRequestData::Final(_) => Err(Self::Error::Conversion(
"mac hash breaking change".to_string(),
)),
v3::request::AuthenticatorRequestData::QueryBandwidth(pub_key) => Ok(
v4::request::AuthenticatorRequestData::QueryBandwidth(pub_key),
),
v3::request::AuthenticatorRequestData::TopUpBandwidth(top_up_message) => Ok(
v4::request::AuthenticatorRequestData::TopUpBandwidth(top_up_message.into()),
),
}
}
}
impl TryFrom<v4::request::AuthenticatorRequestData> for v3::request::AuthenticatorRequestData {
type Error = crate::Error;
fn try_from(
authenticator_request_data: v4::request::AuthenticatorRequestData,
) -> Result<Self, Self::Error> {
impl From<v3::request::AuthenticatorRequestData> for v4::request::AuthenticatorRequestData {
fn from(authenticator_request_data: v3::request::AuthenticatorRequestData) -> Self {
match authenticator_request_data {
v4::request::AuthenticatorRequestData::Initial(init_msg) => Ok(
v3::request::AuthenticatorRequestData::Initial(init_msg.into()),
),
v4::request::AuthenticatorRequestData::Final(_) => Err(Self::Error::Conversion(
"mac hash breaking change".to_string(),
)),
v4::request::AuthenticatorRequestData::QueryBandwidth(pub_key) => Ok(
v3::request::AuthenticatorRequestData::QueryBandwidth(pub_key),
),
v4::request::AuthenticatorRequestData::TopUpBandwidth(top_up_message) => Ok(
v3::request::AuthenticatorRequestData::TopUpBandwidth(top_up_message.into()),
),
v3::request::AuthenticatorRequestData::Initial(init_msg) => {
v4::request::AuthenticatorRequestData::Initial(init_msg.into())
}
v3::request::AuthenticatorRequestData::Final(gw_client) => {
v4::request::AuthenticatorRequestData::Final(gw_client.into())
}
v3::request::AuthenticatorRequestData::QueryBandwidth(pub_key) => {
v4::request::AuthenticatorRequestData::QueryBandwidth(pub_key)
}
v3::request::AuthenticatorRequestData::TopUpBandwidth(top_up_message) => {
v4::request::AuthenticatorRequestData::TopUpBandwidth(top_up_message.into())
}
}
}
}
@@ -91,11 +46,12 @@ impl From<v3::registration::InitMessage> for v4::registration::InitMessage {
}
}
impl From<v4::registration::InitMessage> for v3::registration::InitMessage {
fn from(init_msg: v4::registration::InitMessage) -> Self {
Self {
pub_key: init_msg.pub_key,
}
impl From<Box<v3::registration::FinalMessage>> for Box<v4::registration::FinalMessage> {
fn from(gw_client: Box<v3::registration::FinalMessage>) -> Self {
Box::new(v4::registration::FinalMessage {
gateway_client: gw_client.gateway_client.into(),
credential: gw_client.credential,
})
}
}
@@ -108,26 +64,67 @@ impl From<Box<v3::topup::TopUpMessage>> for Box<v4::topup::TopUpMessage> {
}
}
impl From<Box<v4::topup::TopUpMessage>> for Box<v3::topup::TopUpMessage> {
fn from(top_up_message: Box<v4::topup::TopUpMessage>) -> Self {
Box::new(v3::topup::TopUpMessage {
pub_key: top_up_message.pub_key,
credential: top_up_message.credential,
})
impl From<v2::registration::GatewayClient> for v4::registration::GatewayClient {
fn from(gw_client: v2::registration::GatewayClient) -> Self {
Self {
pub_key: gw_client.pub_key,
private_ips: gw_client.private_ip.into(),
mac: gw_client.mac.into(),
}
}
}
impl TryFrom<v3::response::AuthenticatorResponse> for v4::response::AuthenticatorResponse {
type Error = crate::Error;
fn try_from(value: v3::response::AuthenticatorResponse) -> Result<Self, Self::Error> {
Ok(Self {
protocol: Protocol {
version: 4,
service_provider_type: value.protocol.service_provider_type,
},
data: value.data.try_into()?,
reply_to: value.reply_to,
})
impl From<v3::registration::GatewayClient> for v4::registration::GatewayClient {
fn from(gw_client: v3::registration::GatewayClient) -> Self {
Self {
pub_key: gw_client.pub_key,
private_ips: gw_client.private_ip.into(),
mac: gw_client.mac.into(),
}
}
}
impl From<v4::registration::GatewayClient> for v3::registration::GatewayClient {
fn from(gw_client: v4::registration::GatewayClient) -> Self {
Self {
pub_key: gw_client.pub_key,
private_ip: gw_client.private_ips.ipv4.into(),
mac: gw_client.mac.into(),
}
}
}
impl From<v4::registration::GatewayClient> for v2::registration::GatewayClient {
fn from(gw_client: v4::registration::GatewayClient) -> Self {
Self {
pub_key: gw_client.pub_key,
private_ip: gw_client.private_ips.ipv4.into(),
mac: gw_client.mac.into(),
}
}
}
impl From<v2::registration::ClientMac> for v4::registration::ClientMac {
fn from(mac: v2::registration::ClientMac) -> Self {
Self::new(mac.to_vec())
}
}
impl From<v3::registration::ClientMac> for v4::registration::ClientMac {
fn from(mac: v3::registration::ClientMac) -> Self {
Self::new(mac.to_vec())
}
}
impl From<v4::registration::ClientMac> for v3::registration::ClientMac {
fn from(mac: v4::registration::ClientMac) -> Self {
Self::new(mac.to_vec())
}
}
impl From<v4::registration::ClientMac> for v2::registration::ClientMac {
fn from(mac: v4::registration::ClientMac) -> Self {
Self::new(mac.to_vec())
}
}
@@ -140,40 +137,11 @@ impl TryFrom<v4::response::AuthenticatorResponse> for v3::response::Authenticato
Ok(Self {
data: authenticator_response.data.try_into()?,
reply_to: authenticator_response.reply_to,
protocol: Protocol {
version: 3,
service_provider_type: authenticator_response.protocol.service_provider_type,
},
protocol: authenticator_response.protocol,
})
}
}
impl TryFrom<v3::response::AuthenticatorResponseData> for v4::response::AuthenticatorResponseData {
type Error = crate::Error;
fn try_from(
authenticator_response_data: v3::response::AuthenticatorResponseData,
) -> Result<Self, Self::Error> {
match authenticator_response_data {
v3::response::AuthenticatorResponseData::PendingRegistration(_) => Err(
Self::Error::Conversion("mac hash breaking change".to_string()),
),
v3::response::AuthenticatorResponseData::Registered(registered_response) => Ok(
v4::response::AuthenticatorResponseData::Registered(registered_response.into()),
),
v3::response::AuthenticatorResponseData::RemainingBandwidth(
remaining_bandwidth_response,
) => Ok(v4::response::AuthenticatorResponseData::RemainingBandwidth(
remaining_bandwidth_response.into(),
)),
v3::response::AuthenticatorResponseData::TopUpBandwidth(top_up_response) => Ok(
v4::response::AuthenticatorResponseData::TopUpBandwidth(top_up_response.into()),
),
}
}
}
impl TryFrom<v4::response::AuthenticatorResponseData> for v3::response::AuthenticatorResponseData {
type Error = crate::Error;
@@ -181,10 +149,13 @@ impl TryFrom<v4::response::AuthenticatorResponseData> for v3::response::Authenti
authenticator_response_data: v4::response::AuthenticatorResponseData,
) -> Result<Self, Self::Error> {
match authenticator_response_data {
v4::response::AuthenticatorResponseData::PendingRegistration(_) => Err(
Self::Error::Conversion("mac hash breaking change".to_string()),
v4::response::AuthenticatorResponseData::PendingRegistration(
pending_registration_response,
) => Ok(
v3::response::AuthenticatorResponseData::PendingRegistration(
pending_registration_response.into(),
),
),
v4::response::AuthenticatorResponseData::Registered(registered_response) => Ok(
v3::response::AuthenticatorResponseData::Registered(registered_response.into()),
),
@@ -202,6 +173,16 @@ impl TryFrom<v4::response::AuthenticatorResponseData> for v3::response::Authenti
}
}
impl From<v4::response::PendingRegistrationResponse> for v3::response::PendingRegistrationResponse {
fn from(value: v4::response::PendingRegistrationResponse) -> Self {
Self {
request_id: value.request_id,
reply_to: value.reply_to,
reply: value.reply.into(),
}
}
}
impl From<v4::response::RegisteredResponse> for v3::response::RegisteredResponse {
fn from(value: v4::response::RegisteredResponse) -> Self {
Self {
@@ -212,26 +193,6 @@ impl From<v4::response::RegisteredResponse> for v3::response::RegisteredResponse
}
}
impl From<v3::response::RegisteredResponse> for v4::response::RegisteredResponse {
fn from(value: v3::response::RegisteredResponse) -> Self {
Self {
request_id: value.request_id,
reply_to: value.reply_to,
reply: value.reply.into(),
}
}
}
impl From<v3::response::RemainingBandwidthResponse> for v4::response::RemainingBandwidthResponse {
fn from(value: v3::response::RemainingBandwidthResponse) -> Self {
Self {
request_id: value.request_id,
reply_to: value.reply_to,
reply: value.reply.map(Into::into),
}
}
}
impl From<v4::response::RemainingBandwidthResponse> for v3::response::RemainingBandwidthResponse {
fn from(value: v4::response::RemainingBandwidthResponse) -> Self {
Self {
@@ -242,31 +203,11 @@ impl From<v4::response::RemainingBandwidthResponse> for v3::response::RemainingB
}
}
impl From<v3::response::TopUpBandwidthResponse> for v4::response::TopUpBandwidthResponse {
fn from(value: v3::response::TopUpBandwidthResponse) -> Self {
impl From<v4::registration::RegistrationData> for v3::registration::RegistrationData {
fn from(value: v4::registration::RegistrationData) -> Self {
Self {
request_id: value.request_id,
reply_to: value.reply_to,
reply: value.reply.into(),
}
}
}
impl From<v4::response::TopUpBandwidthResponse> for v3::response::TopUpBandwidthResponse {
fn from(value: v4::response::TopUpBandwidthResponse) -> Self {
Self {
request_id: value.request_id,
reply_to: value.reply_to,
reply: value.reply.into(),
}
}
}
impl From<v3::registration::RegistredData> for v4::registration::RegistredData {
fn from(value: v3::registration::RegistredData) -> Self {
Self {
pub_key: value.pub_key,
private_ips: value.private_ip.into(),
nonce: value.nonce,
gateway_data: value.gateway_data.into(),
wg_port: value.wg_port,
}
}
@@ -282,14 +223,6 @@ impl From<v4::registration::RegistredData> for v3::registration::RegistredData {
}
}
impl From<v3::registration::RemainingBandwidthData> for v4::registration::RemainingBandwidthData {
fn from(value: v3::registration::RemainingBandwidthData) -> Self {
Self {
available_bandwidth: value.available_bandwidth,
}
}
}
impl From<v4::registration::RemainingBandwidthData> for v3::registration::RemainingBandwidthData {
fn from(value: v4::registration::RemainingBandwidthData) -> Self {
Self {
@@ -297,441 +230,3 @@ impl From<v4::registration::RemainingBandwidthData> for v3::registration::Remain
}
}
}
#[cfg(test)]
mod tests {
use std::{
net::{Ipv4Addr, Ipv6Addr},
str::FromStr,
};
use nym_credentials_interface::CredentialSpendingData;
use nym_crypto::asymmetric::encryption::PrivateKey;
use nym_sphinx::addressing::Recipient;
use nym_wireguard_types::PeerPublicKey;
use x25519_dalek::PublicKey;
use super::*;
use crate::util::tests::{CREDENTIAL_BYTES, RECIPIENT};
#[test]
fn upgrade_initial_req() {
let pub_key = PeerPublicKey::new(PublicKey::from([0; 32]));
let reply_to = Recipient::try_from_base58_string(RECIPIENT).unwrap();
let (msg, _) = v3::request::AuthenticatorRequest::new_initial_request(
v3::registration::InitMessage::new(pub_key),
reply_to,
);
let upgraded_msg = v4::request::AuthenticatorRequest::try_from(msg).unwrap();
assert_eq!(
upgraded_msg.protocol,
Protocol {
version: 4,
service_provider_type: ServiceProviderType::Authenticator
}
);
assert_eq!(
upgraded_msg.data,
v4::request::AuthenticatorRequestData::Initial(v4::registration::InitMessage {
pub_key
})
);
}
#[test]
fn downgrade_initial_req() {
let pub_key = PeerPublicKey::new(PublicKey::from([0; 32]));
let reply_to = Recipient::try_from_base58_string(RECIPIENT).unwrap();
let (msg, _) = v4::request::AuthenticatorRequest::new_initial_request(
v4::registration::InitMessage::new(pub_key),
reply_to,
);
let downgraded_msg = v3::request::AuthenticatorRequest::try_from(msg).unwrap();
assert_eq!(
downgraded_msg.protocol,
Protocol {
version: 3,
service_provider_type: ServiceProviderType::Authenticator
}
);
assert_eq!(
downgraded_msg.data,
v3::request::AuthenticatorRequestData::Initial(v3::registration::InitMessage {
pub_key
})
);
}
#[test]
fn upgrade_final_req() {
let mut rng = rand::thread_rng();
let local_secret = PrivateKey::new(&mut rng);
let remote_secret = x25519_dalek::StaticSecret::random_from_rng(&mut rng);
let ipv4 = Ipv4Addr::from_str("10.10.10.10").unwrap();
let nonce = 42;
let gateway_client = v3::registration::GatewayClient::new(
&local_secret,
(&remote_secret).into(),
ipv4.into(),
nonce,
);
let credential = Some(CredentialSpendingData::try_from_bytes(&CREDENTIAL_BYTES).unwrap());
let final_message = v3::registration::FinalMessage {
gateway_client,
credential: credential.clone(),
};
let reply_to = Recipient::try_from_base58_string(RECIPIENT).unwrap();
let (msg, _) =
v3::request::AuthenticatorRequest::new_final_request(final_message, reply_to);
assert!(v4::request::AuthenticatorRequest::try_from(msg).is_err());
}
#[test]
fn downgrade_final_req() {
let mut rng = rand::thread_rng();
let local_secret = PrivateKey::new(&mut rng);
let remote_secret = x25519_dalek::StaticSecret::random_from_rng(&mut rng);
let ipv4 = Ipv4Addr::from_str("10.10.10.10").unwrap();
let private_ips =
v4::registration::IpPair::new(ipv4, Ipv6Addr::from_str("fc01::10").unwrap());
let nonce = 42;
let gateway_client = v4::registration::GatewayClient::new(
&local_secret,
(&remote_secret).into(),
private_ips,
nonce,
);
let credential = Some(CredentialSpendingData::try_from_bytes(&CREDENTIAL_BYTES).unwrap());
let final_message = v4::registration::FinalMessage {
gateway_client,
credential: credential.clone(),
};
let reply_to = Recipient::try_from_base58_string(RECIPIENT).unwrap();
let (msg, _) =
v4::request::AuthenticatorRequest::new_final_request(final_message, reply_to);
assert!(v3::request::AuthenticatorRequest::try_from(msg).is_err());
}
#[test]
fn upgrade_query_req() {
let pub_key = PeerPublicKey::new(PublicKey::from([0; 32]));
let reply_to = Recipient::try_from_base58_string(RECIPIENT).unwrap();
let (msg, _) = v3::request::AuthenticatorRequest::new_query_request(pub_key, reply_to);
let upgraded_msg = v4::request::AuthenticatorRequest::try_from(msg).unwrap();
assert_eq!(
upgraded_msg.protocol,
Protocol {
version: 4,
service_provider_type: ServiceProviderType::Authenticator
}
);
assert_eq!(
upgraded_msg.data,
v4::request::AuthenticatorRequestData::QueryBandwidth(pub_key)
);
}
#[test]
fn downgrade_query_req() {
let pub_key = PeerPublicKey::new(PublicKey::from([0; 32]));
let reply_to = Recipient::try_from_base58_string(RECIPIENT).unwrap();
let (msg, _) = v4::request::AuthenticatorRequest::new_query_request(pub_key, reply_to);
let downgraded_msg = v3::request::AuthenticatorRequest::try_from(msg).unwrap();
assert_eq!(
downgraded_msg.protocol,
Protocol {
version: 3,
service_provider_type: ServiceProviderType::Authenticator
}
);
assert_eq!(
downgraded_msg.data,
v3::request::AuthenticatorRequestData::QueryBandwidth(pub_key)
);
}
#[test]
fn downgrade_topup_req() {
let pub_key = PeerPublicKey::new(PublicKey::from([0; 32]));
let credential = CredentialSpendingData::try_from_bytes(&CREDENTIAL_BYTES).unwrap();
let top_up_message = v4::topup::TopUpMessage {
pub_key,
credential: credential.clone(),
};
let reply_to = Recipient::try_from_base58_string(RECIPIENT).unwrap();
let (msg, _) =
v4::request::AuthenticatorRequest::new_topup_request(top_up_message, reply_to);
let downgraded_msg = v3::request::AuthenticatorRequest::try_from(msg).unwrap();
assert_eq!(
downgraded_msg.protocol,
Protocol {
version: 3,
service_provider_type: ServiceProviderType::Authenticator
}
);
assert_eq!(
downgraded_msg.data,
v3::request::AuthenticatorRequestData::TopUpBandwidth(Box::new(
v3::topup::TopUpMessage {
pub_key,
credential
}
))
);
}
#[test]
fn upgrade_pending_reg_resp() {
let mut rng = rand::thread_rng();
let local_secret = PrivateKey::new(&mut rng);
let remote_secret = x25519_dalek::StaticSecret::random_from_rng(&mut rng);
let ipv4 = Ipv4Addr::from_str("10.10.10.10").unwrap();
let nonce = 42;
let wg_port = 51822;
let gateway_data = v3::registration::GatewayClient::new(
&local_secret,
(&remote_secret).into(),
ipv4.into(),
nonce,
);
let registration_data = v3::registration::RegistrationData {
nonce,
gateway_data,
wg_port,
};
let request_id = 123;
let reply_to = Recipient::try_from_base58_string(RECIPIENT).unwrap();
let msg = v3::response::AuthenticatorResponse::new_pending_registration_success(
registration_data,
request_id,
reply_to,
);
assert!(v4::response::AuthenticatorResponse::try_from(msg).is_err());
}
#[test]
fn downgrade_pending_reg_resp() {
let mut rng = rand::thread_rng();
let local_secret = PrivateKey::new(&mut rng);
let remote_secret = x25519_dalek::StaticSecret::random_from_rng(&mut rng);
let ipv4 = Ipv4Addr::from_str("10.10.10.10").unwrap();
let private_ips =
v4::registration::IpPair::new(ipv4, Ipv6Addr::from_str("fc01::10").unwrap());
let nonce = 42;
let wg_port = 51822;
let gateway_data = v4::registration::GatewayClient::new(
&local_secret,
(&remote_secret).into(),
private_ips,
nonce,
);
let registration_data = v4::registration::RegistrationData {
nonce,
gateway_data,
wg_port,
};
let request_id = 123;
let reply_to = Recipient::try_from_base58_string(RECIPIENT).unwrap();
let msg = v4::response::AuthenticatorResponse::new_pending_registration_success(
registration_data,
request_id,
reply_to,
);
assert!(v3::response::AuthenticatorResponse::try_from(msg).is_err());
}
#[test]
fn upgrade_registered_resp() {
let pub_key = PeerPublicKey::new(PublicKey::from([0; 32]));
let ipv4 = Ipv4Addr::from_str("10.1.10.10").unwrap();
let private_ips =
v4::registration::IpPair::new(ipv4, Ipv6Addr::from_str("fc01::a0a").unwrap());
let wg_port = 51822;
let registred_data = v3::registration::RegistredData {
pub_key,
private_ip: ipv4.into(),
wg_port,
};
let request_id = 123;
let reply_to = Recipient::try_from_base58_string(RECIPIENT).unwrap();
let msg = v3::response::AuthenticatorResponse::new_registered(
registred_data,
reply_to,
request_id,
);
let upgraded_msg = v4::response::AuthenticatorResponse::try_from(msg).unwrap();
assert_eq!(
upgraded_msg.protocol,
Protocol {
version: 4,
service_provider_type: ServiceProviderType::Authenticator
}
);
assert_eq!(
upgraded_msg.data,
v4::response::AuthenticatorResponseData::Registered(v4::response::RegisteredResponse {
request_id,
reply_to,
reply: v4::registration::RegistredData {
wg_port,
pub_key,
private_ips
}
})
);
}
#[test]
fn downgrade_registered_resp() {
let pub_key = PeerPublicKey::new(PublicKey::from([0; 32]));
let ipv4 = Ipv4Addr::from_str("10.10.10.10").unwrap();
let private_ips =
v4::registration::IpPair::new(ipv4, Ipv6Addr::from_str("fc01::10").unwrap());
let wg_port = 51822;
let registred_data = v4::registration::RegistredData {
pub_key,
private_ips,
wg_port,
};
let request_id = 123;
let reply_to = Recipient::try_from_base58_string(RECIPIENT).unwrap();
let msg = v4::response::AuthenticatorResponse::new_registered(
registred_data,
reply_to,
request_id,
);
let downgraded_msg = v3::response::AuthenticatorResponse::try_from(msg).unwrap();
assert_eq!(
downgraded_msg.protocol,
Protocol {
version: 3,
service_provider_type: ServiceProviderType::Authenticator
}
);
assert_eq!(
downgraded_msg.data,
v3::response::AuthenticatorResponseData::Registered(v3::response::RegisteredResponse {
request_id,
reply_to,
reply: v3::registration::RegistredData {
wg_port,
pub_key,
private_ip: ipv4.into()
}
})
);
}
#[test]
fn upgrade_remaining_bandwidth_resp() {
let available_bandwidth = 42;
let remaining_bandwidth_data = Some(v3::registration::RemainingBandwidthData {
available_bandwidth,
});
let request_id = 123;
let reply_to = Recipient::try_from_base58_string(RECIPIENT).unwrap();
let msg = v3::response::AuthenticatorResponse::new_remaining_bandwidth(
remaining_bandwidth_data,
reply_to,
request_id,
);
let upgraded_msg = v4::response::AuthenticatorResponse::try_from(msg).unwrap();
assert_eq!(
upgraded_msg.protocol,
Protocol {
version: 4,
service_provider_type: ServiceProviderType::Authenticator
}
);
assert_eq!(
upgraded_msg.data,
v4::response::AuthenticatorResponseData::RemainingBandwidth(
v4::response::RemainingBandwidthResponse {
request_id,
reply_to,
reply: Some(v4::registration::RemainingBandwidthData {
available_bandwidth,
})
}
)
);
}
#[test]
fn downgrade_remaining_bandwidth_resp() {
let available_bandwidth = 42;
let remaining_bandwidth_data = Some(v4::registration::RemainingBandwidthData {
available_bandwidth,
});
let request_id = 123;
let reply_to = Recipient::try_from_base58_string(RECIPIENT).unwrap();
let msg = v4::response::AuthenticatorResponse::new_remaining_bandwidth(
remaining_bandwidth_data,
reply_to,
request_id,
);
let downgraded_msg = v3::response::AuthenticatorResponse::try_from(msg).unwrap();
assert_eq!(
downgraded_msg.protocol,
Protocol {
version: 3,
service_provider_type: ServiceProviderType::Authenticator
}
);
assert_eq!(
downgraded_msg.data,
v3::response::AuthenticatorResponseData::RemainingBandwidth(
v3::response::RemainingBandwidthResponse {
request_id,
reply_to,
reply: Some(v3::registration::RemainingBandwidthData {
available_bandwidth,
})
}
)
);
}
#[test]
fn downgrade_topup_resp() {
let available_bandwidth = 42;
let remaining_bandwidth_data = v4::registration::RemainingBandwidthData {
available_bandwidth,
};
let request_id = 123;
let reply_to = Recipient::try_from_base58_string(RECIPIENT).unwrap();
let msg = v4::response::AuthenticatorResponse::new_topup_bandwidth(
remaining_bandwidth_data,
reply_to,
request_id,
);
assert!(v3::response::AuthenticatorResponse::try_from(msg).is_err());
}
}
@@ -81,7 +81,7 @@ impl From<IpAddr> for IpPair {
}
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct InitMessage {
/// Base64 encoded x25519 public key
pub pub_key: PeerPublicKey,
@@ -93,7 +93,7 @@ impl InitMessage {
}
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct FinalMessage {
/// Gateway client data
pub gateway_client: GatewayClient,
@@ -102,28 +102,28 @@ pub struct FinalMessage {
pub credential: Option<CredentialSpendingData>,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct RegistrationData {
pub nonce: u64,
pub gateway_data: GatewayClient,
pub wg_port: u16,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct RegistredData {
pub pub_key: PeerPublicKey,
pub private_ips: IpPair,
pub wg_port: u16,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct RemainingBandwidthData {
pub available_bandwidth: i64,
}
/// Client that wants to register sends its PublicKey bytes mac digest encrypted with a DH shared secret.
/// Gateway/Nym node can then verify pub_key payload using the same process
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct GatewayClient {
/// Base64 encoded x25519 public key
pub pub_key: PeerPublicKey,
@@ -199,7 +199,7 @@ impl GatewayClient {
// TODO: change the inner type into generic array of size HmacSha256::OutputSize
// TODO2: rely on our internal crypto/hmac
#[derive(Debug, Clone, PartialEq)]
#[derive(Debug, Clone)]
pub struct ClientMac(Vec<u8>);
impl fmt::Display for ClientMac {
@@ -20,7 +20,7 @@ fn generate_random() -> u64 {
rng.next_u64()
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct AuthenticatorRequest {
pub protocol: Protocol,
pub data: AuthenticatorRequestData,
@@ -106,7 +106,7 @@ impl AuthenticatorRequest {
}
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[derive(Clone, Debug, Serialize, Deserialize)]
pub enum AuthenticatorRequestData {
Initial(InitMessage),
Final(Box<FinalMessage>),
@@ -10,7 +10,7 @@ use crate::make_bincode_serializer;
use super::VERSION;
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct AuthenticatorResponse {
pub protocol: Protocol,
pub data: AuthenticatorResponseData,
@@ -120,7 +120,7 @@ impl AuthenticatorResponse {
}
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[derive(Clone, Debug, Serialize, Deserialize)]
pub enum AuthenticatorResponseData {
PendingRegistration(PendingRegistrationResponse),
Registered(RegisteredResponse),
@@ -128,28 +128,28 @@ pub enum AuthenticatorResponseData {
TopUpBandwidth(TopUpBandwidthResponse),
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct PendingRegistrationResponse {
pub request_id: u64,
pub reply_to: Recipient,
pub reply: RegistrationData,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct RegisteredResponse {
pub request_id: u64,
pub reply_to: Recipient,
pub reply: RegistredData,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct RemainingBandwidthResponse {
pub request_id: u64,
pub reply_to: Recipient,
pub reply: Option<RemainingBandwidthData>,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct TopUpBandwidthResponse {
pub request_id: u64,
pub reply_to: Recipient,
@@ -5,7 +5,7 @@ use nym_credentials_interface::CredentialSpendingData;
use nym_wireguard_types::PeerPublicKey;
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct TopUpMessage {
/// Base64 encoded x25519 public key
pub pub_key: PeerPublicKey,
+2 -1
View File
@@ -15,6 +15,7 @@ const-str = { workspace = true }
log = { workspace = true }
pretty_env_logger = { workspace = true }
schemars = { workspace = true, features = ["preserve_order"], optional = true }
semver.workspace = true
serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true, optional = true }
@@ -43,5 +44,5 @@ tracing = [
"tracing-opentelemetry",
"opentelemetry",
]
clap = ["dep:clap", "dep:clap_complete", "dep:clap_complete_fig"]
clap = [ "dep:clap", "dep:clap_complete", "dep:clap_complete_fig" ]
models = []
+1
View File
@@ -3,6 +3,7 @@
pub mod build_information;
pub mod logging;
pub mod version_checker;
#[cfg(feature = "clap")]
pub mod completions;
@@ -0,0 +1,78 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
pub use semver::Version;
/// Checks if the version is minor version compatible.
///
/// Checks whether given `version` is compatible with a given semantic version requirement `req`
/// according to major-minor semver rules. The semantic version requirement can be passed as a full,
/// concrete version number, because that's what we'll have in our Cargo.toml files (e.g. 0.3.2).
/// The patch number in the requirement gets dropped and replaced with a wildcard (0.3.*) as all
/// minor versions should be compatible with each other.
pub fn is_minor_version_compatible(version: &str, req: &str) -> bool {
let expected_version = match Version::parse(version) {
Ok(v) => v,
Err(_) => return false,
};
let req_version = match Version::parse(req) {
Ok(v) => v,
Err(_) => return false,
};
expected_version.major == req_version.major && expected_version.minor == req_version.minor
}
pub fn parse_version(raw_version: &str) -> Result<Version, semver::Error> {
Version::parse(raw_version)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn version_0_3_0_is_compatible_with_requirement_0_3_x() {
assert!(is_minor_version_compatible("0.3.0", "0.3.2"));
}
#[test]
fn version_0_3_1_is_compatible_with_minimum_requirement_0_3_x() {
assert!(is_minor_version_compatible("0.3.1", "0.3.2"));
}
#[test]
fn version_0_3_2_is_compatible_with_minimum_requirement_0_3_x() {
assert!(is_minor_version_compatible("0.3.2", "0.3.0"));
}
#[test]
fn version_0_2_0_is_not_compatible_with_requirement_0_3_x() {
assert!(!is_minor_version_compatible("0.2.0", "0.3.2"));
}
#[test]
fn version_0_4_0_is_not_compatible_with_requirement_0_3_x() {
assert!(!is_minor_version_compatible("0.4.0", "0.3.2"));
}
#[test]
fn version_1_3_2_is_not_compatible_with_requirement_0_3_x() {
assert!(!is_minor_version_compatible("1.3.2", "0.3.2"));
}
#[test]
fn version_0_4_0_rc_1_is_compatible_with_version_0_4_0_rc_1() {
assert!(is_minor_version_compatible("0.4.0-rc.1", "0.4.0-rc.1"));
}
#[test]
fn returns_false_on_foo_version() {
assert!(!is_minor_version_compatible("foo", "0.3.2"));
}
#[test]
fn returns_false_on_bar_version() {
assert!(!is_minor_version_compatible("0.3.2", "bar"));
}
}
+2 -3
View File
@@ -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.76"
rust-version = "1.70"
license.workspace = true
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
@@ -45,8 +45,7 @@ nym-nonexhaustive-delayqueue = { path = "../nonexhaustive-delayqueue" }
nym-sphinx = { path = "../nymsphinx" }
nym-statistics-common = { path = "../statistics" }
nym-pemstore = { path = "../pemstore" }
nym-topology = { path = "../topology", features = ["persistence"] }
nym-mixnet-client = { path = "../client-libs/mixnet-client", default-features = false }
nym-topology = { path = "../topology", features = ["serializable"] }
nym-validator-client = { path = "../client-libs/validator-client", default-features = false }
nym-task = { path = "../task" }
nym-credentials-interface = { path = "../credentials-interface" }
@@ -550,15 +550,6 @@ pub struct Topology {
/// Specifies a minimum performance of a gateway that is used on route construction.
/// This setting is only applicable when `NymApi` topology is used.
pub minimum_gateway_performance: u8,
/// Specifies whether this client should attempt to retrieve all available network nodes
/// as opposed to just active mixnodes/gateways.
/// Useless without `ignore_epoch_roles = true`
pub use_extended_topology: bool,
/// Specifies whether this client should ignore the current epoch role of the target egress node
/// when constructing the final hop packets.
pub ignore_egress_epoch_role: bool,
}
#[allow(clippy::large_enum_variant)]
@@ -595,8 +586,6 @@ impl Default for Topology {
topology_structure: TopologyStructure::default(),
minimum_mixnode_performance: DEFAULT_MIN_MIXNODE_PERFORMANCE,
minimum_gateway_performance: DEFAULT_MIN_GATEWAY_PERFORMANCE,
use_extended_topology: false,
ignore_egress_epoch_role: false,
}
}
}
@@ -8,10 +8,7 @@ use crate::{
},
};
use log::{debug, error};
use sqlx::{
sqlite::{SqliteAutoVacuum, SqliteSynchronous},
ConnectOptions,
};
use sqlx::ConnectOptions;
use std::path::Path;
#[derive(Debug, Clone)]
@@ -33,9 +30,6 @@ impl StorageManager {
}
let opts = sqlx::sqlite::SqliteConnectOptions::new()
.journal_mode(sqlx::sqlite::SqliteJournalMode::Wal)
.synchronous(SqliteSynchronous::Normal)
.auto_vacuum(SqliteAutoVacuum::Incremental)
.filename(database_path)
.create_if_missing(true)
.disable_statement_logging();
@@ -116,7 +110,7 @@ impl StorageManager {
) -> Result<(), sqlx::Error> {
sqlx::query!(
r#"
INSERT INTO registered_gateway(gateway_id_bs58, registration_timestamp, gateway_type)
INSERT INTO registered_gateway(gateway_id_bs58, registration_timestamp, gateway_type)
VALUES (?, ?, ?)
"#,
registered_gateway.gateway_id_bs58,
@@ -230,7 +224,7 @@ impl StorageManager {
) -> Result<(), sqlx::Error> {
sqlx::query!(
r#"
INSERT INTO custom_gateway_details(gateway_id_bs58, data)
INSERT INTO custom_gateway_details(gateway_id_bs58, data)
VALUES (?, ?)
"#,
custom.gateway_id_bs58,
@@ -112,23 +112,18 @@ where
source,
}
})?;
hardcoded_topology.entry_capable_nodes().cloned().collect()
hardcoded_topology.get_gateways()
} else {
let mut rng = rand::thread_rng();
crate::init::helpers::current_gateways(
&mut rng,
&core.client.nym_api_urls,
user_agent,
core.debug.topology.minimum_gateway_performance,
)
.await?
crate::init::helpers::current_gateways(&mut rng, &core.client.nym_api_urls, user_agent)
.await?
};
// since we're registering with a brand new gateway,
// make sure the list of available gateways doesn't overlap the list of known gateways
let available_gateways = available_gateways
.into_iter()
.filter(|g| !registered_gateways.contains(&g.identity()))
.filter(|g| !registered_gateways.contains(g.identity()))
.collect::<Vec<_>>();
if available_gateways.is_empty() {
@@ -167,16 +167,11 @@ where
source,
}
})?;
hardcoded_topology.entry_capable_nodes().cloned().collect()
hardcoded_topology.get_gateways()
} else {
let mut rng = rand::thread_rng();
crate::init::helpers::current_gateways(
&mut rng,
&core.client.nym_api_urls,
user_agent,
core.debug.topology.minimum_gateway_performance,
)
.await?
crate::init::helpers::current_gateways(&mut rng, &core.client.nym_api_urls, user_agent)
.await?
};
let gateway_setup = GatewaySetup::New {
@@ -3,6 +3,7 @@
use super::received_buffer::ReceivedBufferMessage;
use super::statistics_control::StatisticsControl;
use super::topology_control::geo_aware_provider::GeoAwareTopologyProvider;
use crate::client::base_client::storage::helpers::store_client_keys;
use crate::client::base_client::storage::MixnetClientStorage;
use crate::client::cover_traffic_stream::LoopCoverTrafficStream;
@@ -23,7 +24,7 @@ use crate::client::replies::reply_storage::{
};
use crate::client::topology_control::nym_api_provider::NymApiTopologyProvider;
use crate::client::topology_control::{
TopologyAccessor, TopologyRefresher, TopologyRefresherConfig,
nym_api_provider, TopologyAccessor, TopologyRefresher, TopologyRefresherConfig,
};
use crate::config::{Config, DebugConfig};
use crate::error::ClientCoreError;
@@ -31,7 +32,7 @@ use crate::init::{
setup_gateway,
types::{GatewaySetup, InitialisationResult},
};
use crate::{config, spawn_future, ForgetMe};
use crate::{config, spawn_future};
use futures::channel::mpsc;
use log::*;
use nym_bandwidth_controller::BandwidthController;
@@ -187,11 +188,6 @@ pub struct BaseClientBuilder<'a, C, S: MixnetClientStorage> {
user_agent: Option<UserAgent>,
setup_method: GatewaySetup,
#[cfg(unix)]
connection_fd_callback: Option<Arc<dyn Fn(RawFd) + Send + Sync>>,
forget_me: ForgetMe,
}
impl<'a, C, S> BaseClientBuilder<'a, C, S>
@@ -214,18 +210,9 @@ where
shutdown: None,
user_agent: None,
setup_method: GatewaySetup::MustLoad { gateway_id: None },
#[cfg(unix)]
connection_fd_callback: None,
forget_me: Default::default(),
}
}
#[must_use]
pub fn with_forget_me(mut self, forget_me: &ForgetMe) -> Self {
self.forget_me = forget_me.clone();
self
}
#[must_use]
pub fn with_gateway_setup(mut self, setup: GatewaySetup) -> Self {
self.setup_method = setup;
@@ -274,15 +261,6 @@ where
Ok(self)
}
#[cfg(unix)]
pub fn with_connection_fd_callback(
mut self,
callback: Arc<dyn Fn(RawFd) + Send + Sync>,
) -> Self {
self.connection_fd_callback = Some(callback);
self
}
// note: do **NOT** make this method public as its only valid usage is from within `start_base`
// because it relies on the crypto keys being already loaded
fn mix_address(details: &InitialisationResult) -> Recipient {
@@ -374,7 +352,6 @@ where
controller.start_with_shutdown(shutdown)
}
#[allow(clippy::too_many_arguments)]
async fn start_gateway_client(
config: &Config,
initialisation_result: InitialisationResult,
@@ -382,7 +359,6 @@ where
details_store: &S::GatewaysDetailsStore,
packet_router: PacketRouter,
stats_reporter: ClientStatsSender,
#[cfg(unix)] connection_fd_callback: Option<Arc<dyn Fn(RawFd) + Send + Sync>>,
shutdown: TaskClient,
) -> Result<GatewayClient<C, S::CredentialStore>, ClientCoreError>
where
@@ -425,8 +401,6 @@ where
packet_router,
bandwidth_controller,
stats_reporter,
#[cfg(unix)]
connection_fd_callback,
shutdown,
)
};
@@ -463,8 +437,8 @@ where
details_store
.upgrade_stored_remote_gateway_key(gateway_client.gateway_identity(), &updated_key)
.await.map_err(|err| {
error!("failed to store upgraded gateway key! this connection might be forever broken now: {err}");
ClientCoreError::GatewaysDetailsStoreError { source: Box::new(err) }
error!("failed to store upgraded gateway key! this connection might be forever broken now: {err}");
ClientCoreError::GatewaysDetailsStoreError { source: Box::new(err) }
})?
}
@@ -488,7 +462,6 @@ where
details_store: &S::GatewaysDetailsStore,
packet_router: PacketRouter,
stats_reporter: ClientStatsSender,
#[cfg(unix)] connection_fd_callback: Option<Arc<dyn Fn(RawFd) + Send + Sync>>,
mut shutdown: TaskClient,
) -> Result<Box<dyn GatewayTransceiver + Send>, ClientCoreError>
where
@@ -520,8 +493,6 @@ where
details_store,
packet_router,
stats_reporter,
#[cfg(unix)]
connection_fd_callback,
shutdown,
)
.await?;
@@ -538,15 +509,20 @@ where
// if no custom provider was ... provided ..., create one using nym-api
custom_provider.unwrap_or_else(|| match config_topology.topology_structure {
config::TopologyStructure::NymApi => Box::new(NymApiTopologyProvider::new(
config_topology,
nym_api_provider::Config {
min_mixnode_performance: config_topology.minimum_mixnode_performance,
min_gateway_performance: config_topology.minimum_gateway_performance,
},
nym_api_urls,
env!("CARGO_PKG_VERSION").to_string(),
user_agent,
)),
config::TopologyStructure::GeoAware(group_by) => {
warn!("using deprecated 'GeoAware' topology provider - this option will be removed very soon");
#[allow(deprecated)]
Box::new(crate::client::topology_control::GeoAwareTopologyProvider::new(nym_api_urls, group_by))
Box::new(GeoAwareTopologyProvider::new(
nym_api_urls,
env!("CARGO_PKG_VERSION").to_string(),
group_by,
))
}
})
}
@@ -557,7 +533,7 @@ where
topology_provider: Box<dyn TopologyProvider + Send + Sync>,
topology_config: config::Topology,
topology_accessor: TopologyAccessor,
local_gateway: NodeIdentity,
local_gateway: &NodeIdentity,
wait_for_gateway: bool,
mut shutdown: TaskClient,
) -> Result<(), ClientCoreError> {
@@ -589,7 +565,7 @@ where
};
if let Err(err) = topology_refresher
.ensure_contains_routable_egress(local_gateway)
.ensure_contains_gateway(local_gateway)
.await
{
if let Some(waiting_timeout) = gateway_wait_timeout {
@@ -644,11 +620,9 @@ where
fn start_mix_traffic_controller(
gateway_transceiver: Box<dyn GatewayTransceiver + Send>,
shutdown: TaskClient,
forget_me: ForgetMe,
) -> BatchMixMessageSender {
info!("Starting mix traffic controller...");
let (mix_traffic_controller, mix_tx) =
MixTrafficController::new(gateway_transceiver, forget_me);
let (mix_traffic_controller, mix_tx) = MixTrafficController::new(gateway_transceiver);
mix_traffic_controller.start_with_shutdown(shutdown);
mix_tx
}
@@ -739,8 +713,7 @@ where
// channels responsible for controlling ack messages
let (ack_sender, ack_receiver) = mpsc::unbounded();
let shared_topology_accessor =
TopologyAccessor::new(self.config.debug.topology.ignore_egress_epoch_role);
let shared_topology_accessor = TopologyAccessor::new();
// Shutdown notifier for signalling tasks to stop
let shutdown = self
@@ -804,8 +777,6 @@ where
&details_store,
gateway_packet_router,
stats_reporter.clone(),
#[cfg(unix)]
self.connection_fd_callback,
shutdown.fork("gateway_transceiver"),
)
.await?;
@@ -831,11 +802,9 @@ where
// that are to be sent to the mixnet. They are used by cover traffic stream and real
// traffic stream.
// The MixTrafficController then sends the actual traffic
let message_sender = Self::start_mix_traffic_controller(
gateway_transceiver,
shutdown.fork("mix_traffic_controller"),
self.forget_me,
);
// Channels that the websocket listener can use to signal downstream to the real traffic
@@ -163,7 +163,6 @@ impl LoopCoverTrafficStream<OsRng> {
// poisson delay, but is it really a problem?
let topology_permit = self.topology_access.get_read_permit().await;
// the ack is sent back to ourselves (and then ignored)
let topology_ref = match topology_permit.try_get_valid_topology_ref(
&self.our_full_destination,
Some(&self.our_full_destination),
@@ -28,6 +28,7 @@ pub enum InputMessage {
recipient: Recipient,
data: Vec<u8>,
lane: TransmissionLane,
mix_hops: Option<u8>,
},
/// Creates a message used for a duplex anonymous communication where the recipient
@@ -43,6 +44,7 @@ pub enum InputMessage {
data: Vec<u8>,
reply_surbs: u32,
lane: TransmissionLane,
mix_hops: Option<u8>,
},
/// Attempt to use our internally received and stored `ReplySurb` to send the message back
@@ -92,6 +94,29 @@ impl InputMessage {
recipient,
data,
lane,
mix_hops: None,
};
if let Some(packet_type) = packet_type {
InputMessage::new_wrapper(message, packet_type)
} else {
message
}
}
// IMHO `new_regular` should take `mix_hops: Option<u8>` as an argument instead of creating
// this function, but that would potentially break backwards compatibility with the current API
pub fn new_regular_with_custom_hops(
recipient: Recipient,
data: Vec<u8>,
lane: TransmissionLane,
packet_type: Option<PacketType>,
mix_hops: Option<u8>,
) -> Self {
let message = InputMessage::Regular {
recipient,
data,
lane,
mix_hops,
};
if let Some(packet_type) = packet_type {
InputMessage::new_wrapper(message, packet_type)
@@ -112,6 +137,7 @@ impl InputMessage {
data,
reply_surbs,
lane,
mix_hops: None,
};
if let Some(packet_type) = packet_type {
InputMessage::new_wrapper(message, packet_type)
@@ -128,12 +154,14 @@ impl InputMessage {
reply_surbs: u32,
lane: TransmissionLane,
packet_type: Option<PacketType>,
mix_hops: Option<u8>,
) -> Self {
let message = InputMessage::Anonymous {
recipient,
data,
reply_surbs,
lane,
mix_hops,
};
if let Some(packet_type) = packet_type {
InputMessage::new_wrapper(message, packet_type)
@@ -2,9 +2,8 @@
// SPDX-License-Identifier: Apache-2.0
use crate::client::mix_traffic::transceiver::GatewayTransceiver;
use crate::{spawn_future, ForgetMe};
use crate::spawn_future;
use log::*;
use nym_gateway_requests::ClientRequest;
use nym_sphinx::forwarding::packet::MixPacket;
pub type BatchMixMessageSender = tokio::sync::mpsc::Sender<Vec<MixPacket>>;
@@ -27,14 +26,10 @@ pub struct MixTrafficController {
// TODO: this is temporary work-around.
// in long run `gateway_client` will be moved away from `MixTrafficController` anyway.
consecutive_gateway_failure_count: usize,
forget_me: ForgetMe,
}
impl MixTrafficController {
pub fn new<T>(
gateway_transceiver: T,
forget_me: ForgetMe,
) -> (MixTrafficController, BatchMixMessageSender)
pub fn new<T>(gateway_transceiver: T) -> (MixTrafficController, BatchMixMessageSender)
where
T: GatewayTransceiver + Send + 'static,
{
@@ -45,7 +40,6 @@ impl MixTrafficController {
gateway_transceiver: Box::new(gateway_transceiver),
mix_rx: message_receiver,
consecutive_gateway_failure_count: 0,
forget_me,
},
message_sender,
)
@@ -53,7 +47,6 @@ impl MixTrafficController {
pub fn new_dynamic(
gateway_transceiver: Box<dyn GatewayTransceiver + Send>,
forget_me: ForgetMe,
) -> (MixTrafficController, BatchMixMessageSender) {
let (message_sender, message_receiver) =
tokio::sync::mpsc::channel(MIX_MESSAGE_RECEIVER_BUFFER_SIZE);
@@ -62,7 +55,6 @@ impl MixTrafficController {
gateway_transceiver,
mix_rx: message_receiver,
consecutive_gateway_failure_count: 0,
forget_me,
},
message_sender,
)
@@ -119,27 +111,7 @@ impl MixTrafficController {
}
}
shutdown.recv_timeout().await;
if self.forget_me.any() {
log::info!("Sending forget me request to the gateway");
match self
.gateway_transceiver
.send_client_request(ClientRequest::ForgetMe {
client: self.forget_me.client(),
stats: self.forget_me.stats(),
})
.await
{
Ok(_) => {
log::info!("Successfully sent forget me request to the gateway");
}
Err(err) => {
log::error!("Failed to send forget me request to the gateway: {err}");
}
}
}
log::debug!("MixTrafficController: Exiting");
});
})
}
}
@@ -5,10 +5,8 @@ use async_trait::async_trait;
use log::{debug, error};
use nym_credential_storage::storage::Storage as CredentialStorage;
use nym_crypto::asymmetric::identity;
use nym_gateway_client::error::GatewayClientError;
use nym_gateway_client::GatewayClient;
pub use nym_gateway_client::{GatewayPacketRouter, PacketRouter};
use nym_gateway_requests::ClientRequest;
use nym_sphinx::forwarding::packet::MixPacket;
use nym_validator_client::nyxd::contract_traits::DkgQueryClient;
use std::fmt::Debug;
@@ -16,7 +14,7 @@ use std::os::raw::c_int as RawFd;
use thiserror::Error;
#[cfg(not(target_arch = "wasm32"))]
use futures::channel::oneshot;
use futures::channel::{mpsc, oneshot};
// we need to type erase the error type since we can't have dynamic associated types alongside dynamic dispatch
#[derive(Debug, Error)]
@@ -28,14 +26,9 @@ fn erase_err<E: std::error::Error + Send + Sync + 'static>(err: E) -> ErasedGate
}
/// This combines combines the functionalities of being able to send and receive mix packets.
#[async_trait]
pub trait GatewayTransceiver: GatewaySender + GatewayReceiver {
fn gateway_identity(&self) -> identity::PublicKey;
fn ws_fd(&self) -> Option<RawFd>;
async fn send_client_request(
&mut self,
message: ClientRequest,
) -> Result<(), GatewayClientError>;
}
/// This trait defines the functionality of sending `MixPacket` into the mixnet,
@@ -72,7 +65,6 @@ pub trait GatewayReceiver {
}
// to allow for dynamic dispatch
#[async_trait]
impl<G: GatewayTransceiver + ?Sized + Send> GatewayTransceiver for Box<G> {
#[inline]
fn gateway_identity(&self) -> identity::PublicKey {
@@ -81,13 +73,6 @@ impl<G: GatewayTransceiver + ?Sized + Send> GatewayTransceiver for Box<G> {
fn ws_fd(&self) -> Option<RawFd> {
(**self).ws_fd()
}
async fn send_client_request(
&mut self,
message: ClientRequest,
) -> Result<(), GatewayClientError> {
(**self).send_client_request(message).await
}
}
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
@@ -106,6 +91,7 @@ impl<G: GatewaySender + ?Sized + Send> GatewaySender for Box<G> {
(**self).batch_send_mix_packets(packets).await
}
}
impl<G: GatewayReceiver + ?Sized> GatewayReceiver for Box<G> {
#[inline]
fn set_packet_router(&mut self, packet_router: PacketRouter) -> Result<(), ErasedGatewayError> {
@@ -125,7 +111,6 @@ impl<C, St> RemoteGateway<C, St> {
}
}
#[async_trait]
impl<C, St> GatewayTransceiver for RemoteGateway<C, St>
where
C: DkgQueryClient + Send + Sync,
@@ -138,20 +123,6 @@ where
fn ws_fd(&self) -> Option<RawFd> {
self.gateway_client.ws_fd()
}
async fn send_client_request(
&mut self,
message: ClientRequest,
) -> Result<(), GatewayClientError> {
if let Some(shared_key) = self.gateway_client.shared_key() {
self.gateway_client
.send_websocket_message(message.encrypt(&*shared_key)?)
.await?;
Ok(())
} else {
Err(GatewayClientError::ConnectionInInvalidState)
}
}
}
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
@@ -199,7 +170,7 @@ pub struct LocalGateway {
// 'sender' part
/// Channel responsible for taking mix packets and forwarding them further into the further mixnet layers.
packet_forwarder: nym_mixnet_client::forwarder::MixForwardingSender,
packet_forwarder: mpsc::UnboundedSender<MixPacket>,
// 'receiver' part
packet_router_tx: Option<oneshot::Sender<PacketRouter>>,
@@ -209,7 +180,7 @@ pub struct LocalGateway {
impl LocalGateway {
pub fn new(
local_identity: identity::PublicKey,
packet_forwarder: nym_mixnet_client::forwarder::MixForwardingSender,
packet_forwarder: mpsc::UnboundedSender<MixPacket>,
packet_router_tx: oneshot::Sender<PacketRouter>,
) -> Self {
LocalGateway {
@@ -224,7 +195,6 @@ impl LocalGateway {
mod nonwasm_sealed {
use super::*;
#[async_trait]
impl GatewayTransceiver for LocalGateway {
fn gateway_identity(&self) -> identity::PublicKey {
self.local_identity
@@ -232,20 +202,14 @@ mod nonwasm_sealed {
fn ws_fd(&self) -> Option<RawFd> {
None
}
async fn send_client_request(
&mut self,
_message: ClientRequest,
) -> Result<(), GatewayClientError> {
Ok(())
}
}
#[async_trait]
impl GatewaySender for LocalGateway {
async fn send_mix_packet(&mut self, packet: MixPacket) -> Result<(), ErasedGatewayError> {
self.packet_forwarder
.forward_packet(packet)
.unbounded_send(packet)
.map_err(|err| err.into_send_error())
.map_err(erase_err)
}
}
@@ -306,7 +270,6 @@ impl GatewaySender for MockGateway {
}
}
#[async_trait]
impl GatewayTransceiver for MockGateway {
fn gateway_identity(&self) -> identity::PublicKey {
self.dummy_identity
@@ -314,11 +277,4 @@ impl GatewayTransceiver for MockGateway {
fn ws_fd(&self) -> Option<RawFd> {
None
}
async fn send_client_request(
&mut self,
_message: ClientRequest,
) -> Result<(), GatewayClientError> {
Ok(())
}
}
@@ -73,10 +73,11 @@ where
content: Vec<u8>,
lane: TransmissionLane,
packet_type: PacketType,
mix_hops: Option<u8>,
) {
if let Err(err) = self
.message_handler
.try_send_plain_message(recipient, content, lane, packet_type)
.try_send_plain_message(recipient, content, lane, packet_type, mix_hops)
.await
{
warn!("failed to send a plain message - {err}")
@@ -90,10 +91,18 @@ where
reply_surbs: u32,
lane: TransmissionLane,
packet_type: PacketType,
mix_hops: Option<u8>,
) {
if let Err(err) = self
.message_handler
.try_send_message_with_reply_surbs(recipient, content, reply_surbs, lane, packet_type)
.try_send_message_with_reply_surbs(
recipient,
content,
reply_surbs,
lane,
packet_type,
mix_hops,
)
.await
{
warn!("failed to send a repliable message - {err}")
@@ -106,8 +115,9 @@ where
recipient,
data,
lane,
mix_hops,
} => {
self.handle_plain_message(recipient, data, lane, PacketType::Mix)
self.handle_plain_message(recipient, data, lane, PacketType::Mix, mix_hops)
.await
}
InputMessage::Anonymous {
@@ -115,9 +125,17 @@ where
data,
reply_surbs,
lane,
mix_hops,
} => {
self.handle_repliable_message(recipient, data, reply_surbs, lane, PacketType::Mix)
.await
self.handle_repliable_message(
recipient,
data,
reply_surbs,
lane,
PacketType::Mix,
mix_hops,
)
.await
}
InputMessage::Reply {
recipient_tag,
@@ -135,8 +153,9 @@ where
recipient,
data,
lane,
mix_hops,
} => {
self.handle_plain_message(recipient, data, lane, packet_type)
self.handle_plain_message(recipient, data, lane, packet_type, mix_hops)
.await
}
InputMessage::Anonymous {
@@ -144,9 +163,17 @@ where
data,
reply_surbs,
lane,
mix_hops,
} => {
self.handle_repliable_message(recipient, data, reply_surbs, lane, packet_type)
.await
self.handle_repliable_message(
recipient,
data,
reply_surbs,
lane,
packet_type,
mix_hops,
)
.await
}
InputMessage::Reply {
recipient_tag,
@@ -70,6 +70,7 @@ pub(crate) struct PendingAcknowledgement {
message_chunk: Fragment,
delay: SphinxDelay,
destination: PacketDestination,
mix_hops: Option<u8>,
retransmissions: u32,
}
@@ -79,11 +80,13 @@ impl PendingAcknowledgement {
message_chunk: Fragment,
delay: SphinxDelay,
recipient: Recipient,
mix_hops: Option<u8>,
) -> Self {
PendingAcknowledgement {
message_chunk,
delay,
destination: PacketDestination::KnownRecipient(recipient.into()),
mix_hops,
retransmissions: 0,
}
}
@@ -101,6 +104,9 @@ impl PendingAcknowledgement {
recipient_tag,
extra_surb_request,
},
// Messages sent using SURBs are using the number of mix hops set by the recipient when
// they provided the SURBs, so it doesn't make sense to include it here.
mix_hops: None,
retransmissions: 0,
}
}
@@ -52,12 +52,18 @@ where
packet_recipient: Recipient,
chunk_data: Fragment,
packet_type: PacketType,
mix_hops: Option<u8>,
) -> Result<PreparedFragment, PreparationError> {
debug!("retransmitting normal packet...");
// TODO: Figure out retransmission packet type signaling
self.message_handler
.try_prepare_single_chunk_for_sending(packet_recipient, chunk_data, packet_type)
.try_prepare_single_chunk_for_sending(
packet_recipient,
chunk_data,
packet_type,
mix_hops,
)
.await
}
@@ -104,6 +110,7 @@ where
**recipient,
timed_out_ack.message_chunk.clone(),
packet_type,
timed_out_ack.mix_hops,
)
.await
}
@@ -15,11 +15,11 @@ use nym_sphinx::anonymous_replies::requests::{AnonymousSenderTag, RepliableMessa
use nym_sphinx::anonymous_replies::{ReplySurb, SurbEncryptionKey};
use nym_sphinx::chunking::fragment::{Fragment, FragmentIdentifier};
use nym_sphinx::message::NymMessage;
use nym_sphinx::params::{PacketSize, PacketType};
use nym_sphinx::params::{PacketSize, PacketType, DEFAULT_NUM_MIX_HOPS};
use nym_sphinx::preparer::{MessagePreparer, PreparedFragment};
use nym_sphinx::Delay;
use nym_task::connections::TransmissionLane;
use nym_topology::{NymRouteProvider, NymTopologyError};
use nym_topology::{NymTopology, NymTopologyError};
use rand::{CryptoRng, Rng};
use std::collections::HashMap;
use std::sync::Arc;
@@ -100,6 +100,10 @@ pub(crate) struct Config {
/// Average delay an acknowledgement packet is going to get delay at a single mixnode.
average_ack_delay: Duration,
/// Number of mix hops each packet ('real' message, ack, reply) is expected to take.
/// Note that it does not include gateway hops.
num_mix_hops: u8,
/// Primary predefined packet size used for the encapsulated messages.
primary_packet_size: PacketSize,
@@ -121,11 +125,19 @@ impl Config {
deterministic_route_selection,
average_packet_delay,
average_ack_delay,
num_mix_hops: DEFAULT_NUM_MIX_HOPS,
primary_packet_size: PacketSize::default(),
secondary_packet_size: None,
}
}
/// Allows setting non-default number of expected mix hops in the network.
#[allow(dead_code)]
pub fn with_mix_hops(mut self, hops: u8) -> Self {
self.num_mix_hops = hops;
self
}
/// Allows setting non-default size of the sphinx packets sent out.
pub fn with_custom_primary_packet_size(mut self, packet_size: PacketSize) -> Self {
self.primary_packet_size = packet_size;
@@ -173,7 +185,9 @@ where
config.sender_address,
config.average_packet_delay,
config.average_ack_delay,
);
)
.with_mix_hops(config.num_mix_hops);
MessageHandler {
config,
rng,
@@ -202,7 +216,7 @@ where
fn get_topology<'a>(
&self,
permit: &'a TopologyReadPermit<'a>,
) -> Result<&'a NymRouteProvider, PreparationError> {
) -> Result<&'a NymTopology, PreparationError> {
match permit.try_get_valid_topology_ref(&self.config.sender_address, None) {
Ok(topology_ref) => Ok(topology_ref),
Err(err) => {
@@ -219,8 +233,9 @@ where
return self.config.primary_packet_size;
};
let primary_count = msg.required_packets(self.config.primary_packet_size);
let secondary_count = msg.required_packets(secondary_packet);
let primary_count =
msg.required_packets(self.config.primary_packet_size, self.config.num_mix_hops);
let secondary_count = msg.required_packets(secondary_packet, self.config.num_mix_hops);
trace!("This message would require: {primary_count} primary packets or {secondary_count} secondary packets...");
// if there would be no benefit in using the secondary packet - use the primary (duh)
@@ -409,9 +424,10 @@ where
message: Vec<u8>,
lane: TransmissionLane,
packet_type: PacketType,
mix_hops: Option<u8>,
) -> Result<(), PreparationError> {
let message = NymMessage::new_plain(message);
self.try_split_and_send_non_reply_message(message, recipient, lane, packet_type)
self.try_split_and_send_non_reply_message(message, recipient, lane, packet_type, mix_hops)
.await
}
@@ -421,6 +437,7 @@ where
recipient: Recipient,
lane: TransmissionLane,
packet_type: PacketType,
mix_hops: Option<u8>,
) -> Result<(), PreparationError> {
debug!("Sending non-reply message with packet type {packet_type}");
// TODO: I really dislike existence of this assertion, it implies code has to be re-organised
@@ -453,6 +470,7 @@ where
&self.config.ack_key,
&recipient,
packet_type,
mix_hops,
)?;
let real_message = RealMessage::new(
@@ -460,7 +478,8 @@ where
Some(fragment.fragment_identifier()),
);
let delay = prepared_fragment.total_delay;
let pending_ack = PendingAcknowledgement::new_known(fragment, delay, recipient);
let pending_ack =
PendingAcknowledgement::new_known(fragment, delay, recipient, mix_hops);
real_messages.push(real_message);
pending_acks.push(pending_ack);
@@ -477,6 +496,7 @@ where
recipient: Recipient,
amount: u32,
packet_type: PacketType,
mix_hops: Option<u8>,
) -> Result<(), PreparationError> {
debug!("Sending additional reply SURBs with packet type {packet_type}");
let sender_tag = self.get_or_create_sender_tag(&recipient);
@@ -493,6 +513,7 @@ where
recipient,
TransmissionLane::AdditionalReplySurbs,
packet_type,
mix_hops,
)
.await?;
@@ -509,6 +530,7 @@ where
num_reply_surbs: u32,
lane: TransmissionLane,
packet_type: PacketType,
mix_hops: Option<u8>,
) -> Result<(), SurbWrappedPreparationError> {
debug!("Sending message with reply SURBs with packet type {packet_type}");
let sender_tag = self.get_or_create_sender_tag(&recipient);
@@ -519,7 +541,7 @@ where
let message =
NymMessage::new_repliable(RepliableMessage::new_data(message, sender_tag, reply_surbs));
self.try_split_and_send_non_reply_message(message, recipient, lane, packet_type)
self.try_split_and_send_non_reply_message(message, recipient, lane, packet_type, mix_hops)
.await?;
log::trace!("storing {} reply keys", reply_keys.len());
@@ -533,18 +555,23 @@ where
recipient: Recipient,
chunk: Fragment,
packet_type: PacketType,
mix_hops: Option<u8>,
) -> Result<PreparedFragment, PreparationError> {
debug!("Sending single chunk with packet type {packet_type}");
let topology_permit = self.topology_access.get_read_permit().await;
let topology = self.get_topology(&topology_permit)?;
let prepared_fragment = self.message_preparer.prepare_chunk_for_sending(
chunk,
topology,
&self.config.ack_key,
&recipient,
packet_type,
)?;
let prepared_fragment = self
.message_preparer
.prepare_chunk_for_sending(
chunk,
topology,
&self.config.ack_key,
&recipient,
packet_type,
mix_hops,
)
.unwrap();
Ok(prepared_fragment)
}
@@ -597,13 +624,16 @@ where
Err(err) => return Err(err.return_surbs(vec![reply_surb])),
};
let prepared_fragment = self.message_preparer.prepare_reply_chunk_for_sending(
chunk,
topology,
&self.config.ack_key,
reply_surb,
PacketType::Mix,
)?;
let prepared_fragment = self
.message_preparer
.prepare_reply_chunk_for_sending(
chunk,
topology,
&self.config.ack_key,
reply_surb,
PacketType::Mix,
)
.unwrap();
Ok(prepared_fragment)
}
@@ -230,7 +230,6 @@ where
// poisson delay, but is it really a problem?
let topology_permit = self.topology_access.get_read_permit().await;
// the ack is sent back to ourselves (and then ignored)
let topology_ref = match topology_permit.try_get_valid_topology_ref(
&self.config.our_full_destination,
Some(&self.config.our_full_destination),
@@ -516,6 +516,7 @@ where
recipient,
to_send,
nym_sphinx::params::PacketType::Mix,
self.config.reply_surbs.surb_mix_hops,
)
.await
{
@@ -2,7 +2,8 @@
// SPDX-License-Identifier: Apache-2.0
use nym_sphinx::addressing::clients::Recipient;
use nym_topology::{NymRouteProvider, NymTopology, NymTopologyError};
use nym_sphinx::params::DEFAULT_NUM_MIX_HOPS;
use nym_topology::{NymTopology, NymTopologyError};
use std::ops::Deref;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
@@ -16,36 +17,29 @@ pub struct TopologyAccessorInner {
// few seconds, while reads are needed every single packet generated.
// However, proper benchmarks will be needed to determine if `RwLock` is indeed a better
// approach than a `Mutex`
topology: RwLock<NymRouteProvider>,
topology: RwLock<Option<NymTopology>>,
}
impl TopologyAccessorInner {
fn new(initial: NymRouteProvider) -> Self {
fn new() -> Self {
TopologyAccessorInner {
controlled_manually: AtomicBool::new(false),
released_manual_control: Notify::new(),
topology: RwLock::new(initial),
topology: RwLock::new(None),
}
}
async fn update(&self, new: Option<NymTopology>) {
let mut guard = self.topology.write().await;
match new {
Some(updated) => {
guard.update(updated);
}
None => guard.clear_topology(),
}
*self.topology.write().await = new;
}
}
pub struct TopologyReadPermit<'a> {
permit: RwLockReadGuard<'a, NymRouteProvider>,
permit: RwLockReadGuard<'a, Option<NymTopology>>,
}
impl Deref for TopologyReadPermit<'_> {
type Target = NymRouteProvider;
type Target = Option<NymTopology>;
fn deref(&self) -> &Self::Target {
&self.permit
@@ -59,31 +53,43 @@ impl<'a> TopologyReadPermit<'a> {
&'a self,
ack_recipient: &Recipient,
packet_recipient: Option<&Recipient>,
) -> Result<&'a NymRouteProvider, NymTopologyError> {
let route_provider = self.permit.deref();
let topology = &route_provider.topology;
) -> Result<&'a NymTopology, NymTopologyError> {
// 1. Have we managed to get anything from the refresher, i.e. have the nym-api queries gone through?
topology.ensure_not_empty()?;
let topology = self
.permit
.as_ref()
.ok_or(NymTopologyError::EmptyNetworkTopology)?;
// 2. does the topology have a node on each mixing layer?
topology.ensure_minimally_routable()?;
// 2. does it have any mixnode at all?
// 3. does it have any gateways at all?
// 4. does it have a mixnode on each layer?
topology.ensure_can_construct_path_through(DEFAULT_NUM_MIX_HOPS)?;
// 3. does it contain OUR gateway (so that we could create an ack packet)?
let _ = route_provider.egress_by_identity(ack_recipient.gateway())?;
// 4. for our target recipient, does it contain THEIR gateway (so that we send anything over?)
if let Some(recipient) = packet_recipient {
let _ = route_provider.egress_by_identity(recipient.gateway())?;
// 5. does it contain OUR gateway (so that we could create an ack packet)?
if !topology.gateway_exists(ack_recipient.gateway()) {
return Err(NymTopologyError::NonExistentGatewayError {
identity_key: ack_recipient.gateway().to_base58_string(),
});
}
Ok(route_provider)
// 6. for our target recipient, does it contain THEIR gateway (so that we could create
if let Some(recipient) = packet_recipient {
if !topology.gateway_exists(recipient.gateway()) {
return Err(NymTopologyError::NonExistentGatewayError {
identity_key: recipient.gateway().to_base58_string(),
});
}
}
Ok(topology)
}
}
impl<'a> From<RwLockReadGuard<'a, NymRouteProvider>> for TopologyReadPermit<'a> {
fn from(permit: RwLockReadGuard<'a, NymRouteProvider>) -> Self {
TopologyReadPermit { permit }
impl<'a> From<RwLockReadGuard<'a, Option<NymTopology>>> for TopologyReadPermit<'a> {
fn from(read_permit: RwLockReadGuard<'a, Option<NymTopology>>) -> Self {
TopologyReadPermit {
permit: read_permit,
}
}
}
@@ -93,11 +99,9 @@ pub struct TopologyAccessor {
}
impl TopologyAccessor {
pub fn new(ignore_egress_epoch_roles: bool) -> Self {
pub fn new() -> Self {
TopologyAccessor {
inner: Arc::new(TopologyAccessorInner::new(NymRouteProvider::new_empty(
ignore_egress_epoch_roles,
))),
inner: Arc::new(TopologyAccessorInner::new()),
}
}
@@ -117,21 +121,8 @@ impl TopologyAccessor {
self.inner.released_manual_control.notified().await
}
#[deprecated(note = "use .current_route_provider instead")]
pub async fn current_topology(&self) -> Option<NymTopology> {
self.current_route_provider()
.await
.as_ref()
.map(|p| p.topology.clone())
}
pub async fn current_route_provider(&self) -> Option<RwLockReadGuard<NymRouteProvider>> {
let provider = self.inner.topology.read().await;
if provider.topology.is_empty() {
None
} else {
Some(provider)
}
self.inner.topology.read().await.clone()
}
pub async fn manually_change_topology(&self, new_topology: NymTopology) {
@@ -149,11 +140,15 @@ impl TopologyAccessor {
// only used by the client at startup to get a slightly more reasonable error message
// (currently displays as unused because health checker is disabled due to required changes)
pub async fn ensure_is_routable(&self) -> Result<(), NymTopologyError> {
self.inner
.topology
.read()
.await
.topology
.ensure_minimally_routable()
match self.inner.topology.read().await.deref() {
None => Err(NymTopologyError::EmptyNetworkTopology),
Some(ref topology) => topology.ensure_can_construct_path_through(DEFAULT_NUM_MIX_HOPS),
}
}
}
impl Default for TopologyAccessor {
fn default() -> Self {
TopologyAccessor::new()
}
}
@@ -3,6 +3,7 @@ use log::{debug, error};
use nym_explorer_client::{ExplorerClient, PrettyDetailedMixNodeBond};
use nym_network_defaults::var_names::EXPLORER_API;
use nym_topology::{
nym_topology_from_basic_info,
provider_trait::{async_trait, TopologyProvider},
NymTopology,
};
@@ -14,6 +15,8 @@ use url::Url;
pub use nym_country_group::CountryGroup;
const MIN_NODES_PER_LAYER: usize = 1;
fn create_explorer_client() -> Option<ExplorerClient> {
let Ok(explorer_api_url) = std::env::var(EXPLORER_API) else {
error!("Missing EXPLORER_API");
@@ -60,22 +63,37 @@ fn log_mixnode_distribution(mixnodes: &HashMap<CountryGroup, Vec<NodeId>>) {
}
fn check_layer_integrity(topology: NymTopology) -> Result<(), ()> {
if topology.ensure_minimally_routable().is_err() {
let mixes = topology.mixes();
if mixes.keys().len() < 3 {
error!("Layer is missing in topology!");
return Err(());
}
for (layer, mixnodes) in mixes {
debug!("Layer {:?} has {} mixnodes", layer, mixnodes.len());
if mixnodes.len() < MIN_NODES_PER_LAYER {
error!(
"There are only {} mixnodes in layer {:?}",
mixnodes.len(),
layer
);
return Err(());
}
}
Ok(())
}
#[deprecated(note = "use NymApiTopologyProvider instead as explorer API will soon be removed")]
pub struct GeoAwareTopologyProvider {
validator_client: nym_validator_client::client::NymApiClient,
filter_on: GroupBy,
client_version: String,
}
#[allow(deprecated)]
impl GeoAwareTopologyProvider {
pub fn new(mut nym_api_urls: Vec<Url>, filter_on: GroupBy) -> GeoAwareTopologyProvider {
pub fn new(
mut nym_api_urls: Vec<Url>,
client_version: String,
filter_on: GroupBy,
) -> GeoAwareTopologyProvider {
log::info!(
"Creating geo-aware topology provider with filter on {}",
filter_on
@@ -87,22 +105,14 @@ impl GeoAwareTopologyProvider {
nym_api_urls[0].clone(),
),
filter_on,
client_version,
}
}
async fn get_topology(&self) -> Option<NymTopology> {
let rewarded_set = self
.validator_client
.get_current_rewarded_set()
.await
.inspect_err(|err| error!("failed to get current rewarded set: {err}"))
.ok()?;
let mut topology = NymTopology::new_empty(rewarded_set);
let mixnodes = match self
.validator_client
.get_all_basic_active_mixing_assigned_nodes()
.get_all_basic_active_mixing_assigned_nodes(Some(self.client_version.clone()))
.await
{
Err(err) => {
@@ -114,7 +124,7 @@ impl GeoAwareTopologyProvider {
let gateways = match self
.validator_client
.get_all_basic_entry_assigned_nodes()
.get_all_basic_entry_assigned_nodes(Some(self.client_version.clone()))
.await
{
Err(err) => {
@@ -183,8 +193,7 @@ impl GeoAwareTopologyProvider {
.filter(|m| filtered_mixnode_ids.contains(&m.node_id))
.collect::<Vec<_>>();
topology.add_skimmed_nodes(&mixnodes);
topology.add_skimmed_nodes(&gateways);
let topology = nym_topology_from_basic_info(&mixnodes, &gateways);
// TODO: return real error type
check_layer_integrity(topology.clone()).ok()?;
@@ -193,7 +202,6 @@ impl GeoAwareTopologyProvider {
}
}
#[allow(deprecated)]
#[cfg(not(target_arch = "wasm32"))]
#[async_trait]
impl TopologyProvider for GeoAwareTopologyProvider {
@@ -203,7 +211,6 @@ impl TopologyProvider for GeoAwareTopologyProvider {
}
}
#[allow(deprecated)]
#[cfg(target_arch = "wasm32")]
#[async_trait(?Send)]
impl TopologyProvider for GeoAwareTopologyProvider {
@@ -19,7 +19,6 @@ mod accessor;
pub mod geo_aware_provider;
pub mod nym_api_provider;
#[allow(deprecated)]
pub use geo_aware_provider::GeoAwareTopologyProvider;
pub use nym_api_provider::{Config as NymApiTopologyProviderConfig, NymApiTopologyProvider};
pub use nym_topology::provider_trait::TopologyProvider;
@@ -28,7 +27,7 @@ pub use nym_topology::provider_trait::TopologyProvider;
const MAX_FAILURE_COUNT: usize = 10;
pub struct TopologyRefresherConfig {
pub refresh_rate: Duration,
refresh_rate: Duration,
}
impl TopologyRefresherConfig {
@@ -97,24 +96,28 @@ impl TopologyRefresher {
self.topology_accessor.ensure_is_routable().await
}
pub async fn ensure_contains_routable_egress(
pub async fn ensure_contains_gateway(
&self,
egress: NodeIdentity,
gateway: &NodeIdentity,
) -> Result<(), NymTopologyError> {
let topology = self
.topology_accessor
.current_route_provider()
.current_topology()
.await
.ok_or(NymTopologyError::EmptyNetworkTopology)?;
let _ = topology.egress_by_identity(egress)?;
if !topology.gateway_exists(gateway) {
return Err(NymTopologyError::NonExistentGatewayError {
identity_key: gateway.to_base58_string(),
});
}
Ok(())
}
pub async fn wait_for_gateway(
&mut self,
gateway: NodeIdentity,
gateway: &NodeIdentity,
timeout_duration: Duration,
) -> Result<(), NymTopologyError> {
info!(
@@ -132,7 +135,7 @@ impl TopologyRefresher {
})
}
_ = self.try_refresh() => {
if self.ensure_contains_routable_egress(gateway).await.is_ok() {
if self.ensure_contains_gateway(gateway).await.is_ok() {
return Ok(())
}
info!("gateway '{gateway}' is still not online...");
@@ -4,51 +4,47 @@
use async_trait::async_trait;
use log::{debug, error, warn};
use nym_topology::provider_trait::TopologyProvider;
use nym_topology::NymTopology;
use nym_topology::{NymTopology, NymTopologyError};
use nym_validator_client::UserAgent;
use rand::prelude::SliceRandom;
use rand::thread_rng;
use std::cmp::min;
use url::Url;
// the same values as our current (10.06.24) blacklist
pub const DEFAULT_MIN_MIXNODE_PERFORMANCE: u8 = 50;
pub const DEFAULT_MIN_GATEWAY_PERFORMANCE: u8 = 50;
#[derive(Debug)]
pub struct Config {
pub min_mixnode_performance: u8,
pub min_gateway_performance: u8,
pub use_extended_topology: bool,
pub ignore_egress_epoch_role: bool,
}
impl From<nym_client_core_config_types::Topology> for Config {
fn from(value: nym_client_core_config_types::Topology) -> Self {
impl Default for Config {
fn default() -> Self {
// old values that decided on blacklist membership
Config {
min_mixnode_performance: value.minimum_mixnode_performance,
min_gateway_performance: value.minimum_gateway_performance,
use_extended_topology: value.use_extended_topology,
ignore_egress_epoch_role: value.ignore_egress_epoch_role,
min_mixnode_performance: DEFAULT_MIN_MIXNODE_PERFORMANCE,
min_gateway_performance: DEFAULT_MIN_GATEWAY_PERFORMANCE,
}
}
}
impl Config {
// if we're using 'extended' topology, filter the nodes based on the lowest set performance
fn min_node_performance(&self) -> u8 {
min(self.min_mixnode_performance, self.min_gateway_performance)
}
}
pub struct NymApiTopologyProvider {
config: Config,
validator_client: nym_validator_client::client::NymApiClient,
nym_api_urls: Vec<Url>,
client_version: String,
currently_used_api: usize,
}
impl NymApiTopologyProvider {
pub fn new(
config: impl Into<Config>,
config: Config,
mut nym_api_urls: Vec<Url>,
client_version: String,
user_agent: Option<UserAgent>,
) -> Self {
nym_api_urls.shuffle(&mut thread_rng());
@@ -63,9 +59,10 @@ impl NymApiTopologyProvider {
};
NymApiTopologyProvider {
config: config.into(),
config,
validator_client,
nym_api_urls,
client_version,
currently_used_api: 0,
}
}
@@ -81,69 +78,70 @@ impl NymApiTopologyProvider {
.change_nym_api(self.nym_api_urls[self.currently_used_api].clone())
}
/// Verifies whether nodes a reasonably distributed among all mix layers.
///
/// In ideal world we would have 33% nodes on layer 1, 33% on layer 2 and 33% on layer 3.
/// However, this is a rather unrealistic expectation, instead we check whether there exists
/// a layer with more than 66% of nodes or with fewer than 15% and if so, we trigger a failure.
///
/// # Arguments
///
/// * `topology`: active topology constructed from validator api data
fn check_layer_distribution(
&self,
active_topology: &NymTopology,
) -> Result<(), NymTopologyError> {
let lower_threshold = 0.15;
let upper_threshold = 0.66;
active_topology.ensure_even_layer_distribution(lower_threshold, upper_threshold)
}
async fn get_current_compatible_topology(&mut self) -> Option<NymTopology> {
let rewarded_set = self
let mixnodes = match self
.validator_client
.get_current_rewarded_set()
.get_all_basic_active_mixing_assigned_nodes(Some(self.client_version.clone()))
.await
.inspect_err(|err| error!("failed to get current rewarded set: {err}"))
.ok()?;
let mut topology = NymTopology::new_empty(rewarded_set);
if self.config.use_extended_topology {
let all_nodes = self
.validator_client
.get_all_basic_nodes()
.await
.inspect_err(|err| error!("failed to get network nodes: {err}"))
.ok()?;
debug!(
"there are {} nodes on the network (before filtering)",
all_nodes.len()
);
topology.add_additional_nodes(all_nodes.iter().filter(|n| {
n.performance.round_to_integer() >= self.config.min_node_performance()
}));
} else {
// if we're not using extended topology, we're only getting active set mixnodes and gateways
let mixnodes = self
.validator_client
.get_all_basic_active_mixing_assigned_nodes()
.await
.inspect_err(|err| error!("failed to get network mixnodes: {err}"))
.ok()?;
// TODO: we really should be getting ACTIVE gateways only
let gateways = self
.validator_client
.get_all_basic_entry_assigned_nodes()
.await
.inspect_err(|err| error!("failed to get network gateways: {err}"))
.ok()?;
debug!(
"there are {} mixnodes and {} gateways in total (before performance filtering)",
mixnodes.len(),
gateways.len()
);
topology.add_additional_nodes(mixnodes.iter().filter(|m| {
m.performance.round_to_integer() >= self.config.min_mixnode_performance
}));
topology.add_additional_nodes(gateways.iter().filter(|m| {
m.performance.round_to_integer() >= self.config.min_gateway_performance
}));
{
Err(err) => {
error!("failed to get network mixnodes - {err}");
return None;
}
Ok(mixes) => mixes,
};
if !topology.is_minimally_routable() {
error!("the current filtered active topology can't be used to construct any packets");
return None;
}
let gateways = match self
.validator_client
.get_all_basic_entry_assigned_nodes(Some(self.client_version.clone()))
.await
{
Err(err) => {
error!("failed to get network gateways - {err}");
return None;
}
Ok(gateways) => gateways,
};
Some(topology)
debug!(
"there are {} mixnodes and {} gateways in total (before performance filtering)",
mixnodes.len(),
gateways.len()
);
let topology = NymTopology::from_unordered(
mixnodes.iter().filter(|m| {
m.performance.round_to_integer() >= self.config.min_mixnode_performance
}),
gateways.iter().filter(|g| {
g.performance.round_to_integer() >= self.config.min_gateway_performance
}),
);
if let Err(err) = self.check_layer_distribution(&topology) {
warn!("The current filtered active topology has extremely skewed layer distribution. It cannot be used: {err}");
self.use_next_nym_api();
None
} else {
Some(topology)
}
}
}
@@ -152,11 +150,7 @@ impl NymApiTopologyProvider {
#[async_trait]
impl TopologyProvider for NymApiTopologyProvider {
async fn get_new_topology(&mut self) -> Option<NymTopology> {
let Some(topology) = self.get_current_compatible_topology().await else {
self.use_next_nym_api();
return None;
};
Some(topology)
self.get_current_compatible_topology().await
}
}
@@ -164,10 +158,6 @@ impl TopologyProvider for NymApiTopologyProvider {
#[async_trait(?Send)]
impl TopologyProvider for NymApiTopologyProvider {
async fn get_new_topology(&mut self) -> Option<NymTopology> {
let Some(topology) = self.get_current_compatible_topology().await else {
self.use_next_nym_api();
return None;
};
Some(topology)
self.get_current_compatible_topology().await
}
}
+4 -7
View File
@@ -4,8 +4,8 @@
use crate::client::mix_traffic::transceiver::ErasedGatewayError;
use nym_crypto::asymmetric::identity::Ed25519RecoveryError;
use nym_gateway_client::error::GatewayClientError;
use nym_topology::node::RoutingNodeError;
use nym_topology::{NodeId, NymTopologyError};
use nym_topology::gateway::GatewayConversionError;
use nym_topology::NymTopologyError;
use nym_validator_client::ValidatorClientError;
use std::error::Error;
use std::path::PathBuf;
@@ -74,10 +74,10 @@ pub enum ClientCoreError {
#[error("the gateway id is invalid - {0}")]
UnableToCreatePublicKeyFromGatewayId(Ed25519RecoveryError),
#[error("the node is malformed: {source}")]
#[error("The gateway is malformed: {source}")]
MalformedGateway {
#[from]
source: Box<RoutingNodeError>,
source: GatewayConversionError,
},
#[error("failed to establish connection to gateway: {source}")]
@@ -159,9 +159,6 @@ pub enum ClientCoreError {
#[error("the specified gateway '{gateway}' does not support the wss protocol")]
UnsupportedWssProtocol { gateway: String },
#[error("node {id} ({identity}) does not support mixnet entry mode")]
UnsupportedEntry { id: NodeId, identity: String },
#[error(
"failed to load custom topology using path '{}'. detailed message: {source}", file_path.display()
)]
+45 -49
View File
@@ -7,7 +7,7 @@ use futures::{SinkExt, StreamExt};
use log::{debug, info, trace, warn};
use nym_crypto::asymmetric::identity;
use nym_gateway_client::GatewayClient;
use nym_topology::node::RoutingNode;
use nym_topology::{gateway, mix};
use nym_validator_client::client::IdentityKeyRef;
use nym_validator_client::UserAgent;
use rand::{seq::SliceRandom, Rng};
@@ -15,7 +15,6 @@ use std::{sync::Arc, time::Duration};
use tungstenite::Message;
use url::Url;
use nym_topology::NodeId;
#[cfg(not(target_arch = "wasm32"))]
use tokio::net::TcpStream;
#[cfg(not(target_arch = "wasm32"))]
@@ -26,6 +25,7 @@ use tokio::time::Instant;
use tokio_tungstenite::connect_async;
#[cfg(not(target_arch = "wasm32"))]
use tokio_tungstenite::{MaybeTlsStream, WebSocketStream};
#[cfg(target_arch = "wasm32")]
use wasm_utils::websocket::JSWebsocket;
#[cfg(target_arch = "wasm32")]
@@ -48,30 +48,22 @@ const PING_TIMEOUT: Duration = Duration::from_millis(1000);
// The abstraction that some of these helpers use
pub trait ConnectableGateway {
fn node_id(&self) -> NodeId;
fn identity(&self) -> identity::PublicKey;
fn clients_address(&self, prefer_ipv6: bool) -> Option<String>;
fn identity(&self) -> &identity::PublicKey;
fn clients_address(&self) -> String;
fn is_wss(&self) -> bool;
}
impl ConnectableGateway for RoutingNode {
fn node_id(&self) -> NodeId {
self.node_id
impl ConnectableGateway for gateway::LegacyNode {
fn identity(&self) -> &identity::PublicKey {
self.identity()
}
fn identity(&self) -> identity::PublicKey {
self.identity_key
}
fn clients_address(&self, prefer_ipv6: bool) -> Option<String> {
self.ws_entry_address(prefer_ipv6)
fn clients_address(&self) -> String {
self.clients_address()
}
fn is_wss(&self) -> bool {
self.entry
.as_ref()
.map(|e| e.clients_wss_port.is_some())
.unwrap_or_default()
self.clients_wss_port.is_some()
}
}
@@ -90,8 +82,7 @@ pub async fn current_gateways<R: Rng>(
rng: &mut R,
nym_apis: &[Url],
user_agent: Option<UserAgent>,
minimum_performance: u8,
) -> Result<Vec<RoutingNode>, ClientCoreError> {
) -> Result<Vec<gateway::LegacyNode>, ClientCoreError> {
let nym_api = nym_apis
.choose(rng)
.ok_or(ClientCoreError::ListOfNymApisIsEmpty)?;
@@ -103,27 +94,44 @@ pub async fn current_gateways<R: Rng>(
log::debug!("Fetching list of gateways from: {nym_api}");
let gateways = client.get_all_basic_entry_assigned_nodes().await?;
info!("nym api reports {} gateways", gateways.len());
let gateways = client.get_all_basic_entry_assigned_nodes(None).await?;
log::debug!("Found {} gateways", gateways.len());
log::trace!("Gateways: {:#?}", gateways);
let valid_gateways = gateways
.iter()
.filter(|g| g.performance.round_to_integer() >= minimum_performance)
.filter_map(|gateway| gateway.try_into().ok())
.collect::<Vec<_>>();
.collect::<Vec<gateway::LegacyNode>>();
log::debug!("After checking validity: {}", valid_gateways.len());
log::trace!("Valid gateways: {:#?}", valid_gateways);
log::info!(
"and {} after validity and performance filtering",
valid_gateways.len()
);
log::info!("nym-api reports {} valid gateways", valid_gateways.len());
Ok(valid_gateways)
}
pub async fn current_mixnodes<R: Rng>(
rng: &mut R,
nym_apis: &[Url],
) -> Result<Vec<mix::LegacyNode>, ClientCoreError> {
let nym_api = nym_apis
.choose(rng)
.ok_or(ClientCoreError::ListOfNymApisIsEmpty)?;
let client = nym_validator_client::client::NymApiClient::new(nym_api.clone());
log::trace!("Fetching list of mixnodes from: {nym_api}");
let mixnodes = client
.get_all_basic_active_mixing_assigned_nodes(None)
.await?;
let valid_mixnodes = mixnodes
.iter()
.filter_map(|mixnode| mixnode.try_into().ok())
.collect::<Vec<mix::LegacyNode>>();
Ok(valid_mixnodes)
}
#[cfg(not(target_arch = "wasm32"))]
async fn connect(endpoint: &str) -> Result<WsConn, ClientCoreError> {
match tokio::time::timeout(CONN_TIMEOUT, connect_async(endpoint)).await {
@@ -142,12 +150,7 @@ async fn measure_latency<G>(gateway: &G) -> Result<GatewayWithLatency<G>, Client
where
G: ConnectableGateway,
{
let Some(addr) = gateway.clients_address(false) else {
return Err(ClientCoreError::UnsupportedEntry {
id: gateway.node_id(),
identity: gateway.identity().to_string(),
});
};
let addr = gateway.clients_address();
trace!(
"establishing connection to {} ({addr})...",
gateway.identity(),
@@ -203,7 +206,7 @@ where
Ok(GatewayWithLatency::new(gateway, avg))
}
pub async fn choose_gateway_by_latency<R: Rng, G: ConnectableGateway + Clone>(
pub async fn choose_gateway_by_latency<'a, R: Rng, G: ConnectableGateway + Clone>(
rng: &mut R,
gateways: &[G],
must_use_tls: bool,
@@ -218,7 +221,7 @@ pub async fn choose_gateway_by_latency<R: Rng, G: ConnectableGateway + Clone>(
let gateways_with_latency = Arc::new(tokio::sync::Mutex::new(Vec::new()));
futures::stream::iter(gateways)
.for_each_concurrent(CONCURRENT_GATEWAYS_MEASURED, |gateway| async {
let id = gateway.identity();
let id = *gateway.identity();
trace!("measuring latency to {id}...");
match measure_latency(gateway).await {
Ok(with_latency) => {
@@ -265,9 +268,9 @@ fn filter_by_tls<G: ConnectableGateway>(
pub(super) fn uniformly_random_gateway<R: Rng>(
rng: &mut R,
gateways: &[RoutingNode],
gateways: &[gateway::LegacyNode],
must_use_tls: bool,
) -> Result<RoutingNode, ClientCoreError> {
) -> Result<gateway::LegacyNode, ClientCoreError> {
filter_by_tls(gateways, must_use_tls)?
.choose(rng)
.ok_or(ClientCoreError::NoGatewaysOnNetwork)
@@ -276,9 +279,9 @@ pub(super) fn uniformly_random_gateway<R: Rng>(
pub(super) fn get_specified_gateway(
gateway_identity: IdentityKeyRef,
gateways: &[RoutingNode],
gateways: &[gateway::LegacyNode],
must_use_tls: bool,
) -> Result<RoutingNode, ClientCoreError> {
) -> Result<gateway::LegacyNode, ClientCoreError> {
log::debug!("Requesting specified gateway: {}", gateway_identity);
let user_gateway = identity::PublicKey::from_base58_string(gateway_identity)
.map_err(ClientCoreError::UnableToCreatePublicKeyFromGatewayId)?;
@@ -288,14 +291,7 @@ pub(super) fn get_specified_gateway(
.find(|gateway| gateway.identity_key == user_gateway)
.ok_or_else(|| ClientCoreError::NoGatewayWithId(gateway_identity.to_string()))?;
let Some(entry_details) = gateway.entry.as_ref() else {
return Err(ClientCoreError::UnsupportedEntry {
id: gateway.node_id,
identity: gateway.identity().to_string(),
});
};
if must_use_tls && entry_details.clients_wss_port.is_none() {
if must_use_tls && gateway.clients_wss_port.is_none() {
return Err(ClientCoreError::UnsupportedWssProtocol {
gateway: gateway_identity.to_string(),
});
+2 -2
View File
@@ -19,7 +19,7 @@ use crate::init::types::{
use nym_client_core_gateways_storage::GatewaysDetailsStore;
use nym_client_core_gateways_storage::{GatewayDetails, GatewayRegistration};
use nym_gateway_client::client::InitGatewayClient;
use nym_topology::node::RoutingNode;
use nym_topology::gateway;
use rand::rngs::OsRng;
use rand::{CryptoRng, RngCore};
use serde::Serialize;
@@ -50,7 +50,7 @@ async fn setup_new_gateway<K, D>(
key_store: &K,
details_store: &D,
selection_specification: GatewaySelectionSpecification,
available_gateways: Vec<RoutingNode>,
available_gateways: Vec<gateway::LegacyNode>,
) -> Result<InitialisationResult, ClientCoreError>
where
K: KeyStore,
+5 -12
View File
@@ -13,7 +13,7 @@ use nym_crypto::asymmetric::identity;
use nym_gateway_client::client::InitGatewayClient;
use nym_gateway_requests::shared_key::SharedGatewayKey;
use nym_sphinx::addressing::clients::Recipient;
use nym_topology::node::RoutingNode;
use nym_topology::gateway;
use nym_validator_client::client::IdentityKey;
use nym_validator_client::nyxd::AccountId;
use serde::Serialize;
@@ -38,23 +38,16 @@ pub enum SelectedGateway {
impl SelectedGateway {
pub fn from_topology_node(
node: RoutingNode,
node: gateway::LegacyNode,
must_use_tls: bool,
) -> Result<Self, ClientCoreError> {
// for now, let's use 'old' behaviour, if you want to change it, you can pass it up the enum stack yourself : )
let prefer_ipv6 = false;
let gateway_listener = if must_use_tls {
node.ws_entry_address_tls()
node.clients_address_tls()
.ok_or(ClientCoreError::UnsupportedWssProtocol {
gateway: node.identity_key.to_base58_string(),
})?
} else {
node.ws_entry_address(prefer_ipv6)
.ok_or(ClientCoreError::UnsupportedEntry {
id: node.node_id,
identity: node.identity_key.to_base58_string(),
})?
node.clients_address()
};
let gateway_listener =
@@ -207,7 +200,7 @@ pub enum GatewaySetup {
specification: GatewaySelectionSpecification,
// TODO: seems to be a bit inefficient to pass them by value
available_gateways: Vec<RoutingNode>,
available_gateways: Vec<gateway::LegacyNode>,
},
ReuseConnection {
+2 -46
View File
@@ -14,7 +14,8 @@ pub mod error;
pub mod init;
pub use nym_topology::{
HardcodedTopologyProvider, NymRouteProvider, NymTopology, NymTopologyError, TopologyProvider,
HardcodedTopologyProvider, NymTopology, NymTopologyError, SerializableNymTopology,
SerializableTopologyError, TopologyProvider,
};
#[cfg(target_arch = "wasm32")]
@@ -33,48 +34,3 @@ where
{
tokio::spawn(future);
}
#[derive(Clone, Default, Debug)]
pub struct ForgetMe {
client: bool,
stats: bool,
}
impl ForgetMe {
pub fn new_all() -> Self {
Self {
client: true,
stats: true,
}
}
pub fn new_client() -> Self {
Self {
client: true,
stats: false,
}
}
pub fn new_stats() -> Self {
Self {
client: false,
stats: true,
}
}
pub fn new(client: bool, stats: bool) -> Self {
Self { client, stats }
}
pub fn any(&self) -> bool {
self.client || self.stats
}
pub fn client(&self) -> bool {
self.client
}
pub fn stats(&self) -> bool {
self.stats
}
}
@@ -9,10 +9,7 @@ use crate::backend::fs_backend::{
},
};
use log::{error, info};
use sqlx::{
sqlite::{SqliteAutoVacuum, SqliteSynchronous},
ConnectOptions,
};
use sqlx::ConnectOptions;
use std::path::Path;
#[derive(Debug, Clone)]
@@ -34,9 +31,6 @@ impl StorageManager {
}
let opts = sqlx::sqlite::SqliteConnectOptions::new()
.journal_mode(sqlx::sqlite::SqliteJournalMode::Wal)
.synchronous(SqliteSynchronous::Normal)
.auto_vacuum(SqliteAutoVacuum::Incremental)
.filename(database_path)
.create_if_missing(fresh)
.disable_statement_logging();
@@ -87,10 +87,8 @@ impl ClientBandwidth {
if remaining < 0 {
tracing::warn!("OUT OF BANDWIDTH. remaining: {remaining_bi2}");
} else if remaining < 1_000_000 {
tracing::info!("remaining bandwidth: {remaining_bi2}");
} else {
tracing::debug!("remaining bandwidth: {remaining_bi2}");
tracing::info!("remaining bandwidth: {remaining_bi2}");
}
self.inner
@@ -101,10 +101,6 @@ pub struct GatewayClient<C, St = EphemeralCredentialStorage> {
// currently unused (but populated)
negotiated_protocol: Option<u8>,
// Callback on the fd as soon as the connection has been established
#[cfg(unix)]
connection_fd_callback: Option<Arc<dyn Fn(RawFd) + Send + Sync>>,
/// Listen to shutdown messages and send notifications back to the task manager
task_client: TaskClient,
}
@@ -120,7 +116,6 @@ impl<C, St> GatewayClient<C, St> {
packet_router: PacketRouter,
bandwidth_controller: Option<BandwidthController<C, St>>,
stats_reporter: ClientStatsSender,
#[cfg(unix)] connection_fd_callback: Option<Arc<dyn Fn(RawFd) + Send + Sync>>,
task_client: TaskClient,
) -> Self {
GatewayClient {
@@ -136,8 +131,6 @@ impl<C, St> GatewayClient<C, St> {
bandwidth_controller,
stats_reporter,
negotiated_protocol: None,
#[cfg(unix)]
connection_fd_callback,
task_client,
}
}
@@ -146,10 +139,6 @@ impl<C, St> GatewayClient<C, St> {
self.gateway_identity
}
pub fn shared_key(&self) -> Option<Arc<SharedGatewayKey>> {
self.shared_key.clone()
}
pub fn ws_fd(&self) -> Option<RawFd> {
match &self.connection {
SocketState::Available(conn) => ws_fd(conn.as_ref()),
@@ -212,12 +201,6 @@ impl<C, St> GatewayClient<C, St> {
};
self.connection = SocketState::Available(Box::new(ws_stream));
#[cfg(unix)]
if let (Some(callback), Some(fd)) = (self.connection_fd_callback.as_ref(), self.ws_fd()) {
callback.as_ref()(fd);
}
Ok(())
}
@@ -324,7 +307,7 @@ impl<C, St> GatewayClient<C, St> {
// If we want to send a message (with response), we need to have a full control over the socket,
// as we need to be able to write the request and read the subsequent response
pub async fn send_websocket_message(
async fn send_websocket_message(
&mut self,
msg: impl Into<Message>,
) -> Result<ServerResponse, GatewayClientError> {
@@ -425,7 +408,7 @@ impl<C, St> GatewayClient<C, St> {
}
Some(_) => {
debug!("the gateway is using exactly the same (or older) protocol version as we are. We're good to continue!");
info!("the gateway is using exactly the same (or older) protocol version as we are. We're good to continue!");
Ok(())
}
}
@@ -1009,6 +992,24 @@ impl<C, St> GatewayClient<C, St> {
}
Ok(())
}
#[deprecated(note = "this method does not deal with upgraded keys for legacy clients")]
pub async fn authenticate_and_start(
&mut self,
) -> Result<AuthenticationResponse, GatewayClientError>
where
C: DkgQueryClient + Send + Sync,
St: CredentialStorage,
<St as CredentialStorage>::StorageError: Send + Sync + 'static,
{
let shared_key = self.perform_initial_authentication().await?;
self.claim_initial_bandwidth().await?;
// this call is NON-blocking
self.start_listening_for_mixnet_messages()?;
Ok(shared_key)
}
}
// type alias for an ease of use
@@ -1047,8 +1048,6 @@ impl GatewayClient<InitOnly, EphemeralCredentialStorage> {
bandwidth_controller: None,
stats_reporter: ClientStatsSender::new(None),
negotiated_protocol: None,
#[cfg(unix)]
connection_fd_callback: None,
task_client,
}
}
@@ -1079,8 +1078,6 @@ impl GatewayClient<InitOnly, EphemeralCredentialStorage> {
bandwidth_controller,
stats_reporter,
negotiated_protocol: self.negotiated_protocol,
#[cfg(unix)]
connection_fd_callback: self.connection_fd_callback,
task_client,
}
}
@@ -46,8 +46,7 @@ pub(crate) fn ws_fd(_conn: &WsConn) -> Option<RawFd> {
#[cfg(unix)]
match _conn.get_ref() {
MaybeTlsStream::Plain(stream) => Some(stream.as_raw_fd()),
MaybeTlsStream::Rustls(tls_stream) => Some(tls_stream.as_raw_fd()),
_ => None,
&_ => None,
}
#[cfg(not(unix))]
None
@@ -111,11 +110,6 @@ impl PartiallyDelegatedRouter {
}
};
if self.stream_return.is_canceled() {
// nothing to do, receiver has been dropped
return;
}
let return_res = match ret {
Err(err) => self.stream_return.send(Err(err)),
Ok(_) => {
+4 -8
View File
@@ -9,14 +9,10 @@ license.workspace = true
[dependencies]
futures = { workspace = true }
tracing = { workspace = true }
tokio = { workspace = true, features = ["time"] }
tokio-util = { workspace = true, features = ["codec"], optional = true }
log = { workspace = true }
tokio = { workspace = true, features = ["time", "net", "rt"] }
tokio-util = { workspace = true, features = ["codec"] }
# internal
nym-sphinx = { path = "../../nymsphinx" }
nym-task = { path = "../../task", optional = true }
[features]
default = ["client"]
client = ["tokio-util", "nym-task", "tokio/net", "tokio/rt"]
nym-task = { path = "../../task" }
@@ -3,6 +3,7 @@
use futures::channel::mpsc;
use futures::StreamExt;
use log::*;
use nym_sphinx::addressing::nodes::NymNodeRoutingAddress;
use nym_sphinx::framing::codec::NymCodec;
use nym_sphinx::framing::packet::FramedNymPacket;
@@ -17,14 +18,13 @@ use std::time::Duration;
use tokio::net::TcpStream;
use tokio::time::sleep;
use tokio_util::codec::Framed;
use tracing::*;
#[derive(Clone, Copy)]
pub struct Config {
initial_reconnection_backoff: Duration,
maximum_reconnection_backoff: Duration,
initial_connection_timeout: Duration,
maximum_connection_buffer_size: usize,
use_legacy_version: bool,
}
impl Config {
@@ -33,12 +33,14 @@ impl Config {
maximum_reconnection_backoff: Duration,
initial_connection_timeout: Duration,
maximum_connection_buffer_size: usize,
use_legacy_version: bool,
) -> Self {
Config {
initial_reconnection_backoff,
maximum_reconnection_backoff,
initial_connection_timeout,
maximum_connection_buffer_size,
use_legacy_version,
}
}
}
@@ -198,8 +200,9 @@ impl SendWithoutResponse for Client {
packet: NymPacket,
packet_type: PacketType,
) -> io::Result<()> {
trace!("Sending packet to {address:?}");
let framed_packet = FramedNymPacket::new(packet, packet_type);
trace!("Sending packet to {:?}", address);
let framed_packet =
FramedNymPacket::new(packet, packet_type, self.config.use_legacy_version);
if let Some(sender) = self.conn_new.get_mut(&address) {
if let Err(err) = sender.channel.try_send(framed_packet) {
@@ -257,6 +260,7 @@ mod tests {
maximum_reconnection_backoff: Duration::from_millis(300_000),
initial_connection_timeout: Duration::from_millis(1_500),
maximum_connection_buffer_size: 128,
use_legacy_version: false,
})
}
@@ -1,72 +1,77 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::client::{Client, Config, SendWithoutResponse};
use futures::channel::mpsc;
use futures::channel::mpsc::SendError;
use futures::StreamExt;
use log::*;
use nym_sphinx::forwarding::packet::MixPacket;
use tokio::time::Instant;
use std::time::Duration;
pub fn mix_forwarding_channels() -> (MixForwardingSender, MixForwardingReceiver) {
let (tx, rx) = mpsc::unbounded();
(tx.into(), rx)
pub type MixForwardingSender = mpsc::UnboundedSender<MixPacket>;
type MixForwardingReceiver = mpsc::UnboundedReceiver<MixPacket>;
/// A specialisation of client such that it forwards any received packets on the channel into the
/// mix network immediately, i.e. will not try to listen for any responses.
pub struct PacketForwarder {
mixnet_client: Client,
packet_receiver: MixForwardingReceiver,
shutdown: nym_task::TaskClient,
}
#[derive(Clone)]
pub struct MixForwardingSender(mpsc::UnboundedSender<PacketToForward>);
impl PacketForwarder {
pub fn new(
initial_reconnection_backoff: Duration,
maximum_reconnection_backoff: Duration,
initial_connection_timeout: Duration,
maximum_connection_buffer_size: usize,
use_legacy_version: bool,
shutdown: nym_task::TaskClient,
) -> (PacketForwarder, MixForwardingSender) {
let client_config = Config::new(
initial_reconnection_backoff,
maximum_reconnection_backoff,
initial_connection_timeout,
maximum_connection_buffer_size,
use_legacy_version,
);
impl From<mpsc::UnboundedSender<PacketToForward>> for MixForwardingSender {
fn from(tx: mpsc::UnboundedSender<PacketToForward>) -> Self {
MixForwardingSender(tx)
}
}
let (packet_sender, packet_receiver) = mpsc::unbounded();
impl MixForwardingSender {
pub fn forward_packet(&self, packet: impl Into<PacketToForward>) -> Result<(), SendError> {
self.0
.unbounded_send(packet.into())
.map_err(|err| err.into_send_error())
(
PacketForwarder {
mixnet_client: Client::new(client_config),
packet_receiver,
shutdown,
},
packet_sender,
)
}
#[allow(clippy::len_without_is_empty)]
pub fn len(&self) -> usize {
self.0.len()
}
}
pub async fn run(&mut self) {
while !self.shutdown.is_shutdown() {
tokio::select! {
biased;
_ = self.shutdown.recv() => {
log::trace!("PacketForwarder: Received shutdown");
}
Some(mix_packet) = self.packet_receiver.next() => {
trace!("Going to forward packet to {}", mix_packet.next_hop());
pub type MixForwardingReceiver = mpsc::UnboundedReceiver<PacketToForward>;
let next_hop = mix_packet.next_hop();
let packet_type = mix_packet.packet_type();
let packet = mix_packet.into_packet();
// we don't care about responses, we just want to fire packets
// as quickly as possible
pub struct PacketToForward {
pub packet: MixPacket,
pub forward_delay_target: Option<Instant>,
}
impl From<MixPacket> for PacketToForward {
fn from(packet: MixPacket) -> Self {
PacketToForward::new_no_delay(packet)
}
}
impl From<(MixPacket, Option<Instant>)> for PacketToForward {
fn from((packet, delay_until): (MixPacket, Option<Instant>)) -> Self {
PacketToForward::new(packet, delay_until)
}
}
impl From<(MixPacket, Instant)> for PacketToForward {
fn from((packet, delay_until): (MixPacket, Instant)) -> Self {
PacketToForward::new(packet, Some(delay_until))
}
}
impl PacketToForward {
pub fn new(packet: MixPacket, forward_delay_target: Option<Instant>) -> Self {
PacketToForward {
packet,
forward_delay_target,
if let Err(err) =
self.mixnet_client
.send_without_response(next_hop, packet, packet_type)
{
debug!("failed to forward the packet - {err}")
}
}
}
}
}
pub fn new_no_delay(packet: MixPacket) -> Self {
Self::new(packet, None)
}
}
@@ -1,9 +1,7 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
#[cfg(feature = "client")]
pub mod client;
pub mod forwarder;
#[cfg(feature = "client")]
pub use client::{Client, Config, SendWithoutResponse};
@@ -19,8 +19,8 @@ use nym_api_requests::ecash::{
PartialExpirationDateSignatureResponse, VerificationKeyResponse,
};
use nym_api_requests::models::{
ApiHealthResponse, GatewayBondAnnotated, GatewayCoreStatusResponse, MixnodeCoreStatusResponse,
MixnodeStatusResponse, NymNodeDescription, RewardEstimationResponse, StakeSaturationResponse,
ApiHealthResponse, GatewayCoreStatusResponse, MixnodeCoreStatusResponse, MixnodeStatusResponse,
NymNodeDescription, RewardEstimationResponse, StakeSaturationResponse,
};
use nym_api_requests::models::{LegacyDescribedGateway, MixNodeBondAnnotated};
use nym_api_requests::nym_nodes::SkimmedNode;
@@ -32,10 +32,10 @@ use time::Date;
use url::Url;
pub use crate::nym_api::NymApiClientExt;
use nym_mixnet_contract_common::EpochRewardedSet;
pub use nym_mixnet_contract_common::{
mixnode::MixNodeDetails, GatewayBond, IdentityKey, IdentityKeyRef, NodeId, NymNodeDetails,
};
// re-export the type to not break existing imports
pub use crate::coconut::EcashApiClient;
@@ -257,13 +257,6 @@ impl<C, S> Client<C, S> {
Ok(self.nym_api.get_gateways().await?)
}
#[deprecated]
pub async fn get_cached_gateways_detailed_unfiltered(
&self,
) -> Result<Vec<GatewayBondAnnotated>, ValidatorClientError> {
Ok(self.nym_api.get_gateways_detailed_unfiltered().await?)
}
// TODO: combine with NymApiClient...
pub async fn get_all_cached_described_nodes(
&self,
@@ -358,23 +351,34 @@ impl NymApiClient {
}
#[deprecated(note = "use get_all_basic_active_mixing_assigned_nodes instead")]
pub async fn get_basic_mixnodes(&self) -> Result<Vec<SkimmedNode>, ValidatorClientError> {
Ok(self.nym_api.get_basic_mixnodes().await?.nodes)
pub async fn get_basic_mixnodes(
&self,
semver_compatibility: Option<String>,
) -> Result<Vec<SkimmedNode>, ValidatorClientError> {
Ok(self
.nym_api
.get_basic_mixnodes(semver_compatibility)
.await?
.nodes)
}
#[deprecated(note = "use get_all_basic_entry_assigned_nodes instead")]
pub async fn get_basic_gateways(&self) -> Result<Vec<SkimmedNode>, ValidatorClientError> {
Ok(self.nym_api.get_basic_gateways().await?.nodes)
}
pub async fn get_current_rewarded_set(&self) -> Result<EpochRewardedSet, ValidatorClientError> {
Ok(self.nym_api.get_rewarded_set().await?.into())
pub async fn get_basic_gateways(
&self,
semver_compatibility: Option<String>,
) -> Result<Vec<SkimmedNode>, ValidatorClientError> {
Ok(self
.nym_api
.get_basic_gateways(semver_compatibility)
.await?
.nodes)
}
/// retrieve basic information for nodes are capable of operating as an entry gateway
/// this includes legacy gateways and nym-nodes
pub async fn get_all_basic_entry_assigned_nodes(
&self,
semver_compatibility: Option<String>,
) -> Result<Vec<SkimmedNode>, ValidatorClientError> {
// TODO: deal with paging in macro or some helper function or something, because it's the same pattern everywhere
let mut page = 0;
@@ -383,7 +387,12 @@ impl NymApiClient {
loop {
let mut res = self
.nym_api
.get_basic_entry_assigned_nodes(false, Some(page), None)
.get_basic_entry_assigned_nodes(
semver_compatibility.clone(),
false,
Some(page),
None,
)
.await?;
nodes.append(&mut res.nodes.data);
@@ -401,6 +410,7 @@ impl NymApiClient {
/// this includes legacy mixnodes and nym-nodes
pub async fn get_all_basic_active_mixing_assigned_nodes(
&self,
semver_compatibility: Option<String>,
) -> Result<Vec<SkimmedNode>, ValidatorClientError> {
// TODO: deal with paging in macro or some helper function or something, because it's the same pattern everywhere
let mut page = 0;
@@ -409,7 +419,12 @@ impl NymApiClient {
loop {
let mut res = self
.nym_api
.get_basic_active_mixing_assigned_nodes(false, Some(page), None)
.get_basic_active_mixing_assigned_nodes(
semver_compatibility.clone(),
false,
Some(page),
None,
)
.await?;
nodes.append(&mut res.nodes.data);
@@ -427,6 +442,7 @@ impl NymApiClient {
/// this includes legacy mixnodes and nym-nodes
pub async fn get_all_basic_mixing_capable_nodes(
&self,
semver_compatibility: Option<String>,
) -> Result<Vec<SkimmedNode>, ValidatorClientError> {
// TODO: deal with paging in macro or some helper function or something, because it's the same pattern everywhere
let mut page = 0;
@@ -435,7 +451,12 @@ impl NymApiClient {
loop {
let mut res = self
.nym_api
.get_basic_mixing_capable_nodes(false, Some(page), None)
.get_basic_mixing_capable_nodes(
semver_compatibility.clone(),
false,
Some(page),
None,
)
.await?;
nodes.append(&mut res.nodes.data);
@@ -450,7 +471,10 @@ impl NymApiClient {
}
/// retrieve basic information for all bonded nodes on the network
pub async fn get_all_basic_nodes(&self) -> Result<Vec<SkimmedNode>, ValidatorClientError> {
pub async fn get_all_basic_nodes(
&self,
semver_compatibility: Option<String>,
) -> Result<Vec<SkimmedNode>, ValidatorClientError> {
// TODO: deal with paging in macro or some helper function or something, because it's the same pattern everywhere
let mut page = 0;
let mut nodes = Vec::new();
@@ -458,7 +482,7 @@ impl NymApiClient {
loop {
let mut res = self
.nym_api
.get_basic_nodes(false, Some(page), None)
.get_basic_nodes(semver_compatibility.clone(), false, Some(page), None)
.await?;
nodes.append(&mut res.nodes.data);
@@ -13,7 +13,7 @@ use nym_api_requests::ecash::models::{
use nym_api_requests::ecash::VerificationKeyResponse;
use nym_api_requests::models::{
AnnotationResponse, ApiHealthResponse, LegacyDescribedMixNode, NodePerformanceResponse,
NodeRefreshBody, NymNodeDescription, RewardedSetResponse,
NodeRefreshBody, NymNodeDescription,
};
use nym_api_requests::nym_nodes::PaginatedCachedNodesResponse;
use nym_api_requests::pagination::PaginatedResponse;
@@ -102,23 +102,6 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[deprecated]
#[instrument(level = "debug", skip(self))]
async fn get_gateways_detailed_unfiltered(
&self,
) -> Result<Vec<GatewayBondAnnotated>, NymAPIError> {
self.get_json(
&[
routes::API_VERSION,
routes::STATUS,
routes::GATEWAYS,
routes::DETAILED_UNFILTERED,
],
NO_PARAMS,
)
.await
}
#[deprecated]
#[instrument(level = "debug", skip(self))]
async fn get_mixnodes_detailed_unfiltered(
@@ -205,7 +188,16 @@ pub trait NymApiClientExt: ApiClient {
#[deprecated]
#[tracing::instrument(level = "debug", skip_all)]
async fn get_basic_mixnodes(&self) -> Result<CachedNodesResponse<SkimmedNode>, NymAPIError> {
async fn get_basic_mixnodes(
&self,
semver_compatibility: Option<String>,
) -> Result<CachedNodesResponse<SkimmedNode>, NymAPIError> {
let params = if let Some(semver_compatibility) = &semver_compatibility {
vec![("semver_compatibility", semver_compatibility.as_str())]
} else {
vec![]
};
self.get_json(
&[
routes::API_VERSION,
@@ -214,14 +206,23 @@ pub trait NymApiClientExt: ApiClient {
"mixnodes",
"skimmed",
],
NO_PARAMS,
&params,
)
.await
}
#[deprecated]
#[instrument(level = "debug", skip(self))]
async fn get_basic_gateways(&self) -> Result<CachedNodesResponse<SkimmedNode>, NymAPIError> {
async fn get_basic_gateways(
&self,
semver_compatibility: Option<String>,
) -> Result<CachedNodesResponse<SkimmedNode>, NymAPIError> {
let params = if let Some(semver_compatibility) = &semver_compatibility {
vec![("semver_compatibility", semver_compatibility.as_str())]
} else {
vec![]
};
self.get_json(
&[
routes::API_VERSION,
@@ -230,16 +231,7 @@ pub trait NymApiClientExt: ApiClient {
"gateways",
"skimmed",
],
NO_PARAMS,
)
.await
}
#[instrument(level = "debug", skip(self))]
async fn get_rewarded_set(&self) -> Result<RewardedSetResponse, NymAPIError> {
self.get_json(
&[routes::API_VERSION, "nym-nodes", "rewarded-set"],
NO_PARAMS,
&params,
)
.await
}
@@ -249,12 +241,17 @@ pub trait NymApiClientExt: ApiClient {
#[instrument(level = "debug", skip(self))]
async fn get_basic_entry_assigned_nodes(
&self,
semver_compatibility: Option<String>,
no_legacy: bool,
page: Option<u32>,
per_page: Option<u32>,
) -> Result<PaginatedCachedNodesResponse<SkimmedNode>, NymAPIError> {
let mut params = Vec::new();
if let Some(arg) = &semver_compatibility {
params.push(("semver_compatibility", arg.clone()))
}
if no_legacy {
params.push(("no_legacy", "true".to_string()))
}
@@ -286,12 +283,17 @@ pub trait NymApiClientExt: ApiClient {
#[instrument(level = "debug", skip(self))]
async fn get_basic_active_mixing_assigned_nodes(
&self,
semver_compatibility: Option<String>,
no_legacy: bool,
page: Option<u32>,
per_page: Option<u32>,
) -> Result<PaginatedCachedNodesResponse<SkimmedNode>, NymAPIError> {
let mut params = Vec::new();
if let Some(arg) = &semver_compatibility {
params.push(("semver_compatibility", arg.clone()))
}
if no_legacy {
params.push(("no_legacy", "true".to_string()))
}
@@ -323,12 +325,17 @@ pub trait NymApiClientExt: ApiClient {
#[instrument(level = "debug", skip(self))]
async fn get_basic_mixing_capable_nodes(
&self,
semver_compatibility: Option<String>,
no_legacy: bool,
page: Option<u32>,
per_page: Option<u32>,
) -> Result<PaginatedCachedNodesResponse<SkimmedNode>, NymAPIError> {
let mut params = Vec::new();
if let Some(arg) = &semver_compatibility {
params.push(("semver_compatibility", arg.clone()))
}
if no_legacy {
params.push(("no_legacy", "true".to_string()))
}
@@ -358,12 +365,17 @@ pub trait NymApiClientExt: ApiClient {
#[instrument(level = "debug", skip(self))]
async fn get_basic_nodes(
&self,
semver_compatibility: Option<String>,
no_legacy: bool,
page: Option<u32>,
per_page: Option<u32>,
) -> Result<PaginatedCachedNodesResponse<SkimmedNode>, NymAPIError> {
let mut params = Vec::new();
if let Some(arg) = &semver_compatibility {
params.push(("semver_compatibility", arg.clone()))
}
if no_legacy {
params.push(("no_legacy", "true".to_string()))
}
@@ -921,7 +933,6 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[instrument(level = "debug", skip(self))]
async fn force_refresh_describe_cache(
&self,
request: &NodeRefreshBody,
@@ -934,7 +945,6 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[instrument(level = "debug", skip(self))]
async fn issued_ticketbooks_for(
&self,
expiration_date: Date,
@@ -951,7 +961,6 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[instrument(level = "debug", skip(self))]
async fn issued_ticketbooks_challenge(
&self,
expiration_date: Date,
@@ -26,11 +26,10 @@ use nym_mixnet_contract_common::{
reward_params::{Performance, RewardingParams},
rewarding::{EstimatedCurrentEpochRewardResponse, PendingRewardResponse},
ContractBuildInformation, ContractState, ContractStateParams, CurrentIntervalResponse,
CurrentNymNodeVersionResponse, Delegation, EpochEventId, EpochRewardedSet, EpochStatus,
GatewayBond, GatewayBondResponse, GatewayOwnershipResponse, HistoricalNymNodeVersionEntry,
IdentityKey, IdentityKeyRef, IntervalEventId, MixNodeBond, MixNodeDetails,
MixOwnershipResponse, MixnodeDetailsByIdentityResponse, MixnodeDetailsResponse, NodeId,
NumberOfPendingEventsResponse, NymNodeBond, NymNodeDetails, NymNodeVersionHistoryResponse,
Delegation, EpochEventId, EpochStatus, GatewayBond, GatewayBondResponse,
GatewayOwnershipResponse, IdentityKey, IdentityKeyRef, IntervalEventId, MixNodeBond,
MixNodeDetails, MixOwnershipResponse, MixnodeDetailsByIdentityResponse, MixnodeDetailsResponse,
NodeId, NumberOfPendingEventsResponse, NymNodeBond, NymNodeDetails,
PagedAllDelegationsResponse, PagedDelegatorDelegationsResponse, PagedGatewayResponse,
PagedMixnodeBondsResponse, PagedNodeDelegationsResponse, PendingEpochEvent,
PendingEpochEventResponse, PendingEpochEventsResponse, PendingIntervalEvent,
@@ -72,22 +71,6 @@ pub trait MixnetQueryClient {
.await
}
async fn get_nym_node_version_history_paged(
&self,
start_after: Option<u32>,
limit: Option<u32>,
) -> Result<NymNodeVersionHistoryResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetNymNodeVersionHistory { limit, start_after })
.await
}
async fn get_current_nym_node_version(
&self,
) -> Result<CurrentNymNodeVersionResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetCurrentNymNodeVersion {})
.await
}
async fn get_mixnet_contract_state(&self) -> Result<ContractState, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetState {})
.await
@@ -655,12 +638,6 @@ pub trait PagedMixnetQueryClient: MixnetQueryClient {
) -> Result<Vec<PendingIntervalEvent>, NyxdError> {
collect_paged!(self, get_pending_interval_events_paged, events)
}
async fn get_full_nym_node_version_history(
&self,
) -> Result<Vec<HistoricalNymNodeVersionEntry>, NyxdError> {
collect_paged!(self, get_nym_node_version_history_paged, history)
}
}
#[async_trait]
@@ -670,7 +647,7 @@ impl<T> PagedMixnetQueryClient for T where T: MixnetQueryClient {}
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
pub trait MixnetQueryClientExt: MixnetQueryClient {
async fn get_rewarded_set(&self) -> Result<EpochRewardedSet, NyxdError> {
async fn get_rewarded_set(&self) -> Result<RewardedSet, NyxdError> {
let error_response = |message| Err(NyxdError::extension_query_failure("mixnet", message));
let metadata = self.get_rewarded_set_metadata().await?;
@@ -711,16 +688,13 @@ pub trait MixnetQueryClientExt: MixnetQueryClient {
return error_response("the nodes assigned for 'standby' returned unexpected epoch_id");
}
Ok(EpochRewardedSet {
epoch_id: expected_epoch_id,
assignment: RewardedSet {
entry_gateways: entry.nodes,
exit_gateways: exit.nodes,
layer1: layer1.nodes,
layer2: layer2.nodes,
layer3: layer3.nodes,
standby: standby.nodes,
},
Ok(RewardedSet {
entry_gateways: entry.nodes,
exit_gateways: exit.nodes,
layer1: layer1.nodes,
layer2: layer2.nodes,
layer3: layer3.nodes,
standby: standby.nodes,
})
}
}
@@ -750,7 +724,6 @@ where
mod tests {
use super::*;
use crate::nyxd::contract_traits::tests::IgnoreValue;
use nym_mixnet_contract_common::QueryMsg;
// it's enough that this compiles and clippy is happy about it
#[allow(dead_code)]
@@ -951,10 +924,6 @@ mod tests {
MixnetQueryMsg::GetRewardedSetMetadata {} => {
client.get_rewarded_set_metadata().ignore()
}
QueryMsg::GetCurrentNymNodeVersion {} => client.get_current_nym_node_version().ignore(),
QueryMsg::GetNymNodeVersionHistory { limit, start_after } => client
.get_nym_node_version_history_paged(start_after, limit)
.ignore(),
}
}
}
-2
View File
@@ -48,7 +48,6 @@ nym-vesting-contract-common = { path = "../cosmwasm-smart-contracts/vesting-cont
nym-coconut-dkg-common = { path = "../cosmwasm-smart-contracts/coconut-dkg" }
nym-multisig-contract-common = { path = "../cosmwasm-smart-contracts/multisig-contract" }
nym-ecash-contract-common = { path = "../cosmwasm-smart-contracts/ecash-contract" }
nym-ecash-time = { path = "../../common/ecash-time" }
nym-sphinx = { path = "../../common/nymsphinx" }
nym-client-core = { path = "../../common/client-core" }
nym-config = { path = "../../common/config" }
@@ -57,7 +56,6 @@ nym-credentials-interface = { path = "../../common/credentials-interface" }
nym-credential-storage = { path = "../../common/credential-storage" }
nym-credential-utils = { path = "../../common/credential-utils" }
nym-id = { path = "../nym-id" }
nym-credential-proxy-requests = { path = "../../nym-credential-proxy/nym-credential-proxy-requests" }
nym-pemstore = { path = "../../common/pemstore", version = "0.3.0" }
nym-types = { path = "../../common/types" }
@@ -1,41 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use clap::Parser;
use log::trace;
use nym_credentials_interface::{generate_keypair_user, generate_keypair_user_from_seed, Base58};
use serde::{Deserialize, Serialize};
use std::io::stdout;
#[derive(Serialize, Deserialize)]
pub struct Bs58EncodedKeys {
pub secret_key: String,
pub public_key: String,
}
#[derive(Debug, Parser)]
pub struct Args {
/// Secret value that's used for deriving underlying ecash keypair
#[clap(long)]
pub(crate) bs58_encoded_client_secret: Option<String>,
}
pub fn generate_ecash_keypair(args: Args) -> anyhow::Result<()> {
trace!("args: {args:?}");
let keypair = if let Some(secret) = args.bs58_encoded_client_secret {
let seed = bs58::decode(&secret).into_vec()?;
generate_keypair_user_from_seed(&seed)
} else {
generate_keypair_user()
};
let encoded = Bs58EncodedKeys {
secret_key: keypair.secret_key().to_bs58(),
public_key: keypair.public_key().to_bs58(),
};
serde_json::to_writer_pretty(stdout(), &encoded)?;
Ok(())
}
-23
View File
@@ -1,23 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use clap::{Args, Subcommand};
pub mod generate_keypair;
pub mod withdrawal_request;
#[derive(Debug, Args)]
#[clap(args_conflicts_with_subcommands = true, subcommand_required = true)]
pub struct InternalEcash {
#[clap(subcommand)]
pub command: InternalEcashCommands,
}
#[derive(Debug, Subcommand)]
pub enum InternalEcashCommands {
/// Generate a dummy withdrawal request
GenerateWithdrawalRequest(withdrawal_request::Args),
/// Generate dummy ecash keypair
GenerateKeypair(generate_keypair::Args),
}
@@ -1,78 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use clap::Parser;
use log::trace;
use nym_credential_proxy_requests::api::v1::ticketbook::models::TicketbookRequest;
use nym_credentials_interface::{
generate_keypair_user, withdrawal_request, Base58, SecretKeyUser, TicketType,
};
use nym_ecash_time::{ecash_default_expiration_date, EcashTime};
use serde::{Deserialize, Serialize};
use std::io::stdout;
use time::macros::format_description;
use time::Date;
use zeroize::Zeroizing;
fn parse_date(raw: &str) -> Result<Date, time::error::Parse> {
let format = format_description!("[year]-[month]-[day]");
Date::parse(raw, &format)
}
#[derive(Serialize, Deserialize)]
pub struct Bs58EncodedOutput {
pub ecash_proxy_request: TicketbookRequest,
pub ecash_secret: String,
/// Needed to later unblind shares
pub ecash_request_info_bs58: String,
}
#[derive(Debug, Parser)]
pub struct Args {
/// Specify which type of ticketbook
#[clap(long, default_value_t = TicketType::V1MixnetEntry)]
pub(crate) ticketbook_type: TicketType,
/// Set expiration date for the ticketbook
#[clap(long, value_parser = parse_date, default_value_t = ecash_default_expiration_date())]
pub(crate) expiration_date: Date,
/// Provide ecash secret key (or generate a fresh one)
#[clap(long)]
pub(crate) ecash_secret_key_bs58: Option<String>,
}
pub async fn generate_withdrawal_request(args: Args) -> anyhow::Result<()> {
trace!("args: {args:?}");
let ecash_keypair = if let Some(secret_key) = args.ecash_secret_key_bs58 {
let secret_key = Zeroizing::new(bs58::decode(Zeroizing::new(secret_key)).into_vec()?);
let sk = SecretKeyUser::from_bytes(&secret_key)?;
sk.into()
} else {
generate_keypair_user()
};
let (withdrawal_request, request_info) = withdrawal_request(
ecash_keypair.secret_key(),
args.expiration_date.ecash_unix_timestamp(),
args.ticketbook_type.encode(),
)?;
let encoded = Bs58EncodedOutput {
ecash_proxy_request: TicketbookRequest {
withdrawal_request: withdrawal_request.into(),
ecash_pubkey: ecash_keypair.public_key(),
expiration_date: args.expiration_date,
ticketbook_type: args.ticketbook_type,
is_freepass_request: false,
},
ecash_secret: ecash_keypair.secret_key().to_bs58(),
ecash_request_info_bs58: request_info.to_bs58(),
};
serde_json::to_writer_pretty(stdout(), &encoded)?;
Ok(())
}
-19
View File
@@ -1,19 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use clap::{Args, Subcommand};
pub mod ecash;
#[derive(Debug, Args)]
#[clap(args_conflicts_with_subcommands = true, subcommand_required = true)]
pub struct Internal {
#[clap(subcommand)]
pub command: InternalCommands,
}
#[derive(Debug, Subcommand)]
pub enum InternalCommands {
/// Ecash related internal commands
Ecash(ecash::InternalEcash),
}
-1
View File
@@ -3,6 +3,5 @@
pub mod context;
pub mod ecash;
pub mod internal;
pub mod utils;
pub mod validator;
+1 -2
View File
@@ -12,8 +12,7 @@ dirs = { workspace = true, optional = true }
handlebars = { workspace = true }
log = { workspace = true }
serde = { workspace = true, features = ["derive"] }
thiserror = { workspace = true }
toml = { workspace = true, features = ["display"] }
toml = { workspace = true }
url = { workspace = true }
nym-network-defaults = { path = "../network-defaults", features = ["utoipa"] }
-10
View File
@@ -1,10 +0,0 @@
use std::io;
use thiserror::Error;
#[derive(Debug, Error)]
pub enum NymConfigTomlError {
#[error(transparent)]
FileIoFailure(#[from] io::Error),
#[error(transparent)]
TomlSerializeFailure(#[from] toml::ser::Error),
}
-37
View File
@@ -13,7 +13,6 @@ pub use helpers::{parse_urls, OptionalSet};
pub use toml::de::Error as TomlDeError;
pub mod defaults;
pub mod error;
pub mod helpers;
pub mod legacy_helpers;
pub mod serde_helpers;
@@ -96,42 +95,6 @@ where
config.format_to_writer(file)
}
pub fn save_unformatted_config_to_file<C, P>(
config: &C,
path: P,
) -> Result<(), error::NymConfigTomlError>
where
C: Serialize + ?Sized,
P: AsRef<Path>,
{
let path = path.as_ref();
log::info!("saving config file to {}", path.display());
if let Some(parent) = path.parent() {
create_dir_all(parent)?;
}
let mut file = File::create(path)?;
// TODO: check for whether any of our configs store anything sensitive
// and change that to 0o644 instead
#[cfg(target_family = "unix")]
{
use std::os::unix::fs::PermissionsExt;
let mut perms = fs::metadata(path)?.permissions();
perms.set_mode(0o600);
fs::set_permissions(path, perms)?;
}
// let serde format the TOML in whatever ugly way it chooses
// TODO: in https://docs.rs/toml/latest/toml/fn.to_string_pretty.html it recommends using
// https://docs.rs/toml_edit/latest/toml_edit/struct.DocumentMut.html to preserve formatting
let toml_string = toml::to_string_pretty(config)?;
Ok(file.write_all(toml_string.as_bytes())?)
}
pub fn deserialize_config_from_toml_str<C>(raw: &str) -> Result<C, TomlDeError>
where
C: DeserializeOwned,
@@ -1,18 +0,0 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
/**
* Specification on how the active set should be updated.
*/
export type ActiveSetUpdate = {
/**
* The expected number of nodes assigned entry gateway role (i.e. [`Role::EntryGateway`])
*/
entry_gateways: number,
/**
* The expected number of nodes assigned exit gateway role (i.e. [`Role::ExitGateway`])
*/
exit_gateways: number,
/**
* The expected number of nodes assigned the 'mixnode' role, i.e. total of [`Role::Layer1`], [`Role::Layer2`] and [`Role::Layer3`].
*/
mixnodes: number, };
@@ -1,3 +0,0 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
export type GatewayConfigUpdate = { host: string, mix_port: number, clients_port: number, location: string, version: string, };
@@ -1,30 +0,0 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
/**
* Specification of a rewarding interval.
*/
export type Interval = {
/**
* Monotonously increasing id of this interval.
*/
id: number,
/**
* Number of epochs in this interval.
*/
epochs_in_interval: number,
/**
* The timestamp indicating the start of the current rewarding epoch.
*/
current_epoch_start: string,
/**
* Monotonously increasing id of the current epoch in this interval.
*/
current_epoch_id: number,
/**
* The duration of all epochs in this interval.
*/
epoch_length: { secs: number; nanos: number; },
/**
* The total amount of elapsed epochs since the first epoch of the first interval.
*/
total_elapsed_epochs: number, };
@@ -1,51 +0,0 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
/**
* Parameters required by the mix-mining reward distribution that do not change during an interval.
*/
export type IntervalRewardParams = {
/**
* Current value of the rewarding pool.
* It is expected to be constant throughout the interval.
*/
reward_pool: string,
/**
* Current value of the staking supply.
* It is expected to be constant throughout the interval.
*/
staking_supply: string,
/**
* Defines the percentage of stake needed to reach saturation for all of the nodes in the rewarded set.
* Also known as `beta`.
*/
staking_supply_scale_factor: string,
/**
* Current value of the computed reward budget per epoch, per node.
* It is expected to be constant throughout the interval.
*/
epoch_reward_budget: string,
/**
* Current value of the stake saturation point.
* It is expected to be constant throughout the interval.
*/
stake_saturation_point: string,
/**
* Current value of the sybil resistance percent (`alpha`).
* It is not really expected to be changing very often.
* As a matter of fact, unless there's a very specific reason, it should remain constant.
*/
sybil_resistance: string,
/**
* Current active set work factor.
* It is not really expected to be changing very often.
* As a matter of fact, unless there's a very specific reason, it should remain constant.
*/
active_set_work_factor: string,
/**
* Current maximum interval pool emission.
* Assuming all nodes in the rewarded set are fully saturated and have 100% performance,
* this % of the reward pool would get distributed in rewards to all operators and its delegators.
* It is not really expected to be changing very often.
* As a matter of fact, unless there's a very specific reason, it should remain constant.
*/
interval_pool_emission: string, };
@@ -1,35 +0,0 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { RewardedSetParams } from "./RewardedSetParams";
/**
* Specification on how the rewarding params should be updated.
*/
export type IntervalRewardingParamsUpdate = {
/**
* Defines the new value of the reward pool.
*/
reward_pool: string | null,
/**
* Defines the new value of the staking supply.
*/
staking_supply: string | null,
/**
* Defines the new value of the staking supply scale factor.
*/
staking_supply_scale_factor: string | null,
/**
* Defines the new value of the sybil resistance percent.
*/
sybil_resistance_percent: string | null,
/**
* Defines the new value of the active set work factor.
*/
active_set_work_factor: string | null,
/**
* Defines the new value of the interval pool emission rate.
*/
interval_pool_emission: string | null,
/**
* Defines the parameters of the rewarded set.
*/
rewarded_set_params: RewardedSetParams | null, };
@@ -1,3 +0,0 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
export type MixNodeConfigUpdate = { host: string, mix_port: number, verloc_port: number, http_api_port: number, version: string, };
@@ -1,34 +0,0 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
/**
* Information provided by the node operator during bonding that are used to allow other entities to use the services of this node.
*/
export type MixNode = {
/**
* Network address of this mixnode, for example 1.1.1.1 or foo.mixnode.com
*/
host: string,
/**
* Port used by this mixnode for listening for mix packets.
*/
mix_port: number,
/**
* Port used by this mixnode for listening for verloc requests.
*/
verloc_port: number,
/**
* Port used by this mixnode for its http(s) API
*/
http_api_port: number,
/**
* Base58-encoded x25519 public key used for sphinx key derivation.
*/
sphinx_key: string,
/**
* Base58-encoded ed25519 EdDSA public key.
*/
identity_key: string,
/**
* The self-reported semver version of this mixnode.
*/
version: string, };
@@ -1,3 +0,0 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
export type NodeConfigUpdate = { host: string | null, custom_http_port: number | null, restore_default_http_port: boolean, };
@@ -1,15 +0,0 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
/**
* Parameters used for rewarding particular node.
*/
export type NodeRewardingParameters = {
/**
* Performance of the particular node in the current epoch.
*/
performance: string,
/**
* Amount of work performed by this node in the current epoch
* also known as 'omega' in the paper
*/
work_factor: string, };
@@ -1,20 +0,0 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
/**
* Information provided by the node operator during bonding that are used to allow other entities to use the services of this node.
*/
export type NymNode = {
/**
* Network address of this nym-node, for example 1.1.1.1 or foo.mixnode.com
* that is used to discover other capabilities of this node.
*/
host: string,
/**
* Allow specifying custom port for accessing the http, and thus self-described, api
* of this node for the capabilities discovery.
*/
custom_http_port: number | null,
/**
* Base58-encoded ed25519 EdDSA public key.
*/
identity_key: string, };
@@ -1,3 +0,0 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
export type PendingMixNodeChanges = { pledge_change: number | null, cost_params_change: number | null, };
@@ -1,3 +0,0 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
export type PendingNodeChanges = { pledge_change: number | null, cost_params_change: number | null, };
@@ -1,20 +0,0 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
export type RewardEstimate = {
/**
* The amount of **decimal** coins that are going to get distributed to the node,
* i.e. the operator and all its delegators.
*/
total_node_reward: string,
/**
* The share of the reward that is going to get distributed to the node operator.
*/
operator: string,
/**
* The share of the reward that is going to get distributed among the node delegators.
*/
delegates: string,
/**
* The operating cost of this node. Note: it's already included in the operator reward.
*/
operating_cost: string, };
@@ -1,19 +0,0 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
export type RewardedSetParams = {
/**
* The expected number of nodes assigned entry gateway role (i.e. [`Role::EntryGateway`])
*/
entry_gateways: number,
/**
* The expected number of nodes assigned exit gateway role (i.e. [`Role::ExitGateway`])
*/
exit_gateways: number,
/**
* The expected number of nodes assigned the 'mixnode' role, i.e. total of [`Role::Layer1`], [`Role::Layer2`] and [`Role::Layer3`].
*/
mixnodes: number,
/**
* Number of nodes in the 'standby' set. (i.e. [`Role::Standby`])
*/
standby: number, };

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