Compare commits

..

2 Commits

Author SHA1 Message Date
durch da8fd4a2e6 If not exists 2024-11-27 10:33:14 +01:00
durch 50405de8d4 Add indexes to monitor run and testing route 2024-11-27 10:30:11 +01:00
767 changed files with 15033 additions and 28791 deletions
+1
View File
@@ -4,3 +4,4 @@
**/node_modules **/node_modules
**/target **/target
dist dist
documentation
-1
View File
@@ -1 +0,0 @@
nym-validator-rewarder/.sqlx/** diff=nodiff
-1
View File
@@ -34,7 +34,6 @@ jobs:
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
env: env:
CARGO_TERM_COLOR: always CARGO_TERM_COLOR: always
IPINFO_API_TOKEN: ${{ secrets.IPINFO_API_TOKEN }}
steps: steps:
- name: Install Dependencies (Linux) - 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 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
@@ -56,6 +56,14 @@ jobs:
rustup target add aarch64-linux-android \ rustup target add aarch64-linux-android \
x86_64-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) - name: Build APKs (unsigned)
working-directory: nym-connect/native/android working-directory: nym-connect/native/android
env: env:
+1 -1
View File
@@ -26,7 +26,7 @@ jobs:
git config --global user.name "Lawrence Stalder" git config --global user.name "Lawrence Stalder"
- name: Get version from cargo.toml - name: Get version from cargo.toml
uses: mikefarah/yq@v4.44.6 uses: mikefarah/yq@v4.44.5
id: get_version id: get_version
with: with:
cmd: yq -oy '.package.version' ${{ env.WORKING_DIRECTORY }}/nym-credential-proxy/Cargo.toml 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" git config --global user.name "Lawrence Stalder"
- name: Get version from cargo.toml - name: Get version from cargo.toml
uses: mikefarah/yq@v4.44.6 uses: mikefarah/yq@v4.44.5
id: get_version id: get_version
with: with:
cmd: yq -oy '.package.version' ${{ env.WORKING_DIRECTORY }}/Cargo.toml 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" git config --global user.name "Lawrence Stalder"
- name: Get version from cargo.toml - name: Get version from cargo.toml
uses: mikefarah/yq@v4.44.6 uses: mikefarah/yq@v4.44.5
id: get_version id: get_version
with: with:
cmd: yq -oy '.package.version' ${{ env.WORKING_DIRECTORY }}/nym-network-monitor/Cargo.toml 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 description: Which gateway probe git ref to build the image with
env: env:
WORKING_DIRECTORY: "nym-node-status-api/nym-node-status-agent" WORKING_DIRECTORY: "nym-node-status-agent"
CONTAINER_NAME: "node-status-agent" CONTAINER_NAME: "node-status-agent"
jobs: jobs:
@@ -31,7 +31,7 @@ jobs:
git config --global user.name "Lawrence Stalder" git config --global user.name "Lawrence Stalder"
- name: Get version from cargo.toml - name: Get version from cargo.toml
uses: mikefarah/yq@v4.44.6 uses: mikefarah/yq@v4.44.5
id: get_version id: get_version
with: with:
cmd: yq -oy '.package.version' ${{ env.WORKING_DIRECTORY }}/Cargo.toml cmd: yq -oy '.package.version' ${{ env.WORKING_DIRECTORY }}/Cargo.toml
@@ -58,4 +58,4 @@ jobs:
- name: BuildAndPushImageOnHarbor - name: BuildAndPushImageOnHarbor
run: | 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 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: workflow_dispatch:
env: env:
WORKING_DIRECTORY: "nym-node-status-api/nym-node-status-api" WORKING_DIRECTORY: "nym-node-status-api"
CONTAINER_NAME: "node-status-api" CONTAINER_NAME: "node-status-api"
jobs: jobs:
@@ -26,7 +26,7 @@ jobs:
git config --global user.name "Lawrence Stalder" git config --global user.name "Lawrence Stalder"
- name: Get version from cargo.toml - name: Get version from cargo.toml
uses: mikefarah/yq@v4.44.6 uses: mikefarah/yq@v4.44.5
id: get_version id: get_version
with: with:
cmd: yq -oy '.package.version' ${{ env.WORKING_DIRECTORY }}/Cargo.toml 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" git config --global user.name "Lawrence Stalder"
- name: Get version from cargo.toml - name: Get version from cargo.toml
uses: mikefarah/yq@v4.44.6 uses: mikefarah/yq@v4.44.5
id: get_version id: get_version
with: with:
cmd: yq -oy '.package.version' ${{ env.WORKING_DIRECTORY }}/Cargo.toml 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" git config --global user.name "Lawrence Stalder"
- name: Get version from cargo.toml - name: Get version from cargo.toml
uses: mikefarah/yq@v4.44.6 uses: mikefarah/yq@v4.44.5
id: get_version id: get_version
with: 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 - name: Remove existing tag if exists
run: | run: |
-49
View File
@@ -1,49 +0,0 @@
# This file instructs Redocly's linter to ignore the rules contained for specific parts of your API.
# See https://redocly.com/docs/cli/ for more information.
formatted-openapi.json:
path-parameters-defined:
# - >-
# #/paths/~1v1~1status~1mixnode~1{mix_id}~1compute-reward-estimation/post/parameters/0/name
# - >-
# #/paths/~1v1~1status~1mixnode~1{mix_id}~1compute-reward-estimation/post/parameters/1/name
# - >-
# #/paths/~1v1~1status~1mixnode~1{mix_id}~1compute-reward-estimation/post/parameters/2/name
# - >-
# #/paths/~1v1~1status~1mixnode~1{mix_id}~1compute-reward-estimation/post/parameters/3/name
# - >-
# #/paths/~1v1~1status~1mixnode~1{mix_id}~1compute-reward-estimation/post/parameters/4/name
# - >-
# #/paths/~1v1~1status~1mixnode~1{mix_id}~1compute-reward-estimation/post/parameters/5/name
# - '#/paths/~1v1~1unstable~1nym-nodes~1skimmed~1active/get/parameters/0/name'
# - '#/paths/~1v1~1unstable~1nym-nodes~1skimmed~1active/get/parameters/1/name'
# - '#/paths/~1v1~1unstable~1nym-nodes~1skimmed~1active/get/parameters/2/name'
# - '#/paths/~1v1~1unstable~1nym-nodes~1skimmed~1active/get/parameters/3/name'
operation-operationId-unique:
- >-
#/paths/~1v1~1status~1mixnodes~1active~1detailed/get/get_active_set_detailed
- '#/paths/~1v1~1status~1mixnodes~1detailed/get/get_mixnodes_detailed'
- >-
#/paths/~1v1~1status~1mixnodes~1rewarded~1detailed/get/get_rewarded_set_detailed
no-unused-components:
- '#/components/schemas/AxumErrorResponse'
- '#/components/schemas/DateQuery'
- '#/components/schemas/EcashTicketVerificationRejection'
- '#/components/schemas/ExpirationDatePathParam'
- '#/components/schemas/FullFatNode'
- '#/components/schemas/HistoricalPerformanceResponse'
- '#/components/schemas/HistoricalUptimeResponse'
- '#/components/schemas/MasterVerificationKeyResponse'
- '#/components/schemas/MixnodeStatusReport'
- '#/components/schemas/NodeId'
- '#/components/schemas/NodeRoleQueryParam'
- '#/components/schemas/NoiseDetails'
- '#/components/schemas/NymNodeDescription'
- '#/components/schemas/NymNodeDetails'
- '#/components/schemas/PaginationRequest'
- '#/components/schemas/PartialCoinIndicesSignatureResponse'
- '#/components/schemas/SpentCredentialsResponse'
- '#/components/schemas/UptimeHistoryResponse'
- '#/components/schemas/VerifyEcashCredentialBody'
- '#/components/responses/AxumErrorResponse'
- '#/components/responses/CirculatingSupplyResponse'
- '#/components/responses/RequestError'
-83
View File
@@ -1,83 +0,0 @@
extends:
- minimal
apis:
nym-api:
root: ./formatted-openapi.json
rules:
# https://redocly.com/docs/cli/rules/oas/operation-summary
operation-summary: off
# https://redocly.com/docs/cli/rules/oas/security-defined
security-defined: off
struct: off
# https://redocly.com/docs/cli/rules/oas/operation-2xx-response
operation-2xx-response: off
# rules:
# skip-warnings: true
# ignore:
# - path: /v1/gateways
# method: get
# - path: /v1/gateways/blacklisted
# method: get
# - path: /v1/mixnodes
# method: get
# - path: /v1/mixnodes/active
# method: get
# - path: /v1/mixnodes/active/detailed
# method: get
# - path: /v1/mixnodes/blacklisted
# method: get
# - path: /v1/mixnodes/detailed
# method: get
# - path: /v1/mixnodes/rewarded
# method: get
# - path: /v1/mixnodes/rewarded/detailed
# method: get
# - path: /v1/gateways/described
# method: get
# # network-monitor-status (deprecated)
# - path: /v1/status/gateway/{identity}/avg_uptime
# method: GET
# - path: /v1/status/gateway/{identity}/core-status-count
# method: GET
# - path: /v1/status/gateway/{identity}/history
# method: GET
# - path: /v1/status/gateway/{identity}/report
# method: GET
# - path: /v1/status/gateways/detailed
# method: GET
# - path: /v1/status/gateways/detailed-unfiltered
# method: GET
# - path: /v1/status/mixnode/{mix_id}/avg_uptime
# method: GET
# - path: /v1/status/mixnode/{mix_id}/compute-reward-estimation
# method: POST
# - path: /v1/status/mixnode/{mix_id}/core-status-count
# method: GET
# - path: /v1/status/mixnode/{mix_id}/history
# method: GET
# - path: /v1/status/mixnode/{mix_id}/report
# method: GET
# - path: /v1/status/mixnode/{mix_id}/reward-estimation
# method: GET
# - path: /v1/status/mixnodes/detailed-unfiltered
# method: GET
# # status
# - path: /v1/status/mixnode/{mix_id}/inclusion-probability
# method: GET
# - path: /v1/status/mixnode/{mix_id}/stake-saturation
# method: GET
# - path: /v1/status/mixnode/{mix_id}/status
# method: GET
# - path: /v1/status/mixnodes/active/detailed
# method: GET
# - path: /v1/status/mixnodes/detailed
# method: GET
# - path: /v1/status/mixnodes/inclusion-probability
# method: GET
# - path: /v1/status/mixnodes/rewarded/detailed
# method: GET
# # unstable nym nodes
# - path: /v1/unstable/nym-nodes/gateways/skimmed
# method: get
# - path: /v1/unstable/nym-nodes/mixnodes/skimmed
# method: get
-146
View File
@@ -4,152 +4,6 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
## [Unreleased] ## [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
## [2024.13-magura-patched] (2024-11-22) ## [2024.13-magura-patched] (2024-11-22)
- [experimental] allow clients to change between deterministic route selection based on packet headers and a pseudorandom distribution - [experimental] allow clients to change between deterministic route selection based on packet headers and a pseudorandom distribution
Generated
+471 -227
View File
File diff suppressed because it is too large Load Diff
+14 -7
View File
@@ -98,15 +98,17 @@ members = [
"common/wasm/utils", "common/wasm/utils",
"common/wireguard", "common/wireguard",
"common/wireguard-types", "common/wireguard-types",
"documentation/autodoc", # "documentation/autodoc",
"explorer-api", "explorer-api",
"explorer-api/explorer-api-requests", "explorer-api/explorer-api-requests",
"explorer-api/explorer-client", "explorer-api/explorer-client",
"gateway", "gateway",
"integrations/bity", "integrations/bity",
"mixnode",
"sdk/ffi/cpp", "sdk/ffi/cpp",
"sdk/ffi/go", "sdk/ffi/go",
"sdk/ffi/shared", "sdk/ffi/shared",
"sdk/lib/socks5-listener",
"sdk/rust/nym-sdk", "sdk/rust/nym-sdk",
"service-providers/authenticator", "service-providers/authenticator",
"service-providers/common", "service-providers/common",
@@ -121,8 +123,8 @@ members = [
"nym-data-observatory", "nym-data-observatory",
"nym-network-monitor", "nym-network-monitor",
"nym-node", "nym-node",
"nym-node/nym-node-http-api",
"nym-node/nym-node-requests", "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-agent",
"nym-node-status-api/nym-node-status-api", "nym-node-status-api/nym-node-status-api",
"nym-node-status-api/nym-node-status-client", "nym-node-status-api/nym-node-status-client",
@@ -147,13 +149,15 @@ members = [
"tools/internal/contract-state-importer/importer-cli", "tools/internal/contract-state-importer/importer-cli",
"tools/internal/contract-state-importer/importer-contract", "tools/internal/contract-state-importer/importer-contract",
"tools/internal/testnet-manager", "tools/internal/testnet-manager",
"tools/internal/testnet-manager/dkg-bypass-contract", "common/verloc", "tools/internal/mixnet-connectivity-check", "tools/internal/testnet-manager/dkg-bypass-contract",
] ]
default-members = [ default-members = [
"clients/native", "clients/native",
"clients/socks5", "clients/socks5",
"explorer-api", "explorer-api",
"gateway",
"mixnode",
"nym-api", "nym-api",
"nym-credential-proxy/nym-credential-proxy", "nym-credential-proxy/nym-credential-proxy",
"nym-data-observatory", "nym-data-observatory",
@@ -259,7 +263,6 @@ http-body-util = "0.1"
httpcodec = "0.2.3" httpcodec = "0.2.3"
humantime = "2.1.0" humantime = "2.1.0"
humantime-serde = "1.1.1" humantime-serde = "1.1.1"
human-repr = "1.1.0"
hyper = "1.4.1" hyper = "1.4.1"
hyper-util = "0.1" hyper-util = "0.1"
indicatif = "0.17.8" indicatif = "0.17.8"
@@ -345,9 +348,9 @@ tracing-log = "0.2"
ts-rs = "10.0.0" ts-rs = "10.0.0"
tungstenite = { version = "0.20.1", default-features = false } tungstenite = { version = "0.20.1", default-features = false }
url = "2.5" url = "2.5"
utoipa = "5.2" utoipa = "4.2"
utoipa-swagger-ui = "8.0" utoipa-swagger-ui = "7.1"
utoipauto = "0.2" utoipauto = "0.1"
uuid = "*" uuid = "*"
vergen = { version = "=8.3.1", default-features = false } vergen = { version = "=8.3.1", default-features = false }
walkdir = "2" walkdir = "2"
@@ -416,6 +419,10 @@ web-sys = "0.3.72"
[profile.dev.package.sqlx-macros] [profile.dev.package.sqlx-macros]
opt-level = 3 opt-level = 3
[profile.release.package.nym-socks5-listener]
strip = true
codegen-units = 1
[profile.release.package.nym-client-wasm] [profile.release.package.nym-client-wasm]
# lto = true # lto = true
opt-level = 'z' 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-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-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-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 <!-- 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"). * `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 ### Building
* Platform build instructions are available on Nym [Operators Guide documentation](https://nymtech.net/operators/binaries/building-nym.html). * 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 ### 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: References for developers:
* [Dev Docs](https://nymtech.net/docs/developers) * [Developers Portal](https://nymtech.net/developers)
* [SDKs](https://nymtech.net/docs/developers/rust) * [Typescript SDKs](https://sdk.nymtech.net/)
* [Network Docs](https://nymtech.net/docs/network) * [Technical Documentation - Nym network overview](https://nymtech.net/docs/)
* [Release Cycle - git flow](https://nymtech.net/docs/operators/release-cycle) * [Release Cycle - git flow](https://nymtech.net/operators/release-cycle.html)
### Developer chat ### 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 ### 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: 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: 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 24B2592E801A5AAA8666C8BA7C3C727F05090550
uid [ ultime ] Security Nym Technologies <security@nym.com> uid [ ultime ] Security Nym Technologies <security@nymte.ch>
ssb rsa4096/ACD0FBD79DC70ACC 2023-10-30 [E] [expire : 2026-10-29] sub rsa4096 2023-10-30 [E] [expire : 2026-10-29]
``` ```
The fingerprint of the key is on the second line above. 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. 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----- -----BEGIN PGP PUBLIC KEY BLOCK-----
@@ -34,69 +48,43 @@ vMFUIzBMHOPXH16036zGyFMC1esRd2qqil4b9KtLgCOkrD1VgpjcveoA0VyMJCN6
LmKTrVjwjjDMxby+d49BolRWGnCofXozXwvNQx+CYv8M2WPErTpyYoofYFtpqr7A LmKTrVjwjjDMxby+d49BolRWGnCofXozXwvNQx+CYv8M2WPErTpyYoofYFtpqr7A
fIufc/e0+um3zoGIbHejrhsbuH9Qf+MKsI+Ng93bdDtjeHz6MEgAlsTm0qeizYpj fIufc/e0+um3zoGIbHejrhsbuH9Qf+MKsI+Ng93bdDtjeHz6MEgAlsTm0qeizYpj
IyKZIObPmfvrAm08hFZ8JnGk+XuooF36XWbJYjCCy0bOyMw1r7ZG99TcSwARAQAB IyKZIObPmfvrAm08hFZ8JnGk+XuooF36XWbJYjCCy0bOyMw1r7ZG99TcSwARAQAB
tCxTZWN1cml0eSBOeW0gVGVjaG5vbG9naWVzIDxzZWN1cml0eUBueW0uY29tPokC tC1TZWN1cml0eSBOeW0gVGVjaG5vbG9naWVzIDxzZWN1cml0eUBueW10ZS5jaD6J
VAQTAQoAPhYhBCSyWS6AGlqqhmbIunw8cn8FCQVQBQJnSd5VAhsDBQkFo5qABQsJ AlQEEwEKAD4WIQQkslkugBpaqoZmyLp8PHJ/BQkFUAUCZT9elwIbAwUJBaOagAUL
CAcDBRUKCQgLBRYCAwEAAh4BAheAAAoJEHw8cn8FCQVQPPIP/ipGz2zLAjE2dSE3 CQgHAwUVCgkICwUWAgMBAAIeAQIXgAAKCRB8PHJ/BQkFUL7dD/9zO73uI5VR+SWx
VcqOvras0DfqIL9HDm26Dg6QO2D/4YRntw0RqVyuy+zFnRUm+RZCKLPLUzbQ9Wjb PFmJW+9QsPiQbVRvGwNZurctmQ2s2Pe0vHRELFeqD5oYvSx2Lequ3Ir+zn/C3kDM
G/Og5ttQVYQMu5eKu7OMvXkrbRo3teZFU+8IL08zIW6pyf9haxO6YMhLRy6cLYwW kNs40obSL6jCBiLPkxEY0JqzPM9jZr7EjvlibWV3f6DxooRIqEyfN57I3OBGlqZE
0EYC6Qzn5gz3kI7VkI8fWfs2Dk4XEV3D+SVtBoF6KRxMXT6HZvpzoMSEJZBoNj8S 0Mx7sQuCcgau8C70DF952QhKUwXC2cmpmDKHVEEoio1xGSD4dQhGapCB32RQGtna
jw0TF8TFUQf49jUQbIHumukMswolrHi8a5ej8DSfNwSgz+Tt8oh5lu01kyUJiHn7 OGfAO9celNMvSq0Lp+aJxeACmWFY5T4/y79JPcT5vSs/yEIRmaH/fn2piwaFBsIq
nuHaY4Y9cHUVAOSwq/hovG52+ZE1r3aiswvle/B19o9pKeWWVvacSptGxDQagBtQ gHJJMxO3740P1hF8j7KWUoUofuFaEALHBpEpjWTOj8ej1wmFlu+5F+jSVoc781Wb
igoNLdRvY0XN2TEyX9pOHR0AoVOxtIW11CpkKuDbQG9vPwovqJ2L6+Fh3pzHYzcI ZZXu04cOBXnGTogzSxMpBe9TtLb28zd6WzFotC25KTI3pngMzXsQGLJLOwvoZKiS
2GIShNm/Z2SZBiUqbljJe9H4UAT/aHgMINkEG8qzUKwO42MA5HJT7YbHTR17/QSF LFjPRjg1rwobmB3Q3J2W5GYSveia0CDsZGP+g87GVVf/oD2Djpa68xyVYwIYeA6T
Il5dhneRzmSbNcW2rdRwx/BmzrcsFJfqCt4JG/WDF293xSOjhFqQYvU4gCO+OB7o 3DNdS77qHiRuGiS4kWXyVjDqOICboR4uCvt09zlkBuLDdTWqWYARUvZjtjs4w/Ol
KXjX907XXDjS2KEJ71OGqVfk/P7BqEfQNfrLtb02TyXJAPQXHhybv23c4E7zUs9V rdrBI3A88ti8fRldYaNpu17ME1ilpN44yKoJtqiWc3Tisk8eYLfx6c7FQF3PrRva
lMjNizzxYB96uwJb0LAB2ijzEwoP91uGT2tFjk6F08x2QiArmXUdgrv44b39Stia mr7FZvhFsYML5CeNFHTEzN6Y3jjKN/60DvCfodWnWFK47Txkl8UAXGY2W9B0fWqQ
gJS0GYKqSzyr10xHhUuDA+GKYtcitC1TZWN1cml0eSBOeW0gVGVjaG5vbG9naWVz wUVr8uLuMyyMiKbeoufi7rGOj6AMErkCDQRlP16XARAA8FGmD5J3tM1BOM1niJxZ
IDxzZWN1cml0eUBueW10ZS5jaD6JAjYEMAEKACAWIQQkslkugBpaqoZmyLp8PHJ/ JTdCauzEtxEoBL0RuqGBkR8U29sRM6DwuzjU7PwscFnBaGyU+eU73GwGkH3ozFfF
BQkFUAUCZ0nftQIdIAAKCRB8PHJ/BQkFUFHDEACtyNuUEjKCLAT5mSfow85PjFgo tllYhQrhP/kkN+0rEO5Xi+nR+4JCFRqrf3nJXAAPfiksURMp8er1dUOY2/e1ZSoL
o8kHjQr/IIQ7ZbBOHeJJcrxDuypssiLh5XUjF3x5BiBfZ6vCxSb81RRwsDMp0mA1 tS+nzUivV8CfE+pgj/5YtGwPC+KYHLATkKkMELCrbW4UO06VWOqQsvr6kivXuJQQ
qzv9G8sgW0HTQUnZ9oH6CYut2NgzAnQpmuacrunm9Zy0FJ3ejbmwUY/NqK6gJkle LdEAMpBlADmXFG45DmPKQzsBWUgvTwyGy3LX0nys8cgpex9BH8hhr01QmGyP469s
66duHKhAy7DWjj7amd0C8bPDR+PA44fI3MezDHkQNaauKZTRqd1TqH8Qk5PAl4cB N3cNrtFuu8U6RAsiCD/8mlBuD3EQEU5SF0lc7kCICAZk+wElmXnimEi0TOYsbz6k
o5gVzeZh/U7/usvtGhazAIUF5BqK6bTmDnYopg+2x8jjwrG4+08GrttZkNjBLXeA 90lteicX70rA9GNeyI76H+VSOYvWpkRwaJAgUdzrAM1o9SHASq+cZ6nD85OZioQk
Y/2U064yMz12LPv01qqAFdZ+coRy/ps/gOQTz34/VeW0CFy7TMqs4t3vSBWTqU7w DWM6+Q+sf2oen0qJnnGmUr93kJIC0PIdgrXRrtiNfeRa1Z/H0LmREyyEMoFiVivn
hnw/qj6cM33fdxctj6KDgJSCkZdx2fvwXgxiPqUa5+j9FlFBeD5RDAl6g6t8N1/K z1vVk85Oq6Sf3ltUwvmDzuuJOtsp2Qp6+x6Snn/yKauI4uf4Cf/wKUch4r6Bwgg5
Xca+zNYuSZgc297q1D+mtSD1C7uJNPxoAl+Bv5KNKpsjfQ+m04++CIFtGyX22aCA Dw49ky7lwlnALio4GIVoGLpLef93wWoDmp4Klyh3ZPf2nB0U91u3bHRUo7m+D7QJ
h2/tHwQZIXhOiMAKOoupidDVDhgxtCJ3Ps416xL0sTZfsPfg+j1Uv/Em9pzPClEl 98cyKtqLLzjg7szGf60pIWNWRsadYQT3bSncynqknAjOV3BCvx6/ivsnpj//QjYR
fX6+1O4DdSyZUQ4VsjMu/H5W/NQdbHgmqFrxQ6WX/0s5GMwO6GMDiPe8sOrwz9wD HtviUAcQ1DBB6UC6q23FIs0AEQEAAYkCPAQYAQoAJhYhBCSyWS6AGlqqhmbIunw8
WYtyjafxXOHEZ1OjYX5gr7bGaG4oKc2btTJN0B3Phg4dStnHCNjEYccxuV3507fj cn8FCQVQBQJlP16XAhsMBQkFo5qAAAoJEHw8cn8FCQVQzukP/iLxjOxT+UpPR//c
HnNotkpXF2nGLxy+PYkCVAQTAQoAPhYhBCSyWS6AGlqqhmbIunw8cn8FCQVQBQJl prDVSLkP4pF5bmw36U07jvqpS+/KTXsxiiQleffRabOpNLcd+K1ueavyt9nnIwHH
P16XAhsDBQkFo5qABQsJCAcDBRUKCQgLBRYCAwEAAh4BAheAAAoJEHw8cn8FCQVQ tHS9kM9A7DBw3LnpEbXki46QDCCI6niGijlLOEeAWqnocwMNTT05wVVgCtO3DQP2
vt0P/3M7ve4jlVH5JbE8WYlb71Cw+JBtVG8bA1m6ty2ZDazY97S8dEQsV6oPmhi9 MoSCcqHpXDChvOyr5d5xjYLVJhlctIMSomcVzGryjknPu0Yj/TkC/4c+m86ZWQUD
LHYt6q7civ7Of8LeQMyQ2zjShtIvqMIGIs+TERjQmrM8z2NmvsSO+WJtZXd/oPGi HqMHQIuiEenvb62/F4c5OJIRZPEn70wdddkgJuJU3eHdHrnuhCkjCC93GQGbGj03
hEioTJ83nsjc4EaWpkTQzHuxC4JyBq7wLvQMX3nZCEpTBcLZyamYModUQSiKjXEZ Zqos6699y6hmPeD3U5IUv8ujwZYVCCuDm8gJfrp3R6WLfeZeK9WmTVBpCzsDg3fV
IPh1CEZqkIHfZFAa2do4Z8A71x6U0y9KrQun5onF4AKZYVjlPj/Lv0k9xPm9Kz/I hSwmOk6pp8DAq1/Dev3yRkFggCEyGK6c9b+a0CRBncl8e5Q0QQIzNiS/uExQP3h+
QhGZof9+famLBoUGwiqAckkzE7fvjQ/WEXyPspZShSh+4VoQAscGkSmNZM6Px6PX ELJs3P0MLP+6FWhNUry09n3lnWkr1hY+v1M0GAxbfdv/tsCN1Pq/VQEz+CTqXqya
CYWW77kX6NJWhzvzVZtlle7Thw4FecZOiDNLEykF71O0tvbzN3pbMWi0LbkpMjem ftWldOHWw6Hh+gtwxcHjG4MBOrO5oICQ3lh2hGwQ58cDgZYSK/OGgJ9BggFl1CcM
eAzNexAYsks7C+hkqJIsWM9GODWvChuYHdDcnZbkZhK96JrQIOxkY/6DzsZVV/+g 0uGC0/TRCI1zt/4y+7efSZQMZkHo7VC/3MFbp2hcNejpW+BxVuwKTunFvWK3TLhq
PYOOlrrzHJVjAhh4DpPcM11LvuoeJG4aJLiRZfJWMOo4gJuhHi4K+3T3OWQG4sN1 sSlQ5yyhqchooepsFHq9bosKFjLJC01uprBv1rinoNduOy43FbyS7JPRRspANN0R
NapZgBFS9mO2OzjD86Wt2sEjcDzy2Lx9GV1ho2m7XswTWKWk3jjIqgm2qJZzdOKy iC2pMbWdE0ZTQaFq6tPIg058pjqi
Tx5gt/HpzsVAXc+tG9qavsVm+EWxgwvkJ40UdMTM3pjeOMo3/rQO8J+h1adYUrjt =nqgX
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
-----END PGP PUBLIC KEY BLOCK----- -----END PGP PUBLIC KEY BLOCK-----
``` ```
+1 -1
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "nym-client" name = "nym-client"
version = "1.1.45" version = "1.1.44"
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"] authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"]
description = "Implementation of the Nym Client" description = "Implementation of the Nym Client"
edition = "2021" edition = "2021"
+28 -1
View File
@@ -3,10 +3,13 @@
use crate::commands::try_load_current_config; use crate::commands::try_load_current_config;
use crate::{ use crate::{
client::SocketClient, client::{config::Config, SocketClient},
commands::{override_config, OverrideConfig}, commands::{override_config, OverrideConfig},
error::ClientError,
}; };
use clap::Args; 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::cli_helpers::client_run::CommonClientRunArgs;
use std::error::Error; use std::error::Error;
use std::net::IpAddr; 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>> { pub(crate) async fn execute(args: Run) -> Result<(), Box<dyn Error + Send + Sync>> {
eprintln!("Starting client {}...", args.common_args.id); eprintln!("Starting client {}...", args.common_args.id);
let mut config = try_load_current_config(&args.common_args.id).await?; let mut config = try_load_current_config(&args.common_args.id).await?;
config = override_config(config, OverrideConfig::from(args.clone())); 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) SocketClient::new(config, args.common_args.custom_mixnet)
.run_socket_forever() .run_socket_forever()
.await .await
+3
View File
@@ -17,6 +17,9 @@ pub enum ClientError {
#[error("Failed to validate the loaded config")] #[error("Failed to validate the loaded config")]
ConfigValidationFailure, ConfigValidationFailure,
#[error("Failed local version check, client and config mismatch")]
FailedLocalVersionCheck,
#[error("Attempted to start the client in invalid socket mode")] #[error("Attempted to start the client in invalid socket mode")]
InvalidSocketMode, InvalidSocketMode,
+1 -1
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "nym-socks5-client" name = "nym-socks5-client"
version = "1.1.45" version = "1.1.44"
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"] authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
description = "A SOCKS5 localhost proxy that converts incoming messages to Sphinx and sends them to a Nym address" description = "A SOCKS5 localhost proxy that converts incoming messages to Sphinx and sends them to a Nym address"
edition = "2021" edition = "2021"
+33 -1
View File
@@ -2,8 +2,14 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
use crate::commands::try_load_current_config; 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 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::cli_helpers::client_run::CommonClientRunArgs;
use nym_client_core::client::base_client::storage::OnDiskPersistent; use nym_client_core::client::base_client::storage::OnDiskPersistent;
use nym_client_core::client::topology_control::geo_aware_provider::CountryGroup; 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>> { pub(crate) async fn execute(args: Run) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
eprintln!("Starting client {}...", args.common_args.id); eprintln!("Starting client {}...", args.common_args.id);
let mut config = try_load_current_config(&args.common_args.id).await?; let mut config = try_load_current_config(&args.common_args.id).await?;
config = override_config(config, OverrideConfig::from(args.clone())); 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 = let storage =
OnDiskPersistent::from_paths(config.storage_paths.common_paths, &config.core.base.debug) OnDiskPersistent::from_paths(config.storage_paths.common_paths, &config.core.base.debug)
.await?; .await?;
+3
View File
@@ -14,6 +14,9 @@ pub enum Socks5ClientError {
#[error("Failed to validate the loaded config")] #[error("Failed to validate the loaded config")]
ConfigValidationFailure, ConfigValidationFailure,
#[error("Failed local version check, client and config mismatch")]
FailedLocalVersionCheck,
#[error("Fail to bind address")] #[error("Fail to bind address")]
FailToBindAddress, FailToBindAddress,
-1
View File
@@ -8,7 +8,6 @@ pub mod v3;
pub mod v4; pub mod v4;
mod error; mod error;
mod util;
pub use error::Error; pub use error::Error;
pub use v4 as latest; 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 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 { pub struct InitMessage {
/// Base64 encoded x25519 public key /// Base64 encoded x25519 public key
pub pub_key: PeerPublicKey, pub pub_key: PeerPublicKey,
@@ -41,7 +41,7 @@ impl InitMessage {
} }
} }
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] #[derive(Serialize, Deserialize, Debug, Clone)]
pub struct FinalMessage { pub struct FinalMessage {
/// Gateway client data /// Gateway client data
pub gateway_client: GatewayClient, pub gateway_client: GatewayClient,
@@ -50,28 +50,28 @@ pub struct FinalMessage {
pub credential: Option<CredentialSpendingData>, pub credential: Option<CredentialSpendingData>,
} }
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] #[derive(Serialize, Deserialize, Debug, Clone)]
pub struct RegistrationData { pub struct RegistrationData {
pub nonce: u64, pub nonce: u64,
pub gateway_data: GatewayClient, pub gateway_data: GatewayClient,
pub wg_port: u16, pub wg_port: u16,
} }
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] #[derive(Serialize, Deserialize, Debug, Clone)]
pub struct RegistredData { pub struct RegistredData {
pub pub_key: PeerPublicKey, pub pub_key: PeerPublicKey,
pub private_ip: IpAddr, pub private_ip: IpAddr,
pub wg_port: u16, pub wg_port: u16,
} }
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] #[derive(Serialize, Deserialize, Debug, Clone)]
pub struct RemainingBandwidthData { pub struct RemainingBandwidthData {
pub available_bandwidth: i64, pub available_bandwidth: i64,
} }
/// Client that wants to register sends its PublicKey bytes mac digest encrypted with a DH shared secret. /// 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 /// 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 { pub struct GatewayClient {
/// Base64 encoded x25519 public key /// Base64 encoded x25519 public key
pub pub_key: PeerPublicKey, pub pub_key: PeerPublicKey,
@@ -147,7 +147,7 @@ impl GatewayClient {
// TODO: change the inner type into generic array of size HmacSha256::OutputSize // TODO: change the inner type into generic array of size HmacSha256::OutputSize
// TODO2: rely on our internal crypto/hmac // TODO2: rely on our internal crypto/hmac
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone)]
pub struct ClientMac(Vec<u8>); pub struct ClientMac(Vec<u8>);
impl fmt::Display for ClientMac { 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 { pub enum AuthenticatorRequestData {
Initial(InitMessage), Initial(InitMessage),
Final(Box<FinalMessage>), Final(Box<FinalMessage>),
@@ -100,28 +100,28 @@ impl AuthenticatorResponse {
} }
} }
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] #[derive(Clone, Debug, Serialize, Deserialize)]
pub enum AuthenticatorResponseData { pub enum AuthenticatorResponseData {
PendingRegistration(PendingRegistrationResponse), PendingRegistration(PendingRegistrationResponse),
Registered(RegisteredResponse), Registered(RegisteredResponse),
RemainingBandwidth(RemainingBandwidthResponse), RemainingBandwidth(RemainingBandwidthResponse),
} }
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] #[derive(Clone, Debug, Serialize, Deserialize)]
pub struct PendingRegistrationResponse { pub struct PendingRegistrationResponse {
pub request_id: u64, pub request_id: u64,
pub reply_to: Recipient, pub reply_to: Recipient,
pub reply: RegistrationData, pub reply: RegistrationData,
} }
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] #[derive(Clone, Debug, Serialize, Deserialize)]
pub struct RegisteredResponse { pub struct RegisteredResponse {
pub request_id: u64, pub request_id: u64,
pub reply_to: Recipient, pub reply_to: Recipient,
pub reply: RegistredData, pub reply: RegistredData,
} }
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] #[derive(Clone, Debug, Serialize, Deserialize)]
pub struct RemainingBandwidthResponse { pub struct RemainingBandwidthResponse {
pub request_id: u64, pub request_id: u64,
pub reply_to: Recipient, 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 { impl From<v2::request::AuthenticatorRequestData> for v3::request::AuthenticatorRequestData {
fn from(authenticator_request_data: v2::request::AuthenticatorRequestData) -> Self { fn from(authenticator_request_data: v2::request::AuthenticatorRequestData) -> Self {
match authenticator_request_data { 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 { impl From<v2::registration::InitMessage> for v3::registration::InitMessage {
fn from(init_msg: v2::registration::InitMessage) -> Self { fn from(init_msg: v2::registration::InitMessage) -> Self {
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> { impl From<Box<v2::registration::FinalMessage>> for Box<v3::registration::FinalMessage> {
fn from(gw_client: Box<v2::registration::FinalMessage>) -> Self { fn from(gw_client: Box<v2::registration::FinalMessage>) -> Self {
Box::new(v3::registration::FinalMessage { 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 { impl From<v2::registration::GatewayClient> for v3::registration::GatewayClient {
fn from(gw_client: v2::registration::GatewayClient) -> Self { fn from(gw_client: v2::registration::GatewayClient) -> Self {
Self { Self {
@@ -151,10 +93,7 @@ impl TryFrom<v3::response::AuthenticatorResponse> for v2::response::Authenticato
Ok(Self { Ok(Self {
data: authenticator_response.data.try_into()?, data: authenticator_response.data.try_into()?,
reply_to: authenticator_response.reply_to, reply_to: authenticator_response.reply_to,
protocol: Protocol { protocol: authenticator_response.protocol,
version: 2,
service_provider_type: authenticator_response.protocol.service_provider_type,
},
}) })
} }
} }
@@ -162,10 +101,7 @@ impl TryFrom<v3::response::AuthenticatorResponse> for v2::response::Authenticato
impl From<v2::response::AuthenticatorResponse> for v3::response::AuthenticatorResponse { impl From<v2::response::AuthenticatorResponse> for v3::response::AuthenticatorResponse {
fn from(value: v2::response::AuthenticatorResponse) -> Self { fn from(value: v2::response::AuthenticatorResponse) -> Self {
Self { Self {
protocol: Protocol { protocol: value.protocol,
version: 3,
service_provider_type: value.protocol.service_provider_type,
},
data: value.data.into(), data: value.data.into(),
reply_to: value.reply_to, 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 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 { pub struct InitMessage {
/// Base64 encoded x25519 public key /// Base64 encoded x25519 public key
pub pub_key: PeerPublicKey, pub pub_key: PeerPublicKey,
@@ -41,7 +41,7 @@ impl InitMessage {
} }
} }
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] #[derive(Serialize, Deserialize, Debug, Clone)]
pub struct FinalMessage { pub struct FinalMessage {
/// Gateway client data /// Gateway client data
pub gateway_client: GatewayClient, pub gateway_client: GatewayClient,
@@ -50,28 +50,28 @@ pub struct FinalMessage {
pub credential: Option<CredentialSpendingData>, pub credential: Option<CredentialSpendingData>,
} }
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] #[derive(Serialize, Deserialize, Debug, Clone)]
pub struct RegistrationData { pub struct RegistrationData {
pub nonce: u64, pub nonce: u64,
pub gateway_data: GatewayClient, pub gateway_data: GatewayClient,
pub wg_port: u16, pub wg_port: u16,
} }
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] #[derive(Serialize, Deserialize, Debug, Clone)]
pub struct RegistredData { pub struct RegistredData {
pub pub_key: PeerPublicKey, pub pub_key: PeerPublicKey,
pub private_ip: IpAddr, pub private_ip: IpAddr,
pub wg_port: u16, pub wg_port: u16,
} }
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] #[derive(Serialize, Deserialize, Debug, Clone)]
pub struct RemainingBandwidthData { pub struct RemainingBandwidthData {
pub available_bandwidth: i64, pub available_bandwidth: i64,
} }
/// Client that wants to register sends its PublicKey bytes mac digest encrypted with a DH shared secret. /// 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 /// 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 { pub struct GatewayClient {
/// Base64 encoded x25519 public key /// Base64 encoded x25519 public key
pub pub_key: PeerPublicKey, pub pub_key: PeerPublicKey,
@@ -147,7 +147,7 @@ impl GatewayClient {
// TODO: change the inner type into generic array of size HmacSha256::OutputSize // TODO: change the inner type into generic array of size HmacSha256::OutputSize
// TODO2: rely on our internal crypto/hmac // TODO2: rely on our internal crypto/hmac
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone)]
pub struct ClientMac(Vec<u8>); pub struct ClientMac(Vec<u8>);
impl fmt::Display for ClientMac { 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 { pub enum AuthenticatorRequestData {
Initial(InitMessage), Initial(InitMessage),
Final(Box<FinalMessage>), Final(Box<FinalMessage>),
@@ -120,7 +120,7 @@ impl AuthenticatorResponse {
} }
} }
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] #[derive(Clone, Debug, Serialize, Deserialize)]
pub enum AuthenticatorResponseData { pub enum AuthenticatorResponseData {
PendingRegistration(PendingRegistrationResponse), PendingRegistration(PendingRegistrationResponse),
Registered(RegisteredResponse), Registered(RegisteredResponse),
@@ -128,28 +128,28 @@ pub enum AuthenticatorResponseData {
TopUpBandwidth(TopUpBandwidthResponse), TopUpBandwidth(TopUpBandwidthResponse),
} }
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] #[derive(Clone, Debug, Serialize, Deserialize)]
pub struct PendingRegistrationResponse { pub struct PendingRegistrationResponse {
pub request_id: u64, pub request_id: u64,
pub reply_to: Recipient, pub reply_to: Recipient,
pub reply: RegistrationData, pub reply: RegistrationData,
} }
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] #[derive(Clone, Debug, Serialize, Deserialize)]
pub struct RegisteredResponse { pub struct RegisteredResponse {
pub request_id: u64, pub request_id: u64,
pub reply_to: Recipient, pub reply_to: Recipient,
pub reply: RegistredData, pub reply: RegistredData,
} }
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] #[derive(Clone, Debug, Serialize, Deserialize)]
pub struct RemainingBandwidthResponse { pub struct RemainingBandwidthResponse {
pub request_id: u64, pub request_id: u64,
pub reply_to: Recipient, pub reply_to: Recipient,
pub reply: Option<RemainingBandwidthData>, pub reply: Option<RemainingBandwidthData>,
} }
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] #[derive(Clone, Debug, Serialize, Deserialize)]
pub struct TopUpBandwidthResponse { pub struct TopUpBandwidthResponse {
pub request_id: u64, pub request_id: u64,
pub reply_to: Recipient, pub reply_to: Recipient,
@@ -5,7 +5,7 @@ use nym_credentials_interface::CredentialSpendingData;
use nym_wireguard_types::PeerPublicKey; use nym_wireguard_types::PeerPublicKey;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] #[derive(Serialize, Deserialize, Debug, Clone)]
pub struct TopUpMessage { pub struct TopUpMessage {
/// Base64 encoded x25519 public key /// Base64 encoded x25519 public key
pub pub_key: PeerPublicKey, pub pub_key: PeerPublicKey,
+104 -609
View File
@@ -3,82 +3,37 @@
use nym_service_provider_requests_common::{Protocol, ServiceProviderType}; 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 { impl From<v3::request::AuthenticatorRequest> for v4::request::AuthenticatorRequest {
type Error = crate::Error; fn from(authenticator_request: v3::request::AuthenticatorRequest) -> Self {
fn try_from( Self {
authenticator_request: v3::request::AuthenticatorRequest,
) -> Result<Self, Self::Error> {
Ok(Self {
protocol: Protocol { protocol: Protocol {
version: 4, version: 4,
service_provider_type: ServiceProviderType::Authenticator, service_provider_type: ServiceProviderType::Authenticator,
}, },
data: authenticator_request.data.try_into()?, data: authenticator_request.data.into(),
reply_to: authenticator_request.reply_to, reply_to: authenticator_request.reply_to,
request_id: authenticator_request.request_id, 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 { impl From<v3::request::AuthenticatorRequestData> for v4::request::AuthenticatorRequestData {
type Error = crate::Error; fn from(authenticator_request_data: v3::request::AuthenticatorRequestData) -> Self {
fn try_from(
authenticator_request_data: v4::request::AuthenticatorRequestData,
) -> Result<Self, Self::Error> {
match authenticator_request_data { match authenticator_request_data {
v4::request::AuthenticatorRequestData::Initial(init_msg) => Ok( v3::request::AuthenticatorRequestData::Initial(init_msg) => {
v3::request::AuthenticatorRequestData::Initial(init_msg.into()), v4::request::AuthenticatorRequestData::Initial(init_msg.into())
), }
v4::request::AuthenticatorRequestData::Final(_) => Err(Self::Error::Conversion( v3::request::AuthenticatorRequestData::Final(gw_client) => {
"mac hash breaking change".to_string(), v4::request::AuthenticatorRequestData::Final(gw_client.into())
)), }
v4::request::AuthenticatorRequestData::QueryBandwidth(pub_key) => Ok( v3::request::AuthenticatorRequestData::QueryBandwidth(pub_key) => {
v3::request::AuthenticatorRequestData::QueryBandwidth(pub_key), v4::request::AuthenticatorRequestData::QueryBandwidth(pub_key)
), }
v4::request::AuthenticatorRequestData::TopUpBandwidth(top_up_message) => Ok( v3::request::AuthenticatorRequestData::TopUpBandwidth(top_up_message) => {
v3::request::AuthenticatorRequestData::TopUpBandwidth(top_up_message.into()), 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 { impl From<Box<v3::registration::FinalMessage>> for Box<v4::registration::FinalMessage> {
fn from(init_msg: v4::registration::InitMessage) -> Self { fn from(gw_client: Box<v3::registration::FinalMessage>) -> Self {
Self { Box::new(v4::registration::FinalMessage {
pub_key: init_msg.pub_key, 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> { impl From<v2::registration::GatewayClient> for v4::registration::GatewayClient {
fn from(top_up_message: Box<v4::topup::TopUpMessage>) -> Self { fn from(gw_client: v2::registration::GatewayClient) -> Self {
Box::new(v3::topup::TopUpMessage { Self {
pub_key: top_up_message.pub_key, pub_key: gw_client.pub_key,
credential: top_up_message.credential, private_ips: gw_client.private_ip.into(),
}) mac: gw_client.mac.into(),
}
} }
} }
impl TryFrom<v3::response::AuthenticatorResponse> for v4::response::AuthenticatorResponse { impl From<v3::registration::GatewayClient> for v4::registration::GatewayClient {
type Error = crate::Error; fn from(gw_client: v3::registration::GatewayClient) -> Self {
fn try_from(value: v3::response::AuthenticatorResponse) -> Result<Self, Self::Error> { Self {
Ok(Self { pub_key: gw_client.pub_key,
protocol: Protocol { private_ips: gw_client.private_ip.into(),
version: 4, mac: gw_client.mac.into(),
service_provider_type: value.protocol.service_provider_type, }
}, }
data: value.data.try_into()?, }
reply_to: value.reply_to,
}) 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 { Ok(Self {
data: authenticator_response.data.try_into()?, data: authenticator_response.data.try_into()?,
reply_to: authenticator_response.reply_to, reply_to: authenticator_response.reply_to,
protocol: Protocol { protocol: authenticator_response.protocol,
version: 3,
service_provider_type: authenticator_response.protocol.service_provider_type,
},
}) })
} }
} }
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 { impl TryFrom<v4::response::AuthenticatorResponseData> for v3::response::AuthenticatorResponseData {
type Error = crate::Error; type Error = crate::Error;
@@ -181,10 +149,13 @@ impl TryFrom<v4::response::AuthenticatorResponseData> for v3::response::Authenti
authenticator_response_data: v4::response::AuthenticatorResponseData, authenticator_response_data: v4::response::AuthenticatorResponseData,
) -> Result<Self, Self::Error> { ) -> Result<Self, Self::Error> {
match authenticator_response_data { match authenticator_response_data {
v4::response::AuthenticatorResponseData::PendingRegistration(_) => Err( v4::response::AuthenticatorResponseData::PendingRegistration(
Self::Error::Conversion("mac hash breaking change".to_string()), pending_registration_response,
) => Ok(
v3::response::AuthenticatorResponseData::PendingRegistration(
pending_registration_response.into(),
),
), ),
v4::response::AuthenticatorResponseData::Registered(registered_response) => Ok( v4::response::AuthenticatorResponseData::Registered(registered_response) => Ok(
v3::response::AuthenticatorResponseData::Registered(registered_response.into()), 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 { impl From<v4::response::RegisteredResponse> for v3::response::RegisteredResponse {
fn from(value: v4::response::RegisteredResponse) -> Self { fn from(value: v4::response::RegisteredResponse) -> Self {
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 { impl From<v4::response::RemainingBandwidthResponse> for v3::response::RemainingBandwidthResponse {
fn from(value: v4::response::RemainingBandwidthResponse) -> Self { fn from(value: v4::response::RemainingBandwidthResponse) -> Self {
Self { Self {
@@ -242,31 +203,11 @@ impl From<v4::response::RemainingBandwidthResponse> for v3::response::RemainingB
} }
} }
impl From<v3::response::TopUpBandwidthResponse> for v4::response::TopUpBandwidthResponse { impl From<v4::registration::RegistrationData> for v3::registration::RegistrationData {
fn from(value: v3::response::TopUpBandwidthResponse) -> Self { fn from(value: v4::registration::RegistrationData) -> Self {
Self { Self {
request_id: value.request_id, nonce: value.nonce,
reply_to: value.reply_to, gateway_data: value.gateway_data.into(),
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(),
wg_port: value.wg_port, 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 { impl From<v4::registration::RemainingBandwidthData> for v3::registration::RemainingBandwidthData {
fn from(value: v4::registration::RemainingBandwidthData) -> Self { fn from(value: v4::registration::RemainingBandwidthData) -> Self {
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 { pub struct InitMessage {
/// Base64 encoded x25519 public key /// Base64 encoded x25519 public key
pub pub_key: PeerPublicKey, pub pub_key: PeerPublicKey,
@@ -93,7 +93,7 @@ impl InitMessage {
} }
} }
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] #[derive(Serialize, Deserialize, Debug, Clone)]
pub struct FinalMessage { pub struct FinalMessage {
/// Gateway client data /// Gateway client data
pub gateway_client: GatewayClient, pub gateway_client: GatewayClient,
@@ -102,28 +102,28 @@ pub struct FinalMessage {
pub credential: Option<CredentialSpendingData>, pub credential: Option<CredentialSpendingData>,
} }
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] #[derive(Serialize, Deserialize, Debug, Clone)]
pub struct RegistrationData { pub struct RegistrationData {
pub nonce: u64, pub nonce: u64,
pub gateway_data: GatewayClient, pub gateway_data: GatewayClient,
pub wg_port: u16, pub wg_port: u16,
} }
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] #[derive(Serialize, Deserialize, Debug, Clone)]
pub struct RegistredData { pub struct RegistredData {
pub pub_key: PeerPublicKey, pub pub_key: PeerPublicKey,
pub private_ips: IpPair, pub private_ips: IpPair,
pub wg_port: u16, pub wg_port: u16,
} }
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] #[derive(Serialize, Deserialize, Debug, Clone)]
pub struct RemainingBandwidthData { pub struct RemainingBandwidthData {
pub available_bandwidth: i64, pub available_bandwidth: i64,
} }
/// Client that wants to register sends its PublicKey bytes mac digest encrypted with a DH shared secret. /// 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 /// 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 { pub struct GatewayClient {
/// Base64 encoded x25519 public key /// Base64 encoded x25519 public key
pub pub_key: PeerPublicKey, pub pub_key: PeerPublicKey,
@@ -199,7 +199,7 @@ impl GatewayClient {
// TODO: change the inner type into generic array of size HmacSha256::OutputSize // TODO: change the inner type into generic array of size HmacSha256::OutputSize
// TODO2: rely on our internal crypto/hmac // TODO2: rely on our internal crypto/hmac
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone)]
pub struct ClientMac(Vec<u8>); pub struct ClientMac(Vec<u8>);
impl fmt::Display for ClientMac { impl fmt::Display for ClientMac {
@@ -20,7 +20,7 @@ fn generate_random() -> u64 {
rng.next_u64() rng.next_u64()
} }
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] #[derive(Clone, Debug, Serialize, Deserialize)]
pub struct AuthenticatorRequest { pub struct AuthenticatorRequest {
pub protocol: Protocol, pub protocol: Protocol,
pub data: AuthenticatorRequestData, pub data: AuthenticatorRequestData,
@@ -106,7 +106,7 @@ impl AuthenticatorRequest {
} }
} }
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] #[derive(Clone, Debug, Serialize, Deserialize)]
pub enum AuthenticatorRequestData { pub enum AuthenticatorRequestData {
Initial(InitMessage), Initial(InitMessage),
Final(Box<FinalMessage>), Final(Box<FinalMessage>),
@@ -10,7 +10,7 @@ use crate::make_bincode_serializer;
use super::VERSION; use super::VERSION;
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] #[derive(Clone, Debug, Serialize, Deserialize)]
pub struct AuthenticatorResponse { pub struct AuthenticatorResponse {
pub protocol: Protocol, pub protocol: Protocol,
pub data: AuthenticatorResponseData, pub data: AuthenticatorResponseData,
@@ -120,7 +120,7 @@ impl AuthenticatorResponse {
} }
} }
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] #[derive(Clone, Debug, Serialize, Deserialize)]
pub enum AuthenticatorResponseData { pub enum AuthenticatorResponseData {
PendingRegistration(PendingRegistrationResponse), PendingRegistration(PendingRegistrationResponse),
Registered(RegisteredResponse), Registered(RegisteredResponse),
@@ -128,28 +128,28 @@ pub enum AuthenticatorResponseData {
TopUpBandwidth(TopUpBandwidthResponse), TopUpBandwidth(TopUpBandwidthResponse),
} }
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] #[derive(Clone, Debug, Serialize, Deserialize)]
pub struct PendingRegistrationResponse { pub struct PendingRegistrationResponse {
pub request_id: u64, pub request_id: u64,
pub reply_to: Recipient, pub reply_to: Recipient,
pub reply: RegistrationData, pub reply: RegistrationData,
} }
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] #[derive(Clone, Debug, Serialize, Deserialize)]
pub struct RegisteredResponse { pub struct RegisteredResponse {
pub request_id: u64, pub request_id: u64,
pub reply_to: Recipient, pub reply_to: Recipient,
pub reply: RegistredData, pub reply: RegistredData,
} }
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] #[derive(Clone, Debug, Serialize, Deserialize)]
pub struct RemainingBandwidthResponse { pub struct RemainingBandwidthResponse {
pub request_id: u64, pub request_id: u64,
pub reply_to: Recipient, pub reply_to: Recipient,
pub reply: Option<RemainingBandwidthData>, pub reply: Option<RemainingBandwidthData>,
} }
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] #[derive(Clone, Debug, Serialize, Deserialize)]
pub struct TopUpBandwidthResponse { pub struct TopUpBandwidthResponse {
pub request_id: u64, pub request_id: u64,
pub reply_to: Recipient, pub reply_to: Recipient,
@@ -5,7 +5,7 @@ use nym_credentials_interface::CredentialSpendingData;
use nym_wireguard_types::PeerPublicKey; use nym_wireguard_types::PeerPublicKey;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] #[derive(Serialize, Deserialize, Debug, Clone)]
pub struct TopUpMessage { pub struct TopUpMessage {
/// Base64 encoded x25519 public key /// Base64 encoded x25519 public key
pub pub_key: PeerPublicKey, pub pub_key: PeerPublicKey,
@@ -17,7 +17,7 @@ use nym_validator_client::coconut::all_ecash_api_clients;
use nym_validator_client::nym_api::EpochId; use nym_validator_client::nym_api::EpochId;
use nym_validator_client::nyxd::contract_traits::EcashSigningClient; use nym_validator_client::nyxd::contract_traits::EcashSigningClient;
use nym_validator_client::nyxd::contract_traits::{DkgQueryClient, EcashQueryClient}; use nym_validator_client::nyxd::contract_traits::{DkgQueryClient, EcashQueryClient};
use nym_validator_client::nyxd::cosmwasm_client::ContractResponseData; use nym_validator_client::nyxd::cosmwasm_client::ToSingletonContractData;
use nym_validator_client::EcashApiClient; use nym_validator_client::EcashApiClient;
use rand::rngs::OsRng; use rand::rngs::OsRng;
+2 -1
View File
@@ -15,6 +15,7 @@ const-str = { workspace = true }
log = { workspace = true } log = { workspace = true }
pretty_env_logger = { workspace = true } pretty_env_logger = { workspace = true }
schemars = { workspace = true, features = ["preserve_order"], optional = true } schemars = { workspace = true, features = ["preserve_order"], optional = true }
semver.workspace = true
serde = { workspace = true, features = ["derive"] } serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true, optional = true } serde_json = { workspace = true, optional = true }
@@ -43,5 +44,5 @@ tracing = [
"tracing-opentelemetry", "tracing-opentelemetry",
"opentelemetry", "opentelemetry",
] ]
clap = ["dep:clap", "dep:clap_complete", "dep:clap_complete_fig"] clap = [ "dep:clap", "dep:clap_complete", "dep:clap_complete_fig" ]
models = [] models = []
+1
View File
@@ -3,6 +3,7 @@
pub mod build_information; pub mod build_information;
pub mod logging; pub mod logging;
pub mod version_checker;
#[cfg(feature = "clap")] #[cfg(feature = "clap")]
pub mod completions; 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"));
}
}
-1
View File
@@ -46,7 +46,6 @@ nym-sphinx = { path = "../nymsphinx" }
nym-statistics-common = { path = "../statistics" } nym-statistics-common = { path = "../statistics" }
nym-pemstore = { path = "../pemstore" } nym-pemstore = { path = "../pemstore" }
nym-topology = { path = "../topology", features = ["serializable"] } nym-topology = { path = "../topology", features = ["serializable"] }
nym-mixnet-client = { path = "../client-libs/mixnet-client", default-features = false }
nym-validator-client = { path = "../client-libs/validator-client", default-features = false } nym-validator-client = { path = "../client-libs/validator-client", default-features = false }
nym-task = { path = "../task" } nym-task = { path = "../task" }
nym-credentials-interface = { path = "../credentials-interface" } nym-credentials-interface = { path = "../credentials-interface" }
@@ -115,13 +115,8 @@ where
hardcoded_topology.get_gateways() hardcoded_topology.get_gateways()
} else { } else {
let mut rng = rand::thread_rng(); let mut rng = rand::thread_rng();
crate::init::helpers::current_gateways( crate::init::helpers::current_gateways(&mut rng, &core.client.nym_api_urls, user_agent)
&mut rng, .await?
&core.client.nym_api_urls,
user_agent,
core.debug.topology.minimum_gateway_performance,
)
.await?
}; };
// since we're registering with a brand new gateway, // since we're registering with a brand new gateway,
@@ -170,13 +170,8 @@ where
hardcoded_topology.get_gateways() hardcoded_topology.get_gateways()
} else { } else {
let mut rng = rand::thread_rng(); let mut rng = rand::thread_rng();
crate::init::helpers::current_gateways( crate::init::helpers::current_gateways(&mut rng, &core.client.nym_api_urls, user_agent)
&mut rng, .await?
&core.client.nym_api_urls,
user_agent,
core.debug.topology.minimum_gateway_performance,
)
.await?
}; };
let gateway_setup = GatewaySetup::New { let gateway_setup = GatewaySetup::New {
@@ -514,10 +514,15 @@ where
min_gateway_performance: config_topology.minimum_gateway_performance, min_gateway_performance: config_topology.minimum_gateway_performance,
}, },
nym_api_urls, nym_api_urls,
env!("CARGO_PKG_VERSION").to_string(),
user_agent, user_agent,
)), )),
config::TopologyStructure::GeoAware(group_by) => { config::TopologyStructure::GeoAware(group_by) => {
Box::new(GeoAwareTopologyProvider::new(nym_api_urls, group_by)) Box::new(GeoAwareTopologyProvider::new(
nym_api_urls,
env!("CARGO_PKG_VERSION").to_string(),
group_by,
))
} }
}) })
} }
@@ -14,7 +14,7 @@ use std::os::raw::c_int as RawFd;
use thiserror::Error; use thiserror::Error;
#[cfg(not(target_arch = "wasm32"))] #[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 // we need to type erase the error type since we can't have dynamic associated types alongside dynamic dispatch
#[derive(Debug, Error)] #[derive(Debug, Error)]
@@ -170,7 +170,7 @@ pub struct LocalGateway {
// 'sender' part // 'sender' part
/// Channel responsible for taking mix packets and forwarding them further into the further mixnet layers. /// 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 // 'receiver' part
packet_router_tx: Option<oneshot::Sender<PacketRouter>>, packet_router_tx: Option<oneshot::Sender<PacketRouter>>,
@@ -180,7 +180,7 @@ pub struct LocalGateway {
impl LocalGateway { impl LocalGateway {
pub fn new( pub fn new(
local_identity: identity::PublicKey, local_identity: identity::PublicKey,
packet_forwarder: nym_mixnet_client::forwarder::MixForwardingSender, packet_forwarder: mpsc::UnboundedSender<MixPacket>,
packet_router_tx: oneshot::Sender<PacketRouter>, packet_router_tx: oneshot::Sender<PacketRouter>,
) -> Self { ) -> Self {
LocalGateway { LocalGateway {
@@ -208,7 +208,8 @@ mod nonwasm_sealed {
impl GatewaySender for LocalGateway { impl GatewaySender for LocalGateway {
async fn send_mix_packet(&mut self, packet: MixPacket) -> Result<(), ErasedGatewayError> { async fn send_mix_packet(&mut self, packet: MixPacket) -> Result<(), ErasedGatewayError> {
self.packet_forwarder self.packet_forwarder
.forward_packet(packet) .unbounded_send(packet)
.map_err(|err| err.into_send_error())
.map_err(erase_err) .map_err(erase_err)
} }
} }
@@ -38,7 +38,7 @@ pub struct TopologyReadPermit<'a> {
permit: RwLockReadGuard<'a, Option<NymTopology>>, permit: RwLockReadGuard<'a, Option<NymTopology>>,
} }
impl Deref for TopologyReadPermit<'_> { impl<'a> Deref for TopologyReadPermit<'a> {
type Target = Option<NymTopology>; type Target = Option<NymTopology>;
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
@@ -85,10 +85,15 @@ fn check_layer_integrity(topology: NymTopology) -> Result<(), ()> {
pub struct GeoAwareTopologyProvider { pub struct GeoAwareTopologyProvider {
validator_client: nym_validator_client::client::NymApiClient, validator_client: nym_validator_client::client::NymApiClient,
filter_on: GroupBy, filter_on: GroupBy,
client_version: String,
} }
impl GeoAwareTopologyProvider { 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!( log::info!(
"Creating geo-aware topology provider with filter on {}", "Creating geo-aware topology provider with filter on {}",
filter_on filter_on
@@ -100,13 +105,14 @@ impl GeoAwareTopologyProvider {
nym_api_urls[0].clone(), nym_api_urls[0].clone(),
), ),
filter_on, filter_on,
client_version,
} }
} }
async fn get_topology(&self) -> Option<NymTopology> { async fn get_topology(&self) -> Option<NymTopology> {
let mixnodes = match self let mixnodes = match self
.validator_client .validator_client
.get_all_basic_active_mixing_assigned_nodes() .get_all_basic_active_mixing_assigned_nodes(Some(self.client_version.clone()))
.await .await
{ {
Err(err) => { Err(err) => {
@@ -118,7 +124,7 @@ impl GeoAwareTopologyProvider {
let gateways = match self let gateways = match self
.validator_client .validator_client
.get_all_basic_entry_assigned_nodes() .get_all_basic_entry_assigned_nodes(Some(self.client_version.clone()))
.await .await
{ {
Err(err) => { Err(err) => {
@@ -35,11 +35,18 @@ pub struct NymApiTopologyProvider {
validator_client: nym_validator_client::client::NymApiClient, validator_client: nym_validator_client::client::NymApiClient,
nym_api_urls: Vec<Url>, nym_api_urls: Vec<Url>,
client_version: String,
currently_used_api: usize, currently_used_api: usize,
} }
impl NymApiTopologyProvider { impl NymApiTopologyProvider {
pub fn new(config: Config, mut nym_api_urls: Vec<Url>, user_agent: Option<UserAgent>) -> Self { pub fn new(
config: Config,
mut nym_api_urls: Vec<Url>,
client_version: String,
user_agent: Option<UserAgent>,
) -> Self {
nym_api_urls.shuffle(&mut thread_rng()); nym_api_urls.shuffle(&mut thread_rng());
let validator_client = if let Some(user_agent) = user_agent { let validator_client = if let Some(user_agent) = user_agent {
@@ -55,6 +62,7 @@ impl NymApiTopologyProvider {
config, config,
validator_client, validator_client,
nym_api_urls, nym_api_urls,
client_version,
currently_used_api: 0, currently_used_api: 0,
} }
} }
@@ -91,7 +99,7 @@ impl NymApiTopologyProvider {
async fn get_current_compatible_topology(&mut self) -> Option<NymTopology> { async fn get_current_compatible_topology(&mut self) -> Option<NymTopology> {
let mixnodes = match self let mixnodes = match self
.validator_client .validator_client
.get_all_basic_active_mixing_assigned_nodes() .get_all_basic_active_mixing_assigned_nodes(Some(self.client_version.clone()))
.await .await
{ {
Err(err) => { Err(err) => {
@@ -103,7 +111,7 @@ impl NymApiTopologyProvider {
let gateways = match self let gateways = match self
.validator_client .validator_client
.get_all_basic_entry_assigned_nodes() .get_all_basic_entry_assigned_nodes(Some(self.client_version.clone()))
.await .await
{ {
Err(err) => { Err(err) => {
+26 -10
View File
@@ -7,7 +7,7 @@ use futures::{SinkExt, StreamExt};
use log::{debug, info, trace, warn}; use log::{debug, info, trace, warn};
use nym_crypto::asymmetric::identity; use nym_crypto::asymmetric::identity;
use nym_gateway_client::GatewayClient; use nym_gateway_client::GatewayClient;
use nym_topology::gateway; use nym_topology::{gateway, mix};
use nym_validator_client::client::IdentityKeyRef; use nym_validator_client::client::IdentityKeyRef;
use nym_validator_client::UserAgent; use nym_validator_client::UserAgent;
use rand::{seq::SliceRandom, Rng}; use rand::{seq::SliceRandom, Rng};
@@ -82,7 +82,6 @@ pub async fn current_gateways<R: Rng>(
rng: &mut R, rng: &mut R,
nym_apis: &[Url], nym_apis: &[Url],
user_agent: Option<UserAgent>, user_agent: Option<UserAgent>,
minimum_performance: u8,
) -> Result<Vec<gateway::LegacyNode>, ClientCoreError> { ) -> Result<Vec<gateway::LegacyNode>, ClientCoreError> {
let nym_api = nym_apis let nym_api = nym_apis
.choose(rng) .choose(rng)
@@ -95,27 +94,44 @@ pub async fn current_gateways<R: Rng>(
log::debug!("Fetching list of gateways from: {nym_api}"); log::debug!("Fetching list of gateways from: {nym_api}");
let gateways = client.get_all_basic_entry_assigned_nodes().await?; let gateways = client.get_all_basic_entry_assigned_nodes(None).await?;
info!("nym api reports {} gateways", gateways.len()); log::debug!("Found {} gateways", gateways.len());
log::trace!("Gateways: {:#?}", gateways); log::trace!("Gateways: {:#?}", gateways);
let valid_gateways = gateways let valid_gateways = gateways
.iter() .iter()
.filter(|g| g.performance.round_to_integer() >= minimum_performance)
.filter_map(|gateway| gateway.try_into().ok()) .filter_map(|gateway| gateway.try_into().ok())
.collect::<Vec<gateway::LegacyNode>>(); .collect::<Vec<gateway::LegacyNode>>();
log::debug!("After checking validity: {}", valid_gateways.len()); log::debug!("After checking validity: {}", valid_gateways.len());
log::trace!("Valid gateways: {:#?}", valid_gateways); log::trace!("Valid gateways: {:#?}", valid_gateways);
log::info!( log::info!("nym-api reports {} valid gateways", valid_gateways.len());
"and {} after validity and performance filtering",
valid_gateways.len()
);
Ok(valid_gateways) 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"))] #[cfg(not(target_arch = "wasm32"))]
async fn connect(endpoint: &str) -> Result<WsConn, ClientCoreError> { async fn connect(endpoint: &str) -> Result<WsConn, ClientCoreError> {
match tokio::time::timeout(CONN_TIMEOUT, connect_async(endpoint)).await { match tokio::time::timeout(CONN_TIMEOUT, connect_async(endpoint)).await {
@@ -87,10 +87,8 @@ impl ClientBandwidth {
if remaining < 0 { if remaining < 0 {
tracing::warn!("OUT OF BANDWIDTH. remaining: {remaining_bi2}"); tracing::warn!("OUT OF BANDWIDTH. remaining: {remaining_bi2}");
} else if remaining < 1_000_000 {
tracing::info!("remaining bandwidth: {remaining_bi2}");
} else { } else {
tracing::debug!("remaining bandwidth: {remaining_bi2}"); tracing::info!("remaining bandwidth: {remaining_bi2}");
} }
self.inner self.inner
@@ -139,10 +139,6 @@ impl<C, St> GatewayClient<C, St> {
self.gateway_identity self.gateway_identity
} }
pub fn shared_key(&self) -> Option<Arc<SharedGatewayKey>> {
self.shared_key.clone()
}
pub fn ws_fd(&self) -> Option<RawFd> { pub fn ws_fd(&self) -> Option<RawFd> {
match &self.connection { match &self.connection {
SocketState::Available(conn) => ws_fd(conn.as_ref()), SocketState::Available(conn) => ws_fd(conn.as_ref()),
@@ -412,7 +408,7 @@ impl<C, St> GatewayClient<C, St> {
} }
Some(_) => { 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(()) Ok(())
} }
} }
@@ -996,6 +992,24 @@ impl<C, St> GatewayClient<C, St> {
} }
Ok(()) 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 // type alias for an ease of use
@@ -46,8 +46,7 @@ pub(crate) fn ws_fd(_conn: &WsConn) -> Option<RawFd> {
#[cfg(unix)] #[cfg(unix)]
match _conn.get_ref() { match _conn.get_ref() {
MaybeTlsStream::Plain(stream) => Some(stream.as_raw_fd()), MaybeTlsStream::Plain(stream) => Some(stream.as_raw_fd()),
MaybeTlsStream::Rustls(tls_stream) => Some(tls_stream.as_raw_fd()), &_ => None,
_ => None,
} }
#[cfg(not(unix))] #[cfg(not(unix))]
None 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 { let return_res = match ret {
Err(err) => self.stream_return.send(Err(err)), Err(err) => self.stream_return.send(Err(err)),
Ok(_) => { Ok(_) => {
+4 -8
View File
@@ -9,14 +9,10 @@ license.workspace = true
[dependencies] [dependencies]
futures = { workspace = true } futures = { workspace = true }
tracing = { workspace = true } log = { workspace = true }
tokio = { workspace = true, features = ["time"] } tokio = { workspace = true, features = ["time", "net", "rt"] }
tokio-util = { workspace = true, features = ["codec"], optional = true } tokio-util = { workspace = true, features = ["codec"] }
# internal # internal
nym-sphinx = { path = "../../nymsphinx" } nym-sphinx = { path = "../../nymsphinx" }
nym-task = { path = "../../task", optional = true } nym-task = { path = "../../task" }
[features]
default = ["client"]
client = ["tokio-util", "nym-task", "tokio/net", "tokio/rt"]
@@ -3,6 +3,7 @@
use futures::channel::mpsc; use futures::channel::mpsc;
use futures::StreamExt; use futures::StreamExt;
use log::*;
use nym_sphinx::addressing::nodes::NymNodeRoutingAddress; use nym_sphinx::addressing::nodes::NymNodeRoutingAddress;
use nym_sphinx::framing::codec::NymCodec; use nym_sphinx::framing::codec::NymCodec;
use nym_sphinx::framing::packet::FramedNymPacket; use nym_sphinx::framing::packet::FramedNymPacket;
@@ -17,14 +18,13 @@ use std::time::Duration;
use tokio::net::TcpStream; use tokio::net::TcpStream;
use tokio::time::sleep; use tokio::time::sleep;
use tokio_util::codec::Framed; use tokio_util::codec::Framed;
use tracing::*;
#[derive(Clone, Copy)]
pub struct Config { pub struct Config {
initial_reconnection_backoff: Duration, initial_reconnection_backoff: Duration,
maximum_reconnection_backoff: Duration, maximum_reconnection_backoff: Duration,
initial_connection_timeout: Duration, initial_connection_timeout: Duration,
maximum_connection_buffer_size: usize, maximum_connection_buffer_size: usize,
use_legacy_version: bool,
} }
impl Config { impl Config {
@@ -33,12 +33,14 @@ impl Config {
maximum_reconnection_backoff: Duration, maximum_reconnection_backoff: Duration,
initial_connection_timeout: Duration, initial_connection_timeout: Duration,
maximum_connection_buffer_size: usize, maximum_connection_buffer_size: usize,
use_legacy_version: bool,
) -> Self { ) -> Self {
Config { Config {
initial_reconnection_backoff, initial_reconnection_backoff,
maximum_reconnection_backoff, maximum_reconnection_backoff,
initial_connection_timeout, initial_connection_timeout,
maximum_connection_buffer_size, maximum_connection_buffer_size,
use_legacy_version,
} }
} }
} }
@@ -198,8 +200,9 @@ impl SendWithoutResponse for Client {
packet: NymPacket, packet: NymPacket,
packet_type: PacketType, packet_type: PacketType,
) -> io::Result<()> { ) -> io::Result<()> {
trace!("Sending packet to {address:?}"); trace!("Sending packet to {:?}", address);
let framed_packet = FramedNymPacket::new(packet, packet_type); 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 Some(sender) = self.conn_new.get_mut(&address) {
if let Err(err) = sender.channel.try_send(framed_packet) { if let Err(err) = sender.channel.try_send(framed_packet) {
@@ -257,6 +260,7 @@ mod tests {
maximum_reconnection_backoff: Duration::from_millis(300_000), maximum_reconnection_backoff: Duration::from_millis(300_000),
initial_connection_timeout: Duration::from_millis(1_500), initial_connection_timeout: Duration::from_millis(1_500),
maximum_connection_buffer_size: 128, maximum_connection_buffer_size: 128,
use_legacy_version: false,
}) })
} }
@@ -1,72 +1,77 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net> // Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
use crate::client::{Client, Config, SendWithoutResponse};
use futures::channel::mpsc; use futures::channel::mpsc;
use futures::channel::mpsc::SendError; use futures::StreamExt;
use log::*;
use nym_sphinx::forwarding::packet::MixPacket; use nym_sphinx::forwarding::packet::MixPacket;
use tokio::time::Instant; use std::time::Duration;
pub fn mix_forwarding_channels() -> (MixForwardingSender, MixForwardingReceiver) { pub type MixForwardingSender = mpsc::UnboundedSender<MixPacket>;
let (tx, rx) = mpsc::unbounded(); type MixForwardingReceiver = mpsc::UnboundedReceiver<MixPacket>;
(tx.into(), rx)
/// 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)] impl PacketForwarder {
pub struct MixForwardingSender(mpsc::UnboundedSender<PacketToForward>); 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 { let (packet_sender, packet_receiver) = mpsc::unbounded();
fn from(tx: mpsc::UnboundedSender<PacketToForward>) -> Self {
MixForwardingSender(tx)
}
}
impl MixForwardingSender { (
pub fn forward_packet(&self, packet: impl Into<PacketToForward>) -> Result<(), SendError> { PacketForwarder {
self.0 mixnet_client: Client::new(client_config),
.unbounded_send(packet.into()) packet_receiver,
.map_err(|err| err.into_send_error()) shutdown,
},
packet_sender,
)
} }
#[allow(clippy::len_without_is_empty)] pub async fn run(&mut self) {
pub fn len(&self) -> usize { while !self.shutdown.is_shutdown() {
self.0.len() 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 { if let Err(err) =
pub packet: MixPacket, self.mixnet_client
pub forward_delay_target: Option<Instant>, .send_without_response(next_hop, packet, packet_type)
} {
debug!("failed to forward the packet - {err}")
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,
} }
} }
pub fn new_no_delay(packet: MixPacket) -> Self {
Self::new(packet, None)
}
} }
@@ -1,9 +1,7 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net> // Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
#[cfg(feature = "client")]
pub mod client; pub mod client;
pub mod forwarder; pub mod forwarder;
#[cfg(feature = "client")]
pub use client::{Client, Config, SendWithoutResponse}; pub use client::{Client, Config, SendWithoutResponse};
@@ -19,8 +19,8 @@ use nym_api_requests::ecash::{
PartialExpirationDateSignatureResponse, VerificationKeyResponse, PartialExpirationDateSignatureResponse, VerificationKeyResponse,
}; };
use nym_api_requests::models::{ use nym_api_requests::models::{
ApiHealthResponse, GatewayBondAnnotated, GatewayCoreStatusResponse, MixnodeCoreStatusResponse, ApiHealthResponse, GatewayCoreStatusResponse, MixnodeCoreStatusResponse, MixnodeStatusResponse,
MixnodeStatusResponse, NymNodeDescription, RewardEstimationResponse, StakeSaturationResponse, NymNodeDescription, RewardEstimationResponse, StakeSaturationResponse,
}; };
use nym_api_requests::models::{LegacyDescribedGateway, MixNodeBondAnnotated}; use nym_api_requests::models::{LegacyDescribedGateway, MixNodeBondAnnotated};
use nym_api_requests::nym_nodes::SkimmedNode; use nym_api_requests::nym_nodes::SkimmedNode;
@@ -257,13 +257,6 @@ impl<C, S> Client<C, S> {
Ok(self.nym_api.get_gateways().await?) 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... // TODO: combine with NymApiClient...
pub async fn get_all_cached_described_nodes( pub async fn get_all_cached_described_nodes(
&self, &self,
@@ -358,19 +351,34 @@ impl NymApiClient {
} }
#[deprecated(note = "use get_all_basic_active_mixing_assigned_nodes instead")] #[deprecated(note = "use get_all_basic_active_mixing_assigned_nodes instead")]
pub async fn get_basic_mixnodes(&self) -> Result<Vec<SkimmedNode>, ValidatorClientError> { pub async fn get_basic_mixnodes(
Ok(self.nym_api.get_basic_mixnodes().await?.nodes) &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")] #[deprecated(note = "use get_all_basic_entry_assigned_nodes instead")]
pub async fn get_basic_gateways(&self) -> Result<Vec<SkimmedNode>, ValidatorClientError> { pub async fn get_basic_gateways(
Ok(self.nym_api.get_basic_gateways().await?.nodes) &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 /// retrieve basic information for nodes are capable of operating as an entry gateway
/// this includes legacy gateways and nym-nodes /// this includes legacy gateways and nym-nodes
pub async fn get_all_basic_entry_assigned_nodes( pub async fn get_all_basic_entry_assigned_nodes(
&self, &self,
semver_compatibility: Option<String>,
) -> Result<Vec<SkimmedNode>, ValidatorClientError> { ) -> Result<Vec<SkimmedNode>, ValidatorClientError> {
// TODO: deal with paging in macro or some helper function or something, because it's the same pattern everywhere // 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 page = 0;
@@ -379,7 +387,12 @@ impl NymApiClient {
loop { loop {
let mut res = self let mut res = self
.nym_api .nym_api
.get_basic_entry_assigned_nodes(false, Some(page), None) .get_basic_entry_assigned_nodes(
semver_compatibility.clone(),
false,
Some(page),
None,
)
.await?; .await?;
nodes.append(&mut res.nodes.data); nodes.append(&mut res.nodes.data);
@@ -397,6 +410,7 @@ impl NymApiClient {
/// this includes legacy mixnodes and nym-nodes /// this includes legacy mixnodes and nym-nodes
pub async fn get_all_basic_active_mixing_assigned_nodes( pub async fn get_all_basic_active_mixing_assigned_nodes(
&self, &self,
semver_compatibility: Option<String>,
) -> Result<Vec<SkimmedNode>, ValidatorClientError> { ) -> Result<Vec<SkimmedNode>, ValidatorClientError> {
// TODO: deal with paging in macro or some helper function or something, because it's the same pattern everywhere // 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 page = 0;
@@ -405,7 +419,12 @@ impl NymApiClient {
loop { loop {
let mut res = self let mut res = self
.nym_api .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?; .await?;
nodes.append(&mut res.nodes.data); nodes.append(&mut res.nodes.data);
@@ -423,6 +442,7 @@ impl NymApiClient {
/// this includes legacy mixnodes and nym-nodes /// this includes legacy mixnodes and nym-nodes
pub async fn get_all_basic_mixing_capable_nodes( pub async fn get_all_basic_mixing_capable_nodes(
&self, &self,
semver_compatibility: Option<String>,
) -> Result<Vec<SkimmedNode>, ValidatorClientError> { ) -> Result<Vec<SkimmedNode>, ValidatorClientError> {
// TODO: deal with paging in macro or some helper function or something, because it's the same pattern everywhere // 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 page = 0;
@@ -431,7 +451,12 @@ impl NymApiClient {
loop { loop {
let mut res = self let mut res = self
.nym_api .nym_api
.get_basic_mixing_capable_nodes(false, Some(page), None) .get_basic_mixing_capable_nodes(
semver_compatibility.clone(),
false,
Some(page),
None,
)
.await?; .await?;
nodes.append(&mut res.nodes.data); nodes.append(&mut res.nodes.data);
@@ -446,7 +471,10 @@ impl NymApiClient {
} }
/// retrieve basic information for all bonded nodes on the network /// 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 // 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 page = 0;
let mut nodes = Vec::new(); let mut nodes = Vec::new();
@@ -454,7 +482,7 @@ impl NymApiClient {
loop { loop {
let mut res = self let mut res = self
.nym_api .nym_api
.get_basic_nodes(false, Some(page), None) .get_basic_nodes(semver_compatibility.clone(), false, Some(page), None)
.await?; .await?;
nodes.append(&mut res.nodes.data); nodes.append(&mut res.nodes.data);
@@ -102,23 +102,6 @@ pub trait NymApiClientExt: ApiClient {
.await .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] #[deprecated]
#[instrument(level = "debug", skip(self))] #[instrument(level = "debug", skip(self))]
async fn get_mixnodes_detailed_unfiltered( async fn get_mixnodes_detailed_unfiltered(
@@ -205,7 +188,16 @@ pub trait NymApiClientExt: ApiClient {
#[deprecated] #[deprecated]
#[tracing::instrument(level = "debug", skip_all)] #[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( self.get_json(
&[ &[
routes::API_VERSION, routes::API_VERSION,
@@ -214,14 +206,23 @@ pub trait NymApiClientExt: ApiClient {
"mixnodes", "mixnodes",
"skimmed", "skimmed",
], ],
NO_PARAMS, &params,
) )
.await .await
} }
#[deprecated] #[deprecated]
#[instrument(level = "debug", skip(self))] #[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( self.get_json(
&[ &[
routes::API_VERSION, routes::API_VERSION,
@@ -230,7 +231,7 @@ pub trait NymApiClientExt: ApiClient {
"gateways", "gateways",
"skimmed", "skimmed",
], ],
NO_PARAMS, &params,
) )
.await .await
} }
@@ -240,12 +241,17 @@ pub trait NymApiClientExt: ApiClient {
#[instrument(level = "debug", skip(self))] #[instrument(level = "debug", skip(self))]
async fn get_basic_entry_assigned_nodes( async fn get_basic_entry_assigned_nodes(
&self, &self,
semver_compatibility: Option<String>,
no_legacy: bool, no_legacy: bool,
page: Option<u32>, page: Option<u32>,
per_page: Option<u32>, per_page: Option<u32>,
) -> Result<PaginatedCachedNodesResponse<SkimmedNode>, NymAPIError> { ) -> Result<PaginatedCachedNodesResponse<SkimmedNode>, NymAPIError> {
let mut params = Vec::new(); let mut params = Vec::new();
if let Some(arg) = &semver_compatibility {
params.push(("semver_compatibility", arg.clone()))
}
if no_legacy { if no_legacy {
params.push(("no_legacy", "true".to_string())) params.push(("no_legacy", "true".to_string()))
} }
@@ -277,12 +283,17 @@ pub trait NymApiClientExt: ApiClient {
#[instrument(level = "debug", skip(self))] #[instrument(level = "debug", skip(self))]
async fn get_basic_active_mixing_assigned_nodes( async fn get_basic_active_mixing_assigned_nodes(
&self, &self,
semver_compatibility: Option<String>,
no_legacy: bool, no_legacy: bool,
page: Option<u32>, page: Option<u32>,
per_page: Option<u32>, per_page: Option<u32>,
) -> Result<PaginatedCachedNodesResponse<SkimmedNode>, NymAPIError> { ) -> Result<PaginatedCachedNodesResponse<SkimmedNode>, NymAPIError> {
let mut params = Vec::new(); let mut params = Vec::new();
if let Some(arg) = &semver_compatibility {
params.push(("semver_compatibility", arg.clone()))
}
if no_legacy { if no_legacy {
params.push(("no_legacy", "true".to_string())) params.push(("no_legacy", "true".to_string()))
} }
@@ -314,12 +325,17 @@ pub trait NymApiClientExt: ApiClient {
#[instrument(level = "debug", skip(self))] #[instrument(level = "debug", skip(self))]
async fn get_basic_mixing_capable_nodes( async fn get_basic_mixing_capable_nodes(
&self, &self,
semver_compatibility: Option<String>,
no_legacy: bool, no_legacy: bool,
page: Option<u32>, page: Option<u32>,
per_page: Option<u32>, per_page: Option<u32>,
) -> Result<PaginatedCachedNodesResponse<SkimmedNode>, NymAPIError> { ) -> Result<PaginatedCachedNodesResponse<SkimmedNode>, NymAPIError> {
let mut params = Vec::new(); let mut params = Vec::new();
if let Some(arg) = &semver_compatibility {
params.push(("semver_compatibility", arg.clone()))
}
if no_legacy { if no_legacy {
params.push(("no_legacy", "true".to_string())) params.push(("no_legacy", "true".to_string()))
} }
@@ -349,12 +365,17 @@ pub trait NymApiClientExt: ApiClient {
#[instrument(level = "debug", skip(self))] #[instrument(level = "debug", skip(self))]
async fn get_basic_nodes( async fn get_basic_nodes(
&self, &self,
semver_compatibility: Option<String>,
no_legacy: bool, no_legacy: bool,
page: Option<u32>, page: Option<u32>,
per_page: Option<u32>, per_page: Option<u32>,
) -> Result<PaginatedCachedNodesResponse<SkimmedNode>, NymAPIError> { ) -> Result<PaginatedCachedNodesResponse<SkimmedNode>, NymAPIError> {
let mut params = Vec::new(); let mut params = Vec::new();
if let Some(arg) = &semver_compatibility {
params.push(("semver_compatibility", arg.clone()))
}
if no_legacy { if no_legacy {
params.push(("no_legacy", "true".to_string())) params.push(("no_legacy", "true".to_string()))
} }
@@ -32,7 +32,7 @@ impl Div<GasPrice> for Coin {
} }
} }
impl Div<GasPrice> for &Coin { impl<'a> Div<GasPrice> for &'a Coin {
type Output = Gas; type Output = Gas;
fn div(self, rhs: GasPrice) -> Self::Output { fn div(self, rhs: GasPrice) -> Self::Output {
@@ -26,11 +26,10 @@ use nym_mixnet_contract_common::{
reward_params::{Performance, RewardingParams}, reward_params::{Performance, RewardingParams},
rewarding::{EstimatedCurrentEpochRewardResponse, PendingRewardResponse}, rewarding::{EstimatedCurrentEpochRewardResponse, PendingRewardResponse},
ContractBuildInformation, ContractState, ContractStateParams, CurrentIntervalResponse, ContractBuildInformation, ContractState, ContractStateParams, CurrentIntervalResponse,
CurrentNymNodeVersionResponse, Delegation, EpochEventId, EpochStatus, GatewayBond, Delegation, EpochEventId, EpochStatus, GatewayBond, GatewayBondResponse,
GatewayBondResponse, GatewayOwnershipResponse, HistoricalNymNodeVersionEntry, IdentityKey, GatewayOwnershipResponse, IdentityKey, IdentityKeyRef, IntervalEventId, MixNodeBond,
IdentityKeyRef, IntervalEventId, MixNodeBond, MixNodeDetails, MixOwnershipResponse, MixNodeDetails, MixOwnershipResponse, MixnodeDetailsByIdentityResponse, MixnodeDetailsResponse,
MixnodeDetailsByIdentityResponse, MixnodeDetailsResponse, NodeId, NodeId, NumberOfPendingEventsResponse, NymNodeBond, NymNodeDetails,
NumberOfPendingEventsResponse, NymNodeBond, NymNodeDetails, NymNodeVersionHistoryResponse,
PagedAllDelegationsResponse, PagedDelegatorDelegationsResponse, PagedGatewayResponse, PagedAllDelegationsResponse, PagedDelegatorDelegationsResponse, PagedGatewayResponse,
PagedMixnodeBondsResponse, PagedNodeDelegationsResponse, PendingEpochEvent, PagedMixnodeBondsResponse, PagedNodeDelegationsResponse, PendingEpochEvent,
PendingEpochEventResponse, PendingEpochEventsResponse, PendingIntervalEvent, PendingEpochEventResponse, PendingEpochEventsResponse, PendingIntervalEvent,
@@ -72,22 +71,6 @@ pub trait MixnetQueryClient {
.await .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> { async fn get_mixnet_contract_state(&self) -> Result<ContractState, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetState {}) self.query_mixnet_contract(MixnetQueryMsg::GetState {})
.await .await
@@ -655,12 +638,6 @@ pub trait PagedMixnetQueryClient: MixnetQueryClient {
) -> Result<Vec<PendingIntervalEvent>, NyxdError> { ) -> Result<Vec<PendingIntervalEvent>, NyxdError> {
collect_paged!(self, get_pending_interval_events_paged, events) 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] #[async_trait]
@@ -747,7 +724,6 @@ where
mod tests { mod tests {
use super::*; use super::*;
use crate::nyxd::contract_traits::tests::IgnoreValue; 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 // it's enough that this compiles and clippy is happy about it
#[allow(dead_code)] #[allow(dead_code)]
@@ -948,10 +924,6 @@ mod tests {
MixnetQueryMsg::GetRewardedSetMetadata {} => { MixnetQueryMsg::GetRewardedSetMetadata {} => {
client.get_rewarded_set_metadata().ignore() 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(),
} }
} }
} }
@@ -13,44 +13,6 @@ use tracing::error;
pub use cosmrs::abci::MsgResponse; pub use cosmrs::abci::MsgResponse;
pub fn parse_singleton_u32_from_contract_response(b: Vec<u8>) -> Result<u32, NyxdError> {
if b.len() != 4 {
return Err(NyxdError::MalformedResponseData {
got: b.len(),
expected: 4,
});
}
Ok(u32::from_be_bytes([b[0], b[1], b[2], b[3]]))
}
pub fn parse_singleton_u64_from_contract_response(b: Vec<u8>) -> Result<u64, NyxdError> {
if b.len() != 8 {
return Err(NyxdError::MalformedResponseData {
got: b.len(),
expected: 8,
});
}
Ok(u64::from_be_bytes([
b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7],
]))
}
#[derive(Debug, Clone)]
pub struct ParsedContractResponse {
pub message_index: usize,
pub response: Vec<u8>,
}
impl ParsedContractResponse {
pub fn parse_singleton_u32_contract_data(self) -> Result<u32, NyxdError> {
parse_singleton_u32_from_contract_response(self.response)
}
pub fn parse_singleton_u64_contract_data(self) -> Result<u64, NyxdError> {
parse_singleton_u64_from_contract_response(self.response)
}
}
pub fn parse_msg_responses(data: Bytes) -> Vec<MsgResponse> { pub fn parse_msg_responses(data: Bytes) -> Vec<MsgResponse> {
// it seems that currently, on wasmd 0.43 + tendermint-rs 0.37 + cosmrs 0.17.0-pre // it seems that currently, on wasmd 0.43 + tendermint-rs 0.37 + cosmrs 0.17.0-pre
// the data is left in undecoded base64 form, but I'd imagine this might change so if the decoding fails, // the data is left in undecoded base64 form, but I'd imagine this might change so if the decoding fails,
@@ -72,25 +34,35 @@ pub fn parse_msg_responses(data: Bytes) -> Vec<MsgResponse> {
} }
// requires there's a single response message // requires there's a single response message
pub trait ContractResponseData: Sized { pub trait ToSingletonContractData: Sized {
fn parse_singleton_u32_contract_data(&self) -> Result<u32, NyxdError> { fn parse_singleton_u32_contract_data(&self) -> Result<u32, NyxdError> {
let b = self.to_singleton_contract_data()?; let b = self.to_singleton_contract_data()?;
parse_singleton_u32_from_contract_response(b) if b.len() != 4 {
return Err(NyxdError::MalformedResponseData {
got: b.len(),
expected: 4,
});
}
Ok(u32::from_be_bytes([b[0], b[1], b[2], b[3]]))
} }
fn parse_singleton_u64_contract_data(&self) -> Result<u64, NyxdError> { fn parse_singleton_u64_contract_data(&self) -> Result<u64, NyxdError> {
let b = self.to_singleton_contract_data()?; let b = self.to_singleton_contract_data()?;
parse_singleton_u64_from_contract_response(b) if b.len() != 8 {
return Err(NyxdError::MalformedResponseData {
got: b.len(),
expected: 8,
});
}
Ok(u64::from_be_bytes([
b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7],
]))
} }
fn to_singleton_contract_data(&self) -> Result<Vec<u8>, NyxdError>; fn to_singleton_contract_data(&self) -> Result<Vec<u8>, NyxdError>;
fn to_unchecked_contract_data(&self) -> Result<Vec<Vec<u8>>, NyxdError>;
fn to_contract_data(&self) -> Result<Vec<ParsedContractResponse>, NyxdError>;
} }
impl ContractResponseData for ExecuteResult { impl ToSingletonContractData for ExecuteResult {
fn to_singleton_contract_data(&self) -> Result<Vec<u8>, NyxdError> { fn to_singleton_contract_data(&self) -> Result<Vec<u8>, NyxdError> {
if self.msg_responses.len() != 1 { if self.msg_responses.len() != 1 {
return Err(NyxdError::UnexpectedNumberOfMsgResponses { return Err(NyxdError::UnexpectedNumberOfMsgResponses {
@@ -100,30 +72,6 @@ impl ContractResponseData for ExecuteResult {
self.msg_responses[0].to_contract_response_data() self.msg_responses[0].to_contract_response_data()
} }
fn to_unchecked_contract_data(&self) -> Result<Vec<Vec<u8>>, NyxdError> {
self.msg_responses
.iter()
.map(ToContractResponseData::to_contract_response_data)
.collect()
}
fn to_contract_data(&self) -> Result<Vec<ParsedContractResponse>, NyxdError> {
let mut response = Vec::new();
for (message_index, msg) in self.msg_responses.iter().enumerate() {
// unfortunately `Name` trait has not been derived for `MsgExecuteContractResponse`,
// so we have to make an explicit string comparison instead
if msg.type_url == "/cosmwasm.wasm.v1.MsgExecuteContractResponse" {
response.push(ParsedContractResponse {
message_index,
response: msg.to_contract_response_data()?,
})
}
}
Ok(response)
}
} }
pub trait ToContractResponseData: Sized { pub trait ToContractResponseData: Sized {
@@ -23,7 +23,7 @@ use tendermint_rpc::endpoint::*;
use tendermint_rpc::query::Query; use tendermint_rpc::query::Query;
use tendermint_rpc::{Error as TendermintRpcError, Order, Paging, SimpleRequest}; use tendermint_rpc::{Error as TendermintRpcError, Order, Paging, SimpleRequest};
pub use helpers::{ContractResponseData, ToContractResponseData}; pub use helpers::{ToContractResponseData, ToSingletonContractData};
#[cfg(feature = "http-client")] #[cfg(feature = "http-client")]
use crate::http_client; use crate::http_client;
@@ -22,7 +22,7 @@ pub struct GasPrice {
pub denom: String, pub denom: String,
} }
impl Mul<Gas> for &GasPrice { impl<'a> Mul<Gas> for &'a GasPrice {
type Output = Coin; type Output = Coin;
fn mul(self, gas_limit: Gas) -> Self::Output { fn mul(self, gas_limit: Gas) -> Self::Output {
@@ -13,7 +13,6 @@ cosmwasm-std = { workspace = true }
cosmwasm-schema = { workspace = true } cosmwasm-schema = { workspace = true }
cw-storage-plus = { workspace = true } cw-storage-plus = { workspace = true }
schemars = { workspace = true } schemars = { workspace = true }
utoipa = { workspace = true, optional = true }
serde = { workspace = true, features = ["derive"] } serde = { workspace = true, features = ["derive"] }
thiserror = { workspace = true } thiserror = { workspace = true }
@@ -24,5 +23,4 @@ serde_json = { workspace = true }
vergen = { workspace = true, features = ["build", "git", "gitcl", "rustc", "cargo"] } vergen = { workspace = true, features = ["build", "git", "gitcl", "rustc", "cargo"] }
[features] [features]
naive_float = [] naive_float = []
utoipa = ["dep:utoipa"]
@@ -221,7 +221,6 @@ fn default_unknown() -> String {
// TODO: there's no reason this couldn't be used for proper binaries, but in that case // TODO: there's no reason this couldn't be used for proper binaries, but in that case
// perhaps the struct should get renamed and moved to a "more" common crate // perhaps the struct should get renamed and moved to a "more" common crate
#[cw_serde] #[cw_serde]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
pub struct ContractBuildInformation { pub struct ContractBuildInformation {
/// Provides the name of the binary, i.e. the content of `CARGO_PKG_NAME` environmental variable. /// Provides the name of the binary, i.e. the content of `CARGO_PKG_NAME` environmental variable.
#[serde(default = "default_unknown")] #[serde(default = "default_unknown")]
@@ -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, };
@@ -1,12 +0,0 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { IntervalRewardParams } from "./IntervalRewardParams";
import type { RewardedSetParams } from "./RewardedSetParams";
/**
* Parameters used for reward calculation.
*/
export type RewardingParams = {
/**
* Parameters that should remain unchanged throughout an interval.
*/
interval: IntervalRewardParams, rewarded_set: RewardedSetParams, };
@@ -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 Role = "EntryGateway" | "Layer1" | "Layer2" | "Layer3" | "ExitGateway" | "Standby";
@@ -1,23 +0,0 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
/**
* Basic information of a node that used to be part of the mix network but has already unbonded.
*/
export type UnbondedMixnode = {
/**
* Base58-encoded ed25519 EdDSA public key.
*/
identity_key: string,
/**
* Address of the owner of this mixnode.
*/
owner: string,
/**
* Entity who bonded this mixnode on behalf of the owner.
* If exists, it's most likely the address of the vesting contract.
*/
proxy: string | null,
/**
* Block height at which this mixnode has unbonded.
*/
unbonding_height: number, };
@@ -1,673 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use cosmwasm_schema::cw_serde;
use cosmwasm_std::Decimal;
use std::cmp::Ordering;
use std::ops::{Add, Sub};
#[cw_serde]
pub struct HistoricalNymNodeVersion {
/// Version of the nym node that is going to be used for determining the version score of a node.
/// note: value stored here is pre-validated `semver::Version`
pub semver: String,
/// Block height of when this version has been added to the contract
pub introduced_at_height: u64,
/// The absolute version difference as compared against the first version introduced into the contract.
pub difference_since_genesis: TotalVersionDifference,
}
impl HistoricalNymNodeVersion {
pub fn genesis(semver: String, height: u64) -> HistoricalNymNodeVersion {
HistoricalNymNodeVersion {
semver,
introduced_at_height: height,
difference_since_genesis: Default::default(),
}
}
// SAFETY: the value stored in the contract is always valid
// if you manually construct that struct with invalid value, it's on you.
#[allow(clippy::unwrap_used)]
pub fn semver_unchecked(&self) -> semver::Version {
self.semver.parse().unwrap()
}
/// Return [`TotalVersionDifference`] for a new release version that is going to be pushed right after this one
/// this function cannot be called against 2 arbitrary versions
#[inline]
pub fn cumulative_difference_since_genesis(
&self,
new_version: &semver::Version,
) -> TotalVersionDifference {
let self_semver = self.semver_unchecked();
let mut new_absolute = self.difference_since_genesis;
if new_version.major > self_semver.major {
new_absolute.major += (new_version.major - self_semver.major) as u32
} else if new_version.minor > self_semver.minor {
new_absolute.minor += (new_version.minor - self_semver.minor) as u32
} else if new_version.patch > self_semver.patch {
new_absolute.patch += (new_version.patch - self_semver.patch) as u32
} else if new_version.pre != self_semver.pre {
new_absolute.prerelease += 1
}
new_absolute
}
pub fn relative_difference(&self, other: &Self) -> TotalVersionDifference {
if self.difference_since_genesis > other.difference_since_genesis {
self.difference_since_genesis - other.difference_since_genesis
} else {
other.difference_since_genesis - self.difference_since_genesis
}
}
pub fn difference_against_legacy(
&self,
legacy_version: &semver::Version,
) -> TotalVersionDifference {
let current = self.semver_unchecked();
let major_diff = (current.major as i64 - legacy_version.major as i64).unsigned_abs() as u32;
let minor_diff = (current.minor as i64 - legacy_version.minor as i64).unsigned_abs() as u32;
let patch_diff = (current.patch as i64 - legacy_version.patch as i64).unsigned_abs() as u32;
let prerelease_diff = if current.pre == legacy_version.pre {
0
} else {
1
};
let mut diff = TotalVersionDifference::default();
// if there's a major increase, ignore minor and patch and treat it as 0
if major_diff != 0 {
diff.major += major_diff;
return diff;
}
// if there's a minor increase, ignore patch and treat is as 0
if minor_diff != 0 {
diff.minor += minor_diff;
return diff;
}
diff.patch = patch_diff;
diff.prerelease = prerelease_diff;
diff
}
}
#[cw_serde]
#[derive(Default, Copy, PartialOrd, Ord, Eq)]
pub struct TotalVersionDifference {
pub major: u32,
pub minor: u32,
pub patch: u32,
pub prerelease: u32,
}
impl Add for TotalVersionDifference {
type Output = TotalVersionDifference;
fn add(self, rhs: TotalVersionDifference) -> Self::Output {
TotalVersionDifference {
major: self.major.add(rhs.major),
minor: self.minor.add(rhs.minor),
patch: self.patch.add(rhs.patch),
prerelease: self.prerelease.add(rhs.prerelease),
}
}
}
impl Sub for TotalVersionDifference {
type Output = TotalVersionDifference;
fn sub(self, rhs: TotalVersionDifference) -> Self::Output {
TotalVersionDifference {
major: self.major.saturating_sub(rhs.major),
minor: self.minor.saturating_sub(rhs.minor),
patch: self.patch.saturating_sub(rhs.patch),
prerelease: self.prerelease.saturating_sub(rhs.prerelease),
}
}
}
#[cw_serde]
pub struct HistoricalNymNodeVersionEntry {
/// The unique, ordered, id of this particular entry
pub id: u32,
/// Data associated with this particular version
pub version_information: HistoricalNymNodeVersion,
}
impl From<(u32, HistoricalNymNodeVersion)> for HistoricalNymNodeVersionEntry {
fn from((id, version_information): (u32, HistoricalNymNodeVersion)) -> Self {
HistoricalNymNodeVersionEntry {
id,
version_information,
}
}
}
impl PartialOrd for HistoricalNymNodeVersionEntry {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
// we only care about id for the purposes of ordering as they should have unique data
self.id.partial_cmp(&other.id)
}
}
#[cw_serde]
pub struct NymNodeVersionHistoryResponse {
pub history: Vec<HistoricalNymNodeVersionEntry>,
/// Field indicating paging information for the following queries if the caller wishes to get further entries.
pub start_next_after: Option<u32>,
}
#[cw_serde]
pub struct CurrentNymNodeVersionResponse {
pub version: Option<HistoricalNymNodeVersionEntry>,
}
#[cw_serde]
pub struct ConfigScoreParams {
/// Defines weights for calculating numbers of versions behind the current release.
pub version_weights: OutdatedVersionWeights,
/// Defines the parameters of the formula for calculating the version score
pub version_score_formula_params: VersionScoreFormulaParams,
}
/// Defines weights for calculating numbers of versions behind the current release.
#[cw_serde]
#[derive(Copy)]
pub struct OutdatedVersionWeights {
pub major: u32,
pub minor: u32,
pub patch: u32,
pub prerelease: u32,
}
fn is_one_semver_difference(this: &semver::Version, other: &semver::Version) -> bool {
let major_diff = (this.major as i64 - other.major as i64).unsigned_abs() as u32;
let minor_diff = (this.minor as i64 - other.minor as i64).unsigned_abs() as u32;
let patch_diff = (this.patch as i64 - other.patch as i64).unsigned_abs() as u32;
let prerelease_diff = if this.pre == other.pre { 0 } else { 1 };
if major_diff == 1 {
return true;
}
if major_diff == 0 && minor_diff == 1 {
return true;
}
if major_diff == 0 && minor_diff == 0 && patch_diff == 1 {
return true;
}
prerelease_diff == 1
}
impl OutdatedVersionWeights {
pub fn difference_to_versions_behind_factor(&self, diff: TotalVersionDifference) -> u32 {
diff.major * self.major
+ diff.minor * self.minor
+ diff.patch * self.patch
+ diff.prerelease * self.prerelease
}
// INVARIANT: release chain is sorted
// do NOT call this method directly from inside the contract. it's too inefficient
// it relies on some external caching.
pub fn versions_behind_factor(
&self,
node_version: &semver::Version,
release_chain: &[HistoricalNymNodeVersionEntry],
) -> u32 {
let Some(latest) = release_chain.last() else {
return 0;
};
let latest_semver = latest.version_information.semver_unchecked();
// if you're more recent than the latest, you get the benefit of the doubt, the release might have not yet been commited to the chain
// but only if you're only a single semver ahead, otherwise you get penalty equivalent of being major version behind for cheating
if node_version > &latest_semver {
return if is_one_semver_difference(node_version, &latest_semver) {
0
} else {
self.major
};
}
// find your position in the release chain, if we fail, we assume that the node comes from before the changes were introduced
// in which case we simply calculate the absolute difference between the genesis entry and add up the total difference
let version_diff = match release_chain
.iter()
.rfind(|h| &h.version_information.semver_unchecked() <= node_version)
{
Some(h) => {
// first chain entry that is smaller (or equal) to the provided node version
// now, calculate the difference to the genesis version and ultimately against the current head
let diff_since_genesis = if h.version_information.semver == node_version.to_string()
{
h.version_information.difference_since_genesis
} else {
h.version_information
.cumulative_difference_since_genesis(node_version)
};
latest.version_information.difference_since_genesis - diff_since_genesis
}
None => {
// SAFETY: since we managed to get 'last' entry, it means the release chain is not empty,
// so we must be able to obtain the first entry
#[allow(clippy::unwrap_used)]
let genesis = release_chain.first().unwrap();
let difference_from_genesis = genesis
.version_information
.difference_against_legacy(node_version);
difference_from_genesis + latest.version_information.difference_since_genesis
}
};
self.difference_to_versions_behind_factor(version_diff)
}
}
impl Default for OutdatedVersionWeights {
fn default() -> Self {
OutdatedVersionWeights {
major: 100,
minor: 10,
patch: 1,
prerelease: 1,
}
}
}
/// Given the formula of version_score = penalty ^ (versions_behind_factor ^ penalty_scaling)
/// define the relevant parameters
#[cw_serde]
#[derive(Copy)]
pub struct VersionScoreFormulaParams {
pub penalty: Decimal,
pub penalty_scaling: Decimal,
}
impl Default for VersionScoreFormulaParams {
fn default() -> Self {
#[allow(clippy::unwrap_used)]
VersionScoreFormulaParams {
penalty: "0.995".parse().unwrap(),
penalty_scaling: "1.65".parse().unwrap(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::ops::Deref;
// simple wrapper for tests
struct ReleaseChain {
inner: Vec<HistoricalNymNodeVersionEntry>,
}
impl Deref for ReleaseChain {
type Target = [HistoricalNymNodeVersionEntry];
fn deref(&self) -> &Self::Target {
self.inner.deref()
}
}
impl ReleaseChain {
fn new(initial: &str) -> Self {
ReleaseChain {
inner: vec![HistoricalNymNodeVersionEntry {
id: 0,
version_information: HistoricalNymNodeVersion {
semver: initial.to_string(),
introduced_at_height: 123,
difference_since_genesis: TotalVersionDifference::default(),
},
}],
}
}
fn with_release(mut self, raw: &str) -> Self {
self.push_new(raw);
self
}
fn push_new(&mut self, raw: &str) {
let latest = self.inner.last().unwrap();
let new_version: semver::Version = raw.parse().unwrap();
let new_absolute = latest
.version_information
.cumulative_difference_since_genesis(&new_version);
self.inner.push(HistoricalNymNodeVersionEntry {
id: latest.id + 1,
version_information: HistoricalNymNodeVersion {
semver: new_version.to_string(),
introduced_at_height: latest.version_information.introduced_at_height + 1,
difference_since_genesis: new_absolute,
},
})
}
}
#[test]
fn versions_behind_factor() {
// helper to compact the parsing
fn s(raw: &str) -> semver::Version {
raw.parse().unwrap()
}
let weights = OutdatedVersionWeights::default();
// no releases:
let res = weights.versions_behind_factor(&s("1.1.13"), &[]);
assert_eq!(0, res);
// ###############################
// single released version (1.1.13)
// ###############################
let mut release_chain = ReleaseChain::new("1.1.13");
// "legacy" versions
let res = weights.versions_behind_factor(&s("1.0.12"), &release_chain);
assert_eq!(10, res);
let res = weights.versions_behind_factor(&s("1.0.4"), &release_chain);
assert_eq!(10, res);
let res = weights.versions_behind_factor(&s("1.0.1"), &release_chain);
assert_eq!(10, res);
let res = weights.versions_behind_factor(&s("0.1.12"), &release_chain);
assert_eq!(100, res);
let res = weights.versions_behind_factor(&s("1.1.12"), &release_chain);
assert_eq!(1, res);
let res = weights.versions_behind_factor(&s("1.1.11"), &release_chain);
assert_eq!(2, res);
let res = weights.versions_behind_factor(&s("1.1.9"), &release_chain);
assert_eq!(4, res);
// current version
let res = weights.versions_behind_factor(&s("1.1.13"), &release_chain);
assert_eq!(0, res);
// "ahead" versions
let res = weights.versions_behind_factor(&s("1.1.14"), &release_chain);
assert_eq!(0, res);
let res = weights.versions_behind_factor(&s("1.2.0"), &release_chain);
assert_eq!(0, res);
let res = weights.versions_behind_factor(&s("2.0.0"), &release_chain);
assert_eq!(0, res);
// cheating ahead:
let res = weights.versions_behind_factor(&s("1.1.15"), &release_chain);
assert_eq!(100, res);
let res = weights.versions_behind_factor(&s("1.3.0"), &release_chain);
assert_eq!(100, res);
let res = weights.versions_behind_factor(&s("3.0.0"), &release_chain);
assert_eq!(100, res);
// ###############################
// small patch release chain (1.1.13 => 1.1.14 => 1.1.15 => 1.1.16)
// ###############################
release_chain.push_new("1.1.14");
release_chain.push_new("1.1.15");
release_chain.push_new("1.1.16");
// "legacy" versions
let res = weights.versions_behind_factor(&s("1.0.12"), &release_chain);
assert_eq!(13, res);
let res = weights.versions_behind_factor(&s("1.0.4"), &release_chain);
assert_eq!(13, res);
let res = weights.versions_behind_factor(&s("1.0.1"), &release_chain);
assert_eq!(13, res);
let res = weights.versions_behind_factor(&s("0.1.12"), &release_chain);
assert_eq!(103, res);
let res = weights.versions_behind_factor(&s("1.1.12"), &release_chain);
assert_eq!(4, res);
let res = weights.versions_behind_factor(&s("1.1.11"), &release_chain);
assert_eq!(5, res);
let res = weights.versions_behind_factor(&s("1.1.9"), &release_chain);
assert_eq!(7, res);
// current version
let res = weights.versions_behind_factor(&s("1.1.16"), &release_chain);
assert_eq!(0, res);
// present in the chain
let res = weights.versions_behind_factor(&s("1.1.15"), &release_chain);
assert_eq!(1, res);
let res = weights.versions_behind_factor(&s("1.1.14"), &release_chain);
assert_eq!(2, res);
let res = weights.versions_behind_factor(&s("1.1.13"), &release_chain);
assert_eq!(3, res);
// "ahead" versions
let res = weights.versions_behind_factor(&s("1.1.17"), &release_chain);
assert_eq!(0, res);
let res = weights.versions_behind_factor(&s("1.2.0"), &release_chain);
assert_eq!(0, res);
let res = weights.versions_behind_factor(&s("2.0.0"), &release_chain);
assert_eq!(0, res);
// cheating ahead:
let res = weights.versions_behind_factor(&s("1.1.18"), &release_chain);
assert_eq!(100, res);
let res = weights.versions_behind_factor(&s("1.3.0"), &release_chain);
assert_eq!(100, res);
let res = weights.versions_behind_factor(&s("3.0.0"), &release_chain);
assert_eq!(100, res);
// ###############################
// small minor release chain (1.2.0 => 1.3.0 => 1.4.0)
// ###############################
let release_chain = ReleaseChain::new("1.2.0")
.with_release("1.3.0")
.with_release("1.4.0");
// "legacy" versions
let res = weights.versions_behind_factor(&s("1.0.12"), &release_chain);
assert_eq!(40, res);
let res = weights.versions_behind_factor(&s("1.0.4"), &release_chain);
assert_eq!(40, res);
let res = weights.versions_behind_factor(&s("1.0.1"), &release_chain);
assert_eq!(40, res);
let res = weights.versions_behind_factor(&s("0.1.12"), &release_chain);
assert_eq!(120, res);
let res = weights.versions_behind_factor(&s("1.1.12"), &release_chain);
assert_eq!(30, res);
let res = weights.versions_behind_factor(&s("1.1.11"), &release_chain);
assert_eq!(30, res);
let res = weights.versions_behind_factor(&s("1.1.9"), &release_chain);
assert_eq!(30, res);
// current version
let res = weights.versions_behind_factor(&s("1.4.0"), &release_chain);
assert_eq!(0, res);
// present in the chain
let res = weights.versions_behind_factor(&s("1.2.0"), &release_chain);
assert_eq!(20, res);
let res = weights.versions_behind_factor(&s("1.3.0"), &release_chain);
assert_eq!(10, res);
// weird in between
let res = weights.versions_behind_factor(&s("1.2.1"), &release_chain);
assert_eq!(20, res);
let res = weights.versions_behind_factor(&s("1.3.3"), &release_chain);
assert_eq!(10, res);
// "ahead" versions
let res = weights.versions_behind_factor(&s("1.4.1"), &release_chain);
assert_eq!(0, res);
let res = weights.versions_behind_factor(&s("1.5.0"), &release_chain);
assert_eq!(0, res);
let res = weights.versions_behind_factor(&s("2.0.0"), &release_chain);
assert_eq!(0, res);
// cheating ahead:
let res = weights.versions_behind_factor(&s("1.4.2"), &release_chain);
assert_eq!(100, res);
let res = weights.versions_behind_factor(&s("1.6.0"), &release_chain);
assert_eq!(100, res);
let res = weights.versions_behind_factor(&s("3.0.0"), &release_chain);
assert_eq!(100, res);
// ###############################
// mixed release chain (1.1.13 => 1.2.0 => 1.2.1 => 1.3.0 => 1.3.1 => 1.3.2 => 1.4.0)
// ###############################
let release_chain = ReleaseChain::new("1.1.13")
.with_release("1.2.0")
.with_release("1.2.1")
.with_release("1.3.0")
.with_release("1.3.1-importantpre")
.with_release("1.3.1")
.with_release("1.3.2")
.with_release("1.4.0");
// "legacy" versions
let res = weights.versions_behind_factor(&s("1.0.12"), &release_chain);
assert_eq!(44, res);
let res = weights.versions_behind_factor(&s("1.0.4"), &release_chain);
assert_eq!(44, res);
let res = weights.versions_behind_factor(&s("1.0.1"), &release_chain);
assert_eq!(44, res);
let res = weights.versions_behind_factor(&s("0.1.12"), &release_chain);
assert_eq!(134, res);
let res = weights.versions_behind_factor(&s("1.1.12"), &release_chain);
assert_eq!(35, res);
let res = weights.versions_behind_factor(&s("1.1.11"), &release_chain);
assert_eq!(36, res);
let res = weights.versions_behind_factor(&s("1.1.9"), &release_chain);
assert_eq!(38, res);
// current version
let res = weights.versions_behind_factor(&s("1.4.0"), &release_chain);
assert_eq!(0, res);
// present in the chain
let res = weights.versions_behind_factor(&s("1.1.13"), &release_chain);
assert_eq!(34, res);
let res = weights.versions_behind_factor(&s("1.2.0"), &release_chain);
assert_eq!(24, res);
let res = weights.versions_behind_factor(&s("1.2.1"), &release_chain);
assert_eq!(23, res);
let res = weights.versions_behind_factor(&s("1.3.0"), &release_chain);
assert_eq!(13, res);
let res = weights.versions_behind_factor(&s("1.3.1-importantpre"), &release_chain);
assert_eq!(12, res);
let res = weights.versions_behind_factor(&s("1.3.1"), &release_chain);
assert_eq!(11, res);
let res = weights.versions_behind_factor(&s("1.3.2"), &release_chain);
assert_eq!(10, res);
// weird in between
let res = weights.versions_behind_factor(&s("1.2.3"), &release_chain);
assert_eq!(21, res);
let res = weights.versions_behind_factor(&s("1.3.69"), &release_chain);
assert_eq!(10, res);
// "ahead" versions
let res = weights.versions_behind_factor(&s("1.4.1"), &release_chain);
assert_eq!(0, res);
let res = weights.versions_behind_factor(&s("1.5.0"), &release_chain);
assert_eq!(0, res);
let res = weights.versions_behind_factor(&s("2.0.0"), &release_chain);
assert_eq!(0, res);
// cheating ahead:
let res = weights.versions_behind_factor(&s("1.4.2"), &release_chain);
assert_eq!(100, res);
let res = weights.versions_behind_factor(&s("1.6.0"), &release_chain);
assert_eq!(100, res);
let res = weights.versions_behind_factor(&s("3.0.0"), &release_chain);
assert_eq!(100, res);
// ###############################
// skipped patch chain (1.1.13 => 1.2.0 => 1.2.1 => 1.2.4 => [1.3.0])
// ###############################
let mut release_chain = ReleaseChain::new("1.1.13")
.with_release("1.2.0")
.with_release("1.2.1")
.with_release("1.2.4");
// current
let res = weights.versions_behind_factor(&s("1.2.4"), &release_chain);
assert_eq!(0, res);
// on 'skipped' version
let res = weights.versions_behind_factor(&s("1.2.2"), &release_chain);
assert_eq!(2, res);
// on version before the skip
let res = weights.versions_behind_factor(&s("1.2.1"), &release_chain);
assert_eq!(3, res);
release_chain.push_new("1.3.0");
// current
let res = weights.versions_behind_factor(&s("1.3.0"), &release_chain);
assert_eq!(0, res);
// on 'skipped' version
let res = weights.versions_behind_factor(&s("1.2.2"), &release_chain);
assert_eq!(12, res);
// on version before the skip
let res = weights.versions_behind_factor(&s("1.2.1"), &release_chain);
assert_eq!(13, res);
// ###############################
// skipped minor chain (1.1.13 => 1.2.0 => 1.2.1 => 1.4.0 => [1.5.0])
// ###############################
let mut release_chain = ReleaseChain::new("1.1.13")
.with_release("1.2.0")
.with_release("1.2.1")
.with_release("1.4.0");
// current
let res = weights.versions_behind_factor(&s("1.4.0"), &release_chain);
assert_eq!(0, res);
// on 'skipped' version
let res = weights.versions_behind_factor(&s("1.3.0"), &release_chain);
assert_eq!(10, res);
// on version before the skip
let res = weights.versions_behind_factor(&s("1.2.1"), &release_chain);
assert_eq!(20, res);
let res = weights.versions_behind_factor(&s("1.2.0"), &release_chain);
assert_eq!(21, res);
release_chain.push_new("1.5.0");
// current
let res = weights.versions_behind_factor(&s("1.5.0"), &release_chain);
assert_eq!(0, res);
let res = weights.versions_behind_factor(&s("1.4.0"), &release_chain);
assert_eq!(10, res);
// on 'skipped' version
let res = weights.versions_behind_factor(&s("1.3.0"), &release_chain);
assert_eq!(20, res);
// on version before the skip
let res = weights.versions_behind_factor(&s("1.2.1"), &release_chain);
assert_eq!(30, res);
let res = weights.versions_behind_factor(&s("1.2.0"), &release_chain);
assert_eq!(31, res);
}
}
@@ -275,9 +275,6 @@ pub enum MixnetContractError {
#[error("the provided nym-node version is not a valid semver. got: {provided}")] #[error("the provided nym-node version is not a valid semver. got: {provided}")]
InvalidNymNodeSemver { provided: String }, InvalidNymNodeSemver { provided: String },
#[error("the provided nym-node version is not greater than the current one. got: {provided}. current: {current}")]
NonIncreasingSemver { provided: String, current: String },
} }
impl MixnetContractError { impl MixnetContractError {
@@ -141,7 +141,6 @@ pub const NEW_INTERVAL_OPERATING_COST_RANGE_KEY: &str = "new_interval_operating_
pub const NEW_VERSION_WEIGHTS_RANGE_KEY: &str = "new_version_weights_range"; pub const NEW_VERSION_WEIGHTS_RANGE_KEY: &str = "new_version_weights_range";
pub const NEW_VERSION_SCORE_FORMULA_PARAMS_KEY: &str = "new_version_score_formula_params"; pub const NEW_VERSION_SCORE_FORMULA_PARAMS_KEY: &str = "new_version_score_formula_params";
pub const NYM_NODE_CURRENT_SEMVER_KEY: &str = "new_current_semver"; pub const NYM_NODE_CURRENT_SEMVER_KEY: &str = "new_current_semver";
pub const NYM_NODE_CURRENT_SEMVER_ID_KEY: &str = "new_current_semver_id";
pub const OLD_REWARDING_VALIDATOR_ADDRESS_KEY: &str = "old_rewarding_validator_address"; pub const OLD_REWARDING_VALIDATOR_ADDRESS_KEY: &str = "old_rewarding_validator_address";
pub const NEW_REWARDING_VALIDATOR_ADDRESS_KEY: &str = "new_rewarding_validator_address"; pub const NEW_REWARDING_VALIDATOR_ADDRESS_KEY: &str = "new_rewarding_validator_address";
@@ -482,6 +481,12 @@ pub fn new_settings_update_event(update: &ContractStateParamsUpdate) -> Event {
// check for config score params updates // check for config score params updates
if let Some(config_score_update) = &update.config_score_params { if let Some(config_score_update) = &update.config_score_params {
if let Some(current_nym_node_semver) = &config_score_update.current_nym_node_semver {
event.attributes.push(attr(
NYM_NODE_CURRENT_SEMVER_KEY,
current_nym_node_semver.to_string(),
))
}
if let Some(version_weights) = &config_score_update.version_weights { if let Some(version_weights) = &config_score_update.version_weights {
event.attributes.push(attr( event.attributes.push(attr(
NEW_VERSION_WEIGHTS_RANGE_KEY, NEW_VERSION_WEIGHTS_RANGE_KEY,
@@ -501,10 +506,9 @@ pub fn new_settings_update_event(update: &ContractStateParamsUpdate) -> Event {
event event
} }
pub fn new_update_nym_node_semver_event(new_version: &str, new_id: u32) -> Event { pub fn new_update_nym_node_semver_event(new_version: &str) -> Event {
Event::new(MixnetEventType::NymNodeSemverUpdate) Event::new(MixnetEventType::NymNodeSemverUpdate)
.add_attribute(NYM_NODE_CURRENT_SEMVER_KEY, new_version) .add_attribute(NYM_NODE_CURRENT_SEMVER_KEY, new_version)
.add_attribute(NYM_NODE_CURRENT_SEMVER_ID_KEY, new_id.to_string())
} }
pub fn new_not_found_node_operator_rewarding_event(interval: Interval, node_id: NodeId) -> Event { pub fn new_not_found_node_operator_rewarding_event(interval: Interval, node_id: NodeId) -> Event {
@@ -42,11 +42,9 @@ pub struct Gateway {
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))] #[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
pub struct GatewayBond { pub struct GatewayBond {
/// Original amount pledged by the operator of this node. /// Original amount pledged by the operator of this node.
#[cfg_attr(feature = "utoipa", schema(value_type = crate::CoinSchema))]
pub pledge_amount: Coin, pub pledge_amount: Coin,
/// Address of the owner of this gateway. /// Address of the owner of this gateway.
#[cfg_attr(feature = "utoipa", schema(value_type = String))]
pub owner: Addr, pub owner: Addr,
/// Block height at which this gateway has been bonded. /// Block height at which this gateway has been bonded.
@@ -57,7 +55,6 @@ pub struct GatewayBond {
/// Entity who bonded this gateway on behalf of the owner. /// Entity who bonded this gateway on behalf of the owner.
/// If exists, it's most likely the address of the vesting contract. /// If exists, it's most likely the address of the vesting contract.
#[cfg_attr(feature = "utoipa", schema(value_type = String))]
pub proxy: Option<Addr>, pub proxy: Option<Addr>,
} }
@@ -32,7 +32,7 @@ pub(crate) mod string_rfc3339_offset_date_time {
struct Rfc3339OffsetDateTimeVisitor; struct Rfc3339OffsetDateTimeVisitor;
impl Visitor<'_> for Rfc3339OffsetDateTimeVisitor { impl<'de> Visitor<'de> for Rfc3339OffsetDateTimeVisitor {
type Value = OffsetDateTime; type Value = OffsetDateTime;
fn expecting(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result { fn expecting(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result {
@@ -5,7 +5,6 @@
#![warn(clippy::unwrap_used)] #![warn(clippy::unwrap_used)]
#![warn(clippy::todo)] #![warn(clippy::todo)]
mod config_score;
pub mod constants; pub mod constants;
pub mod delegation; pub mod delegation;
pub mod error; pub mod error;
@@ -22,7 +21,6 @@ pub mod rewarding;
pub mod signing_types; pub mod signing_types;
pub mod types; pub mod types;
pub use config_score::*;
pub use constants::*; pub use constants::*;
pub use contracts_common::types::*; pub use contracts_common::types::*;
pub use cosmwasm_std::{Addr, Coin, Decimal, Fraction}; pub use cosmwasm_std::{Addr, Coin, Decimal, Fraction};
@@ -81,25 +81,20 @@ impl MixNodeDetails {
// currently this struct is shared between mixnodes and nymnodes // currently this struct is shared between mixnodes and nymnodes
#[cw_serde] #[cw_serde]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
pub struct NodeRewarding { pub struct NodeRewarding {
/// Information provided by the operator that influence the cost function. /// Information provided by the operator that influence the cost function.
pub cost_params: NodeCostParams, pub cost_params: NodeCostParams,
/// Total pledge and compounded reward earned by the node operator. /// Total pledge and compounded reward earned by the node operator.
#[cfg_attr(feature = "utoipa", schema(value_type = String))]
pub operator: Decimal, pub operator: Decimal,
/// Total delegation and compounded reward earned by all node delegators. /// Total delegation and compounded reward earned by all node delegators.
#[cfg_attr(feature = "utoipa", schema(value_type = String))]
pub delegates: Decimal, pub delegates: Decimal,
/// Cumulative reward earned by the "unit delegation" since the block 0. /// Cumulative reward earned by the "unit delegation" since the block 0.
#[cfg_attr(feature = "utoipa", schema(value_type = String))]
pub total_unit_reward: Decimal, pub total_unit_reward: Decimal,
/// Value of the theoretical "unit delegation" that has delegated to this node at block 0. /// Value of the theoretical "unit delegation" that has delegated to this node at block 0.
#[cfg_attr(feature = "utoipa", schema(value_type = String))]
pub unit_delegation: Decimal, pub unit_delegation: Decimal,
/// Marks the epoch when this node was last rewarded so that we wouldn't accidentally attempt /// Marks the epoch when this node was last rewarded so that we wouldn't accidentally attempt
@@ -496,17 +491,14 @@ impl NodeRewarding {
::cosmwasm_schema::schemars::JsonSchema, ::cosmwasm_schema::schemars::JsonSchema,
)] )]
#[schemars(crate = "::cosmwasm_schema::schemars")] #[schemars(crate = "::cosmwasm_schema::schemars")]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
pub struct MixNodeBond { pub struct MixNodeBond {
/// Unique id assigned to the bonded mixnode. /// Unique id assigned to the bonded mixnode.
pub mix_id: NodeId, pub mix_id: NodeId,
/// Address of the owner of this mixnode. /// Address of the owner of this mixnode.
#[cfg_attr(feature = "utoipa", schema(value_type = String))]
pub owner: Addr, pub owner: Addr,
/// Original amount pledged by the operator of this node. /// Original amount pledged by the operator of this node.
#[cfg_attr(feature = "utoipa", schema(value_type = crate::CoinSchema))]
pub original_pledge: Coin, pub original_pledge: Coin,
// REMOVED (but might be needed due to legacy things, idk yet) // REMOVED (but might be needed due to legacy things, idk yet)
@@ -517,7 +509,6 @@ pub struct MixNodeBond {
/// Entity who bonded this mixnode on behalf of the owner. /// Entity who bonded this mixnode on behalf of the owner.
/// If exists, it's most likely the address of the vesting contract. /// If exists, it's most likely the address of the vesting contract.
#[cfg_attr(feature = "utoipa", schema(value_type = Option<String>))]
pub proxy: Option<Addr>, pub proxy: Option<Addr>,
/// Block height at which this mixnode has been bonded. /// Block height at which this mixnode has been bonded.
@@ -553,7 +544,6 @@ impl MixNodeBond {
feature = "generate-ts", feature = "generate-ts",
ts(export, export_to = "ts-packages/types/src/types/rust/Mixnode.ts") ts(export, export_to = "ts-packages/types/src/types/rust/Mixnode.ts")
)] )]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
pub struct MixNode { pub struct MixNode {
/// Network address of this mixnode, for example 1.1.1.1 or foo.mixnode.com /// Network address of this mixnode, for example 1.1.1.1 or foo.mixnode.com
pub host: String, pub host: String,
@@ -580,14 +570,11 @@ pub struct MixNode {
/// The cost parameters, or the cost function, defined for the particular mixnode that influences /// The cost parameters, or the cost function, defined for the particular mixnode that influences
/// how the rewards should be split between the node operator and its delegators. /// how the rewards should be split between the node operator and its delegators.
#[cw_serde] #[cw_serde]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
pub struct NodeCostParams { pub struct NodeCostParams {
/// The profit margin of the associated node, i.e. the desired percent of the reward to be distributed to the operator. /// The profit margin of the associated node, i.e. the desired percent of the reward to be distributed to the operator.
#[cfg_attr(feature = "utoipa", schema(value_type = String))]
pub profit_margin_percent: Percent, pub profit_margin_percent: Percent,
/// Operating cost of the associated node per the entire interval. /// Operating cost of the associated node per the entire interval.
#[cfg_attr(feature = "utoipa", schema(value_type = crate::CoinSchema))]
pub interval_operating_cost: Coin, pub interval_operating_cost: Coin,
} }
@@ -682,9 +669,7 @@ pub struct PendingMixNodeChanges {
} }
#[derive(Default, Copy, Clone, Debug, Serialize, Deserialize, JsonSchema)] #[derive(Default, Copy, Clone, Debug, Serialize, Deserialize, JsonSchema)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
pub struct LegacyPendingMixNodeChanges { pub struct LegacyPendingMixNodeChanges {
#[cfg_attr(feature = "utoipa", schema(value_type = Option<u32>))]
pub pledge_change: Option<EpochEventId>, pub pledge_change: Option<EpochEventId>,
} }
@@ -25,7 +25,6 @@ use std::time::Duration;
#[cfg(feature = "schema")] #[cfg(feature = "schema")]
use crate::{ use crate::{
config_score::{CurrentNymNodeVersionResponse, NymNodeVersionHistoryResponse},
delegation::{ delegation::{
NodeDelegationResponse, PagedAllDelegationsResponse, PagedDelegatorDelegationsResponse, NodeDelegationResponse, PagedAllDelegationsResponse, PagedDelegatorDelegationsResponse,
PagedNodeDelegationsResponse, PagedNodeDelegationsResponse,
@@ -424,20 +423,6 @@ pub enum QueryMsg {
#[cfg_attr(feature = "schema", returns(ContractState))] #[cfg_attr(feature = "schema", returns(ContractState))]
GetState {}, GetState {},
/// Get the current expected version of a Nym Node.
#[cfg_attr(feature = "schema", returns(CurrentNymNodeVersionResponse))]
GetCurrentNymNodeVersion {},
/// Get the version history of Nym Node.
#[cfg_attr(feature = "schema", returns(NymNodeVersionHistoryResponse))]
GetNymNodeVersionHistory {
/// Controls the maximum number of entries returned by the query. Note that too large values will be overwritten by a saner default.
limit: Option<u32>,
/// Pagination control for the values returned by the query. Note that the provided value itself will **not** be used for the response.
start_after: Option<u32>,
},
/// Gets the current parameters used for reward calculation. /// Gets the current parameters used for reward calculation.
#[cfg_attr(feature = "schema", returns(RewardingParams))] #[cfg_attr(feature = "schema", returns(RewardingParams))]
GetRewardingParams {}, GetRewardingParams {},
@@ -231,7 +231,6 @@ pub struct RoleMetadata {
/// Full details associated with given node. /// Full details associated with given node.
#[cw_serde] #[cw_serde]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
pub struct NymNodeDetails { pub struct NymNodeDetails {
/// Basic bond information of this node, such as owner address, original pledge, etc. /// Basic bond information of this node, such as owner address, original pledge, etc.
pub bond_information: NymNodeBond, pub bond_information: NymNodeBond,
@@ -289,19 +288,14 @@ impl NymNodeDetails {
} }
#[cw_serde] #[cw_serde]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
pub struct NymNodeBond { pub struct NymNodeBond {
/// Unique id assigned to the bonded node. /// Unique id assigned to the bonded node.
#[cfg_attr(feature = "utoipa", schema(value_type = u32))]
pub node_id: NodeId, pub node_id: NodeId,
/// Address of the owner of this nym-node. /// Address of the owner of this nym-node.
#[cfg_attr(feature = "utoipa", schema(value_type = String))]
pub owner: Addr, pub owner: Addr,
/// Original amount pledged by the operator of this node. /// Original amount pledged by the operator of this node.
#[cfg_attr(feature = "utoipa", schema(value_type = crate::CoinSchema))]
pub original_pledge: Coin, pub original_pledge: Coin,
/// Block height at which this nym-node has been bonded. /// Block height at which this nym-node has been bonded.
@@ -354,7 +348,6 @@ impl NymNodeBond {
feature = "generate-ts", feature = "generate-ts",
ts(export, export_to = "ts-packages/types/src/types/rust/NymNode.ts") ts(export, export_to = "ts-packages/types/src/types/rust/NymNode.ts")
)] )]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
pub struct NymNode { pub struct NymNode {
/// Network address of this nym-node, for example 1.1.1.1 or foo.mixnode.com /// 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. /// that is used to discover other capabilities of this node.
@@ -365,7 +358,6 @@ pub struct NymNode {
pub custom_http_port: Option<u16>, pub custom_http_port: Option<u16>,
/// Base58-encoded ed25519 EdDSA public key. /// Base58-encoded ed25519 EdDSA public key.
#[cfg_attr(feature = "utoipa", schema(value_type = String))]
pub identity_key: IdentityKey, pub identity_key: IdentityKey,
// TODO: I don't think we want to include sphinx keys here, // TODO: I don't think we want to include sphinx keys here,
// given we want to rotate them and keeping that in sync with contract will be a PITA // given we want to rotate them and keeping that in sync with contract will be a PITA
@@ -443,11 +435,8 @@ pub struct NodeConfigUpdate {
export_to = "ts-packages/types/src/types/rust/PendingNodeChanges.ts" export_to = "ts-packages/types/src/types/rust/PendingNodeChanges.ts"
) )
)] )]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
pub struct PendingNodeChanges { pub struct PendingNodeChanges {
#[cfg_attr(feature = "utoipa", schema(value_type = Option<u32>))]
pub pledge_change: Option<EpochEventId>, pub pledge_change: Option<EpochEventId>,
#[cfg_attr(feature = "utoipa", schema(value_type = Option<u32>))]
pub cost_params_change: Option<IntervalEventId>, pub cost_params_change: Option<IntervalEventId>,
} }
@@ -21,37 +21,31 @@ pub type WorkFactor = Decimal;
)] )]
#[cw_serde] #[cw_serde]
#[derive(Copy)] #[derive(Copy)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
pub struct IntervalRewardParams { pub struct IntervalRewardParams {
/// Current value of the rewarding pool. /// Current value of the rewarding pool.
/// It is expected to be constant throughout the interval. /// It is expected to be constant throughout the interval.
#[cfg_attr(feature = "generate-ts", ts(type = "string"))] #[cfg_attr(feature = "generate-ts", ts(type = "string"))]
#[cfg_attr(feature = "utoipa", schema(value_type = String))]
pub reward_pool: Decimal, pub reward_pool: Decimal,
/// Current value of the staking supply. /// Current value of the staking supply.
/// It is expected to be constant throughout the interval. /// It is expected to be constant throughout the interval.
#[cfg_attr(feature = "generate-ts", ts(type = "string"))] #[cfg_attr(feature = "generate-ts", ts(type = "string"))]
#[cfg_attr(feature = "utoipa", schema(value_type = String))]
pub staking_supply: Decimal, pub staking_supply: Decimal,
/// Defines the percentage of stake needed to reach saturation for all of the nodes in the rewarded set. /// Defines the percentage of stake needed to reach saturation for all of the nodes in the rewarded set.
/// Also known as `beta`. /// Also known as `beta`.
#[cfg_attr(feature = "generate-ts", ts(type = "string"))] #[cfg_attr(feature = "generate-ts", ts(type = "string"))]
#[cfg_attr(feature = "utoipa", schema(value_type = String))]
pub staking_supply_scale_factor: Percent, pub staking_supply_scale_factor: Percent,
// computed values // computed values
/// Current value of the computed reward budget per epoch, per node. /// Current value of the computed reward budget per epoch, per node.
/// It is expected to be constant throughout the interval. /// It is expected to be constant throughout the interval.
#[cfg_attr(feature = "generate-ts", ts(type = "string"))] #[cfg_attr(feature = "generate-ts", ts(type = "string"))]
#[cfg_attr(feature = "utoipa", schema(value_type = String))]
pub epoch_reward_budget: Decimal, pub epoch_reward_budget: Decimal,
/// Current value of the stake saturation point. /// Current value of the stake saturation point.
/// It is expected to be constant throughout the interval. /// It is expected to be constant throughout the interval.
#[cfg_attr(feature = "generate-ts", ts(type = "string"))] #[cfg_attr(feature = "generate-ts", ts(type = "string"))]
#[cfg_attr(feature = "utoipa", schema(value_type = String))]
pub stake_saturation_point: Decimal, pub stake_saturation_point: Decimal,
// constants(-ish) // constants(-ish)
@@ -60,7 +54,6 @@ pub struct IntervalRewardParams {
/// It is not really expected to be changing very often. /// 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. /// As a matter of fact, unless there's a very specific reason, it should remain constant.
#[cfg_attr(feature = "generate-ts", ts(type = "string"))] #[cfg_attr(feature = "generate-ts", ts(type = "string"))]
#[cfg_attr(feature = "utoipa", schema(value_type = String))]
pub sybil_resistance: Percent, pub sybil_resistance: Percent,
// default: 10 // default: 10
@@ -68,7 +61,6 @@ pub struct IntervalRewardParams {
/// It is not really expected to be changing very often. /// 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. /// As a matter of fact, unless there's a very specific reason, it should remain constant.
#[cfg_attr(feature = "generate-ts", ts(type = "string"))] #[cfg_attr(feature = "generate-ts", ts(type = "string"))]
#[cfg_attr(feature = "utoipa", schema(value_type = String))]
pub active_set_work_factor: Decimal, pub active_set_work_factor: Decimal,
// default: 2% // default: 2%
@@ -78,7 +70,6 @@ pub struct IntervalRewardParams {
/// It is not really expected to be changing very often. /// 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. /// As a matter of fact, unless there's a very specific reason, it should remain constant.
#[cfg_attr(feature = "generate-ts", ts(type = "string"))] #[cfg_attr(feature = "generate-ts", ts(type = "string"))]
#[cfg_attr(feature = "utoipa", schema(value_type = String))]
pub interval_pool_emission: Percent, pub interval_pool_emission: Percent,
} }
@@ -99,7 +90,6 @@ impl IntervalRewardParams {
)] )]
#[cw_serde] #[cw_serde]
#[derive(Copy)] #[derive(Copy)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
pub struct RewardingParams { pub struct RewardingParams {
/// Parameters that should remain unchanged throughout an interval. /// Parameters that should remain unchanged throughout an interval.
pub interval: IntervalRewardParams, pub interval: IntervalRewardParams,
@@ -264,7 +254,6 @@ impl RewardingParams {
)] )]
#[cw_serde] #[cw_serde]
#[derive(Copy)] #[derive(Copy)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
pub struct RewardedSetParams { pub struct RewardedSetParams {
/// The expected number of nodes assigned entry gateway role (i.e. [`Role::EntryGateway`]) /// The expected number of nodes assigned entry gateway role (i.e. [`Role::EntryGateway`])
pub entry_gateways: u32, pub entry_gateways: u32,
@@ -17,12 +17,10 @@ pub mod simulator;
)] )]
#[cw_serde] #[cw_serde]
#[derive(Copy, Default)] #[derive(Copy, Default)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
pub struct RewardEstimate { pub struct RewardEstimate {
/// The amount of **decimal** coins that are going to get distributed to the node, /// The amount of **decimal** coins that are going to get distributed to the node,
/// i.e. the operator and all its delegators. /// i.e. the operator and all its delegators.
#[cfg_attr(feature = "generate-ts", ts(type = "string"))] #[cfg_attr(feature = "generate-ts", ts(type = "string"))]
#[cfg_attr(feature = "utoipa", schema(value_type = String))]
pub total_node_reward: Decimal, pub total_node_reward: Decimal,
// note that operator reward includes the operating_cost, // note that operator reward includes the operating_cost,
@@ -30,17 +28,14 @@ pub struct RewardEstimate {
// in that case the operator reward would still be `1nym` as opposed to 0 // in that case the operator reward would still be `1nym` as opposed to 0
/// The share of the reward that is going to get distributed to the node operator. /// The share of the reward that is going to get distributed to the node operator.
#[cfg_attr(feature = "generate-ts", ts(type = "string"))] #[cfg_attr(feature = "generate-ts", ts(type = "string"))]
#[cfg_attr(feature = "utoipa", schema(value_type = String))]
pub operator: Decimal, pub operator: Decimal,
/// The share of the reward that is going to get distributed among the node delegators. /// The share of the reward that is going to get distributed among the node delegators.
#[cfg_attr(feature = "generate-ts", ts(type = "string"))] #[cfg_attr(feature = "generate-ts", ts(type = "string"))]
#[cfg_attr(feature = "utoipa", schema(value_type = String))]
pub delegates: Decimal, pub delegates: Decimal,
/// The operating cost of this node. Note: it's already included in the operator reward. /// The operating cost of this node. Note: it's already included in the operator reward.
#[cfg_attr(feature = "generate-ts", ts(type = "string"))] #[cfg_attr(feature = "generate-ts", ts(type = "string"))]
#[cfg_attr(feature = "utoipa", schema(value_type = String))]
pub operating_cost: Decimal, pub operating_cost: Decimal,
} }
@@ -1,12 +1,11 @@
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net> // Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
use crate::config_score::{ConfigScoreParams, OutdatedVersionWeights, VersionScoreFormulaParams};
use crate::nym_node::Role; use crate::nym_node::Role;
use contracts_common::Percent; use contracts_common::Percent;
use cosmwasm_schema::cw_serde; use cosmwasm_schema::cw_serde;
use cosmwasm_std::Coin;
use cosmwasm_std::{Addr, Uint128}; use cosmwasm_std::{Addr, Uint128};
use cosmwasm_std::{Coin, Decimal};
use std::fmt::{Display, Formatter}; use std::fmt::{Display, Formatter};
// type aliases for better reasoning about available data // type aliases for better reasoning about available data
@@ -134,14 +133,6 @@ where
} }
} }
#[cfg(feature = "utoipa")]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "utoipa", schema(title = "Coin"))]
pub struct CoinSchema {
pub denom: String,
pub amount: String,
}
/// The current state of the mixnet contract. /// The current state of the mixnet contract.
#[cw_serde] #[cw_serde]
pub struct ContractState { pub struct ContractState {
@@ -230,14 +221,96 @@ impl OperatorsParamsUpdate {
} }
} }
#[cw_serde]
pub struct ConfigScoreParams {
/// Current version of the nym node that is going to be used for determining the version score of a node.
/// note: value stored here is pre-validated `semver::Version`
pub current_nym_node_semver: String,
/// Defines weights for calculating numbers of versions behind the current release.
pub version_weights: OutdatedVersionWeights,
/// Defines the parameters of the formula for calculating the version score
pub version_score_formula_params: VersionScoreFormulaParams,
}
impl ConfigScoreParams {
// SAFETY: the value stored in the contract is always valid
#[allow(clippy::unwrap_used)]
pub fn unchecked_nym_node_version(&self) -> semver::Version {
self.current_nym_node_semver.parse().unwrap()
}
pub fn versions_behind(&self, node_semver: &semver::Version) -> u32 {
let expected = self.unchecked_nym_node_version();
let major_diff = (node_semver.major as i64 - expected.major as i64).unsigned_abs() as u32;
let minor_diff = (node_semver.minor as i64 - expected.minor as i64).unsigned_abs() as u32;
let patch_diff = (node_semver.patch as i64 - expected.patch as i64).unsigned_abs() as u32;
let prerelease_diff = if node_semver.pre == expected.pre {
0
} else {
1
};
major_diff * self.version_weights.major
+ minor_diff * self.version_weights.minor
+ patch_diff * self.version_weights.patch
+ prerelease_diff * self.version_weights.prerelease
}
}
/// Defines weights for calculating numbers of versions behind the current release.
#[cw_serde]
#[derive(Copy)]
pub struct OutdatedVersionWeights {
pub major: u32,
pub minor: u32,
pub patch: u32,
pub prerelease: u32,
}
impl Default for OutdatedVersionWeights {
fn default() -> Self {
OutdatedVersionWeights {
major: 100,
minor: 10,
patch: 1,
prerelease: 1,
}
}
}
/// Given the formula of version_score = penalty ^ (num_versions_behind ^ penalty_scaling)
/// define the relevant parameters
#[cw_serde]
#[derive(Copy)]
pub struct VersionScoreFormulaParams {
pub penalty: Decimal,
pub penalty_scaling: Decimal,
}
impl Default for VersionScoreFormulaParams {
fn default() -> Self {
#[allow(clippy::unwrap_used)]
VersionScoreFormulaParams {
penalty: "0.8".parse().unwrap(),
penalty_scaling: "2.0".parse().unwrap(),
}
}
}
#[cw_serde] #[cw_serde]
pub struct ConfigScoreParamsUpdate { pub struct ConfigScoreParamsUpdate {
pub current_nym_node_semver: Option<String>,
pub version_weights: Option<OutdatedVersionWeights>, pub version_weights: Option<OutdatedVersionWeights>,
pub version_score_formula_params: Option<VersionScoreFormulaParams>, pub version_score_formula_params: Option<VersionScoreFormulaParams>,
} }
impl ConfigScoreParamsUpdate { impl ConfigScoreParamsUpdate {
pub fn contains_updates(&self) -> bool { pub fn contains_updates(&self) -> bool {
self.version_weights.is_some() || self.version_score_formula_params.is_some() self.current_nym_node_semver.is_some()
|| self.version_weights.is_some()
|| self.version_score_formula_params.is_some()
} }
} }
@@ -1,6 +0,0 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
/**
* The vesting period.
*/
export type Period = "Before" | { "In": number } | "After";
@@ -7,7 +7,7 @@ use crate::ClientBandwidth;
use nym_credentials::ecash::utils::ecash_today; use nym_credentials::ecash::utils::ecash_today;
use nym_credentials_interface::Bandwidth; use nym_credentials_interface::Bandwidth;
use nym_gateway_requests::ServerResponse; use nym_gateway_requests::ServerResponse;
use nym_gateway_storage::GatewayStorage; use nym_gateway_storage::Storage;
use si_scale::helpers::bibytes2; use si_scale::helpers::bibytes2;
use time::OffsetDateTime; use time::OffsetDateTime;
use tracing::*; use tracing::*;
@@ -15,17 +15,17 @@ use tracing::*;
const FREE_TESTNET_BANDWIDTH_VALUE: Bandwidth = Bandwidth::new_unchecked(64 * 1024 * 1024 * 1024); // 64GB const FREE_TESTNET_BANDWIDTH_VALUE: Bandwidth = Bandwidth::new_unchecked(64 * 1024 * 1024 * 1024); // 64GB
#[derive(Clone)] #[derive(Clone)]
pub struct BandwidthStorageManager { pub struct BandwidthStorageManager<S> {
pub(crate) storage: GatewayStorage, pub(crate) storage: S,
pub(crate) client_bandwidth: ClientBandwidth, pub(crate) client_bandwidth: ClientBandwidth,
pub(crate) client_id: i64, pub(crate) client_id: i64,
pub(crate) bandwidth_cfg: BandwidthFlushingBehaviourConfig, pub(crate) bandwidth_cfg: BandwidthFlushingBehaviourConfig,
pub(crate) only_coconut_credentials: bool, pub(crate) only_coconut_credentials: bool,
} }
impl BandwidthStorageManager { impl<S: Storage + Clone + 'static> BandwidthStorageManager<S> {
pub fn new( pub fn new(
storage: GatewayStorage, storage: S,
client_bandwidth: ClientBandwidth, client_bandwidth: ClientBandwidth,
client_id: i64, client_id: i64,
bandwidth_cfg: BandwidthFlushingBehaviourConfig, bandwidth_cfg: BandwidthFlushingBehaviourConfig,
@@ -111,7 +111,7 @@ impl BandwidthStorageManager {
} }
#[instrument(level = "trace", skip_all)] #[instrument(level = "trace", skip_all)]
pub async fn sync_storage_bandwidth(&mut self) -> Result<()> { async fn sync_storage_bandwidth(&mut self) -> Result<()> {
trace!("syncing client bandwidth with the underlying storage"); trace!("syncing client bandwidth with the underlying storage");
let updated = self let updated = self
.storage .storage

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