Compare commits
74 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8e992c3c58 | |||
| 5ab164d229 | |||
| 26538c5884 | |||
| c202e2d598 | |||
| a7874add88 | |||
| 3d84be22e2 | |||
| 25766dc0ec | |||
| 676e93a372 | |||
| 5a6770e5e2 | |||
| 529e8d49ee | |||
| a94c035c0a | |||
| 24480418f0 | |||
| a46245ffe3 | |||
| 7c1c13e139 | |||
| 836a93cd96 | |||
| b47a742dd0 | |||
| 6e14882246 | |||
| a7466a0e02 | |||
| 78f45012db | |||
| f6a2f62ea9 | |||
| 3efeededc5 | |||
| c482350ec6 | |||
| f7a7a8072f | |||
| acd068e5ab | |||
| 8d5a41a790 | |||
| caa17d933c | |||
| 039b05cf7e | |||
| 37b10b59aa | |||
| a9ede22bbd | |||
| b656003306 | |||
| b4f51baf94 | |||
| a3f3d83c1b | |||
| 84d7004cb2 | |||
| be063a36eb | |||
| 0a712b9fce | |||
| 88d6fb4e22 | |||
| 04c2045d94 | |||
| c0b4e8dd70 | |||
| e7702a1e7a | |||
| 07435ce3b2 | |||
| 9690c73c91 | |||
| 684d7ac1a2 | |||
| b813044360 | |||
| c26d4f24fc | |||
| ee7b3f1415 | |||
| ccd66f8a51 | |||
| c31d1f63e6 | |||
| 2ab172146a | |||
| 9b5e14c78e | |||
| d9e5c62b5c | |||
| a336893116 | |||
| 1d0d62f798 | |||
| daa680d6b8 | |||
| a491e6a71a | |||
| fd47768b75 | |||
| 4e2aa2c0b3 | |||
| 96f99bb9e4 | |||
| 10933ff8f1 | |||
| 5454b36022 | |||
| 675e5a0305 | |||
| 210cc5286e | |||
| d07e293cb5 | |||
| 4b055a9bf0 | |||
| 80d1a24164 | |||
| b481da9c55 | |||
| 585d752c83 | |||
| 6eddc913f4 | |||
| 15c3012199 | |||
| 78bf413e6a | |||
| 29ea4623c8 | |||
| 60c21a8d1d | |||
| feefde9022 | |||
| 645be5fa22 | |||
| ac56717b23 |
@@ -4,4 +4,3 @@
|
||||
**/node_modules
|
||||
**/target
|
||||
dist
|
||||
documentation
|
||||
|
||||
@@ -30,7 +30,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ arc-ubuntu-20.04, custom-runner-mac-m1 ]
|
||||
os: [ arc-ubuntu-20.04, custom-windows-11, custom-runner-mac-m1 ]
|
||||
runs-on: ${{ matrix.os }}
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
|
||||
@@ -56,14 +56,6 @@ jobs:
|
||||
rustup target add aarch64-linux-android \
|
||||
x86_64-linux-android
|
||||
|
||||
- name: Build lib nym-socks5-listener
|
||||
working-directory: sdk/lib/socks5-listener/
|
||||
env:
|
||||
RELEASE: true
|
||||
RUSTFLAGS: "-C link-args=-Wl,--hash-style=gnu"
|
||||
# build for arm64 and x86_64
|
||||
run: ./build-android.sh aarch64 x86_64
|
||||
|
||||
- name: Build APKs (unsigned)
|
||||
working-directory: nym-connect/native/android
|
||||
env:
|
||||
|
||||
+3
-1
@@ -51,4 +51,6 @@ ppa-private-key.b64
|
||||
ppa-private-key.asc
|
||||
nym-network-monitor/topology.json
|
||||
nym-network-monitor/__pycache__
|
||||
nym-network-monitor/*.key
|
||||
nym-network-monitor/*.key
|
||||
nym-network-monitor/.envrc
|
||||
nym-network-monitor/.envrc
|
||||
|
||||
+227
@@ -4,6 +4,233 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [2025.1-reeses] (2025-01-15)
|
||||
|
||||
- Feture/legacy alert ([#5346])
|
||||
- chore: readjusted --mode behaviour to fix the regression ([#5331])
|
||||
- chore: apply 1.84 linter suggestions ([#5330])
|
||||
- bugfix: make sure refresh data key matches bond info ([#5329])
|
||||
- reduce log severity for number of packets being delayed ([#5321])
|
||||
- feat: warn users if node is run in exit mode only ([#5320])
|
||||
- Bugfix/contract version assignment ([#5318])
|
||||
- fixed client session histogram buckets ([#5316])
|
||||
- amend 250gb limit ([#5313])
|
||||
- feature: expand nym-node prometheus metrics ([#5298])
|
||||
- Cherry picked #5286 ([#5287])
|
||||
- Add close to credential storage ([#5283])
|
||||
- feature: wireguard metrics ([#5278])
|
||||
- Add PATCH support to nym-http-api-client ([#5260])
|
||||
- chore: removed legacy socks5 listener ([#5259])
|
||||
- bugfix: make sure to apply gateway score filtering when choosing initial node ([#5256])
|
||||
- Update TS bindings ([#5255])
|
||||
- Add conversion unit tests for auth msg ([#5251])
|
||||
- Add control messages to GatewayTransciver ([#5247])
|
||||
- Remove unneeded async function annotation ([#5246])
|
||||
- bugfix: make sure to update timestamp of last batch verification to prevent double redemption ([#5239])
|
||||
- Add FromStr impl for UserAgent ([#5236])
|
||||
- Extend swagger docs ([#5235])
|
||||
- TicketType derive Hash and Eq ([#5233])
|
||||
- Add fd callback to client core ([#5230])
|
||||
- Extend raw ws fd for gateway client ([#5218])
|
||||
- Shipping raw metrics to PG ([#5216])
|
||||
- Change sqlite journal mode to WAL ([#5213])
|
||||
- Derive serialize for UserAgent ([#5210])
|
||||
- Restore Location fields ([#5208])
|
||||
- better date serialization ([#5207])
|
||||
- Fix overflow ([#5204])
|
||||
- feature: hopefully final steps of the smoosh™️ ([#5201])
|
||||
- Fix overflow ([#5184])
|
||||
- NS API - Gateway stats scraping ([#5180])
|
||||
- introduced initial internal commands for nym-cli: ecash key and request generation ([#5174])
|
||||
- Move NS client to separate package under NS API ([#5171])
|
||||
- build(deps): bump micromatch from 4.0.4 to 4.0.8 in /testnet-faucet ([#4813])
|
||||
|
||||
[#5346]: https://github.com/nymtech/nym/pull/5346
|
||||
[#5331]: https://github.com/nymtech/nym/pull/5331
|
||||
[#5330]: https://github.com/nymtech/nym/pull/5330
|
||||
[#5329]: https://github.com/nymtech/nym/pull/5329
|
||||
[#5321]: https://github.com/nymtech/nym/pull/5321
|
||||
[#5320]: https://github.com/nymtech/nym/pull/5320
|
||||
[#5318]: https://github.com/nymtech/nym/pull/5318
|
||||
[#5316]: https://github.com/nymtech/nym/pull/5316
|
||||
[#5313]: https://github.com/nymtech/nym/pull/5313
|
||||
[#5298]: https://github.com/nymtech/nym/pull/5298
|
||||
[#5287]: https://github.com/nymtech/nym/pull/5287
|
||||
[#5283]: https://github.com/nymtech/nym/pull/5283
|
||||
[#5278]: https://github.com/nymtech/nym/pull/5278
|
||||
[#5260]: https://github.com/nymtech/nym/pull/5260
|
||||
[#5259]: https://github.com/nymtech/nym/pull/5259
|
||||
[#5256]: https://github.com/nymtech/nym/pull/5256
|
||||
[#5255]: https://github.com/nymtech/nym/pull/5255
|
||||
[#5251]: https://github.com/nymtech/nym/pull/5251
|
||||
[#5247]: https://github.com/nymtech/nym/pull/5247
|
||||
[#5246]: https://github.com/nymtech/nym/pull/5246
|
||||
[#5239]: https://github.com/nymtech/nym/pull/5239
|
||||
[#5236]: https://github.com/nymtech/nym/pull/5236
|
||||
[#5235]: https://github.com/nymtech/nym/pull/5235
|
||||
[#5233]: https://github.com/nymtech/nym/pull/5233
|
||||
[#5230]: https://github.com/nymtech/nym/pull/5230
|
||||
[#5218]: https://github.com/nymtech/nym/pull/5218
|
||||
[#5216]: https://github.com/nymtech/nym/pull/5216
|
||||
[#5213]: https://github.com/nymtech/nym/pull/5213
|
||||
[#5210]: https://github.com/nymtech/nym/pull/5210
|
||||
[#5208]: https://github.com/nymtech/nym/pull/5208
|
||||
[#5207]: https://github.com/nymtech/nym/pull/5207
|
||||
[#5204]: https://github.com/nymtech/nym/pull/5204
|
||||
[#5201]: https://github.com/nymtech/nym/pull/5201
|
||||
[#5184]: https://github.com/nymtech/nym/pull/5184
|
||||
[#5180]: https://github.com/nymtech/nym/pull/5180
|
||||
[#5174]: https://github.com/nymtech/nym/pull/5174
|
||||
[#5171]: https://github.com/nymtech/nym/pull/5171
|
||||
[#4813]: https://github.com/nymtech/nym/pull/4813
|
||||
|
||||
## [2024.14-crunch-patched] (2024-12-17)
|
||||
|
||||
- Fixes an issue to allow previously registred clients to connect to latest nym-nodes
|
||||
- Fixes compatibility issues between nym-nodes and older clients
|
||||
|
||||
## [2024.14-crunch] (2024-12-11)
|
||||
|
||||
- Merge/release/2024.14-crunch ([#5242])
|
||||
- bugfix: added explicit openapi servers to account for route prefixes ([#5237])
|
||||
- Further config score adjustments ([#5225])
|
||||
- feature: remve any filtering on node semver ([#5224])
|
||||
- Backport #5218 ([#5220])
|
||||
- Derive serialize for UserAgent (#5210) ([#5217])
|
||||
- dont consider legacy nodes for rewarded set selection ([#5215])
|
||||
- introduce UNSTABLE endpoints for returning network monitor run details ([#5214])
|
||||
- Nmv2 add debug config ([#5212])
|
||||
- nym-api NMv1 adjustments ([#5209])
|
||||
- adjusted config score penalty calculation ([#5206])
|
||||
- Fix backwards compat mac generation ([#5202])
|
||||
- merge crunch into develop ([#5199])
|
||||
- Update Security disclosure email, public key and policy ([#5195])
|
||||
- Guard storage access with cache ([#5193])
|
||||
- chore: apply 1.84 linter suggestions ([#5192])
|
||||
- improvement: make internal gateway clients use the same topology cache ([#5191])
|
||||
- Bugfix/credential proxy sequencing ([#5187])
|
||||
- Add monitor_run and testing_route indexes ([#5182])
|
||||
- Add indexes to monitor run and testing route ([#5181])
|
||||
- bugfix: fixed nym-node config migrations (again) ([#5179])
|
||||
- bugfix: use default value for verloc config when deserialising missing values ([#5177])
|
||||
- Remove peers with no allowed ip from storage ([#5175])
|
||||
- Move two minor jobs to free tier github hosted runners ([#5169])
|
||||
- Add support for DELETE to nym-http-api-client ([#5166])
|
||||
- Fix env var name ([#5165])
|
||||
- Add strum::EnumIter for TicketType ([#5164])
|
||||
- Add export_to_env to NymNetworkDetails ([#5162])
|
||||
- bugfix: correctly expose ecash-related data on nym-api ([#5155])
|
||||
- fix: validator-rewarder GH job ([#5151])
|
||||
- build(deps): bump cross-spawn from 7.0.3 to 7.0.6 in /testnet-faucet ([#5150])
|
||||
- build(deps): bump mikefarah/yq from 4.44.3 to 4.44.5 ([#5149])
|
||||
- start session collection for exit gateways ([#5148])
|
||||
- add version to clientStatsReport ([#5147])
|
||||
- update serde_json_path due to compilation issue ([#5144])
|
||||
- chore: remove standalone legacy mixnode/gateway binaries ([#5135])
|
||||
- [Product Data] Set up country reporting from vpn-client ([#5134])
|
||||
- removed ci-nym-api-tests.yml which was running outdated (and broken) tests ([#5133])
|
||||
- CI: reduce jobs running on cluster ([#5132])
|
||||
- [DOCS/operators]: Release changes v2024.13-magura & Tokenomics pages v1.0 ([#5128])
|
||||
- NS Agent auth with NS API ([#5127])
|
||||
- [Product Data] Config deserialization bug fix ([#5126])
|
||||
- bugfix: don't send empty BankMsg in ecash contract ([#5121])
|
||||
- [Product data] Data consumption with ecash ticket ([#5120])
|
||||
- feat: add GH workflow for nym-validator-rewarder ([#5119])
|
||||
- feat: add Dockerfile and add env vars for clap arguments ([#5118])
|
||||
- feature: config score ([#5117])
|
||||
- [Product Data] Add stats reporting configuration in client config ([#5115])
|
||||
- Correct IPv6 address generation ([#5113])
|
||||
- feature: rewarding for ticketbook issuance ([#5112])
|
||||
- Add granular log on nym-node ([#5111])
|
||||
- Send mixnet packet stats using task client ([#5109])
|
||||
- Expose time range ([#5108])
|
||||
- [Product Data] Client-side stats collection ([#5107])
|
||||
- chore: ecash contract migration to remove unused 'redemption_gateway_share' ([#5104])
|
||||
- [Product Data] Better unique user count on gateways ([#5084])
|
||||
- feat: add nym node GH workflow ([#5080])
|
||||
- IPv6 support for wireguard ([#5059])
|
||||
- Node Status API ([#5050])
|
||||
- Authenticator CLI client mode ([#5044])
|
||||
- Integrate nym-credential-proxy into workspace ([#5027])
|
||||
- [Product Data] Introduce data persistence on gateways ([#5022])
|
||||
- Bump the patch-updates group across 1 directory with 10 updates ([#5011])
|
||||
- build(deps): bump once_cell from 1.19.0 to 1.20.2 ([#4952])
|
||||
- Create TaskStatusEvent trait instead of piggybacking on Error ([#4919])
|
||||
- build(deps): bump lazy_static from 1.4.0 to 1.5.0 ([#4913])
|
||||
- Sync code with .env in build.rs ([#4876])
|
||||
- build(deps): bump axios from 1.6.0 to 1.7.5 in /nym-api/tests ([#4790])
|
||||
- Bump elliptic from 6.5.4 to 6.5.7 in /testnet-faucet ([#4768])
|
||||
|
||||
[#5242]: https://github.com/nymtech/nym/pull/5242
|
||||
[#5237]: https://github.com/nymtech/nym/pull/5237
|
||||
[#5225]: https://github.com/nymtech/nym/pull/5225
|
||||
[#5224]: https://github.com/nymtech/nym/pull/5224
|
||||
[#5220]: https://github.com/nymtech/nym/pull/5220
|
||||
[#5217]: https://github.com/nymtech/nym/pull/5217
|
||||
[#5215]: https://github.com/nymtech/nym/pull/5215
|
||||
[#5214]: https://github.com/nymtech/nym/pull/5214
|
||||
[#5212]: https://github.com/nymtech/nym/pull/5212
|
||||
[#5209]: https://github.com/nymtech/nym/pull/5209
|
||||
[#5206]: https://github.com/nymtech/nym/pull/5206
|
||||
[#5202]: https://github.com/nymtech/nym/pull/5202
|
||||
[#5199]: https://github.com/nymtech/nym/pull/5199
|
||||
[#5195]: https://github.com/nymtech/nym/pull/5195
|
||||
[#5193]: https://github.com/nymtech/nym/pull/5193
|
||||
[#5192]: https://github.com/nymtech/nym/pull/5192
|
||||
[#5191]: https://github.com/nymtech/nym/pull/5191
|
||||
[#5187]: https://github.com/nymtech/nym/pull/5187
|
||||
[#5182]: https://github.com/nymtech/nym/pull/5182
|
||||
[#5181]: https://github.com/nymtech/nym/pull/5181
|
||||
[#5179]: https://github.com/nymtech/nym/pull/5179
|
||||
[#5177]: https://github.com/nymtech/nym/pull/5177
|
||||
[#5175]: https://github.com/nymtech/nym/pull/5175
|
||||
[#5169]: https://github.com/nymtech/nym/pull/5169
|
||||
[#5166]: https://github.com/nymtech/nym/pull/5166
|
||||
[#5165]: https://github.com/nymtech/nym/pull/5165
|
||||
[#5164]: https://github.com/nymtech/nym/pull/5164
|
||||
[#5162]: https://github.com/nymtech/nym/pull/5162
|
||||
[#5155]: https://github.com/nymtech/nym/pull/5155
|
||||
[#5151]: https://github.com/nymtech/nym/pull/5151
|
||||
[#5150]: https://github.com/nymtech/nym/pull/5150
|
||||
[#5149]: https://github.com/nymtech/nym/pull/5149
|
||||
[#5148]: https://github.com/nymtech/nym/pull/5148
|
||||
[#5147]: https://github.com/nymtech/nym/pull/5147
|
||||
[#5144]: https://github.com/nymtech/nym/pull/5144
|
||||
[#5135]: https://github.com/nymtech/nym/pull/5135
|
||||
[#5134]: https://github.com/nymtech/nym/pull/5134
|
||||
[#5133]: https://github.com/nymtech/nym/pull/5133
|
||||
[#5132]: https://github.com/nymtech/nym/pull/5132
|
||||
[#5128]: https://github.com/nymtech/nym/pull/5128
|
||||
[#5127]: https://github.com/nymtech/nym/pull/5127
|
||||
[#5126]: https://github.com/nymtech/nym/pull/5126
|
||||
[#5121]: https://github.com/nymtech/nym/pull/5121
|
||||
[#5120]: https://github.com/nymtech/nym/pull/5120
|
||||
[#5119]: https://github.com/nymtech/nym/pull/5119
|
||||
[#5118]: https://github.com/nymtech/nym/pull/5118
|
||||
[#5117]: https://github.com/nymtech/nym/pull/5117
|
||||
[#5115]: https://github.com/nymtech/nym/pull/5115
|
||||
[#5113]: https://github.com/nymtech/nym/pull/5113
|
||||
[#5112]: https://github.com/nymtech/nym/pull/5112
|
||||
[#5111]: https://github.com/nymtech/nym/pull/5111
|
||||
[#5109]: https://github.com/nymtech/nym/pull/5109
|
||||
[#5108]: https://github.com/nymtech/nym/pull/5108
|
||||
[#5107]: https://github.com/nymtech/nym/pull/5107
|
||||
[#5104]: https://github.com/nymtech/nym/pull/5104
|
||||
[#5084]: https://github.com/nymtech/nym/pull/5084
|
||||
[#5080]: https://github.com/nymtech/nym/pull/5080
|
||||
[#5059]: https://github.com/nymtech/nym/pull/5059
|
||||
[#5050]: https://github.com/nymtech/nym/pull/5050
|
||||
[#5044]: https://github.com/nymtech/nym/pull/5044
|
||||
[#5027]: https://github.com/nymtech/nym/pull/5027
|
||||
[#5022]: https://github.com/nymtech/nym/pull/5022
|
||||
[#5011]: https://github.com/nymtech/nym/pull/5011
|
||||
[#4952]: https://github.com/nymtech/nym/pull/4952
|
||||
[#4919]: https://github.com/nymtech/nym/pull/4919
|
||||
[#4913]: https://github.com/nymtech/nym/pull/4913
|
||||
[#4876]: https://github.com/nymtech/nym/pull/4876
|
||||
[#4790]: https://github.com/nymtech/nym/pull/4790
|
||||
[#4768]: https://github.com/nymtech/nym/pull/4768
|
||||
|
||||
## [2024.13-magura-drift] (2024-11-29)
|
||||
|
||||
- Optimised syncing bandwidth information to storage
|
||||
|
||||
Generated
+149
-283
@@ -140,23 +140,6 @@ version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
|
||||
|
||||
[[package]]
|
||||
name = "android_log-sys"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5ecc8056bf6ab9892dcd53216c83d1597487d7dacac16c8df6b877d127df9937"
|
||||
|
||||
[[package]]
|
||||
name = "android_logger"
|
||||
version = "0.14.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "05b07e8e73d720a1f2e4b6014766e6039fd2e96a4fa44e2a78d0e1fa2ff49826"
|
||||
dependencies = [
|
||||
"android_log-sys",
|
||||
"env_filter",
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "android_system_properties"
|
||||
version = "0.1.5"
|
||||
@@ -430,6 +413,14 @@ version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
|
||||
|
||||
[[package]]
|
||||
name = "autodoc"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"env_logger 0.11.5",
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "axum"
|
||||
version = "0.6.20"
|
||||
@@ -973,12 +964,6 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cesu8"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
@@ -1174,16 +1159,6 @@ dependencies = [
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "combine"
|
||||
version = "4.6.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "comfy-table"
|
||||
version = "7.1.1"
|
||||
@@ -2354,6 +2329,19 @@ dependencies = [
|
||||
"termcolor",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "env_logger"
|
||||
version = "0.11.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e13fa619b91fb2381732789fc5de83b45675e882f66623b7d8cb4f643017018d"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
"env_filter",
|
||||
"humantime 2.1.0",
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "envy"
|
||||
version = "0.4.2"
|
||||
@@ -2428,7 +2416,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "explorer-api"
|
||||
version = "1.1.43"
|
||||
version = "1.1.44"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"clap 4.5.20",
|
||||
@@ -2461,26 +2449,6 @@ dependencies = [
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ext-trait"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d772df1c1a777963712fb68e014235e80863d6a91a85c4e06ba2d16243a310e5"
|
||||
dependencies = [
|
||||
"ext-trait-proc_macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ext-trait-proc_macros"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ab7934152eaf26aa5aa9f7371408ad5af4c31357073c9e84c3b9d7f11ad639a"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "extension-storage"
|
||||
version = "1.3.0-rc.0"
|
||||
@@ -2497,21 +2465,6 @@ dependencies = [
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "extension-traits"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a296e5a895621edf9fa8329c83aa1cb69a964643e36cf54d8d7a69b789089537"
|
||||
dependencies = [
|
||||
"ext-trait",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "extern-c"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "320bea982e85d42441eb25c49b41218e7eaa2657e8f90bc4eca7437376751e23"
|
||||
|
||||
[[package]]
|
||||
name = "eyre"
|
||||
version = "0.6.12"
|
||||
@@ -2523,10 +2476,16 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fancy_constructor"
|
||||
version = "1.2.2"
|
||||
name = "fallible-iterator"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f71f317e4af73b2f8f608fac190c52eac4b1879d2145df1db2fe48881ca69435"
|
||||
checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7"
|
||||
|
||||
[[package]]
|
||||
name = "fancy_constructor"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "07b19d0e43eae2bfbafe4931b5e79c73fb1a849ca15cd41a761a7b8587f9a1a2"
|
||||
dependencies = [
|
||||
"macroific",
|
||||
"proc-macro2",
|
||||
@@ -2887,15 +2846,15 @@ checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
|
||||
|
||||
[[package]]
|
||||
name = "gloo-net"
|
||||
version = "0.5.0"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43aaa242d1239a8822c15c645f02166398da4f8b5c4bae795c1f5b44e9eee173"
|
||||
checksum = "c06f627b1a58ca3d42b45d6104bf1e1a03799df472df00988b6ba21accc10580"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
"gloo-utils 0.2.0",
|
||||
"http 0.2.12",
|
||||
"http 1.1.0",
|
||||
"js-sys",
|
||||
"pin-project",
|
||||
"serde",
|
||||
@@ -3473,7 +3432,8 @@ checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683"
|
||||
[[package]]
|
||||
name = "indexed_db_futures"
|
||||
version = "0.4.2"
|
||||
source = "git+https://github.com/TiemenSch/rust-indexed-db?branch=update-uuid#9745d015707008b0c410115d787014a6d1af2efb"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0704b71f13f81b5933d791abf2de26b33c40935143985220299a357721166706"
|
||||
dependencies = [
|
||||
"accessory",
|
||||
"cfg-if",
|
||||
@@ -3709,34 +3669,13 @@ version = "1.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
|
||||
|
||||
[[package]]
|
||||
name = "jni"
|
||||
version = "0.21.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97"
|
||||
dependencies = [
|
||||
"cesu8",
|
||||
"cfg-if",
|
||||
"combine",
|
||||
"jni-sys",
|
||||
"log",
|
||||
"thiserror",
|
||||
"walkdir",
|
||||
"windows-sys 0.45.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jni-sys"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130"
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.72"
|
||||
version = "0.3.76"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9"
|
||||
checksum = "6717b6b5b077764fb5966237269cb3c64edddde4b14ce42647430a78ced9e7b7"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
@@ -3920,22 +3859,6 @@ dependencies = [
|
||||
"tracing-subscriber",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "macro_rules_attribute"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf0c9b980bf4f3a37fd7b1c066941dd1b1d0152ce6ee6e8fe8c49b9f6810d862"
|
||||
dependencies = [
|
||||
"macro_rules_attribute-proc_macro",
|
||||
"paste",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "macro_rules_attribute-proc_macro"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "58093314a45e00c77d5c508f76e77c3396afbbc0d01506e7fae47b018bac2b1d"
|
||||
|
||||
[[package]]
|
||||
name = "macroific"
|
||||
version = "1.3.1"
|
||||
@@ -4472,7 +4395,7 @@ checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3"
|
||||
|
||||
[[package]]
|
||||
name = "nym-api"
|
||||
version = "1.1.47"
|
||||
version = "1.1.48"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@@ -4695,7 +4618,6 @@ dependencies = [
|
||||
"opentelemetry-jaeger",
|
||||
"pretty_env_logger",
|
||||
"schemars",
|
||||
"semver 1.0.23",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tracing-opentelemetry",
|
||||
@@ -4722,7 +4644,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-cli"
|
||||
version = "1.1.45"
|
||||
version = "1.1.46"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"base64 0.22.1",
|
||||
@@ -4805,7 +4727,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-client"
|
||||
version = "1.1.45"
|
||||
version = "1.1.46"
|
||||
dependencies = [
|
||||
"bs58",
|
||||
"clap 4.5.20",
|
||||
@@ -5107,7 +5029,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-credential-proxy"
|
||||
version = "0.1.3"
|
||||
version = "0.1.6"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@@ -5127,6 +5049,7 @@ dependencies = [
|
||||
"nym-credentials",
|
||||
"nym-credentials-interface",
|
||||
"nym-crypto",
|
||||
"nym-ecash-contract-common",
|
||||
"nym-http-api-common",
|
||||
"nym-network-defaults",
|
||||
"nym-validator-client",
|
||||
@@ -5636,12 +5559,15 @@ dependencies = [
|
||||
"axum-client-ip",
|
||||
"bytes",
|
||||
"colored",
|
||||
"futures",
|
||||
"mime",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_yaml",
|
||||
"tower 0.4.13",
|
||||
"tracing",
|
||||
"utoipa",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -5755,18 +5681,20 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"dashmap",
|
||||
"lazy_static",
|
||||
"log",
|
||||
"prometheus",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nym-mixnet-client"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"dashmap",
|
||||
"futures",
|
||||
"nym-sphinx",
|
||||
"nym-task",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
"tokio-util",
|
||||
"tracing",
|
||||
]
|
||||
@@ -5864,6 +5792,7 @@ dependencies = [
|
||||
"nym-bin-common",
|
||||
"nym-client-core",
|
||||
"nym-crypto",
|
||||
"nym-gateway-requests",
|
||||
"nym-network-defaults",
|
||||
"nym-sdk",
|
||||
"nym-sphinx",
|
||||
@@ -5877,6 +5806,7 @@ dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tokio",
|
||||
"tokio-postgres",
|
||||
"tokio-util",
|
||||
"utoipa",
|
||||
"utoipa-swagger-ui",
|
||||
@@ -5884,7 +5814,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-network-requester"
|
||||
version = "1.1.46"
|
||||
version = "1.1.47"
|
||||
dependencies = [
|
||||
"addr",
|
||||
"anyhow",
|
||||
@@ -5935,7 +5865,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-node"
|
||||
version = "1.1.12"
|
||||
version = "1.3.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@@ -6307,7 +6237,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-socks5-client"
|
||||
version = "1.1.45"
|
||||
version = "1.1.46"
|
||||
dependencies = [
|
||||
"bs58",
|
||||
"clap 4.5.20",
|
||||
@@ -6370,28 +6300,6 @@ dependencies = [
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nym-socks5-listener"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"android_logger",
|
||||
"anyhow",
|
||||
"futures",
|
||||
"jni",
|
||||
"lazy_static",
|
||||
"log",
|
||||
"nym-bin-common",
|
||||
"nym-client-core",
|
||||
"nym-config",
|
||||
"nym-credential-storage",
|
||||
"nym-crypto",
|
||||
"nym-socks5-client-core",
|
||||
"rand",
|
||||
"safer-ffi",
|
||||
"serde",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nym-socks5-proxy-helpers"
|
||||
version = "0.1.0"
|
||||
@@ -6903,6 +6811,7 @@ dependencies = [
|
||||
"nym-crypto",
|
||||
"nym-gateway-storage",
|
||||
"nym-network-defaults",
|
||||
"nym-node-metrics",
|
||||
"nym-task",
|
||||
"nym-wireguard-types",
|
||||
"thiserror",
|
||||
@@ -6930,7 +6839,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nymvisor"
|
||||
version = "0.1.10"
|
||||
version = "0.1.11"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bytes",
|
||||
@@ -7354,6 +7263,24 @@ dependencies = [
|
||||
"indexmap 2.2.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "phf"
|
||||
version = "0.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc"
|
||||
dependencies = [
|
||||
"phf_shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "phf_shared"
|
||||
version = "0.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b"
|
||||
dependencies = [
|
||||
"siphasher 0.3.11",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project"
|
||||
version = "1.1.6"
|
||||
@@ -7492,6 +7419,35 @@ version = "1.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0"
|
||||
|
||||
[[package]]
|
||||
name = "postgres-protocol"
|
||||
version = "0.6.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "acda0ebdebc28befa84bee35e651e4c5f09073d668c7aed4cf7e23c3cda84b23"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"byteorder",
|
||||
"bytes",
|
||||
"fallible-iterator",
|
||||
"hmac",
|
||||
"md-5",
|
||||
"memchr",
|
||||
"rand",
|
||||
"sha2 0.10.8",
|
||||
"stringprep",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "postgres-types"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f66ea23a2d0e5734297357705193335e0a957696f34bed2f2faefacb2fec336f"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"fallible-iterator",
|
||||
"postgres-protocol",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "powerfmt"
|
||||
version = "0.2.0"
|
||||
@@ -7520,20 +7476,10 @@ version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "926d36b9553851b8b0005f1275891b392ee4d2d833852c417ed025477350fb9d"
|
||||
dependencies = [
|
||||
"env_logger",
|
||||
"env_logger 0.7.1",
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "prettyplease"
|
||||
version = "0.1.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c8646e95016a7a6c4adea95bafa8a16baab64b583356217f2c85db4a39d9a86"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-crate"
|
||||
version = "3.1.0"
|
||||
@@ -8431,38 +8377,6 @@ version = "1.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
|
||||
|
||||
[[package]]
|
||||
name = "safer-ffi"
|
||||
version = "0.1.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "435fdd58b61a6f1d8545274c1dfa458e905ff68c166e65e294a0130ef5e675bd"
|
||||
dependencies = [
|
||||
"extern-c",
|
||||
"inventory",
|
||||
"libc",
|
||||
"macro_rules_attribute",
|
||||
"paste",
|
||||
"safer_ffi-proc_macros",
|
||||
"scopeguard",
|
||||
"stabby",
|
||||
"uninit",
|
||||
"unwind_safe",
|
||||
"with_builtin_macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "safer_ffi-proc_macros"
|
||||
version = "0.1.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0f25be5ba5f319542edb31925517e0380245ae37df50a9752cdbc05ef948156"
|
||||
dependencies = [
|
||||
"macro_rules_attribute",
|
||||
"prettyplease",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "same-file"
|
||||
version = "1.0.6"
|
||||
@@ -8895,12 +8809,6 @@ dependencies = [
|
||||
"digest 0.10.7",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha2-const-stable"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5f179d4e11094a893b82fff208f74d448a7512f99f5a0acbd5c679b705f83ed9"
|
||||
|
||||
[[package]]
|
||||
name = "sharded-slab"
|
||||
version = "0.1.7"
|
||||
@@ -9301,40 +9209,6 @@ dependencies = [
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "stabby"
|
||||
version = "36.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "311d6bcf0070c462ff626122ec2246f42bd2acd44b28908eedbfd07d500c7d99"
|
||||
dependencies = [
|
||||
"rustversion",
|
||||
"stabby-abi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "stabby-abi"
|
||||
version = "36.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6daae1a0707399f56d27fce7f212e50e31d215112a447e1bbcd837ae1bf5f49"
|
||||
dependencies = [
|
||||
"rustversion",
|
||||
"sha2-const-stable",
|
||||
"stabby-macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "stabby-macros"
|
||||
version = "36.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43cf89a0cc9131279235baf8599b0e073fbcb096419204de0cc5d1a48ae73f74"
|
||||
dependencies = [
|
||||
"proc-macro-crate",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rand",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "stable-pattern"
|
||||
version = "0.1.0"
|
||||
@@ -9908,6 +9782,32 @@ dependencies = [
|
||||
"syn 2.0.90",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-postgres"
|
||||
version = "0.7.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3b5d3742945bc7d7f210693b0c58ae542c6fd47b17adbbda0885f3dcb34a6bdb"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"byteorder",
|
||||
"bytes",
|
||||
"fallible-iterator",
|
||||
"futures-channel",
|
||||
"futures-util",
|
||||
"log",
|
||||
"parking_lot",
|
||||
"percent-encoding",
|
||||
"phf",
|
||||
"pin-project-lite",
|
||||
"postgres-protocol",
|
||||
"postgres-types",
|
||||
"rand",
|
||||
"socket2",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
"whoami",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-rustls"
|
||||
version = "0.24.1"
|
||||
@@ -10653,15 +10553,6 @@ dependencies = [
|
||||
"weedle2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uninit"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3e130f2ed46ca5d8ec13c7ff95836827f92f5f5f37fd2b2bf16f33c408d98bb6"
|
||||
dependencies = [
|
||||
"extension-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "universal-hash"
|
||||
version = "0.5.1"
|
||||
@@ -10684,12 +10575,6 @@ version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
|
||||
|
||||
[[package]]
|
||||
name = "unwind_safe"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0976c77def3f1f75c4ef892a292c31c0bbe9e3d0702c63044d7c76db298171a3"
|
||||
|
||||
[[package]]
|
||||
name = "url"
|
||||
version = "2.5.2"
|
||||
@@ -10879,9 +10764,9 @@ checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.95"
|
||||
version = "0.2.99"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e"
|
||||
checksum = "a474f6281d1d70c17ae7aa6a613c87fce69a127e2624002df63dcb39d6cf6396"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
@@ -10890,13 +10775,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-backend"
|
||||
version = "0.2.95"
|
||||
version = "0.2.99"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358"
|
||||
checksum = "5f89bb38646b4f81674e8f5c3fb81b562be1fd936d84320f3264486418519c79"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"log",
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.90",
|
||||
@@ -10905,21 +10789,22 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-futures"
|
||||
version = "0.4.45"
|
||||
version = "0.4.49"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cc7ec4f8827a71586374db3e87abdb5a2bb3a15afed140221307c3ec06b1f63b"
|
||||
checksum = "38176d9b44ea84e9184eff0bc34cc167ed044f816accfe5922e54d84cf48eca2"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"js-sys",
|
||||
"once_cell",
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.95"
|
||||
version = "0.2.99"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56"
|
||||
checksum = "2cc6181fd9a7492eef6fef1f33961e3695e4579b9872a6f7c83aee556666d4fe"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
@@ -10927,9 +10812,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.95"
|
||||
version = "0.2.99"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68"
|
||||
checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -10940,9 +10825,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.95"
|
||||
version = "0.2.99"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d"
|
||||
checksum = "943aab3fdaaa029a6e0271b35ea10b72b943135afe9bffca82384098ad0e06a6"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-test"
|
||||
@@ -11050,9 +10935,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasmtimer"
|
||||
version = "0.2.0"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5f656cd8858a5164932d8a90f936700860976ec21eb00e0fe2aa8cab13f6b4cf"
|
||||
checksum = "0048ad49a55b9deb3953841fa1fc5858f0efbcb7a18868c899a360269fac1b23"
|
||||
dependencies = [
|
||||
"futures",
|
||||
"js-sys",
|
||||
@@ -11064,9 +10949,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "web-sys"
|
||||
version = "0.3.72"
|
||||
version = "0.3.76"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f6488b90108c040df0fe62fa815cbdee25124641df01814dd7282749234c6112"
|
||||
checksum = "04dd7223427d52553d3702c004d3b2fe07c148165faa56313cb00211e31c12bc"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
@@ -11113,6 +10998,7 @@ checksum = "372d5b87f58ec45c384ba03563b03544dc5fadc3983e434b286913f5b4a9bb6d"
|
||||
dependencies = [
|
||||
"redox_syscall 0.5.1",
|
||||
"wasite",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -11417,26 +11303,6 @@ dependencies = [
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "with_builtin_macros"
|
||||
version = "0.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a59d55032495429b87f9d69954c6c8602e4d3f3e0a747a12dea6b0b23de685da"
|
||||
dependencies = [
|
||||
"with_builtin_macros-proc_macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "with_builtin_macros-proc_macros"
|
||||
version = "0.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "15bd7679c15e22924f53aee34d4e448c45b674feb6129689af88593e129f8f42"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wyz"
|
||||
version = "0.5.1"
|
||||
|
||||
+9
-16
@@ -98,7 +98,7 @@ members = [
|
||||
"common/wasm/utils",
|
||||
"common/wireguard",
|
||||
"common/wireguard-types",
|
||||
# "documentation/autodoc",
|
||||
"documentation/autodoc",
|
||||
"explorer-api",
|
||||
"explorer-api/explorer-api-requests",
|
||||
"explorer-api/explorer-client",
|
||||
@@ -107,7 +107,6 @@ members = [
|
||||
"sdk/ffi/cpp",
|
||||
"sdk/ffi/go",
|
||||
"sdk/ffi/shared",
|
||||
"sdk/lib/socks5-listener",
|
||||
"sdk/rust/nym-sdk",
|
||||
"service-providers/authenticator",
|
||||
"service-providers/common",
|
||||
@@ -395,19 +394,17 @@ prost = { version = "0.12", default-features = false }
|
||||
|
||||
# wasm-related dependencies
|
||||
gloo-utils = "0.2.0"
|
||||
gloo-net = "0.5.0"
|
||||
gloo-net = "0.6.0"
|
||||
|
||||
# use a separate branch due to feature unification failures
|
||||
# this is blocked until the upstream removes outdates `wasm_bindgen` feature usage
|
||||
# indexed_db_futures = "0.4.1"
|
||||
indexed_db_futures = { git = "https://github.com/TiemenSch/rust-indexed-db", branch = "update-uuid" }
|
||||
js-sys = "0.3.70"
|
||||
# TODO: migrate to 0.6+
|
||||
indexed_db_futures = "0.4.2"
|
||||
js-sys = "0.3.76"
|
||||
serde-wasm-bindgen = "0.6.5"
|
||||
tsify = "0.4.5"
|
||||
wasm-bindgen = "0.2.95"
|
||||
wasm-bindgen-futures = "0.4.45"
|
||||
wasmtimer = "0.2.0"
|
||||
web-sys = "0.3.72"
|
||||
wasm-bindgen = "0.2.99"
|
||||
wasm-bindgen-futures = "0.4.49"
|
||||
wasmtimer = "0.4.1"
|
||||
web-sys = "0.3.76"
|
||||
|
||||
# Profile settings for individual crates
|
||||
|
||||
@@ -417,10 +414,6 @@ web-sys = "0.3.72"
|
||||
[profile.dev.package.sqlx-macros]
|
||||
opt-level = 3
|
||||
|
||||
[profile.release.package.nym-socks5-listener]
|
||||
strip = true
|
||||
codegen-units = 1
|
||||
|
||||
[profile.release.package.nym-client-wasm]
|
||||
# lto = true
|
||||
opt-level = 'z'
|
||||
|
||||
@@ -14,6 +14,7 @@ The platform is composed of multiple Rust crates. Top-level executable binary cr
|
||||
* `nym-socks5-client` - a Socks5 proxy you can run on your machine and use with existing applications.
|
||||
* `nym-explorer` - a (projected) block explorer and (existing) mixnet viewer.
|
||||
* `nym-wallet` - a desktop wallet implemented using the [Tauri](https://tauri.studio/en/docs/about/intro) framework.
|
||||
* `nym-cli` - a tool for interacting with the network from the CLI.
|
||||
<!-- coming soon
|
||||
* `nym-network-monitor` - sends packets through the full system to check that they are working as expected, and stores node uptime histories as the basis of a rewards system ("mixmining" or "proof-of-mixing").
|
||||
-->
|
||||
@@ -35,24 +36,20 @@ client ───► Gateway ──┘ mix │ mix ┌─►mix ───►
|
||||
### Building
|
||||
|
||||
* Platform build instructions are available on Nym [Operators Guide documentation](https://nymtech.net/operators/binaries/building-nym.html).
|
||||
* Wallet build instructions are available on Nym [Technical docs](https://nymtech.net/docs/wallet/desktop-wallet.html).
|
||||
* Wallet build instructions are available [here](https://github.com/nymtech/nym/tree/master/nym-wallet#installation-prerequisites---linux--mac).
|
||||
|
||||
### 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:
|
||||
|
||||
* [Developers Portal](https://nymtech.net/developers)
|
||||
* [Typescript SDKs](https://sdk.nymtech.net/)
|
||||
* [Technical Documentation - Nym network overview](https://nymtech.net/docs/)
|
||||
* [Release Cycle - git flow](https://nymtech.net/operators/release-cycle.html)
|
||||
* [Dev Docs](https://nymtech.net/docs/developers)
|
||||
* [SDKs](https://nymtech.net/docs/developers/rust)
|
||||
* [Network Docs](https://nymtech.net/docs/network)
|
||||
* [Release Cycle - git flow](https://nymtech.net/docs/operators/release-cycle)
|
||||
|
||||
### Developer chat
|
||||
|
||||
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)
|
||||
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).
|
||||
|
||||
### Tokenomics & Rewards
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "nym-client"
|
||||
version = "1.1.45"
|
||||
version = "1.1.46"
|
||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"]
|
||||
description = "Implementation of the Nym Client"
|
||||
edition = "2021"
|
||||
|
||||
@@ -3,13 +3,10 @@
|
||||
|
||||
use crate::commands::try_load_current_config;
|
||||
use crate::{
|
||||
client::{config::Config, SocketClient},
|
||||
client::SocketClient,
|
||||
commands::{override_config, OverrideConfig},
|
||||
error::ClientError,
|
||||
};
|
||||
use clap::Args;
|
||||
use log::*;
|
||||
use nym_bin_common::version_checker::is_minor_version_compatible;
|
||||
use nym_client_core::cli_helpers::client_run::CommonClientRunArgs;
|
||||
use std::error::Error;
|
||||
use std::net::IpAddr;
|
||||
@@ -48,36 +45,12 @@ impl From<Run> for OverrideConfig {
|
||||
}
|
||||
}
|
||||
|
||||
// this only checks compatibility between config the binary. It does not take into consideration
|
||||
// network version. It might do so in the future.
|
||||
fn version_check(cfg: &Config) -> bool {
|
||||
let binary_version = env!("CARGO_PKG_VERSION");
|
||||
let config_version = &cfg.base.client.version;
|
||||
if binary_version == config_version {
|
||||
true
|
||||
} else {
|
||||
warn!("The native-client binary has different version than what is specified in config file! {} and {}", binary_version, config_version);
|
||||
if is_minor_version_compatible(binary_version, config_version) {
|
||||
info!("but they are still semver compatible. However, consider running the `upgrade` command");
|
||||
true
|
||||
} else {
|
||||
error!("and they are semver incompatible! - please run the `upgrade` command before attempting `run` again");
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) async fn execute(args: Run) -> Result<(), Box<dyn Error + Send + Sync>> {
|
||||
eprintln!("Starting client {}...", args.common_args.id);
|
||||
|
||||
let mut config = try_load_current_config(&args.common_args.id).await?;
|
||||
config = override_config(config, OverrideConfig::from(args.clone()));
|
||||
|
||||
if !version_check(&config) {
|
||||
error!("failed the local version check");
|
||||
return Err(Box::new(ClientError::FailedLocalVersionCheck));
|
||||
}
|
||||
|
||||
SocketClient::new(config, args.common_args.custom_mixnet)
|
||||
.run_socket_forever()
|
||||
.await
|
||||
|
||||
@@ -17,9 +17,6 @@ pub enum ClientError {
|
||||
#[error("Failed to validate the loaded config")]
|
||||
ConfigValidationFailure,
|
||||
|
||||
#[error("Failed local version check, client and config mismatch")]
|
||||
FailedLocalVersionCheck,
|
||||
|
||||
#[error("Attempted to start the client in invalid socket mode")]
|
||||
InvalidSocketMode,
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "nym-socks5-client"
|
||||
version = "1.1.45"
|
||||
version = "1.1.46"
|
||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
|
||||
description = "A SOCKS5 localhost proxy that converts incoming messages to Sphinx and sends them to a Nym address"
|
||||
edition = "2021"
|
||||
|
||||
@@ -2,14 +2,8 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::commands::try_load_current_config;
|
||||
use crate::config::Config;
|
||||
use crate::{
|
||||
commands::{override_config, OverrideConfig},
|
||||
error::Socks5ClientError,
|
||||
};
|
||||
use crate::commands::{override_config, OverrideConfig};
|
||||
use clap::Args;
|
||||
use log::*;
|
||||
use nym_bin_common::version_checker::is_minor_version_compatible;
|
||||
use nym_client_core::cli_helpers::client_run::CommonClientRunArgs;
|
||||
use nym_client_core::client::base_client::storage::OnDiskPersistent;
|
||||
use nym_client_core::client::topology_control::geo_aware_provider::CountryGroup;
|
||||
@@ -82,38 +76,12 @@ fn validate_country_group(s: &str) -> Result<CountryGroup, String> {
|
||||
}
|
||||
}
|
||||
|
||||
// this only checks compatibility between config the binary. It does not take into consideration
|
||||
// network version. It might do so in the future.
|
||||
fn version_check(cfg: &Config) -> bool {
|
||||
let binary_version = env!("CARGO_PKG_VERSION");
|
||||
let config_version = &cfg.core.base.client.version;
|
||||
if binary_version == config_version {
|
||||
true
|
||||
} else {
|
||||
warn!(
|
||||
"The socks5-client binary has different version than what is specified in config file! {binary_version} and {config_version}",
|
||||
);
|
||||
if is_minor_version_compatible(binary_version, config_version) {
|
||||
info!("but they are still semver compatible. However, consider running the `upgrade` command");
|
||||
true
|
||||
} else {
|
||||
error!("and they are semver incompatible! - please run the `upgrade` command before attempting `run` again");
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) async fn execute(args: Run) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||
eprintln!("Starting client {}...", args.common_args.id);
|
||||
|
||||
let mut config = try_load_current_config(&args.common_args.id).await?;
|
||||
config = override_config(config, OverrideConfig::from(args.clone()));
|
||||
|
||||
if !version_check(&config) {
|
||||
error!("failed the local version check");
|
||||
return Err(Box::new(Socks5ClientError::FailedLocalVersionCheck));
|
||||
}
|
||||
|
||||
let storage =
|
||||
OnDiskPersistent::from_paths(config.storage_paths.common_paths, &config.core.base.debug)
|
||||
.await?;
|
||||
|
||||
@@ -14,9 +14,6 @@ pub enum Socks5ClientError {
|
||||
#[error("Failed to validate the loaded config")]
|
||||
ConfigValidationFailure,
|
||||
|
||||
#[error("Failed local version check, client and config mismatch")]
|
||||
FailedLocalVersionCheck,
|
||||
|
||||
#[error("Fail to bind address")]
|
||||
FailToBindAddress,
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ pub mod v3;
|
||||
pub mod v4;
|
||||
|
||||
mod error;
|
||||
mod util;
|
||||
|
||||
pub use error::Error;
|
||||
pub use v4 as latest;
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) mod tests {
|
||||
pub(crate) const CREDENTIAL_BYTES: [u8; 1245] = [
|
||||
0, 0, 4, 133, 96, 179, 223, 185, 136, 23, 213, 166, 59, 203, 66, 69, 209, 181, 227, 254,
|
||||
16, 102, 98, 237, 59, 119, 170, 111, 31, 194, 51, 59, 120, 17, 115, 229, 79, 91, 11, 139,
|
||||
154, 2, 212, 23, 68, 70, 167, 3, 240, 54, 224, 171, 221, 1, 69, 48, 60, 118, 119, 249, 123,
|
||||
35, 172, 227, 131, 96, 232, 209, 187, 123, 4, 197, 102, 90, 96, 45, 125, 135, 140, 99, 1,
|
||||
151, 17, 131, 143, 157, 97, 107, 139, 232, 212, 87, 14, 115, 253, 255, 166, 167, 186, 43,
|
||||
90, 96, 173, 105, 120, 40, 10, 163, 250, 224, 214, 200, 178, 4, 160, 16, 130, 59, 76, 193,
|
||||
39, 240, 3, 101, 141, 209, 183, 226, 186, 207, 56, 210, 187, 7, 164, 240, 164, 205, 37, 81,
|
||||
184, 214, 193, 195, 90, 205, 238, 225, 195, 104, 12, 123, 203, 57, 233, 243, 215, 145, 195,
|
||||
196, 57, 38, 125, 172, 18, 47, 63, 165, 110, 219, 180, 40, 58, 116, 92, 254, 160, 98, 48,
|
||||
92, 254, 232, 107, 184, 80, 234, 60, 160, 235, 249, 76, 41, 38, 165, 28, 40, 136, 74, 48,
|
||||
166, 50, 245, 23, 201, 140, 101, 79, 93, 235, 128, 186, 146, 126, 180, 134, 43, 13, 186,
|
||||
19, 195, 48, 168, 201, 29, 216, 95, 176, 198, 132, 188, 64, 39, 212, 150, 32, 52, 53, 38,
|
||||
228, 199, 122, 226, 217, 75, 40, 191, 151, 48, 164, 242, 177, 79, 14, 122, 105, 151, 85,
|
||||
88, 199, 162, 17, 96, 103, 83, 178, 128, 9, 24, 30, 74, 108, 241, 85, 240, 166, 97, 241,
|
||||
85, 199, 11, 198, 226, 234, 70, 107, 145, 28, 208, 114, 51, 12, 234, 108, 101, 202, 112,
|
||||
48, 185, 22, 159, 67, 109, 49, 27, 149, 90, 109, 32, 226, 112, 7, 201, 208, 209, 104, 31,
|
||||
97, 134, 204, 145, 27, 181, 206, 181, 106, 32, 110, 136, 115, 249, 201, 111, 5, 245, 203,
|
||||
71, 121, 169, 126, 151, 178, 236, 59, 221, 195, 48, 135, 115, 6, 50, 227, 74, 97, 107, 107,
|
||||
213, 90, 2, 203, 154, 138, 47, 128, 52, 134, 128, 224, 51, 65, 240, 90, 8, 55, 175, 180,
|
||||
178, 204, 206, 168, 110, 51, 57, 189, 169, 48, 169, 136, 121, 99, 51, 170, 178, 214, 74, 1,
|
||||
96, 151, 167, 25, 173, 180, 171, 155, 10, 55, 142, 234, 190, 113, 90, 79, 80, 244, 71, 166,
|
||||
30, 235, 113, 150, 133, 1, 218, 17, 109, 111, 223, 24, 216, 177, 41, 2, 204, 65, 221, 212,
|
||||
207, 236, 144, 6, 65, 224, 55, 42, 1, 1, 161, 134, 118, 127, 111, 220, 110, 127, 240, 71,
|
||||
223, 129, 12, 93, 20, 220, 60, 56, 71, 146, 184, 95, 132, 69, 28, 56, 53, 192, 213, 22,
|
||||
119, 230, 152, 225, 182, 188, 163, 219, 37, 175, 247, 73, 14, 247, 38, 72, 243, 1, 48, 131,
|
||||
59, 8, 13, 96, 143, 185, 127, 241, 161, 217, 24, 149, 193, 40, 16, 30, 202, 151, 28, 119,
|
||||
240, 153, 101, 156, 61, 193, 72, 245, 199, 181, 12, 231, 65, 166, 67, 142, 121, 207, 202,
|
||||
58, 197, 113, 188, 248, 42, 124, 105, 48, 161, 241, 55, 209, 36, 194, 27, 63, 233, 144,
|
||||
189, 85, 117, 234, 9, 139, 46, 31, 206, 114, 95, 131, 29, 240, 13, 81, 142, 140, 133, 33,
|
||||
30, 41, 141, 37, 80, 217, 95, 221, 76, 115, 86, 201, 165, 51, 252, 9, 28, 209, 1, 48, 150,
|
||||
74, 248, 212, 187, 222, 66, 210, 3, 200, 19, 217, 171, 184, 42, 148, 53, 150, 57, 50, 6,
|
||||
227, 227, 62, 49, 42, 148, 148, 157, 82, 191, 58, 24, 34, 56, 98, 120, 89, 105, 176, 85,
|
||||
15, 253, 241, 41, 153, 195, 136, 1, 48, 142, 126, 213, 101, 223, 79, 133, 230, 105, 38,
|
||||
161, 149, 2, 21, 136, 150, 42, 72, 218, 85, 146, 63, 223, 58, 108, 186, 183, 248, 62, 20,
|
||||
47, 34, 113, 160, 177, 204, 181, 16, 24, 212, 224, 35, 84, 51, 168, 56, 136, 11, 1, 48,
|
||||
135, 242, 62, 149, 230, 178, 32, 224, 119, 26, 234, 163, 237, 224, 114, 95, 112, 140, 170,
|
||||
150, 96, 125, 136, 221, 180, 78, 18, 11, 12, 184, 2, 198, 217, 119, 43, 69, 4, 172, 109,
|
||||
55, 183, 40, 131, 172, 161, 88, 183, 101, 1, 48, 173, 216, 22, 73, 42, 255, 211, 93, 249,
|
||||
87, 159, 115, 61, 91, 55, 130, 17, 216, 60, 34, 122, 55, 8, 244, 244, 153, 151, 57, 5, 144,
|
||||
178, 55, 249, 64, 211, 168, 34, 148, 56, 89, 92, 203, 70, 124, 219, 152, 253, 165, 0, 32,
|
||||
203, 116, 63, 7, 240, 222, 82, 86, 11, 149, 167, 72, 224, 55, 190, 66, 201, 65, 168, 184,
|
||||
96, 47, 194, 241, 168, 124, 7, 74, 214, 250, 37, 76, 32, 218, 69, 122, 103, 215, 145, 169,
|
||||
24, 212, 229, 168, 106, 10, 144, 31, 13, 25, 178, 242, 250, 106, 159, 40, 48, 163, 165, 61,
|
||||
130, 57, 146, 4, 73, 32, 254, 233, 125, 135, 212, 29, 111, 4, 177, 114, 15, 210, 170, 82,
|
||||
108, 110, 62, 166, 81, 209, 106, 176, 156, 14, 133, 242, 60, 127, 120, 242, 28, 97, 0, 1,
|
||||
32, 103, 93, 109, 89, 240, 91, 1, 84, 150, 50, 206, 157, 203, 49, 220, 120, 234, 175, 234,
|
||||
150, 126, 225, 94, 163, 164, 199, 138, 114, 62, 99, 106, 112, 1, 32, 171, 40, 220, 82, 241,
|
||||
203, 76, 146, 111, 139, 182, 179, 237, 182, 115, 75, 128, 201, 107, 43, 214, 0, 135, 217,
|
||||
160, 68, 150, 232, 144, 114, 237, 98, 32, 30, 134, 232, 59, 93, 163, 253, 244, 13, 202, 52,
|
||||
147, 168, 83, 121, 123, 95, 21, 210, 209, 225, 223, 143, 49, 10, 205, 238, 1, 22, 83, 81,
|
||||
70, 1, 32, 26, 76, 6, 234, 160, 50, 139, 102, 161, 232, 155, 106, 130, 171, 226, 210, 233,
|
||||
178, 85, 247, 71, 123, 55, 53, 46, 67, 148, 137, 156, 207, 208, 107, 1, 32, 102, 31, 4, 98,
|
||||
110, 156, 144, 61, 229, 140, 198, 84, 196, 238, 128, 35, 131, 182, 137, 125, 241, 95, 69,
|
||||
131, 170, 27, 2, 144, 75, 72, 242, 102, 3, 32, 121, 80, 45, 173, 56, 65, 218, 27, 40, 251,
|
||||
197, 32, 169, 104, 123, 110, 90, 78, 153, 166, 38, 9, 129, 228, 99, 8, 1, 116, 142, 233,
|
||||
162, 69, 32, 216, 169, 159, 116, 95, 12, 63, 176, 195, 6, 183, 123, 135, 75, 61, 112, 106,
|
||||
83, 235, 176, 41, 27, 248, 48, 71, 165, 170, 12, 92, 103, 103, 81, 32, 58, 74, 75, 145,
|
||||
192, 94, 153, 69, 80, 128, 241, 3, 16, 117, 192, 86, 161, 103, 44, 174, 211, 196, 182, 124,
|
||||
55, 11, 107, 142, 49, 88, 6, 41, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
|
||||
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
|
||||
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0, 37, 139, 240, 0, 0,
|
||||
0, 0, 0, 0, 0, 1,
|
||||
];
|
||||
pub(crate) const RECIPIENT: &str = "CytBseW6yFXUMzz4SGAKdNLGR7q3sJLLYxyBGvutNEQV.4QXYyEVc5fUDjmmi8PrHN9tdUFV4PCvSJE1278cHyvoe@4sBbL1ngf1vtNqykydQKTFh26sQCw888GpUqvPvyNB4f";
|
||||
}
|
||||
@@ -29,7 +29,7 @@ pub type Taken = Option<SystemTime>;
|
||||
|
||||
pub const BANDWIDTH_CAP_PER_DAY: u64 = 1024 * 1024 * 1024; // 1 GB
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
|
||||
pub struct InitMessage {
|
||||
/// Base64 encoded x25519 public key
|
||||
pub pub_key: PeerPublicKey,
|
||||
@@ -41,7 +41,7 @@ impl InitMessage {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
|
||||
pub struct FinalMessage {
|
||||
/// Gateway client data
|
||||
pub gateway_client: GatewayClient,
|
||||
@@ -50,28 +50,28 @@ pub struct FinalMessage {
|
||||
pub credential: Option<CredentialSpendingData>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
|
||||
pub struct RegistrationData {
|
||||
pub nonce: u64,
|
||||
pub gateway_data: GatewayClient,
|
||||
pub wg_port: u16,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
|
||||
pub struct RegistredData {
|
||||
pub pub_key: PeerPublicKey,
|
||||
pub private_ip: IpAddr,
|
||||
pub wg_port: u16,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
|
||||
pub struct RemainingBandwidthData {
|
||||
pub available_bandwidth: i64,
|
||||
}
|
||||
|
||||
/// Client that wants to register sends its PublicKey bytes mac digest encrypted with a DH shared secret.
|
||||
/// Gateway/Nym node can then verify pub_key payload using the same process
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
|
||||
pub struct GatewayClient {
|
||||
/// Base64 encoded x25519 public key
|
||||
pub pub_key: PeerPublicKey,
|
||||
@@ -147,7 +147,7 @@ impl GatewayClient {
|
||||
|
||||
// TODO: change the inner type into generic array of size HmacSha256::OutputSize
|
||||
// TODO2: rely on our internal crypto/hmac
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct ClientMac(Vec<u8>);
|
||||
|
||||
impl fmt::Display for ClientMac {
|
||||
|
||||
@@ -87,7 +87,7 @@ impl AuthenticatorRequest {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
pub enum AuthenticatorRequestData {
|
||||
Initial(InitMessage),
|
||||
Final(Box<FinalMessage>),
|
||||
|
||||
@@ -100,28 +100,28 @@ impl AuthenticatorResponse {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
pub enum AuthenticatorResponseData {
|
||||
PendingRegistration(PendingRegistrationResponse),
|
||||
Registered(RegisteredResponse),
|
||||
RemainingBandwidth(RemainingBandwidthResponse),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
pub struct PendingRegistrationResponse {
|
||||
pub request_id: u64,
|
||||
pub reply_to: Recipient,
|
||||
pub reply: RegistrationData,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
pub struct RegisteredResponse {
|
||||
pub request_id: u64,
|
||||
pub reply_to: Recipient,
|
||||
pub reply: RegistredData,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
pub struct RemainingBandwidthResponse {
|
||||
pub request_id: u64,
|
||||
pub reply_to: Recipient,
|
||||
|
||||
@@ -19,6 +19,24 @@ impl From<v2::request::AuthenticatorRequest> for v3::request::AuthenticatorReque
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<v3::request::AuthenticatorRequest> for v2::request::AuthenticatorRequest {
|
||||
type Error = crate::Error;
|
||||
|
||||
fn try_from(
|
||||
authenticator_request: v3::request::AuthenticatorRequest,
|
||||
) -> Result<Self, Self::Error> {
|
||||
Ok(Self {
|
||||
protocol: Protocol {
|
||||
version: 2,
|
||||
service_provider_type: ServiceProviderType::Authenticator,
|
||||
},
|
||||
data: authenticator_request.data.try_into()?,
|
||||
reply_to: authenticator_request.reply_to,
|
||||
request_id: authenticator_request.request_id,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl From<v2::request::AuthenticatorRequestData> for v3::request::AuthenticatorRequestData {
|
||||
fn from(authenticator_request_data: v2::request::AuthenticatorRequestData) -> Self {
|
||||
match authenticator_request_data {
|
||||
@@ -35,6 +53,29 @@ impl From<v2::request::AuthenticatorRequestData> for v3::request::AuthenticatorR
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<v3::request::AuthenticatorRequestData> for v2::request::AuthenticatorRequestData {
|
||||
type Error = crate::Error;
|
||||
|
||||
fn try_from(
|
||||
authenticator_request_data: v3::request::AuthenticatorRequestData,
|
||||
) -> Result<Self, Self::Error> {
|
||||
match authenticator_request_data {
|
||||
v3::request::AuthenticatorRequestData::Initial(init_msg) => Ok(
|
||||
v2::request::AuthenticatorRequestData::Initial(init_msg.into()),
|
||||
),
|
||||
v3::request::AuthenticatorRequestData::Final(gw_client) => Ok(
|
||||
v2::request::AuthenticatorRequestData::Final(gw_client.into()),
|
||||
),
|
||||
v3::request::AuthenticatorRequestData::QueryBandwidth(pub_key) => Ok(
|
||||
v2::request::AuthenticatorRequestData::QueryBandwidth(pub_key),
|
||||
),
|
||||
v3::request::AuthenticatorRequestData::TopUpBandwidth(_) => Err(
|
||||
Self::Error::Conversion("no top up bandwidth variant in v2".to_string()),
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<v2::registration::InitMessage> for v3::registration::InitMessage {
|
||||
fn from(init_msg: v2::registration::InitMessage) -> Self {
|
||||
Self {
|
||||
@@ -43,6 +84,14 @@ impl From<v2::registration::InitMessage> for v3::registration::InitMessage {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<v3::registration::InitMessage> for v2::registration::InitMessage {
|
||||
fn from(init_msg: v3::registration::InitMessage) -> Self {
|
||||
Self {
|
||||
pub_key: init_msg.pub_key,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Box<v2::registration::FinalMessage>> for Box<v3::registration::FinalMessage> {
|
||||
fn from(gw_client: Box<v2::registration::FinalMessage>) -> Self {
|
||||
Box::new(v3::registration::FinalMessage {
|
||||
@@ -52,6 +101,15 @@ impl From<Box<v2::registration::FinalMessage>> for Box<v3::registration::FinalMe
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Box<v3::registration::FinalMessage>> for Box<v2::registration::FinalMessage> {
|
||||
fn from(gw_client: Box<v3::registration::FinalMessage>) -> Self {
|
||||
Box::new(v2::registration::FinalMessage {
|
||||
gateway_client: gw_client.gateway_client.into(),
|
||||
credential: gw_client.credential,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl From<v2::registration::GatewayClient> for v3::registration::GatewayClient {
|
||||
fn from(gw_client: v2::registration::GatewayClient) -> Self {
|
||||
Self {
|
||||
@@ -93,7 +151,10 @@ impl TryFrom<v3::response::AuthenticatorResponse> for v2::response::Authenticato
|
||||
Ok(Self {
|
||||
data: authenticator_response.data.try_into()?,
|
||||
reply_to: authenticator_response.reply_to,
|
||||
protocol: authenticator_response.protocol,
|
||||
protocol: Protocol {
|
||||
version: 2,
|
||||
service_provider_type: authenticator_response.protocol.service_provider_type,
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -101,7 +162,10 @@ impl TryFrom<v3::response::AuthenticatorResponse> for v2::response::Authenticato
|
||||
impl From<v2::response::AuthenticatorResponse> for v3::response::AuthenticatorResponse {
|
||||
fn from(value: v2::response::AuthenticatorResponse) -> Self {
|
||||
Self {
|
||||
protocol: value.protocol,
|
||||
protocol: Protocol {
|
||||
version: 3,
|
||||
service_provider_type: value.protocol.service_provider_type,
|
||||
},
|
||||
data: value.data.into(),
|
||||
reply_to: value.reply_to,
|
||||
}
|
||||
@@ -270,3 +334,511 @@ impl From<v2::registration::RemainingBandwidthData> for v3::registration::Remain
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::{net::IpAddr, str::FromStr};
|
||||
|
||||
use nym_credentials_interface::CredentialSpendingData;
|
||||
use nym_crypto::asymmetric::encryption::PrivateKey;
|
||||
use nym_sphinx::addressing::Recipient;
|
||||
use nym_wireguard_types::PeerPublicKey;
|
||||
use x25519_dalek::PublicKey;
|
||||
|
||||
use super::*;
|
||||
use crate::util::tests::{CREDENTIAL_BYTES, RECIPIENT};
|
||||
|
||||
#[test]
|
||||
fn upgrade_initial_req() {
|
||||
let pub_key = PeerPublicKey::new(PublicKey::from([0; 32]));
|
||||
let reply_to = Recipient::try_from_base58_string(RECIPIENT).unwrap();
|
||||
|
||||
let (msg, _) = v2::request::AuthenticatorRequest::new_initial_request(
|
||||
v2::registration::InitMessage::new(pub_key),
|
||||
reply_to,
|
||||
);
|
||||
let upgraded_msg = v3::request::AuthenticatorRequest::from(msg);
|
||||
|
||||
assert_eq!(
|
||||
upgraded_msg.protocol,
|
||||
Protocol {
|
||||
version: 3,
|
||||
service_provider_type: ServiceProviderType::Authenticator
|
||||
}
|
||||
);
|
||||
assert_eq!(
|
||||
upgraded_msg.data,
|
||||
v3::request::AuthenticatorRequestData::Initial(v3::registration::InitMessage {
|
||||
pub_key
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn downgrade_initial_req() {
|
||||
let pub_key = PeerPublicKey::new(PublicKey::from([0; 32]));
|
||||
let reply_to = Recipient::try_from_base58_string(RECIPIENT).unwrap();
|
||||
|
||||
let (msg, _) = v3::request::AuthenticatorRequest::new_initial_request(
|
||||
v3::registration::InitMessage::new(pub_key),
|
||||
reply_to,
|
||||
);
|
||||
let downgraded_msg = v2::request::AuthenticatorRequest::try_from(msg).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
downgraded_msg.protocol,
|
||||
Protocol {
|
||||
version: 2,
|
||||
service_provider_type: ServiceProviderType::Authenticator
|
||||
}
|
||||
);
|
||||
assert_eq!(
|
||||
downgraded_msg.data,
|
||||
v2::request::AuthenticatorRequestData::Initial(v2::registration::InitMessage {
|
||||
pub_key
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn upgrade_final_req() {
|
||||
let mut rng = rand::thread_rng();
|
||||
|
||||
let local_secret = PrivateKey::new(&mut rng);
|
||||
let remote_secret = x25519_dalek::StaticSecret::random_from_rng(&mut rng);
|
||||
let private_ip = IpAddr::from_str("10.10.10.10").unwrap();
|
||||
let nonce = 42;
|
||||
let gateway_client = v2::registration::GatewayClient::new(
|
||||
&local_secret,
|
||||
(&remote_secret).into(),
|
||||
private_ip,
|
||||
nonce,
|
||||
);
|
||||
let credential = Some(CredentialSpendingData::try_from_bytes(&CREDENTIAL_BYTES).unwrap());
|
||||
let final_message = v2::registration::FinalMessage {
|
||||
gateway_client,
|
||||
credential: credential.clone(),
|
||||
};
|
||||
let reply_to = Recipient::try_from_base58_string(RECIPIENT).unwrap();
|
||||
|
||||
let (msg, _) =
|
||||
v2::request::AuthenticatorRequest::new_final_request(final_message, reply_to);
|
||||
let upgraded_msg = v3::request::AuthenticatorRequest::from(msg);
|
||||
|
||||
assert_eq!(
|
||||
upgraded_msg.protocol,
|
||||
Protocol {
|
||||
version: 3,
|
||||
service_provider_type: ServiceProviderType::Authenticator
|
||||
}
|
||||
);
|
||||
assert_eq!(
|
||||
upgraded_msg.data,
|
||||
v3::request::AuthenticatorRequestData::Final(Box::new(
|
||||
v3::registration::FinalMessage {
|
||||
gateway_client: v3::registration::GatewayClient::new(
|
||||
&local_secret,
|
||||
(&remote_secret).into(),
|
||||
private_ip,
|
||||
nonce,
|
||||
),
|
||||
credential
|
||||
}
|
||||
))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn downgrade_final_req() {
|
||||
let mut rng = rand::thread_rng();
|
||||
|
||||
let local_secret = PrivateKey::new(&mut rng);
|
||||
let remote_secret = x25519_dalek::StaticSecret::random_from_rng(&mut rng);
|
||||
let private_ip = IpAddr::from_str("10.10.10.10").unwrap();
|
||||
let nonce = 42;
|
||||
let gateway_client = v3::registration::GatewayClient::new(
|
||||
&local_secret,
|
||||
(&remote_secret).into(),
|
||||
private_ip,
|
||||
nonce,
|
||||
);
|
||||
let credential = Some(CredentialSpendingData::try_from_bytes(&CREDENTIAL_BYTES).unwrap());
|
||||
let final_message = v3::registration::FinalMessage {
|
||||
gateway_client,
|
||||
credential: credential.clone(),
|
||||
};
|
||||
let reply_to = Recipient::try_from_base58_string(RECIPIENT).unwrap();
|
||||
|
||||
let (msg, _) =
|
||||
v3::request::AuthenticatorRequest::new_final_request(final_message, reply_to);
|
||||
let upgraded_msg = v2::request::AuthenticatorRequest::try_from(msg).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
upgraded_msg.protocol,
|
||||
Protocol {
|
||||
version: 2,
|
||||
service_provider_type: ServiceProviderType::Authenticator
|
||||
}
|
||||
);
|
||||
assert_eq!(
|
||||
upgraded_msg.data,
|
||||
v2::request::AuthenticatorRequestData::Final(Box::new(
|
||||
v2::registration::FinalMessage {
|
||||
gateway_client: v2::registration::GatewayClient::new(
|
||||
&local_secret,
|
||||
(&remote_secret).into(),
|
||||
private_ip,
|
||||
nonce,
|
||||
),
|
||||
credential
|
||||
}
|
||||
))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn upgrade_query_req() {
|
||||
let pub_key = PeerPublicKey::new(PublicKey::from([0; 32]));
|
||||
let reply_to = Recipient::try_from_base58_string(RECIPIENT).unwrap();
|
||||
|
||||
let (msg, _) = v2::request::AuthenticatorRequest::new_query_request(pub_key, reply_to);
|
||||
let upgraded_msg = v3::request::AuthenticatorRequest::from(msg);
|
||||
|
||||
assert_eq!(
|
||||
upgraded_msg.protocol,
|
||||
Protocol {
|
||||
version: 3,
|
||||
service_provider_type: ServiceProviderType::Authenticator
|
||||
}
|
||||
);
|
||||
assert_eq!(
|
||||
upgraded_msg.data,
|
||||
v3::request::AuthenticatorRequestData::QueryBandwidth(pub_key)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn downgrade_query_req() {
|
||||
let pub_key = PeerPublicKey::new(PublicKey::from([0; 32]));
|
||||
let reply_to = Recipient::try_from_base58_string(RECIPIENT).unwrap();
|
||||
|
||||
let (msg, _) = v3::request::AuthenticatorRequest::new_query_request(pub_key, reply_to);
|
||||
let downgraded_msg = v2::request::AuthenticatorRequest::try_from(msg).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
downgraded_msg.protocol,
|
||||
Protocol {
|
||||
version: 2,
|
||||
service_provider_type: ServiceProviderType::Authenticator
|
||||
}
|
||||
);
|
||||
assert_eq!(
|
||||
downgraded_msg.data,
|
||||
v2::request::AuthenticatorRequestData::QueryBandwidth(pub_key)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn downgrade_topup_req() {
|
||||
let pub_key = PeerPublicKey::new(PublicKey::from([0; 32]));
|
||||
let credential = CredentialSpendingData::try_from_bytes(&CREDENTIAL_BYTES).unwrap();
|
||||
let top_up_message = v3::topup::TopUpMessage {
|
||||
pub_key,
|
||||
credential,
|
||||
};
|
||||
let reply_to = Recipient::try_from_base58_string(RECIPIENT).unwrap();
|
||||
|
||||
let (msg, _) =
|
||||
v3::request::AuthenticatorRequest::new_topup_request(top_up_message, reply_to);
|
||||
assert!(v2::request::AuthenticatorRequest::try_from(msg).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn upgrade_pending_reg_resp() {
|
||||
let mut rng = rand::thread_rng();
|
||||
|
||||
let local_secret = PrivateKey::new(&mut rng);
|
||||
let remote_secret = x25519_dalek::StaticSecret::random_from_rng(&mut rng);
|
||||
let private_ip = IpAddr::from_str("10.10.10.10").unwrap();
|
||||
let nonce = 42;
|
||||
let wg_port = 51822;
|
||||
let gateway_data = v2::registration::GatewayClient::new(
|
||||
&local_secret,
|
||||
(&remote_secret).into(),
|
||||
private_ip,
|
||||
nonce,
|
||||
);
|
||||
let registration_data = v2::registration::RegistrationData {
|
||||
nonce,
|
||||
gateway_data,
|
||||
wg_port,
|
||||
};
|
||||
let request_id = 123;
|
||||
let reply_to = Recipient::try_from_base58_string(RECIPIENT).unwrap();
|
||||
|
||||
let msg = v2::response::AuthenticatorResponse::new_pending_registration_success(
|
||||
registration_data,
|
||||
request_id,
|
||||
reply_to,
|
||||
);
|
||||
let upgraded_msg = v3::response::AuthenticatorResponse::from(msg);
|
||||
|
||||
assert_eq!(
|
||||
upgraded_msg.protocol,
|
||||
Protocol {
|
||||
version: 3,
|
||||
service_provider_type: ServiceProviderType::Authenticator
|
||||
}
|
||||
);
|
||||
assert_eq!(
|
||||
upgraded_msg.data,
|
||||
v3::response::AuthenticatorResponseData::PendingRegistration(
|
||||
v3::response::PendingRegistrationResponse {
|
||||
request_id,
|
||||
reply_to,
|
||||
reply: v3::registration::RegistrationData {
|
||||
nonce,
|
||||
gateway_data: v3::registration::GatewayClient::new(
|
||||
&local_secret,
|
||||
(&remote_secret).into(),
|
||||
private_ip,
|
||||
nonce,
|
||||
),
|
||||
wg_port,
|
||||
}
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn downgrade_pending_reg_resp() {
|
||||
let mut rng = rand::thread_rng();
|
||||
|
||||
let local_secret = PrivateKey::new(&mut rng);
|
||||
let remote_secret = x25519_dalek::StaticSecret::random_from_rng(&mut rng);
|
||||
let private_ip = IpAddr::from_str("10.10.10.10").unwrap();
|
||||
let nonce = 42;
|
||||
let wg_port = 51822;
|
||||
let gateway_data = v3::registration::GatewayClient::new(
|
||||
&local_secret,
|
||||
(&remote_secret).into(),
|
||||
private_ip,
|
||||
nonce,
|
||||
);
|
||||
let registration_data = v3::registration::RegistrationData {
|
||||
nonce,
|
||||
gateway_data,
|
||||
wg_port,
|
||||
};
|
||||
let request_id = 123;
|
||||
let reply_to = Recipient::try_from_base58_string(RECIPIENT).unwrap();
|
||||
|
||||
let msg = v3::response::AuthenticatorResponse::new_pending_registration_success(
|
||||
registration_data,
|
||||
request_id,
|
||||
reply_to,
|
||||
);
|
||||
let downgraded_msg = v2::response::AuthenticatorResponse::try_from(msg).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
downgraded_msg.protocol,
|
||||
Protocol {
|
||||
version: 2,
|
||||
service_provider_type: ServiceProviderType::Authenticator
|
||||
}
|
||||
);
|
||||
assert_eq!(
|
||||
downgraded_msg.data,
|
||||
v2::response::AuthenticatorResponseData::PendingRegistration(
|
||||
v2::response::PendingRegistrationResponse {
|
||||
request_id,
|
||||
reply_to,
|
||||
reply: v2::registration::RegistrationData {
|
||||
nonce,
|
||||
gateway_data: v2::registration::GatewayClient::new(
|
||||
&local_secret,
|
||||
(&remote_secret).into(),
|
||||
private_ip,
|
||||
nonce,
|
||||
),
|
||||
wg_port,
|
||||
}
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn upgrade_registered_resp() {
|
||||
let pub_key = PeerPublicKey::new(PublicKey::from([0; 32]));
|
||||
let private_ip = IpAddr::from_str("10.10.10.10").unwrap();
|
||||
let wg_port = 51822;
|
||||
let registred_data = v2::registration::RegistredData {
|
||||
pub_key,
|
||||
private_ip,
|
||||
wg_port,
|
||||
};
|
||||
let request_id = 123;
|
||||
let reply_to = Recipient::try_from_base58_string(RECIPIENT).unwrap();
|
||||
|
||||
let msg = v2::response::AuthenticatorResponse::new_registered(
|
||||
registred_data,
|
||||
reply_to,
|
||||
request_id,
|
||||
);
|
||||
let upgraded_msg = v3::response::AuthenticatorResponse::from(msg);
|
||||
|
||||
assert_eq!(
|
||||
upgraded_msg.protocol,
|
||||
Protocol {
|
||||
version: 3,
|
||||
service_provider_type: ServiceProviderType::Authenticator
|
||||
}
|
||||
);
|
||||
assert_eq!(
|
||||
upgraded_msg.data,
|
||||
v3::response::AuthenticatorResponseData::Registered(v3::response::RegisteredResponse {
|
||||
request_id,
|
||||
reply_to,
|
||||
reply: v3::registration::RegistredData {
|
||||
wg_port,
|
||||
pub_key,
|
||||
private_ip
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn downgrade_registered_resp() {
|
||||
let pub_key = PeerPublicKey::new(PublicKey::from([0; 32]));
|
||||
let private_ip = IpAddr::from_str("10.10.10.10").unwrap();
|
||||
let wg_port = 51822;
|
||||
let registred_data = v3::registration::RegistredData {
|
||||
pub_key,
|
||||
private_ip,
|
||||
wg_port,
|
||||
};
|
||||
let request_id = 123;
|
||||
let reply_to = Recipient::try_from_base58_string(RECIPIENT).unwrap();
|
||||
|
||||
let msg = v3::response::AuthenticatorResponse::new_registered(
|
||||
registred_data,
|
||||
reply_to,
|
||||
request_id,
|
||||
);
|
||||
let downgraded_msg = v2::response::AuthenticatorResponse::try_from(msg).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
downgraded_msg.protocol,
|
||||
Protocol {
|
||||
version: 2,
|
||||
service_provider_type: ServiceProviderType::Authenticator
|
||||
}
|
||||
);
|
||||
assert_eq!(
|
||||
downgraded_msg.data,
|
||||
v2::response::AuthenticatorResponseData::Registered(v2::response::RegisteredResponse {
|
||||
request_id,
|
||||
reply_to,
|
||||
reply: v2::registration::RegistredData {
|
||||
wg_port,
|
||||
pub_key,
|
||||
private_ip
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn upgrade_remaining_bandwidth_resp() {
|
||||
let available_bandwidth = 42;
|
||||
let remaining_bandwidth_data = Some(v2::registration::RemainingBandwidthData {
|
||||
available_bandwidth,
|
||||
});
|
||||
let request_id = 123;
|
||||
let reply_to = Recipient::try_from_base58_string(RECIPIENT).unwrap();
|
||||
|
||||
let msg = v2::response::AuthenticatorResponse::new_remaining_bandwidth(
|
||||
remaining_bandwidth_data,
|
||||
reply_to,
|
||||
request_id,
|
||||
);
|
||||
let upgraded_msg = v3::response::AuthenticatorResponse::from(msg);
|
||||
|
||||
assert_eq!(
|
||||
upgraded_msg.protocol,
|
||||
Protocol {
|
||||
version: 3,
|
||||
service_provider_type: ServiceProviderType::Authenticator
|
||||
}
|
||||
);
|
||||
assert_eq!(
|
||||
upgraded_msg.data,
|
||||
v3::response::AuthenticatorResponseData::RemainingBandwidth(
|
||||
v3::response::RemainingBandwidthResponse {
|
||||
request_id,
|
||||
reply_to,
|
||||
reply: Some(v3::registration::RemainingBandwidthData {
|
||||
available_bandwidth,
|
||||
})
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn downgrade_remaining_bandwidth_resp() {
|
||||
let available_bandwidth = 42;
|
||||
let remaining_bandwidth_data = Some(v3::registration::RemainingBandwidthData {
|
||||
available_bandwidth,
|
||||
});
|
||||
let request_id = 123;
|
||||
let reply_to = Recipient::try_from_base58_string(RECIPIENT).unwrap();
|
||||
|
||||
let msg = v3::response::AuthenticatorResponse::new_remaining_bandwidth(
|
||||
remaining_bandwidth_data,
|
||||
reply_to,
|
||||
request_id,
|
||||
);
|
||||
let downgraded_msg = v2::response::AuthenticatorResponse::try_from(msg).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
downgraded_msg.protocol,
|
||||
Protocol {
|
||||
version: 2,
|
||||
service_provider_type: ServiceProviderType::Authenticator
|
||||
}
|
||||
);
|
||||
assert_eq!(
|
||||
downgraded_msg.data,
|
||||
v2::response::AuthenticatorResponseData::RemainingBandwidth(
|
||||
v2::response::RemainingBandwidthResponse {
|
||||
request_id,
|
||||
reply_to,
|
||||
reply: Some(v2::registration::RemainingBandwidthData {
|
||||
available_bandwidth,
|
||||
})
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn downgrade_topup_resp() {
|
||||
let available_bandwidth = 42;
|
||||
let remaining_bandwidth_data = v3::registration::RemainingBandwidthData {
|
||||
available_bandwidth,
|
||||
};
|
||||
let request_id = 123;
|
||||
let reply_to = Recipient::try_from_base58_string(RECIPIENT).unwrap();
|
||||
|
||||
let msg = v3::response::AuthenticatorResponse::new_topup_bandwidth(
|
||||
remaining_bandwidth_data,
|
||||
reply_to,
|
||||
request_id,
|
||||
);
|
||||
assert!(v2::response::AuthenticatorResponse::try_from(msg).is_err());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ pub type Taken = Option<SystemTime>;
|
||||
|
||||
pub const BANDWIDTH_CAP_PER_DAY: u64 = 250 * 1024 * 1024 * 1024; // 250 GB
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
|
||||
pub struct InitMessage {
|
||||
/// Base64 encoded x25519 public key
|
||||
pub pub_key: PeerPublicKey,
|
||||
@@ -41,7 +41,7 @@ impl InitMessage {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
|
||||
pub struct FinalMessage {
|
||||
/// Gateway client data
|
||||
pub gateway_client: GatewayClient,
|
||||
@@ -50,28 +50,28 @@ pub struct FinalMessage {
|
||||
pub credential: Option<CredentialSpendingData>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
|
||||
pub struct RegistrationData {
|
||||
pub nonce: u64,
|
||||
pub gateway_data: GatewayClient,
|
||||
pub wg_port: u16,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
|
||||
pub struct RegistredData {
|
||||
pub pub_key: PeerPublicKey,
|
||||
pub private_ip: IpAddr,
|
||||
pub wg_port: u16,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
|
||||
pub struct RemainingBandwidthData {
|
||||
pub available_bandwidth: i64,
|
||||
}
|
||||
|
||||
/// Client that wants to register sends its PublicKey bytes mac digest encrypted with a DH shared secret.
|
||||
/// Gateway/Nym node can then verify pub_key payload using the same process
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
|
||||
pub struct GatewayClient {
|
||||
/// Base64 encoded x25519 public key
|
||||
pub pub_key: PeerPublicKey,
|
||||
@@ -147,7 +147,7 @@ impl GatewayClient {
|
||||
|
||||
// TODO: change the inner type into generic array of size HmacSha256::OutputSize
|
||||
// TODO2: rely on our internal crypto/hmac
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct ClientMac(Vec<u8>);
|
||||
|
||||
impl fmt::Display for ClientMac {
|
||||
|
||||
@@ -106,7 +106,7 @@ impl AuthenticatorRequest {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
pub enum AuthenticatorRequestData {
|
||||
Initial(InitMessage),
|
||||
Final(Box<FinalMessage>),
|
||||
|
||||
@@ -120,7 +120,7 @@ impl AuthenticatorResponse {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
pub enum AuthenticatorResponseData {
|
||||
PendingRegistration(PendingRegistrationResponse),
|
||||
Registered(RegisteredResponse),
|
||||
@@ -128,28 +128,28 @@ pub enum AuthenticatorResponseData {
|
||||
TopUpBandwidth(TopUpBandwidthResponse),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
pub struct PendingRegistrationResponse {
|
||||
pub request_id: u64,
|
||||
pub reply_to: Recipient,
|
||||
pub reply: RegistrationData,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
pub struct RegisteredResponse {
|
||||
pub request_id: u64,
|
||||
pub reply_to: Recipient,
|
||||
pub reply: RegistredData,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
pub struct RemainingBandwidthResponse {
|
||||
pub request_id: u64,
|
||||
pub reply_to: Recipient,
|
||||
pub reply: Option<RemainingBandwidthData>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
pub struct TopUpBandwidthResponse {
|
||||
pub request_id: u64,
|
||||
pub reply_to: Recipient,
|
||||
|
||||
@@ -5,7 +5,7 @@ use nym_credentials_interface::CredentialSpendingData;
|
||||
use nym_wireguard_types::PeerPublicKey;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
|
||||
pub struct TopUpMessage {
|
||||
/// Base64 encoded x25519 public key
|
||||
pub pub_key: PeerPublicKey,
|
||||
|
||||
@@ -3,37 +3,82 @@
|
||||
|
||||
use nym_service_provider_requests_common::{Protocol, ServiceProviderType};
|
||||
|
||||
use crate::{v2, v3, v4};
|
||||
use crate::{v3, v4};
|
||||
|
||||
impl From<v3::request::AuthenticatorRequest> for v4::request::AuthenticatorRequest {
|
||||
fn from(authenticator_request: v3::request::AuthenticatorRequest) -> Self {
|
||||
Self {
|
||||
impl TryFrom<v3::request::AuthenticatorRequest> for v4::request::AuthenticatorRequest {
|
||||
type Error = crate::Error;
|
||||
fn try_from(
|
||||
authenticator_request: v3::request::AuthenticatorRequest,
|
||||
) -> Result<Self, Self::Error> {
|
||||
Ok(Self {
|
||||
protocol: Protocol {
|
||||
version: 4,
|
||||
service_provider_type: ServiceProviderType::Authenticator,
|
||||
},
|
||||
data: authenticator_request.data.into(),
|
||||
data: authenticator_request.data.try_into()?,
|
||||
reply_to: authenticator_request.reply_to,
|
||||
request_id: authenticator_request.request_id,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<v4::request::AuthenticatorRequest> for v3::request::AuthenticatorRequest {
|
||||
type Error = crate::Error;
|
||||
fn try_from(
|
||||
authenticator_request: v4::request::AuthenticatorRequest,
|
||||
) -> Result<Self, Self::Error> {
|
||||
Ok(Self {
|
||||
protocol: Protocol {
|
||||
version: 3,
|
||||
service_provider_type: ServiceProviderType::Authenticator,
|
||||
},
|
||||
data: authenticator_request.data.try_into()?,
|
||||
reply_to: authenticator_request.reply_to,
|
||||
request_id: authenticator_request.request_id,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<v3::request::AuthenticatorRequestData> for v4::request::AuthenticatorRequestData {
|
||||
type Error = crate::Error;
|
||||
fn try_from(
|
||||
authenticator_request_data: v3::request::AuthenticatorRequestData,
|
||||
) -> Result<Self, Self::Error> {
|
||||
match authenticator_request_data {
|
||||
v3::request::AuthenticatorRequestData::Initial(init_msg) => Ok(
|
||||
v4::request::AuthenticatorRequestData::Initial(init_msg.into()),
|
||||
),
|
||||
v3::request::AuthenticatorRequestData::Final(_) => Err(Self::Error::Conversion(
|
||||
"mac hash breaking change".to_string(),
|
||||
)),
|
||||
v3::request::AuthenticatorRequestData::QueryBandwidth(pub_key) => Ok(
|
||||
v4::request::AuthenticatorRequestData::QueryBandwidth(pub_key),
|
||||
),
|
||||
v3::request::AuthenticatorRequestData::TopUpBandwidth(top_up_message) => Ok(
|
||||
v4::request::AuthenticatorRequestData::TopUpBandwidth(top_up_message.into()),
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<v3::request::AuthenticatorRequestData> for v4::request::AuthenticatorRequestData {
|
||||
fn from(authenticator_request_data: v3::request::AuthenticatorRequestData) -> Self {
|
||||
impl TryFrom<v4::request::AuthenticatorRequestData> for v3::request::AuthenticatorRequestData {
|
||||
type Error = crate::Error;
|
||||
fn try_from(
|
||||
authenticator_request_data: v4::request::AuthenticatorRequestData,
|
||||
) -> Result<Self, Self::Error> {
|
||||
match authenticator_request_data {
|
||||
v3::request::AuthenticatorRequestData::Initial(init_msg) => {
|
||||
v4::request::AuthenticatorRequestData::Initial(init_msg.into())
|
||||
}
|
||||
v3::request::AuthenticatorRequestData::Final(gw_client) => {
|
||||
v4::request::AuthenticatorRequestData::Final(gw_client.into())
|
||||
}
|
||||
v3::request::AuthenticatorRequestData::QueryBandwidth(pub_key) => {
|
||||
v4::request::AuthenticatorRequestData::QueryBandwidth(pub_key)
|
||||
}
|
||||
v3::request::AuthenticatorRequestData::TopUpBandwidth(top_up_message) => {
|
||||
v4::request::AuthenticatorRequestData::TopUpBandwidth(top_up_message.into())
|
||||
}
|
||||
v4::request::AuthenticatorRequestData::Initial(init_msg) => Ok(
|
||||
v3::request::AuthenticatorRequestData::Initial(init_msg.into()),
|
||||
),
|
||||
v4::request::AuthenticatorRequestData::Final(_) => Err(Self::Error::Conversion(
|
||||
"mac hash breaking change".to_string(),
|
||||
)),
|
||||
v4::request::AuthenticatorRequestData::QueryBandwidth(pub_key) => Ok(
|
||||
v3::request::AuthenticatorRequestData::QueryBandwidth(pub_key),
|
||||
),
|
||||
v4::request::AuthenticatorRequestData::TopUpBandwidth(top_up_message) => Ok(
|
||||
v3::request::AuthenticatorRequestData::TopUpBandwidth(top_up_message.into()),
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -46,12 +91,11 @@ impl From<v3::registration::InitMessage> for v4::registration::InitMessage {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Box<v3::registration::FinalMessage>> for Box<v4::registration::FinalMessage> {
|
||||
fn from(gw_client: Box<v3::registration::FinalMessage>) -> Self {
|
||||
Box::new(v4::registration::FinalMessage {
|
||||
gateway_client: gw_client.gateway_client.into(),
|
||||
credential: gw_client.credential,
|
||||
})
|
||||
impl From<v4::registration::InitMessage> for v3::registration::InitMessage {
|
||||
fn from(init_msg: v4::registration::InitMessage) -> Self {
|
||||
Self {
|
||||
pub_key: init_msg.pub_key,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,67 +108,26 @@ impl From<Box<v3::topup::TopUpMessage>> for Box<v4::topup::TopUpMessage> {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<v2::registration::GatewayClient> for v4::registration::GatewayClient {
|
||||
fn from(gw_client: v2::registration::GatewayClient) -> Self {
|
||||
Self {
|
||||
pub_key: gw_client.pub_key,
|
||||
private_ips: gw_client.private_ip.into(),
|
||||
mac: gw_client.mac.into(),
|
||||
}
|
||||
impl From<Box<v4::topup::TopUpMessage>> for Box<v3::topup::TopUpMessage> {
|
||||
fn from(top_up_message: Box<v4::topup::TopUpMessage>) -> Self {
|
||||
Box::new(v3::topup::TopUpMessage {
|
||||
pub_key: top_up_message.pub_key,
|
||||
credential: top_up_message.credential,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl From<v3::registration::GatewayClient> for v4::registration::GatewayClient {
|
||||
fn from(gw_client: v3::registration::GatewayClient) -> Self {
|
||||
Self {
|
||||
pub_key: gw_client.pub_key,
|
||||
private_ips: gw_client.private_ip.into(),
|
||||
mac: gw_client.mac.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<v4::registration::GatewayClient> for v3::registration::GatewayClient {
|
||||
fn from(gw_client: v4::registration::GatewayClient) -> Self {
|
||||
Self {
|
||||
pub_key: gw_client.pub_key,
|
||||
private_ip: gw_client.private_ips.ipv4.into(),
|
||||
mac: gw_client.mac.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<v4::registration::GatewayClient> for v2::registration::GatewayClient {
|
||||
fn from(gw_client: v4::registration::GatewayClient) -> Self {
|
||||
Self {
|
||||
pub_key: gw_client.pub_key,
|
||||
private_ip: gw_client.private_ips.ipv4.into(),
|
||||
mac: gw_client.mac.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<v2::registration::ClientMac> for v4::registration::ClientMac {
|
||||
fn from(mac: v2::registration::ClientMac) -> Self {
|
||||
Self::new(mac.to_vec())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<v3::registration::ClientMac> for v4::registration::ClientMac {
|
||||
fn from(mac: v3::registration::ClientMac) -> Self {
|
||||
Self::new(mac.to_vec())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<v4::registration::ClientMac> for v3::registration::ClientMac {
|
||||
fn from(mac: v4::registration::ClientMac) -> Self {
|
||||
Self::new(mac.to_vec())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<v4::registration::ClientMac> for v2::registration::ClientMac {
|
||||
fn from(mac: v4::registration::ClientMac) -> Self {
|
||||
Self::new(mac.to_vec())
|
||||
impl TryFrom<v3::response::AuthenticatorResponse> for v4::response::AuthenticatorResponse {
|
||||
type Error = crate::Error;
|
||||
fn try_from(value: v3::response::AuthenticatorResponse) -> Result<Self, Self::Error> {
|
||||
Ok(Self {
|
||||
protocol: Protocol {
|
||||
version: 4,
|
||||
service_provider_type: value.protocol.service_provider_type,
|
||||
},
|
||||
data: value.data.try_into()?,
|
||||
reply_to: value.reply_to,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,11 +140,40 @@ impl TryFrom<v4::response::AuthenticatorResponse> for v3::response::Authenticato
|
||||
Ok(Self {
|
||||
data: authenticator_response.data.try_into()?,
|
||||
reply_to: authenticator_response.reply_to,
|
||||
protocol: authenticator_response.protocol,
|
||||
protocol: 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 {
|
||||
type Error = crate::Error;
|
||||
|
||||
@@ -149,13 +181,10 @@ impl TryFrom<v4::response::AuthenticatorResponseData> for v3::response::Authenti
|
||||
authenticator_response_data: v4::response::AuthenticatorResponseData,
|
||||
) -> Result<Self, Self::Error> {
|
||||
match authenticator_response_data {
|
||||
v4::response::AuthenticatorResponseData::PendingRegistration(
|
||||
pending_registration_response,
|
||||
) => Ok(
|
||||
v3::response::AuthenticatorResponseData::PendingRegistration(
|
||||
pending_registration_response.into(),
|
||||
),
|
||||
v4::response::AuthenticatorResponseData::PendingRegistration(_) => Err(
|
||||
Self::Error::Conversion("mac hash breaking change".to_string()),
|
||||
),
|
||||
|
||||
v4::response::AuthenticatorResponseData::Registered(registered_response) => Ok(
|
||||
v3::response::AuthenticatorResponseData::Registered(registered_response.into()),
|
||||
),
|
||||
@@ -173,8 +202,8 @@ 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 {
|
||||
impl From<v4::response::RegisteredResponse> for v3::response::RegisteredResponse {
|
||||
fn from(value: v4::response::RegisteredResponse) -> Self {
|
||||
Self {
|
||||
request_id: value.request_id,
|
||||
reply_to: value.reply_to,
|
||||
@@ -183,8 +212,8 @@ impl From<v4::response::PendingRegistrationResponse> for v3::response::PendingRe
|
||||
}
|
||||
}
|
||||
|
||||
impl From<v4::response::RegisteredResponse> for v3::response::RegisteredResponse {
|
||||
fn from(value: v4::response::RegisteredResponse) -> Self {
|
||||
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,
|
||||
@@ -193,6 +222,16 @@ impl From<v4::response::RegisteredResponse> for v3::response::RegisteredResponse
|
||||
}
|
||||
}
|
||||
|
||||
impl From<v3::response::RemainingBandwidthResponse> for v4::response::RemainingBandwidthResponse {
|
||||
fn from(value: v3::response::RemainingBandwidthResponse) -> Self {
|
||||
Self {
|
||||
request_id: value.request_id,
|
||||
reply_to: value.reply_to,
|
||||
reply: value.reply.map(Into::into),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<v4::response::RemainingBandwidthResponse> for v3::response::RemainingBandwidthResponse {
|
||||
fn from(value: v4::response::RemainingBandwidthResponse) -> Self {
|
||||
Self {
|
||||
@@ -203,11 +242,31 @@ impl From<v4::response::RemainingBandwidthResponse> for v3::response::RemainingB
|
||||
}
|
||||
}
|
||||
|
||||
impl From<v4::registration::RegistrationData> for v3::registration::RegistrationData {
|
||||
fn from(value: v4::registration::RegistrationData) -> Self {
|
||||
impl From<v3::response::TopUpBandwidthResponse> for v4::response::TopUpBandwidthResponse {
|
||||
fn from(value: v3::response::TopUpBandwidthResponse) -> Self {
|
||||
Self {
|
||||
nonce: value.nonce,
|
||||
gateway_data: value.gateway_data.into(),
|
||||
request_id: value.request_id,
|
||||
reply_to: value.reply_to,
|
||||
reply: value.reply.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<v4::response::TopUpBandwidthResponse> for v3::response::TopUpBandwidthResponse {
|
||||
fn from(value: v4::response::TopUpBandwidthResponse) -> Self {
|
||||
Self {
|
||||
request_id: value.request_id,
|
||||
reply_to: value.reply_to,
|
||||
reply: value.reply.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<v3::registration::RegistredData> for v4::registration::RegistredData {
|
||||
fn from(value: v3::registration::RegistredData) -> Self {
|
||||
Self {
|
||||
pub_key: value.pub_key,
|
||||
private_ips: value.private_ip.into(),
|
||||
wg_port: value.wg_port,
|
||||
}
|
||||
}
|
||||
@@ -223,6 +282,14 @@ impl From<v4::registration::RegistredData> for v3::registration::RegistredData {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<v3::registration::RemainingBandwidthData> for v4::registration::RemainingBandwidthData {
|
||||
fn from(value: v3::registration::RemainingBandwidthData) -> Self {
|
||||
Self {
|
||||
available_bandwidth: value.available_bandwidth,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<v4::registration::RemainingBandwidthData> for v3::registration::RemainingBandwidthData {
|
||||
fn from(value: v4::registration::RemainingBandwidthData) -> Self {
|
||||
Self {
|
||||
@@ -230,3 +297,441 @@ 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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ pub type HmacSha256 = Hmac<Sha256>;
|
||||
pub type Nonce = u64;
|
||||
pub type Taken = Option<SystemTime>;
|
||||
|
||||
pub const BANDWIDTH_CAP_PER_DAY: u64 = 1024 * 1024 * 1024; // 1 GB
|
||||
pub const BANDWIDTH_CAP_PER_DAY: u64 = 250 * 1024 * 1024 * 1024; // 250 GB
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
pub struct IpPair {
|
||||
@@ -81,7 +81,7 @@ impl From<IpAddr> for IpPair {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
|
||||
pub struct InitMessage {
|
||||
/// Base64 encoded x25519 public key
|
||||
pub pub_key: PeerPublicKey,
|
||||
@@ -93,7 +93,7 @@ impl InitMessage {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
|
||||
pub struct FinalMessage {
|
||||
/// Gateway client data
|
||||
pub gateway_client: GatewayClient,
|
||||
@@ -102,28 +102,28 @@ pub struct FinalMessage {
|
||||
pub credential: Option<CredentialSpendingData>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
|
||||
pub struct RegistrationData {
|
||||
pub nonce: u64,
|
||||
pub gateway_data: GatewayClient,
|
||||
pub wg_port: u16,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
|
||||
pub struct RegistredData {
|
||||
pub pub_key: PeerPublicKey,
|
||||
pub private_ips: IpPair,
|
||||
pub wg_port: u16,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
|
||||
pub struct RemainingBandwidthData {
|
||||
pub available_bandwidth: i64,
|
||||
}
|
||||
|
||||
/// Client that wants to register sends its PublicKey bytes mac digest encrypted with a DH shared secret.
|
||||
/// Gateway/Nym node can then verify pub_key payload using the same process
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
|
||||
pub struct GatewayClient {
|
||||
/// Base64 encoded x25519 public key
|
||||
pub pub_key: PeerPublicKey,
|
||||
@@ -199,7 +199,7 @@ impl GatewayClient {
|
||||
|
||||
// TODO: change the inner type into generic array of size HmacSha256::OutputSize
|
||||
// TODO2: rely on our internal crypto/hmac
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct ClientMac(Vec<u8>);
|
||||
|
||||
impl fmt::Display for ClientMac {
|
||||
|
||||
@@ -20,7 +20,7 @@ fn generate_random() -> u64 {
|
||||
rng.next_u64()
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
pub struct AuthenticatorRequest {
|
||||
pub protocol: Protocol,
|
||||
pub data: AuthenticatorRequestData,
|
||||
@@ -106,7 +106,7 @@ impl AuthenticatorRequest {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
pub enum AuthenticatorRequestData {
|
||||
Initial(InitMessage),
|
||||
Final(Box<FinalMessage>),
|
||||
|
||||
@@ -10,7 +10,7 @@ use crate::make_bincode_serializer;
|
||||
|
||||
use super::VERSION;
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
pub struct AuthenticatorResponse {
|
||||
pub protocol: Protocol,
|
||||
pub data: AuthenticatorResponseData,
|
||||
@@ -120,7 +120,7 @@ impl AuthenticatorResponse {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
pub enum AuthenticatorResponseData {
|
||||
PendingRegistration(PendingRegistrationResponse),
|
||||
Registered(RegisteredResponse),
|
||||
@@ -128,28 +128,28 @@ pub enum AuthenticatorResponseData {
|
||||
TopUpBandwidth(TopUpBandwidthResponse),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
pub struct PendingRegistrationResponse {
|
||||
pub request_id: u64,
|
||||
pub reply_to: Recipient,
|
||||
pub reply: RegistrationData,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
pub struct RegisteredResponse {
|
||||
pub request_id: u64,
|
||||
pub reply_to: Recipient,
|
||||
pub reply: RegistredData,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
pub struct RemainingBandwidthResponse {
|
||||
pub request_id: u64,
|
||||
pub reply_to: Recipient,
|
||||
pub reply: Option<RemainingBandwidthData>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
pub struct TopUpBandwidthResponse {
|
||||
pub request_id: u64,
|
||||
pub reply_to: Recipient,
|
||||
|
||||
@@ -5,7 +5,7 @@ use nym_credentials_interface::CredentialSpendingData;
|
||||
use nym_wireguard_types::PeerPublicKey;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
|
||||
pub struct TopUpMessage {
|
||||
/// Base64 encoded x25519 public key
|
||||
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::nyxd::contract_traits::EcashSigningClient;
|
||||
use nym_validator_client::nyxd::contract_traits::{DkgQueryClient, EcashQueryClient};
|
||||
use nym_validator_client::nyxd::cosmwasm_client::ToSingletonContractData;
|
||||
use nym_validator_client::nyxd::cosmwasm_client::ContractResponseData;
|
||||
use nym_validator_client::EcashApiClient;
|
||||
use rand::rngs::OsRng;
|
||||
|
||||
|
||||
@@ -15,7 +15,6 @@ const-str = { workspace = true }
|
||||
log = { workspace = true }
|
||||
pretty_env_logger = { workspace = true }
|
||||
schemars = { workspace = true, features = ["preserve_order"], optional = true }
|
||||
semver.workspace = true
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
serde_json = { workspace = true, optional = true }
|
||||
|
||||
@@ -44,5 +43,5 @@ tracing = [
|
||||
"tracing-opentelemetry",
|
||||
"opentelemetry",
|
||||
]
|
||||
clap = [ "dep:clap", "dep:clap_complete", "dep:clap_complete_fig" ]
|
||||
clap = ["dep:clap", "dep:clap_complete", "dep:clap_complete_fig"]
|
||||
models = []
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
pub mod build_information;
|
||||
pub mod logging;
|
||||
pub mod version_checker;
|
||||
|
||||
#[cfg(feature = "clap")]
|
||||
pub mod completions;
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
// 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"));
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,10 @@ use crate::{
|
||||
},
|
||||
};
|
||||
use log::{debug, error};
|
||||
use sqlx::ConnectOptions;
|
||||
use sqlx::{
|
||||
sqlite::{SqliteAutoVacuum, SqliteSynchronous},
|
||||
ConnectOptions,
|
||||
};
|
||||
use std::path::Path;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@@ -30,6 +33,9 @@ impl StorageManager {
|
||||
}
|
||||
|
||||
let opts = sqlx::sqlite::SqliteConnectOptions::new()
|
||||
.journal_mode(sqlx::sqlite::SqliteJournalMode::Wal)
|
||||
.synchronous(SqliteSynchronous::Normal)
|
||||
.auto_vacuum(SqliteAutoVacuum::Incremental)
|
||||
.filename(database_path)
|
||||
.create_if_missing(true)
|
||||
.disable_statement_logging();
|
||||
@@ -110,7 +116,7 @@ impl StorageManager {
|
||||
) -> Result<(), sqlx::Error> {
|
||||
sqlx::query!(
|
||||
r#"
|
||||
INSERT INTO registered_gateway(gateway_id_bs58, registration_timestamp, gateway_type)
|
||||
INSERT INTO registered_gateway(gateway_id_bs58, registration_timestamp, gateway_type)
|
||||
VALUES (?, ?, ?)
|
||||
"#,
|
||||
registered_gateway.gateway_id_bs58,
|
||||
@@ -224,7 +230,7 @@ impl StorageManager {
|
||||
) -> Result<(), sqlx::Error> {
|
||||
sqlx::query!(
|
||||
r#"
|
||||
INSERT INTO custom_gateway_details(gateway_id_bs58, data)
|
||||
INSERT INTO custom_gateway_details(gateway_id_bs58, data)
|
||||
VALUES (?, ?)
|
||||
"#,
|
||||
custom.gateway_id_bs58,
|
||||
|
||||
@@ -115,8 +115,13 @@ where
|
||||
hardcoded_topology.get_gateways()
|
||||
} else {
|
||||
let mut rng = rand::thread_rng();
|
||||
crate::init::helpers::current_gateways(&mut rng, &core.client.nym_api_urls, user_agent)
|
||||
.await?
|
||||
crate::init::helpers::current_gateways(
|
||||
&mut rng,
|
||||
&core.client.nym_api_urls,
|
||||
user_agent,
|
||||
core.debug.topology.minimum_gateway_performance,
|
||||
)
|
||||
.await?
|
||||
};
|
||||
|
||||
// since we're registering with a brand new gateway,
|
||||
|
||||
@@ -170,8 +170,13 @@ where
|
||||
hardcoded_topology.get_gateways()
|
||||
} else {
|
||||
let mut rng = rand::thread_rng();
|
||||
crate::init::helpers::current_gateways(&mut rng, &core.client.nym_api_urls, user_agent)
|
||||
.await?
|
||||
crate::init::helpers::current_gateways(
|
||||
&mut rng,
|
||||
&core.client.nym_api_urls,
|
||||
user_agent,
|
||||
core.debug.topology.minimum_gateway_performance,
|
||||
)
|
||||
.await?
|
||||
};
|
||||
|
||||
let gateway_setup = GatewaySetup::New {
|
||||
|
||||
@@ -32,7 +32,7 @@ use crate::init::{
|
||||
setup_gateway,
|
||||
types::{GatewaySetup, InitialisationResult},
|
||||
};
|
||||
use crate::{config, spawn_future};
|
||||
use crate::{config, spawn_future, ForgetMe};
|
||||
use futures::channel::mpsc;
|
||||
use log::*;
|
||||
use nym_bandwidth_controller::BandwidthController;
|
||||
@@ -188,6 +188,11 @@ pub struct BaseClientBuilder<'a, C, S: MixnetClientStorage> {
|
||||
user_agent: Option<UserAgent>,
|
||||
|
||||
setup_method: GatewaySetup,
|
||||
|
||||
#[cfg(unix)]
|
||||
connection_fd_callback: Option<Arc<dyn Fn(RawFd) + Send + Sync>>,
|
||||
|
||||
forget_me: ForgetMe,
|
||||
}
|
||||
|
||||
impl<'a, C, S> BaseClientBuilder<'a, C, S>
|
||||
@@ -210,9 +215,18 @@ where
|
||||
shutdown: None,
|
||||
user_agent: None,
|
||||
setup_method: GatewaySetup::MustLoad { gateway_id: None },
|
||||
#[cfg(unix)]
|
||||
connection_fd_callback: None,
|
||||
forget_me: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn with_forget_me(mut self, forget_me: &ForgetMe) -> Self {
|
||||
self.forget_me = forget_me.clone();
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn with_gateway_setup(mut self, setup: GatewaySetup) -> Self {
|
||||
self.setup_method = setup;
|
||||
@@ -261,6 +275,15 @@ where
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
pub fn with_connection_fd_callback(
|
||||
mut self,
|
||||
callback: Arc<dyn Fn(RawFd) + Send + Sync>,
|
||||
) -> Self {
|
||||
self.connection_fd_callback = Some(callback);
|
||||
self
|
||||
}
|
||||
|
||||
// note: do **NOT** make this method public as its only valid usage is from within `start_base`
|
||||
// because it relies on the crypto keys being already loaded
|
||||
fn mix_address(details: &InitialisationResult) -> Recipient {
|
||||
@@ -352,6 +375,7 @@ where
|
||||
controller.start_with_shutdown(shutdown)
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
async fn start_gateway_client(
|
||||
config: &Config,
|
||||
initialisation_result: InitialisationResult,
|
||||
@@ -359,6 +383,7 @@ where
|
||||
details_store: &S::GatewaysDetailsStore,
|
||||
packet_router: PacketRouter,
|
||||
stats_reporter: ClientStatsSender,
|
||||
#[cfg(unix)] connection_fd_callback: Option<Arc<dyn Fn(RawFd) + Send + Sync>>,
|
||||
shutdown: TaskClient,
|
||||
) -> Result<GatewayClient<C, S::CredentialStore>, ClientCoreError>
|
||||
where
|
||||
@@ -401,6 +426,8 @@ where
|
||||
packet_router,
|
||||
bandwidth_controller,
|
||||
stats_reporter,
|
||||
#[cfg(unix)]
|
||||
connection_fd_callback,
|
||||
shutdown,
|
||||
)
|
||||
};
|
||||
@@ -462,6 +489,7 @@ where
|
||||
details_store: &S::GatewaysDetailsStore,
|
||||
packet_router: PacketRouter,
|
||||
stats_reporter: ClientStatsSender,
|
||||
#[cfg(unix)] connection_fd_callback: Option<Arc<dyn Fn(RawFd) + Send + Sync>>,
|
||||
mut shutdown: TaskClient,
|
||||
) -> Result<Box<dyn GatewayTransceiver + Send>, ClientCoreError>
|
||||
where
|
||||
@@ -493,6 +521,8 @@ where
|
||||
details_store,
|
||||
packet_router,
|
||||
stats_reporter,
|
||||
#[cfg(unix)]
|
||||
connection_fd_callback,
|
||||
shutdown,
|
||||
)
|
||||
.await?;
|
||||
@@ -514,15 +544,10 @@ where
|
||||
min_gateway_performance: config_topology.minimum_gateway_performance,
|
||||
},
|
||||
nym_api_urls,
|
||||
env!("CARGO_PKG_VERSION").to_string(),
|
||||
user_agent,
|
||||
)),
|
||||
config::TopologyStructure::GeoAware(group_by) => {
|
||||
Box::new(GeoAwareTopologyProvider::new(
|
||||
nym_api_urls,
|
||||
env!("CARGO_PKG_VERSION").to_string(),
|
||||
group_by,
|
||||
))
|
||||
Box::new(GeoAwareTopologyProvider::new(nym_api_urls, group_by))
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -620,9 +645,11 @@ where
|
||||
fn start_mix_traffic_controller(
|
||||
gateway_transceiver: Box<dyn GatewayTransceiver + Send>,
|
||||
shutdown: TaskClient,
|
||||
forget_me: ForgetMe,
|
||||
) -> BatchMixMessageSender {
|
||||
info!("Starting mix traffic controller...");
|
||||
let (mix_traffic_controller, mix_tx) = MixTrafficController::new(gateway_transceiver);
|
||||
let (mix_traffic_controller, mix_tx) =
|
||||
MixTrafficController::new(gateway_transceiver, forget_me);
|
||||
mix_traffic_controller.start_with_shutdown(shutdown);
|
||||
mix_tx
|
||||
}
|
||||
@@ -777,6 +804,8 @@ where
|
||||
&details_store,
|
||||
gateway_packet_router,
|
||||
stats_reporter.clone(),
|
||||
#[cfg(unix)]
|
||||
self.connection_fd_callback,
|
||||
shutdown.fork("gateway_transceiver"),
|
||||
)
|
||||
.await?;
|
||||
@@ -802,9 +831,11 @@ where
|
||||
// that are to be sent to the mixnet. They are used by cover traffic stream and real
|
||||
// traffic stream.
|
||||
// The MixTrafficController then sends the actual traffic
|
||||
|
||||
let message_sender = Self::start_mix_traffic_controller(
|
||||
gateway_transceiver,
|
||||
shutdown.fork("mix_traffic_controller"),
|
||||
self.forget_me,
|
||||
);
|
||||
|
||||
// Channels that the websocket listener can use to signal downstream to the real traffic
|
||||
|
||||
@@ -2,8 +2,9 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::client::mix_traffic::transceiver::GatewayTransceiver;
|
||||
use crate::spawn_future;
|
||||
use crate::{spawn_future, ForgetMe};
|
||||
use log::*;
|
||||
use nym_gateway_requests::ClientRequest;
|
||||
use nym_sphinx::forwarding::packet::MixPacket;
|
||||
|
||||
pub type BatchMixMessageSender = tokio::sync::mpsc::Sender<Vec<MixPacket>>;
|
||||
@@ -26,10 +27,14 @@ pub struct MixTrafficController {
|
||||
// TODO: this is temporary work-around.
|
||||
// in long run `gateway_client` will be moved away from `MixTrafficController` anyway.
|
||||
consecutive_gateway_failure_count: usize,
|
||||
forget_me: ForgetMe,
|
||||
}
|
||||
|
||||
impl MixTrafficController {
|
||||
pub fn new<T>(gateway_transceiver: T) -> (MixTrafficController, BatchMixMessageSender)
|
||||
pub fn new<T>(
|
||||
gateway_transceiver: T,
|
||||
forget_me: ForgetMe,
|
||||
) -> (MixTrafficController, BatchMixMessageSender)
|
||||
where
|
||||
T: GatewayTransceiver + Send + 'static,
|
||||
{
|
||||
@@ -40,6 +45,7 @@ impl MixTrafficController {
|
||||
gateway_transceiver: Box::new(gateway_transceiver),
|
||||
mix_rx: message_receiver,
|
||||
consecutive_gateway_failure_count: 0,
|
||||
forget_me,
|
||||
},
|
||||
message_sender,
|
||||
)
|
||||
@@ -47,6 +53,7 @@ impl MixTrafficController {
|
||||
|
||||
pub fn new_dynamic(
|
||||
gateway_transceiver: Box<dyn GatewayTransceiver + Send>,
|
||||
forget_me: ForgetMe,
|
||||
) -> (MixTrafficController, BatchMixMessageSender) {
|
||||
let (message_sender, message_receiver) =
|
||||
tokio::sync::mpsc::channel(MIX_MESSAGE_RECEIVER_BUFFER_SIZE);
|
||||
@@ -55,6 +62,7 @@ impl MixTrafficController {
|
||||
gateway_transceiver,
|
||||
mix_rx: message_receiver,
|
||||
consecutive_gateway_failure_count: 0,
|
||||
forget_me,
|
||||
},
|
||||
message_sender,
|
||||
)
|
||||
@@ -111,7 +119,27 @@ impl MixTrafficController {
|
||||
}
|
||||
}
|
||||
shutdown.recv_timeout().await;
|
||||
|
||||
if self.forget_me.any() {
|
||||
log::info!("Sending forget me request to the gateway");
|
||||
match self
|
||||
.gateway_transceiver
|
||||
.send_client_request(ClientRequest::ForgetMe {
|
||||
client: self.forget_me.client(),
|
||||
stats: self.forget_me.stats(),
|
||||
})
|
||||
.await
|
||||
{
|
||||
Ok(_) => {
|
||||
log::info!("Successfully sent forget me request to the gateway");
|
||||
}
|
||||
Err(err) => {
|
||||
log::error!("Failed to send forget me request to the gateway: {err}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log::debug!("MixTrafficController: Exiting");
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,8 +5,10 @@ use async_trait::async_trait;
|
||||
use log::{debug, error};
|
||||
use nym_credential_storage::storage::Storage as CredentialStorage;
|
||||
use nym_crypto::asymmetric::identity;
|
||||
use nym_gateway_client::error::GatewayClientError;
|
||||
use nym_gateway_client::GatewayClient;
|
||||
pub use nym_gateway_client::{GatewayPacketRouter, PacketRouter};
|
||||
use nym_gateway_requests::ClientRequest;
|
||||
use nym_sphinx::forwarding::packet::MixPacket;
|
||||
use nym_validator_client::nyxd::contract_traits::DkgQueryClient;
|
||||
use std::fmt::Debug;
|
||||
@@ -26,9 +28,14 @@ fn erase_err<E: std::error::Error + Send + Sync + 'static>(err: E) -> ErasedGate
|
||||
}
|
||||
|
||||
/// This combines combines the functionalities of being able to send and receive mix packets.
|
||||
#[async_trait]
|
||||
pub trait GatewayTransceiver: GatewaySender + GatewayReceiver {
|
||||
fn gateway_identity(&self) -> identity::PublicKey;
|
||||
fn ws_fd(&self) -> Option<RawFd>;
|
||||
async fn send_client_request(
|
||||
&mut self,
|
||||
message: ClientRequest,
|
||||
) -> Result<(), GatewayClientError>;
|
||||
}
|
||||
|
||||
/// This trait defines the functionality of sending `MixPacket` into the mixnet,
|
||||
@@ -65,6 +72,7 @@ pub trait GatewayReceiver {
|
||||
}
|
||||
|
||||
// to allow for dynamic dispatch
|
||||
#[async_trait]
|
||||
impl<G: GatewayTransceiver + ?Sized + Send> GatewayTransceiver for Box<G> {
|
||||
#[inline]
|
||||
fn gateway_identity(&self) -> identity::PublicKey {
|
||||
@@ -73,6 +81,13 @@ impl<G: GatewayTransceiver + ?Sized + Send> GatewayTransceiver for Box<G> {
|
||||
fn ws_fd(&self) -> Option<RawFd> {
|
||||
(**self).ws_fd()
|
||||
}
|
||||
|
||||
async fn send_client_request(
|
||||
&mut self,
|
||||
message: ClientRequest,
|
||||
) -> Result<(), GatewayClientError> {
|
||||
(**self).send_client_request(message).await
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
|
||||
@@ -91,7 +106,6 @@ impl<G: GatewaySender + ?Sized + Send> GatewaySender for Box<G> {
|
||||
(**self).batch_send_mix_packets(packets).await
|
||||
}
|
||||
}
|
||||
|
||||
impl<G: GatewayReceiver + ?Sized> GatewayReceiver for Box<G> {
|
||||
#[inline]
|
||||
fn set_packet_router(&mut self, packet_router: PacketRouter) -> Result<(), ErasedGatewayError> {
|
||||
@@ -111,6 +125,7 @@ impl<C, St> RemoteGateway<C, St> {
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<C, St> GatewayTransceiver for RemoteGateway<C, St>
|
||||
where
|
||||
C: DkgQueryClient + Send + Sync,
|
||||
@@ -123,6 +138,20 @@ where
|
||||
fn ws_fd(&self) -> Option<RawFd> {
|
||||
self.gateway_client.ws_fd()
|
||||
}
|
||||
|
||||
async fn send_client_request(
|
||||
&mut self,
|
||||
message: ClientRequest,
|
||||
) -> Result<(), GatewayClientError> {
|
||||
if let Some(shared_key) = self.gateway_client.shared_key() {
|
||||
self.gateway_client
|
||||
.send_websocket_message(message.encrypt(&*shared_key)?)
|
||||
.await?;
|
||||
Ok(())
|
||||
} else {
|
||||
Err(GatewayClientError::ConnectionInInvalidState)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
|
||||
@@ -195,6 +224,7 @@ impl LocalGateway {
|
||||
mod nonwasm_sealed {
|
||||
use super::*;
|
||||
|
||||
#[async_trait]
|
||||
impl GatewayTransceiver for LocalGateway {
|
||||
fn gateway_identity(&self) -> identity::PublicKey {
|
||||
self.local_identity
|
||||
@@ -202,6 +232,13 @@ mod nonwasm_sealed {
|
||||
fn ws_fd(&self) -> Option<RawFd> {
|
||||
None
|
||||
}
|
||||
|
||||
async fn send_client_request(
|
||||
&mut self,
|
||||
_message: ClientRequest,
|
||||
) -> Result<(), GatewayClientError> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
@@ -269,6 +306,7 @@ impl GatewaySender for MockGateway {
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl GatewayTransceiver for MockGateway {
|
||||
fn gateway_identity(&self) -> identity::PublicKey {
|
||||
self.dummy_identity
|
||||
@@ -276,4 +314,11 @@ impl GatewayTransceiver for MockGateway {
|
||||
fn ws_fd(&self) -> Option<RawFd> {
|
||||
None
|
||||
}
|
||||
|
||||
async fn send_client_request(
|
||||
&mut self,
|
||||
_message: ClientRequest,
|
||||
) -> Result<(), GatewayClientError> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,15 +85,10 @@ fn check_layer_integrity(topology: NymTopology) -> Result<(), ()> {
|
||||
pub struct GeoAwareTopologyProvider {
|
||||
validator_client: nym_validator_client::client::NymApiClient,
|
||||
filter_on: GroupBy,
|
||||
client_version: String,
|
||||
}
|
||||
|
||||
impl GeoAwareTopologyProvider {
|
||||
pub fn new(
|
||||
mut nym_api_urls: Vec<Url>,
|
||||
client_version: String,
|
||||
filter_on: GroupBy,
|
||||
) -> GeoAwareTopologyProvider {
|
||||
pub fn new(mut nym_api_urls: Vec<Url>, filter_on: GroupBy) -> GeoAwareTopologyProvider {
|
||||
log::info!(
|
||||
"Creating geo-aware topology provider with filter on {}",
|
||||
filter_on
|
||||
@@ -105,14 +100,13 @@ impl GeoAwareTopologyProvider {
|
||||
nym_api_urls[0].clone(),
|
||||
),
|
||||
filter_on,
|
||||
client_version,
|
||||
}
|
||||
}
|
||||
|
||||
async fn get_topology(&self) -> Option<NymTopology> {
|
||||
let mixnodes = match self
|
||||
.validator_client
|
||||
.get_all_basic_active_mixing_assigned_nodes(Some(self.client_version.clone()))
|
||||
.get_all_basic_active_mixing_assigned_nodes()
|
||||
.await
|
||||
{
|
||||
Err(err) => {
|
||||
@@ -124,7 +118,7 @@ impl GeoAwareTopologyProvider {
|
||||
|
||||
let gateways = match self
|
||||
.validator_client
|
||||
.get_all_basic_entry_assigned_nodes(Some(self.client_version.clone()))
|
||||
.get_all_basic_entry_assigned_nodes()
|
||||
.await
|
||||
{
|
||||
Err(err) => {
|
||||
|
||||
@@ -35,18 +35,11 @@ pub struct NymApiTopologyProvider {
|
||||
|
||||
validator_client: nym_validator_client::client::NymApiClient,
|
||||
nym_api_urls: Vec<Url>,
|
||||
|
||||
client_version: String,
|
||||
currently_used_api: usize,
|
||||
}
|
||||
|
||||
impl NymApiTopologyProvider {
|
||||
pub fn new(
|
||||
config: Config,
|
||||
mut nym_api_urls: Vec<Url>,
|
||||
client_version: String,
|
||||
user_agent: Option<UserAgent>,
|
||||
) -> Self {
|
||||
pub fn new(config: Config, mut nym_api_urls: Vec<Url>, user_agent: Option<UserAgent>) -> Self {
|
||||
nym_api_urls.shuffle(&mut thread_rng());
|
||||
|
||||
let validator_client = if let Some(user_agent) = user_agent {
|
||||
@@ -62,7 +55,6 @@ impl NymApiTopologyProvider {
|
||||
config,
|
||||
validator_client,
|
||||
nym_api_urls,
|
||||
client_version,
|
||||
currently_used_api: 0,
|
||||
}
|
||||
}
|
||||
@@ -99,7 +91,7 @@ impl NymApiTopologyProvider {
|
||||
async fn get_current_compatible_topology(&mut self) -> Option<NymTopology> {
|
||||
let mixnodes = match self
|
||||
.validator_client
|
||||
.get_all_basic_active_mixing_assigned_nodes(Some(self.client_version.clone()))
|
||||
.get_all_basic_active_mixing_assigned_nodes()
|
||||
.await
|
||||
{
|
||||
Err(err) => {
|
||||
@@ -111,7 +103,7 @@ impl NymApiTopologyProvider {
|
||||
|
||||
let gateways = match self
|
||||
.validator_client
|
||||
.get_all_basic_entry_assigned_nodes(Some(self.client_version.clone()))
|
||||
.get_all_basic_entry_assigned_nodes()
|
||||
.await
|
||||
{
|
||||
Err(err) => {
|
||||
|
||||
@@ -7,7 +7,7 @@ use futures::{SinkExt, StreamExt};
|
||||
use log::{debug, info, trace, warn};
|
||||
use nym_crypto::asymmetric::identity;
|
||||
use nym_gateway_client::GatewayClient;
|
||||
use nym_topology::{gateway, mix};
|
||||
use nym_topology::gateway;
|
||||
use nym_validator_client::client::IdentityKeyRef;
|
||||
use nym_validator_client::UserAgent;
|
||||
use rand::{seq::SliceRandom, Rng};
|
||||
@@ -82,6 +82,7 @@ pub async fn current_gateways<R: Rng>(
|
||||
rng: &mut R,
|
||||
nym_apis: &[Url],
|
||||
user_agent: Option<UserAgent>,
|
||||
minimum_performance: u8,
|
||||
) -> Result<Vec<gateway::LegacyNode>, ClientCoreError> {
|
||||
let nym_api = nym_apis
|
||||
.choose(rng)
|
||||
@@ -94,44 +95,27 @@ pub async fn current_gateways<R: Rng>(
|
||||
|
||||
log::debug!("Fetching list of gateways from: {nym_api}");
|
||||
|
||||
let gateways = client.get_all_basic_entry_assigned_nodes(None).await?;
|
||||
log::debug!("Found {} gateways", gateways.len());
|
||||
let gateways = client.get_all_basic_entry_assigned_nodes().await?;
|
||||
info!("nym api reports {} gateways", gateways.len());
|
||||
|
||||
log::trace!("Gateways: {:#?}", gateways);
|
||||
|
||||
let valid_gateways = gateways
|
||||
.iter()
|
||||
.filter(|g| g.performance.round_to_integer() >= minimum_performance)
|
||||
.filter_map(|gateway| gateway.try_into().ok())
|
||||
.collect::<Vec<gateway::LegacyNode>>();
|
||||
log::debug!("After checking validity: {}", valid_gateways.len());
|
||||
log::trace!("Valid gateways: {:#?}", valid_gateways);
|
||||
|
||||
log::info!("nym-api reports {} valid gateways", valid_gateways.len());
|
||||
log::info!(
|
||||
"and {} after validity and performance filtering",
|
||||
valid_gateways.len()
|
||||
);
|
||||
|
||||
Ok(valid_gateways)
|
||||
}
|
||||
|
||||
pub async fn current_mixnodes<R: Rng>(
|
||||
rng: &mut R,
|
||||
nym_apis: &[Url],
|
||||
) -> Result<Vec<mix::LegacyNode>, ClientCoreError> {
|
||||
let nym_api = nym_apis
|
||||
.choose(rng)
|
||||
.ok_or(ClientCoreError::ListOfNymApisIsEmpty)?;
|
||||
let client = nym_validator_client::client::NymApiClient::new(nym_api.clone());
|
||||
|
||||
log::trace!("Fetching list of mixnodes from: {nym_api}");
|
||||
|
||||
let mixnodes = client
|
||||
.get_all_basic_active_mixing_assigned_nodes(None)
|
||||
.await?;
|
||||
let valid_mixnodes = mixnodes
|
||||
.iter()
|
||||
.filter_map(|mixnode| mixnode.try_into().ok())
|
||||
.collect::<Vec<mix::LegacyNode>>();
|
||||
|
||||
Ok(valid_mixnodes)
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
async fn connect(endpoint: &str) -> Result<WsConn, ClientCoreError> {
|
||||
match tokio::time::timeout(CONN_TIMEOUT, connect_async(endpoint)).await {
|
||||
@@ -206,7 +190,7 @@ where
|
||||
Ok(GatewayWithLatency::new(gateway, avg))
|
||||
}
|
||||
|
||||
pub async fn choose_gateway_by_latency<'a, R: Rng, G: ConnectableGateway + Clone>(
|
||||
pub async fn choose_gateway_by_latency<R: Rng, G: ConnectableGateway + Clone>(
|
||||
rng: &mut R,
|
||||
gateways: &[G],
|
||||
must_use_tls: bool,
|
||||
|
||||
@@ -34,3 +34,48 @@ where
|
||||
{
|
||||
tokio::spawn(future);
|
||||
}
|
||||
|
||||
#[derive(Clone, Default, Debug)]
|
||||
pub struct ForgetMe {
|
||||
client: bool,
|
||||
stats: bool,
|
||||
}
|
||||
|
||||
impl ForgetMe {
|
||||
pub fn new_all() -> Self {
|
||||
Self {
|
||||
client: true,
|
||||
stats: true,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_client() -> Self {
|
||||
Self {
|
||||
client: true,
|
||||
stats: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_stats() -> Self {
|
||||
Self {
|
||||
client: false,
|
||||
stats: true,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(client: bool, stats: bool) -> Self {
|
||||
Self { client, stats }
|
||||
}
|
||||
|
||||
pub fn any(&self) -> bool {
|
||||
self.client || self.stats
|
||||
}
|
||||
|
||||
pub fn client(&self) -> bool {
|
||||
self.client
|
||||
}
|
||||
|
||||
pub fn stats(&self) -> bool {
|
||||
self.stats
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,10 @@ use crate::backend::fs_backend::{
|
||||
},
|
||||
};
|
||||
use log::{error, info};
|
||||
use sqlx::ConnectOptions;
|
||||
use sqlx::{
|
||||
sqlite::{SqliteAutoVacuum, SqliteSynchronous},
|
||||
ConnectOptions,
|
||||
};
|
||||
use std::path::Path;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@@ -31,6 +34,9 @@ impl StorageManager {
|
||||
}
|
||||
|
||||
let opts = sqlx::sqlite::SqliteConnectOptions::new()
|
||||
.journal_mode(sqlx::sqlite::SqliteJournalMode::Wal)
|
||||
.synchronous(SqliteSynchronous::Normal)
|
||||
.auto_vacuum(SqliteAutoVacuum::Incremental)
|
||||
.filename(database_path)
|
||||
.create_if_missing(fresh)
|
||||
.disable_statement_logging();
|
||||
|
||||
@@ -87,8 +87,10 @@ impl ClientBandwidth {
|
||||
|
||||
if remaining < 0 {
|
||||
tracing::warn!("OUT OF BANDWIDTH. remaining: {remaining_bi2}");
|
||||
} else {
|
||||
} else if remaining < 1_000_000 {
|
||||
tracing::info!("remaining bandwidth: {remaining_bi2}");
|
||||
} else {
|
||||
tracing::debug!("remaining bandwidth: {remaining_bi2}");
|
||||
}
|
||||
|
||||
self.inner
|
||||
|
||||
@@ -101,6 +101,10 @@ pub struct GatewayClient<C, St = EphemeralCredentialStorage> {
|
||||
// currently unused (but populated)
|
||||
negotiated_protocol: Option<u8>,
|
||||
|
||||
// Callback on the fd as soon as the connection has been established
|
||||
#[cfg(unix)]
|
||||
connection_fd_callback: Option<Arc<dyn Fn(RawFd) + Send + Sync>>,
|
||||
|
||||
/// Listen to shutdown messages and send notifications back to the task manager
|
||||
task_client: TaskClient,
|
||||
}
|
||||
@@ -116,6 +120,7 @@ impl<C, St> GatewayClient<C, St> {
|
||||
packet_router: PacketRouter,
|
||||
bandwidth_controller: Option<BandwidthController<C, St>>,
|
||||
stats_reporter: ClientStatsSender,
|
||||
#[cfg(unix)] connection_fd_callback: Option<Arc<dyn Fn(RawFd) + Send + Sync>>,
|
||||
task_client: TaskClient,
|
||||
) -> Self {
|
||||
GatewayClient {
|
||||
@@ -131,6 +136,8 @@ impl<C, St> GatewayClient<C, St> {
|
||||
bandwidth_controller,
|
||||
stats_reporter,
|
||||
negotiated_protocol: None,
|
||||
#[cfg(unix)]
|
||||
connection_fd_callback,
|
||||
task_client,
|
||||
}
|
||||
}
|
||||
@@ -139,6 +146,10 @@ impl<C, St> GatewayClient<C, St> {
|
||||
self.gateway_identity
|
||||
}
|
||||
|
||||
pub fn shared_key(&self) -> Option<Arc<SharedGatewayKey>> {
|
||||
self.shared_key.clone()
|
||||
}
|
||||
|
||||
pub fn ws_fd(&self) -> Option<RawFd> {
|
||||
match &self.connection {
|
||||
SocketState::Available(conn) => ws_fd(conn.as_ref()),
|
||||
@@ -201,6 +212,12 @@ impl<C, St> GatewayClient<C, St> {
|
||||
};
|
||||
|
||||
self.connection = SocketState::Available(Box::new(ws_stream));
|
||||
|
||||
#[cfg(unix)]
|
||||
if let (Some(callback), Some(fd)) = (self.connection_fd_callback.as_ref(), self.ws_fd()) {
|
||||
callback.as_ref()(fd);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -307,7 +324,7 @@ impl<C, St> GatewayClient<C, St> {
|
||||
|
||||
// If we want to send a message (with response), we need to have a full control over the socket,
|
||||
// as we need to be able to write the request and read the subsequent response
|
||||
async fn send_websocket_message(
|
||||
pub async fn send_websocket_message(
|
||||
&mut self,
|
||||
msg: impl Into<Message>,
|
||||
) -> Result<ServerResponse, GatewayClientError> {
|
||||
@@ -408,7 +425,7 @@ impl<C, St> GatewayClient<C, St> {
|
||||
}
|
||||
|
||||
Some(_) => {
|
||||
info!("the gateway is using exactly the same (or older) protocol version as we are. We're good to continue!");
|
||||
debug!("the gateway is using exactly the same (or older) protocol version as we are. We're good to continue!");
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -992,24 +1009,6 @@ impl<C, St> GatewayClient<C, St> {
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[deprecated(note = "this method does not deal with upgraded keys for legacy clients")]
|
||||
pub async fn authenticate_and_start(
|
||||
&mut self,
|
||||
) -> Result<AuthenticationResponse, GatewayClientError>
|
||||
where
|
||||
C: DkgQueryClient + Send + Sync,
|
||||
St: CredentialStorage,
|
||||
<St as CredentialStorage>::StorageError: Send + Sync + 'static,
|
||||
{
|
||||
let shared_key = self.perform_initial_authentication().await?;
|
||||
self.claim_initial_bandwidth().await?;
|
||||
|
||||
// this call is NON-blocking
|
||||
self.start_listening_for_mixnet_messages()?;
|
||||
|
||||
Ok(shared_key)
|
||||
}
|
||||
}
|
||||
|
||||
// type alias for an ease of use
|
||||
@@ -1048,6 +1047,8 @@ impl GatewayClient<InitOnly, EphemeralCredentialStorage> {
|
||||
bandwidth_controller: None,
|
||||
stats_reporter: ClientStatsSender::new(None),
|
||||
negotiated_protocol: None,
|
||||
#[cfg(unix)]
|
||||
connection_fd_callback: None,
|
||||
task_client,
|
||||
}
|
||||
}
|
||||
@@ -1078,6 +1079,8 @@ impl GatewayClient<InitOnly, EphemeralCredentialStorage> {
|
||||
bandwidth_controller,
|
||||
stats_reporter,
|
||||
negotiated_protocol: self.negotiated_protocol,
|
||||
#[cfg(unix)]
|
||||
connection_fd_callback: self.connection_fd_callback,
|
||||
task_client,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,6 +111,11 @@ impl PartiallyDelegatedRouter {
|
||||
}
|
||||
};
|
||||
|
||||
if self.stream_return.is_canceled() {
|
||||
// nothing to do, receiver has been dropped
|
||||
return;
|
||||
}
|
||||
|
||||
let return_res = match ret {
|
||||
Err(err) => self.stream_return.send(Err(err)),
|
||||
Ok(_) => {
|
||||
|
||||
@@ -8,10 +8,12 @@ license.workspace = true
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
dashmap = { workspace = true }
|
||||
futures = { workspace = true }
|
||||
tracing = { workspace = true }
|
||||
tokio = { workspace = true, features = ["time"] }
|
||||
tokio = { workspace = true, features = ["time", "sync"] }
|
||||
tokio-util = { workspace = true, features = ["codec"], optional = true }
|
||||
tokio-stream = { workspace = true }
|
||||
|
||||
# internal
|
||||
nym-sphinx = { path = "../../nymsphinx" }
|
||||
|
||||
@@ -1,21 +1,24 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2021-2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use futures::channel::mpsc;
|
||||
use dashmap::DashMap;
|
||||
use futures::StreamExt;
|
||||
use nym_sphinx::addressing::nodes::NymNodeRoutingAddress;
|
||||
use nym_sphinx::framing::codec::NymCodec;
|
||||
use nym_sphinx::framing::packet::FramedNymPacket;
|
||||
use nym_sphinx::params::PacketType;
|
||||
use nym_sphinx::NymPacket;
|
||||
use std::collections::HashMap;
|
||||
use std::io;
|
||||
use std::net::SocketAddr;
|
||||
use std::sync::atomic::{AtomicU32, Ordering};
|
||||
use std::ops::Deref;
|
||||
use std::sync::atomic::{AtomicU32, AtomicUsize, Ordering};
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use tokio::net::TcpStream;
|
||||
use tokio::sync::mpsc;
|
||||
use tokio::sync::mpsc::error::TrySendError;
|
||||
use tokio::time::sleep;
|
||||
use tokio_stream::wrappers::ReceiverStream;
|
||||
use tokio_util::codec::Framed;
|
||||
use tracing::*;
|
||||
|
||||
@@ -55,11 +58,37 @@ pub trait SendWithoutResponse {
|
||||
}
|
||||
|
||||
pub struct Client {
|
||||
conn_new: HashMap<NymNodeRoutingAddress, ConnectionSender>,
|
||||
active_connections: ActiveConnections,
|
||||
connections_count: Arc<AtomicUsize>,
|
||||
config: Config,
|
||||
}
|
||||
|
||||
struct ConnectionSender {
|
||||
#[derive(Default, Clone)]
|
||||
pub struct ActiveConnections {
|
||||
inner: Arc<DashMap<NymNodeRoutingAddress, ConnectionSender>>,
|
||||
}
|
||||
|
||||
impl ActiveConnections {
|
||||
pub fn pending_packets(&self) -> usize {
|
||||
self.inner
|
||||
.iter()
|
||||
.map(|sender| {
|
||||
let max_capacity = sender.channel.max_capacity();
|
||||
let capacity = sender.channel.capacity();
|
||||
max_capacity - capacity
|
||||
})
|
||||
.sum()
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for ActiveConnections {
|
||||
type Target = DashMap<NymNodeRoutingAddress, ConnectionSender>;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.inner
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ConnectionSender {
|
||||
channel: mpsc::Sender<FramedNymPacket>,
|
||||
current_reconnection_attempt: Arc<AtomicU32>,
|
||||
}
|
||||
@@ -73,46 +102,53 @@ impl ConnectionSender {
|
||||
}
|
||||
}
|
||||
|
||||
impl Client {
|
||||
pub fn new(config: Config) -> Client {
|
||||
Client {
|
||||
conn_new: HashMap::new(),
|
||||
config,
|
||||
struct ManagedConnection {
|
||||
address: SocketAddr,
|
||||
message_receiver: ReceiverStream<FramedNymPacket>,
|
||||
connection_timeout: Duration,
|
||||
current_reconnection: Arc<AtomicU32>,
|
||||
}
|
||||
|
||||
impl ManagedConnection {
|
||||
fn new(
|
||||
address: SocketAddr,
|
||||
message_receiver: mpsc::Receiver<FramedNymPacket>,
|
||||
connection_timeout: Duration,
|
||||
current_reconnection: Arc<AtomicU32>,
|
||||
) -> Self {
|
||||
ManagedConnection {
|
||||
address,
|
||||
message_receiver: ReceiverStream::new(message_receiver),
|
||||
connection_timeout,
|
||||
current_reconnection,
|
||||
}
|
||||
}
|
||||
|
||||
async fn manage_connection(
|
||||
address: SocketAddr,
|
||||
receiver: mpsc::Receiver<FramedNymPacket>,
|
||||
connection_timeout: Duration,
|
||||
current_reconnection: &AtomicU32,
|
||||
) {
|
||||
async fn run(self) {
|
||||
let address = self.address;
|
||||
let connection_fut = TcpStream::connect(address);
|
||||
|
||||
let conn = match tokio::time::timeout(connection_timeout, connection_fut).await {
|
||||
let conn = match tokio::time::timeout(self.connection_timeout, connection_fut).await {
|
||||
Ok(stream_res) => match stream_res {
|
||||
Ok(stream) => {
|
||||
debug!("Managed to establish connection to {}", address);
|
||||
debug!("Managed to establish connection to {}", self.address);
|
||||
// if we managed to connect, reset the reconnection count (whatever it might have been)
|
||||
current_reconnection.store(0, Ordering::Release);
|
||||
self.current_reconnection.store(0, Ordering::Release);
|
||||
Framed::new(stream, NymCodec)
|
||||
}
|
||||
Err(err) => {
|
||||
debug!(
|
||||
"failed to establish connection to {} (err: {})",
|
||||
address, err
|
||||
);
|
||||
debug!("failed to establish connection to {address} (err: {err})",);
|
||||
return;
|
||||
}
|
||||
},
|
||||
Err(_) => {
|
||||
debug!(
|
||||
"failed to connect to {} within {:?}",
|
||||
address, connection_timeout
|
||||
"failed to connect to {address} within {:?}",
|
||||
self.connection_timeout
|
||||
);
|
||||
|
||||
// we failed to connect - increase reconnection attempt
|
||||
current_reconnection.fetch_add(1, Ordering::SeqCst);
|
||||
self.current_reconnection.fetch_add(1, Ordering::SeqCst);
|
||||
return;
|
||||
}
|
||||
};
|
||||
@@ -120,15 +156,28 @@ impl Client {
|
||||
// Take whatever the receiver channel produces and put it on the connection.
|
||||
// We could have as well used conn.send_all(receiver.map(Ok)), but considering we don't care
|
||||
// about neither receiver nor the connection, it doesn't matter which one gets consumed
|
||||
if let Err(err) = receiver.map(Ok).forward(conn).await {
|
||||
warn!("Failed to forward packets to {} - {err}", address);
|
||||
if let Err(err) = self.message_receiver.map(Ok).forward(conn).await {
|
||||
warn!("Failed to forward packets to {address}: {err}");
|
||||
}
|
||||
|
||||
debug!(
|
||||
"connection manager to {} is finished. Either the connection failed or mixnet client got dropped",
|
||||
address
|
||||
"connection manager to {address} is finished. Either the connection failed or mixnet client got dropped",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
impl Client {
|
||||
pub fn new(config: Config, connections_count: Arc<AtomicUsize>) -> Client {
|
||||
Client {
|
||||
active_connections: Default::default(),
|
||||
connections_count,
|
||||
config,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn active_connections(&self) -> ActiveConnections {
|
||||
self.active_connections.clone()
|
||||
}
|
||||
|
||||
/// If we're trying to reconnect, determine how long we should wait.
|
||||
fn determine_backoff(&self, current_attempt: u32) -> Option<Duration> {
|
||||
@@ -148,7 +197,7 @@ impl Client {
|
||||
}
|
||||
|
||||
fn make_connection(&mut self, address: NymNodeRoutingAddress, pending_packet: FramedNymPacket) {
|
||||
let (mut sender, receiver) = mpsc::channel(self.config.maximum_connection_buffer_size);
|
||||
let (sender, receiver) = mpsc::channel(self.config.maximum_connection_buffer_size);
|
||||
|
||||
// this CAN'T fail because we just created the channel which has a non-zero capacity
|
||||
if self.config.maximum_connection_buffer_size > 0 {
|
||||
@@ -156,15 +205,16 @@ impl Client {
|
||||
}
|
||||
|
||||
// if we already tried to connect to `address` before, grab the current attempt count
|
||||
let current_reconnection_attempt = if let Some(existing) = self.conn_new.get_mut(&address) {
|
||||
existing.channel = sender;
|
||||
Arc::clone(&existing.current_reconnection_attempt)
|
||||
} else {
|
||||
let new_entry = ConnectionSender::new(sender);
|
||||
let current_attempt = Arc::clone(&new_entry.current_reconnection_attempt);
|
||||
self.conn_new.insert(address, new_entry);
|
||||
current_attempt
|
||||
};
|
||||
let current_reconnection_attempt =
|
||||
if let Some(mut existing) = self.active_connections.get_mut(&address) {
|
||||
existing.channel = sender;
|
||||
Arc::clone(&existing.current_reconnection_attempt)
|
||||
} else {
|
||||
let new_entry = ConnectionSender::new(sender);
|
||||
let current_attempt = Arc::clone(&new_entry.current_reconnection_attempt);
|
||||
self.active_connections.insert(address, new_entry);
|
||||
current_attempt
|
||||
};
|
||||
|
||||
// load the actual value.
|
||||
let reconnection_attempt = current_reconnection_attempt.load(Ordering::Acquire);
|
||||
@@ -173,6 +223,7 @@ impl Client {
|
||||
// copy the value before moving into another task
|
||||
let initial_connection_timeout = self.config.initial_connection_timeout;
|
||||
|
||||
let connections_count = self.connections_count.clone();
|
||||
tokio::spawn(async move {
|
||||
// before executing the manager, wait for what was specified, if anything
|
||||
if let Some(backoff) = backoff {
|
||||
@@ -180,13 +231,16 @@ impl Client {
|
||||
sleep(backoff).await;
|
||||
}
|
||||
|
||||
Self::manage_connection(
|
||||
connections_count.fetch_add(1, Ordering::SeqCst);
|
||||
ManagedConnection::new(
|
||||
address.into(),
|
||||
receiver,
|
||||
initial_connection_timeout,
|
||||
¤t_reconnection_attempt,
|
||||
current_reconnection_attempt,
|
||||
)
|
||||
.await
|
||||
.run()
|
||||
.await;
|
||||
connections_count.fetch_sub(1, Ordering::SeqCst);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -201,49 +255,47 @@ impl SendWithoutResponse for Client {
|
||||
trace!("Sending packet to {address:?}");
|
||||
let framed_packet = FramedNymPacket::new(packet, packet_type);
|
||||
|
||||
if let Some(sender) = self.conn_new.get_mut(&address) {
|
||||
if let Err(err) = sender.channel.try_send(framed_packet) {
|
||||
if err.is_full() {
|
||||
debug!("Connection to {} seems to not be able to handle all the traffic - dropping the current packet", address);
|
||||
// it's not a 'big' error, but we did not manage to send the packet
|
||||
// if the queue is full, we can't really do anything but to drop the packet
|
||||
Err(io::Error::new(
|
||||
io::ErrorKind::WouldBlock,
|
||||
"connection queue is full",
|
||||
))
|
||||
} else if err.is_disconnected() {
|
||||
debug!(
|
||||
"Connection to {} seems to be dead. attempting to re-establish it...",
|
||||
address
|
||||
);
|
||||
// it's not a 'big' error, but we did not manage to send the packet, but queue
|
||||
// it up to send it as soon as the connection is re-established
|
||||
self.make_connection(address, err.into_inner());
|
||||
Err(io::Error::new(
|
||||
io::ErrorKind::ConnectionAborted,
|
||||
"reconnection attempt is in progress",
|
||||
))
|
||||
} else {
|
||||
// this can't really happen, but let's safe-guard against it in case something changes in futures library
|
||||
Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
"unknown connection buffer error",
|
||||
))
|
||||
}
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
} else {
|
||||
let Some(sender) = self.active_connections.get_mut(&address) else {
|
||||
// there was never a connection to begin with
|
||||
debug!("establishing initial connection to {}", address);
|
||||
// it's not a 'big' error, but we did not manage to send the packet, but queue the packet
|
||||
// for sending for as soon as the connection is created
|
||||
self.make_connection(address, framed_packet);
|
||||
Err(io::Error::new(
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::NotConnected,
|
||||
"connection is in progress",
|
||||
))
|
||||
}
|
||||
));
|
||||
};
|
||||
|
||||
let sending_res = sender.channel.try_send(framed_packet);
|
||||
drop(sender);
|
||||
|
||||
sending_res.map_err(|err| {
|
||||
match err {
|
||||
TrySendError::Full(_) => {
|
||||
debug!("Connection to {address} seems to not be able to handle all the traffic - dropping the current packet");
|
||||
// it's not a 'big' error, but we did not manage to send the packet
|
||||
// if the queue is full, we can't really do anything but to drop the packet
|
||||
io::Error::new(
|
||||
io::ErrorKind::WouldBlock,
|
||||
"connection queue is full",
|
||||
)
|
||||
}
|
||||
TrySendError::Closed(dropped) => {
|
||||
debug!(
|
||||
"Connection to {address} seems to be dead. attempting to re-establish it...",
|
||||
);
|
||||
|
||||
// it's not a 'big' error, but we did not manage to send the packet, but queue
|
||||
// it up to send it as soon as the connection is re-established
|
||||
self.make_connection(address, dropped);
|
||||
io::Error::new(
|
||||
io::ErrorKind::ConnectionAborted,
|
||||
"reconnection attempt is in progress",
|
||||
)
|
||||
}
|
||||
}
|
||||
} )
|
||||
}
|
||||
}
|
||||
|
||||
@@ -252,12 +304,15 @@ mod tests {
|
||||
use super::*;
|
||||
|
||||
fn dummy_client() -> Client {
|
||||
Client::new(Config {
|
||||
initial_reconnection_backoff: Duration::from_millis(10_000),
|
||||
maximum_reconnection_backoff: Duration::from_millis(300_000),
|
||||
initial_connection_timeout: Duration::from_millis(1_500),
|
||||
maximum_connection_buffer_size: 128,
|
||||
})
|
||||
Client::new(
|
||||
Config {
|
||||
initial_reconnection_backoff: Duration::from_millis(10_000),
|
||||
maximum_reconnection_backoff: Duration::from_millis(300_000),
|
||||
initial_connection_timeout: Duration::from_millis(1_500),
|
||||
maximum_connection_buffer_size: 128,
|
||||
},
|
||||
Default::default(),
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -19,8 +19,8 @@ use nym_api_requests::ecash::{
|
||||
PartialExpirationDateSignatureResponse, VerificationKeyResponse,
|
||||
};
|
||||
use nym_api_requests::models::{
|
||||
ApiHealthResponse, GatewayCoreStatusResponse, MixnodeCoreStatusResponse, MixnodeStatusResponse,
|
||||
NymNodeDescription, RewardEstimationResponse, StakeSaturationResponse,
|
||||
ApiHealthResponse, GatewayBondAnnotated, GatewayCoreStatusResponse, MixnodeCoreStatusResponse,
|
||||
MixnodeStatusResponse, NymNodeDescription, RewardEstimationResponse, StakeSaturationResponse,
|
||||
};
|
||||
use nym_api_requests::models::{LegacyDescribedGateway, MixNodeBondAnnotated};
|
||||
use nym_api_requests::nym_nodes::SkimmedNode;
|
||||
@@ -257,6 +257,13 @@ impl<C, S> Client<C, S> {
|
||||
Ok(self.nym_api.get_gateways().await?)
|
||||
}
|
||||
|
||||
#[deprecated]
|
||||
pub async fn get_cached_gateways_detailed_unfiltered(
|
||||
&self,
|
||||
) -> Result<Vec<GatewayBondAnnotated>, ValidatorClientError> {
|
||||
Ok(self.nym_api.get_gateways_detailed_unfiltered().await?)
|
||||
}
|
||||
|
||||
// TODO: combine with NymApiClient...
|
||||
pub async fn get_all_cached_described_nodes(
|
||||
&self,
|
||||
@@ -351,34 +358,19 @@ impl NymApiClient {
|
||||
}
|
||||
|
||||
#[deprecated(note = "use get_all_basic_active_mixing_assigned_nodes instead")]
|
||||
pub async fn get_basic_mixnodes(
|
||||
&self,
|
||||
semver_compatibility: Option<String>,
|
||||
) -> Result<Vec<SkimmedNode>, ValidatorClientError> {
|
||||
Ok(self
|
||||
.nym_api
|
||||
.get_basic_mixnodes(semver_compatibility)
|
||||
.await?
|
||||
.nodes)
|
||||
pub async fn get_basic_mixnodes(&self) -> Result<Vec<SkimmedNode>, ValidatorClientError> {
|
||||
Ok(self.nym_api.get_basic_mixnodes().await?.nodes)
|
||||
}
|
||||
|
||||
#[deprecated(note = "use get_all_basic_entry_assigned_nodes instead")]
|
||||
pub async fn get_basic_gateways(
|
||||
&self,
|
||||
semver_compatibility: Option<String>,
|
||||
) -> Result<Vec<SkimmedNode>, ValidatorClientError> {
|
||||
Ok(self
|
||||
.nym_api
|
||||
.get_basic_gateways(semver_compatibility)
|
||||
.await?
|
||||
.nodes)
|
||||
pub async fn get_basic_gateways(&self) -> Result<Vec<SkimmedNode>, ValidatorClientError> {
|
||||
Ok(self.nym_api.get_basic_gateways().await?.nodes)
|
||||
}
|
||||
|
||||
/// retrieve basic information for nodes are capable of operating as an entry gateway
|
||||
/// this includes legacy gateways and nym-nodes
|
||||
pub async fn get_all_basic_entry_assigned_nodes(
|
||||
&self,
|
||||
semver_compatibility: Option<String>,
|
||||
) -> Result<Vec<SkimmedNode>, ValidatorClientError> {
|
||||
// TODO: deal with paging in macro or some helper function or something, because it's the same pattern everywhere
|
||||
let mut page = 0;
|
||||
@@ -387,12 +379,7 @@ impl NymApiClient {
|
||||
loop {
|
||||
let mut res = self
|
||||
.nym_api
|
||||
.get_basic_entry_assigned_nodes(
|
||||
semver_compatibility.clone(),
|
||||
false,
|
||||
Some(page),
|
||||
None,
|
||||
)
|
||||
.get_basic_entry_assigned_nodes(false, Some(page), None)
|
||||
.await?;
|
||||
|
||||
nodes.append(&mut res.nodes.data);
|
||||
@@ -410,7 +397,6 @@ impl NymApiClient {
|
||||
/// this includes legacy mixnodes and nym-nodes
|
||||
pub async fn get_all_basic_active_mixing_assigned_nodes(
|
||||
&self,
|
||||
semver_compatibility: Option<String>,
|
||||
) -> Result<Vec<SkimmedNode>, ValidatorClientError> {
|
||||
// TODO: deal with paging in macro or some helper function or something, because it's the same pattern everywhere
|
||||
let mut page = 0;
|
||||
@@ -419,12 +405,7 @@ impl NymApiClient {
|
||||
loop {
|
||||
let mut res = self
|
||||
.nym_api
|
||||
.get_basic_active_mixing_assigned_nodes(
|
||||
semver_compatibility.clone(),
|
||||
false,
|
||||
Some(page),
|
||||
None,
|
||||
)
|
||||
.get_basic_active_mixing_assigned_nodes(false, Some(page), None)
|
||||
.await?;
|
||||
|
||||
nodes.append(&mut res.nodes.data);
|
||||
@@ -442,7 +423,6 @@ impl NymApiClient {
|
||||
/// this includes legacy mixnodes and nym-nodes
|
||||
pub async fn get_all_basic_mixing_capable_nodes(
|
||||
&self,
|
||||
semver_compatibility: Option<String>,
|
||||
) -> Result<Vec<SkimmedNode>, ValidatorClientError> {
|
||||
// TODO: deal with paging in macro or some helper function or something, because it's the same pattern everywhere
|
||||
let mut page = 0;
|
||||
@@ -451,12 +431,7 @@ impl NymApiClient {
|
||||
loop {
|
||||
let mut res = self
|
||||
.nym_api
|
||||
.get_basic_mixing_capable_nodes(
|
||||
semver_compatibility.clone(),
|
||||
false,
|
||||
Some(page),
|
||||
None,
|
||||
)
|
||||
.get_basic_mixing_capable_nodes(false, Some(page), None)
|
||||
.await?;
|
||||
|
||||
nodes.append(&mut res.nodes.data);
|
||||
@@ -471,10 +446,7 @@ impl NymApiClient {
|
||||
}
|
||||
|
||||
/// retrieve basic information for all bonded nodes on the network
|
||||
pub async fn get_all_basic_nodes(
|
||||
&self,
|
||||
semver_compatibility: Option<String>,
|
||||
) -> Result<Vec<SkimmedNode>, ValidatorClientError> {
|
||||
pub async fn get_all_basic_nodes(&self) -> Result<Vec<SkimmedNode>, ValidatorClientError> {
|
||||
// TODO: deal with paging in macro or some helper function or something, because it's the same pattern everywhere
|
||||
let mut page = 0;
|
||||
let mut nodes = Vec::new();
|
||||
@@ -482,7 +454,7 @@ impl NymApiClient {
|
||||
loop {
|
||||
let mut res = self
|
||||
.nym_api
|
||||
.get_basic_nodes(semver_compatibility.clone(), false, Some(page), None)
|
||||
.get_basic_nodes(false, Some(page), None)
|
||||
.await?;
|
||||
|
||||
nodes.append(&mut res.nodes.data);
|
||||
|
||||
@@ -65,6 +65,12 @@ pub enum EcashApiError {
|
||||
#[from]
|
||||
source: cosmrs::ErrorReport,
|
||||
},
|
||||
|
||||
#[error("nym api error")]
|
||||
NymApi {
|
||||
#[from]
|
||||
source: crate::ValidatorClientError,
|
||||
},
|
||||
}
|
||||
|
||||
impl TryFrom<ContractVKShare> for EcashApiClient {
|
||||
|
||||
@@ -102,6 +102,23 @@ pub trait NymApiClientExt: ApiClient {
|
||||
.await
|
||||
}
|
||||
|
||||
#[deprecated]
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
async fn get_gateways_detailed_unfiltered(
|
||||
&self,
|
||||
) -> Result<Vec<GatewayBondAnnotated>, NymAPIError> {
|
||||
self.get_json(
|
||||
&[
|
||||
routes::API_VERSION,
|
||||
routes::STATUS,
|
||||
routes::GATEWAYS,
|
||||
routes::DETAILED_UNFILTERED,
|
||||
],
|
||||
NO_PARAMS,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
#[deprecated]
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
async fn get_mixnodes_detailed_unfiltered(
|
||||
@@ -188,16 +205,7 @@ pub trait NymApiClientExt: ApiClient {
|
||||
|
||||
#[deprecated]
|
||||
#[tracing::instrument(level = "debug", skip_all)]
|
||||
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![]
|
||||
};
|
||||
|
||||
async fn get_basic_mixnodes(&self) -> Result<CachedNodesResponse<SkimmedNode>, NymAPIError> {
|
||||
self.get_json(
|
||||
&[
|
||||
routes::API_VERSION,
|
||||
@@ -206,23 +214,14 @@ pub trait NymApiClientExt: ApiClient {
|
||||
"mixnodes",
|
||||
"skimmed",
|
||||
],
|
||||
¶ms,
|
||||
NO_PARAMS,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
#[deprecated]
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
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![]
|
||||
};
|
||||
|
||||
async fn get_basic_gateways(&self) -> Result<CachedNodesResponse<SkimmedNode>, NymAPIError> {
|
||||
self.get_json(
|
||||
&[
|
||||
routes::API_VERSION,
|
||||
@@ -231,7 +230,7 @@ pub trait NymApiClientExt: ApiClient {
|
||||
"gateways",
|
||||
"skimmed",
|
||||
],
|
||||
¶ms,
|
||||
NO_PARAMS,
|
||||
)
|
||||
.await
|
||||
}
|
||||
@@ -241,17 +240,12 @@ pub trait NymApiClientExt: ApiClient {
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
async fn get_basic_entry_assigned_nodes(
|
||||
&self,
|
||||
semver_compatibility: Option<String>,
|
||||
no_legacy: bool,
|
||||
page: Option<u32>,
|
||||
per_page: Option<u32>,
|
||||
) -> Result<PaginatedCachedNodesResponse<SkimmedNode>, NymAPIError> {
|
||||
let mut params = Vec::new();
|
||||
|
||||
if let Some(arg) = &semver_compatibility {
|
||||
params.push(("semver_compatibility", arg.clone()))
|
||||
}
|
||||
|
||||
if no_legacy {
|
||||
params.push(("no_legacy", "true".to_string()))
|
||||
}
|
||||
@@ -283,17 +277,12 @@ pub trait NymApiClientExt: ApiClient {
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
async fn get_basic_active_mixing_assigned_nodes(
|
||||
&self,
|
||||
semver_compatibility: Option<String>,
|
||||
no_legacy: bool,
|
||||
page: Option<u32>,
|
||||
per_page: Option<u32>,
|
||||
) -> Result<PaginatedCachedNodesResponse<SkimmedNode>, NymAPIError> {
|
||||
let mut params = Vec::new();
|
||||
|
||||
if let Some(arg) = &semver_compatibility {
|
||||
params.push(("semver_compatibility", arg.clone()))
|
||||
}
|
||||
|
||||
if no_legacy {
|
||||
params.push(("no_legacy", "true".to_string()))
|
||||
}
|
||||
@@ -325,17 +314,12 @@ pub trait NymApiClientExt: ApiClient {
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
async fn get_basic_mixing_capable_nodes(
|
||||
&self,
|
||||
semver_compatibility: Option<String>,
|
||||
no_legacy: bool,
|
||||
page: Option<u32>,
|
||||
per_page: Option<u32>,
|
||||
) -> Result<PaginatedCachedNodesResponse<SkimmedNode>, NymAPIError> {
|
||||
let mut params = Vec::new();
|
||||
|
||||
if let Some(arg) = &semver_compatibility {
|
||||
params.push(("semver_compatibility", arg.clone()))
|
||||
}
|
||||
|
||||
if no_legacy {
|
||||
params.push(("no_legacy", "true".to_string()))
|
||||
}
|
||||
@@ -365,17 +349,12 @@ pub trait NymApiClientExt: ApiClient {
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
async fn get_basic_nodes(
|
||||
&self,
|
||||
semver_compatibility: Option<String>,
|
||||
no_legacy: bool,
|
||||
page: Option<u32>,
|
||||
per_page: Option<u32>,
|
||||
) -> Result<PaginatedCachedNodesResponse<SkimmedNode>, NymAPIError> {
|
||||
let mut params = Vec::new();
|
||||
|
||||
if let Some(arg) = &semver_compatibility {
|
||||
params.push(("semver_compatibility", arg.clone()))
|
||||
}
|
||||
|
||||
if no_legacy {
|
||||
params.push(("no_legacy", "true".to_string()))
|
||||
}
|
||||
|
||||
+32
-4
@@ -26,10 +26,11 @@ use nym_mixnet_contract_common::{
|
||||
reward_params::{Performance, RewardingParams},
|
||||
rewarding::{EstimatedCurrentEpochRewardResponse, PendingRewardResponse},
|
||||
ContractBuildInformation, ContractState, ContractStateParams, CurrentIntervalResponse,
|
||||
Delegation, EpochEventId, EpochStatus, GatewayBond, GatewayBondResponse,
|
||||
GatewayOwnershipResponse, IdentityKey, IdentityKeyRef, IntervalEventId, MixNodeBond,
|
||||
MixNodeDetails, MixOwnershipResponse, MixnodeDetailsByIdentityResponse, MixnodeDetailsResponse,
|
||||
NodeId, NumberOfPendingEventsResponse, NymNodeBond, NymNodeDetails,
|
||||
CurrentNymNodeVersionResponse, Delegation, EpochEventId, EpochStatus, GatewayBond,
|
||||
GatewayBondResponse, GatewayOwnershipResponse, HistoricalNymNodeVersionEntry, IdentityKey,
|
||||
IdentityKeyRef, IntervalEventId, MixNodeBond, MixNodeDetails, MixOwnershipResponse,
|
||||
MixnodeDetailsByIdentityResponse, MixnodeDetailsResponse, NodeId,
|
||||
NumberOfPendingEventsResponse, NymNodeBond, NymNodeDetails, NymNodeVersionHistoryResponse,
|
||||
PagedAllDelegationsResponse, PagedDelegatorDelegationsResponse, PagedGatewayResponse,
|
||||
PagedMixnodeBondsResponse, PagedNodeDelegationsResponse, PendingEpochEvent,
|
||||
PendingEpochEventResponse, PendingEpochEventsResponse, PendingIntervalEvent,
|
||||
@@ -71,6 +72,22 @@ pub trait MixnetQueryClient {
|
||||
.await
|
||||
}
|
||||
|
||||
async fn get_nym_node_version_history_paged(
|
||||
&self,
|
||||
start_after: Option<u32>,
|
||||
limit: Option<u32>,
|
||||
) -> Result<NymNodeVersionHistoryResponse, NyxdError> {
|
||||
self.query_mixnet_contract(MixnetQueryMsg::GetNymNodeVersionHistory { limit, start_after })
|
||||
.await
|
||||
}
|
||||
|
||||
async fn get_current_nym_node_version(
|
||||
&self,
|
||||
) -> Result<CurrentNymNodeVersionResponse, NyxdError> {
|
||||
self.query_mixnet_contract(MixnetQueryMsg::GetCurrentNymNodeVersion {})
|
||||
.await
|
||||
}
|
||||
|
||||
async fn get_mixnet_contract_state(&self) -> Result<ContractState, NyxdError> {
|
||||
self.query_mixnet_contract(MixnetQueryMsg::GetState {})
|
||||
.await
|
||||
@@ -638,6 +655,12 @@ pub trait PagedMixnetQueryClient: MixnetQueryClient {
|
||||
) -> Result<Vec<PendingIntervalEvent>, NyxdError> {
|
||||
collect_paged!(self, get_pending_interval_events_paged, events)
|
||||
}
|
||||
|
||||
async fn get_full_nym_node_version_history(
|
||||
&self,
|
||||
) -> Result<Vec<HistoricalNymNodeVersionEntry>, NyxdError> {
|
||||
collect_paged!(self, get_nym_node_version_history_paged, history)
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
@@ -724,6 +747,7 @@ where
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::nyxd::contract_traits::tests::IgnoreValue;
|
||||
use nym_mixnet_contract_common::QueryMsg;
|
||||
|
||||
// it's enough that this compiles and clippy is happy about it
|
||||
#[allow(dead_code)]
|
||||
@@ -924,6 +948,10 @@ mod tests {
|
||||
MixnetQueryMsg::GetRewardedSetMetadata {} => {
|
||||
client.get_rewarded_set_metadata().ignore()
|
||||
}
|
||||
QueryMsg::GetCurrentNymNodeVersion {} => client.get_current_nym_node_version().ignore(),
|
||||
QueryMsg::GetNymNodeVersionHistory { limit, start_after } => client
|
||||
.get_nym_node_version_history_paged(start_after, limit)
|
||||
.ignore(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,44 @@ use tracing::error;
|
||||
|
||||
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> {
|
||||
// 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,
|
||||
@@ -34,35 +72,25 @@ pub fn parse_msg_responses(data: Bytes) -> Vec<MsgResponse> {
|
||||
}
|
||||
|
||||
// requires there's a single response message
|
||||
pub trait ToSingletonContractData: Sized {
|
||||
pub trait ContractResponseData: Sized {
|
||||
fn parse_singleton_u32_contract_data(&self) -> Result<u32, NyxdError> {
|
||||
let b = self.to_singleton_contract_data()?;
|
||||
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]]))
|
||||
parse_singleton_u32_from_contract_response(b)
|
||||
}
|
||||
|
||||
fn parse_singleton_u64_contract_data(&self) -> Result<u64, NyxdError> {
|
||||
let b = self.to_singleton_contract_data()?;
|
||||
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],
|
||||
]))
|
||||
parse_singleton_u64_from_contract_response(b)
|
||||
}
|
||||
|
||||
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 ToSingletonContractData for ExecuteResult {
|
||||
impl ContractResponseData for ExecuteResult {
|
||||
fn to_singleton_contract_data(&self) -> Result<Vec<u8>, NyxdError> {
|
||||
if self.msg_responses.len() != 1 {
|
||||
return Err(NyxdError::UnexpectedNumberOfMsgResponses {
|
||||
@@ -72,6 +100,30 @@ impl ToSingletonContractData for ExecuteResult {
|
||||
|
||||
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 {
|
||||
|
||||
@@ -23,7 +23,7 @@ use tendermint_rpc::endpoint::*;
|
||||
use tendermint_rpc::query::Query;
|
||||
use tendermint_rpc::{Error as TendermintRpcError, Order, Paging, SimpleRequest};
|
||||
|
||||
pub use helpers::{ToContractResponseData, ToSingletonContractData};
|
||||
pub use helpers::{ContractResponseData, ToContractResponseData};
|
||||
|
||||
#[cfg(feature = "http-client")]
|
||||
use crate::http_client;
|
||||
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
// 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, };
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
// 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, };
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
// 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, };
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
// 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, };
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
// 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, };
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
// 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, };
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
// 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, };
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
// 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, };
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
// 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, };
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
// 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, };
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
// 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, };
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
// 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, };
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
// 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, };
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
// 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, };
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
// 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, };
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
// 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";
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
// 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, };
|
||||
@@ -0,0 +1,673 @@
|
||||
// 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,6 +275,9 @@ pub enum MixnetContractError {
|
||||
|
||||
#[error("the provided nym-node version is not a valid semver. got: {provided}")]
|
||||
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 {
|
||||
|
||||
@@ -141,6 +141,7 @@ 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_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_ID_KEY: &str = "new_current_semver_id";
|
||||
|
||||
pub const OLD_REWARDING_VALIDATOR_ADDRESS_KEY: &str = "old_rewarding_validator_address";
|
||||
pub const NEW_REWARDING_VALIDATOR_ADDRESS_KEY: &str = "new_rewarding_validator_address";
|
||||
@@ -481,12 +482,6 @@ pub fn new_settings_update_event(update: &ContractStateParamsUpdate) -> Event {
|
||||
|
||||
// check for config score params updates
|
||||
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 {
|
||||
event.attributes.push(attr(
|
||||
NEW_VERSION_WEIGHTS_RANGE_KEY,
|
||||
@@ -506,9 +501,10 @@ pub fn new_settings_update_event(update: &ContractStateParamsUpdate) -> Event {
|
||||
event
|
||||
}
|
||||
|
||||
pub fn new_update_nym_node_semver_event(new_version: &str) -> Event {
|
||||
pub fn new_update_nym_node_semver_event(new_version: &str, new_id: u32) -> Event {
|
||||
Event::new(MixnetEventType::NymNodeSemverUpdate)
|
||||
.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 {
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#![warn(clippy::unwrap_used)]
|
||||
#![warn(clippy::todo)]
|
||||
|
||||
mod config_score;
|
||||
pub mod constants;
|
||||
pub mod delegation;
|
||||
pub mod error;
|
||||
@@ -21,6 +22,7 @@ pub mod rewarding;
|
||||
pub mod signing_types;
|
||||
pub mod types;
|
||||
|
||||
pub use config_score::*;
|
||||
pub use constants::*;
|
||||
pub use contracts_common::types::*;
|
||||
pub use cosmwasm_std::{Addr, Coin, Decimal, Fraction};
|
||||
|
||||
@@ -25,6 +25,7 @@ use std::time::Duration;
|
||||
|
||||
#[cfg(feature = "schema")]
|
||||
use crate::{
|
||||
config_score::{CurrentNymNodeVersionResponse, NymNodeVersionHistoryResponse},
|
||||
delegation::{
|
||||
NodeDelegationResponse, PagedAllDelegationsResponse, PagedDelegatorDelegationsResponse,
|
||||
PagedNodeDelegationsResponse,
|
||||
@@ -423,6 +424,20 @@ pub enum QueryMsg {
|
||||
#[cfg_attr(feature = "schema", returns(ContractState))]
|
||||
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.
|
||||
#[cfg_attr(feature = "schema", returns(RewardingParams))]
|
||||
GetRewardingParams {},
|
||||
@@ -848,11 +863,4 @@ pub enum QueryMsg {
|
||||
pub struct MigrateMsg {
|
||||
pub unsafe_skip_state_updates: Option<bool>,
|
||||
pub vesting_contract_address: Option<String>,
|
||||
pub current_nym_node_semver: String,
|
||||
|
||||
#[serde(default)]
|
||||
pub version_score_weights: OutdatedVersionWeights,
|
||||
|
||||
#[serde(default)]
|
||||
pub version_score_params: VersionScoreFormulaParams,
|
||||
}
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::config_score::{ConfigScoreParams, OutdatedVersionWeights, VersionScoreFormulaParams};
|
||||
use crate::nym_node::Role;
|
||||
use contracts_common::Percent;
|
||||
use cosmwasm_schema::cw_serde;
|
||||
use cosmwasm_std::Coin;
|
||||
use cosmwasm_std::{Addr, Uint128};
|
||||
use cosmwasm_std::{Coin, Decimal};
|
||||
use std::fmt::{Display, Formatter};
|
||||
|
||||
// type aliases for better reasoning about available data
|
||||
@@ -221,96 +222,14 @@ 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]
|
||||
pub struct ConfigScoreParamsUpdate {
|
||||
pub current_nym_node_semver: Option<String>,
|
||||
pub version_weights: Option<OutdatedVersionWeights>,
|
||||
pub version_score_formula_params: Option<VersionScoreFormulaParams>,
|
||||
}
|
||||
|
||||
impl ConfigScoreParamsUpdate {
|
||||
pub fn contains_updates(&self) -> bool {
|
||||
self.current_nym_node_semver.is_some()
|
||||
|| self.version_weights.is_some()
|
||||
|| self.version_score_formula_params.is_some()
|
||||
self.version_weights.is_some() || self.version_score_formula_params.is_some()
|
||||
}
|
||||
}
|
||||
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
// 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";
|
||||
@@ -23,6 +23,11 @@ impl SqliteEcashTicketbookManager {
|
||||
SqliteEcashTicketbookManager { connection_pool }
|
||||
}
|
||||
|
||||
/// Closes the connection pool.
|
||||
pub async fn close(&self) {
|
||||
self.connection_pool.close().await
|
||||
}
|
||||
|
||||
pub(crate) async fn cleanup_expired(&self, deadline: Date) -> Result<(), sqlx::Error> {
|
||||
sqlx::query!(
|
||||
"DELETE FROM ecash_ticketbook WHERE expiration_date <= ?",
|
||||
|
||||
@@ -43,6 +43,10 @@ impl Debug for EphemeralStorage {
|
||||
impl Storage for EphemeralStorage {
|
||||
type StorageError = StorageError;
|
||||
|
||||
async fn close(&self) {
|
||||
// nothing to do here
|
||||
}
|
||||
|
||||
async fn cleanup_expired(&self) -> Result<(), Self::StorageError> {
|
||||
self.storage_manager.cleanup_expired().await;
|
||||
Ok(())
|
||||
|
||||
@@ -33,7 +33,10 @@ use nym_credentials::{
|
||||
IssuanceTicketBook, IssuedTicketBook,
|
||||
};
|
||||
use nym_ecash_time::{ecash_today, Date, EcashTime};
|
||||
use sqlx::ConnectOptions;
|
||||
use sqlx::{
|
||||
sqlite::{SqliteAutoVacuum, SqliteSynchronous},
|
||||
ConnectOptions,
|
||||
};
|
||||
use std::path::Path;
|
||||
use zeroize::Zeroizing;
|
||||
|
||||
@@ -56,6 +59,9 @@ impl PersistentStorage {
|
||||
);
|
||||
|
||||
let opts = sqlx::sqlite::SqliteConnectOptions::new()
|
||||
.journal_mode(sqlx::sqlite::SqliteJournalMode::Wal)
|
||||
.synchronous(SqliteSynchronous::Normal)
|
||||
.auto_vacuum(SqliteAutoVacuum::Incremental)
|
||||
.filename(database_path)
|
||||
.create_if_missing(true)
|
||||
.disable_statement_logging();
|
||||
@@ -83,6 +89,10 @@ impl PersistentStorage {
|
||||
impl Storage for PersistentStorage {
|
||||
type StorageError = StorageError;
|
||||
|
||||
async fn close(&self) {
|
||||
self.storage_manager.close().await
|
||||
}
|
||||
|
||||
/// remove all expired ticketbooks and expiration date signatures
|
||||
async fn cleanup_expired(&self) -> Result<(), Self::StorageError> {
|
||||
let ecash_yesterday = ecash_today().date().previous_day().unwrap();
|
||||
|
||||
@@ -22,6 +22,8 @@ use std::error::Error;
|
||||
pub trait Storage: Send + Sync {
|
||||
type StorageError: Error;
|
||||
|
||||
async fn close(&self);
|
||||
|
||||
/// remove all expired ticketbooks and expiration date signatures
|
||||
async fn cleanup_expired(&self) -> Result<(), Self::StorageError>;
|
||||
|
||||
|
||||
@@ -13,11 +13,12 @@ use nym_api_requests::constants::MIN_BATCH_REDEMPTION_DELAY;
|
||||
use nym_api_requests::ecash::models::{BatchRedeemTicketsBody, VerifyEcashTicketBody};
|
||||
use nym_credentials_interface::Bandwidth;
|
||||
use nym_credentials_interface::{ClientTicket, TicketType};
|
||||
use nym_validator_client::coconut::EcashApiError;
|
||||
use nym_validator_client::nym_api::EpochId;
|
||||
use nym_validator_client::nyxd::contract_traits::{
|
||||
EcashSigningClient, MultisigQueryClient, MultisigSigningClient, PagedMultisigQueryClient,
|
||||
};
|
||||
use nym_validator_client::nyxd::cosmwasm_client::ToSingletonContractData;
|
||||
use nym_validator_client::nyxd::cosmwasm_client::ContractResponseData;
|
||||
use nym_validator_client::nyxd::cw3::Status;
|
||||
use nym_validator_client::nyxd::AccountId;
|
||||
use nym_validator_client::EcashApiClient;
|
||||
@@ -352,7 +353,9 @@ impl CredentialHandler {
|
||||
}
|
||||
Err(err) => {
|
||||
error!("failed to send ticket {ticket_id} for verification to ecash signer '{client}': {err}. if we don't reach quorum, we'll retry later");
|
||||
Ok(false)
|
||||
Err(EcashTicketError::ApiFailure(EcashApiError::NymApi {
|
||||
source: err,
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ use ed25519_dalek::{Signer, SigningKey};
|
||||
pub use ed25519_dalek::{Verifier, PUBLIC_KEY_LENGTH, SECRET_KEY_LENGTH, SIGNATURE_LENGTH};
|
||||
use nym_pemstore::traits::{PemStorableKey, PemStorableKeyPair};
|
||||
use std::fmt::{self, Debug, Display, Formatter};
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::str::FromStr;
|
||||
use thiserror::Error;
|
||||
use zeroize::{Zeroize, ZeroizeOnDrop};
|
||||
@@ -122,6 +123,14 @@ impl PemStorableKeyPair for KeyPair {
|
||||
#[derive(Copy, Clone, Eq, PartialEq)]
|
||||
pub struct PublicKey(ed25519_dalek::VerifyingKey);
|
||||
|
||||
impl Hash for PublicKey {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
// each public key has unique bytes representation which can be used
|
||||
// for the hash implementation
|
||||
self.to_bytes().hash(state)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for PublicKey {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
Display::fmt(&self.to_base58_string(), f)
|
||||
|
||||
@@ -9,7 +9,7 @@ use futures::{Sink, Stream};
|
||||
use rand::{CryptoRng, RngCore};
|
||||
use tungstenite::Message as WsMessage;
|
||||
|
||||
impl<'a, S, R> State<'a, S, R> {
|
||||
impl<S, R> State<'_, S, R> {
|
||||
async fn client_handshake_inner(&mut self) -> Result<(), HandshakeError>
|
||||
where
|
||||
S: Stream<Item = WsItem> + Sink<WsMessage> + Unpin,
|
||||
|
||||
@@ -10,7 +10,7 @@ use crate::registration::handshake::{error::HandshakeError, WsItem};
|
||||
use futures::{Sink, Stream};
|
||||
use tungstenite::Message as WsMessage;
|
||||
|
||||
impl<'a, S, R> State<'a, S, R> {
|
||||
impl<S, R> State<'_, S, R> {
|
||||
async fn gateway_handshake_inner(
|
||||
&mut self,
|
||||
raw_init_message: Vec<u8>,
|
||||
|
||||
@@ -20,6 +20,10 @@ pub enum ClientRequest {
|
||||
hkdf_salt: Vec<u8>,
|
||||
derived_key_digest: Vec<u8>,
|
||||
},
|
||||
ForgetMe {
|
||||
client: bool,
|
||||
stats: bool,
|
||||
},
|
||||
}
|
||||
|
||||
impl ClientRequest {
|
||||
|
||||
@@ -11,6 +11,7 @@ use tungstenite::Message;
|
||||
#[non_exhaustive]
|
||||
pub enum SensitiveServerResponse {
|
||||
KeyUpgradeAck {},
|
||||
ForgetMeAck {},
|
||||
}
|
||||
|
||||
impl SensitiveServerResponse {
|
||||
|
||||
@@ -6,7 +6,10 @@ use models::StoredFinishedSession;
|
||||
use nym_node_metrics::entry::{ActiveSession, FinishedSession, SessionType};
|
||||
use nym_sphinx::DestinationAddressBytes;
|
||||
use sessions::SessionManager;
|
||||
use sqlx::ConnectOptions;
|
||||
use sqlx::{
|
||||
sqlite::{SqliteAutoVacuum, SqliteSynchronous},
|
||||
ConnectOptions,
|
||||
};
|
||||
use std::path::Path;
|
||||
use time::Date;
|
||||
use tracing::{debug, error};
|
||||
@@ -36,6 +39,9 @@ impl PersistentStatsStorage {
|
||||
// TODO: we can inject here more stuff based on our gateway global config
|
||||
// struct. Maybe different pool size or timeout intervals?
|
||||
let opts = sqlx::sqlite::SqliteConnectOptions::new()
|
||||
.journal_mode(sqlx::sqlite::SqliteJournalMode::Wal)
|
||||
.synchronous(SqliteSynchronous::Normal)
|
||||
.auto_vacuum(SqliteAutoVacuum::Incremental)
|
||||
.filename(database_path)
|
||||
.create_if_missing(true)
|
||||
.disable_statement_logging();
|
||||
@@ -116,6 +122,16 @@ impl PersistentStatsStorage {
|
||||
.await?)
|
||||
}
|
||||
|
||||
pub async fn delete_unique_user(
|
||||
&self,
|
||||
client_address: DestinationAddressBytes,
|
||||
) -> Result<(), StatsStorageError> {
|
||||
Ok(self
|
||||
.session_manager
|
||||
.delete_unique_user(client_address.as_base58_string())
|
||||
.await?)
|
||||
}
|
||||
|
||||
pub async fn insert_active_session(
|
||||
&self,
|
||||
client_address: DestinationAddressBytes,
|
||||
|
||||
@@ -71,6 +71,16 @@ impl SessionManager {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) async fn delete_unique_user(&self, client_address_b58: String) -> Result<()> {
|
||||
sqlx::query!(
|
||||
"DELETE FROM sessions_unique_users WHERE client_address = ?",
|
||||
client_address_b58
|
||||
)
|
||||
.execute(&self.connection_pool)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) async fn get_unique_users(&self, date: Date) -> Result<Vec<String>> {
|
||||
sqlx::query_scalar!(
|
||||
"SELECT client_address as count FROM sessions_unique_users WHERE day = ?",
|
||||
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "DELETE FROM message_store WHERE client_address_bs58 = ?",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 1
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "3ea5542b21a41b14276a8fd6b870c61aa0ddd30fee2565803b88c6086bd2a734"
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "DELETE FROM available_bandwidth WHERE client_id = ?",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 1
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "a3cc707995b8215fa77738cd1a55f9e8d251a3e764104d2a54153895dee1a118"
|
||||
}
|
||||
@@ -49,6 +49,16 @@ impl BandwidthManager {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) async fn remove_client(&self, client_id: i64) -> Result<(), sqlx::Error> {
|
||||
sqlx::query!(
|
||||
"DELETE FROM available_bandwidth WHERE client_id = ?",
|
||||
client_id
|
||||
)
|
||||
.execute(&self.connection_pool)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Set the expiration date of the particular client to the provided date.
|
||||
pub(crate) async fn set_expiration(
|
||||
&self,
|
||||
|
||||
@@ -133,4 +133,17 @@ impl InboxManager {
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) async fn remove_messages_for_client(
|
||||
&self,
|
||||
client_address_bs58: &str,
|
||||
) -> Result<(), sqlx::Error> {
|
||||
sqlx::query!(
|
||||
"DELETE FROM message_store WHERE client_address_bs58 = ?",
|
||||
client_address_bs58
|
||||
)
|
||||
.execute(&self.connection_pool)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,10 @@ use nym_credentials_interface::ClientTicket;
|
||||
use nym_gateway_requests::shared_key::SharedGatewayKey;
|
||||
use nym_sphinx::DestinationAddressBytes;
|
||||
use shared_keys::SharedKeysManager;
|
||||
use sqlx::ConnectOptions;
|
||||
use sqlx::{
|
||||
sqlite::{SqliteAutoVacuum, SqliteSynchronous},
|
||||
ConnectOptions,
|
||||
};
|
||||
use std::path::Path;
|
||||
use tickets::TicketStorageManager;
|
||||
use time::OffsetDateTime;
|
||||
@@ -41,6 +44,33 @@ pub struct GatewayStorage {
|
||||
}
|
||||
|
||||
impl GatewayStorage {
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn client_manager(&self) -> &ClientManager {
|
||||
&self.client_manager
|
||||
}
|
||||
|
||||
pub(crate) fn shared_key_manager(&self) -> &SharedKeysManager {
|
||||
&self.shared_key_manager
|
||||
}
|
||||
|
||||
pub(crate) fn inbox_manager(&self) -> &InboxManager {
|
||||
&self.inbox_manager
|
||||
}
|
||||
|
||||
pub(crate) fn bandwidth_manager(&self) -> &BandwidthManager {
|
||||
&self.bandwidth_manager
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn ticket_manager(&self) -> &TicketStorageManager {
|
||||
&self.ticket_manager
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn wireguard_peer_manager(&self) -> &wireguard_peers::WgPeerManager {
|
||||
&self.wireguard_peer_manager
|
||||
}
|
||||
|
||||
/// Initialises `PersistentStorage` using the provided path.
|
||||
///
|
||||
/// # Arguments
|
||||
@@ -59,6 +89,9 @@ impl GatewayStorage {
|
||||
// TODO: we can inject here more stuff based on our gateway global config
|
||||
// struct. Maybe different pool size or timeout intervals?
|
||||
let opts = sqlx::sqlite::SqliteConnectOptions::new()
|
||||
.journal_mode(sqlx::sqlite::SqliteJournalMode::Wal)
|
||||
.synchronous(SqliteSynchronous::Normal)
|
||||
.auto_vacuum(SqliteAutoVacuum::Incremental)
|
||||
.filename(database_path)
|
||||
.create_if_missing(true)
|
||||
.disable_statement_logging();
|
||||
@@ -101,6 +134,21 @@ impl GatewayStorage {
|
||||
.await?)
|
||||
}
|
||||
|
||||
pub async fn handle_forget_me(
|
||||
&self,
|
||||
client_address: DestinationAddressBytes,
|
||||
) -> Result<(), GatewayStorageError> {
|
||||
let client_id = self.get_mixnet_client_id(client_address).await?;
|
||||
self.inbox_manager()
|
||||
.remove_messages_for_client(&client_address.as_base58_string())
|
||||
.await?;
|
||||
self.bandwidth_manager().remove_client(client_id).await?;
|
||||
self.shared_key_manager()
|
||||
.remove_shared_keys(&client_address.as_base58_string())
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn insert_shared_keys(
|
||||
&self,
|
||||
client_address: DestinationAddressBytes,
|
||||
|
||||
@@ -282,7 +282,7 @@ impl Client {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn create_delete_request<K, V>(
|
||||
pub fn create_delete_request<K, V>(
|
||||
&self,
|
||||
path: PathSegments<'_>,
|
||||
params: Params<'_, K, V>,
|
||||
@@ -324,6 +324,56 @@ impl Client {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_patch_request<B, K, V>(
|
||||
&self,
|
||||
path: PathSegments<'_>,
|
||||
params: Params<'_, K, V>,
|
||||
json_body: &B,
|
||||
) -> RequestBuilder
|
||||
where
|
||||
B: Serialize + ?Sized,
|
||||
K: AsRef<str>,
|
||||
V: AsRef<str>,
|
||||
{
|
||||
let url = sanitize_url(&self.base_url, path, params);
|
||||
self.reqwest_client.patch(url).json(json_body)
|
||||
}
|
||||
|
||||
pub async fn send_patch_request<B, K, V, E>(
|
||||
&self,
|
||||
path: PathSegments<'_>,
|
||||
params: Params<'_, K, V>,
|
||||
json_body: &B,
|
||||
) -> Result<Response, HttpClientError<E>>
|
||||
where
|
||||
B: Serialize + ?Sized,
|
||||
K: AsRef<str>,
|
||||
V: AsRef<str>,
|
||||
E: Display,
|
||||
{
|
||||
let url = sanitize_url(&self.base_url, path, params);
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
{
|
||||
Ok(wasmtimer::tokio::timeout(
|
||||
self.request_timeout,
|
||||
self.reqwest_client.patch(url).json(json_body).send(),
|
||||
)
|
||||
.await
|
||||
.map_err(|_timeout| HttpClientError::RequestTimeout)??)
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
{
|
||||
Ok(self
|
||||
.reqwest_client
|
||||
.patch(url)
|
||||
.json(json_body)
|
||||
.send()
|
||||
.await?)
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip_all)]
|
||||
pub async fn get_json<T, K, V, E>(
|
||||
&self,
|
||||
@@ -372,6 +422,23 @@ impl Client {
|
||||
parse_response(res, false).await
|
||||
}
|
||||
|
||||
pub async fn patch_json<B, T, K, V, E>(
|
||||
&self,
|
||||
path: PathSegments<'_>,
|
||||
params: Params<'_, K, V>,
|
||||
json_body: &B,
|
||||
) -> Result<T, HttpClientError<E>>
|
||||
where
|
||||
B: Serialize + ?Sized,
|
||||
for<'a> T: Deserialize<'a>,
|
||||
K: AsRef<str>,
|
||||
V: AsRef<str>,
|
||||
E: Display + DeserializeOwned,
|
||||
{
|
||||
let res = self.send_patch_request(path, params, json_body).await?;
|
||||
parse_response(res, true).await
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip_all)]
|
||||
pub async fn get_json_endpoint<T, S, E>(&self, endpoint: S) -> Result<T, HttpClientError<E>>
|
||||
where
|
||||
@@ -466,6 +533,42 @@ impl Client {
|
||||
|
||||
parse_response(res, false).await
|
||||
}
|
||||
|
||||
pub async fn patch_json_endpoint<B, T, S, E>(
|
||||
&self,
|
||||
endpoint: S,
|
||||
json_body: &B,
|
||||
) -> Result<T, HttpClientError<E>>
|
||||
where
|
||||
B: Serialize + ?Sized,
|
||||
for<'a> T: Deserialize<'a>,
|
||||
E: Display + DeserializeOwned,
|
||||
S: AsRef<str>,
|
||||
{
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
let res = {
|
||||
wasmtimer::tokio::timeout(
|
||||
self.request_timeout,
|
||||
self.reqwest_client
|
||||
.patch(self.base_url.join(endpoint.as_ref())?)
|
||||
.json(json_body)
|
||||
.send(),
|
||||
)
|
||||
.await
|
||||
.map_err(|_timeout| HttpClientError::RequestTimeout)??
|
||||
};
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
let res = {
|
||||
self.reqwest_client
|
||||
.patch(self.base_url.join(endpoint.as_ref())?)
|
||||
.json(json_body)
|
||||
.send()
|
||||
.await?
|
||||
};
|
||||
|
||||
parse_response(res, true).await
|
||||
}
|
||||
}
|
||||
|
||||
// define those methods on the trait for nicer extensions (and not having to type the thing twice)
|
||||
|
||||
@@ -15,12 +15,15 @@ axum-client-ip.workspace = true
|
||||
axum.workspace = true
|
||||
bytes = { workspace = true }
|
||||
colored.workspace = true
|
||||
futures = { workspace = true }
|
||||
mime = { workspace = true }
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
serde_json.workspace = true
|
||||
serde_yaml = { workspace = true }
|
||||
tower = { workspace = true }
|
||||
tracing.workspace = true
|
||||
utoipa = { workspace = true, optional = true }
|
||||
zeroize = { workspace = true }
|
||||
|
||||
[features]
|
||||
utoipa = ["dep:utoipa"]
|
||||
|
||||
@@ -7,7 +7,7 @@ use axum::Json;
|
||||
use bytes::{BufMut, BytesMut};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
pub mod logging;
|
||||
pub mod middleware;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use axum::http::{header, HeaderValue, StatusCode};
|
||||
use axum::response::IntoResponse;
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user