Compare commits

..

459 Commits

Author SHA1 Message Date
Bogdan-Ștefan Neacşu 099de36c60 Revert "Remove rustls feature on workspace deps (#4422)"
This reverts commit 2bff66e2c7.
2024-03-06 12:39:36 +02:00
dependabot[bot] 9e5890a0d7 Bump ip in /clients/native/examples/js-examples/websocket (#4421)
Bumps [ip](https://github.com/indutny/node-ip) from 1.1.5 to 1.1.9.
- [Commits](https://github.com/indutny/node-ip/compare/v1.1.5...v1.1.9)

---
updated-dependencies:
- dependency-name: ip
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-06 08:15:03 +01:00
dependabot[bot] 3bda5f59a3 Bump ip from 2.0.0 to 2.0.1 (#4417)
Bumps [ip](https://github.com/indutny/node-ip) from 2.0.0 to 2.0.1.
- [Commits](https://github.com/indutny/node-ip/compare/v2.0.0...v2.0.1)

---
updated-dependencies:
- dependency-name: ip
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-06 07:58:31 +01:00
import this 154dfa089b [DOC]: Hotfix - remove unexisting page (#4438)
* [DOC]: Hotfix - remove unexisting page

* update modules and run build

* installed with nvm 18

* yarn version solved

* remove extra files

* attempt to resolve module versioning

* Update package versions and fix keplr example

---------

Co-authored-by: Mark Sinclair <mmsinclair@users.noreply.github.com>
2024-03-05 15:07:38 +00:00
Jon Häggblad bd0cbbc18a Fix typo in macro invocation (#4441) 2024-03-04 14:48:43 +01:00
Jędrzej Stuczyński ed0e7a7a25 Merge pull request #4439 from nymtech/chore/move-nym-id
Chore/move nym
2024-03-04 12:19:41 +00:00
Jon Häggblad 5b35cfcfb2 build-information: pick up vergen from consuming crate (#4424) 2024-03-04 12:16:48 +01:00
Bogdan-Ștefan Neacşu d3ba008b88 Add IPPair constructor (#4440)
* Add IPPair constructor

* Rename
2024-03-04 12:56:10 +02:00
Jędrzej Stuczyński a04a782dbf renamed nym-id-lib to nym-id 2024-03-04 10:08:10 +00:00
Jędrzej Stuczyński f5d9fda0b1 moved and renamed nym-id to nym-id-cli 2024-03-04 09:38:29 +00:00
Bogdan-Ștefan Neacşu aebd386382 Add IPv6 support to IPPR (#4431) 2024-03-01 19:28:21 +02:00
Bogdan-Ștefan Neacşu 9a6f96b5e0 Fix windows build (#4426)
* Fix windows build

* Fix in another place too

* Install clang

* With sudo

* Revert "cargo update -p rustls@0.21.7 (#4404)"

This reverts commit ecc47cd418.
2024-03-01 12:07:38 +02:00
Jędrzej Stuczyński 5a3ff0f9f7 Merge pull request #4436 from nymtech/feature/nym-id-scaffold
Feature/nym id scaffold
2024-03-01 09:14:40 +00:00
Jędrzej Stuczyński 160db34651 clippy 2024-02-29 16:53:50 +00:00
Jędrzej Stuczyński ae20d2afb8 removed old test code 2024-02-29 16:04:07 +00:00
Jędrzej Stuczyński 41b7a2a20d cargo fmt 2024-02-29 15:57:48 +00:00
Jędrzej Stuczyński 208ec4574b using the shared code for credentials import 2024-02-29 15:29:41 +00:00
Jon Häggblad 2bff66e2c7 Remove rustls feature on workspace deps (#4422)
* Remove rustls feature on workspace deps

* Cargo.lock for nym-connect and nym-wallet
2024-02-28 18:45:00 +02:00
Jędrzej Stuczyński 1aad5fc1bf created nym-id for importing credentials 2024-02-28 11:22:46 +00:00
import this cb3e73fbd7 [DOC]/operators: Validator rewards (#4427)
* initialise token economics chapter

* initialise validator rewards page

* add todo points

* syntax edits

* docs: minor fixes

* add currency overview

* create bash scripts for nyx stake

* add nymvisor url

* final version of validator rewards

* final version of validator rewards

* final version of validator rewards

---------

Co-authored-by: Sachin Kamath <github@skamath.me>
2024-02-27 14:17:44 +00:00
Tommy Verrall eabb36b975 Merge pull request #4425 from nymtech/fix/nym-vpn/testing
[DOC]: Fix NymVPN desktop setup guide
2024-02-22 11:00:23 +01:00
serinko 2eed8e3f6c syntax edit 2024-02-22 10:40:38 +01:00
serinko bfac3e0b89 add gui-mac to summary 2024-02-22 10:23:00 +01:00
serinko 90680ceb16 add moving application step 2024-02-22 10:14:14 +01:00
Tommy Verrall f9c5684d6c Merge pull request #4414 from nymtech/qa/remove-deb-build
temporarily remove the debian builder from gh action
2024-02-22 09:49:44 +01:00
serinko ffb053fe4a desktop auto script update 2024-02-22 06:28:12 +01:00
serinko e83be64a52 mac desktop manual steps 2024-02-22 06:23:18 +01:00
serinko 32c897f789 add mac desktop manual setup 2024-02-21 11:33:51 +01:00
Bogdan-Ștefan Neacşu 9ff37d2f9f Propagate gateway ws fd into sdk (#4398)
* Propagate gateway ws fd into sdk

* Wrap fd in a more general struct
2024-02-21 12:27:18 +02:00
serinko a6ebfb521d remove redundant part 2024-02-21 11:20:57 +01:00
import this ac23ef924a [DOC]: Publish Nymvisor guide (#4423) 2024-02-21 09:27:12 +00:00
Tommy Verrall 5a770614dd formatting 2024-02-20 19:48:04 +01:00
Tommy Verrall 8f8cd79a65 amend workflow to input event instead 2024-02-20 19:45:22 +01:00
Jon Häggblad d8f73ef97a Update Cargo.lock 2024-02-20 19:03:54 +01:00
Tommy Verrall c7fb89bd5e Merge pull request #4412 from nymtech/master
Merge Master into Develop from Latest 2024.1-marabou release
2024-02-20 18:59:01 +01:00
benedettadavico 3c2d47ad18 update cargo.lock 2024-02-20 18:34:23 +01:00
Tommy Verrall 6f13720530 Merge pull request #4416 from nymtech/qa/merge-conflicts
make check on conflicts
2024-02-20 17:59:10 +01:00
Tommy Verrall 0efd7a2318 make check on conflicts 2024-02-20 17:45:23 +01:00
Lawrence Stalder 2ca2b9e032 Merge pull request #4413 from nymtech/fix-localnet-script
fix: localnet script fix typo to attach tmux session
2024-02-20 16:33:51 +01:00
Tommy Verrall d92a8ea028 temporarily remove the debian builder from gh action
- it's not needed but in the future we may want to reactivate it, currently commenting it out
2024-02-20 16:25:58 +01:00
Lawrence Stalder 7483d10701 fix: localnet script fix typo to attach tmux session 2024-02-20 16:02:53 +01:00
Jędrzej Stuczyński ca75c06f4c Merge pull request #4396 from nymtech/feature/freepass-combined
freepass credentials
2024-02-20 12:26:24 +00:00
import this 73632a0ae7 [DOC]: Update nym-vpn commands (#4386)
* update nym-vpn commands

* update testing flow

* bumped up scripts and version url to 0.0.4

* correct cli script version -> 0.0.2

* update extract commands

* update extract commands

* update gui and cli auto scripts

* correct curl url

* minor fixes to formatting

* add final bash script for desktop

* syntax change

* commenting mac manual steps

* comment off mac manual steps from summary

* Update SUMMARY.md

* Update troubleshooting.md

---------

Co-authored-by: mfahampshire <mfahampshire@pm.me>
2024-02-20 12:08:36 +00:00
Tommy Verrall 3d3dd80247 Merge pull request #4411 from nymtech/release/2024.1-marabou
Release/2024.1 marabou
2024-02-20 12:22:20 +01:00
Jędrzej Stuczyński 1d481db179 additional log for dkg address 2024-02-20 11:07:04 +00:00
Jędrzej Stuczyński cae97663c1 additional gateway logs 2024-02-20 11:03:44 +00:00
Tommy Verrall 795329b874 Merge pull request #4410 from nymtech/qa/debian-test
Debian Package Pre/Post install
2024-02-20 10:58:42 +01:00
Tommy Verrall 87ea3fcfc4 remove extra line 2024-02-20 09:29:26 +01:00
Tommy Verrall 289343d1c8 one last tweak 2024-02-20 09:26:00 +01:00
Jędrzej Stuczyński f96f74f2f1 removed unused imports 2024-02-19 18:27:16 +00:00
Jędrzej Stuczyński 3ec2ea904f fixed local expiration check 2024-02-19 17:55:36 +00:00
Jędrzej Stuczyński 04373589b1 added import-credential command to network requester 2024-02-19 17:51:19 +00:00
Jędrzej Stuczyński 1a8814ccdc changed nonces to be random bytes to prevent replay attacks 2024-02-19 17:45:39 +00:00
Jędrzej Stuczyński d62a41b9c1 fixed client route used for free pass 2024-02-19 17:09:16 +00:00
Jędrzej Stuczyński d3e30e98f9 preventing spending credentials with outdated gateways 2024-02-19 16:01:29 +00:00
Jędrzej Stuczyński 88a49dfc7e making sure the retrieved credentials haven't expired 2024-02-19 15:26:51 +00:00
Tommy Verrall 66a54aeab3 small formatting 2024-02-19 14:51:23 +01:00
Tommy Verrall d6afa74284 debhelper 2024-02-19 14:40:14 +01:00
Tommy Verrall 49e2be5b04 a condition was not being met for new installs
therefore, input a preinst script too to back up
2024-02-19 14:37:35 +01:00
Tommy Verrall 1cfddb942b remove line 2024-02-19 13:43:56 +01:00
Tommy Verrall 49c43617c9 include a pretty print of the service file here 2024-02-19 13:41:38 +01:00
Jędrzej Stuczyński ff01fc79e3 removed duplicate code 2024-02-19 12:19:54 +00:00
Jędrzej Stuczyński 5cf53b7002 fixed logging 2024-02-19 12:11:50 +00:00
Jędrzej Stuczyński 387d07fb93 additional logs 2024-02-19 11:43:17 +00:00
Jędrzej Stuczyński dcd6dcc6e3 restored accidentally removed lazy static in socks5 lib 2024-02-19 11:43:16 +00:00
Jędrzej Stuczyński e7d0c1812a added import commands for client binaries 2024-02-19 11:43:15 +00:00
Jędrzej Stuczyński 7bbac26676 replaced usage of lazy_static to oncelock for build information 2024-02-19 11:42:57 +00:00
Jędrzej Stuczyński 688ac2efb5 added nym-cli command for importing credentials 2024-02-19 11:42:57 +00:00
Jędrzej Stuczyński f348e6972a clippy 2024-02-19 11:42:57 +00:00
Jędrzej Stuczyński dd97eb13a8 locally marking credentials as spent 2024-02-19 11:42:57 +00:00
Jędrzej Stuczyński 92d9cb7dab added database code for the serial number storage 2024-02-19 11:42:56 +00:00
Jędrzej Stuczyński 5a4dfafe9f cargo fmt 2024-02-19 11:42:56 +00:00
Jędrzej Stuczyński fa93c4598f removing redundant epoch_id field 2024-02-19 11:42:56 +00:00
Jędrzej Stuczyński edbcade5f5 clippy 2024-02-19 11:42:56 +00:00
Jędrzej Stuczyński 3f0194a9aa nym-cli commands for issuing free passes 2024-02-19 11:42:56 +00:00
Jędrzej Stuczyński c2517ac63b clippy 2024-02-19 11:42:55 +00:00
Jędrzej Stuczyński 3fa74c90ff cargo fmt 2024-02-19 11:42:55 +00:00
Jędrzej Stuczyński 96f3192694 validating request attributes 2024-02-19 11:42:55 +00:00
Jędrzej Stuczyński f61b898c4f storage implementation 2024-02-19 11:42:55 +00:00
Jędrzej Stuczyński c9ff550311 nym-api logic for issuing free passes (minus storage impl) 2024-02-19 11:42:53 +00:00
Jędrzej Stuczyński 740cc72ec8 request type for obtaining free pass 2024-02-19 11:41:42 +00:00
benedettadavico 6e7bac1e7e cargo fmt 2024-02-19 11:41:32 +00:00
benedettadavico 691884e20a add return statement 2024-02-19 11:41:32 +00:00
Jędrzej Stuczyński 400d71bf07 ibid 2024-02-19 11:41:32 +00:00
benedettadavico ffe55ba072 running cargo fmt 2024-02-19 11:41:32 +00:00
Jędrzej Stuczyński 00f1ce98ba gateway downgrading advertised protocol for incompatible clients 2024-02-19 11:41:31 +00:00
Jędrzej Stuczyński b02bbdef19 fixed SQL type for epoch_id 2024-02-19 11:41:31 +00:00
Jędrzej Stuczyński 78e1d84905 restored OldV1Credential::as_bytes to be available to non-test code 2024-02-19 11:41:31 +00:00
Jędrzej Stuczyński 2638952f5a reintroduced handling of old v1 credentials 2024-02-19 11:41:31 +00:00
Jędrzej Stuczyński 9a3bd7a2a9 clippy and fixing tests 2024-02-19 11:41:31 +00:00
Jędrzej Stuczyński ad9aee0ec0 missing serialization 2024-02-19 11:41:31 +00:00
Jędrzej Stuczyński f687ebb0f5 persisting the issued credentials 2024-02-19 11:41:31 +00:00
Jędrzej Stuczyński ddf2770c8e reintroduced recovery of vouchers 2024-02-19 11:41:30 +00:00
Jędrzej Stuczyński 16c942d72e removed nym-api placeholders 2024-02-19 11:41:30 +00:00
Jędrzej Stuczyński 0ee727bac1 gateway handling of both credential types 2024-02-19 11:41:30 +00:00
Jędrzej Stuczyński 675cf3d7da removed usage of coconut-interface crate 2024-02-19 11:41:29 +00:00
Jędrzej Stuczyński 9a0cbf5072 wip in removing the Credential type for more strongly typed alternative 2024-02-19 11:39:54 +00:00
Jędrzej Stuczyński 6f3dd9f778 wip 2024-02-19 11:39:53 +00:00
Jędrzej Stuczyński 7a7fbce8ea using bincode serialization 2024-02-19 11:39:53 +00:00
Jędrzej Stuczyński 36242fa257 serde for 'IssuanceBandwidthCredential' 2024-02-19 11:39:53 +00:00
Jędrzej Stuczyński b764fcc756 revamped BandwidthVoucher to allow for different kinds of bandwidth credentials 2024-02-19 11:39:53 +00:00
Jędrzej Stuczyński ac676760d4 Merge pull request #4399 from nymtech/bugfix/signing-rewards
Bugfix/signing rewards
2024-02-19 11:30:42 +00:00
Jędrzej Stuczyński 20819331f3 Merge pull request #4405 from nymtech/bugfix/further-dkg-changes
Bugfix/further dkg changes
2024-02-19 11:29:53 +00:00
Jędrzej Stuczyński 6b6980c523 missing schema 2024-02-16 17:41:46 +00:00
Jędrzej Stuczyński 8b0953624f being less aggressive in contract polling 2024-02-16 17:39:22 +00:00
Jędrzej Stuczyński 24a260fbc9 missing trait implementation in test 2024-02-16 17:36:23 +00:00
Jędrzej Stuczyński 510ad11c98 nym-api using the new query 2024-02-16 17:33:07 +00:00
Jędrzej Stuczyński 627334cfe2 added dkg contract query to check if state can be advanced 2024-02-16 17:16:39 +00:00
Jędrzej Stuczyński d4c98e3ff5 clippy test 2024-02-16 16:47:01 +00:00
Jędrzej Stuczyński 9821dd994b updated schema 2024-02-16 16:38:03 +00:00
Jędrzej Stuczyński a977310225 fixed existing dkg contract tests 2024-02-16 16:27:58 +00:00
Tommy Verrall 8e16678f74 fix syntax 2024-02-16 16:39:01 +01:00
Tommy Verrall 52c46f371e shell 2024-02-16 16:18:11 +01:00
Tommy Verrall 3010d5192f add helper 2024-02-16 16:00:18 +01:00
Tommy Verrall 721ad9d8bb remove helper 2024-02-16 15:55:43 +01:00
Tommy Verrall 85803ec11c change some of the logic 2024-02-16 15:25:25 +01:00
Tommy Verrall 83da1f228b debian package changer
- instead of dealing with the complexities of initing the builds, it's a complex beast for automagically guessing a user config for a binary
- therefore, find their existing binary, move the executable from /usr/bin/ then find and replace it with their current set up
- a user then can do sudo apt install nym-gateway && systemctl restart nym-gateway.service
- script tells the user a few key things too
2024-02-16 14:05:53 +01:00
Jędrzej Stuczyński c663ba08f2 fixed dkg incorrectly setting state deadlines 2024-02-16 09:16:59 +00:00
Jędrzej Stuczyński 92bf31d9f4 fixed dkg progress not being recorded 2024-02-16 09:16:58 +00:00
Jędrzej Stuczyński 646f522142 fixed nym-api tests 2024-02-16 09:16:58 +00:00
Jędrzej Stuczyński be3dd2c250 setting threshold value upon entering dealing exchange 2024-02-16 09:16:58 +00:00
Jędrzej Stuczyński db826c4fb4 missing DkgExecuteMsg client impls 2024-02-16 09:16:58 +00:00
Jędrzej Stuczyński b960dc8aaf removed 'SurpassedThreshold' message 2024-02-16 09:16:58 +00:00
Jędrzej Stuczyński da70ae70a5 nym-api updates 2024-02-16 09:16:58 +00:00
Jędrzej Stuczyński 914b8a6dc2 updated the validator client 2024-02-16 09:16:58 +00:00
Jędrzej Stuczyński ad2552ec78 schema 2024-02-16 09:16:57 +00:00
Jędrzej Stuczyński 45686f7ca6 queries 2024-02-16 09:16:57 +00:00
Jędrzej Stuczyński 27554f52e3 revamped dealers storage structure (for txs) 2024-02-16 09:16:57 +00:00
Jędrzej Stuczyński 29edc8799a dkg reset/resharing triggered by admin messages instead 2024-02-16 09:16:57 +00:00
Jędrzej Stuczyński 46875cdf2f moved epoch advancement logic into separate file 2024-02-16 09:16:57 +00:00
Jędrzej Stuczyński 629081b5ec fixed reset mode not being triggered when enough parties left 2024-02-16 09:16:57 +00:00
Jędrzej Stuczyński d2c77d7f64 integration test for failed DKG redoing 2024-02-16 09:16:57 +00:00
Jędrzej Stuczyński eab7eb03c7 reduced tick rate logging 2024-02-16 09:16:56 +00:00
Jon Häggblad ecc47cd418 cargo update -p rustls@0.21.7 (#4404) 2024-02-15 16:06:09 +01:00
benedetta davico 71c975d20c Update publish-nym-binaries.yml 2024-02-15 11:46:20 +01:00
benedettadavico f0705cd1f9 Update workflow to add nymvisor binary 2024-02-15 10:56:13 +01:00
Stefano Piermatteo b6d5f780d2 [DOC]: Add landing page howto (#4378)
* add html snippet

* add reverse proxy

* fix typos
fix variables conventions
fix markdown

* add Avril 14th sentence

* fix syntax
2024-02-15 07:40:36 +00:00
Jędrzej Stuczyński 0b46e5b753 improved startup log regarding the epoch 2024-02-14 16:36:37 +00:00
Jędrzej Stuczyński 2c65460164 additional logs 2024-02-14 16:10:14 +00:00
Jędrzej Stuczyński e86419540c don't try to send empty rewarding txs 2024-02-14 16:10:14 +00:00
benedettadavico 3771cb9188 Update changelog and bump versions 2024-02-14 11:55:30 +01:00
mx e8f6d6e55d fixed theme bug? (#4401)
Co-authored-by: mfahampshire <mfahampshire@pm.me>
2024-02-14 09:59:19 +01:00
Jędrzej Stuczyński 536b892c91 fixed epoch id being advanced at wrong point 2024-02-14 08:49:08 +00:00
Jędrzej Stuczyński a40cd73dec Merge pull request #4402 from nymtech/bugfix/post-ephemera-nym-api
fixed nym-api config template
2024-02-13 17:41:38 +00:00
Jędrzej Stuczyński d7255374de fixed nym-api config template 2024-02-13 17:41:07 +00:00
Jędrzej Stuczyński 0b6cb236d8 allow running in monitor only mode without any tokens 2024-02-13 15:22:03 +00:00
Jędrzej Stuczyński f0361a200b log errors on failing to determine rewarding amounts and advance epochs regardless 2024-02-13 15:20:36 +00:00
Jędrzej Stuczyński f1c5e8bdc0 attempt to re-create websocket creation on failure 2024-02-13 14:41:57 +00:00
Jędrzej Stuczyński b03d737393 making sure to stop nym-rewarder if nyxd scraper has terminated 2024-02-13 12:03:06 +00:00
Jon Häggblad 3088b69711 Merge pull request #3503 from nymtech/jon/feat/test-rustls
Replace openssl with rustls
2024-02-13 08:55:47 +01:00
Jon Häggblad 412b7b9898 Remove sdk-version-bump from main workspace temporarily
In the upcoming cargo-edit version then the dependency on ureq is
dropped and also the implicit dependency on openssl
2024-02-13 08:29:39 +01:00
Jon Häggblad 30754a7a4a Switch tungstenite to rustls 2024-02-13 08:28:09 +01:00
Jon Häggblad e99b04f1c6 Remove explicit openssl dependency 2024-02-13 08:28:09 +01:00
Jon Häggblad 279fea9a0b Switch reqwest to rustls 2024-02-13 08:28:09 +01:00
Jon Häggblad c2aba223b8 Add openssl to cargo deny ban 2024-02-13 08:28:09 +01:00
Jędrzej Stuczyński 501f314266 Merge pull request #4356 from nymtech/chore/remove-ephemera
Chore/remove ephemera
2024-02-12 18:31:58 +00:00
Jędrzej Stuczyński 3ecd2af216 fixed test imports 2024-02-12 17:14:25 +00:00
Jon Häggblad 9b44674f43 Remove sdk-version-bump from main workspace temporarily
In the upcoming cargo-edit version then the dependency on ureq is
dropped and also the implicit dependency on openssl
2024-02-12 14:14:30 +01:00
Jon Häggblad 588839740f Switch tungstenite to rustls 2024-02-12 14:14:30 +01:00
Jon Häggblad 4353bab636 Remove explicit openssl dependency 2024-02-12 14:14:30 +01:00
Jon Häggblad 05957c366f Switch reqwest to rustls 2024-02-12 14:14:30 +01:00
Jon Häggblad 60e14f866e Add openssl to cargo deny ban 2024-02-12 14:14:30 +01:00
Jon Häggblad cec05a99f4 Tweak packet rate log string 2024-02-12 13:05:30 +01:00
Jon Häggblad d487f4d98c Merge pull request #4389 from nymtech/jon/handle-multiple-ip-packet-in-ipr
Handle multiple IP packets in ip-packet-router
2024-02-12 12:39:40 +01:00
Jon Häggblad b9e9809938 Extract out handle_responses 2024-02-12 12:14:51 +01:00
Jędrzej Stuczyński 9b50188d7d Merge pull request #4391 from nymtech/chore/reexport-types
re-export cosmrs' cosmwasm types
2024-02-12 09:14:33 +00:00
Jon Häggblad 0e3dbece8b Fix unit test 2024-02-12 08:21:32 +01:00
Jędrzej Stuczyński 052f7649a8 re-export cosmrs' cosmwasm types 2024-02-11 18:57:32 +00:00
Jon Häggblad 3fde9e648f Add health request response 2024-02-10 23:53:03 +01:00
Jon Häggblad 0b37b9fb1c Add ping pong request response 2024-02-10 23:35:36 +01:00
Jon Häggblad e273bfc25e Add message for unrequested disconnect on the IPR 2024-02-10 23:27:07 +01:00
Jon Häggblad d2ef94f1bd Add buffer timeout to connect request 2024-02-10 23:13:50 +01:00
Jon Häggblad 92ab794294 Encode packets in connection handler 2024-02-10 23:07:45 +01:00
Jon Häggblad 3f0210d56a Handle incoming multi-ip packets in IPR 2024-02-10 22:40:21 +01:00
Jon Häggblad 9b53473bee Tweak retransmission log info (#4387) 2024-02-09 18:22:25 +01:00
Tommy Verrall 5fdae14cb9 Merge pull request #4385 from nymtech/bugfix/gateway-vk-caching-without-coconut
[bugfix] remove hard failure on dkg contract queries in case it doesn't exist
2024-02-09 18:11:05 +01:00
Jędrzej Stuczyński ccb4d7fd5e comment regarding removal of ephemera 2024-02-09 14:40:24 +00:00
Jędrzej Stuczyński a8e520d13b removed unused import 2024-02-09 14:38:43 +00:00
Jędrzej Stuczyński 148db2f350 replaced uses of 'serde_derive' with 'serde' 2024-02-09 14:38:02 +00:00
Jędrzej Stuczyński 2f4fad3ce3 [bugfix] remove hard failure on dkg contract queries in case it doesn't exist 2024-02-09 11:39:27 +00:00
Jon Häggblad cc604c5f18 Merge pull request #4380 from nymtech/jon/ipr-connected-client-handler
Connected client handler in the IPR
2024-02-09 11:37:13 +01:00
Jon Häggblad d0aece501f Add missing deploy step to ci-build-upload-binaries 2024-02-09 11:28:32 +01:00
Jon Häggblad 22b5670396 Update release/publish workflow names to match filenames (#4383) 2024-02-09 11:26:39 +01:00
benedetta davico 4ebbf175fc Merge branch 'develop' into chore/remove-ephemera 2024-02-09 11:24:52 +01:00
Jon Häggblad 79e9399dfe Add nightly schedule trigger for ci-build-upload-binaries 2024-02-09 11:17:34 +01:00
Jon Häggblad 8450df28df Tweak logging 2024-02-09 10:58:49 +01:00
Jon Häggblad 0b23d1624f Switch to JoinHandle 2024-02-09 09:49:18 +01:00
Jon Häggblad 2026ffd61f Error logging 2024-02-09 09:49:18 +01:00
Jon Häggblad 48e5aecda1 Don't unwrap on failed to send close signal 2024-02-09 09:49:18 +01:00
Jon Häggblad d8e484b77e Disconnect stopped client handlers 2024-02-09 09:49:18 +01:00
Jon Häggblad d4ca2a7220 Implement drop for client handlers too 2024-02-09 09:49:18 +01:00
Jon Häggblad 2f0074821c Downgrade some logging after checking it works 2024-02-09 09:49:18 +01:00
Jon Häggblad d5e332ad39 Deduplicate and clean up 2024-02-09 09:49:18 +01:00
Jon Häggblad 14bf5645b1 Add missing module 2024-02-09 09:49:18 +01:00
Jon Häggblad a11582749c Add connected_client_handler 2024-02-09 09:49:18 +01:00
Jon Häggblad aedff7fe30 Fix clippy::useless_conversion (#4384) 2024-02-09 09:37:32 +01:00
Jon Häggblad 36e4c181fc Add enable_wireguard toggle to build-upload-binaries workflow (#4382)
* Add enable_wireguard toggle to ci-build-upload-binaries workflow

* Remove old deprecated build-upload-binaries

* fixup! Add enable_wireguard toggle to ci-build-upload-binaries workflow
2024-02-09 09:15:30 +01:00
Tommy Verrall 68cfe2e755 fix unit test 2024-02-08 17:43:51 +00:00
Tommy Verrall 2baac3de1b Merge pull request #4338 from nymtech/feature/nym-cli-multisend
nym-cli: add command to broadcast a transaction with multiple send token messages
2024-02-08 17:08:41 +01:00
Tommy Verrall edc9b78b6c last clippy warning 2024-02-08 16:07:13 +00:00
Tommy Verrall 9f07f3aff3 fmt 2024-02-08 15:55:57 +00:00
Tommy Verrall 23ba8298be amend code, as described on PR, trialled and testing on QA 2024-02-08 15:46:21 +00:00
Tommy Verrall 629d124838 Merge pull request #4371 from nymtech/feature/DKG-revamp1
Feature/dkg revamp1
2024-02-08 14:35:33 +01:00
mx fe2d602cd8 Max/new mdbook theme (#4377)
* stripped out theme plugin + edited coal default

* cleanedup gitignore

* stripped down light theme

* new theme dir structure

* removed themes aside from dark and light custom

* moved search to right hand side

* added toc

* changed up header bar

* hard centred title

* themed dropdown menus

* copied all vars between book tomls for the moment

* moved new theming to operators and devportal

* changed comment on future language support

---------

Co-authored-by: mfahampshire <mfahampshire@pm.me>
2024-02-08 10:02:57 +00:00
Jon Häggblad 8b2f80b03c Multi IP packet codec (#4379)
* Codec implementation

* rustfmt

* Extract out magic numbers
2024-02-08 11:01:01 +01:00
Jędrzej Stuczyński 336cd30dd8 updated dkg contract schema 2024-02-07 12:28:51 +00:00
Jon Häggblad a8dc703399 Merge pull request #4370 from nymtech/jon/reply-on-ipr-version-incompat
Extend IPR request / responses to handle more reply types
2024-02-07 13:24:14 +01:00
Jędrzej Stuczyński c8562ecac1 fixed dkg contract test build 2024-02-07 11:56:44 +00:00
Jędrzej Stuczyński dd0067f542 fixed arguments passed for dealer registration 2024-02-07 11:55:49 +00:00
Jędrzej Stuczyński a18dab55a6 fixed coconut key existence check in key derivation 2024-02-07 11:55:48 +00:00
Jędrzej Stuczyński 4c8ae077a2 fixed nym-api config template 2024-02-07 11:55:48 +00:00
Jędrzej Stuczyński 79a7860185 changed 'DealingChunkInfo' 'size' field from usize to u64 to remove floating point operations during deserialization 2024-02-07 11:55:48 +00:00
Jędrzej Stuczyński bb71da55e8 regenerated DKG contract schema 2024-02-07 11:55:48 +00:00
Jędrzej Stuczyński ca18fb9f33 fixed clippy warnings on existing code 2024-02-07 11:55:48 +00:00
Jędrzej Stuczyński ceec8217e0 nym-cli build fix 2024-02-07 11:55:48 +00:00
Jędrzej Stuczyński a52e81b66e temporarily commented out broken test 2024-02-07 11:55:48 +00:00
Jędrzej Stuczyński a44339433e fixed nym-api tests 2024-02-07 11:55:48 +00:00
Jędrzej Stuczyński c9290cbcc0 handle chunking on nym-api side 2024-02-07 11:55:47 +00:00
Jędrzej Stuczyński ce3e674528 updated dkg client traits 2024-02-07 11:55:47 +00:00
Jędrzej Stuczyński c9f5594ca5 contract changes 2024-02-07 11:55:47 +00:00
Jędrzej Stuczyński a7feeaa660 dealing metadata storage logic 2024-02-07 11:55:47 +00:00
Jędrzej Stuczyński e7bc50fc4a resharing test + bugfixes 2024-02-07 11:55:47 +00:00
Jędrzej Stuczyński e926a1e2c0 fixed bug in DKG to allow for different sets of dealers and receivers 2024-02-07 11:55:47 +00:00
Jędrzej Stuczyński bd9a628a98 restored key derivation tests 2024-02-07 11:55:47 +00:00
Jędrzej Stuczyński 19a9d5413d restored dealings tests 2024-02-07 11:55:46 +00:00
Jędrzej Stuczyński 016ab58648 updated contract schema 2024-02-07 11:55:46 +00:00
Jędrzej Stuczyński 8ec7534b57 clippy fixes 2024-02-07 11:55:46 +00:00
Jędrzej Stuczyński 3c66ab9adc test code compiles
but doesnt fully work yet
2024-02-07 11:55:46 +00:00
Jędrzej Stuczyński a66f63e34d cleanup 2024-02-07 11:55:46 +00:00
Jędrzej Stuczyński c9814a1c6e more completed key derivation 2024-02-07 11:55:46 +00:00
Jędrzej Stuczyński 59d31cfa2b more completed key validation 2024-02-07 11:55:46 +00:00
Jędrzej Stuczyński 6d9bc302ff more completed key finalization 2024-02-07 11:55:45 +00:00
Jędrzej Stuczyński 75cc310fc8 happy path for key finalization 2024-02-07 11:55:45 +00:00
Jędrzej Stuczyński bd7eebf463 happy path for key validation 2024-02-07 11:55:45 +00:00
Jędrzej Stuczyński c31561d46d actually working happy path with a unit test 2024-02-07 11:55:45 +00:00
Jędrzej Stuczyński faffdf9b2f happy path for key derivation 2024-02-07 11:55:45 +00:00
Jędrzej Stuczyński 7081076842 improved test fixture + dealing exchange test 2024-02-07 11:55:45 +00:00
Jędrzej Stuczyński b0174dcd0b [wip] dealing exchange 2024-02-07 11:55:45 +00:00
Jędrzej Stuczyński 90de0a30a8 storing epoch id alongside coconut key 2024-02-07 11:55:44 +00:00
Jędrzej Stuczyński 546e7c794f [wip]: improving error recovery during key submission phase 2024-02-07 11:55:44 +00:00
Jędrzej Stuczyński a1f68170c9 more explicit errors in the controller outer loop 2024-02-07 11:55:44 +00:00
Jędrzej Stuczyński ae29e86db0 cleaned up key loading 2024-02-07 11:55:44 +00:00
Jędrzej Stuczyński 359f038dff removed the dkg client retries 2024-02-07 11:55:44 +00:00
Jędrzej Stuczyński 0aa8084625 cargo fmt 2024-02-07 11:55:44 +00:00
Jędrzej Stuczyński 9b7815d45b making nym-api aware of the changes 2024-02-07 11:55:44 +00:00
Jędrzej Stuczyński ad5a167fe5 client support 2024-02-07 11:55:43 +00:00
Jędrzej Stuczyński 16f7ac9998 schema 2024-02-07 11:55:43 +00:00
Jędrzej Stuczyński 0235932dda making dkg kick off when a start message is sent 2024-02-07 11:55:43 +00:00
Jędrzej Stuczyński 96fd084582 fixed the return type of the query 2024-02-07 11:55:43 +00:00
Jędrzej Stuczyński 7344248f3b added a query msg for the data 2024-02-07 11:55:43 +00:00
Jędrzej Stuczyński 824dfa3d6d added cw2 interface to dkg contract 2024-02-07 11:55:43 +00:00
Jędrzej Stuczyński 2548c8d42d missing test fix 2024-02-07 11:55:43 +00:00
Jędrzej Stuczyński f4facc08ea fixed tests 2024-02-07 11:55:42 +00:00
Jędrzej Stuczyński f20f96831a api support: submit ed25519 public key alongside the bte public key 2024-02-07 11:55:42 +00:00
Jędrzej Stuczyński a94196eb82 submit ed25519 public key alongside the bte public key 2024-02-07 11:55:42 +00:00
Jędrzej Stuczyński 02884d183d reusing already generated dealings 2024-02-07 11:55:42 +00:00
Jędrzej Stuczyński 75b02c739d client support 2024-02-07 11:55:42 +00:00
Jędrzej Stuczyński 3b39ec4b28 schema 2024-02-07 11:55:42 +00:00
Jędrzej Stuczyński 8a6b6ead95 contract query for dealing status 2024-02-07 11:55:42 +00:00
Jędrzej Stuczyński 6b6bbe535f fixed dealings query arguments 2024-02-07 11:55:42 +00:00
Jędrzej Stuczyński 85d9d65da3 more clippy 2024-02-07 11:55:41 +00:00
Jędrzej Stuczyński 9f580d7bc2 updated dkg schema 2024-02-07 11:55:41 +00:00
Jędrzej Stuczyński 4dee8858da clippy 2024-02-07 11:55:41 +00:00
Jędrzej Stuczyński 49797d46bb removed old debug code 2024-02-07 11:55:41 +00:00
Jędrzej Stuczyński 4060489bd1 ephemera contract fix 2024-02-07 11:55:41 +00:00
Jędrzej Stuczyński 205e44a857 fixes 2024-02-07 11:55:41 +00:00
Jędrzej Stuczyński 6bf9dca722 reintroducing bug in deterministic_filter_dealers to make tests pass
yes, it's as bad as it sounds
2024-02-07 11:55:41 +00:00
Jędrzej Stuczyński 48be25f9c7 ability to query for dkg contract state 2024-02-07 11:55:40 +00:00
Jędrzej Stuczyński 58080ec681 client support 2024-02-07 11:55:40 +00:00
Jędrzej Stuczyński 45e8d3d78e renaming 2024-02-07 11:55:40 +00:00
Jędrzej Stuczyński c7b8622cf4 removed todos from commented tests 2024-02-07 11:55:40 +00:00
Jędrzej Stuczyński fbd58122f4 storage and query tests 2024-02-07 11:55:40 +00:00
Jędrzej Stuczyński 13f8449dc8 updated dealings queries 2024-02-07 11:55:40 +00:00
Jędrzej Stuczyński db36f72200 storing dealings in new map 2024-02-07 11:55:40 +00:00
Jędrzej Stuczyński e09986e505 fixed arguments for installing yarn (#4376) 2024-02-07 12:52:59 +01:00
Jędrzej Stuczyński bb3c015633 Merge pull request #4353 from nymtech/feature/gateway-cached-vk
make gateway cache master verification keys between requests
2024-02-07 11:31:12 +00:00
Jon Häggblad b21346064e Add disconnect request/response for the future 2024-02-07 10:18:23 +01:00
import this fa81b96951 [DOC]: hotfix - typo correction (#4374) 2024-02-06 16:03:17 +01:00
Jon Häggblad 8cccc9ab24 Bump IPR request version 2024-02-06 11:01:54 +01:00
Drazen Urch b567ac22d3 Fix builds action (#4372)
* Fix builds action

* Filter deb files
2024-02-05 22:05:21 +01:00
Jon Häggblad b43a1b8c94 Include destination in error reply 2024-02-05 11:27:28 +01:00
Jon Häggblad d7da6ed1ab Remove unused error case 2024-02-05 09:01:11 +01:00
Jon Häggblad 4d62dc9c74 Respond to sender on version mismatch 2024-02-04 18:34:29 +01:00
import this 2d39f3c722 [DOC]: NymVPN GUI new auto-script implementation (#4369)
Binaries have new name convention and the script was failing. This PR solves the issue for both MacOS and Linux users.
2024-02-02 19:11:21 +00:00
Jon Häggblad 3d122f45b4 Add two more error responses likely to be used in the future 2024-02-02 17:02:24 +01:00
Jon Häggblad cb375f15c2 Add ipr response for version mismatch 2024-02-02 16:43:52 +01:00
Tommy Verrall 7406fdd677 Merge pull request #4363 from nymtech/jon/ci-cargo-deny-pull-request-trigger
Enable pull_request trigger on ci-cargo-deny
2024-02-02 16:16:52 +01:00
Jon Häggblad d7d4c9f09a Split ip-packet-requests types into modules 2024-02-02 14:49:51 +01:00
Tommy Verrall 94d83648c2 Merge pull request #4357 from nymtech/chore/update-rocket
Chore/update rocket
2024-02-01 19:50:57 +01:00
Tommy Verrall aa51af7023 Merge pull request #4366 from nymtech/feature/validator-rewarder-monitor-only
Add config to run the block signing in monitoring mode only
2024-02-01 19:29:20 +01:00
import this f45ed78806 [DOC] : add NymVPN videos (#4367)
* create community councel and landing pages stub

* address review comments -> finished

* remove redundant

* reorganize menu and fix link

* branch url fix

* update testing video
2024-02-01 13:50:14 +00:00
import this c0337ec1d4 [DOC/operators]: Legal Forum - Community landing pages stub (#4365)
* create community councel and landing pages stub

* address review comments -> finished

* remove redundant
2024-02-01 07:41:24 +00:00
Tommy Verrall 6fe049d1a2 Merge pull request #4351 from nymtech/move-ppa-s3
Clean up git, update docs,
2024-02-01 06:11:22 +01:00
Mark Sinclair 63ed99d4d6 Add config to run the block signing in monitoring mode only. Will write 0's as the hash for rewarding. 2024-01-31 11:46:57 +00:00
Jędrzej Stuczyński 2061629d1d Merge pull request #4364 from nymtech/bugfix/rewarding-epoch-start
[bugfix] make sure first rewarding epoch starts at :00
2024-01-31 09:30:50 +00:00
Jędrzej Stuczyński 9b99a19ba0 [bugfix] make sure first rewarding epoch starts at :00 2024-01-31 09:08:21 +00:00
Jon Häggblad 6a3afb50b8 Remove continue-on-error for cargo deny check licenses 2024-01-31 09:40:51 +01:00
Jon Häggblad bea64b926f Add license to cpu-cycles matching libcpucycles 2024-01-30 21:56:34 +01:00
Jon Häggblad 3b83c30558 Add zlib to the list of allowed licenses 2024-01-30 21:37:19 +01:00
Jon Häggblad ceeccbba07 License typo 2024-01-30 21:37:19 +01:00
Jon Häggblad be55bb61cb Add missing license annotations to ephemera and bity integration 2024-01-30 21:37:08 +01:00
Jon Häggblad f2af35fc2e Enable pull_request trigger on ci-cargo-deny 2024-01-30 13:56:12 +01:00
Jon Häggblad b874fc9314 Standalone ip-packet-router (#4342)
* Initial copy of code from network-requester

* Fix unused

* Fix reading nym-api

* Log env setup steps

* rustfmt

* fix

* Fix unused

* Log number of retransmissions instead of rate
2024-01-30 13:15:34 +01:00
Jędrzej Stuczyński 914c586e68 Merge pull request #4346 from nymtech/feature/rewarder-whitelist
Feature/rewarder whitelist
2024-01-30 10:08:21 +00:00
Jon Häggblad 10ba3c2ab9 Fix printing percentage instead of fraction (#4359) 2024-01-29 22:53:35 +01:00
Jędrzej Stuczyński 7e32787ab2 updated lock file 2024-01-26 17:28:01 +00:00
Jędrzej Stuczyński 7062f69e45 updated rocket in explorer-api 2024-01-26 17:27:51 +00:00
Jędrzej Stuczyński 5e98c14a98 updated rocket in network statistics 2024-01-26 17:27:42 +00:00
Jędrzej Stuczyński f04d1fea56 updated rocket in nym-api 2024-01-26 17:27:33 +00:00
Jędrzej Stuczyński 339c6c6d24 finally using the correct feature in nym-node for utoipa 2024-01-26 17:21:24 +00:00
Jędrzej Stuczyński bd6ba89e96 removed ephemera usage from nym-api 2024-01-26 17:21:01 +00:00
import this 836e237116 [DOC] Hot-Fix (#4355)
* update gui ato-script

* update scripts and simplify steps

* finish NymVPN demo guide update
2024-01-26 16:38:41 +00:00
import this 0f9bd648a1 [DOC]: NymVPN auto-scripts update (#4350)
* update gui ato-script

* update scripts and simplify steps
2024-01-26 14:29:25 +00:00
Jędrzej Stuczyński 0c2c0bdc54 delay acquiring vk lock 2024-01-26 12:11:43 +00:00
Jędrzej Stuczyński 991cc3fa01 make gateway cache master verification keys between requests 2024-01-26 12:07:51 +00:00
Jon Häggblad 3510ee8df6 Report packet traffic rates in nym client (#4345)
* Report packet traffic rates

* Tweak log

* Check for unusual events

* Log tweaks
2024-01-26 12:13:46 +01:00
Jon Häggblad 6774158e7a Upgrade publicsuffix crate to latest (#4341)
* Upgrade publicsuffix crate to latest

This is a step in removing dependencies on OpenSSL

* fix clippy
2024-01-26 10:35:12 +01:00
durch f98698a121 Clean up git 2024-01-26 09:50:18 +01:00
import this 8e99c17f49 [DOC]: Update NymVPN Guides to v0.0.3 (#4347)
* correct GW API endpoint url

* update shasum verification

* update nym-vpn versions

* syntax edit

* change vars in book.toml

* fix name convention

* address feedback changes

* udpdate script name
2024-01-24 17:19:39 +00:00
mx ab4cc9b282 C++ FFI (#4348)
* first commit in monorepo

* *formatting
*added license

* Fix up license headers

---------

Co-authored-by: mfahampshire <mfahampshire@pm.me>
Co-authored-by: Mark Sinclair <mmsinclair@users.noreply.github.com>
2024-01-24 15:05:59 +00:00
Jon Häggblad dbe6a5de7d Fix reported sizes of the received packets (#4343)
The received packet sizes as reported in the stats should include the
encryption that is decrypted by the client. Note that this does not
include the sphinx encryption, which is already removed by the exit
gateway. This is also the reason for the relatively large discrepancy of
the reported sent and received packets.
2024-01-24 14:54:40 +01:00
Drazen Urch 1948fd8e67 Publish deb packages to builds.ci (#4344)
* Publish deb

* Pass secret as argument

* Install cargo-deb
2024-01-24 13:18:52 +01:00
Jędrzej Stuczyński c8f38ae785 added whitelisting information in logs 2024-01-23 15:10:53 +00:00
Jędrzej Stuczyński f32ea17de5 disabled credential issuance by default 2024-01-23 15:05:53 +00:00
Jędrzej Stuczyński 4ac25aef4d setting 0 ratios for not whitelisted runners 2024-01-23 14:54:41 +00:00
Jędrzej Stuczyński 3ad6a31e1f don't increment total issued credentials from not whitelisted nodes 2024-01-23 14:52:38 +00:00
Jędrzej Stuczyński 6cacc53e5a resolved old todo 2024-01-23 14:43:46 +00:00
Jędrzej Stuczyński 387933a975 using whitelisting information for rewarding 2024-01-23 14:41:15 +00:00
Jędrzej Stuczyński f6c24412c0 checking for empty whitelists 2024-01-23 13:54:19 +00:00
Jędrzej Stuczyński 5c753c0794 added new whitelist entries to the config 2024-01-23 13:53:31 +00:00
Tommy Verrall 67132161f4 Merge pull request #4332 from nymtech/update/explorer-rounded-values
Mixnode table - Round value to 2dp
2024-01-22 10:42:58 +01:00
Jon Häggblad 643f54024b Client packet counters (#4325)
* WIP: put in some packet counters

* ws packet counters

* wip

* Add static counters to client traffic stream

* Tweak status log message

* Add packet statistics control

* fixup! Add static counters to client traffic stream

* tweak log

* Move the packet statistics control one level up

* Redo packet stats control to collect locally

* Switch loop cover traffic report over to new channel mechanism

* Switch packet stats in real message stream to channel report

* Finished switching over to channel reporting

* Fix handle stats event

* Log packets received

* Tidy up

* rustfmt

* Add strongly typed stats reporter

* Count cover packets as well

* Log packet sizes sent

* Also log recieved sizes
2024-01-22 09:00:11 +01:00
serinko 16aaf7b5df [DOC]: FAQ Updates (#4339)
* add mixnet live stats to faq

* add point to mixnet faq

* syntax edit

* addressed comments
2024-01-19 14:09:31 +00:00
serinko 17c6b79735 delete redundant leftovers (#4340) 2024-01-19 11:38:03 +00:00
Tommy Verrall 8bd758ad0e Update sandbox.env (#4331) 2024-01-19 11:18:14 +01:00
Jon Häggblad a51fc0cb9e Restore BinaryBuildInformation schema (#4333)
* wip

* Restore BinaryBuildInformation schema
2024-01-19 11:16:25 +01:00
Mark Sinclair fd68debf9d nym-cli: add command to broadcast a transaction with multiple send tokens in it 2024-01-18 15:41:02 +00:00
serinko ae602ae771 [DOC]: Edit commands and text flow (#4337)
* syntax hotfix

erase a white space

* edit numbering

* edit numbering

* edit numbering

* syntax edit

* syntax edit
2024-01-18 11:30:10 +00:00
Sachin Kamath d6d36364b0 Add full node configuration and requirements (#4335)
* docs: add CORS line to maintenance page

* docs: add full node configuration and size to nym-api page

* docs: fix review comments
2024-01-18 09:40:10 +00:00
serinko accb42cad9 [DOCs]: serinko/syntax-hotfix (#4334)
* [DOCs]: nymvpn syntax hotfix

* cli naming hotfix
2024-01-17 14:35:24 +00:00
serinko dd43c5d2d2 [DOCs]: Create NymVPN user manual (#4323)
* initialise new nymvpn guide pages

* docs: nymvpn guide, testing, troubleshooting and faq

* add faq

* remove todo points

* resolve review comments

* change landing page order

* incorporate huxis user feedback

* add binaries link

* change menu naming -> upper case

* final version for cryptotalk demo

* change naming convention client -> cli

* initialise clean and organized  nymvpn guides

* remove redundant

* add faq page

* add cli.md content

* add gui.md content

* almost final version - ready for review

* simplify menu titles

* finished version for review and production

* last tweak

* addressed requests

* syntax fix

* add extra intro warning

* yank directly ./nym-cli --help output text

* change landing page and warning -> info

* add variables and finish the guides

* edit point formatting
2024-01-17 14:09:05 +00:00
fmtabbara e42d46100a allow currencyToString function to accept an object with amount, dp, and denom properties 2024-01-17 13:36:34 +00:00
Drazen Urch ed8b1841dc nym-cli deb + ppa (#4330) 2024-01-17 11:12:46 +01:00
Drazen Urch dd15a9454a Add nym-gateway to ppa repo (#4321)
* Add gateway ppa scaffolding

* Resolve host ip address, add curl dep

* make deb -> make ppa

* Add build targets for deb packages

* Add gateway public-ips

* Update PPA repo

* Typo
2024-01-16 18:31:15 +01:00
Jędrzej Stuczyński f4e42d74c4 Merge pull request #4326 from nymtech/bugfix/nymvisor-windows-ci
Bugfix/nymvisor windows ci
2024-01-16 11:36:47 +01:00
Pierre Dommerc 9de1e6e844 chore: remove nym-vpn projects (#4327) 2024-01-16 11:10:26 +01:00
Tommy Verrall 713df39106 Merge pull request #4324 from nymtech/feature/bity-sell
Update text on buy page to Buy/Sell
2024-01-15 16:55:18 +01:00
Jędrzej Stuczyński 5ec4674f9b even more target locking 2024-01-15 15:45:19 +00:00
Jędrzej Stuczyński 58c5092e80 added a dummy main for non unix targets 2024-01-15 15:18:52 +00:00
Jędrzej Stuczyński 677ad54a7f used global unix cfg 2024-01-15 14:54:49 +00:00
fmtabbara 5e17c3199f update text on buy page to buy/sell 2024-01-15 14:32:39 +00:00
Tommy Verrall 3c3a34ec0f Merge pull request #4322 from nymtech/update-localnet-script
Check that localnet is running fromt the scripts dir
2024-01-15 13:43:27 +01:00
Tommy Verrall e9b442e634 Merge pull request #4303 from nymtech/dependabot/npm_and_yarn/follow-redirects-1.15.4
Bump follow-redirects from 1.15.3 to 1.15.4
2024-01-15 13:42:55 +01:00
Tommy Verrall ca02e2bce1 Merge pull request #4310 from nymtech/dependabot/npm_and_yarn/wasm/node-tester/internal-dev/follow-redirects-1.15.4
Bump follow-redirects from 1.15.2 to 1.15.4 in /wasm/node-tester/internal-dev
2024-01-15 13:42:36 +01:00
Tommy Verrall 985ab43fe9 Merge pull request #4306 from nymtech/dependabot/npm_and_yarn/clients/native/examples/js-examples/websocket/follow-redirects-1.15.4
Bump follow-redirects from 1.14.9 to 1.15.4 in /clients/native/examples/js-examples/websocket
2024-01-15 13:42:12 +01:00
dependabot[bot] f4dad37b14 Bump follow-redirects from 1.15.2 to 1.15.4 in /wasm/client/internal-dev (#4311)
Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.15.2 to 1.15.4.
- [Release notes](https://github.com/follow-redirects/follow-redirects/releases)
- [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.15.2...v1.15.4)

---
updated-dependencies:
- dependency-name: follow-redirects
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-15 11:52:56 +01:00
durch 08a57fa8df Check that we are running fromt the scripts dir 2024-01-15 10:25:51 +01:00
Tommy Verrall 98e88e2f11 Merge pull request #4253 from nymtech/feature/validator-rewarder
Feature/validator rewarder
2024-01-15 09:25:26 +01:00
Tommy Verrall 2a589b049c Merge pull request #4316 from nymtech/feature/bump_vergen
Bump vergen version to latest
2024-01-12 14:44:09 +00:00
Tommy Verrall 9bcd56e254 Merge pull request #4312 from nymtech/dependabot/npm_and_yarn/wasm/mix-fetch/internal-dev/follow-redirects-1.15.4
Bump follow-redirects from 1.15.2 to 1.15.4 in /wasm/mix-fetch/internal-dev
2024-01-12 12:58:55 +00:00
Bogdan-Ștefan Neacşu 025ba2ec5f Bump vergen version to latest 2024-01-12 14:46:37 +02:00
Tommy Verrall 1a1d11c447 Merge pull request #4247 from nymtech/fix/test-route-construction
Only use good nodes for test route construction
2024-01-12 12:28:21 +00:00
serinko 958bc2ae9a [DOCs]: NymVPN alpha - pages for events (#4309)
* initialise new nymvpn guide pages

* docs: nymvpn guide, testing, troubleshooting and faq

* add faq

* remove todo points

* resolve review comments

* change landing page order

* incorporate huxis user feedback

* add binaries link

* change menu naming -> upper case

* final version for cryptotalk demo

* change naming convention client -> cli
2024-01-11 16:34:25 +00:00
Jon Häggblad d3d5cc3424 Don't build wg deps where it's not supported (#4305)
* Don't build wg deps where it's not supported

* Fix compilation

* Another fix

* More fixes

* another fix
2024-01-11 13:53:57 +01:00
Pierre Dommerc a834bb17f8 chore(vpn-desktop): bump version 0.0.2 (#4314)
* bump version

* add nym-vpn html icon
2024-01-11 12:18:33 +01:00
Zane Schepke cee6d8c308 Merge pull request #4298 from nymtech/fix/vpndesktop_ui_divergences
fix(vpn-desktop-ui): fix design divergences
2024-01-11 06:03:54 -05:00
Zane Schepke 142eaf533b fix macos artifact 2024-01-11 06:01:37 -05:00
Jon Häggblad 42365769f8 Update Cargo.lock for nym-vpn-ui (#4313) 2024-01-11 09:52:44 +01:00
pierre 9fc822298f fix overflow padding
fix settings screens
remove spin animation on connect button
use cursor progress
add select-none on some elements
2024-01-11 06:56:01 +01:00
dependabot[bot] cfb9f3d356 Bump follow-redirects in /wasm/mix-fetch/internal-dev
Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.15.2 to 1.15.4.
- [Release notes](https://github.com/follow-redirects/follow-redirects/releases)
- [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.15.2...v1.15.4)

---
updated-dependencies:
- dependency-name: follow-redirects
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-10 23:47:45 +00:00
dependabot[bot] ea386b6145 Bump follow-redirects in /wasm/node-tester/internal-dev
Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.15.2 to 1.15.4.
- [Release notes](https://github.com/follow-redirects/follow-redirects/releases)
- [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.15.2...v1.15.4)

---
updated-dependencies:
- dependency-name: follow-redirects
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-10 23:47:41 +00:00
pierre 75221cfd3e wip 2024-01-10 18:25:35 +01:00
pierre 50f71a21e0 fix various design divergences 2024-01-10 18:16:55 +01:00
pierre cfa9ecfcc4 fix various design divergences 2024-01-10 17:52:10 +01:00
Jon Häggblad 549b33cd91 Fix clippy in beta toolchain (#4299)
* clippy::lines_filter_map_ok

* clippy::ineffective-open-options
2024-01-10 15:29:05 +01:00
Tommy Verrall be46da9906 Merge pull request #4302 from nymtech/dependabot/npm_and_yarn/nym-api/tests/follow-redirects-1.15.4
Bump follow-redirects from 1.15.1 to 1.15.4 in /nym-api/tests
2024-01-10 13:54:42 +00:00
Tommy Verrall 66d123312f Merge pull request #4301 from nymtech/dependabot/npm_and_yarn/testnet-faucet/follow-redirects-1.15.4
Bump follow-redirects from 1.14.8 to 1.15.4 in /testnet-faucet
2024-01-10 13:54:25 +00:00
Tommy Verrall a29f3db5fb Merge pull request #4304 from nymtech/jon/update-openssl
cargo update -p openssl
2024-01-10 13:53:13 +00:00
dependabot[bot] d0fa1792e2 Bump follow-redirects in /clients/native/examples/js-examples/websocket
Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.14.9 to 1.15.4.
- [Release notes](https://github.com/follow-redirects/follow-redirects/releases)
- [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.14.9...v1.15.4)

---
updated-dependencies:
- dependency-name: follow-redirects
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-09 19:35:21 +00:00
Jon Häggblad f452d97979 cargo update -p openssl 2024-01-09 14:14:42 +01:00
Jędrzej Stuczyński 9b2d224e54 clippy 2024-01-09 11:03:05 +01:00
Jędrzej Stuczyński 3f504d7500 fixed builds of other binaries 2024-01-09 11:03:05 +01:00
Jędrzej Stuczyński 67701290d3 cargo fmt 2024-01-09 11:03:05 +01:00
Jędrzej Stuczyński 22541f5a79 smoothing some rough edges 2024-01-09 11:03:05 +01:00
Jędrzej Stuczyński bd8f666405 config template 2024-01-09 11:03:05 +01:00
Jędrzej Stuczyński a3c1541660 actually sending the rewards 2024-01-09 11:03:05 +01:00
Jędrzej Stuczyński 6c1d14a4bc clippy 2024-01-09 11:03:05 +01:00
Jędrzej Stuczyński defd148d73 cli arguments + balance check 2024-01-09 11:03:05 +01:00
Jędrzej Stuczyński 162ff71814 more granual configs 2024-01-09 11:03:05 +01:00
Jędrzej Stuczyński 5c864cb055 monitoring done 2024-01-09 11:03:05 +01:00
Jędrzej Stuczyński cfc13671a4 most of the issuance monitoring logic 2024-01-09 11:03:05 +01:00
Jędrzej Stuczyński 668a255e0d issuance score calculation logic 2024-01-09 11:03:05 +01:00
Jędrzej Stuczyński 31d8352621 persisting rewarding data 2024-01-09 11:03:05 +01:00
Jędrzej Stuczyński 4f6fe88b4c starting on persistence 2024-01-09 11:03:05 +01:00
Jędrzej Stuczyński 397ef8723d block signing related code 2024-01-09 11:03:05 +01:00
Jędrzej Stuczyński 2c2223947c wip 2024-01-09 11:03:04 +01:00
Jędrzej Stuczyński e1c0638f1e getting signing rewards 2024-01-09 11:02:41 +01:00
Jędrzej Stuczyński 13fa2119fc wip 2024-01-09 11:02:41 +01:00
Jędrzej Stuczyński 8f24e8f208 starting to integrate scraper into the rewarder 2024-01-09 11:02:40 +01:00
Jędrzej Stuczyński 37dd20ded1 wip2 2024-01-09 11:01:17 +01:00
Jędrzej Stuczyński b4b32bb907 wip 2024-01-09 10:59:52 +01:00
dependabot[bot] c1718154cb Bump follow-redirects from 1.15.3 to 1.15.4
Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.15.3 to 1.15.4.
- [Release notes](https://github.com/follow-redirects/follow-redirects/releases)
- [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.15.3...v1.15.4)

---
updated-dependencies:
- dependency-name: follow-redirects
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-09 09:32:28 +00:00
dependabot[bot] 3eb7710a12 Bump follow-redirects from 1.15.1 to 1.15.4 in /nym-api/tests
Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.15.1 to 1.15.4.
- [Release notes](https://github.com/follow-redirects/follow-redirects/releases)
- [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.15.1...v1.15.4)

---
updated-dependencies:
- dependency-name: follow-redirects
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-09 09:30:41 +00:00
dependabot[bot] d1c9251904 Bump follow-redirects from 1.14.8 to 1.15.4 in /testnet-faucet
Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.14.8 to 1.15.4.
- [Release notes](https://github.com/follow-redirects/follow-redirects/releases)
- [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.14.8...v1.15.4)

---
updated-dependencies:
- dependency-name: follow-redirects
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-09 09:30:36 +00:00
Tommy Verrall 62894e2b40 Merge pull request #4300 from nymtech/jon/update-lock
Update Cargo.lock files
2024-01-09 09:29:23 +00:00
Jon Häggblad bd7fd1a61c Update Cargo.lock files 2024-01-09 10:12:02 +01:00
pierre 28f118c73b provide lato font 2024-01-08 17:22:25 +01:00
Tommy Verrall 65699736ee Merge pull request #4018 from nymtech/feature/nym-node-api-tests
Initial step to adding nym-node functional tests
2024-01-08 15:49:37 +00:00
benedettadavico caba594c95 update workflow file 2024-01-08 16:23:57 +01:00
benedettadavico 746d52d017 Merge remote-tracking branch 'origin/develop' into feature/nym-node-api-tests 2024-01-08 16:11:38 +01:00
Zane Schepke e323c05b33 Merge pull request #4297 from nymtech/chore/vpndesktop_update_deps
chore(vpn_desktop): update js dependencies
2024-01-08 09:42:34 -05:00
pierre abdf071448 update js dependencies 2024-01-08 15:35:37 +01:00
Zane Schepke a6f2b0e8c8 feat(vpn_desktop): add entry node location selector support (#4296)
* entry selector read from state

* remove entry_node_location from config

---------

Co-authored-by: pierre <dommerc.pierre@gmail.com>
2024-01-08 12:17:53 +01:00
Tommy Verrall f78b4a1742 Merge pull request #4242 from nymtech/feature/basic-scraper
Feature/basic scraper
2024-01-08 11:04:09 +00:00
Tommy Verrall d4fde7b788 Merge pull request #4194 from nymtech/dependabot/cargo/nym-vpn/ui/src-tauri/openssl-0.10.60
Bump openssl from 0.10.59 to 0.10.60 in /nym-vpn/ui/src-tauri
2024-01-08 10:02:19 +00:00
Tommy Verrall d5a2952ef9 Merge pull request #4255 from nymtech/jon/add-cargo-about
Add cargo-about files
2024-01-08 09:59:16 +00:00
Tommy Verrall 206b6ba742 Merge pull request #4274 from nymtech/dependabot/npm_and_yarn/tauri-apps/cli-1.5.6
Bump @tauri-apps/cli from 1.5.2 to 1.5.6
2024-01-08 09:58:13 +00:00
Zane Schepke 67449b1c19 Merge pull request #4295 from nymtech/chore/vpndesktop_bump_version
chore(vpn_desktop): bump version
2024-01-05 12:37:49 -05:00
pierre 8d6e5d4fff bump version 2024-01-05 18:30:19 +01:00
Zane Schepke f448355b35 Merge pull request #4294 from nymtech/feat/vpnapp_overflow_scroll
fix(vpn_desktop): fix vertical overflow
2024-01-05 11:15:52 -05:00
pierre cf78af6b98 redo cursor pointer 2024-01-05 17:01:18 +01:00
pierre d041cfe5c5 disalbe settings not implemented yet 2024-01-05 16:55:33 +01:00
pierre 85b0b6d73d fix vertical overflow 2024-01-05 13:44:01 +01:00
Zane Schepke 685019884f feat(vpn-desktop): support screen UI and routing (#4279)
* add base setting screen and routing

* add version

* add logs icons

* fix comments

* refactor to nested routes

* add settingslayout

* remove useless note

* fix typecheck

* fix exports and optionals

* fix icon

---------

Co-authored-by: pierre <dommerc.pierre@gmail.com>
2024-01-04 15:55:46 +01:00
Tommy Verrall cd9d4eebd3 Merge pull request #4258 from nymtech/jon/exit-policy-for-portless
Apply exit policy check on destination ips without port
2024-01-03 09:55:09 +00:00
Jędrzej Stuczyński 78610c7e28 Chore/nym api commands (#4225)
* created run and init commands for nym-api + nasty mnemonic workaround

* removed dead code

* cargo fmt + clippy

* fixed key loader

* made announce address optional and removed the nonobvious fallback value

* clippy

* removed contract addresses from config template

* fixed conflicting arguments macro

* post-rebasing fixes: applied client macro to balance method
2024-01-03 10:49:10 +01:00
Tommy Verrall 496870b5f6 Merge pull request #4275 from nymtech/dependabot/npm_and_yarn/testnet-faucet/msgpackr-1.10.1
Bump msgpackr from 1.5.5 to 1.10.1 in /testnet-faucet
2024-01-03 08:55:42 +00:00
serinko 7eac5e3529 url correction (#4281) 2024-01-02 14:22:47 +00:00
Jędrzej Stuczyński 4ad4072709 naively resolve gateway credential spending race condition (#4229)
a non-naive solution would require queuing up pending request and batch executing them
2024-01-02 14:47:01 +01:00
serinko bd3711892a remove ccc event pages (#4280) 2024-01-02 13:36:06 +00:00
Jędrzej Stuczyński b5926def85 fixed rebasing artifact 2024-01-02 12:54:12 +00:00
Jędrzej Stuczyński 50cc8bd0bf improved startup sync 2024-01-02 12:54:12 +00:00
Jędrzej Stuczyński fb1b58b5fb fixed startup sync 2024-01-02 12:54:11 +00:00
Jędrzej Stuczyński c3a9ceae52 fixed update_last_processed 2024-01-02 12:54:11 +00:00
Jędrzej Stuczyński c92a7e3e35 Squashed scraper
globally updated sqlx to 0.6.3

wip

basic processing loop

wip

starting on modules

all of the requesting logic, catching up, etc

remaining work includes persisting the data

wip

persisting block data

initial and extremely basic nyxd block scraper
2024-01-02 12:54:11 +00:00
Jędrzej Stuczyński e152c9a99e Merge pull request #4278 from nymtech/bugfix/api-tests
bugfix: gateway average uptime test
2024-01-02 13:29:59 +01:00
Jędrzej Stuczyński 78cce00adf bugfix: gateway average uptime test 2024-01-02 12:11:51 +00:00
Jędrzej Stuczyński 55e00a9a38 Feature/remove feegrant (#4227)
* nym-api using own funds when voting in multisig

* startup check for token balance

* dead code
2024-01-02 13:06:17 +01:00
Jędrzej Stuczyński 6d1b26daeb Merge pull request #4277 from nymtech/chore/1.75.0-lints
Chore/1.75.0 lints
2024-01-02 11:42:50 +01:00
Jędrzej Stuczyński 2d9e34cc81 clippy 2024-01-02 10:27:43 +00:00
Jędrzej Stuczyński 7232fd83d1 ignoring pedantic clippy lints from ephemera 2024-01-02 10:09:03 +00:00
Jędrzej Stuczyński 3816142479 ignoring unused imports created in macro expansions 2024-01-02 10:06:26 +00:00
dependabot[bot] 112ecc2e4c Bump msgpackr from 1.5.5 to 1.10.1 in /testnet-faucet
Bumps [msgpackr](https://github.com/kriszyp/msgpackr) from 1.5.5 to 1.10.1.
- [Release notes](https://github.com/kriszyp/msgpackr/releases)
- [Commits](https://github.com/kriszyp/msgpackr/commits/v1.10.1)

---
updated-dependencies:
- dependency-name: msgpackr
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-12-28 21:37:47 +00:00
dependabot[bot] 2f0fbd5ebd Bump @tauri-apps/cli from 1.5.2 to 1.5.6
Bumps [@tauri-apps/cli](https://github.com/tauri-apps/tauri) from 1.5.2 to 1.5.6.
- [Release notes](https://github.com/tauri-apps/tauri/releases)
- [Commits](https://github.com/tauri-apps/tauri/compare/@tauri-apps/cli-v1.5.2...@tauri-apps/cli-v1.5.6)

---
updated-dependencies:
- dependency-name: "@tauri-apps/cli"
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-12-28 05:09:29 +00:00
serinko f45a803139 [DOCs]: ccc-event-hotfix (#4273)
* edit script, form warning, faq landing page

* Update nym-vpn.md

update script to include wg changes if need be

* update script tests.sh

* add tests-wireguard.sh script

* syntax edit

* Update nym-vpn.md

updated testing

* remove leftover flag

* edit testing guide

* final copy edits

---------

Co-authored-by: Tommy Verrall <60836166+tommyv1987@users.noreply.github.com>
2023-12-27 08:42:38 +00:00
serinko 7e16932c4a [DOC]: CCC 23 event pages + NymVPN guide (#4261)
* initialise ccc event pages

* compose existing FAQs

* edit flow

* restructure faq

* add vpn install steps

* add testing section

* initialise troubleshooting

* note add warning

* add warning

* add run cli steps

* add args

* document running flow

* add mulwald info to args desc

* add consent warning

* add FAQ questions

* add FAQ questions

* syntax fix

* edit guide flow

* add error troubleshooting point

* add warning to use two gateways

* remove reduntant message

* add clarification on testing

* rename to 37c3 to respect convention

* delete mixnet overview, replace with a link

* delete redundant

* grammar tweaks

* add gui config steps

* syntax fix

* syntax fix

* add releases and simple command info

* syntax edits

* add clarification on test logs

* describe TUN and IP flag

* add embedded video

* spellcheck

---------

Co-authored-by: mfahampshire <mfahampshire@pm.me>
2023-12-22 14:37:28 +00:00
Zane Schepke a0a44509af Merge pull request #4271 from nymtech/feat/vpnapp_ui_zoom
feat(vpn-deskop): add ui zoom level setting
2023-12-22 07:43:35 -05:00
Zane Schepke 852ed78e5d update README 2023-12-21 12:33:58 -05:00
pierre 1ea78e8e97 add ui zoom level setting 2023-12-21 14:25:15 +01:00
Jon Häggblad 10ff165c18 Apply exit policy check on portless packets 2023-12-19 10:33:38 +01:00
Jon Häggblad eec3cc4c47 Add cargo-about files 2023-12-19 09:24:44 +01:00
durch 3126053cbe Add three measurements grace period 2023-12-14 14:50:53 +01:00
durch 54266fd5df Only use good nodes for test route construction 2023-12-13 16:39:21 +01:00
dependabot[bot] 7407872b71 Bump openssl from 0.10.59 to 0.10.60 in /nym-vpn/ui/src-tauri
Bumps [openssl](https://github.com/sfackler/rust-openssl) from 0.10.59 to 0.10.60.
- [Release notes](https://github.com/sfackler/rust-openssl/releases)
- [Commits](https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.59...openssl-v0.10.60)

---
updated-dependencies:
- dependency-name: openssl
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-11-28 21:56:44 +00:00
benedettadavico 8d9387d3ac Merge remote-tracking branch 'origin/develop' into feature/nym-node-api-tests 2023-11-09 11:22:22 +01:00
benedettadavico e8bc2c7a01 Merge remote-tracking branch 'origin/develop' into feature/nym-node-api-tests 2023-11-06 16:46:31 +01:00
benedettadavico 0486cd2e63 refactoring the utils 2023-10-24 11:16:06 +02:00
benedettadavico 604098844a node-api test updates 2023-10-23 10:59:03 +02:00
benedettadavico 65e35bd2b0 Initial step to adding nym-node functional tests 2023-10-19 12:52:46 +02:00
1183 changed files with 42558 additions and 47925 deletions
@@ -1,61 +0,0 @@
name: build-upload-binaries
on:
workflow_dispatch:
inputs:
add_tokio_unstable:
description: 'True to add RUSTFLAGS="--cfg tokio_unstable"'
required: true
default: false
type: boolean
env:
NETWORK: mainnet
jobs:
publish-nym:
strategy:
fail-fast: false
matrix:
platform: [ubuntu-20.04]
runs-on: ${{ matrix.platform }}
env:
CARGO_TERM_COLOR: always
steps:
- uses: actions/checkout@v3
- name: Install Dependencies (Linux)
run: sudo apt-get update && sudo apt-get -y install libwebkit2gtk-4.0-dev build-essential curl wget libssl-dev libgtk-3-dev libudev-dev squashfs-tools
continue-on-error: true
- name: Sets env vars for tokio if set in manual dispatch inputs
run: |
echo 'RUSTFLAGS="--cfg tokio_unstable"' >> $GITHUB_ENV
if: github.event_name == 'workflow_dispatch' && inputs.add_tokio_unstable == true
- name: Install Rust stable
uses: actions-rs/toolchain@v1
with:
toolchain: stable
- name: Build all binaries
uses: actions-rs/cargo@v1
with:
command: build
args: --workspace --release
- name: Upload Artifact
uses: actions/upload-artifact@v3
with:
name: nym-binaries-artifacts
path: |
target/release/nym-client
target/release/nym-gateway
target/release/nym-mixnode
target/release/nym-socks5-client
target/release/nym-api
target/release/nym-network-requester
target/release/nym-network-statistics
target/release/nym-cli
retention-days: 30
+81 -13
View File
@@ -2,20 +2,40 @@ name: ci-build-upload-binaries
on:
workflow_dispatch:
inputs:
add_tokio_unstable:
description: 'True to add RUSTFLAGS="--cfg tokio_unstable"'
required: true
default: false
type: boolean
enable_wireguard:
description: "Add --features wireguard"
required: true
default: false
type: boolean
enable_deb:
description: "True to enable cargo-deb installation and .deb package building"
required: false
default: false
type: boolean
schedule:
- cron: "14 0 * * *"
pull_request:
paths:
- 'clients/**'
- 'common/**'
- 'explorer-api/**'
- 'gateway/**'
- 'integrations/**'
- 'mixnode/**'
- 'sdk/rust/nym-sdk/**'
- 'service-providers/**'
- 'nym-api/**'
- 'nym-outfox/**'
- 'tools/nym-cli/**'
- 'tools/ts-rs-cli/**'
- "clients/**"
- "common/**"
- "explorer-api/**"
- "gateway/**"
- "integrations/**"
- "mixnode/**"
- "nym-api/**"
- "nym-node/**"
- "nym-outfox/**"
- "nym-validator-rewarder/**"
- "sdk/rust/nym-sdk/**"
- "service-providers/**"
- "tools/**"
- "nymvisor/**"
jobs:
publish-nym:
@@ -42,6 +62,18 @@ jobs:
- name: Install Dependencies (Linux)
run: sudo apt update && sudo apt install libudev-dev
- name: Sets env vars for tokio if set in manual dispatch inputs
run: |
echo 'RUSTFLAGS="--cfg tokio_unstable"' >> $GITHUB_ENV
if: github.event_name == 'workflow_dispatch' && inputs.add_tokio_unstable == true
- name: Set CARGO_FEATURES
run: |
echo 'CARGO_FEATURES=--features wireguard' >> $GITHUB_ENV
if: >
github.event_name == 'schedule' ||
(github.event_name == 'workflow_dispatch' && inputs.enable_wireguard == true)
- name: Install Rust stable
uses: actions-rs/toolchain@v1
with:
@@ -51,9 +83,41 @@ jobs:
uses: actions-rs/cargo@v1
with:
command: build
args: --workspace --release
args: --workspace --release ${{ env.CARGO_FEATURES }}
- name: Install cargo-deb
uses: actions-rs/cargo@v1
with:
command: install
args: cargo-deb
if: github.event_name == 'workflow_dispatch' && inputs.enable_deb == true
- name: Build deb packages
shell: bash
run: make deb
if: github.event_name == 'workflow_dispatch' && inputs.enable_deb == true
- name: Upload Artifact
if: github.event_name == 'workflow_dispatch'
uses: actions/upload-artifact@v3
with:
name: nym-binaries-artifacts
path: |
target/release/nym-client
target/release/nym-gateway
target/release/nym-mixnode
target/release/nym-socks5-client
target/release/nym-api
target/release/nym-network-requester
target/release/nym-network-statistics
target/release/nym-cli
target/release/nymvisor
retention-days: 30
# If this was a pull_request or nightly, upload to build server
- name: Prepare build output
# if: github.event_name == 'schedule' || github.event_name == 'pull_request'
shell: bash
env:
OUTPUT_DIR: ci-builds/${{ github.ref_name }}
@@ -65,8 +129,12 @@ jobs:
cp target/release/nym-api $OUTPUT_DIR
cp target/release/nym-network-requester $OUTPUT_DIR
cp target/release/nym-network-statistics $OUTPUT_DIR
cp target/release/nymvisor $OUTPUT_DIR
cp target/release/nym-cli $OUTPUT_DIR
cp target/release/explorer-api $OUTPUT_DIR
if [ ${{ github.event_name == 'workflow_dispatch' && inputs.enable_deb == true }} = true ]; then
cp target/debian/*.deb $OUTPUT_DIR
fi
- name: Deploy branch to CI www
continue-on-error: true
+5 -5
View File
@@ -1,5 +1,8 @@
name: ci-cargo-deny
on: [workflow_dispatch]
on:
workflow_dispatch:
pull_request:
jobs:
cargo-deny:
runs-on: ubuntu-22.04
@@ -7,10 +10,7 @@ jobs:
matrix:
checks:
# - advisories
- licenses
- bans sources
continue-on-error: ${{ matrix.checks == 'licenses' }}
- licenses bans sources
steps:
- uses: actions/checkout@v3
+3
View File
@@ -17,6 +17,9 @@ jobs:
steps:
- uses: actions/checkout@v2
- name: install yarn in root
run: cd ../.. && yarn install
- name: Install npm
run: npm install
-40
View File
@@ -1,40 +0,0 @@
name: ci-nym-vpn-ui-js
on:
workflow_dispatch:
pull_request:
paths:
- 'nym-vpn/ui/src/**'
- 'nym-vpn/ui/package.json'
- 'nym-vpn/ui/index.html'
jobs:
check:
runs-on: custom-linux
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install Node
uses: actions/setup-node@v3
with:
node-version: 18
- name: Install Yarn
run: npm install -g yarn
- name: Install dependencies
working-directory: nym-vpn/ui
run: yarn
- name: Type-check
working-directory: nym-vpn/ui
run: yarn typecheck
- name: Check lint
working-directory: nym-vpn/ui
run: yarn lint
- name: Check formatting
working-directory: nym-vpn/ui
run: yarn fmt:check
# - name: Run tests
# working-directory: nym-vpn/ui
# run: yarn test
- name: Check build
working-directory: nym-vpn/ui
run: yarn build
-63
View File
@@ -1,63 +0,0 @@
name: ci-nym-vpn-ui-rust
on:
workflow_dispatch:
pull_request:
paths:
- 'nym-vpn/ui/src-tauri/**'
jobs:
build:
runs-on: custom-linux
env:
CARGO_TERM_COLOR: always
CARGOTOML_PATH: ./nym-vpn/ui/src-tauri/Cargo.toml
steps:
- name: Install Dependencies (Linux)
run: sudo apt-get update && sudo apt-get -y install libwebkit2gtk-4.0-dev build-essential curl wget libssl-dev libgtk-3-dev squashfs-tools libayatana-appindicator3-dev
continue-on-error: true
- name: Checkout
uses: actions/checkout@v4
- name: Install rust toolchain
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
override: true
components: rustfmt, clippy
- name: Prepare build
run: mkdir nym-vpn/ui/dist
- name: Build
uses: actions-rs/cargo@v1
with:
command: build
args: --manifest-path ${{ env.CARGOTOML_PATH }} --features custom-protocol
# - name: Run all tests
# uses: actions-rs/cargo@v1
# with:
# command: test
# args: --manifest-path ${{ env.CARGOTOML_PATH }}
- name: Check formatting
uses: actions-rs/cargo@v1
with:
command: fmt
args: --manifest-path ${{ env.CARGOTOML_PATH }} --all -- --check
- name: Annotate with clippy checks
uses: actions-rs/clippy-check@v1
continue-on-error: true
with:
token: ${{ secrets.GITHUB_TOKEN }}
args: --manifest-path ${{ env.CARGOTOML_PATH }} --all-features
- name: Clippy
uses: actions-rs/cargo@v1
with:
command: clippy
args: --manifest-path ${{ env.CARGOTOML_PATH }} --all-features --all-targets -- -D warnings
+5 -1
View File
@@ -1,4 +1,4 @@
name: Publish Nym binaries
name: publish-nym-binaries
on:
workflow_dispatch:
@@ -29,6 +29,7 @@ jobs:
client_hash: ${{ steps.binary-hashes.outputs.client_hash }}
mixnode_hash: ${{ steps.binary-hashes.outputs.mixnode_hash }}
gateway_hash: ${{ steps.binary-hashes.outputs.gateway_hash }}
nymvisor_hash: ${{ steps.binary-hashes.outputs.nymvisor_hash }}
socks5_hash: ${{ steps.binary-hashes.outputs.socks5_hash }}
netreq_hash: ${{ steps.binary-hashes.outputs.netreq_hash }}
cli_hash: ${{ steps.binary-hashes.outputs.cli_hash }}
@@ -36,6 +37,7 @@ jobs:
client_version: ${{ steps.binary-versions.outputs.client_version }}
mixnode_version: ${{ steps.binary-versions.outputs.mixnode_version }}
gateway_version: ${{ steps.binary-versions.outputs.gateway_version }}
nymvisor_version: ${{ steps.binary-versions.outputs.nymvisor_version }}
socks5_version: ${{ steps.binary-versions.outputs.socks5_version }}
netreq_version: ${{ steps.binary-versions.outputs.netreq_version }}
cli_version: ${{ steps.binary-versions.outputs.cli_version }}
@@ -78,6 +80,7 @@ jobs:
target/release/nym-network-requester
target/release/nym-network-statistics
target/release/nym-cli
target/release/nymvisor
retention-days: 30
- id: create-release
@@ -95,6 +98,7 @@ jobs:
target/release/nym-network-requester
target/release/nym-network-statistics
target/release/nym-cli
target/release/nymvisor
push-release-data-client:
if: ${{ (startsWith(github.ref, 'refs/tags/nym-binaries-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
@@ -1,4 +1,4 @@
name: Publish Nym Connect - desktop (MacOS)
name: publish-nym-connect-macos
on:
workflow_dispatch:
release:
@@ -1,4 +1,4 @@
name: Publish Nym Connect - desktop (Ubuntu)
name: publish-nym-connect-ubuntu
on:
workflow_dispatch:
release:
@@ -1,4 +1,4 @@
name: Publish Nym Connect - desktop (Windows 10)
name: publish-nym-connect-win10
on:
workflow_dispatch:
release:
+1 -1
View File
@@ -1,4 +1,4 @@
name: Build release of Nym smart contracts
name: publish-nym-contracts
on:
workflow_dispatch:
release:
@@ -1,4 +1,4 @@
name: Publish Nym Wallet (MacOS)
name: publish-nym-wallet-macos
on:
workflow_dispatch:
release:
@@ -1,4 +1,4 @@
name: Publish Nym Wallet (Ubuntu)
name: publish-nym-wallet-ubuntu
on:
workflow_dispatch:
release:
@@ -1,4 +1,4 @@
name: Publish Nym Wallet (Windows 10)
name: publish-nym-wallet-win10
on:
workflow_dispatch:
release:
+1 -1
View File
@@ -1,4 +1,4 @@
name: Publish Typescript SDK
name: publish-sdk-npm
on:
workflow_dispatch:
+1 -1
View File
@@ -1,4 +1,4 @@
name: Releases - calculate file hashes
name: release-calculate-hash
on:
workflow_call:
+17
View File
@@ -4,6 +4,23 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
## [Unreleased]
## [2024.1-marabou] (2024-02-15)
**New Features:**
- Introduced nymvisor support for nym-api, gateway, and mixnode binaries ([#4158])
- Revamped nym-api execution with the addition of init and run commands ([#4225])
**Enhancements:**
- Implemented internal improvements for gateways to optimize internal packet routing
- Improved routing score calculation
**Bug Fixes:**
- Resolved various bugs to enhance overall stability
[#4158]: https://github.com/nymtech/nym/pull/4158
[#4225]: https://github.com/nymtech/nym/pull/4225
## [2023.5-rolo] (2023-11-28)
- Gateway won't open websocket listener until embedded Network Requester becomes available ([#4166])
Generated
+568 -1772
View File
File diff suppressed because it is too large Load Diff
+19 -9
View File
@@ -27,13 +27,12 @@ members = [
"common/client-libs/gateway-client",
"common/client-libs/mixnet-client",
"common/client-libs/validator-client",
"common/coconut-interface",
"common/commands",
"common/config",
"common/cosmwasm-smart-contracts/coconut-bandwidth-contract",
"common/cosmwasm-smart-contracts/coconut-dkg",
"common/cosmwasm-smart-contracts/contracts-common",
"common/cosmwasm-smart-contracts/ephemera",
# "common/cosmwasm-smart-contracts/ephemera",
"common/cosmwasm-smart-contracts/group-contract",
"common/cosmwasm-smart-contracts/mixnet-contract",
"common/cosmwasm-smart-contracts/multisig-contract",
@@ -43,6 +42,7 @@ members = [
"common/credential-storage",
"common/credentials",
"common/credential-utils",
"common/credentials-interface",
"common/crypto",
"common/dkg",
"common/execute",
@@ -56,6 +56,7 @@ members = [
"common/node-tester-utils",
"common/nonexhaustive-delayqueue",
"common/nymcoconut",
"common/nym-id",
"common/nymsphinx",
"common/nymsphinx/acknowledgements",
"common/nymsphinx/addressing",
@@ -67,6 +68,7 @@ members = [
"common/nymsphinx/params",
"common/nymsphinx/routing",
"common/nymsphinx/types",
"common/nyxd-scraper",
"common/pemstore",
"common/socks5-client-core",
"common/socks5/proxy-helpers",
@@ -101,9 +103,11 @@ members = [
"nym-node",
"nym-node/nym-node-requests",
"nym-outfox",
"nym-validator-rewarder",
"tools/internal/ssl-inject",
"tools/internal/sdk-version-bump",
# "tools/internal/sdk-version-bump",
"tools/nym-cli",
"tools/nym-id-cli",
"tools/nym-nr-query",
"tools/nymvisor",
"tools/ts-rs-cli",
@@ -123,9 +127,10 @@ default-members = [
"nym-api",
"tools/nymvisor",
"explorer-api",
"nym-validator-rewarder",
]
exclude = ["explorer", "contracts", "nym-wallet", "nym-connect/mobile/src-tauri", "nym-connect/desktop", "nym-vpn/ui/src-tauri", "cpu-cycles"]
exclude = ["explorer", "contracts", "nym-wallet", "nym-connect/mobile/src-tauri", "nym-connect/desktop", "nym-vpn/ui/src-tauri", "cpu-cycles", "sdk/ffi/cpp"]
[workspace.package]
authors = ["Nym Technologies SA"]
@@ -140,6 +145,7 @@ anyhow = "1.0.71"
async-trait = "0.1.68"
axum = "0.6.20"
base64 = "0.21.4"
bs58 = "0.5.0"
bip39 = { version = "2.0.0", features = ["zeroize"] }
clap = "4.4.7"
cfg-if = "1.0.0"
@@ -155,18 +161,19 @@ log = "0.4"
once_cell = "1.7.2"
parking_lot = "0.12.1"
rand = "0.8.5"
reqwest = "0.11.22"
reqwest = { version = "0.11.22", default_features = false, features = ["rustls-tls"] }
schemars = "0.8.1"
serde = "1.0.152"
serde_json = "1.0.91"
sqlx = "0.6.3"
tap = "1.0.1"
time = "0.3.30"
thiserror = "1.0.48"
tokio = "1.33.0"
tokio-util = "0.7.10"
tokio-tungstenite = "0.20.1"
tokio-tungstenite = { version = "0.20.1", features = ["rustls"] }
tracing = "0.1.37"
tungstenite = { version = "0.20.1", default-features = false }
tungstenite = { version = "0.20.1", default-features = false, features = ["rustls"] }
ts-rs = "7.0.0"
utoipa = "3.5.0"
utoipa-swagger-ui = "3.1.5"
@@ -199,9 +206,12 @@ cw-controllers = { version = "=1.1.0" }
# cosmrs-related
bip32 = "0.5.1"
cosmrs = "=0.15.0"
tendermint-rpc = "0.34" # same version as used by cosmrs
# temporarily using a fork again (yay.) because we need staking and slashing support
cosmrs = { git = "https://github.com/jstuczyn/cosmos-rust", branch ="nym-temp/all-validator-features" }
#cosmrs = { git = "https://github.com/jstuczyn/cosmos-rust", branch = "nym-temp/all-validator-features" } # unfortuntely we need a fork by yours truly to get the staking support
tendermint = "0.34" # same version as used by cosmrs
tendermint-rpc = "0.34" # same version as used by cosmrs
prost = "0.12"
# wasm-related dependencies
+17 -3
View File
@@ -12,6 +12,7 @@ help:
@echo " clippy: run clippy for all workspaces"
@echo " test: run clippy, unit tests, and formatting."
@echo " test-all: like test, but also includes the expensive tests"
@echo " deb: build debian packages
# -----------------------------------------------------------------------------
# Meta targets
@@ -157,6 +158,12 @@ build-explorer-api:
build-nym-cli:
cargo build -p nym-cli --release
build-nym-gateway:
cargo build -p nym-gateway --release
build-nym-mixnode:
cargo build -p nym-mixnode --release
# -----------------------------------------------------------------------------
# Misc
# -----------------------------------------------------------------------------
@@ -169,6 +176,13 @@ run-api-tests:
cd nym-api/tests/functional_test && yarn test:qa
# Build debian package, and update PPA
# Requires base64 encode GPG key to be set up in environment PPA_SIGNING_KEY
deb:
scripts/ppa.sh
deb-mixnode: build-nym-mixnode
cargo deb -p nym-mixnode
deb-gateway: build-nym-gateway
cargo deb -p nym-gateway
deb-cli: build-nym-cli
cargo deb -p nym-cli
deb: deb-mixnode deb-gateway deb-cli
+70
View File
@@ -0,0 +1,70 @@
<html>
<head>
<style>
@media (prefers-color-scheme: dark) {
body {
background: #333;
color: white;
}
a {
color: skyblue;
}
}
.container {
font-family: sans-serif;
max-width: 800px;
margin: 0 auto;
}
.intro {
text-align: center;
}
.licenses-list {
list-style-type: none;
margin: 0;
padding: 0;
}
.license-used-by {
margin-top: -10px;
}
.license-text {
max-height: 200px;
overflow-y: scroll;
white-space: pre-wrap;
}
</style>
</head>
<body>
<main class="container">
<div class="intro">
<h1>Third Party Licenses</h1>
<p>This page lists the licenses of the projects used in cargo-about.</p>
</div>
<h2>Overview of licenses:</h2>
<ul class="licenses-overview">
{{#each overview}}
<li><a href="#{{id}}">{{name}}</a> ({{count}})</li>
{{/each}}
</ul>
<h2>All license text:</h2>
<ul class="licenses-list">
{{#each licenses}}
<li class="license">
<h3 id="{{id}}">{{name}}</h3>
<h4>Used by:</h4>
<ul class="license-used-by">
{{#each used_by}}
<li><a href="{{#if crate.repository}} {{crate.repository}} {{else}} https://crates.io/crates/{{crate.name}} {{/if}}">{{crate.name}} {{crate.version}}</a></li>
{{/each}}
</ul>
<pre class="license-text">{{text}}</pre>
</li>
{{/each}}
</ul>
</main>
</body>
</html>
+19
View File
@@ -0,0 +1,19 @@
private = { ignore = true }
accepted = [
"0BSD",
"Apache-2.0",
"BSD-2-Clause",
"BSD-3-Clause",
"CC0-1.0",
"ISC",
"MIT",
"MPL-2.0",
"Unicode-DFS-2016",
"OpenSSL",
]
workarounds = [
"ring",
"rustls",
]
+5 -4
View File
@@ -1,6 +1,6 @@
[package]
name = "nym-client"
version = "1.1.32"
version = "1.1.33"
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"]
description = "Implementation of the Nym Client"
edition = "2021"
@@ -21,24 +21,24 @@ futures = { workspace = true } # bunch of futures stuff, however, now that I thi
# and the single instance of abortable we have should really be refactored anyway
url = { workspace = true }
bs58 = { workspace = true }
clap = { workspace = true, features = ["cargo", "derive"] }
dirs = "4.0"
lazy_static = "1.4.0"
log = { workspace = true } # self explanatory
pretty_env_logger = "0.4" # for formatting log messages
rand = { version = "0.7.3", features = ["wasm-bindgen"] } # rng-related traits + some rng implementation to use
serde = { workspace = true, features = ["derive"] } # for config serialization/deserialization
serde_json = { workspace = true }
thiserror = { workspace = true }
tap = "1.0.1"
time = { workspace = true }
tokio = { workspace = true, features = ["rt-multi-thread", "net", "signal"] } # async runtime
tokio-tungstenite = { workspace = true }
zeroize = { workspace = true }
## internal
nym-bandwidth-controller = { path = "../../common/bandwidth-controller" }
nym-bin-common = { path = "../../common/bin-common", features = ["output_format"] }
nym-client-core = { path = "../../common/client-core", features = ["fs-surb-storage", "cli"] }
nym-coconut-interface = { path = "../../common/coconut-interface" }
nym-config = { path = "../../common/config" }
nym-credential-storage = { path = "../../common/credential-storage" }
nym-credentials = { path = "../../common/credentials" }
@@ -51,5 +51,6 @@ nym-task = { path = "../../common/task" }
nym-topology = { path = "../../common/topology" }
nym-validator-client = { path = "../../common/client-libs/validator-client", features = ["http-client"] }
nym-client-websocket-requests = { path = "websocket-requests" }
nym-id = { path = "../../common/nym-id" }
[dev-dependencies]
@@ -1667,9 +1667,9 @@
}
},
"node_modules/follow-redirects": {
"version": "1.14.9",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.9.tgz",
"integrity": "sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w==",
"version": "1.15.4",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.4.tgz",
"integrity": "sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw==",
"dev": true,
"funding": [
{
@@ -2160,9 +2160,9 @@
}
},
"node_modules/ip": {
"version": "1.1.5",
"resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz",
"integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=",
"version": "1.1.9",
"resolved": "https://registry.npmjs.org/ip/-/ip-1.1.9.tgz",
"integrity": "sha512-cyRxvOEpNHNtchU3Ln9KC/auJgup87llfQpQ+t5ghoC/UhL16SWzbueiCsdTnWmqAWl7LadfuwhlqmtOaqMHdQ==",
"dev": true
},
"node_modules/ipaddr.js": {
@@ -5800,9 +5800,9 @@
}
},
"follow-redirects": {
"version": "1.14.9",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.9.tgz",
"integrity": "sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w==",
"version": "1.15.4",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.4.tgz",
"integrity": "sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw==",
"dev": true
},
"forwarded": {
@@ -6157,9 +6157,9 @@
"dev": true
},
"ip": {
"version": "1.1.5",
"resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz",
"integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=",
"version": "1.1.9",
"resolved": "https://registry.npmjs.org/ip/-/ip-1.1.9.tgz",
"integrity": "sha512-cyRxvOEpNHNtchU3Ln9KC/auJgup87llfQpQ+t5ghoC/UhL16SWzbueiCsdTnWmqAWl7LadfuwhlqmtOaqMHdQ==",
"dev": true
},
"ipaddr.js": {
@@ -0,0 +1,54 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::commands::try_load_current_config;
use crate::error::ClientError;
use clap::ArgGroup;
use nym_id::import_credential;
use std::fs;
use std::path::PathBuf;
fn parse_encoded_credential_data(raw: &str) -> bs58::decode::Result<Vec<u8>> {
bs58::decode(raw).into_vec()
}
#[derive(clap::Args)]
#[clap(group(ArgGroup::new("cred_data").required(true)))]
pub(crate) struct Args {
/// Id of client that is going to import the credential
#[clap(long)]
pub id: String,
/// Explicitly provide the encoded credential data (as base58)
#[clap(long, group = "cred_data", value_parser = parse_encoded_credential_data)]
pub(crate) credential_data: Option<Vec<u8>>,
/// Specifies the path to file containing binary credential data
#[clap(long, group = "cred_data")]
pub(crate) credential_path: Option<PathBuf>,
// currently hidden as there exists only a single serialization standard
#[clap(long, hide = true)]
pub(crate) version: Option<u8>,
}
pub(crate) async fn execute(args: Args) -> Result<(), ClientError> {
let config = try_load_current_config(&args.id)?;
let credentials_store = nym_credential_storage::initialise_persistent_storage(
&config.storage_paths.common_paths.credentials_database,
)
.await;
let raw_credential = match args.credential_data {
Some(data) => data,
None => {
// SAFETY: one of those arguments must have been set
fs::read(args.credential_path.unwrap())?
}
};
import_credential(credentials_store, raw_credential, args.version).await?;
Ok(())
}
+1 -1
View File
@@ -51,7 +51,7 @@ impl InitialisableClient for NativeClientInit {
}
}
#[derive(Args, Clone)]
#[derive(Args, Clone, Debug)]
pub(crate) struct Init {
#[command(flatten)]
common_args: CommonClientInitArgs,
+8 -7
View File
@@ -8,7 +8,6 @@ use crate::client::config::{BaseClientConfig, Config};
use crate::error::ClientError;
use clap::CommandFactory;
use clap::{Parser, Subcommand};
use lazy_static::lazy_static;
use log::{error, info};
use nym_bin_common::bin_info;
use nym_bin_common::completions::{fig_generate, ArgShell};
@@ -21,18 +20,16 @@ use nym_client_core::error::ClientCoreError;
use nym_config::OptionalSet;
use std::error::Error;
use std::net::IpAddr;
use std::sync::OnceLock;
pub(crate) mod build_info;
pub(crate) mod import_credential;
pub(crate) mod init;
pub(crate) mod run;
lazy_static! {
pub static ref PRETTY_BUILD_INFORMATION: String = bin_info!().pretty_print();
}
// Helper for passing LONG_VERSION to clap
fn pretty_build_info_static() -> &'static str {
&PRETTY_BUILD_INFORMATION
static PRETTY_BUILD_INFORMATION: OnceLock<String> = OnceLock::new();
PRETTY_BUILD_INFORMATION.get_or_init(|| bin_info!().pretty_print())
}
#[derive(Parser)]
@@ -58,6 +55,9 @@ pub(crate) enum Commands {
/// Run the Nym client with provided configuration client optionally overriding set parameters
Run(run::Run),
/// Import a pre-generated credential
ImportCredential(import_credential::Args),
/// Show build information of this binary
BuildInfo(build_info::BuildInfo),
@@ -86,6 +86,7 @@ pub(crate) async fn execute(args: Cli) -> Result<(), Box<dyn Error + Send + Sync
match args.command {
Commands::Init(m) => init::execute(m).await?,
Commands::Run(m) => run::execute(m).await?,
Commands::ImportCredential(m) => import_credential::execute(m).await?,
Commands::BuildInfo(m) => build_info::execute(m),
Commands::Completions(s) => s.generate(&mut Cli::command(), bin_name),
Commands::GenerateFigSpec => fig_generate(&mut Cli::command(), bin_name),
+6 -1
View File
@@ -1,11 +1,13 @@
use nym_client_core::error::ClientCoreError;
use nym_id::NymIdError;
#[derive(thiserror::Error, Debug)]
pub enum ClientError {
#[error("I/O error: {0}")]
IoError(#[from] std::io::Error),
#[error("client-core error: {0}")]
#[error(transparent)]
ClientCoreError(#[from] ClientCoreError),
#[error("Failed to load config for: {0}")]
@@ -20,4 +22,7 @@ pub enum ClientError {
#[error("Attempted to start the client in invalid socket mode")]
InvalidSocketMode,
#[error(transparent)]
NymIdError(#[from] NymIdError),
}
+5 -4
View File
@@ -1,6 +1,6 @@
[package]
name = "nym-socks5-client"
version = "1.1.32"
version = "1.1.33"
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
description = "A SOCKS5 localhost proxy that converts incoming messages to Sphinx and sends them to a Nym address"
edition = "2021"
@@ -8,22 +8,22 @@ rust-version = "1.56"
license.workspace = true
[dependencies]
bs58 = { workspace = true }
clap = { workspace = true, features = ["cargo", "derive"] }
lazy_static = "1.4.0"
log = { workspace = true }
pretty_env_logger = "0.4"
serde = { workspace = true, features = ["derive"] } # for config serialization/deserialization
serde_json = { workspace = true }
tap = "1.0.1"
thiserror = { workspace = true }
tokio = { version = "1.24.1", features = ["rt-multi-thread", "net", "signal"] }
rand = "0.7.3"
time = { workspace = true }
url = { workspace = true }
zeroize = { workspace = true }
# internal
nym-bin-common = { path = "../../common/bin-common", features = ["output_format"] }
nym-client-core = { path = "../../common/client-core", features = ["fs-surb-storage", "cli"] }
nym-coconut-interface = { path = "../../common/coconut-interface" }
nym-config = { path = "../../common/config" }
nym-credentials = { path = "../../common/credentials" }
nym-crypto = { path = "../../common/crypto" }
@@ -35,6 +35,7 @@ nym-ordered-buffer = { path = "../../common/socks5/ordered-buffer" }
nym-pemstore = { path = "../../common/pemstore" }
nym-topology = { path = "../../common/topology" }
nym-socks5-client-core = { path = "../../common/socks5-client-core" }
nym-id = { path = "../../common/nym-id" }
[features]
default = []
@@ -0,0 +1,54 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::commands::try_load_current_config;
use crate::error::Socks5ClientError;
use clap::ArgGroup;
use nym_id::import_credential;
use std::fs;
use std::path::PathBuf;
fn parse_encoded_credential_data(raw: &str) -> bs58::decode::Result<Vec<u8>> {
bs58::decode(raw).into_vec()
}
#[derive(clap::Args)]
#[clap(group(ArgGroup::new("cred_data").required(true)))]
pub(crate) struct Args {
/// Id of client that is going to import the credential
#[clap(long)]
pub id: String,
/// Explicitly provide the encoded credential data (as base58)
#[clap(long, group = "cred_data", value_parser = parse_encoded_credential_data)]
pub(crate) credential_data: Option<Vec<u8>>,
/// Specifies the path to file containing binary credential data
#[clap(long, group = "cred_data")]
pub(crate) credential_path: Option<PathBuf>,
// currently hidden as there exists only a single serialization standard
#[clap(long, hide = true)]
pub(crate) version: Option<u8>,
}
pub(crate) async fn execute(args: Args) -> Result<(), Socks5ClientError> {
let config = try_load_current_config(&args.id)?;
let credentials_store = nym_credential_storage::initialise_persistent_storage(
&config.storage_paths.common_paths.credentials_database,
)
.await;
let raw_credential = match args.credential_data {
Some(data) => data,
None => {
// SAFETY: one of those arguments must have been set
fs::read(args.credential_path.unwrap())?
}
};
import_credential(credentials_store, raw_credential, args.version).await?;
Ok(())
}
+1 -1
View File
@@ -51,7 +51,7 @@ impl InitialisableClient for Socks5ClientInit {
}
}
#[derive(Args, Clone)]
#[derive(Args, Clone, Debug)]
pub(crate) struct Init {
#[command(flatten)]
common_args: CommonClientInitArgs,
+8 -7
View File
@@ -9,7 +9,6 @@ use crate::config::{BaseClientConfig, Config, SocksClientPaths};
use crate::error::Socks5ClientError;
use clap::CommandFactory;
use clap::{Parser, Subcommand};
use lazy_static::lazy_static;
use log::{error, info};
use nym_bin_common::bin_info;
use nym_bin_common::completions::{fig_generate, ArgShell};
@@ -24,18 +23,16 @@ use nym_config::OptionalSet;
use nym_sphinx::params::{PacketSize, PacketType};
use std::error::Error;
use std::net::IpAddr;
use std::sync::OnceLock;
pub(crate) mod build_info;
mod import_credential;
pub mod init;
pub(crate) mod run;
lazy_static! {
pub static ref PRETTY_BUILD_INFORMATION: String = bin_info!().pretty_print();
}
// Helper for passing LONG_VERSION to clap
fn pretty_build_info_static() -> &'static str {
&PRETTY_BUILD_INFORMATION
static PRETTY_BUILD_INFORMATION: OnceLock<String> = OnceLock::new();
PRETTY_BUILD_INFORMATION.get_or_init(|| bin_info!().pretty_print())
}
#[derive(Parser)]
@@ -61,6 +58,9 @@ pub(crate) enum Commands {
/// Run the Nym client with provided configuration client optionally overriding set parameters
Run(run::Run),
/// Import a pre-generated credential
ImportCredential(import_credential::Args),
/// Show build information of this binary
BuildInfo(build_info::BuildInfo),
@@ -92,6 +92,7 @@ pub(crate) async fn execute(args: Cli) -> Result<(), Box<dyn Error + Send + Sync
match args.command {
Commands::Init(m) => init::execute(m).await?,
Commands::Run(m) => run::execute(m).await?,
Commands::ImportCredential(m) => import_credential::execute(m).await?,
Commands::BuildInfo(m) => build_info::execute(m),
Commands::Completions(s) => s.generate(&mut Cli::command(), bin_name),
Commands::GenerateFigSpec => fig_generate(&mut Cli::command(), bin_name),
+6 -1
View File
@@ -1,5 +1,7 @@
use nym_client_core::error::ClientCoreError;
use nym_id::NymIdError;
#[derive(thiserror::Error, Debug)]
pub enum Socks5ClientError {
#[error("I/O error: {0}")]
@@ -18,6 +20,9 @@ pub enum Socks5ClientError {
#[error("Fail to bind address")]
FailToBindAddress,
#[error("client-core error: {0}")]
#[error(transparent)]
ClientCoreError(#[from] ClientCoreError),
#[error(transparent)]
NymIdError(#[from] NymIdError),
}
@@ -15,4 +15,4 @@ prod:
mixnode_identity: 3pMCJswCyA19MGYWGDWT5fBk2M8ybSZGXttyAoNY5gBB
gateway_identity: 2BuMSfMW3zpeAjKXyKLhmY4QW1DXurrtSPEJ6CjX3SEh
log_level: error
time_zone: utc
time_zone: utc
@@ -1,4 +1,6 @@
import { dir } from "console";
import { readFileSync } from "fs";
import { dirname } from "path";
import { TLogLevelName } from "tslog";
import YAML from "yaml";
@@ -10,9 +12,11 @@ class ConfigHandler {
public commonConfig: { request_headers: object };
private currentEnvironment: string;
public environment: string;
public environmnetConfig: {
public environmentConfig: {
log_level: TLogLevelName;
time_zone: string;
api_base_url: string;
@@ -35,8 +39,9 @@ class ConfigHandler {
private setCommonConfig(): void {
try {
const baseWorkingDirectory = __dirname;
this.commonConfig = YAML.parse(
readFileSync("src/config/config.yaml", "utf8")
readFileSync(baseWorkingDirectory + "/config.yaml", "utf8"),
).common;
} catch (error) {
throw Error(`Error reading common config: (${error})`);
@@ -46,14 +51,24 @@ class ConfigHandler {
private setEnvironmentConfig(environment: string): void {
this.ensureEnvironmentIsValid(environment);
try {
this.environmnetConfig = YAML.parse(
readFileSync("src/config/config.yaml", "utf8")
const baseWorkingDirectory = __dirname;
this.environmentConfig = YAML.parse(
readFileSync(baseWorkingDirectory + "/config.yaml", "utf8"),
)[environment];
} catch (error) {
console.log("fadsfasdfasdfsdfsa")
throw Error(`Error reading environment config: (${error})`);
}
}
public getEnvironmentConfig(environment: string): any {
const baseWorkingDirectory = __dirname;
return (
this.environmentConfig ||
YAML.parse(readFileSync(baseWorkingDirectory + "/config.yaml", "utf8"))[environment]
);
}
private ensureEnvironmentIsValid(environment: string): void {
if (this.validEnvironments.indexOf(environment) === -1) {
throw Error(`Config environment is not valid: "${environment}"`);
+4
View File
@@ -0,0 +1,4 @@
module.exports = {
ConfigHandler: require('./config/configHandler.ts'),
RestClient: require('./restClient/RestClient.ts')
};
@@ -13,9 +13,9 @@ import ConfigHandler from "../config/configHandler";
const config = ConfigHandler.getInstance();
const log = new Logger({
minLevel: config.environmnetConfig.log_level,
minLevel: config.environmentConfig.log_level,
dateTimeTimezone:
config.environmnetConfig.time_zone ||
config.environmentConfig.time_zone ||
Intl.DateTimeFormat().resolvedOptions().timeZone,
});
@@ -24,7 +24,7 @@ function isSet(property): boolean {
}
export class RestClient {
private static authToken: string;
public static authToken: string;
private axiosInstance: AxiosInstance;
@@ -83,7 +83,7 @@ export class RestClient {
data,
additionalConfigs,
params,
})
}),
);
await this.axiosInstance
@@ -214,7 +214,7 @@ export class RestClient {
if (isSet(additionalConfigs)) {
logRecord = `${logRecord}\nAdditional Configuration: ${stringify(
additionalConfigs
additionalConfigs,
)}`;
}
+3 -1
View File
@@ -8,14 +8,16 @@ license.workspace = true
[dependencies]
bip39 = { workspace = true }
log = { workspace = true }
rand = "0.7.3"
thiserror = { workspace = true }
url = { workspace = true }
zeroize = { workspace = true }
nym-coconut-interface = { path = "../coconut-interface" }
nym-coconut = { path = "../nymcoconut" }
nym-credential-storage = { path = "../credential-storage" }
nym-credentials = { path = "../credentials" }
nym-credentials-interface = { path = "../credentials-interface" }
nym-crypto = { path = "../crypto", features = ["rand", "asymmetric", "symmetric", "aes", "hashing"] }
nym-network-defaults = { path = "../network-defaults" }
nym-validator-client = { path = "../client-libs/validator-client", default-features = false }
+28 -32
View File
@@ -2,18 +2,18 @@
// SPDX-License-Identifier: Apache-2.0
use crate::error::BandwidthControllerError;
use nym_coconut_interface::Base58;
use nym_credential_storage::models::StorableIssuedCredential;
use nym_credential_storage::storage::Storage;
use nym_credentials::coconut::bandwidth::BandwidthVoucher;
use nym_credentials::coconut::bandwidth::{CredentialType, IssuanceBandwidthCredential};
use nym_credentials::coconut::utils::obtain_aggregate_signature;
use nym_crypto::asymmetric::{encryption, identity};
use nym_network_defaults::VOUCHER_INFO;
use nym_validator_client::coconut::all_coconut_api_clients;
use nym_validator_client::nyxd::contract_traits::CoconutBandwidthSigningClient;
use nym_validator_client::nyxd::contract_traits::DkgQueryClient;
use nym_validator_client::nyxd::Coin;
use rand::rngs::OsRng;
use state::State;
use zeroize::Zeroizing;
pub mod state;
@@ -24,13 +24,11 @@ where
let mut rng = OsRng;
let signing_key = identity::PrivateKey::new(&mut rng);
let encryption_key = encryption::PrivateKey::new(&mut rng);
let params = BandwidthVoucher::default_parameters();
let voucher_value = amount.amount.to_string();
let tx_hash = client
.deposit(
amount,
String::from(VOUCHER_INFO),
amount.clone(),
CredentialType::Voucher.to_string(),
signing_key.public_key().to_base58_string(),
encryption_key.public_key().to_base58_string(),
None,
@@ -38,21 +36,15 @@ where
.await?
.transaction_hash;
let voucher = BandwidthVoucher::new(
&params,
voucher_value,
VOUCHER_INFO.to_string(),
tx_hash,
signing_key,
encryption_key,
);
let voucher =
IssuanceBandwidthCredential::new_voucher(amount, tx_hash, signing_key, encryption_key);
let state = State { voucher, params };
let state = State { voucher };
Ok(state)
}
pub async fn get_credential<C, St>(
pub async fn get_bandwidth_voucher<C, St>(
state: &State,
client: &C,
storage: &St,
@@ -62,6 +54,9 @@ where
St: Storage,
<St as Storage>::StorageError: Send + Sync + 'static,
{
// temporary
assert!(state.voucher.typ().is_voucher());
let epoch_id = client.get_current_epoch().await?.epoch_id;
let threshold = client
.get_current_epoch_threshold()
@@ -70,22 +65,23 @@ where
let coconut_api_clients = all_coconut_api_clients(client, epoch_id).await?;
let signature = obtain_aggregate_signature(
&state.params,
&state.voucher,
&coconut_api_clients,
threshold,
)
.await?;
let signature =
obtain_aggregate_signature(&state.voucher, &coconut_api_clients, threshold).await?;
let issued = state.voucher.to_issued_credential(signature, epoch_id);
// make sure the data gets zeroized after persisting it
let credential_data = Zeroizing::new(issued.pack_v1());
let storable = StorableIssuedCredential {
serialization_revision: issued.current_serialization_revision(),
credential_data: credential_data.as_ref(),
credential_type: issued.typ().to_string(),
epoch_id: epoch_id
.try_into()
.expect("our epoch is has run over u32::MAX!"),
};
storage
.insert_coconut_credential(
state.voucher.get_voucher_value(),
VOUCHER_INFO.to_string(),
state.voucher.get_private_attributes()[0].to_bs58(),
state.voucher.get_private_attributes()[1].to_bs58(),
signature.to_bs58(),
epoch_id.to_string(),
)
.insert_issued_credential(storable)
.await
.map_err(|err| BandwidthControllerError::CredentialStorageError(Box::new(err)))
}
@@ -1,19 +1,14 @@
// Copyright 2022-2023 - Nym Technologies SA <contact@nymtech.net>
// Copyright 2022-2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use nym_coconut_interface::Parameters;
use nym_credentials::coconut::bandwidth::BandwidthVoucher;
use nym_credentials::coconut::bandwidth::IssuanceBandwidthCredential;
pub struct State {
pub voucher: BandwidthVoucher,
pub params: Parameters,
pub voucher: IssuanceBandwidthCredential,
}
impl State {
pub fn new(voucher: BandwidthVoucher) -> Self {
State {
voucher,
params: BandwidthVoucher::default_parameters(),
}
pub fn new(voucher: IssuanceBandwidthCredential) -> Self {
State { voucher }
}
}
+7 -1
View File
@@ -1,7 +1,7 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use nym_coconut_interface::CoconutError;
use nym_coconut::CoconutError;
use nym_credential_storage::error::StorageError;
use nym_credentials::error::Error as CredentialsError;
use nym_crypto::asymmetric::encryption::KeyRecoveryError;
@@ -21,6 +21,9 @@ pub enum BandwidthControllerError {
#[error("There was a credential storage error - {0}")]
CredentialStorageError(Box<dyn std::error::Error + Send + Sync>),
#[error("the credential storage does not contain any usable credentials")]
NoCredentialsAvailable,
// this should really be fully incorporated into the above, but messing with coconut is the last thing I want to do now
#[error(transparent)]
StorageError(#[from] StorageError),
@@ -45,4 +48,7 @@ pub enum BandwidthControllerError {
#[error("Threshold not set yet")]
NoThreshold,
#[error("can't handle recovering storage with revision {stored}. {expected} was expected")]
UnsupportedCredentialStorageRevision { stored: u8, expected: u8 },
}
+106 -46
View File
@@ -1,80 +1,140 @@
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
// Copyright 2021-2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::error::BandwidthControllerError;
use nym_credential_storage::error::StorageError;
use crate::utils::stored_credential_to_issued_bandwidth;
use log::{debug, error, warn};
use nym_credential_storage::storage::Storage;
use nym_credentials::coconut::bandwidth::issued::BandwidthCredentialIssuedDataVariant;
use nym_credentials::coconut::bandwidth::CredentialSpendingData;
use nym_credentials::coconut::utils::obtain_aggregate_verification_key;
use nym_credentials::IssuedBandwidthCredential;
use nym_credentials_interface::VerificationKey;
use nym_validator_client::coconut::all_coconut_api_clients;
use nym_validator_client::nym_api::EpochId;
use nym_validator_client::nyxd::contract_traits::DkgQueryClient;
use std::str::FromStr;
use zeroize::Zeroizing;
use {
nym_coconut_interface::Base58,
nym_credentials::coconut::{
bandwidth::prepare_for_spending, utils::obtain_aggregate_verification_key,
},
};
pub mod acquire;
pub mod error;
mod utils;
pub struct BandwidthController<C, St> {
storage: St,
client: C,
}
pub struct PreparedCredential {
/// The cryptographic material required for spending the underlying credential.
pub data: CredentialSpendingData,
/// The (DKG) epoch id under which the credential has been issued so that the verifier
/// could use correct verification key for validation.
pub epoch_id: EpochId,
/// The database id of the stored credential.
pub credential_id: i64,
}
pub struct RetrievedCredential {
pub credential: IssuedBandwidthCredential,
pub credential_id: i64,
}
impl<C, St: Storage> BandwidthController<C, St> {
pub fn new(storage: St, client: C) -> Self {
BandwidthController { storage, client }
}
/// Tries to retrieve one of the stored, unused credentials that hasn't yet expired.
/// It marks any retrieved intermediate credentials as expired.
pub async fn get_next_usable_credential(
&self,
) -> Result<RetrievedCredential, BandwidthControllerError>
where
<St as Storage>::StorageError: Send + Sync + 'static,
{
loop {
let Some(maybe_next) = self
.storage
.get_next_unspent_credential()
.await
.map_err(|err| BandwidthControllerError::CredentialStorageError(Box::new(err)))?
else {
return Err(BandwidthControllerError::NoCredentialsAvailable);
};
let id = maybe_next.id;
// try to deserialize it
let valid_credential = match stored_credential_to_issued_bandwidth(maybe_next) {
// check if it has already expired
Ok(credential) => match credential.variant_data() {
BandwidthCredentialIssuedDataVariant::Voucher(_) => {
debug!("credential {id} is a bandwidth voucher");
credential
}
BandwidthCredentialIssuedDataVariant::FreePass(freepass_info) => {
debug!("credential {id} is a free pass");
if freepass_info.expired() {
warn!("the free pass (id: {id}) has already expired! The expiration was set to {}", freepass_info.expiry_date());
self.storage.mark_expired(id).await.map_err(|err| {
BandwidthControllerError::CredentialStorageError(Box::new(err))
})?;
continue;
}
credential
}
},
Err(err) => {
error!("failed to deserialize credential with id {id}: {err}. it may need to be manually removed from the storage");
return Err(err);
}
};
return Ok(RetrievedCredential {
credential: valid_credential,
credential_id: id,
});
}
}
pub fn storage(&self) -> &St {
&self.storage
}
pub async fn prepare_coconut_credential(
async fn get_aggregate_verification_key(
&self,
) -> Result<(nym_coconut_interface::Credential, i64), BandwidthControllerError>
epoch_id: EpochId,
) -> Result<VerificationKey, BandwidthControllerError>
where
C: DkgQueryClient + Sync + Send,
<St as Storage>::StorageError: Send + Sync + 'static,
{
let bandwidth_credential = self
.storage
.get_next_coconut_credential()
.await
.map_err(|err| BandwidthControllerError::CredentialStorageError(Box::new(err)))?;
let voucher_value = u64::from_str(&bandwidth_credential.voucher_value)
.map_err(|_| StorageError::InconsistentData)?;
let voucher_info = bandwidth_credential.voucher_info.clone();
let serial_number = Zeroizing::new(nym_coconut_interface::Attribute::try_from_bs58(
bandwidth_credential.serial_number,
)?);
let binding_number = Zeroizing::new(nym_coconut_interface::Attribute::try_from_bs58(
bandwidth_credential.binding_number,
)?);
let signature =
nym_coconut_interface::Signature::try_from_bs58(bandwidth_credential.signature)?;
let epoch_id = u64::from_str(&bandwidth_credential.epoch_id)
.map_err(|_| StorageError::InconsistentData)?;
let coconut_api_clients = all_coconut_api_clients(&self.client, epoch_id).await?;
Ok(obtain_aggregate_verification_key(&coconut_api_clients)?)
}
let verification_key = obtain_aggregate_verification_key(&coconut_api_clients).await?;
pub async fn prepare_bandwidth_credential(
&self,
) -> Result<PreparedCredential, BandwidthControllerError>
where
C: DkgQueryClient + Sync + Send,
<St as Storage>::StorageError: Send + Sync + 'static,
{
let retrieved_credential = self.get_next_usable_credential().await?;
// the below would only be executed once we know where we want to spend it (i.e. which gateway and stuff)
Ok((
prepare_for_spending(
voucher_value,
voucher_info,
&serial_number,
&binding_number,
epoch_id,
&signature,
&verification_key,
)?,
bandwidth_credential.id,
))
let epoch_id = retrieved_credential.credential.epoch_id();
let credential_id = retrieved_credential.credential_id;
let verification_key = self.get_aggregate_verification_key(epoch_id).await?;
let spend_request = retrieved_credential
.credential
.prepare_for_spending(&verification_key)?;
Ok(PreparedCredential {
data: spend_request,
epoch_id,
credential_id,
})
}
pub async fn consume_credential(&self, id: i64) -> Result<(), BandwidthControllerError>
@@ -93,7 +153,7 @@ impl<C, St: Storage> BandwidthController<C, St> {
impl<C, St> Clone for BandwidthController<C, St>
where
C: Clone,
St: Storage + Clone,
St: Clone,
{
fn clone(&self) -> Self {
BandwidthController {
+22
View File
@@ -0,0 +1,22 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::error::BandwidthControllerError;
use nym_credential_storage::models::StoredIssuedCredential;
use nym_credentials::coconut::bandwidth::issued::CURRENT_SERIALIZATION_REVISION;
use nym_credentials::coconut::bandwidth::IssuedBandwidthCredential;
pub fn stored_credential_to_issued_bandwidth(
cred: StoredIssuedCredential,
) -> Result<IssuedBandwidthCredential, BandwidthControllerError> {
if cred.serialization_revision != CURRENT_SERIALIZATION_REVISION {
return Err(
BandwidthControllerError::UnsupportedCredentialStorageRevision {
stored: cred.serialization_revision,
expected: CURRENT_SERIALIZATION_REVISION,
},
);
}
Ok(IssuedBandwidthCredential::unpack_v1(&cred.credential_data)?)
}
+3 -1
View File
@@ -9,6 +9,7 @@ repository = { workspace = true }
[dependencies]
atty = "0.2"
const-str = "0.5.6"
clap = { workspace = true, features = ["derive"] }
clap_complete = "4.0"
clap_complete_fig = "4.0"
@@ -35,9 +36,10 @@ opentelemetry = { version = "0.19.0", optional = true, features = ["rt-tokio"] }
[build-dependencies]
vergen = { version = "=7.4.3", default-features = false, features = [
vergen = { version = "=8.2.6", default-features = false, features = [
"build",
"git",
"gitcl",
"rustc",
"cargo",
] }
+8 -7
View File
@@ -1,13 +1,14 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use vergen::{vergen, Config};
use vergen::EmitBuilder;
fn main() {
let mut config = Config::default();
if std::env::var("DOCS_RS").is_ok() {
// If we don't have access to git information, such as in a docs.rs build, don't error
*config.git_mut().skip_if_error_mut() = true;
}
vergen(config).expect("failed to extract build metadata");
EmitBuilder::builder()
.all_build()
.all_git()
.all_rustc()
.all_cargo()
.emit()
.expect("failed to extract build metadata");
}
+73 -5
View File
@@ -40,14 +40,22 @@ pub struct BinaryBuildInformation {
/// Provides the rustc channel that was used for the build, for example `nightly`.
pub rustc_channel: &'static str,
// VERGEN_CARGO_PROFILE
/// Provides the cargo profile that was used for the build, for example `debug`.
// VERGEN_CARGO_DEBUG
/// Provides the cargo debug mode that was used for the build.
// NOTE: keep the old name cargo_profile instead of cargo_debug for backwards compatibility
pub cargo_profile: &'static str,
}
impl BinaryBuildInformation {
// explicitly require the build_version to be passed as it's binary specific
pub const fn new(binary_name: &'static str, build_version: &'static str) -> Self {
let cargo_debug = env!("VERGEN_CARGO_DEBUG");
let cargo_profile = if const_str::equal!(cargo_debug, "true") {
"debug"
} else {
"release"
};
BinaryBuildInformation {
binary_name,
build_timestamp: env!("VERGEN_BUILD_TIMESTAMP"),
@@ -57,7 +65,36 @@ impl BinaryBuildInformation {
commit_branch: env!("VERGEN_GIT_BRANCH"),
rustc_version: env!("VERGEN_RUSTC_SEMVER"),
rustc_channel: env!("VERGEN_RUSTC_CHANNEL"),
cargo_profile: env!("VERGEN_CARGO_PROFILE"),
cargo_profile,
}
}
// Varient where we want to use the metadata generated by vergen in the consuming crate.
pub const fn new_with_local_vergen(
binary_name: &'static str,
build_timestamp: &'static str,
build_version: &'static str,
commit_sha: &'static str,
commit_timestamp: &'static str,
commit_branch: &'static str,
) -> Self {
let cargo_debug = env!("VERGEN_CARGO_DEBUG");
let cargo_profile = if const_str::equal!(cargo_debug, "true") {
"debug"
} else {
"release"
};
BinaryBuildInformation {
binary_name,
build_timestamp,
build_version,
commit_sha,
commit_timestamp,
commit_branch,
rustc_version: env!("VERGEN_RUSTC_SEMVER"),
rustc_channel: env!("VERGEN_RUSTC_CHANNEL"),
cargo_profile,
}
}
@@ -115,8 +152,9 @@ pub struct BinaryBuildInformationOwned {
/// Provides the rustc channel that was used for the build, for example `nightly`.
pub rustc_channel: String,
// VERGEN_CARGO_PROFILE
/// Provides the cargo profile that was used for the build, for example `debug`.
// VERGEN_CARGO_DEBUG
/// Provides the cargo debug mode that was used for the build.
// NOTE: keep the old name cargo_profile instead of cargo_debug for backwards compatibility
pub cargo_profile: String,
}
@@ -178,3 +216,33 @@ macro_rules! bin_info_owned {
.to_owned()
};
}
// variant that picks up the vergen build information generated by the build.rs in the consumer
// crate.
#[macro_export]
macro_rules! bin_info_local_vergen {
() => {
$crate::build_information::BinaryBuildInformation::new_with_local_vergen(
env!("CARGO_PKG_NAME"),
env!("VERGEN_BUILD_TIMESTAMP"),
env!("CARGO_PKG_VERSION"),
env!("VERGEN_GIT_SHA"),
env!("VERGEN_GIT_COMMIT_TIMESTAMP"),
env!("VERGEN_GIT_BRANCH"),
)
};
}
#[macro_export]
macro_rules! bin_info_local_vergen_owned {
() => {
$crate::build_information::BinaryBuildInformation::new_with_local_vergen(
env!("CARGO_PKG_NAME"),
env!("VERGEN_BUILD_TIMESTAMP"),
env!("CARGO_PKG_VERSION"),
env!("VERGEN_GIT_SHA"),
env!("VERGEN_GIT_COMMIT_TIMESTAMP"),
env!("VERGEN_GIT_BRANCH"),
)
};
}
+3 -2
View File
@@ -46,6 +46,7 @@ nym-validator-client = { path = "../client-libs/validator-client", default-featu
nym-task = { path = "../task" }
nym-credential-storage = { path = "../credential-storage" }
nym-network-defaults = { path = "../network-defaults" }
si-scale = "0.2.2"
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.tokio-stream]
version = "0.1.11"
@@ -59,7 +60,7 @@ features = ["time"]
version = "0.20.1"
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.sqlx]
version = "0.6.2"
workspace = true
features = ["runtime-tokio-rustls", "sqlite", "macros", "migrate"]
optional = true
@@ -90,7 +91,7 @@ tempfile = "3.1.0"
[build-dependencies]
tokio = { workspace = true, features = ["rt-multi-thread", "macros"] }
sqlx = { version = "0.6.2", features = ["runtime-tokio-rustls", "sqlite", "macros", "migrate"] }
sqlx = { workspace = true, features = ["runtime-tokio-rustls", "sqlite", "macros", "migrate"] }
[features]
default = []
@@ -109,6 +109,8 @@ pub async fn initialise_client<C>(
) -> Result<InitResultsWithConfig<C::Config>, C::Error>
where
C: InitialisableClient,
<C as InitialisableClient>::Config: std::fmt::Debug,
<C as InitialisableClient>::InitArgs: std::fmt::Debug,
{
info!("initialising {} client", C::NAME);
@@ -140,17 +142,32 @@ where
// Attempt to use a user-provided gateway, if possible
let user_chosen_gateway_id = common_args.gateway;
log::debug!("User chosen gateway id: {user_chosen_gateway_id:?}");
let selection_spec = GatewaySelectionSpecification::new(
user_chosen_gateway_id.map(|id| id.to_base58_string()),
Some(common_args.latency_based_selection),
false,
);
log::debug!("Gateway selection specification: {selection_spec:?}");
// Load and potentially override config
log::debug!("Init arguments: {init_args:#?}");
let config = C::construct_config(&init_args);
log::debug!("Constructed config: {config:#?}");
let paths = config.common_paths();
let core = config.core_config();
log::info!(
"Using nym-api: {}",
core.client
.nym_api_urls
.iter()
.map(|url| url.as_str())
.collect::<Vec<&str>>()
.join(",")
);
// Setup gateway by either registering a new one, or creating a new config from the selected
// one but with keys kept, or reusing the gateway configuration.
let key_store = OnDiskKeys::new(paths.keys.clone());
@@ -1,6 +1,7 @@
// Copyright 2022-2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use super::packet_statistics_control::PacketStatisticsReporter;
use super::received_buffer::ReceivedBufferMessage;
use super::topology_control::geo_aware_provider::GeoAwareTopologyProvider;
use crate::client::base_client::storage::gateway_details::GatewayDetailsStore;
@@ -10,6 +11,7 @@ use crate::client::inbound_messages::{InputMessage, InputMessageReceiver, InputM
use crate::client::key_manager::persistence::KeyStore;
use crate::client::mix_traffic::transceiver::{GatewayReceiver, GatewayTransceiver, RemoteGateway};
use crate::client::mix_traffic::{BatchMixMessageSender, MixTrafficController};
use crate::client::packet_statistics_control::PacketStatisticsControl;
use crate::client::real_messages_control;
use crate::client::real_messages_control::RealMessagesController;
use crate::client::received_buffer::{
@@ -50,6 +52,7 @@ use nym_topology::provider_trait::TopologyProvider;
use nym_topology::HardcodedTopologyProvider;
use nym_validator_client::nyxd::contract_traits::DkgQueryClient;
use std::fmt::Debug;
use std::os::raw::c_int as RawFd;
use std::path::Path;
use std::sync::Arc;
use url::Url;
@@ -101,6 +104,12 @@ pub struct ClientState {
pub shared_lane_queue_lengths: LaneQueueLengths,
pub reply_controller_sender: ReplyControllerSender,
pub topology_accessor: TopologyAccessor,
pub gateway_connection: GatewayConnection,
}
#[derive(Clone, Copy, Debug)]
pub struct GatewayConnection {
pub gateway_ws_fd: Option<RawFd>,
}
pub enum ClientInputStatus {
@@ -254,6 +263,7 @@ where
self_address: Recipient,
topology_accessor: TopologyAccessor,
mix_tx: BatchMixMessageSender,
stats_tx: PacketStatisticsReporter,
shutdown: TaskClient,
) {
info!("Starting loop cover traffic stream...");
@@ -266,6 +276,7 @@ where
topology_accessor,
debug_config.traffic,
debug_config.cover_traffic,
stats_tx,
);
stream.start_with_shutdown(shutdown);
@@ -285,6 +296,7 @@ where
client_connection_rx: ConnectionCommandReceiver,
shutdown: TaskClient,
packet_type: PacketType,
stats_tx: PacketStatisticsReporter,
) {
info!("Starting real traffic stream...");
@@ -299,6 +311,7 @@ where
reply_controller_receiver,
lane_queue_lengths,
client_connection_rx,
stats_tx,
)
.start_with_shutdown(shutdown, packet_type);
}
@@ -312,6 +325,7 @@ where
reply_key_storage: SentReplyKeys,
reply_controller_sender: ReplyControllerSender,
shutdown: TaskClient,
packet_statistics_control: PacketStatisticsReporter,
) {
info!("Starting received messages buffer controller...");
let controller: ReceivedMessagesBufferController<SphinxMessageReceiver> =
@@ -321,6 +335,7 @@ where
mixnet_receiver,
reply_key_storage,
reply_controller_sender,
packet_statistics_control,
);
controller.start_with_shutdown(shutdown)
}
@@ -506,6 +521,13 @@ where
Ok(())
}
fn start_packet_statistics_control(shutdown: TaskClient) -> PacketStatisticsReporter {
info!("Starting packet statistics control...");
let (packet_statistics_control, packet_stats_reporter) = PacketStatisticsControl::new();
packet_statistics_control.start_with_shutdown(shutdown);
packet_stats_reporter
}
fn start_mix_traffic_controller(
gateway_transceiver: Box<dyn GatewayTransceiver + Send>,
shutdown: TaskClient,
@@ -633,6 +655,9 @@ where
)
.await?;
let packet_stats_reporter =
Self::start_packet_statistics_control(shutdown.fork("packet_statistics_control"));
let gateway_packet_router = PacketRouter::new(
ack_sender,
mixnet_messages_sender,
@@ -648,6 +673,7 @@ where
shutdown.fork("gateway_transceiver"),
)
.await?;
let gateway_ws_fd = gateway_transceiver.ws_fd();
let reply_storage = Self::setup_persistent_reply_storage(
reply_storage_backend,
@@ -662,6 +688,7 @@ where
reply_storage.key_storage(),
reply_controller_sender.clone(),
shutdown.fork("received_messages_buffer"),
packet_stats_reporter.clone(),
);
// The message_sender is the transmitter for any component generating sphinx packets
@@ -700,6 +727,7 @@ where
client_connection_rx,
shutdown.fork("real_traffic_controller"),
self.config.debug.traffic.packet_type,
packet_stats_reporter.clone(),
);
if !self
@@ -714,6 +742,7 @@ where
self_address,
shared_topology_accessor.clone(),
message_sender,
packet_stats_reporter,
shutdown.fork("cover_traffic_stream"),
);
}
@@ -738,6 +767,7 @@ where
shared_lane_queue_lengths,
reply_controller_sender,
topology_accessor: shared_topology_accessor,
gateway_connection: GatewayConnection { gateway_ws_fd },
},
task_handle: shutdown,
})
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: Apache-2.0
use crate::client::mix_traffic::BatchMixMessageSender;
use crate::client::packet_statistics_control::{PacketStatisticsEvent, PacketStatisticsReporter};
use crate::client::topology_control::TopologyAccessor;
use crate::{config, spawn_future};
use futures::task::{Context, Poll};
@@ -61,6 +62,8 @@ where
secondary_packet_size: Option<PacketSize>,
packet_type: PacketType,
stats_tx: PacketStatisticsReporter,
}
impl<R> Stream for LoopCoverTrafficStream<R>
@@ -97,7 +100,8 @@ where
// obviously when we finally make shared rng that is on 'higher' level, this should become
// generic `R`
impl LoopCoverTrafficStream<OsRng> {
pub fn new(
#[allow(clippy::too_many_arguments)]
pub(crate) fn new(
ack_key: Arc<AckKey>,
average_ack_delay: Duration,
mix_tx: BatchMixMessageSender,
@@ -105,6 +109,7 @@ impl LoopCoverTrafficStream<OsRng> {
topology_access: TopologyAccessor,
traffic_config: config::Traffic,
cover_config: config::CoverTraffic,
stats_tx: PacketStatisticsReporter,
) -> Self {
let rng = OsRng;
@@ -122,6 +127,7 @@ impl LoopCoverTrafficStream<OsRng> {
primary_packet_size: traffic_config.primary_packet_size,
secondary_packet_size: traffic_config.secondary_packet_size,
packet_type: traffic_config.packet_type,
stats_tx,
}
}
@@ -191,6 +197,10 @@ impl LoopCoverTrafficStream<OsRng> {
log::warn!("Failed to send cover message - channel closed");
}
}
} else {
self.stats_tx.report(PacketStatisticsEvent::CoverPacketSent(
cover_traffic_packet_size.size(),
));
}
// TODO: I'm not entirely sure whether this is really required, because I'm not 100%
@@ -1,6 +1,8 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
#![allow(unused_imports)]
use std::time::Duration;
pub use wasmtimer::{std::Instant, tokio::*};
@@ -8,6 +8,7 @@ use nym_gateway_client::GatewayClient;
pub use nym_gateway_client::{GatewayPacketRouter, PacketRouter};
use nym_sphinx::forwarding::packet::MixPacket;
use std::fmt::Debug;
use std::os::raw::c_int as RawFd;
use thiserror::Error;
#[cfg(not(target_arch = "wasm32"))]
@@ -25,6 +26,7 @@ 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.
pub trait GatewayTransceiver: GatewaySender + GatewayReceiver {
fn gateway_identity(&self) -> identity::PublicKey;
fn ws_fd(&self) -> Option<RawFd>;
}
/// This trait defines the functionality of sending `MixPacket` into the mixnet,
@@ -66,6 +68,9 @@ impl<G: GatewayTransceiver + ?Sized + Send> GatewayTransceiver for Box<G> {
fn gateway_identity(&self) -> identity::PublicKey {
(**self).gateway_identity()
}
fn ws_fd(&self) -> Option<RawFd> {
(**self).ws_fd()
}
}
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
@@ -112,6 +117,9 @@ where
fn gateway_identity(&self) -> identity::PublicKey {
self.gateway_client.gateway_identity()
}
fn ws_fd(&self) -> Option<RawFd> {
self.gateway_client.ws_fd()
}
}
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
@@ -187,6 +195,9 @@ mod nonwasm_sealed {
fn gateway_identity(&self) -> identity::PublicKey {
self.local_identity
}
fn ws_fd(&self) -> Option<RawFd> {
None
}
}
#[async_trait]
@@ -259,4 +270,7 @@ impl GatewayTransceiver for MockGateway {
fn gateway_identity(&self) -> identity::PublicKey {
self.dummy_identity
}
fn ws_fd(&self) -> Option<RawFd> {
None
}
}
+1
View File
@@ -7,6 +7,7 @@ pub(crate) mod helpers;
pub mod inbound_messages;
pub mod key_manager;
pub mod mix_traffic;
pub(crate) mod packet_statistics_control;
pub mod real_messages_control;
pub mod received_buffer;
pub mod replies;
@@ -0,0 +1,503 @@
use std::{
collections::VecDeque,
time::{Duration, Instant},
};
use si_scale::helpers::bibytes2;
use crate::spawn_future;
// Time interval between reporting packet statistics
const PACKET_REPORT_INTERVAL_SECS: u64 = 2;
// Interval for taking snapshots of the packet statistics
const SNAPSHOT_INTERVAL_MS: u64 = 500;
// When computing rates, we include snapshots that are up to this old. We set it to some odd number
// a tad larger than an integer number of snapshot intervals, so that we don't have to worry about
// threshold effects.
// Also, set it larger than the packet report interval so that we don't miss notable singular events
const RECORDING_WINDOW_MS: u64 = 2300;
#[derive(Default, Debug, Clone)]
struct PacketStatistics {
// Sent
real_packets_sent: u64,
real_packets_sent_size: usize,
cover_packets_sent: u64,
cover_packets_sent_size: usize,
// Received
real_packets_received: u64,
real_packets_received_size: usize,
cover_packets_received: u64,
cover_packets_received_size: usize,
// Acks
total_acks_received: u64,
total_acks_received_size: usize,
real_acks_received: u64,
real_acks_received_size: usize,
cover_acks_received: u64,
cover_acks_received_size: usize,
// Types of packets queued
// TODO: track the type sent instead
real_packets_queued: u64,
retransmissions_queued: u64,
reply_surbs_queued: u64,
additional_reply_surbs_queued: u64,
}
impl PacketStatistics {
fn handle_event(&mut self, event: PacketStatisticsEvent) {
match event {
PacketStatisticsEvent::RealPacketSent(packet_size) => {
self.real_packets_sent += 1;
self.real_packets_sent_size += packet_size;
}
PacketStatisticsEvent::CoverPacketSent(packet_size) => {
self.cover_packets_sent += 1;
self.cover_packets_sent_size += packet_size;
}
PacketStatisticsEvent::RealPacketReceived(packet_size) => {
self.real_packets_received += 1;
self.real_packets_received_size += packet_size;
}
PacketStatisticsEvent::CoverPacketReceived(packet_size) => {
self.cover_packets_received += 1;
self.cover_packets_received_size += packet_size;
}
PacketStatisticsEvent::AckReceived(packet_size) => {
self.total_acks_received += 1;
self.total_acks_received_size += packet_size;
}
PacketStatisticsEvent::RealAckReceived(packet_size) => {
self.real_acks_received += 1;
self.real_acks_received_size += packet_size;
}
PacketStatisticsEvent::CoverAckReceived(packet_size) => {
self.cover_acks_received += 1;
self.cover_acks_received_size += packet_size;
}
PacketStatisticsEvent::RealPacketQueued => {
self.real_packets_queued += 1;
}
PacketStatisticsEvent::RetransmissionQueued => {
self.retransmissions_queued += 1;
}
PacketStatisticsEvent::ReplySurbRequestQueued => {
self.reply_surbs_queued += 1;
}
PacketStatisticsEvent::AdditionalReplySurbRequestQueued => {
self.additional_reply_surbs_queued += 1;
}
}
}
fn summary(&self) -> (String, String) {
(
format!(
"packets sent: {} (real: {}, cover: {}, retransmissions: {})",
self.real_packets_sent + self.cover_packets_sent,
self.real_packets_sent,
self.cover_packets_sent,
self.retransmissions_queued,
),
format!(
"packets received: {}, (real: {}, cover: {}, acks: {}, acks for cover: {})",
self.real_packets_received + self.cover_packets_received,
self.real_packets_received,
self.cover_packets_received,
self.real_acks_received,
self.cover_acks_received,
),
)
}
}
impl std::ops::Sub for PacketStatistics {
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
Self {
real_packets_sent: self.real_packets_sent - rhs.real_packets_sent,
real_packets_sent_size: self.real_packets_sent_size - rhs.real_packets_sent_size,
cover_packets_sent: self.cover_packets_sent - rhs.cover_packets_sent,
cover_packets_sent_size: self.cover_packets_sent_size - rhs.cover_packets_sent_size,
real_packets_received: self.real_packets_received - rhs.real_packets_received,
real_packets_received_size: self.real_packets_received_size
- rhs.real_packets_received_size,
cover_packets_received: self.cover_packets_received - rhs.cover_packets_received,
cover_packets_received_size: self.cover_packets_received_size
- rhs.cover_packets_received_size,
total_acks_received: self.total_acks_received - rhs.total_acks_received,
total_acks_received_size: self.total_acks_received_size - rhs.total_acks_received_size,
real_acks_received: self.real_acks_received - rhs.real_acks_received,
real_acks_received_size: self.real_acks_received_size - rhs.real_acks_received_size,
cover_acks_received: self.cover_acks_received - rhs.cover_acks_received,
cover_acks_received_size: self.cover_acks_received_size - rhs.cover_acks_received_size,
real_packets_queued: self.real_packets_queued - rhs.real_packets_queued,
retransmissions_queued: self.retransmissions_queued - rhs.retransmissions_queued,
reply_surbs_queued: self.reply_surbs_queued - rhs.reply_surbs_queued,
additional_reply_surbs_queued: self.additional_reply_surbs_queued
- rhs.additional_reply_surbs_queued,
}
}
}
#[derive(Debug, Clone)]
struct PacketRates {
real_packets_sent: f64,
real_packets_sent_size: f64,
cover_packets_sent: f64,
cover_packets_sent_size: f64,
real_packets_received: f64,
real_packets_received_size: f64,
cover_packets_received: f64,
cover_packets_received_size: f64,
total_acks_received: f64,
total_acks_received_size: f64,
real_acks_received: f64,
real_acks_received_size: f64,
cover_acks_received: f64,
cover_acks_received_size: f64,
real_packets_queued: f64,
retransmissions_queued: f64,
reply_surbs_queued: f64,
additional_reply_surbs_queued: f64,
}
impl From<PacketStatistics> for PacketRates {
fn from(stats: PacketStatistics) -> Self {
Self {
real_packets_sent: stats.real_packets_sent as f64,
real_packets_sent_size: stats.real_packets_sent_size as f64,
cover_packets_sent: stats.cover_packets_sent as f64,
cover_packets_sent_size: stats.cover_packets_sent_size as f64,
real_packets_received: stats.real_packets_received as f64,
real_packets_received_size: stats.real_packets_received_size as f64,
cover_packets_received: stats.cover_packets_received as f64,
cover_packets_received_size: stats.cover_packets_received_size as f64,
total_acks_received: stats.total_acks_received as f64,
total_acks_received_size: stats.total_acks_received_size as f64,
real_acks_received: stats.real_acks_received as f64,
real_acks_received_size: stats.real_acks_received_size as f64,
cover_acks_received: stats.cover_acks_received as f64,
cover_acks_received_size: stats.cover_acks_received_size as f64,
real_packets_queued: stats.real_packets_queued as f64,
retransmissions_queued: stats.retransmissions_queued as f64,
reply_surbs_queued: stats.reply_surbs_queued as f64,
additional_reply_surbs_queued: stats.additional_reply_surbs_queued as f64,
}
}
}
impl std::ops::Sub for PacketRates {
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
Self {
real_packets_sent: self.real_packets_sent - rhs.real_packets_sent,
real_packets_sent_size: self.real_packets_sent_size - rhs.real_packets_sent_size,
cover_packets_sent: self.cover_packets_sent - rhs.cover_packets_sent,
cover_packets_sent_size: self.cover_packets_sent_size - rhs.cover_packets_sent_size,
real_packets_received: self.real_packets_received - rhs.real_packets_received,
real_packets_received_size: self.real_packets_received_size
- rhs.real_packets_received_size,
cover_packets_received: self.cover_packets_received - rhs.cover_packets_received,
cover_packets_received_size: self.cover_packets_received_size
- rhs.cover_packets_received_size,
total_acks_received: self.total_acks_received - rhs.total_acks_received,
total_acks_received_size: self.total_acks_received_size - rhs.total_acks_received_size,
real_acks_received: self.real_acks_received - rhs.real_acks_received,
real_acks_received_size: self.real_acks_received_size - rhs.real_acks_received_size,
cover_acks_received: self.cover_acks_received - rhs.cover_acks_received,
cover_acks_received_size: self.cover_acks_received_size - rhs.cover_acks_received_size,
real_packets_queued: self.real_packets_queued - rhs.real_packets_queued,
retransmissions_queued: self.retransmissions_queued - rhs.retransmissions_queued,
reply_surbs_queued: self.reply_surbs_queued - rhs.reply_surbs_queued,
additional_reply_surbs_queued: self.additional_reply_surbs_queued
- rhs.additional_reply_surbs_queued,
}
}
}
impl std::ops::Div<f64> for PacketRates {
type Output = Self;
fn div(self, rhs: f64) -> Self::Output {
Self {
real_packets_sent: self.real_packets_sent / rhs,
real_packets_sent_size: self.real_packets_sent_size / rhs,
cover_packets_sent: self.cover_packets_sent / rhs,
cover_packets_sent_size: self.cover_packets_sent_size / rhs,
real_packets_received: self.real_packets_received / rhs,
real_packets_received_size: self.real_packets_received_size / rhs,
cover_packets_received: self.cover_packets_received / rhs,
cover_packets_received_size: self.cover_packets_received_size / rhs,
total_acks_received: self.total_acks_received / rhs,
total_acks_received_size: self.total_acks_received_size / rhs,
real_acks_received: self.real_acks_received / rhs,
real_acks_received_size: self.real_acks_received_size / rhs,
cover_acks_received: self.cover_acks_received / rhs,
cover_acks_received_size: self.cover_acks_received_size / rhs,
real_packets_queued: self.real_packets_queued / rhs,
retransmissions_queued: self.retransmissions_queued / rhs,
reply_surbs_queued: self.reply_surbs_queued / rhs,
additional_reply_surbs_queued: self.additional_reply_surbs_queued / rhs,
}
}
}
impl PacketRates {
fn summary(&self) -> String {
format!(
"down: {}/s, up: {}/s (cover down: {}/s, cover up: {}/s)",
bibytes2(self.real_packets_received_size),
bibytes2(self.real_packets_sent_size),
bibytes2(self.cover_packets_received_size),
bibytes2(self.cover_packets_sent_size),
)
}
fn detailed_summary(&self) -> String {
format!(
"RX: {:.1} mixpkt/s, {}/s (real: {}/s, acks: {}/s), TX: {:.1} mixpkt/s, {}/s (real: {}/s)",
self.real_packets_received + self.cover_packets_received,
bibytes2(self.real_packets_received_size + self.cover_packets_received_size),
bibytes2(self.real_packets_received_size),
bibytes2(self.total_acks_received_size),
self.real_packets_sent + self.cover_packets_sent,
bibytes2(self.real_packets_sent_size + self.cover_packets_sent_size),
bibytes2(self.real_packets_sent_size),
)
}
}
#[derive(Debug)]
pub(crate) enum PacketStatisticsEvent {
// The real packets sent. Recall that acks are sent by the gateway, so it's not included here.
RealPacketSent(usize),
// The cover packets sent
CoverPacketSent(usize),
// Real packets received
RealPacketReceived(usize),
// Cover packets received
CoverPacketReceived(usize),
// Ack of any type received. This is mostly used as a consistency check, and should be the sum
// of real and cover acks received.
AckReceived(usize),
// Out of the total acks received, this is the subset of those that were real
RealAckReceived(usize),
// Out of the total acks received, this is the subset of those that were for cover traffic
CoverAckReceived(usize),
// Types of packets queued
RealPacketQueued,
RetransmissionQueued,
ReplySurbRequestQueued,
AdditionalReplySurbRequestQueued,
}
type PacketStatisticsReceiver = tokio::sync::mpsc::UnboundedReceiver<PacketStatisticsEvent>;
#[derive(Clone)]
pub(crate) struct PacketStatisticsReporter {
stats_tx: tokio::sync::mpsc::UnboundedSender<PacketStatisticsEvent>,
}
impl PacketStatisticsReporter {
pub(crate) fn new(stats_tx: tokio::sync::mpsc::UnboundedSender<PacketStatisticsEvent>) -> Self {
Self { stats_tx }
}
pub(crate) fn report(&self, event: PacketStatisticsEvent) {
self.stats_tx.send(event).unwrap_or_else(|err| {
log::error!("Failed to report packet stat: {:?}", err);
});
}
}
pub(crate) struct PacketStatisticsControl {
// Incoming packet stats events from other tasks
stats_rx: PacketStatisticsReceiver,
// Keep track of packet statistics over time
stats: PacketStatistics,
// We keep snapshots of the statistics over time so we can compute rates, and also keeping the
// full history allows for some more fancy averaging if we want to do that.
history: VecDeque<(Instant, PacketStatistics)>,
// Keep previous rates so that we can detect notable events
rates: VecDeque<(Instant, PacketRates)>,
}
impl PacketStatisticsControl {
pub(crate) fn new() -> (Self, PacketStatisticsReporter) {
let (stats_tx, stats_rx) = tokio::sync::mpsc::unbounded_channel();
(
Self {
stats_rx,
stats: PacketStatistics::default(),
history: VecDeque::new(),
rates: VecDeque::new(),
},
PacketStatisticsReporter::new(stats_tx),
)
}
// Add the current stats to the history, and remove old ones.
fn update_history(&mut self) {
// Update latest
self.history.push_back((Instant::now(), self.stats.clone()));
// Filter out old ones
let recording_window = Instant::now() - Duration::from_millis(RECORDING_WINDOW_MS);
while self
.history
.front()
.map_or(false, |&(t, _)| t < recording_window)
{
self.history.pop_front();
}
}
fn compute_rates(&self) -> Option<PacketRates> {
// NOTE: consider changing this to compute rates over the history instead of using current
// stats. Currently it should not make much of a difference since we call this just after
// updating the history, but it seems like it could be more internally consistent to do it
// that way.
// Do basic averaging over the entire history, which just uses the first and last
if let Some((start, start_stats)) = self.history.front() {
let duration_secs = Instant::now().duration_since(*start).as_secs_f64();
let delta = self.stats.clone() - start_stats.clone();
let rates = PacketRates::from(delta) / duration_secs;
Some(rates)
} else {
None
}
}
fn update_rates(&mut self) {
// Update latest
if let Some(rates) = self.compute_rates() {
self.rates.push_back((Instant::now(), rates));
}
// Filter out old ones
let recording_window = Instant::now() - Duration::from_millis(RECORDING_WINDOW_MS);
while self
.rates
.front()
.map_or(false, |&(t, _)| t < recording_window)
{
self.rates.pop_front();
}
}
fn report_rates(&self) {
if let Some((_, rates)) = self.rates.back() {
log::info!("{}", rates.summary());
log::debug!("{}", rates.detailed_summary());
}
}
fn report_counters(&self) {
log::trace!("packet statistics: {:?}", &self.stats);
let (summary_sent, summary_recv) = self.stats.summary();
log::debug!("{}", summary_sent);
log::debug!("{}", summary_recv);
}
fn check_for_notable_events(&self) {
let Some((_, latest_rates)) = self.rates.back() else {
return;
};
// If we get a burst of retransmissions
// TODO: consider making this the number of retransmissions since last report instead.
if latest_rates.retransmissions_queued > 0.0 {
log::debug!(
"retransmissions: {:.2} pkt/s",
latest_rates.retransmissions_queued
);
// Check what the number of retransmissions was during the recording window
if let Some((_, start_stats)) = self.history.front() {
let delta = self.stats.clone() - start_stats.clone();
log::info!(
"mix packet retransmissions/real mix packets: {}/{}",
delta.retransmissions_queued,
delta.real_packets_queued,
);
} else {
log::warn!("Unable to check retransmissions during recording window");
}
}
// IDEA: if there is a burst of acks, that could indicate tokio task starvation.
}
pub(crate) async fn run_with_shutdown(&mut self, mut shutdown: nym_task::TaskClient) {
log::debug!("Started PacketStatisticsControl with graceful shutdown support");
let report_interval = Duration::from_secs(PACKET_REPORT_INTERVAL_SECS);
let mut report_interval = tokio::time::interval(report_interval);
let snapshot_interval = Duration::from_millis(SNAPSHOT_INTERVAL_MS);
let mut snapshot_interval = tokio::time::interval(snapshot_interval);
loop {
tokio::select! {
stats_event = self.stats_rx.recv() => match stats_event {
Some(stats_event) => {
log::trace!("PacketStatisticsControl: Received stats event");
self.stats.handle_event(stats_event);
},
None => {
log::trace!("PacketStatisticsControl: stopping since stats channel was closed");
break;
}
},
_ = snapshot_interval.tick() => {
self.update_history();
self.update_rates();
}
_ = report_interval.tick() => {
self.report_rates();
self.check_for_notable_events();
self.report_counters();
}
_ = shutdown.recv_with_delay() => {
log::trace!("PacketStatisticsControl: Received shutdown");
break;
},
}
}
log::debug!("PacketStatisticsControl: Exiting");
}
pub(crate) fn start_with_shutdown(mut self, task_client: nym_task::TaskClient) {
spawn_future(async move {
self.run_with_shutdown(task_client).await;
})
}
}
@@ -1,6 +1,8 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::client::packet_statistics_control::{PacketStatisticsEvent, PacketStatisticsReporter};
use super::action_controller::{AckActionSender, Action};
use futures::StreamExt;
use log::*;
@@ -17,6 +19,7 @@ pub(super) struct AcknowledgementListener {
ack_key: Arc<AckKey>,
ack_receiver: AcknowledgementReceiver,
action_sender: AckActionSender,
stats_tx: PacketStatisticsReporter,
}
impl AcknowledgementListener {
@@ -24,16 +27,21 @@ impl AcknowledgementListener {
ack_key: Arc<AckKey>,
ack_receiver: AcknowledgementReceiver,
action_sender: AckActionSender,
stats_tx: PacketStatisticsReporter,
) -> Self {
AcknowledgementListener {
ack_key,
ack_receiver,
action_sender,
stats_tx,
}
}
async fn on_ack(&mut self, ack_content: Vec<u8>) {
trace!("Received an ack");
self.stats_tx
.report(PacketStatisticsEvent::AckReceived(ack_content.len()));
let frag_id = match recover_identifier(&self.ack_key, &ack_content)
.map(FragmentIdentifier::try_from_bytes)
{
@@ -48,11 +56,14 @@ impl AcknowledgementListener {
// because nothing was inserted in the first place
if frag_id == COVER_FRAG_ID {
trace!("Received an ack for a cover message - no need to do anything");
self.stats_tx
.report(PacketStatisticsEvent::CoverAckReceived(ack_content.len()));
return;
}
trace!("Received {} from the mix network", frag_id);
self.stats_tx
.report(PacketStatisticsEvent::RealAckReceived(ack_content.len()));
self.action_sender
.unbounded_send(Action::new_remove(frag_id))
.unwrap();
@@ -8,6 +8,7 @@ use self::{
sent_notification_listener::SentNotificationListener,
};
use crate::client::inbound_messages::InputMessageReceiver;
use crate::client::packet_statistics_control::PacketStatisticsReporter;
use crate::client::real_messages_control::message_handler::MessageHandler;
use crate::client::replies::reply_controller::ReplyControllerSender;
use crate::spawn_future;
@@ -208,6 +209,7 @@ where
connectors: AcknowledgementControllerConnectors,
message_handler: MessageHandler<R>,
reply_controller_sender: ReplyControllerSender,
stats_tx: PacketStatisticsReporter,
) -> Self {
let (retransmission_tx, retransmission_rx) = mpsc::unbounded();
@@ -224,6 +226,7 @@ where
Arc::clone(&ack_key),
connectors.ack_receiver,
connectors.ack_action_sender.clone(),
stats_tx,
);
// will listen for any new messages from the client
@@ -35,6 +35,8 @@ use crate::client::replies::reply_controller;
use crate::config;
pub(crate) use acknowledgement_control::{AckActionSender, Action};
use super::packet_statistics_control::PacketStatisticsReporter;
pub(crate) mod acknowledgement_control;
pub(crate) mod message_handler;
pub(crate) mod real_traffic_stream;
@@ -143,6 +145,7 @@ impl RealMessagesController<OsRng> {
reply_controller_receiver: ReplyControllerReceiver,
lane_queue_lengths: LaneQueueLengths,
client_connection_rx: ConnectionCommandReceiver,
stats_tx: PacketStatisticsReporter,
) -> Self {
let rng = OsRng;
@@ -181,6 +184,7 @@ impl RealMessagesController<OsRng> {
ack_controller_connectors,
message_handler.clone(),
reply_controller_sender,
stats_tx.clone(),
);
let reply_control = ReplyController::new(
@@ -199,6 +203,7 @@ impl RealMessagesController<OsRng> {
topology_access,
lane_queue_lengths,
client_connection_rx,
stats_tx,
);
RealMessagesController {
@@ -3,6 +3,7 @@
use self::sending_delay_controller::SendingDelayController;
use crate::client::mix_traffic::BatchMixMessageSender;
use crate::client::packet_statistics_control::{PacketStatisticsEvent, PacketStatisticsReporter};
use crate::client::real_messages_control::acknowledgement_control::SentPacketNotificationSender;
use crate::client::topology_control::TopologyAccessor;
use crate::client::transmission_buffer::TransmissionBuffer;
@@ -113,6 +114,9 @@ where
/// Report queue lengths so that upstream can backoff sending data, and keep connections open.
lane_queue_lengths: LaneQueueLengths,
/// Channel used for sending statistics events to `PacketStatisticsControl`.
stats_tx: PacketStatisticsReporter,
}
#[derive(Debug)]
@@ -171,6 +175,7 @@ where
topology_access: TopologyAccessor,
lane_queue_lengths: LaneQueueLengths,
client_connection_rx: ConnectionCommandReceiver,
stats_tx: PacketStatisticsReporter,
) -> Self {
OutQueueControl {
config,
@@ -184,6 +189,7 @@ where
transmission_buffer: TransmissionBuffer::new(),
client_connection_rx,
lane_queue_lengths,
stats_tx,
}
}
@@ -214,7 +220,7 @@ where
async fn on_message(&mut self, next_message: StreamMessage) {
trace!("created new message");
let (next_message, fragment_id) = match next_message {
let (next_message, fragment_id, packet_size) = match next_message {
StreamMessage::Cover => {
let cover_traffic_packet_size = self.loop_cover_message_size();
trace!("the next loop cover message will be put in a {cover_traffic_packet_size} packet");
@@ -250,15 +256,28 @@ where
"Somehow failed to generate a loop cover message with a valid topology",
),
None,
cover_traffic_packet_size.size(),
)
}
StreamMessage::Real(real_message) => {
(real_message.mix_packet, real_message.fragment_id)
let packet_size = real_message.packet_size();
(
real_message.mix_packet,
real_message.fragment_id,
packet_size,
)
}
};
if let Err(err) = self.mix_tx.send(vec![next_message]).await {
log::error!("Failed to send: {err}");
} else {
let event = if fragment_id.is_some() {
PacketStatisticsEvent::RealPacketSent(packet_size)
} else {
PacketStatisticsEvent::CoverPacketSent(packet_size)
};
self.stats_tx.report(event);
}
// notify ack controller about sending our message only after we actually managed to push it
@@ -340,6 +359,28 @@ where
let lane_length = self.transmission_buffer.lane_length(&lane);
self.lane_queue_lengths.set(&lane, lane_length);
// This is the last step in the pipeline where we know the type of the message, so
// lets count the number of retransmissions and reply surb messages sent here.
let stat_event = match lane {
TransmissionLane::General => None,
TransmissionLane::ConnectionId(_) => None,
TransmissionLane::ReplySurbRequest => {
Some(PacketStatisticsEvent::ReplySurbRequestQueued)
}
TransmissionLane::AdditionalReplySurbs => {
Some(PacketStatisticsEvent::AdditionalReplySurbRequestQueued)
}
TransmissionLane::Retransmission => Some(PacketStatisticsEvent::RetransmissionQueued),
};
if let Some(stat_event) = stat_event {
self.stats_tx.report(stat_event);
}
// To avoid comparing apples to oranges when presenting the fraction of packets that are
// retransmissions, we also need to keep track to the total number of real messages queued,
// even though we also track the actual number of messages sent later in the pipeline.
self.stats_tx
.report(PacketStatisticsEvent::RealPacketQueued);
Some(real_next)
}
@@ -433,6 +474,13 @@ where
Poll::Ready(Some((real_messages, conn_id))) => {
log::trace!("handling real_messages: size: {}", real_messages.len());
// This is the last step in the pipeline where we know the type of the message, so
// lets count the number of retransmissions here.
if conn_id == TransmissionLane::Retransmission {
self.stats_tx
.report(PacketStatisticsEvent::RetransmissionQueued);
}
// First store what we got for the given connection id
self.transmission_buffer.store(&conn_id, real_messages);
let real_next = self.pop_next_message().expect("we just added one");
@@ -471,10 +519,10 @@ where
let mult = self.sending_delay_controller.current_multiplier();
let delay = self.current_average_message_sending_delay().as_millis();
let status_str = if self.config.traffic.disable_main_poisson_packet_distribution {
format!("Status: {lanes} lanes, backlog: {backlog:.2} kiB ({packets}), no delay")
format!("Packet backlog: {backlog:.2} kiB ({packets}), {lanes} lanes, no delay")
} else {
format!(
"Status: {lanes} lanes, backlog: {backlog:.2} kiB ({packets}), avg delay: {delay}ms ({mult})"
"Packet backlog: {backlog:.2} kiB ({packets}), {lanes} lanes, avg delay: {delay}ms ({mult})"
)
};
if packets > 1000 {
@@ -1,8 +1,10 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::client::replies::reply_controller::ReplyControllerSender;
use crate::client::replies::reply_storage::SentReplyKeys;
use crate::client::{
packet_statistics_control::{PacketStatisticsEvent, PacketStatisticsReporter},
replies::{reply_controller::ReplyControllerSender, reply_storage::SentReplyKeys},
};
use crate::spawn_future;
use futures::channel::mpsc;
use futures::lock::Mutex;
@@ -43,15 +45,33 @@ struct ReceivedMessagesBufferInner<R: MessageReceiver> {
// but perhaps it should be changed to include timestamps of when the message was reconstructed
// and every now and then remove ids older than X
recently_reconstructed: HashSet<i32>,
stats_tx: PacketStatisticsReporter,
}
impl<R: MessageReceiver> ReceivedMessagesBufferInner<R> {
fn recover_from_fragment(&mut self, fragment_data: &[u8]) -> Option<NymMessage> {
fn recover_from_fragment(
&mut self,
fragment_data: &[u8],
fragment_data_size: usize,
) -> Option<NymMessage> {
if nym_sphinx::cover::is_cover(fragment_data) {
trace!("The message was a loop cover message! Skipping it");
// NOTE: it's important to note that there is quite a bit of difference in size of
// received and sent packets due to the sphinx layers being removed by the exit gateway
// before it reaches the mixnet client.
self.stats_tx
.report(PacketStatisticsEvent::CoverPacketReceived(
fragment_data_size,
));
return None;
}
self.stats_tx
.report(PacketStatisticsEvent::RealPacketReceived(
fragment_data_size,
));
let fragment = match self.message_receiver.recover_fragment(fragment_data) {
Err(err) => {
warn!("failed to recover fragment from raw data: {err}. The whole underlying message might be corrupted and unrecoverable!");
@@ -103,15 +123,17 @@ impl<R: MessageReceiver> ReceivedMessagesBufferInner<R> {
reply_ciphertext: &mut [u8],
reply_key: SurbEncryptionKey,
) -> Result<Option<NymMessage>, MessageRecoveryError> {
let reply_ciphertext_size = reply_ciphertext.len();
// note: this performs decryption IN PLACE without extra allocation
self.message_receiver
.recover_plaintext_from_reply(reply_ciphertext, reply_key)?;
let fragment_data = reply_ciphertext;
Ok(self.recover_from_fragment(fragment_data))
Ok(self.recover_from_fragment(fragment_data, reply_ciphertext_size))
}
fn process_received_regular_packet(&mut self, mut raw_fragment: Vec<u8>) -> Option<NymMessage> {
let raw_fragment_size = raw_fragment.len();
let fragment_data = match self.message_receiver.recover_plaintext_from_regular_packet(
self.local_encryption_keypair.private_key(),
&mut raw_fragment,
@@ -123,7 +145,7 @@ impl<R: MessageReceiver> ReceivedMessagesBufferInner<R> {
Ok(frag_data) => frag_data,
};
self.recover_from_fragment(fragment_data)
self.recover_from_fragment(fragment_data, raw_fragment_size)
}
}
@@ -141,6 +163,7 @@ impl<R: MessageReceiver> ReceivedMessagesBuffer<R> {
local_encryption_keypair: Arc<encryption::KeyPair>,
reply_key_storage: SentReplyKeys,
reply_controller_sender: ReplyControllerSender,
stats_tx: PacketStatisticsReporter,
) -> Self {
ReceivedMessagesBuffer {
inner: Arc::new(Mutex::new(ReceivedMessagesBufferInner {
@@ -149,6 +172,7 @@ impl<R: MessageReceiver> ReceivedMessagesBuffer<R> {
message_receiver: R::new(),
message_sender: None,
recently_reconstructed: HashSet::new(),
stats_tx,
})),
reply_key_storage,
reply_controller_sender,
@@ -353,7 +377,7 @@ impl<R: MessageReceiver> ReceivedMessagesBuffer<R> {
};
if let Some(completed) = completed_message {
info!("received {completed}");
debug!("received {completed}");
completed_messages.push(completed)
}
}
@@ -480,11 +504,13 @@ impl<R: MessageReceiver + Clone + Send + 'static> ReceivedMessagesBufferControll
mixnet_packet_receiver: MixnetMessageReceiver,
reply_key_storage: SentReplyKeys,
reply_controller_sender: ReplyControllerSender,
packet_statistics_reporter: PacketStatisticsReporter,
) -> Self {
let received_buffer = ReceivedMessagesBuffer::new(
local_encryption_keypair,
reply_key_storage,
reply_controller_sender,
packet_statistics_reporter,
);
ReceivedMessagesBufferController {
+1 -1
View File
@@ -65,7 +65,7 @@ pub async fn current_gateways<R: Rng>(
.ok_or(ClientCoreError::ListOfNymApisIsEmpty)?;
let client = nym_validator_client::client::NymApiClient::new(nym_api.clone());
log::trace!("Fetching list of gateways from: {nym_api}");
log::debug!("Fetching list of gateways from: {nym_api}");
let gateways = client.get_cached_described_gateways().await?;
log::debug!("Found {} gateways", gateways.len());
+1 -1
View File
@@ -178,7 +178,7 @@ impl<T> From<PersistedGatewayDetails<T>> for GatewayDetails<T> {
}
}
#[derive(Clone)]
#[derive(Clone, Debug)]
pub enum GatewaySelectionSpecification<T = EmptyCustomDetails> {
/// Uniformly choose a random remote gateway.
UniformRemote { must_use_tls: bool },
+2 -2
View File
@@ -19,7 +19,7 @@ tokio = { version = "1.24.1", features = ["macros"] }
# internal
nym-bandwidth-controller = { path = "../../bandwidth-controller" }
nym-coconut-interface = { path = "../../coconut-interface" }
nym-credentials = { path = "../../credentials" }
nym-credential-storage = { path = "../../credential-storage" }
nym-crypto = { path = "../../crypto" }
nym-gateway-requests = { path = "../../../gateway/gateway-requests" }
@@ -48,7 +48,7 @@ features = ["net", "sync", "time"]
workspace = true
# the choice of this particular tls feature was arbitrary;
# if you reckon a different one would be more appropriate, feel free to change it
features = ["native-tls"]
# features = ["native-tls"]
# wasm-only dependencies
[target."cfg(target_arch = \"wasm32\")".dependencies.wasm-bindgen]
+55 -14
View File
@@ -1,4 +1,4 @@
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
// Copyright 2021-2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::error::GatewayClientError;
@@ -6,20 +6,23 @@ use crate::packet_router::PacketRouter;
pub use crate::packet_router::{
AcknowledgementReceiver, AcknowledgementSender, MixnetMessageReceiver, MixnetMessageSender,
};
use crate::socket_state::{PartiallyDelegated, SocketState};
use crate::socket_state::{ws_fd, PartiallyDelegated, SocketState};
use crate::traits::GatewayPacketRouter;
use crate::{cleanup_socket_message, try_decrypt_binary_message};
use futures::{SinkExt, StreamExt};
use log::*;
use nym_bandwidth_controller::BandwidthController;
use nym_coconut_interface::Credential;
use nym_credential_storage::ephemeral_storage::EphemeralStorage as EphemeralCredentialStorage;
use nym_credential_storage::storage::Storage as CredentialStorage;
use nym_credentials::CredentialSpendingData;
use nym_crypto::asymmetric::identity;
use nym_gateway_requests::authentication::encrypted_address::EncryptedAddressBytes;
use nym_gateway_requests::iv::IV;
use nym_gateway_requests::registration::handshake::{client_handshake, SharedKeys};
use nym_gateway_requests::{BinaryRequest, ClientControlRequest, ServerResponse, PROTOCOL_VERSION};
use nym_gateway_requests::{
BinaryRequest, ClientControlRequest, ServerResponse, CREDENTIAL_UPDATE_V1_PROTOCOL_VERSION,
CURRENT_PROTOCOL_VERSION,
};
use nym_network_defaults::{REMAINING_BANDWIDTH_THRESHOLD, TOKENS_TO_BURN};
use nym_sphinx::forwarding::packet::MixPacket;
use nym_task::TaskClient;
@@ -30,11 +33,15 @@ use std::sync::Arc;
use std::time::Duration;
use tungstenite::protocol::Message;
#[cfg(unix)]
use std::os::fd::RawFd;
#[cfg(not(target_arch = "wasm32"))]
use tokio::time::sleep;
#[cfg(not(target_arch = "wasm32"))]
use tokio_tungstenite::connect_async;
#[cfg(not(unix))]
use std::os::raw::c_int as RawFd;
#[cfg(target_arch = "wasm32")]
use wasm_utils::websocket::JSWebsocket;
#[cfg(target_arch = "wasm32")]
@@ -79,6 +86,9 @@ pub struct GatewayClient<C, St = EphemeralCredentialStorage> {
/// Delay between each subsequent reconnection attempt.
reconnection_backoff: Duration,
// currently unused (but populated)
negotiated_protocol: Option<u8>,
/// Listen to shutdown messages.
shutdown: TaskClient,
}
@@ -108,6 +118,7 @@ impl<C, St> GatewayClient<C, St> {
should_reconnect_on_failure: true,
reconnection_attempts: DEFAULT_RECONNECTION_ATTEMPTS,
reconnection_backoff: DEFAULT_RECONNECTION_BACKOFF,
negotiated_protocol: None,
shutdown,
}
}
@@ -146,6 +157,14 @@ impl<C, St> GatewayClient<C, St> {
self.gateway_identity
}
pub fn ws_fd(&self) -> Option<RawFd> {
match &self.connection {
SocketState::Available(conn) => ws_fd(conn.as_ref()),
SocketState::PartiallyDelegated(conn) => conn.ws_fd(),
_ => None,
}
}
pub fn remaining_bandwidth(&self) -> i64 {
self.bandwidth_remaining
}
@@ -376,6 +395,8 @@ impl<C, St> GatewayClient<C, St> {
&self,
gateway_protocol: Option<u8>,
) -> Result<(), GatewayClientError> {
debug!("gateway protocol: {gateway_protocol:?}, ours: {CURRENT_PROTOCOL_VERSION}");
// right now there are no failure cases here, but this might change in the future
match gateway_protocol {
None => {
@@ -383,17 +404,17 @@ impl<C, St> GatewayClient<C, St> {
// note: in +1.2.0 we will have to return a hard error here
Ok(())
}
Some(v) if v != PROTOCOL_VERSION => {
Some(v) if v > CURRENT_PROTOCOL_VERSION => {
let err = GatewayClientError::IncompatibleProtocol {
gateway: Some(v),
current: PROTOCOL_VERSION,
current: CURRENT_PROTOCOL_VERSION,
};
error!("{err}");
Err(err)
}
Some(_) => {
info!("the gateway is using exactly the same protocol version as we are. We're good to continue!");
info!("the gateway is using exactly the same (or older) protocol version as we are. We're good to continue!");
Ok(())
}
}
@@ -439,6 +460,10 @@ impl<C, St> GatewayClient<C, St> {
if self.authenticated {
self.shared_key = Some(Arc::new(shared_key));
}
// populate the negotiated protocol for future uses
self.negotiated_protocol = gateway_protocol;
Ok(())
}
@@ -481,6 +506,7 @@ impl<C, St> GatewayClient<C, St> {
self.check_gateway_protocol(protocol_version)?;
self.authenticated = status;
self.bandwidth_remaining = bandwidth_remaining;
self.negotiated_protocol = protocol_version;
Ok(())
}
ServerResponse::Error { message } => Err(GatewayClientError::GatewayError(message)),
@@ -515,13 +541,13 @@ impl<C, St> GatewayClient<C, St> {
async fn claim_coconut_bandwidth(
&mut self,
credential: Credential,
credential: CredentialSpendingData,
) -> Result<(), GatewayClientError> {
let mut rng = OsRng;
let iv = IV::new_random(&mut rng);
let msg = ClientControlRequest::new_enc_coconut_bandwidth_credential(
&credential,
let msg = ClientControlRequest::new_enc_coconut_bandwidth_credential_v2(
credential,
self.shared_key.as_ref().unwrap(),
iv,
)
@@ -567,18 +593,31 @@ impl<C, St> GatewayClient<C, St> {
return self.try_claim_testnet_bandwidth().await;
}
let (credential, credential_id) = self
let Some(gateway_protocol) = self.negotiated_protocol else {
return Err(GatewayClientError::OutdatedGatewayCredentialVersion {
negotiated_protocol: None,
});
};
if gateway_protocol < CREDENTIAL_UPDATE_V1_PROTOCOL_VERSION {
return Err(GatewayClientError::OutdatedGatewayCredentialVersion {
negotiated_protocol: Some(gateway_protocol),
});
}
let prepared_credential = self
.bandwidth_controller
.as_ref()
.unwrap()
.prepare_coconut_credential()
.prepare_bandwidth_credential()
.await?;
self.claim_coconut_bandwidth(credential).await?;
self.claim_coconut_bandwidth(prepared_credential.data)
.await?;
self.bandwidth_controller
.as_ref()
.unwrap()
.consume_credential(credential_id)
.consume_credential(prepared_credential.credential_id)
.await?;
Ok(())
@@ -817,6 +856,7 @@ impl GatewayClient<InitOnly, EphemeralCredentialStorage> {
should_reconnect_on_failure: false,
reconnection_attempts: DEFAULT_RECONNECTION_ATTEMPTS,
reconnection_backoff: DEFAULT_RECONNECTION_BACKOFF,
negotiated_protocol: None,
shutdown,
}
}
@@ -848,6 +888,7 @@ impl GatewayClient<InitOnly, EphemeralCredentialStorage> {
should_reconnect_on_failure: self.should_reconnect_on_failure,
reconnection_attempts: self.reconnection_attempts,
reconnection_backoff: self.reconnection_backoff,
negotiated_protocol: self.negotiated_protocol,
shutdown,
}
}
@@ -47,6 +47,9 @@ pub enum GatewayClientError {
#[error("Credential could not be serialized")]
SerializeCredential,
#[error("can not spend bandwidth credential with the gateway as it's using outdated protocol (version: {negotiated_protocol:?})")]
OutdatedGatewayCredentialVersion { negotiated_protocol: Option<u8> },
#[error("Client is not authenticated")]
NotAuthenticated,
@@ -11,9 +11,12 @@ use futures::{SinkExt, StreamExt};
use log::*;
use nym_gateway_requests::registration::handshake::SharedKeys;
use nym_task::TaskClient;
use std::os::raw::c_int as RawFd;
use std::sync::Arc;
use tungstenite::Message;
#[cfg(unix)]
use std::os::fd::AsRawFd;
#[cfg(not(target_arch = "wasm32"))]
use tokio::net::TcpStream;
#[cfg(not(target_arch = "wasm32"))]
@@ -37,9 +40,22 @@ type WsConn = JSWebsocket;
type SplitStreamReceiver = oneshot::Receiver<Result<SplitStream<WsConn>, GatewayClientError>>;
pub(crate) fn ws_fd(_conn: &WsConn) -> Option<RawFd> {
#[cfg(unix)]
match _conn.get_ref() {
MaybeTlsStream::Plain(stream) => Some(stream.as_raw_fd()),
&_ => unreachable!(
"If tls features are enabled, the inner stream needs to be unpacked into raw fd"
),
}
#[cfg(not(unix))]
None
}
pub(crate) struct PartiallyDelegated {
sink_half: SplitSink<WsConn, Message>,
delegated_stream: (SplitStreamReceiver, oneshot::Sender<()>),
ws_fd: Option<RawFd>,
}
impl PartiallyDelegated {
@@ -92,6 +108,8 @@ impl PartiallyDelegated {
let (notify_sender, notify_receiver) = oneshot::channel();
let (stream_sender, stream_receiver) = oneshot::channel();
let ws_fd = ws_fd(&conn);
let (sink, mut stream) = conn.split();
let mixnet_receiver_future = async move {
@@ -141,11 +159,16 @@ impl PartiallyDelegated {
tokio::spawn(mixnet_receiver_future);
PartiallyDelegated {
ws_fd,
sink_half: sink,
delegated_stream: (stream_receiver, notify_sender),
}
}
pub(crate) fn ws_fd(&self) -> Option<RawFd> {
self.ws_fd
}
// if we want to send a message and don't care about response, we can don't need to reunite the split,
// the sink itself is enough
pub(crate) async fn send_without_response(
@@ -31,9 +31,8 @@ log = { workspace = true }
url = { workspace = true, features = ["serde"] }
tokio = { workspace = true, features = ["sync", "time"] }
futures = { workspace = true }
openssl = { version = "^0.10.55", features = ["vendored"], optional = true }
nym-coconut-interface = { path = "../../coconut-interface" }
nym-coconut = { path = "../../nymcoconut" }
nym-network-defaults = { path = "../../network-defaults" }
nym-api-requests = { path = "../../../nym-api/nym-api-requests" }
@@ -90,7 +89,7 @@ required-features = ["http-client"]
[features]
default = ["http-client"]
http-client = ["cosmrs/rpc", "openssl"]
http-client = ["cosmrs/rpc"]
generate-ts = []
contract-testing = ["nym-mixnet-contract-common/contract-testing"]
@@ -8,8 +8,10 @@ use crate::{
nym_api, DirectSigningReqwestRpcValidatorClient, QueryReqwestRpcValidatorClient,
ReqwestRpcClient, ValidatorClientError,
};
use nym_api_requests::coconut::models::FreePassNonceResponse;
use nym_api_requests::coconut::{
BlindSignRequestBody, BlindedSignatureResponse, VerifyCredentialBody, VerifyCredentialResponse,
BlindSignRequestBody, BlindedSignatureResponse, FreePassRequest, VerifyCredentialBody,
VerifyCredentialResponse,
};
use nym_api_requests::models::{DescribedGateway, MixNodeBondAnnotated};
use nym_api_requests::models::{
@@ -42,6 +44,14 @@ pub struct Config {
nyxd_config: nyxd::Config,
}
impl TryFrom<NymNetworkDetails> for Config {
type Error = ValidatorClientError;
fn try_from(value: NymNetworkDetails) -> Result<Self, Self::Error> {
Config::try_from_nym_network_details(&value)
}
}
impl Config {
pub fn try_from_nym_network_details(
details: &NymNetworkDetails,
@@ -340,4 +350,15 @@ impl NymApiClient {
.verify_bandwidth_credential(request_body)
.await?)
}
pub async fn free_pass_nonce(&self) -> Result<FreePassNonceResponse, ValidatorClientError> {
Ok(self.nym_api.free_pass_nonce().await?)
}
pub async fn issue_free_pass_credential(
&self,
request: &FreePassRequest,
) -> Result<BlindedSignatureResponse, ValidatorClientError> {
Ok(self.nym_api.free_pass(request).await?)
}
}
@@ -4,9 +4,9 @@
use crate::nyxd::contract_traits::{DkgQueryClient, PagedDkgQueryClient};
use crate::nyxd::error::NyxdError;
use crate::NymApiClient;
use nym_coconut::{Base58, CoconutError, VerificationKey};
use nym_coconut_dkg_common::types::{EpochId, NodeIndex};
use nym_coconut_dkg_common::verification_key::ContractVKShare;
use nym_coconut_interface::{Base58, CoconutError, VerificationKey};
use thiserror::Error;
use url::Url;
@@ -5,21 +5,24 @@ use crate::nym_api::error::NymAPIError;
use crate::nym_api::routes::{CORE_STATUS_COUNT, SINCE_ARG};
use async_trait::async_trait;
use http_api_client::{ApiClient, NO_PARAMS};
use nym_api_requests::coconut::models::{
EpochCredentialsResponse, IssuedCredentialResponse, IssuedCredentialsResponse,
pub use nym_api_requests::{
coconut::{
models::{
EpochCredentialsResponse, IssuedCredential, IssuedCredentialBody,
IssuedCredentialResponse, IssuedCredentialsResponse,
},
BlindSignRequestBody, BlindedSignatureResponse, CredentialsRequestBody,
VerifyCredentialBody, VerifyCredentialResponse,
},
models::{
ComputeRewardEstParam, DescribedGateway, GatewayBondAnnotated, GatewayCoreStatusResponse,
GatewayStatusReportResponse, GatewayUptimeHistoryResponse, InclusionProbabilityResponse,
MixNodeBondAnnotated, MixnodeCoreStatusResponse, MixnodeStatusReportResponse,
MixnodeStatusResponse, MixnodeUptimeHistoryResponse, RewardEstimationResponse,
StakeSaturationResponse, UptimeResponse,
},
};
use nym_api_requests::coconut::{
BlindSignRequestBody, BlindedSignatureResponse, CredentialsRequestBody, VerifyCredentialBody,
VerifyCredentialResponse,
};
use nym_api_requests::models::{
ComputeRewardEstParam, DescribedGateway, GatewayBondAnnotated, GatewayCoreStatusResponse,
GatewayStatusReportResponse, GatewayUptimeHistoryResponse, InclusionProbabilityResponse,
MixNodeBondAnnotated, MixnodeCoreStatusResponse, MixnodeStatusReportResponse,
MixnodeStatusResponse, MixnodeUptimeHistoryResponse, RewardEstimationResponse,
StakeSaturationResponse, UptimeResponse,
};
use nym_coconut_dkg_common::types::EpochId;
pub use nym_coconut_dkg_common::types::EpochId;
use nym_mixnet_contract_common::mixnode::MixNodeDetails;
use nym_mixnet_contract_common::{GatewayBond, IdentityKeyRef, MixId};
use nym_name_service_common::response::NamesListResponse;
@@ -29,6 +32,8 @@ pub mod error;
pub mod routes;
pub use http_api_client::Client;
use nym_api_requests::coconut::models::FreePassNonceResponse;
use nym_api_requests::coconut::FreePassRequest;
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
@@ -370,6 +375,36 @@ pub trait NymApiClientExt: ApiClient {
.await
}
async fn free_pass_nonce(&self) -> Result<FreePassNonceResponse, NymAPIError> {
self.get_json(
&[
routes::API_VERSION,
routes::COCONUT_ROUTES,
routes::BANDWIDTH,
routes::COCONUT_FREE_PASS_NONCE,
],
NO_PARAMS,
)
.await
}
async fn free_pass(
&self,
request: &FreePassRequest,
) -> Result<BlindedSignatureResponse, NymAPIError> {
self.post_json(
&[
routes::API_VERSION,
routes::COCONUT_ROUTES,
routes::BANDWIDTH,
routes::COCONUT_FREE_PASS,
],
NO_PARAMS,
request,
)
.await
}
async fn blind_sign(
&self,
request_body: &BlindSignRequestBody,
@@ -15,6 +15,8 @@ pub const REWARDED: &str = "rewarded";
pub const COCONUT_ROUTES: &str = "coconut";
pub const BANDWIDTH: &str = "bandwidth";
pub const COCONUT_FREE_PASS: &str = "free-pass";
pub const COCONUT_FREE_PASS_NONCE: &str = "free-pass-nonce";
pub const COCONUT_BLIND_SIGN: &str = "blind-sign";
pub const COCONUT_VERIFY_BANDWIDTH_CREDENTIAL: &str = "verify-bandwidth-credential";
pub const COCONUT_EPOCH_CREDENTIALS: &str = "epoch-credentials";
@@ -8,6 +8,8 @@ use cosmwasm_std::{Fraction, Uint128};
use serde::{Deserialize, Serialize};
use std::fmt;
use std::ops::Div;
use std::str::FromStr;
use thiserror::Error;
#[derive(Serialize, Deserialize, Clone, Copy, Default, Debug, PartialEq, Eq)]
pub struct MismatchedDenoms;
@@ -126,6 +128,37 @@ impl From<CosmWasmCoin> for Coin {
}
}
// unfortunately cosmwasm didn't re-export this correct so we just redefine its
#[derive(Error, Debug, PartialEq, Eq)]
pub enum CoinFromStrError {
#[error("Missing denominator")]
MissingDenom,
#[error("Missing amount or non-digit characters in amount")]
MissingAmount,
#[error("Invalid amount: {0}")]
InvalidAmount(#[from] std::num::ParseIntError),
}
impl FromStr for Coin {
type Err = CoinFromStrError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let pos = s
.find(|c: char| !c.is_ascii_digit())
.ok_or(CoinFromStrError::MissingDenom)?;
let (amount, denom) = s.split_at(pos);
if amount.is_empty() {
return Err(CoinFromStrError::MissingAmount);
}
Ok(Coin {
amount: amount.parse::<u128>()?,
denom: denom.to_string(),
})
}
}
pub trait CoinConverter {
type Target;
@@ -1,4 +1,4 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// Copyright 2022-2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::collect_paged;
@@ -7,14 +7,23 @@ use crate::nyxd::error::NyxdError;
use crate::nyxd::CosmWasmClient;
use async_trait::async_trait;
use cosmrs::AccountId;
use nym_coconut_dkg_common::dealer::{
ContractDealing, DealerDetailsResponse, PagedDealerResponse, PagedDealingsResponse,
};
use nym_coconut_dkg_common::msg::QueryMsg as DkgQueryMsg;
use nym_coconut_dkg_common::types::{DealerDetails, Epoch, EpochId, InitialReplacementData};
use nym_coconut_dkg_common::verification_key::{ContractVKShare, PagedVKSharesResponse};
use cosmwasm_std::Addr;
use log::trace;
use nym_coconut_dkg_common::types::{ChunkIndex, NodeIndex, StateAdvanceResponse};
use serde::Deserialize;
use nym_coconut_dkg_common::dealer::RegisteredDealerDetails;
pub use nym_coconut_dkg_common::{
dealer::{DealerDetailsResponse, PagedDealerIndexResponse, PagedDealerResponse},
dealing::{
DealerDealingsStatusResponse, DealingChunkResponse, DealingChunkStatusResponse,
DealingMetadataResponse, DealingStatusResponse,
},
msg::QueryMsg as DkgQueryMsg,
types::{DealerDetails, DealingIndex, Epoch, EpochId, EpochState, State},
verification_key::{ContractVKShare, PagedVKSharesResponse, VkShareResponse},
};
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
pub trait DkgQueryClient {
@@ -22,17 +31,35 @@ pub trait DkgQueryClient {
where
for<'a> T: Deserialize<'a>;
async fn get_state(&self) -> Result<State, NyxdError> {
let request = DkgQueryMsg::GetState {};
self.query_dkg_contract(request).await
}
async fn get_current_epoch(&self) -> Result<Epoch, NyxdError> {
let request = DkgQueryMsg::GetCurrentEpochState {};
self.query_dkg_contract(request).await
}
async fn can_advance_state(&self) -> Result<StateAdvanceResponse, NyxdError> {
let request = DkgQueryMsg::CanAdvanceState {};
self.query_dkg_contract(request).await
}
async fn get_current_epoch_threshold(&self) -> Result<Option<u64>, NyxdError> {
let request = DkgQueryMsg::GetCurrentEpochThreshold {};
self.query_dkg_contract(request).await
}
async fn get_initial_dealers(&self) -> Result<Option<InitialReplacementData>, NyxdError> {
let request = DkgQueryMsg::GetInitialDealers {};
async fn get_registered_dealer_details(
&self,
address: &AccountId,
epoch_id: Option<EpochId>,
) -> Result<RegisteredDealerDetails, NyxdError> {
let request = DkgQueryMsg::GetRegisteredDealer {
dealer_address: address.to_string(),
epoch_id,
};
self.query_dkg_contract(request).await
}
@@ -55,26 +82,95 @@ pub trait DkgQueryClient {
self.query_dkg_contract(request).await
}
async fn get_past_dealers_paged(
async fn get_dealer_indices_paged(
&self,
start_after: Option<String>,
limit: Option<u32>,
) -> Result<PagedDealerResponse, NyxdError> {
let request = DkgQueryMsg::GetPastDealers { start_after, limit };
) -> Result<PagedDealerIndexResponse, NyxdError> {
let request = DkgQueryMsg::GetDealerIndices { start_after, limit };
self.query_dkg_contract(request).await
}
async fn get_dealings_paged(
async fn get_dealings_metadata(
&self,
idx: u64,
start_after: Option<String>,
limit: Option<u32>,
) -> Result<PagedDealingsResponse, NyxdError> {
let request = DkgQueryMsg::GetDealing {
idx,
limit,
start_after,
epoch_id: EpochId,
dealer: String,
dealing_index: DealingIndex,
) -> Result<DealingMetadataResponse, NyxdError> {
let request = DkgQueryMsg::GetDealingsMetadata {
epoch_id,
dealer,
dealing_index,
};
self.query_dkg_contract(request).await
}
async fn get_dealer_dealings_status(
&self,
epoch_id: EpochId,
dealer: String,
) -> Result<DealerDealingsStatusResponse, NyxdError> {
let request = DkgQueryMsg::GetDealerDealingsStatus { epoch_id, dealer };
self.query_dkg_contract(request).await
}
async fn get_dealing_status(
&self,
epoch_id: EpochId,
dealer: String,
dealing_index: DealingIndex,
) -> Result<DealingStatusResponse, NyxdError> {
let request = DkgQueryMsg::GetDealingStatus {
epoch_id,
dealer,
dealing_index,
};
self.query_dkg_contract(request).await
}
async fn get_dealing_chunk_status(
&self,
epoch_id: EpochId,
dealer: String,
dealing_index: DealingIndex,
chunk_index: ChunkIndex,
) -> Result<DealingChunkStatusResponse, NyxdError> {
let request = DkgQueryMsg::GetDealingChunkStatus {
epoch_id,
dealer,
dealing_index,
chunk_index,
};
self.query_dkg_contract(request).await
}
async fn get_dealing_chunk(
&self,
epoch_id: EpochId,
dealer: String,
dealing_index: DealingIndex,
chunk_index: ChunkIndex,
) -> Result<DealingChunkResponse, NyxdError> {
let request = DkgQueryMsg::GetDealingChunk {
epoch_id,
dealer,
dealing_index,
chunk_index,
};
self.query_dkg_contract(request).await
}
async fn get_vk_share(
&self,
epoch_id: EpochId,
owner: String,
) -> Result<VkShareResponse, NyxdError> {
let request = DkgQueryMsg::GetVerificationKey { epoch_id, owner };
self.query_dkg_contract(request).await
}
@@ -91,6 +187,11 @@ pub trait DkgQueryClient {
};
self.query_dkg_contract(request).await
}
async fn get_contract_cw2_version(&self) -> Result<cw2::ContractVersion, NyxdError> {
self.query_dkg_contract(DkgQueryMsg::GetCW2ContractVersion {})
.await
}
}
// extension trait to the query client to deal with the paged queries
@@ -102,12 +203,8 @@ pub trait PagedDkgQueryClient: DkgQueryClient {
collect_paged!(self, get_current_dealers_paged, dealers)
}
async fn get_all_past_dealers(&self) -> Result<Vec<DealerDetails>, NyxdError> {
collect_paged!(self, get_past_dealers_paged, dealers)
}
async fn get_all_epoch_dealings(&self, idx: u64) -> Result<Vec<ContractDealing>, NyxdError> {
collect_paged!(self, get_dealings_paged, dealings, idx)
async fn get_all_dealer_indices(&self) -> Result<Vec<(Addr, NodeIndex)>, NyxdError> {
collect_paged!(self, get_dealer_indices_paged, indices)
}
async fn get_all_verification_key_shares(
@@ -134,6 +231,7 @@ where
let dkg_contract_address = &self
.dkg_contract_address()
.ok_or_else(|| NyxdError::unavailable_contract_address("dkg contract"))?;
trace!("using the following dkg contract: {dkg_contract_address}");
self.query_contract_smart(dkg_contract_address, &query)
.await
}
@@ -143,6 +241,7 @@ where
mod tests {
use super::*;
use crate::nyxd::contract_traits::tests::IgnoreValue;
use nym_coconut_dkg_common::msg::QueryMsg;
// it's enough that this compiles and clippy is happy about it
#[allow(dead_code)]
@@ -151,25 +250,63 @@ mod tests {
msg: DkgQueryMsg,
) {
match msg {
DkgQueryMsg::GetState {} => client.get_state().ignore(),
DkgQueryMsg::GetCurrentEpochState {} => client.get_current_epoch().ignore(),
DkgQueryMsg::CanAdvanceState {} => client.can_advance_state().ignore(),
DkgQueryMsg::GetCurrentEpochThreshold {} => {
client.get_current_epoch_threshold().ignore()
}
DkgQueryMsg::GetInitialDealers {} => client.get_initial_dealers().ignore(),
DkgQueryMsg::GetRegisteredDealer {
dealer_address,
epoch_id,
} => client
.get_registered_dealer_details(&dealer_address.parse().unwrap(), epoch_id)
.ignore(),
DkgQueryMsg::GetDealerDetails { dealer_address } => client
.get_dealer_details(&dealer_address.parse().unwrap())
.ignore(),
DkgQueryMsg::GetCurrentDealers { limit, start_after } => client
.get_current_dealers_paged(start_after, limit)
.ignore(),
DkgQueryMsg::GetPastDealers { limit, start_after } => {
client.get_past_dealers_paged(start_after, limit).ignore()
DkgQueryMsg::GetDealerIndices { limit, start_after } => {
client.get_dealer_indices_paged(start_after, limit).ignore()
}
DkgQueryMsg::GetDealingStatus {
epoch_id,
dealer,
dealing_index,
} => client
.get_dealing_status(epoch_id, dealer, dealing_index)
.ignore(),
DkgQueryMsg::GetDealingsMetadata {
epoch_id,
dealer,
dealing_index,
} => client
.get_dealings_metadata(epoch_id, dealer, dealing_index)
.ignore(),
QueryMsg::GetDealerDealingsStatus { epoch_id, dealer } => {
client.get_dealer_dealings_status(epoch_id, dealer).ignore()
}
DkgQueryMsg::GetDealingChunkStatus {
epoch_id,
dealer,
dealing_index,
chunk_index,
} => client
.get_dealing_chunk_status(epoch_id, dealer, dealing_index, chunk_index)
.ignore(),
DkgQueryMsg::GetDealingChunk {
epoch_id,
dealer,
dealing_index,
chunk_index,
} => client
.get_dealing_chunk(epoch_id, dealer, dealing_index, chunk_index)
.ignore(),
DkgQueryMsg::GetVerificationKey { epoch_id, owner } => {
client.get_vk_share(epoch_id, owner).ignore()
}
DkgQueryMsg::GetDealing {
idx,
limit,
start_after,
} => client.get_dealings_paged(idx, start_after, limit).ignore(),
DkgQueryMsg::GetVerificationKeys {
epoch_id,
limit,
@@ -177,6 +314,7 @@ mod tests {
} => client
.get_vk_shares_paged(epoch_id, start_after, limit)
.ignore(),
DkgQueryMsg::GetCW2ContractVersion {} => client.get_contract_cw2_version().ignore(),
};
}
}
@@ -8,11 +8,11 @@ use crate::nyxd::{Coin, Fee, SigningCosmWasmClient};
use crate::signing::signer::OfflineSigner;
use async_trait::async_trait;
use cosmrs::AccountId;
use cosmwasm_std::Addr;
use nym_coconut_dkg_common::dealing::{DealingChunkInfo, PartialContractDealing};
use nym_coconut_dkg_common::msg::ExecuteMsg as DkgExecuteMsg;
use nym_coconut_dkg_common::types::EncodedBTEPublicKeyWithProof;
use nym_coconut_dkg_common::types::{DealingIndex, EncodedBTEPublicKeyWithProof};
use nym_coconut_dkg_common::verification_key::VerificationKeyShare;
use nym_contracts_common::dealings::ContractSafeBytes;
use nym_contracts_common::IdentityKey;
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
@@ -25,6 +25,13 @@ pub trait DkgSigningClient {
funds: Vec<Coin>,
) -> Result<ExecuteResult, NyxdError>;
async fn initiate_dkg(&self, fee: Option<Fee>) -> Result<ExecuteResult, NyxdError> {
let req = DkgExecuteMsg::InitiateDkg {};
self.execute_dkg_contract(fee, req, "initiating the DKG".to_string(), vec![])
.await
}
async fn advance_dkg_epoch_state(&self, fee: Option<Fee>) -> Result<ExecuteResult, NyxdError> {
let req = DkgExecuteMsg::AdvanceEpochState {};
@@ -32,22 +39,17 @@ pub trait DkgSigningClient {
.await
}
async fn surpass_threshold(&self, fee: Option<Fee>) -> Result<ExecuteResult, NyxdError> {
let req = DkgExecuteMsg::SurpassedThreshold {};
self.execute_dkg_contract(fee, req, "surpass DKG threshold".to_string(), vec![])
.await
}
async fn register_dealer(
&self,
bte_key: EncodedBTEPublicKeyWithProof,
identity_key: IdentityKey,
announce_address: String,
resharing: bool,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
let req = DkgExecuteMsg::RegisterDealer {
bte_key_with_proof: bte_key,
identity_key,
announce_address,
resharing,
};
@@ -56,18 +58,31 @@ pub trait DkgSigningClient {
.await
}
async fn submit_dealing_bytes(
async fn submit_dealing_metadata(
&self,
dealing_bytes: ContractSafeBytes,
dealing_index: DealingIndex,
chunks: Vec<DealingChunkInfo>,
resharing: bool,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
let req = DkgExecuteMsg::CommitDealing {
dealing_bytes,
let req = DkgExecuteMsg::CommitDealingsMetadata {
dealing_index,
chunks,
resharing,
};
self.execute_dkg_contract(fee, req, "dealing commitment".to_string(), vec![])
self.execute_dkg_contract(fee, req, "dealing metadata commitment".to_string(), vec![])
.await
}
async fn submit_dealing_chunk(
&self,
chunk: PartialContractDealing,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
let req = DkgExecuteMsg::CommitDealingsChunk { chunk };
self.execute_dkg_contract(fee, req, "dealing chunk commitment".to_string(), vec![])
.await
}
@@ -94,9 +109,10 @@ pub trait DkgSigningClient {
resharing: bool,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
// the call to unchecked is fine as we're converting from pre-validated `AccountId`
let owner = Addr::unchecked(owner.to_string());
let req = DkgExecuteMsg::VerifyVerificationKeyShare { owner, resharing };
let req = DkgExecuteMsg::VerifyVerificationKeyShare {
owner: owner.to_string(),
resharing,
};
self.execute_dkg_contract(
fee,
@@ -106,6 +122,20 @@ pub trait DkgSigningClient {
)
.await
}
async fn trigger_dkg_reset(&self, fee: Option<Fee>) -> Result<ExecuteResult, NyxdError> {
let req = DkgExecuteMsg::TriggerReset {};
self.execute_dkg_contract(fee, req, "trigger DKG reset".to_string(), vec![])
.await
}
async fn trigger_dkg_resharing(&self, fee: Option<Fee>) -> Result<ExecuteResult, NyxdError> {
let req = DkgExecuteMsg::TriggerResharing {};
self.execute_dkg_contract(fee, req, "trigger DKG resharing".to_string(), vec![])
.await
}
}
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
@@ -146,31 +176,40 @@ mod tests {
msg: DkgExecuteMsg,
) {
match msg {
DkgExecuteMsg::InitiateDkg {} => client.initiate_dkg(None).ignore(),
DkgExecuteMsg::RegisterDealer {
bte_key_with_proof,
identity_key,
announce_address,
resharing,
} => client
.register_dealer(bte_key_with_proof, announce_address, resharing, None)
.ignore(),
DkgExecuteMsg::CommitDealing {
dealing_bytes,
resharing,
} => client
.submit_dealing_bytes(dealing_bytes, resharing, None)
.ignore(),
DkgExecuteMsg::CommitVerificationKeyShare { share, resharing } => client
.submit_verification_key_share(share, resharing, None)
.ignore(),
DkgExecuteMsg::VerifyVerificationKeyShare { owner, resharing } => client
.verify_verification_key_share(
&owner.into_string().parse().unwrap(),
.register_dealer(
bte_key_with_proof,
identity_key,
announce_address,
resharing,
None,
)
.ignore(),
DkgExecuteMsg::SurpassedThreshold {} => client.surpass_threshold(None).ignore(),
DkgExecuteMsg::CommitDealingsMetadata {
dealing_index,
chunks,
resharing,
} => client
.submit_dealing_metadata(dealing_index, chunks, resharing, None)
.ignore(),
DkgExecuteMsg::CommitDealingsChunk { chunk } => {
client.submit_dealing_chunk(chunk, None).ignore()
}
DkgExecuteMsg::CommitVerificationKeyShare { share, resharing } => client
.submit_verification_key_share(share, resharing, None)
.ignore(),
DkgExecuteMsg::VerifyVerificationKeyShare { owner, resharing } => client
.verify_verification_key_share(&owner.parse().unwrap(), resharing, None)
.ignore(),
DkgExecuteMsg::AdvanceEpochState {} => client.advance_dkg_epoch_state(None).ignore(),
DkgExecuteMsg::TriggerReset {} => client.trigger_dkg_reset(None).ignore(),
DkgExecuteMsg::TriggerResharing {} => client.trigger_dkg_resharing(None).ignore(),
};
}
}
@@ -8,26 +8,26 @@ use std::str::FromStr;
// TODO: all of those could/should be derived via a macro
// query clients
mod coconut_bandwidth_query_client;
mod dkg_query_client;
mod ephemera_query_client;
mod group_query_client;
mod mixnet_query_client;
mod multisig_query_client;
mod name_service_query_client;
mod sp_directory_query_client;
mod vesting_query_client;
pub mod coconut_bandwidth_query_client;
pub mod dkg_query_client;
pub mod ephemera_query_client;
pub mod group_query_client;
pub mod mixnet_query_client;
pub mod multisig_query_client;
pub mod name_service_query_client;
pub mod sp_directory_query_client;
pub mod vesting_query_client;
// signing clients
mod coconut_bandwidth_signing_client;
mod dkg_signing_client;
mod ephemera_signing_client;
mod group_signing_client;
mod mixnet_signing_client;
mod multisig_signing_client;
mod name_service_signing_client;
mod sp_directory_signing_client;
mod vesting_signing_client;
pub mod coconut_bandwidth_signing_client;
pub mod dkg_signing_client;
pub mod ephemera_signing_client;
pub mod group_signing_client;
pub mod mixnet_signing_client;
pub mod multisig_signing_client;
pub mod name_service_signing_client;
pub mod sp_directory_signing_client;
pub mod vesting_signing_client;
// re-export query traits
pub use coconut_bandwidth_query_client::{
@@ -52,10 +52,6 @@ use wasmtimer::tokio::sleep;
pub const DEFAULT_BROADCAST_POLLING_RATE: Duration = Duration::from_secs(4);
pub const DEFAULT_BROADCAST_TIMEOUT: Duration = Duration::from_secs(60);
#[cfg(feature = "http-client")]
#[async_trait]
impl CosmWasmClient for cosmrs::rpc::HttpClient {}
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
pub trait CosmWasmClient: TendermintRpcClient {
@@ -522,3 +518,7 @@ pub trait CosmWasmClient: TendermintRpcClient {
res.try_into()
}
}
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
impl<T> CosmWasmClient for T where T: TendermintRpcClient {}
@@ -425,7 +425,7 @@ where
amount: amount.into_iter().map(Into::into).collect(),
}
.to_any()
.map_err(|_| NyxdError::SerializationError("MsgExecuteContract".to_owned()))
.map_err(|_| NyxdError::SerializationError("MsgSend".to_owned()))
})
.collect::<Result<_, _>>()?;
@@ -1,7 +1,7 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::nyxd::cosmwasm_client::client_traits::{CosmWasmClient, SigningCosmWasmClient};
use crate::nyxd::cosmwasm_client::client_traits::SigningCosmWasmClient;
use crate::nyxd::error::NyxdError;
use crate::nyxd::{Config, GasPrice, Hash, Height};
use crate::rpc::TendermintRpcClient;
@@ -26,6 +26,7 @@ use cosmrs::rpc::{HttpClient, HttpClientUrl};
pub mod client_traits;
mod helpers;
pub mod logs;
pub mod module_traits;
pub mod types;
#[derive(Debug)]
@@ -329,14 +330,6 @@ where
}
}
#[async_trait]
impl<C, S> CosmWasmClient for MaybeSigningClient<C, S>
where
C: TendermintRpcClient + Send + Sync,
S: Send + Sync,
{
}
#[async_trait]
impl<C, S> SigningCosmWasmClient for MaybeSigningClient<C, S>
where
@@ -0,0 +1,8 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
pub mod slashing;
pub mod staking;
pub use staking::query::StakingQueryClient;
// pub use slashing::query
@@ -0,0 +1,4 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
pub mod query;
@@ -0,0 +1,2 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
@@ -0,0 +1,8 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
pub mod query;
pub use cosmrs::staking::{
QueryHistoricalInfoResponse, QueryValidatorResponse, QueryValidatorsResponse, Validator,
};
@@ -0,0 +1,78 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use super::{QueryHistoricalInfoResponse, QueryValidatorResponse, QueryValidatorsResponse};
use crate::nyxd::error::NyxdError;
use crate::nyxd::{CosmWasmClient, PageRequest};
use async_trait::async_trait;
use cosmrs::proto::cosmos::staking::v1beta1::{
QueryHistoricalInfoRequest as ProtoQueryHistoricalInfoRequest,
QueryHistoricalInfoResponse as ProtoQueryHistoricalInfoResponse,
QueryValidatorRequest as ProtoQueryValidatorRequest,
QueryValidatorResponse as ProtoQueryValidatorResponse,
QueryValidatorsRequest as ProtoQueryValidatorsRequest,
QueryValidatorsResponse as ProtoQueryValidatorsResponse,
};
use cosmrs::staking::{QueryHistoricalInfoRequest, QueryValidatorRequest, QueryValidatorsRequest};
use cosmrs::AccountId;
// TODO: change trait restriction from `CosmWasmClient` to `TendermintRpcClient`
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
pub trait StakingQueryClient: CosmWasmClient {
async fn historical_info(&self, height: i64) -> Result<QueryHistoricalInfoResponse, NyxdError> {
let path = Some("/cosmos.staking.v1beta1.Query/HistoricalInfo".to_owned());
let req = QueryHistoricalInfoRequest { height };
let res = self
.make_abci_query::<ProtoQueryHistoricalInfoRequest, ProtoQueryHistoricalInfoResponse>(
path,
req.into(),
)
.await?;
Ok(res.try_into()?)
}
async fn validator(
&self,
validator_addr: AccountId,
) -> Result<QueryValidatorResponse, NyxdError> {
let path = Some("/cosmos.staking.v1beta1.Query/Validator".to_owned());
let req = QueryValidatorRequest { validator_addr };
let res = self
.make_abci_query::<ProtoQueryValidatorRequest, ProtoQueryValidatorResponse>(
path,
req.into(),
)
.await?;
Ok(res.try_into()?)
}
async fn validators(
&self,
status: String,
pagination: Option<PageRequest>,
) -> Result<QueryValidatorsResponse, NyxdError> {
let path = Some("/cosmos.staking.v1beta1.Query/Validators".to_owned());
let req = QueryValidatorsRequest { status, pagination };
let res = self
.make_abci_query::<ProtoQueryValidatorsRequest, ProtoQueryValidatorsResponse>(
path,
req.into(),
)
.await?;
Ok(res.try_into()?)
}
}
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
impl<T> StakingQueryClient for T where T: CosmWasmClient {}
@@ -140,9 +140,6 @@ pub enum NyxdError {
#[error("Cosmwasm std error: {0}")]
CosmwasmStdError(#[from] cosmwasm_std::StdError),
#[error("Coconut interface error: {0}")]
CoconutInterfaceError(#[from] nym_coconut_interface::error::CoconutInterfaceError),
#[error("Account had an unexpected bech32 prefix. Expected: {expected}, got: {got}")]
UnexpectedBech32Prefix { got: String, expected: String },
}
@@ -16,7 +16,6 @@ use crate::signing::tx_signer::TxSigner;
use crate::signing::AccountData;
use crate::{DirectSigningReqwestRpcNyxdClient, QueryReqwestRpcNyxdClient, ReqwestRpcClient};
use async_trait::async_trait;
use cosmrs::cosmwasm;
use cosmrs::tendermint::{abci, evidence::Evidence, Genesis};
use cosmrs::tx::{Raw, SignDoc};
use cosmwasm_std::Addr;
@@ -29,23 +28,30 @@ use tendermint_rpc::endpoint::*;
use tendermint_rpc::{Error as TendermintRpcError, Order};
use url::Url;
pub use crate::nyxd::cosmwasm_client::client_traits::{CosmWasmClient, SigningCosmWasmClient};
pub use crate::nyxd::fee::Fee;
pub use crate::nyxd::{
cosmwasm_client::{
client_traits::{CosmWasmClient, SigningCosmWasmClient},
module_traits::{self, StakingQueryClient},
},
fee::Fee,
};
pub use crate::rpc::TendermintRpcClient;
pub use coin::Coin;
pub use cosmrs::bank::MsgSend;
pub use cosmrs::tendermint::abci::{
response::DeliverTx, types::ExecTxResult, Event, EventAttribute,
pub use cosmrs::{
bank::MsgSend,
bip32, cosmwasm,
crypto::PublicKey,
query::{PageRequest, PageResponse},
tendermint::{
abci::{response::DeliverTx, types::ExecTxResult, Event, EventAttribute},
block::Height,
hash::{self, Algorithm, Hash},
validator::Info as TendermintValidatorInfo,
Time as TendermintTime,
},
tx::{self, Msg},
AccountId, Any, Coin as CosmosCoin, Denom, Gas,
};
pub use cosmrs::tendermint::block::Height;
pub use cosmrs::tendermint::hash::{self, Algorithm, Hash};
pub use cosmrs::tendermint::validator::Info as TendermintValidatorInfo;
pub use cosmrs::tendermint::Time as TendermintTime;
pub use cosmrs::tx::Msg;
pub use cosmrs::tx::{self};
pub use cosmrs::Coin as CosmosCoin;
pub use cosmrs::Gas;
pub use cosmrs::{bip32, AccountId, Denom};
pub use cosmwasm_std::Coin as CosmWasmCoin;
pub use cw2;
pub use cw3;
@@ -55,9 +61,8 @@ pub use fee::{gas_price::GasPrice, GasAdjustable, GasAdjustment};
pub use tendermint_rpc::{
endpoint::{tx::Response as TxResponse, validators::Response as ValidatorResponse},
query::Query,
Paging,
Paging, Request, Response, SimpleRequest,
};
pub use tendermint_rpc::{Request, Response, SimpleRequest};
#[cfg(feature = "http-client")]
use crate::http_client;
@@ -97,6 +102,14 @@ impl Config {
}
}
impl TryFrom<NymNetworkDetails> for Config {
type Error = NyxdError;
fn try_from(value: NymNetworkDetails) -> Result<Self, Self::Error> {
Config::try_from_nym_network_details(&value)
}
}
#[derive(Debug)]
pub struct NyxdClient<C, S = NoSigner> {
client: MaybeSigningClient<C, S>,
@@ -345,6 +358,10 @@ where
S: OfflineSigner + Send + Sync,
NyxdError: From<<S as OfflineSigner>::Error>,
{
pub fn signing_account(&self) -> Result<AccountData, NyxdError> {
Ok(self.find_account(&self.address())?)
}
pub fn address(&self) -> AccountId {
match self.client.signer_addresses() {
Ok(addresses) => addresses[0].clone(),
@@ -728,7 +745,7 @@ where
where
H: Into<Height> + Send,
{
self.client.validators(height, paging).await
TendermintRpcClient::validators(&self.client, height, paging).await
}
async fn latest_consensus_params(
@@ -803,14 +820,6 @@ where
}
}
#[async_trait]
impl<C, S> CosmWasmClient for NyxdClient<C, S>
where
C: TendermintRpcClient + Send + Sync,
S: Send + Sync,
{
}
impl<C, S> OfflineSigner for NyxdClient<C, S>
where
S: OfflineSigner,
-14
View File
@@ -1,14 +0,0 @@
[package]
name = "nym-coconut-interface"
version = "0.1.0"
edition = "2021"
description = "Crutch library until there is proper SerDe support for coconut structs"
license.workspace = true
[dependencies]
bs58 = "0.4.0"
getset = "0.1.1"
serde = { workspace = true, features = ["derive"] }
thiserror = { workspace = true }
nym-coconut = {path = "../nymcoconut" }
-17
View File
@@ -1,17 +0,0 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use nym_coconut::CoconutError;
use thiserror::Error;
#[derive(Debug, Error)]
pub enum CoconutInterfaceError {
#[error("not enough bytes: {0} received, minimum {1} required")]
InvalidByteLength(usize, usize),
#[error("Could not decode base 58 string - {0}")]
MalformedString(#[from] bs58::decode::Error),
#[error("Coconut error - {0}")]
CoconutError(#[from] CoconutError),
}
-196
View File
@@ -1,196 +0,0 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
pub mod error;
use getset::{CopyGetters, Getters};
use serde::{Deserialize, Serialize};
use error::CoconutInterfaceError;
// We list these explicity instead of glob export due to shadowing warnings with the pub tests
// module.
pub use nym_coconut::{
aggregate_signature_shares, aggregate_verification_keys, blind_sign, hash_to_scalar,
prepare_blind_sign, prove_bandwidth_credential, Attribute, Base58, BlindSignRequest,
BlindedSignature, Bytable, CoconutError, KeyPair, Parameters, PrivateAttribute,
PublicAttribute, Signature, SignatureShare, Theta, VerificationKey,
};
#[derive(Debug, Serialize, Deserialize, Getters, CopyGetters, Clone, PartialEq, Eq)]
pub struct Credential {
#[getset(get = "pub")]
n_params: u32,
#[getset(get = "pub")]
theta: Theta,
voucher_value: u64,
voucher_info: String,
#[getset(get = "pub")]
epoch_id: u64,
}
impl Credential {
pub fn new(
n_params: u32,
theta: Theta,
voucher_value: u64,
voucher_info: String,
epoch_id: u64,
) -> Credential {
Credential {
n_params,
theta,
voucher_value,
voucher_info,
epoch_id,
}
}
pub fn blinded_serial_number(&self) -> String {
self.theta.blinded_serial_number_bs58()
}
pub fn has_blinded_serial_number(
&self,
blinded_serial_number_bs58: &str,
) -> Result<bool, CoconutInterfaceError> {
Ok(self
.theta
.has_blinded_serial_number(blinded_serial_number_bs58)?)
}
pub fn voucher_value(&self) -> u64 {
self.voucher_value
}
pub fn verify(&self, verification_key: &VerificationKey) -> bool {
let params = Parameters::new(self.n_params).unwrap();
let hashed_value = hash_to_scalar(self.voucher_value.to_string());
let hashed_info = hash_to_scalar(&self.voucher_info);
let public_attributes = &[&hashed_value, &hashed_info];
nym_coconut::verify_credential(&params, verification_key, &self.theta, public_attributes)
}
pub fn as_bytes(&self) -> Vec<u8> {
let n_params_bytes = self.n_params.to_be_bytes();
let theta_bytes = self.theta.to_bytes();
let theta_bytes_len = theta_bytes.len();
let voucher_value_bytes = self.voucher_value.to_be_bytes();
let epoch_id_bytes = self.epoch_id.to_be_bytes();
let voucher_info_bytes = self.voucher_info.as_bytes();
let voucher_info_len = voucher_info_bytes.len();
let mut bytes = Vec::with_capacity(28 + theta_bytes_len + voucher_info_len);
bytes.extend_from_slice(&n_params_bytes);
bytes.extend_from_slice(&(theta_bytes_len as u64).to_be_bytes());
bytes.extend_from_slice(&theta_bytes);
bytes.extend_from_slice(&voucher_value_bytes);
bytes.extend_from_slice(&epoch_id_bytes);
bytes.extend_from_slice(voucher_info_bytes);
bytes
}
pub fn from_bytes(bytes: &[u8]) -> Result<Self, CoconutError> {
if bytes.len() < 28 {
return Err(CoconutError::Deserialization(String::from(
"To few bytes in credential",
)));
}
let mut four_byte = [0u8; 4];
let mut eight_byte = [0u8; 8];
four_byte.copy_from_slice(&bytes[..4]);
let n_params = u32::from_be_bytes(four_byte);
eight_byte.copy_from_slice(&bytes[4..12]);
let theta_len = u64::from_be_bytes(eight_byte);
if bytes.len() < 28 + theta_len as usize {
return Err(CoconutError::Deserialization(String::from(
"To few bytes in credential",
)));
}
let theta = Theta::from_bytes(&bytes[12..12 + theta_len as usize])
.map_err(|e| CoconutError::Deserialization(e.to_string()))?;
eight_byte.copy_from_slice(&bytes[12 + theta_len as usize..20 + theta_len as usize]);
let voucher_value = u64::from_be_bytes(eight_byte);
eight_byte.copy_from_slice(&bytes[20 + theta_len as usize..28 + theta_len as usize]);
let epoch_id = u64::from_be_bytes(eight_byte);
let voucher_info = String::from_utf8(bytes[28 + theta_len as usize..].to_vec())
.map_err(|e| CoconutError::Deserialization(e.to_string()))?;
Ok(Credential {
n_params,
theta,
voucher_value,
voucher_info,
epoch_id,
})
}
}
impl Bytable for Credential {
fn to_byte_vec(&self) -> Vec<u8> {
self.as_bytes()
}
fn try_from_byte_slice(slice: &[u8]) -> Result<Self, CoconutError> {
Credential::from_bytes(slice)
}
}
impl Base58 for Credential {}
#[cfg(test)]
mod tests {
use nym_coconut::{prove_bandwidth_credential, Signature};
use super::*;
#[test]
fn serde_coconut_credential() {
let voucher_value = 1000000u64;
let voucher_info = String::from("BandwidthVoucher");
let serial_number =
Attribute::try_from_bs58("7Rp3imcuNX3w9se9wm5th8gSvc2czsnMrGsdt5HsrycA").unwrap();
let binding_number =
Attribute::try_from_bs58("Auf8yVEgyEAWNHaXUZmimS4n9g5YiYnNYqp6F9BtBe9E").unwrap();
let signature = Signature::try_from_bs58(
"ta3pM9ffj5T6YGbwjSBp2W118rcwyP9PXStc\
7ssb91g5GQYMQHhuTNajbdZcjxUFBFL5rhED8EHpRzE8r432ss3qbPBfpNev4CdkfMkQ3wepyM7hy7q1W6Rn9WmFoZL\
ZR9j",
)
.unwrap();
let params = Parameters::new(4).unwrap();
let verification_key = VerificationKey::try_from_bs58("8CFtVVXdwLy4WHMQPE4\
woe89q3DRHoNxBSchftrEjSBPWA4r4xZv4Y9qSvS5x5bMmFtp7BX6ikECAnuXr5EjXWSsgjirZJmpS5XDUynVfht1cD\
FWGDvy2XFrRCuoCMotNXi3PoF6wYqdTR9Rqcfoj3i2H5Nid422WBaLtVoC9QNobvpvaqq6vX5PbsSyPayvU8HCXFxM6\
JjScYpbRTxQtdwefWLrk3LmXyJQBWi7c2VAhSxu9msp7VTBycqdwQNgxHETStZuwXsozxaGQ2KssVUCaaoYPR4g2RqK\
UAvtWwA7pMiAQNcbkXcbsjCgVjWaCpMWC37XA31cLcFf3zbjHD9e5tXjAcqa4M89fbFhuvvSXxowSAZ5NoWrN32kd5d\
wxJm1JW3Tt2h6yDDBe84oMy71462dZn7N78DVk2mFNGwBCibrZWA7oUzRBMfYxiQrksoFcou7QfLLd58zoNYmPQPt84\
1VpQopEBfdQ7Nf9zoXxBt3zMy7g5NsFGvzh7KTbDUyeeXrdkKJPQBs6dqaizr9sS8CPPmR4uk96vDTRh8CJ5FbSsmb8\
nP71dRvvwRZJHGzwYirMo6SXS3ZYxFuiA3mkxYuqDHCwkTWDuRCcAaztrDYRZg7VCMo4Q446AaEso5eqpeWpHZQt53E\
ZRpqmNYKASGwMhTeEHPSLgSmtoAAUcaRWpGRzYfd6kzEma8tdGLwyP4rLXgvSvtDLP37dU7YgF3LEXbGAz57U9ATy46\
6sroLpHPdaCWB8RF11wvB6Tu196JnJd2KyQBP1iUWP3rtZs3GhAF1QVcxquh8BqDZzAcpQ6wCS1P9c5GxKgww77FVF5\
Kp83XtoxSrw3GaYVyKTGxNh3vcKPR31txCjTxPaN2fg7TaPLhoQJX4YaAroFSXqrqbbRsisuHhhCeUP2YwDjHedes9y")
.unwrap();
let theta = prove_bandwidth_credential(
&params,
&verification_key,
&signature,
&serial_number,
&binding_number,
)
.unwrap();
let credential = Credential::new(4, theta, voucher_value, voucher_info, 42);
let serialized_credential = credential.as_bytes();
let deserialized_credential = Credential::from_bytes(&serialized_credential).unwrap();
assert_eq!(credential, deserialized_credential);
}
}
+8 -1
View File
@@ -9,13 +9,16 @@ license.workspace = true
anyhow = { workspace = true }
base64 = "0.13.0"
bip39 = { workspace = true }
bs58 = "0.4"
bs58 = { workspace = true }
comfy-table = "6.0.0"
cfg-if = "1.0.0"
clap = { workspace = true, features = ["derive"] }
csv = "1.3.0"
cw-utils = { workspace = true }
futures = { workspace = true }
handlebars = "3.0.1"
humantime-serde = "1.0"
inquire = "0.6.2"
k256 = { workspace = true, features = ["ecdsa", "sha256"] }
log = { workspace = true }
rand = {version = "0.6", features = ["std"] }
@@ -23,9 +26,11 @@ serde = { version = "1.0", features = ["derive"] }
serde_json = { workspace = true }
thiserror = { workspace = true }
time = { workspace = true, features = ["parsing", "formatting"] }
tokio = { workspace = true, features = ["sync"]}
toml = "0.5.6"
url = { workspace = true }
tap = "1"
zeroize = { workspace = true }
cosmrs = { workspace = true }
cosmwasm-std = { workspace = true }
@@ -47,8 +52,10 @@ nym-sphinx = { path = "../../common/nymsphinx" }
nym-client-core = { path = "../../common/client-core" }
nym-config = { path = "../../common/config" }
nym-credentials = { path = "../../common/credentials" }
nym-credentials-interface = { path = "../../common/credentials-interface" }
nym-credential-storage = { path = "../../common/credential-storage" }
nym-credential-utils = { path = "../../common/credential-utils" }
nym-id = { path = "../nym-id" }
nym-pemstore = { path = "../../common/pemstore", version = "0.3.0" }
nym-types = { path = "../../common/types" }
@@ -0,0 +1,4 @@
n1q85lscptz860j3dx92f8phaeaw08j2l5dt7adq,50,nym
n136ckky0n39eskewg04xhvahq9yp9f7sgtnxytt,50,unym
n1xh7ru0zp67czxhvx0r5e8ur7rvg6n3ymmje0ju,50,nyx
n13mpm4aj03alffnvz2x9ynjy4u3cxemxn2xw34w,50,unyx
1 n1q85lscptz860j3dx92f8phaeaw08j2l5dt7adq 50 nym
2 n136ckky0n39eskewg04xhvahq9yp9f7sgtnxytt 50 unym
3 n1xh7ru0zp67czxhvx0r5e8ur7rvg6n3ymmje0ju 50 nyx
4 n13mpm4aj03alffnvz2x9ynjy4u3cxemxn2xw34w 50 unyx
@@ -0,0 +1,190 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::context::SigningClient;
use anyhow::{anyhow, bail};
use clap::ArgGroup;
use clap::Parser;
use futures::StreamExt;
use log::{error, info};
use nym_coconut_dkg_common::types::EpochId;
use nym_credential_utils::utils::block_until_coconut_is_available;
use nym_credentials::coconut::bandwidth::freepass::MAX_FREE_PASS_VALIDITY;
use nym_credentials::{
obtain_aggregate_verification_key, IssuanceBandwidthCredential, IssuedBandwidthCredential,
};
use nym_credentials_interface::VerificationKey;
use nym_validator_client::coconut::all_coconut_api_clients;
use nym_validator_client::nyxd::contract_traits::{DkgQueryClient, NymContractsProvider};
use nym_validator_client::nyxd::CosmWasmClient;
use nym_validator_client::signing::AccountData;
use nym_validator_client::CoconutApiClient;
use std::fs::File;
use std::io::Write;
use std::path::PathBuf;
use std::sync::Arc;
use time::format_description::well_known::Rfc3339;
use time::OffsetDateTime;
use zeroize::Zeroizing;
fn parse_rfc3339_expiration_date(raw: &str) -> Result<OffsetDateTime, time::error::Parse> {
OffsetDateTime::parse(raw, &Rfc3339)
}
#[derive(Debug, Parser)]
#[clap(group(ArgGroup::new("expiration").required(true)))]
pub struct Args {
/// Specifies the expiration date of the free pass(es)
/// Can't be set to more than a week into the future.
#[clap(long, group = "expiration", value_parser = parse_rfc3339_expiration_date)]
pub(crate) expiration_date: Option<OffsetDateTime>,
/// The expiration of the free pass(es) expresses as unix timestamp.
/// Can't be set to more than a week into the future.
#[clap(long, group = "expiration")]
pub(crate) expiration_timestamp: Option<i64>,
/// The number of free passes to issue
#[clap(long, default_value = "1")]
pub(crate) amount: u64,
/// Path to the output directory for generated free passes.
#[clap(long)]
pub(crate) output_dir: PathBuf,
}
async fn get_freepass(
api_clients: Vec<CoconutApiClient>,
aggregate_vk: &VerificationKey,
threshold: u64,
epoch_id: EpochId,
signing_account: &AccountData,
expiration_date: OffsetDateTime,
) -> anyhow::Result<IssuedBandwidthCredential> {
let issuance_pass = IssuanceBandwidthCredential::new_freepass(Some(expiration_date));
let signing_data = issuance_pass.prepare_for_signing();
let credential_shares = Arc::new(tokio::sync::Mutex::new(Vec::new()));
futures::stream::iter(api_clients)
.for_each_concurrent(None, |client| async {
// move the client into the block
let client = client;
let api_url = client.api_client.api_url();
info!("contacting {api_url} for blinded free pass");
match issuance_pass
.obtain_partial_freepass_credential(
&client.api_client,
signing_account,
&client.verification_key,
signing_data.clone(),
)
.await
{
Ok(partial_credential) => {
credential_shares
.lock()
.await
.push((partial_credential, client.node_id).into());
}
Err(err) => {
error!("failed to obtain partial free pass from {api_url}: {err}")
}
}
})
.await;
// SAFETY: the futures have completed, so we MUST have the only arc reference
#[allow(clippy::unwrap_used)]
let credential_shares = Arc::into_inner(credential_shares).unwrap().into_inner();
if credential_shares.len() < threshold as usize {
bail!("we managed to obtain only {} partial credentials while the minimum threshold is {threshold}", credential_shares.len());
}
let signature = issuance_pass.aggregate_signature_shares(aggregate_vk, &credential_shares)?;
Ok(issuance_pass.into_issued_credential(signature, epoch_id))
}
pub async fn execute(args: Args, client: SigningClient) -> anyhow::Result<()> {
let address = client.address();
if !args.output_dir.is_dir() {
bail!("the provided output directory is not a directory!");
}
if args.output_dir.read_dir()?.next().is_some() {
bail!("the provided output directory is not empty!");
}
let Some(bandwidth_contract) = client.coconut_bandwidth_contract_address() else {
bail!("the bandwidth contract address is not set")
};
let Some(bandwidth_admin) = client
.get_contract(bandwidth_contract)
.await
.map(|c| c.contract_info.admin)?
else {
bail!("the bandwidth contract doesn't have any admin set")
};
// sanity checks since nym-apis will reject invalid requests anyway
if address != bandwidth_admin {
bail!("the provided mnemonic does not correspond to the current admin of the bandwidth contract")
}
let expiration_date = match args.expiration_date {
Some(date) => date,
// SAFETY: one of those arguments must have been set
None => OffsetDateTime::from_unix_timestamp(args.expiration_timestamp.unwrap())?,
};
let now = OffsetDateTime::now_utc();
if expiration_date > now + MAX_FREE_PASS_VALIDITY {
bail!("the provided free pass request has too long expiry (expiry is set to on {expiration_date})")
}
// issuance start
block_until_coconut_is_available(&client).await?;
let signing_account = client.signing_account()?;
let epoch_id = client.get_current_epoch().await?.epoch_id;
let threshold = client
.get_current_epoch_threshold()
.await?
.ok_or(anyhow!("no threshold available"))?;
let api_clients = all_coconut_api_clients(&client, epoch_id).await?;
if api_clients.len() < threshold as usize {
bail!(
"we have only {} api clients available while the minimum threshold is {threshold}",
api_clients.len()
)
}
let aggregate_vk = obtain_aggregate_verification_key(&api_clients)?;
for i in 0..args.amount {
let human_index = i + 1;
info!("trying to obtain free pass {human_index}/{}", args.amount);
let free_pass = get_freepass(
api_clients.clone(),
&aggregate_vk,
threshold,
epoch_id,
&signing_account,
expiration_date,
)
.await?;
let credential_data = Zeroizing::new(free_pass.pack_v1());
let output = args.output_dir.join(format!("freepass_{i}.nym"));
info!("saving the freepass to '{}'", output.display());
File::create(output)?.write_all(&credential_data)?;
}
Ok(())
}
@@ -0,0 +1,64 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::utils::CommonConfigsWrapper;
use anyhow::bail;
use clap::ArgGroup;
use clap::Parser;
use nym_credential_storage::initialise_persistent_storage;
use nym_id::import_credential;
use std::fs;
use std::path::PathBuf;
fn parse_encoded_credential_data(raw: &str) -> bs58::decode::Result<Vec<u8>> {
bs58::decode(raw).into_vec()
}
#[derive(Debug, Parser)]
#[clap(group(ArgGroup::new("cred_data").required(true)))]
pub struct Args {
/// Config file of the client that is supposed to use the credential.
#[clap(long)]
pub(crate) client_config: PathBuf,
/// Explicitly provide the encoded credential data (as base58)
#[clap(long, group = "cred_data", value_parser = parse_encoded_credential_data)]
pub(crate) credential_data: Option<Vec<u8>>,
/// Specifies the path to file containing binary credential data
#[clap(long, group = "cred_data")]
pub(crate) credential_path: Option<PathBuf>,
// currently hidden as there exists only a single serialization standard
#[clap(long, hide = true)]
pub(crate) version: Option<u8>,
}
pub async fn execute(args: Args) -> anyhow::Result<()> {
let loaded = CommonConfigsWrapper::try_load(args.client_config)?;
if let Ok(id) = loaded.try_get_id() {
println!("loaded config file for client '{id}'");
}
let Ok(credentials_store) = loaded.try_get_credentials_store() else {
bail!("the loaded config does not have a credentials store information")
};
println!(
"using credentials store at '{}'",
credentials_store.display()
);
let credentials_store = initialise_persistent_storage(credentials_store).await;
let raw_credential = match args.credential_data {
Some(data) => data,
None => {
// SAFETY: one of those arguments must have been set
fs::read(args.credential_path.unwrap())?
}
};
import_credential(credentials_store, raw_credential, args.version).await?;
Ok(())
}
+4
View File
@@ -3,6 +3,8 @@
use clap::{Args, Subcommand};
pub mod generate_freepass;
pub mod import_credential;
pub mod issue_credentials;
pub mod recover_credentials;
@@ -15,6 +17,8 @@ pub struct Coconut {
#[derive(Debug, Subcommand)]
pub enum CoconutCommands {
GenerateFreepass(generate_freepass::Args),
IssueCredentials(issue_credentials::Args),
RecoverCredentials(recover_credentials::Args),
ImportCredential(import_credential::Args),
}
+4 -1
View File
@@ -1,4 +1,4 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use clap::{Args, Subcommand};
@@ -7,6 +7,7 @@ pub mod balance;
pub mod create;
pub mod pubkey;
pub mod send;
pub mod send_multiple;
#[derive(Debug, Args)]
#[clap(args_conflicts_with_subcommands = true, subcommand_required = true)]
@@ -25,4 +26,6 @@ pub enum AccountCommands {
PubKey(crate::validator::account::pubkey::Args),
/// Sends tokens to another account
Send(crate::validator::account::send::Args),
/// Batch multiple token sends
SendMultiple(crate::validator::account::send_multiple::Args),
}
@@ -0,0 +1,216 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::context::SigningClient;
use crate::utils::pretty_coin;
use clap::Parser;
use comfy_table::Table;
use cosmrs::rpc::endpoint::tx::Response;
use log::{error, info};
use nym_validator_client::nyxd::{AccountId, Coin};
use serde_json::json;
use std::str::FromStr;
use std::{fs, io::Write};
#[derive(Debug, Parser)]
pub struct Args {
#[clap(long)]
pub memo: Option<String>,
#[clap(
long,
help = "Input file path (CSV format) with account/amount pairs to send"
)]
pub input: String,
#[clap(
long,
help = "An output file path (CSV format) to create or append a log of results to"
)]
pub output: Option<String>,
}
pub async fn send_multiple(args: Args, client: &SigningClient) {
let memo = args
.memo
.unwrap_or_else(|| "Sending tokens with nym-cli".to_owned());
let rows = InputFileReader::new(&args.input);
if let Err(e) = rows {
error!("Failed to read input file: {}", e);
return;
}
let rows = rows.unwrap();
let mut table = Table::new();
if rows.rows.is_empty() {
error!("No transactions to send");
return;
}
println!(
"The following transfer will be made from account {} to:",
client.address()
);
table.set_header(vec!["Address", "Amount"]);
for row in rows.rows.iter() {
table.add_row(vec![row.address.to_string(), pretty_coin(&row.amount)]);
}
println!("{table}");
let ans = inquire::Confirm::new("Do you want to continue with the transfers?")
.with_default(false)
.with_help_message("You must confirm before the transaction will be sent")
.prompt();
if let Err(e) = ans {
info!("Aborting, {}...", e);
return;
}
if let Ok(false) = ans {
info!("Aborting!");
return;
}
info!("Transferring from {}...", client.address());
let multiple_sends: Vec<(AccountId, Vec<Coin>)> = rows
.rows
.iter()
.map(|row| (row.address.clone(), vec![row.amount.clone()]))
.collect();
let res = client
.send_multiple(multiple_sends, memo, None)
.await
.expect("failed to send tokens!");
info!("Sending result: {}", json!(res));
println!();
println!(
"Nodesguru: https://nym.explorers.guru/transaction/{}",
&res.hash
);
println!("Mintscan: https://www.mintscan.io/nyx/txs/{}", &res.hash);
println!("Transaction result code: {}", &res.tx_result.code.value());
println!("Transaction hash: {}", &res.hash);
if let Some(output_filename) = args.output {
println!("\nWriting output log to {}", output_filename);
if let Err(e) = write_output_file(rows, res, &output_filename) {
error!(
"Failed to write output file {} with error {}",
output_filename, e
);
}
}
}
fn write_output_file(
rows: InputFileReader,
res: Response,
output_filename: &String,
) -> Result<(), anyhow::Error> {
let mut file = fs::OpenOptions::new()
.create(true)
.append(true)
.open(output_filename)?;
let now = time::OffsetDateTime::now_utc();
let now = now.format(&time::format_description::well_known::Rfc3339)?;
let data = rows
.rows
.iter()
.map(|row| {
format!(
"{},{},{},{},{}",
row.address, row.amount.amount, row.amount.denom, now, res.hash
)
})
.collect::<Vec<String>>()
.join("\n");
Ok(file.write_all(format!("{}\n", data).as_bytes())?)
}
#[derive(Debug)]
pub struct InputFileRow {
pub address: AccountId,
pub amount: Coin,
}
pub struct InputFileReader {
pub rows: Vec<InputFileRow>,
}
impl InputFileReader {
pub fn new(path: &str) -> Result<InputFileReader, anyhow::Error> {
let mut rows: Vec<InputFileRow> = vec![];
let file_contents = fs::read_to_string(path)?;
let lines: Vec<String> = file_contents.lines().map(String::from).collect();
for line in lines {
let tokens: Vec<_> = line.split(',').collect();
if tokens.len() < 3 {
return Err(anyhow::anyhow!(
"'{}' does not have enough columns, expecting <address>,<amount>,<denom>",
line
));
}
// try parse amount to u128
let amount = u128::from_str(tokens[1])
.map_err(|_| anyhow::anyhow!("'{}' has an invalid amount", line))?;
let denom: String = tokens[2].into();
// multiply when a whole token amount, e.g. 50nym (50.123456nym is not allowed, that must be input as 50123456unym)
let (amount, denom) = if !denom.starts_with('u') {
(amount * 1_000_000u128, format!("u{}", denom))
} else {
(amount, denom)
};
let address = AccountId::from_str(tokens[0])
.map_err(|e| anyhow::anyhow!("'{}' has an invalid address: {}", line, e))?;
let amount = Coin { amount, denom };
rows.push(InputFileRow { address, amount })
}
Ok(InputFileReader { rows })
}
}
#[cfg(test)]
mod test_multiple_send_input_csv {
use super::*;
use nym_validator_client::nyxd::AccountId;
use std::str::FromStr;
#[test]
fn works_on_happy_path() {
let input_csv = InputFileReader::new("fixtures/test_send_multiple.csv").unwrap();
assert_eq!(
AccountId::from_str("n1q85lscptz860j3dx92f8phaeaw08j2l5dt7adq").unwrap(),
input_csv.rows[0].address
);
println!("{:?}", input_csv.rows);
assert_eq!(50_000_000u128, input_csv.rows[0].amount.amount);
assert_eq!(50u128, input_csv.rows[1].amount.amount);
assert_eq!(50_000_000u128, input_csv.rows[2].amount.amount);
assert_eq!(50u128, input_csv.rows[3].amount.amount);
assert_eq!("unym", input_csv.rows[0].amount.denom);
assert_eq!("unym", input_csv.rows[1].amount.denom);
assert_eq!("unyx", input_csv.rows[2].amount.denom);
assert_eq!("unyx", input_csv.rows[3].amount.denom);
}
}
@@ -3,6 +3,7 @@
use clap::Parser;
use log::{debug, info};
use nym_coconut_dkg_common::dealing::DEFAULT_DEALINGS;
use std::str::FromStr;
use nym_coconut_dkg_common::msg::InstantiateMsg;
@@ -93,6 +94,7 @@ pub async fn generate(args: Args) {
multisig_addr: multisig_addr.to_string(),
time_configuration: Some(time_configuration),
mix_denom,
key_size: DEFAULT_DEALINGS as u32,
};
debug!("instantiate_msg: {:?}", instantiate_msg);
+1 -1
View File
@@ -73,7 +73,7 @@ where
P: AsRef<Path>,
{
let path = path.as_ref();
log::debug!("trying to save config file to {}", path.display());
log::info!("saving config file to {}", path.display());
if let Some(parent) = path.parent() {
create_dir_all(parent)?;
@@ -10,6 +10,8 @@ license.workspace = true
cosmwasm-schema = { workspace = true }
cosmwasm-std = { workspace = true }
cw-utils = { workspace = true }
cw2 = { workspace = true }
cw4 = { workspace = true }
contracts-common = { path = "../contracts-common", package = "nym-contracts-common" }
nym-multisig-contract-common = { path = "../multisig-contract" }
@@ -1,7 +1,7 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::types::{ContractSafeBytes, EncodedBTEPublicKeyWithProof, NodeIndex};
use crate::types::{EncodedBTEPublicKeyWithProof, NodeIndex};
use cosmwasm_schema::cw_serde;
use cosmwasm_std::Addr;
@@ -9,24 +9,37 @@ use cosmwasm_std::Addr;
pub struct DealerDetails {
pub address: Addr,
pub bte_public_key_with_proof: EncodedBTEPublicKeyWithProof,
pub ed25519_identity: String,
pub announce_address: String,
pub assigned_index: NodeIndex,
}
#[cw_serde]
pub struct DealerRegistrationDetails {
pub bte_public_key_with_proof: EncodedBTEPublicKeyWithProof,
pub ed25519_identity: String,
pub announce_address: String,
}
#[cw_serde]
#[derive(Copy)]
pub enum DealerType {
Current,
Past,
Current { assigned_index: NodeIndex },
Past { assigned_index: NodeIndex },
Unknown,
}
impl DealerType {
pub fn is_current(&self) -> bool {
matches!(&self, DealerType::Current)
matches!(&self, DealerType::Current { .. })
}
}
#[cw_serde]
pub struct RegisteredDealerDetails {
pub details: Option<DealerRegistrationDetails>,
}
#[cw_serde]
pub struct DealerDetailsResponse {
pub details: Option<DealerDetails>,
@@ -66,35 +79,17 @@ impl PagedDealerResponse {
}
#[cw_serde]
pub struct ContractDealing {
pub dealing: ContractSafeBytes,
pub dealer: Addr,
}
impl ContractDealing {
pub fn new(dealing: ContractSafeBytes, dealer: Addr) -> Self {
ContractDealing { dealing, dealer }
}
}
#[cw_serde]
pub struct PagedDealingsResponse {
pub dealings: Vec<ContractDealing>,
pub per_page: usize,
pub struct PagedDealerIndexResponse {
pub indices: Vec<(Addr, NodeIndex)>,
/// Field indicating paging information for the following queries if the caller wishes to get further entries.
pub start_next_after: Option<Addr>,
}
impl PagedDealingsResponse {
pub fn new(
dealings: Vec<ContractDealing>,
per_page: usize,
start_next_after: Option<Addr>,
) -> Self {
PagedDealingsResponse {
dealings,
per_page,
impl PagedDealerIndexResponse {
pub fn new(indices: Vec<(Addr, NodeIndex)>, start_next_after: Option<Addr>) -> Self {
PagedDealerIndexResponse {
indices,
start_next_after,
}
}
@@ -0,0 +1,290 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::types::{ChunkIndex, DealingIndex, EpochId, PartialContractDealingData};
use contracts_common::dealings::ContractSafeBytes;
use cosmwasm_schema::cw_serde;
use cosmwasm_std::Addr;
use std::collections::{BTreeMap, HashMap};
/// Defines the maximum size of a dealing chunk. Currently set to 2kB
pub const MAX_DEALING_CHUNK_SIZE: usize = 2048;
/// Defines the maximum size of a full dealing.
/// Currently set to 100kB (which is enough for a dealing created for 100 parties)
pub const MAX_DEALING_SIZE: usize = 102400;
pub const MAX_DEALING_CHUNKS: usize = MAX_DEALING_SIZE / MAX_DEALING_CHUNK_SIZE;
// 2 public attributes, 2 private attributes, 1 fixed for coconut credential
pub const DEFAULT_DEALINGS: usize = 2 + 2 + 1;
pub fn chunk_dealing(
dealing_index: DealingIndex,
dealing_bytes: Vec<u8>,
chunk_size: usize,
) -> HashMap<ChunkIndex, PartialContractDealing> {
let mut chunks = HashMap::new();
for (chunk_index, chunk) in dealing_bytes.chunks(chunk_size).enumerate() {
let chunk = PartialContractDealing {
dealing_index,
chunk_index: chunk_index as ChunkIndex,
data: ContractSafeBytes(chunk.to_vec()),
};
chunks.insert(chunk_index as ChunkIndex, chunk);
}
chunks
}
#[cw_serde]
#[derive(Copy)]
pub struct DealingChunkInfo {
pub size: u64,
}
impl DealingChunkInfo {
pub fn new(size: usize) -> Self {
DealingChunkInfo { size: size as u64 }
}
pub fn construct(dealing_len: usize, chunk_size: usize) -> Vec<Self> {
let (full_chunks, overflow) = (dealing_len / chunk_size, dealing_len % chunk_size);
let mut chunks = Vec::new();
for _ in 0..full_chunks {
chunks.push(DealingChunkInfo::new(chunk_size));
}
if overflow != 0 {
chunks.push(DealingChunkInfo::new(overflow));
}
chunks
}
}
#[cw_serde]
#[derive(Copy)]
pub struct SubmittedChunk {
pub info: DealingChunkInfo,
pub status: ChunkSubmissionStatus,
}
#[cw_serde]
#[derive(Default, Copy)]
pub struct ChunkSubmissionStatus {
// this field is updated by the contract itself to indicate when this particular chunk has been received
pub submission_height: Option<u64>,
}
impl ChunkSubmissionStatus {
pub fn submitted(&self) -> bool {
self.submission_height.is_some()
}
}
impl From<DealingChunkInfo> for SubmittedChunk {
fn from(value: DealingChunkInfo) -> Self {
SubmittedChunk::new(value)
}
}
impl SubmittedChunk {
pub fn new(info: DealingChunkInfo) -> Self {
SubmittedChunk {
info,
status: Default::default(),
}
}
pub fn submitted(&self) -> bool {
self.status.submitted()
}
}
#[cw_serde]
pub struct DealingMetadata {
pub dealing_index: DealingIndex,
pub submitted_chunks: BTreeMap<ChunkIndex, SubmittedChunk>,
}
impl DealingMetadata {
pub fn new(dealing_index: DealingIndex, chunks: Vec<DealingChunkInfo>) -> Self {
DealingMetadata {
dealing_index,
submitted_chunks: chunks
.into_iter()
.enumerate()
.map(|(id, chunk)| (id as ChunkIndex, chunk.into()))
.collect(),
}
}
pub fn is_complete(&self) -> bool {
self.submitted_chunks.values().all(|c| c.submitted())
}
pub fn total_size(&self) -> usize {
self.submitted_chunks
.values()
.map(|c| c.info.size as usize)
.sum()
}
pub fn submission_statuses(&self) -> BTreeMap<ChunkIndex, ChunkSubmissionStatus> {
self.submitted_chunks
.iter()
.map(|(id, c)| (*id, c.status))
.collect()
}
}
#[cw_serde]
pub struct PartialContractDealing {
pub dealing_index: DealingIndex,
pub chunk_index: ChunkIndex,
pub data: PartialContractDealingData,
}
impl PartialContractDealing {
pub fn new(
dealing_index: DealingIndex,
chunk_index: ChunkIndex,
data: PartialContractDealingData,
) -> Self {
PartialContractDealing {
dealing_index,
chunk_index,
data,
}
}
}
#[cw_serde]
pub struct DealingMetadataResponse {
pub epoch_id: EpochId,
pub dealer: Addr,
pub dealing_index: DealingIndex,
pub metadata: Option<DealingMetadata>,
}
#[cw_serde]
pub struct DealingChunkResponse {
pub epoch_id: EpochId,
pub dealer: Addr,
pub dealing_index: DealingIndex,
pub chunk_index: ChunkIndex,
pub chunk: Option<PartialContractDealingData>,
}
#[cw_serde]
pub struct DealingChunkStatusResponse {
pub epoch_id: EpochId,
pub dealer: Addr,
pub dealing_index: DealingIndex,
pub chunk_index: ChunkIndex,
pub status: ChunkSubmissionStatus,
}
#[cw_serde]
pub struct DealingStatusResponse {
pub epoch_id: EpochId,
pub dealer: Addr,
pub dealing_index: DealingIndex,
pub status: DealingStatus,
}
#[cw_serde]
pub struct DealingStatus {
pub has_metadata: bool,
pub fully_submitted: bool,
pub chunk_submission_status: BTreeMap<ChunkIndex, ChunkSubmissionStatus>,
}
impl From<Option<DealingMetadata>> for DealingStatus {
fn from(metadata: Option<DealingMetadata>) -> Self {
DealingStatus {
has_metadata: metadata.is_some(),
fully_submitted: metadata
.as_ref()
.map(|m| m.is_complete())
.unwrap_or_default(),
chunk_submission_status: metadata
.map(|m| m.submission_statuses())
.unwrap_or_default(),
}
}
}
#[cw_serde]
pub struct DealerDealingsStatusResponse {
pub epoch_id: EpochId,
pub dealer: Addr,
pub all_dealings_fully_submitted: bool,
pub dealing_submission_status: BTreeMap<DealingIndex, DealingStatus>,
}
impl DealerDealingsStatusResponse {
pub fn full_dealings(&self) -> usize {
self.dealing_submission_status
.values()
.filter(|s| s.fully_submitted)
.count()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn chunking_dealings() {
const CHUNK_SIZE: usize = 512;
let test_cases = [
(CHUNK_SIZE - 10, CHUNK_SIZE, 1),
(CHUNK_SIZE, CHUNK_SIZE, 1),
(CHUNK_SIZE + 10, CHUNK_SIZE, 2),
(CHUNK_SIZE * 2, CHUNK_SIZE, 2),
(CHUNK_SIZE * 2 + 1, CHUNK_SIZE, 3),
(CHUNK_SIZE * 10 + 42, CHUNK_SIZE, 11),
];
for (dealing_len, chunk_size, expected_chunks) in test_cases {
let chunks = DealingChunkInfo::construct(dealing_len, chunk_size);
assert_eq!(expected_chunks, chunks.len());
assert_eq!(
dealing_len as u64,
chunks.iter().map(|c| c.size).sum::<u64>()
);
let mut expected_last = dealing_len % chunk_size;
if expected_last == 0 {
expected_last = chunk_size;
}
assert_eq!(chunks.last().unwrap().size, expected_last as u64);
}
}
}
@@ -1,4 +1,8 @@
// Copyright 2022-2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
pub mod dealer;
pub mod dealing;
pub mod event_attributes;
pub mod msg;
pub mod types;

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