Compare commits

..

291 Commits

Author SHA1 Message Date
Tommy Verrall 3a80b9bf59 update branch for latest changes 2023-04-25 12:53:45 +02:00
Raphaël Walther 3f7f4b82de Move workflows to custom runner 2023-04-25 11:10:12 +02:00
farbanas 934ba2b027 Merge branch 'master' into develop 2023-04-25 10:53:43 +02:00
Jędrzej Stuczyński eda223ed3d Resolved beta clippy complaints (#3351) 2023-04-25 09:53:11 +01:00
farbanas c98d4305fa update cargo locks 2023-04-25 10:09:49 +02:00
farbanas 2eecbca6eb bump versions and update changelogs for release v1.1.16 2023-04-25 10:06:03 +02:00
farbanas a58c80ef08 update versions of mixnet and vesting contract crates 2023-04-25 10:06:03 +02:00
farbanas ac9d0db8be update versions of mixnet and vesting contract crates 2023-04-25 10:06:03 +02:00
farbanas 7521d98963 update versions of mixnet and vesting contract common crates 2023-04-25 10:06:03 +02:00
mx 1e98131090 Merge pull request #3349 from nymtech/feature/general-docs-updates
version bump for next release
2023-04-25 07:39:10 +00:00
mx 46bf65462c Merge pull request #3325 from esomore/mixnode/description
update mix-node setup docs with node description
2023-04-25 07:38:22 +00:00
mx e3df4c2d68 reintroduce minimum rust version variable 2023-04-24 17:13:03 +02:00
mx 45c013350f version bump for next release 2023-04-24 17:10:41 +02:00
mx 6fecc53975 Merge pull request #3339 from nymtech/feature/coconut-rust-sdk-docs
added coconut credential generation example
2023-04-24 14:49:24 +00:00
Tommy Verrall e4dbfb1904 Merge pull request #3222 from nymtech/feature/available_reader_changes
Feature/available reader changes
2023-04-24 15:48:08 +01:00
Tommy Verrall f822d3db7b cargo fmt 2023-04-24 15:29:51 +01:00
Jędrzej Stuczyński 9d23766288 updated used packet size 2023-04-24 15:29:51 +01:00
Jędrzej Stuczyński fd4930b198 removed old leftover log statement 2023-04-24 15:29:51 +01:00
Jędrzej Stuczyński 5d7be89edb replaced inner implementation with tokio's 'ReaderStream' 2023-04-24 15:29:51 +01:00
Jędrzej Stuczyński 47f5b4ceac limit the maximum buffer size of AvailableReader by PacketSize of our mix packets 2023-04-24 15:29:51 +01:00
Jędrzej Stuczyński 790220039b added read deadline to AvailableReader 2023-04-24 15:29:51 +01:00
Tommy Verrall 16fdfa4583 Update mainnet.env 2023-04-24 13:54:54 +02:00
Jędrzej Stuczyński cbbeb66b5b Feature/wasm client topology injection (#3311)
* added cargo config file to explicitly specify build target

* wip

* Config option to disable topology refreshing

* extracted common parsing code

* helper trait for working on wasm topology

* wasm topology parsing

* restored (slightly modified) old js-example

* wip

* Moved message preparation into a trait

* wip

* long-winded way of sending test packet

* standalone NymNodeTester

* finishing the test upon receiving all packets even if timeout wasnt reached

* initial round of cleanup

* sending multiple test packets in normal NymClient

* javascript-side cleanup

* starting mixnode test on btn click

* Improved NymNodeTester constructors

* improved error handling and constructors

* tester utils error handling

* further cleanup + using BTreeMap for NymTopology mixnodes

* handling missed errors

* splitting up 'test_node'

* split up and cleaned up generation of test result

* clippy + fixed example

* post rebase fixes

* another broken test

* prevent running multiple parallel tests

* cargo fmt

* Added nym- prefix to node tester utils
2023-04-24 09:56:26 +01:00
Jon Häggblad 3f0d4846df Fix a few clippy warnings in contract test code (#3340)
* ci: don't fail fast for contracts

* contracts: fix clippy in tests
2023-04-24 10:30:22 +02:00
mx de020f46a6 added coconut credential generation example 2023-04-21 16:32:20 +02:00
Jon Häggblad 9bfcdbe8e2 Add --all-targets to clippy for contracts (#3337) 2023-04-21 11:47:43 +02:00
Tommy Verrall 8c4885ce2c Merge pull request #3294 from nymtech/feature/fix-clippy-warnings
A branch with all clippy warnings dealt with in contracts
2023-04-21 10:37:33 +01:00
Jędrzej Stuczyński f24bb5c038 reduced noise in CODEOWNERS (#3313)
* reduced noise in CODEOWNERS

* Add @octol to codeowners

* added @mfahampshire as owner of /documentation

---------

Co-authored-by: Jon Häggblad <jon.haggblad@gmail.com>
2023-04-20 15:25:23 +01:00
Jon Häggblad 79dfe7eeda Add clippy target in top-level Makefile 2023-04-20 14:13:20 +02:00
Jon Häggblad 0108c6ed19 Merge remote-tracking branch 'origin/release/v1.1.16' into develop 2023-04-20 09:55:19 +02:00
Tommy Verrall 926389df89 Merge pull request #3300 from nymtech/bugfix/empty-ack-stream-map
make sure to clear inner 'ack_map' in 'GatewaysReader'
2023-04-20 08:31:31 +01:00
Tommy Verrall b55db00408 Merge pull request #3324 from nymtech/bugfix/nym-cli-gateway-commands
exposed missing gateway commands in nym-cli
2023-04-20 07:55:56 +01:00
Jędrzej Stuczyński cfcb64f7e5 Feature/reduce pledge (#3254)
* basic contract work for 'decrease_pledge' functionality

note: it doesn't yet return tokens back to the operator

* returning extra tokens after decreasing pledge

* added vesting message to track pledge decrease

* attaching the track message when processing delegation decrease

* checking for zero value request

* fixed event test

* allowing to decrease pledge from the vesting contract

* integration test for the feature

* reorganised the integration tests

* updated nyxd client traits

* wallet support

* typescript helpers

* moved 'pledge more' functionality to operator commands

* cli commands for decreasing pledge

* changed error variant to make clippy happier

* removed unused import

* eslint

* fixed post-rebase imports

* added cargo config

* added PendingMixNodeChanges to MixNodeDetails

* returning event id after creating it

* Streamlined getting mixnode details by identity key

* setting pending pledge changes on increase/decrease

* clearing the value on resolving the event

* checking for correct invariants when clearing events

* further pending events unit tests fixes

* new unit tests for tx endpoints

* queries for pending events (by id)

* migration code

* using default value for pending changes if unavailable

* improved integration test assertions
2023-04-20 07:52:10 +01:00
Itamar Perez 0e8f60d501 update mix-node setup docs with node description 2023-04-19 12:01:36 -07:00
Jon Häggblad 9c6c5f5170 Add --all-targets to nym-wallet CI clippy (#3326) 2023-04-19 10:44:46 +02:00
Jon Häggblad f28888e3e7 Update Cargo.lock files after bumping internal versions during 1.1.15 release 2023-04-19 09:41:03 +02:00
Jon Häggblad 6e30e6178b Update Cargo.lock files after bumping internal versions during release 2023-04-19 09:37:38 +02:00
Jędrzej Stuczyński 9549bed8bb exposed missing gateway commands in nym-cli 2023-04-18 16:28:13 +01:00
Tommy Verrall 7c65d61d91 Merge pull request #3321 from nymtech/bug/explorer-fix-stake-saturation-sorting
Convert stake saturation string to number type
2023-04-18 13:57:07 +01:00
farbanas ad2efb7e62 Merge branch 'master' into develop 2023-04-18 14:35:56 +02:00
Drazen Urch a50c9bfa1a Outfox compatibility layer (#3317)
* Outfox compatibility layer

* Lint
2023-04-18 14:07:34 +02:00
mx 30cdbf535a added polkachu snapshot links 2023-04-18 13:26:02 +02:00
mx f5365cbca9 reintroduced laddr change to config setup instructions 2023-04-18 13:11:13 +02:00
mx 22e7cb887b final tweaks 2023-04-18 13:08:21 +02:00
fmtabbara b571f1a881 convert stake saturation string to number type 2023-04-18 11:32:35 +01:00
mx b1c4e3ded7 hotfix on sandbox testnet naming 2023-04-18 12:30:44 +02:00
mx 4694ded8bd updated platform release version variable 2023-04-18 12:17:47 +02:00
mx 7971573026 hotfix on sandbox testnet naming 2023-04-18 12:16:49 +02:00
Jon Häggblad c4780c8af2 Rework Poisson process throttling to more aggressively up-regulate (#3298)
* Rework Poisson process throttling

* Tweak parameters
2023-04-18 12:07:54 +02:00
farbanas 246f0b3f52 fix: nym-wallet CHANGELOG version 2023-04-18 11:43:10 +02:00
Jon Häggblad 7879d76592 Reduce logging of warnings associated with Poisson process throttling (#3314)
* Reduce logging of warnings associated with Poisson process throttling

* More granularity when logging about slow gateway

* Refine logging of elevated delay multiplier

* clippy

* Tweak output when printing address

* rustfmt

* Fix initial delay
2023-04-18 11:40:50 +02:00
Bogdan-Ștefan Neacşu 0f62ea25d8 Fix nym-cli clap requirement (#3303) 2023-04-18 12:31:42 +03:00
mx 6dbe8205d6 updated version var in book.toml 2023-04-18 11:14:29 +02:00
mx 1b94ad5c4c Merge pull request #3291 from nymtech/feature/add-docs-to-monorepo
Feature/add docs to monorepo
2023-04-18 09:03:41 +00:00
mx 37be99ab8f Merge branch 'release/v1.1.15' into feature/add-docs-to-monorepo 2023-04-18 09:02:59 +00:00
farbanas 6f5cee8c36 chore: updated changelogs, revert change to nym-connect version as there were no changes 2023-04-18 10:54:57 +02:00
farbanas 58d805ab72 chore: update contract versions in preparation for release v1.1.15 2023-04-18 10:27:43 +02:00
farbanas 68ad75f737 chore: update contract versions in preparation for release v1.1.15 2023-04-18 10:25:52 +02:00
farbanas 73ea2b5fec chore: update versions in preparation for release v1.1.15 2023-04-18 10:15:24 +02:00
pierre a0b37daeb0 build: fix clippy ci 2023-04-18 09:48:28 +02:00
Pierre Dommerc c9972047f6 feat(wallet): app version check (#3308) (#3319)
* feat(wallet): app version check (#3308)

* wrap tauri calls to check version into try/catch
2023-04-17 18:19:23 +02:00
mx ccdf698380 added docs and devportal import to changelog 2023-04-17 17:23:19 +02:00
Raphaël Walther c10ed5a2f3 Enable dependabot on github actions 2023-04-17 17:23:19 +02:00
Raphaël Walther 600b6d2b03 Move workflow broken link check 2023-04-17 17:23:19 +02:00
Raphaël Walther b1391bbb17 Move workflow broken link check 2023-04-17 17:23:19 +02:00
Raphaël Walther a171103a80 Move workflow broken link check 2023-04-17 17:23:19 +02:00
mx 3e2009aa9d small tweaks 2023-04-17 17:23:19 +02:00
mx 4b6e942667 small tweak to make generic 2023-04-17 17:23:19 +02:00
mx a6723044b9 removed accidental hyperlink 2023-04-17 17:23:19 +02:00
mx f60a25ee2d * added sandbox makefile env
* updated sandbox persistent peer address
2023-04-17 17:23:19 +02:00
Raphaël Walther 770baefe35 Add workflow for dev-portal deployment 2023-04-17 17:23:19 +02:00
Raphaël Walther 1c3403d7e6 Add workflow for dev-portal deployment 2023-04-17 17:23:19 +02:00
Raphaël Walther 342fd869a2 Add workflow for dev-portal deployment 2023-04-17 17:23:19 +02:00
Raphaël Walther 6f7db4172f Add workflow for dev-portal deployment 2023-04-17 17:23:19 +02:00
Raphaël Walther 55fd7b8890 Add workflow for dev-portal deployment 2023-04-17 17:23:19 +02:00
Raphaël Walther a14b4dc80c Add workflow for dev-portal deployment 2023-04-17 17:23:19 +02:00
Raoul c81f6962d7 fix a minor issue in mkdir/touch paths 2023-04-17 17:23:19 +02:00
Raphaël Walther 9f4ef6842b Add workflow for docs deployment 2023-04-17 17:23:19 +02:00
Raphaël Walther 7ca0c06c87 Add workflow for docs deployment 2023-04-17 17:23:19 +02:00
Raphaël Walther 57aa763a84 Add workflow for docs deployment 2023-04-17 17:23:19 +02:00
Raphaël Walther ba5fecf6b3 Add workflow for docs deployment 2023-04-17 17:23:19 +02:00
Raphaël Walther 35343509f9 Add workflow for docs deployment 2023-04-17 17:23:19 +02:00
Raphaël Walther 42d8b06346 Add workflow for docs deployment 2023-04-17 17:23:19 +02:00
Raphaël Walther f30f0e8316 Add workflow for docs deployment 2023-04-17 17:23:19 +02:00
Raphaël Walther e1aaf509d1 Add workflow for docs deployment 2023-04-17 17:23:19 +02:00
Raphaël Walther 8db5eadea6 Add workflow for docs deployment 2023-04-17 17:23:19 +02:00
Raphaël Walther 4dda824d37 Add workflow for docs deployment 2023-04-17 17:23:19 +02:00
mx 0579b3afb0 Update validator-setup.md 2023-04-17 17:23:19 +02:00
mx d328c458e6 updated readmes 2023-04-17 17:23:19 +02:00
mx c8651cddbb removed comment on NR 2023-04-17 17:23:19 +02:00
mx cde2a1ab26 tried to get run autocommands to work. 2023-04-17 17:23:19 +02:00
mx 8d78c92c03 format tweaking validator 2023-04-17 17:23:19 +02:00
mx af311c3d33 checked over devportal 2023-04-17 17:23:19 +02:00
mx 906bcf1634 added websocket client cmdrun automation 2023-04-17 17:23:19 +02:00
mx 843bd4f4fa some final cmdrun cleanup 2023-04-17 17:23:19 +02:00
mx 9bbe4a96d0 temp commit 2023-04-17 17:23:19 +02:00
mx 974ac0691c pushed dev-portal theme to remote for rebase to autodeploy working branch 2023-04-17 17:23:19 +02:00
mx 1188e48313 pushed theme to remote for rebase to autodeploy working branch 2023-04-17 17:23:19 +02:00
mx e7ed5f3de3 changed default theme build behaviour in book.toml for autodeploy 2023-04-17 17:23:19 +02:00
mx d45b2de241 pulled in missed out upgrade path info 2023-04-17 17:23:19 +02:00
mx 3d9cbf351f * started adding cmdrun command inputs instead of hardcoded command
outputs
2023-04-17 17:23:19 +02:00
mx 844e22d94d precommit before trying to import autocommands 2023-04-17 17:23:18 +02:00
mx 09c905910e added link to mdbook docs 2023-04-17 17:23:18 +02:00
mx 8fd8bf8792 * deleted old ama layout css
* edited gitignore files
2023-04-17 17:23:18 +02:00
mx 243658637c * changed manual devrel ama links to playlist embed
* removed 'coming soon' from intro links
2023-04-17 17:23:18 +02:00
mx 5603a79d49 cleanup validator docs: makefile instructions + general tweak 2023-04-17 17:23:18 +02:00
mx 0007a4cc74 * updated software prerequisites
* added arch based prereq instructions to validator nodes
2023-04-17 17:23:18 +02:00
mx 3dafe02f0e first commit of moving docs and dev portal to monorepo 2023-04-17 17:23:18 +02:00
Pierre Dommerc e62e9cde02 feat(wallet): add security settings (#3262) 2023-04-17 16:38:17 +02:00
Pierre Dommerc cde53c02e7 feat(wallet): add security settings (#3262) 2023-04-17 16:36:39 +02:00
Pierre Dommerc de64da8e20 feat(wallet): app version check (#3308) 2023-04-17 15:12:26 +02:00
Jon Häggblad 683790b068 Merge remote-tracking branch 'origin/master' into release/v1.1.15 2023-04-17 15:05:03 +02:00
Tommy Verrall f9c24c8a23 Merge pull request #3318 from nymtech/fix/wallet-bonding-signature
Wallet - fix bonding signature issue with vesting acc
2023-04-17 13:06:19 +01:00
pierre 886bb95e18 fix bonding signature issue 2023-04-17 13:30:25 +02:00
Jon Häggblad 214fd0caf5 Fix issue where nr run failed on fresh init (#3316) 2023-04-17 12:25:20 +02:00
Jędrzej Stuczyński 4aeac1acd2 Revert "another broken test"
This reverts commit 679be24074.
2023-04-14 16:56:26 +01:00
Jędrzej Stuczyński 679be24074 another broken test 2023-04-14 16:52:24 +01:00
Nadim Kobeissi 36e07f546d Merge pull request #3304 from nymtech/nadimkobeissi-fix-readme
Update README.md
2023-04-14 11:19:30 +02:00
Nadim Kobeissi d264feaf22 Update README.md
The link for build instructions was incorrect.
2023-04-14 11:19:11 +02:00
Dave Hrycyszyn 32b7b7afdc Update SECURITY.md 2023-04-13 12:23:01 +01:00
Jędrzej Stuczyński 7a50f0c3b2 make sure to clear inner 'ack_map' in 'GatewaysReader' 2023-04-13 10:51:03 +01:00
durch 237597da90 Remove dependency 2023-04-12 14:33:01 +02:00
durch 8000100735 Log to $HOME/.nym/logs 2023-04-12 13:53:43 +02:00
Jon Häggblad 091382ef30 Tidy the service provider directory contract (#3295)
Tidy the service provider directory contract after implementing query
methods on the validator-client.

- split out response types and use consistently
- query msg use "By" prefix
- pass address as String and validator
2023-04-12 09:22:35 +02:00
durch 68b8993e84 Merge branch 'feature/cpu-mixnode-build' of https://github.com/nymtech/nym into feature/cpu-mixnode-build 2023-04-12 09:21:58 +02:00
durch 3a897ed08e Log if measurement is ON or OFF 2023-04-12 09:21:51 +02:00
Tommy Verrall 18a24fc10d update cpu-cycles 2023-04-12 09:20:30 +02:00
Tommy Verrall dfcf812243 change the binary build 2023-04-12 09:19:11 +02:00
Dave Hrycyszyn 2da6a2fbfa Adding a clippy.toml so we can see correct warnings in mixnet contract 2023-04-11 14:57:04 +01:00
Dave Hrycyszyn d910a4e0ee The make test target seems to be wrapping differently than local 2023-04-11 14:53:51 +01:00
Dave Hrycyszyn 672ab79421 A branch with all clippy warnings dealt with in contracts 2023-04-11 14:46:45 +01:00
Bogdan-Ștefan Neacşu 1ad97adc7c Feature/sdk coconut (#3273)
* Replace expect with error

* Move PersistentStorage in separate file

* Add in-memory cred manager

* Make wasm and mobile build

* Unify wasm and mobile cred storage

* Network defaults has mainnet default

* Add network_details to SDK

* Move BandwidthController in its own crate

* Move out credential into lib crate

* Remove nyxd arg in credential binary

* Use acquire cred in sdk

* Add example file, in sandbox

* Mobile lock file

* Update changelog

* Clearer builder methods and more documentation for them

* Sign only amount, without denom

* Toggle credentials mode on when enabled
2023-04-11 16:17:35 +03:00
benedettadavico 2bd585a0ff Empty commit 2023-04-11 12:55:59 +02:00
Jon Häggblad df0b0367a4 Rename service provider owner to announcer (#3290) 2023-04-11 10:39:03 +02:00
Jon Häggblad bb9e26d745 Add build-release command to Makefile and tidy (#3288) 2023-04-11 08:03:30 +02:00
Jon Häggblad dc5c765ecb Last set of crates to add the nym- prefix to (#3286)
* Add nym- prefix to mixnode-common

* Add nym- prefix to mixnet-client

* Add nym-client- prefix to websocket-requests

* Makefile: add check target

* Rename to nym-credential-client

* rustfmt

* update to nym-credential-client in github workflow
2023-04-07 21:25:28 +02:00
Jon Häggblad 95e2e3d0d2 Comment out unused code that breaks clippy (#3287) 2023-04-06 23:05:47 +02:00
Jon Häggblad 690c4164a7 Cargo.lock 2023-04-06 15:15:24 +02:00
Jon Häggblad ee656aa3ef clippy: allow unused generic parameter 2023-04-06 12:47:19 +02:00
Tommy Verrall 3d4123aca5 Merge pull request #3217 from nymtech/feature/dual_packet_sizes 2023-04-06 11:09:28 +01:00
Jędrzej Stuczyński 29a8e23f72 added additional logs 2023-04-06 10:52:45 +01:00
Jędrzej Stuczyński a4c5407b04 removed redundant disconnect in simple.rs 2023-04-06 10:52:45 +01:00
Jędrzej Stuczyński 75bc36a9e6 post-rebase wasm fixes 2023-04-06 10:52:45 +01:00
Jędrzej Stuczyński b8e2fb46fb added config validation to network requester 2023-04-06 10:52:45 +01:00
Jędrzej Stuczyński eff931f9ca fixed network monitor 2023-04-06 10:52:45 +01:00
Jędrzej Stuczyński e4d8d721c0 adjusted message handler to allow for dual packet sizes 2023-04-06 10:52:45 +01:00
Jędrzej Stuczyński 21335b5ff1 ibid for the cover traffic stream 2023-04-06 10:52:45 +01:00
Jędrzej Stuczyński dadfdacf14 weighted decision on cover traffic packet size ('real traffic stream') 2023-04-06 10:52:45 +01:00
Jędrzej Stuczyński e3eeef4301 removed old deprecated 'extended_packet_size' 2023-04-06 10:52:45 +01:00
Jędrzej Stuczyński 6a519f4a1a message handler choosing packet size based on serialized size 2023-04-06 10:52:45 +01:00
Jędrzej Stuczyński fde8bd89b6 Ord and PartialOrd for PacketSize 2023-04-06 10:52:45 +01:00
Jędrzej Stuczyński 099013bc6d propagating packet size information to message preparer 2023-04-06 10:52:45 +01:00
Jędrzej Stuczyński 11eef024ea simplified real_messages_control config 2023-04-06 10:52:45 +01:00
Jędrzej Stuczyński cc6017db3b added packet size configuration to client config files 2023-04-06 10:52:42 +01:00
Tommy Verrall bdc91bb324 build only the mixnode binary with cpu-cycles 2023-04-06 10:08:38 +02:00
Jon Häggblad 84c1679973 Add more nym- crate prefixes (#3284)
* Add nym- prefix to nymcoconut

* Add nym- prefix to validator-client

* Add nym- prefix to gateway-requests

* Add nym- prefix to mobile-storage

* Add nym- prefix to gateway-client

* Add nym- prefix to client-core

* rustfmt
2023-04-06 09:04:49 +02:00
Jon Häggblad b1d18a5974 Makefile: invert NYM_NO_MOBILE flag (#3280) 2023-04-05 17:55:23 +02:00
Jon Häggblad 5019b4b266 Fix comments in nym-sdk builder_with_storage example (#3283) 2023-04-05 14:30:58 +02:00
Drazen Urch 790e7a0e1e Sphinx packet processing CPU cycles measurement (#3247)
* POC measurement

* parent ce76790761
author durch <durch@users.noreply.github.com> 1680116778 +0200
committer durch <durch@users.noreply.github.com> 1680683399 +0200

Instrument packet processing

* Cleanup and format

* Feature gate tracing

* Add .gitkeep to wallet dist

* Squashed commit of the following:

commit 0b1b6947e8
Author: Jon Häggblad <jon.haggblad@gmail.com>
Date:   Wed Apr 5 11:28:28 2023 +0200

    Replace mobile flag with target_os = android (#3278)

    * Remove old lock file

    * Start replacing mobile with android

    * Regex replace all mobile with android

    * Remove the mobile feature flag

    * keep the cfg mobile in tauri

commit c79b2cfb78
Author: Jon Häggblad <jon.haggblad@gmail.com>
Date:   Wed Apr 5 11:27:38 2023 +0200

    Service provider directory contract (#3220)

    * first commit of service provider directory contract proof of concept

    * *added config set on instantiation,
    *removed greetQuery test function

    * commit before mapping change

    * *changed mapping of service to use client address instead of cosmos addr

    * commit before mapping change

    * added acl to delete()

    * added test for acl in delete()

    * changed whitelist<vec> to standrd_whitelist bool in Service struct

    * removed old comments and commented out code

    * rustfmt

    * wup

    * wup

    * Older version of cw-multi-test that works with 1.0.0

    * wip

    * Remove .gitignore

    * Basic tests for announce and query now works

    * Restore tests for delete as well

    * Consolidate tests

    * Tidy

    * fmt

    * Start reworking test helpers

    * Tidy tests

    * More test work

    * More test improvements

    * More work on tests

    * Tweaks

    * Further tests

    * rustfmt

    * Add some comments

    * Initial work on requiring deposit

    * wip

    * Work on updating tests for handling funds

    * Start updating integration tests

    * Integration tests updated

    * merge test mods in state

    * Address review comments

    * Enable wasm-opt

    * Unify Result type

    * consistent amount in error type

    * WIP: paging output

    * IndexedMap working

    * extract to config file

    * WIP: middle of extracting out types

    * Extract types

    * wip

    * Types now extracted out:

    * Paged response type too

    * rustfmt

    * Start working on switching to cw Admin

    * Complete switch to Admin

    * Remove owner from announce msg

    * remove unused imports

    * Assert owner

    * Extract out types to common crate

    * Fix test compilation

    * Add query by owner and nym address

    * Move msg to common crate

    * rustfmt

    * tests for service id

    * service storage tests

    * state services tests

    * function rename

    * tidy

    * Fix clippy warning

    * User ServiceId instead and not u32

    * Delete by nym address

    * Emit explicit events

    * Swap ToString for Display

    * Move all storage keys to constants.rs

    * clippy

    * Test for deleting by name

    * Tidy integration tests

    * Remove to_string

    * Some comments to tests

    * Integration test for paging

    * serde snake_csae for NymAddress and ServiceType

    * Add migrate entry point

    * Add query contract version

    * A few more asserts for balance

    * Make MigrateMsg a struct

    ---------

    Co-authored-by: mx <maxhampshire@pm.me>

commit dd699bce9a
Merge: 5ce017ef3 e6957e7a9
Author: Tommy Verrall <60836166+tommyv1987@users.noreply.github.com>
Date:   Wed Apr 5 10:18:16 2023 +0100

    Merge pull request #3235 from nymtech/feature/performance-active-set-selection

    Feature/performance active set selection

commit 5ce017ef3d
Author: benedetta davico <46782255+benedettadavico@users.noreply.github.com>
Date:   Wed Apr 5 10:57:45 2023 +0200

    adding vesting tests (#3279)

commit 59c1ce2639
Merge: 4fb63d889 276edfd56
Author: Tommy Verrall <60836166+tommyv1987@users.noreply.github.com>
Date:   Wed Apr 5 09:50:53 2023 +0100

    Merge pull request #3261 from nymtech/feature/refresh-allow-list

    Feature/refresh allow list

commit 4fb63d8892
Author: Jędrzej Stuczyński <jedrzej.stuczynski@gmail.com>
Date:   Wed Apr 5 09:22:43 2023 +0100

    Feature/vesting delegation amount query (#3229)

    * moved queries and transactions out of contract.rs

    * added queries for vesting delegation details

    * nyxd_client support

commit 276edfd562
Author: Jędrzej Stuczyński <jedrzej.stuczynski@gmail.com>
Date:   Fri Mar 31 15:56:21 2023 +0100

    clippy

commit 605f8fcde3
Author: Jędrzej Stuczyński <jedrzej.stuczynski@gmail.com>
Date:   Fri Mar 31 15:06:12 2023 +0100

    updated and cleaned up tests

commit f0e4d1a7cf
Author: Jędrzej Stuczyński <jedrzej.stuczynski@gmail.com>
Date:   Fri Mar 31 14:01:36 2023 +0100

    configurable stored lists locations

commit 055ec4bdd5
Author: Jędrzej Stuczyński <jedrzej.stuczynski@gmail.com>
Date:   Fri Mar 31 12:57:02 2023 +0100

    updating stored allow list on file changes

commit 5761f9ac7f
Author: Jędrzej Stuczyński <jedrzej.stuczynski@gmail.com>
Date:   Fri Mar 31 12:15:45 2023 +0100

    file watcher

commit 32620fd55f
Author: Jędrzej Stuczyński <jedrzej.stuczynski@gmail.com>
Date:   Thu Mar 30 17:47:12 2023 +0100

    updating standard list in a timer

commit abb5cdbe06
Author: Jędrzej Stuczyński <jedrzej.stuczynski@gmail.com>
Date:   Thu Mar 30 16:43:58 2023 +0100

    extracted domain and ipnet information to separate struct

commit e6957e7a99
Author: Jędrzej Stuczyński <jedrzej.stuczynski@gmail.com>
Date:   Tue Mar 28 11:25:43 2023 +0100

    use combination of stake and performance for rewarded set selection

commit de2406a2c7
Author: Jędrzej Stuczyński <jedrzej.stuczynski@gmail.com>
Date:   Tue Mar 28 10:54:14 2023 +0100

    Moved MixnodeWithPerformance to helpers

* Squashed commit of the following:

commit 0b1b6947e8
Author: Jon Häggblad <jon.haggblad@gmail.com>
Date:   Wed Apr 5 11:28:28 2023 +0200

    Replace mobile flag with target_os = android (#3278)

    * Remove old lock file

    * Start replacing mobile with android

    * Regex replace all mobile with android

    * Remove the mobile feature flag

    * keep the cfg mobile in tauri

commit c79b2cfb78
Author: Jon Häggblad <jon.haggblad@gmail.com>
Date:   Wed Apr 5 11:27:38 2023 +0200

    Service provider directory contract (#3220)

    * first commit of service provider directory contract proof of concept

    * *added config set on instantiation,
    *removed greetQuery test function

    * commit before mapping change

    * *changed mapping of service to use client address instead of cosmos addr

    * commit before mapping change

    * added acl to delete()

    * added test for acl in delete()

    * changed whitelist<vec> to standrd_whitelist bool in Service struct

    * removed old comments and commented out code

    * rustfmt

    * wup

    * wup

    * Older version of cw-multi-test that works with 1.0.0

    * wip

    * Remove .gitignore

    * Basic tests for announce and query now works

    * Restore tests for delete as well

    * Consolidate tests

    * Tidy

    * fmt

    * Start reworking test helpers

    * Tidy tests

    * More test work

    * More test improvements

    * More work on tests

    * Tweaks

    * Further tests

    * rustfmt

    * Add some comments

    * Initial work on requiring deposit

    * wip

    * Work on updating tests for handling funds

    * Start updating integration tests

    * Integration tests updated

    * merge test mods in state

    * Address review comments

    * Enable wasm-opt

    * Unify Result type

    * consistent amount in error type

    * WIP: paging output

    * IndexedMap working

    * extract to config file

    * WIP: middle of extracting out types

    * Extract types

    * wip

    * Types now extracted out:

    * Paged response type too

    * rustfmt

    * Start working on switching to cw Admin

    * Complete switch to Admin

    * Remove owner from announce msg

    * remove unused imports

    * Assert owner

    * Extract out types to common crate

    * Fix test compilation

    * Add query by owner and nym address

    * Move msg to common crate

    * rustfmt

    * tests for service id

    * service storage tests

    * state services tests

    * function rename

    * tidy

    * Fix clippy warning

    * User ServiceId instead and not u32

    * Delete by nym address

    * Emit explicit events

    * Swap ToString for Display

    * Move all storage keys to constants.rs

    * clippy

    * Test for deleting by name

    * Tidy integration tests

    * Remove to_string

    * Some comments to tests

    * Integration test for paging

    * serde snake_csae for NymAddress and ServiceType

    * Add migrate entry point

    * Add query contract version

    * A few more asserts for balance

    * Make MigrateMsg a struct

    ---------

    Co-authored-by: mx <maxhampshire@pm.me>

commit dd699bce9a
Merge: 5ce017ef3 e6957e7a9
Author: Tommy Verrall <60836166+tommyv1987@users.noreply.github.com>
Date:   Wed Apr 5 10:18:16 2023 +0100

    Merge pull request #3235 from nymtech/feature/performance-active-set-selection

    Feature/performance active set selection

commit 5ce017ef3d
Author: benedetta davico <46782255+benedettadavico@users.noreply.github.com>
Date:   Wed Apr 5 10:57:45 2023 +0200

    adding vesting tests (#3279)

commit 59c1ce2639
Merge: 4fb63d889 276edfd56
Author: Tommy Verrall <60836166+tommyv1987@users.noreply.github.com>
Date:   Wed Apr 5 09:50:53 2023 +0100

    Merge pull request #3261 from nymtech/feature/refresh-allow-list

    Feature/refresh allow list

commit 4fb63d8892
Author: Jędrzej Stuczyński <jedrzej.stuczynski@gmail.com>
Date:   Wed Apr 5 09:22:43 2023 +0100

    Feature/vesting delegation amount query (#3229)

    * moved queries and transactions out of contract.rs

    * added queries for vesting delegation details

    * nyxd_client support

commit 276edfd562
Author: Jędrzej Stuczyński <jedrzej.stuczynski@gmail.com>
Date:   Fri Mar 31 15:56:21 2023 +0100

    clippy

commit 605f8fcde3
Author: Jędrzej Stuczyński <jedrzej.stuczynski@gmail.com>
Date:   Fri Mar 31 15:06:12 2023 +0100

    updated and cleaned up tests

commit f0e4d1a7cf
Author: Jędrzej Stuczyński <jedrzej.stuczynski@gmail.com>
Date:   Fri Mar 31 14:01:36 2023 +0100

    configurable stored lists locations

commit 055ec4bdd5
Author: Jędrzej Stuczyński <jedrzej.stuczynski@gmail.com>
Date:   Fri Mar 31 12:57:02 2023 +0100

    updating stored allow list on file changes

commit 5761f9ac7f
Author: Jędrzej Stuczyński <jedrzej.stuczynski@gmail.com>
Date:   Fri Mar 31 12:15:45 2023 +0100

    file watcher

commit 32620fd55f
Author: Jędrzej Stuczyński <jedrzej.stuczynski@gmail.com>
Date:   Thu Mar 30 17:47:12 2023 +0100

    updating standard list in a timer

commit abb5cdbe06
Author: Jędrzej Stuczyński <jedrzej.stuczynski@gmail.com>
Date:   Thu Mar 30 16:43:58 2023 +0100

    extracted domain and ipnet information to separate struct

commit e6957e7a99
Author: Jędrzej Stuczyński <jedrzej.stuczynski@gmail.com>
Date:   Tue Mar 28 11:25:43 2023 +0100

    use combination of stake and performance for rewarded set selection

commit de2406a2c7
Author: Jędrzej Stuczyński <jedrzej.stuczynski@gmail.com>
Date:   Tue Mar 28 10:54:14 2023 +0100

    Moved MixnodeWithPerformance to helpers
2023-04-05 12:29:41 +02:00
Jon Häggblad 0b1b6947e8 Replace mobile flag with target_os = android (#3278)
* Remove old lock file

* Start replacing mobile with android

* Regex replace all mobile with android

* Remove the mobile feature flag

* keep the cfg mobile in tauri
2023-04-05 11:28:28 +02:00
Jon Häggblad c79b2cfb78 Service provider directory contract (#3220)
* first commit of service provider directory contract proof of concept

* *added config set on instantiation,
*removed greetQuery test function

* commit before mapping change

* *changed mapping of service to use client address instead of cosmos addr

* commit before mapping change

* added acl to delete()

* added test for acl in delete()

* changed whitelist<vec> to standrd_whitelist bool in Service struct

* removed old comments and commented out code

* rustfmt

* wup

* wup

* Older version of cw-multi-test that works with 1.0.0

* wip

* Remove .gitignore

* Basic tests for announce and query now works

* Restore tests for delete as well

* Consolidate tests

* Tidy

* fmt

* Start reworking test helpers

* Tidy tests

* More test work

* More test improvements

* More work on tests

* Tweaks

* Further tests

* rustfmt

* Add some comments

* Initial work on requiring deposit

* wip

* Work on updating tests for handling funds

* Start updating integration tests

* Integration tests updated

* merge test mods in state

* Address review comments

* Enable wasm-opt

* Unify Result type

* consistent amount in error type

* WIP: paging output

* IndexedMap working

* extract to config file

* WIP: middle of extracting out types

* Extract types

* wip

* Types now extracted out:

* Paged response type too

* rustfmt

* Start working on switching to cw Admin

* Complete switch to Admin

* Remove owner from announce msg

* remove unused imports

* Assert owner

* Extract out types to common crate

* Fix test compilation

* Add query by owner and nym address

* Move msg to common crate

* rustfmt

* tests for service id

* service storage tests

* state services tests

* function rename

* tidy

* Fix clippy warning

* User ServiceId instead and not u32

* Delete by nym address

* Emit explicit events

* Swap ToString for Display

* Move all storage keys to constants.rs

* clippy

* Test for deleting by name

* Tidy integration tests

* Remove to_string

* Some comments to tests

* Integration test for paging

* serde snake_csae for NymAddress and ServiceType

* Add migrate entry point

* Add query contract version

* A few more asserts for balance

* Make MigrateMsg a struct

---------

Co-authored-by: mx <maxhampshire@pm.me>
2023-04-05 11:27:38 +02:00
Tommy Verrall dd699bce9a Merge pull request #3235 from nymtech/feature/performance-active-set-selection
Feature/performance active set selection
2023-04-05 10:18:16 +01:00
benedetta davico 5ce017ef3d adding vesting tests (#3279) 2023-04-05 10:57:45 +02:00
Tommy Verrall 59c1ce2639 Merge pull request #3261 from nymtech/feature/refresh-allow-list
Feature/refresh allow list
2023-04-05 09:50:53 +01:00
Jędrzej Stuczyński 4fb63d8892 Feature/vesting delegation amount query (#3229)
* moved queries and transactions out of contract.rs

* added queries for vesting delegation details

* nyxd_client support
2023-04-05 09:22:43 +01:00
Jon Häggblad a3b4d04d02 fix clippy in beta toolchain (#3276) 2023-04-05 08:31:38 +02:00
Jędrzej Stuczyński aa3af8faea removed stake and location fields from gateway::Node (#3272)
* removed stake and location fields from gateway::Node

* fixed unused test fixture
2023-04-04 15:16:49 +01:00
farbanas 20c7f0e96f fix: nym-wallet version 2023-04-04 12:56:13 +02:00
farbanas e21142f1bd update contracts changelog 2023-04-04 11:51:14 +02:00
farbanas ba3a6eaeb5 Merge branch 'release/v1.1.14' 2023-04-04 11:38:40 +02:00
farbanas 9d0bc8ab9e update changelogs 2023-04-04 11:38:01 +02:00
Tommy Verrall 0d65ca78c4 Merge pull request #3260 from nymtech/feature/standarise-output-json
Feature/standarise output json
2023-04-04 10:29:50 +01:00
Jędrzej Stuczyński 0505a4807d using string representation of 'Recipient' for 'InitResults' 2023-04-04 10:27:48 +01:00
Jędrzej Stuczyński 01aa06e488 standarise printing of banner based on tty 2023-04-04 10:27:38 +01:00
Jędrzej Stuczyński 3b8dd1f4a5 using stderr when registering gateway 2023-04-04 10:27:38 +01:00
Jędrzej Stuczyński 4a837ce28c added output argument for generating gateway sign payload 2023-04-04 10:27:38 +01:00
Jędrzej Stuczyński 696f6c399c feature cleanup + added the capability to few nym-cli commands 2023-04-04 10:27:38 +01:00
Jędrzej Stuczyński ac9290de27 clippy 2023-04-04 10:27:38 +01:00
Jędrzej Stuczyński b026e9107f standarised output-json in client init 2023-04-04 10:27:35 +01:00
Jędrzej Stuczyński 1347535e8f mixnode: ibid 2023-04-04 10:26:41 +01:00
Jędrzej Stuczyński 479327849a gateway: added --output to commands that strictly require it 2023-04-04 10:26:41 +01:00
farbanas 21611a9434 update versions of contracts in preparation for release v1.1.14 2023-04-04 11:04:44 +02:00
farbanas 78d9030567 update versions in preparation for release v1.1.14 2023-04-04 10:30:20 +02:00
Pierre Dommerc 4feb168cf7 chore: update prettier and unpin version (#3265) 2023-04-03 15:52:51 +02:00
Tommy Verrall f3c16476f9 Merge pull request #3267 from nymtech/feature/gateway-settings-version-and-location
location and version needed in gateway settings updates
2023-04-03 12:11:46 +01:00
fmtabbara 4678059eaf add validation for version and location 2023-04-03 11:22:49 +01:00
fmtabbara a69d4bb457 location and version needed in gateway settings updates 2023-04-03 10:40:08 +01:00
Tommy Verrall 50e3f2be38 Merge pull request #3246 from nymtech/bug/explorer-remove-sandbox-sps
Dont fetch Service Provider list on Testnet Explorer
2023-04-03 10:05:52 +01:00
Jędrzej Stuczyński 276edfd562 clippy 2023-03-31 15:56:21 +01:00
Jędrzej Stuczyński 605f8fcde3 updated and cleaned up tests 2023-03-31 15:06:12 +01:00
Bogdan-Ștefan Neacşu 645c9b5e67 Feature/sdk socks5 (#3255)
* Use full socks5 config when setting client config

Also move socks5 setup sleep inside the sdk function

* SDK Socks5 Mixnet Client

* Remove NymClientConfig from sdk

* Update changelog

* Remove pub modifier

* Replace sleep with waiting on the control channel

* Add error on simple connect if socks5 configured
2023-03-31 16:34:07 +03:00
Jędrzej Stuczyński f0e4d1a7cf configurable stored lists locations 2023-03-31 14:01:36 +01:00
Jędrzej Stuczyński 055ec4bdd5 updating stored allow list on file changes 2023-03-31 12:57:02 +01:00
Jędrzej Stuczyński 5761f9ac7f file watcher 2023-03-31 12:15:45 +01:00
Jędrzej Stuczyński 32620fd55f updating standard list in a timer 2023-03-30 17:47:12 +01:00
Jędrzej Stuczyński abb5cdbe06 extracted domain and ipnet information to separate struct 2023-03-30 16:43:58 +01:00
Jędrzej Stuczyński 8cad2b0076 removed lock files from the old basic bandwidth generator (#3259) 2023-03-30 14:56:30 +01:00
dependabot[bot] bcd6c19a97 Bump webpack in /clients/native/examples/js-examples/websocket (#3185)
Bumps [webpack](https://github.com/webpack/webpack) from 5.70.0 to 5.76.0.
- [Release notes](https://github.com/webpack/webpack/releases)
- [Commits](https://github.com/webpack/webpack/compare/v5.70.0...v5.76.0)

---
updated-dependencies:
- dependency-name: webpack
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-30 14:47:39 +01:00
dependabot[bot] 764a3a6228 Bump webpack from 5.75.0 to 5.76.0 (#3186)
Bumps [webpack](https://github.com/webpack/webpack) from 5.75.0 to 5.76.0.
- [Release notes](https://github.com/webpack/webpack/releases)
- [Commits](https://github.com/webpack/webpack/compare/v5.75.0...v5.76.0)

---
updated-dependencies:
- dependency-name: webpack
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-30 14:47:26 +01:00
Jędrzej Stuczyński d17aa72829 chore: clippy 2023-03-30 14:17:37 +01:00
Jędrzej Stuczyński d62658f515 added --output json|text to mixnode and gateway 'sign' commands (#3251) 2023-03-30 10:23:53 +01:00
Pierre Dommerc e6d4095bf9 feat(wallet): main settings (#3253) 2023-03-30 11:02:49 +02:00
Tommy Verrall 9ace9d6960 Merge pull request #3252 from nymtech/bugfix/unstuck_verloc
Bugfix/unstuck verloc
2023-03-30 09:25:24 +01:00
Tommy Verrall 6c32ff9708 fix ci 2023-03-30 09:42:44 +02:00
Tommy Verrall 5eae62ae33 commit 2023-03-30 09:37:35 +02:00
Jędrzej Stuczyński 331483f86a breaking out of measurement loop on exhausted stream 2023-03-29 16:38:13 +01:00
Jędrzej Stuczyński 4ee0aeb2b1 disabling shutdown on drop for verloc measurement 2023-03-29 16:33:26 +01:00
Bogdan-Ștefan Neacşu 08354f7651 Feature/socks5 crate (#3226)
* Move client-core to common dir

* Factor out socks5-client in its own crate

* Possible sdk-socks5 integration

* Update changelog

* Remove socks5 client lib

* Rename crate to include nym- prefix

* Trim the socks5 wrapped message so that it's printable

* Fix intellij auto refactoring

* Post merge fixes
2023-03-29 13:31:24 +03:00
Jędrzej Stuczyński f1f599dd09 log % of wasted space when padding NymMessage (#3243) 2023-03-29 10:48:00 +01:00
fmtabbara 51251668e3 dont fetch service providers on testnet 2023-03-28 15:47:36 +01:00
Bogdan-Ștefan Neacşu 6e72433f99 Feature/coconut hash (#3231)
* Hash over public attributes too

* Improve and fix api unit test

* Rename hash function
2023-03-28 15:08:54 +03:00
Jędrzej Stuczyński e6957e7a99 use combination of stake and performance for rewarded set selection 2023-03-28 11:25:43 +01:00
Jędrzej Stuczyński de2406a2c7 Moved MixnodeWithPerformance to helpers 2023-03-28 10:54:14 +01:00
Jon Häggblad 956a264106 nym-connect lock files 2023-03-28 11:53:55 +02:00
Jędrzej Stuczyński 9b62d18101 Merge remote-tracking branch 'origin/release/v1.1.14' into develop 2023-03-28 10:28:11 +01:00
Pierre Dommerc 390730f304 refactor(wallet): balance grid ui (#3230) 2023-03-28 10:33:33 +02:00
pierre e134ef8e15 build(nc-mobile): remove webpack favicon plugin 2023-03-28 09:26:42 +02:00
Drazen Urch 7bd1550195 libcpucycles (#3219)
* Checkpoint

* cpu cycle ffi

* Rename

* mixnode feature

* Bundle libcpucycles
2023-03-27 16:34:10 +02:00
Jędrzej Stuczyński 134ab2f0d6 Stop using rewarding reports as a source of truth for whether mixnodes got rewards (#3227)
use contract information instead
2023-03-27 14:52:40 +01:00
Jędrzej Stuczyński 1a4e7433b2 Bugfix: NR after #3199 (#3225)
* updated NR config template

* upgrading NR config if usingn <= 1.1.13
2023-03-27 12:21:35 +01:00
Bogdan-Ștefan Neacșu f211b1e366 Add sandbox.env and update credential readme 2023-03-27 13:49:14 +03:00
Bogdan-Ștefan Neacşu b2db208e6e Add README for credential binary (#3221) 2023-03-27 13:33:00 +03:00
Jędrzej Stuczyński c9c0de1fba Offline signing (#3175)
* renamed secp265k1 to secp256k1

* added optional 'explicit_signer_data' argument for sign method

* wip

* made client signer generic

which required to undertake an adventure into coconut bandwidth trait bounds...

* separate wrapper for TxSigner

* moves signing-related features to separate module

* fixed build of binaries from outside default workspace

* offline signing example

* fixed wallet build

* post rebasing formatting

* fixed bity integration build

* making clippy happier

* fixed post-rebase bip39 dependency version
2023-03-27 10:15:30 +01:00
durch 9d91a018b2 Dont clone reconstructor 2023-03-24 16:22:14 +01:00
Drazen Urch 0f7e3fe53e Fix Reconstructor (#3218) 2023-03-24 16:21:31 +01:00
Tommy Verrall ae9c1b4070 Merge pull request #3199 from nymtech/chore/group-client-debug-config
chore: tidy up client `Debug` config section
2023-03-24 15:48:00 +03:00
benedetta davico e0d98af04f Feature/nym api tests (#3216)
* some edits

* more edits

* adding unfiltered tests, cleaning up

* "name change"
2023-03-24 12:22:03 +01:00
pierre 81e31c0550 build(nc-mobile): remove webpack-favicons plugin 2023-03-24 12:21:03 +01:00
Tommy Verrall 1c771df941 Merge pull request #3211 from nymtech/feature/no_creds_err_msg
Better error log for lacking credential in db
2023-03-24 11:18:41 +03:00
Jędrzej Stuczyński adcd8703d3 attempting to upgrade old config in 'init' 2023-03-23 16:06:22 +00:00
Jędrzej Stuczyński aee4c2d80d Feature/families signatures (#3156)
* wip family creation signatures + cli

* nym-cli commands for creating families

* Changed family join signature inside the contract

* Generating family join permit via nym-cli

* ability to join families via nym-cli

* more strongly typed FamilyHead arguments

* initial work on removing redundant family signatures

* removed all redundant signatures from families in the mixnet contract

* moved up the call stack

* nym-cli family operations

* fixed family related unit tests

* family member kick

* removed family operations from the wallet

* clippy
2023-03-23 16:36:10 +01:00
Jędrzej Stuczyński 5e04f48500 bugfix: drop tasks to connections closed by remote (#3190)
* applied patch #3187

* applied the same concept to the verloc listener
2023-03-23 12:09:43 +01:00
Fouad a7610a7a88 Gateway settings (#2725)
* add gateway settings button

* remove unneeded mixnode type check

* add additional properties to gateway type

* update node settings nav options

* set up gateway update requests

* create gateway settings page

* use update gateway validation

* PR updates

* dont show playground on gateways

* set up gateway config update

* fix lint errors in wallet

* run cargo fmt
2023-03-23 10:38:33 +01:00
Tommy Verrall 28e6e9140c Merge pull request #3203 from nymtech/chore/disable-sign-ext
disable sign-ext when using wasm-opt + update wasm-opt
2023-03-23 10:32:58 +02:00
benedetta davico 17c2aecd99 starting to add vesting tests (#3134)
* starting to add vesting tests

* adding more vesting client tests

* starting to add vesting tests & merging develop

* adding more vesting client tests

* fix linting

* Revert "Merge conflicts"

This reverts commit 0beb025a62.

* fix linting errors

* fix linting errors

* removing only adding skip

---------

Co-authored-by: fmtabbara <fmtabbara@hotmail.co.uk>
2023-03-22 18:30:07 +01:00
Bogdan-Ștefan Neacșu 85074f3ac8 Better error log for lacking credential in db 2023-03-22 17:21:20 +02:00
Bogdan-Ștefan Neacşu c7020da81c Use nym task crate for network statistics signal handle (#3209)
* Use nym task crate for network statistics signal handle

* Update changelog
2023-03-22 16:43:00 +02:00
Jędrzej Stuczyński 271a126556 removed migration code from mixnet and vesting contracts (#3207) 2023-03-22 14:27:51 +00:00
Jędrzej Stuczyński 7da444c7a4 clippy 2023-03-22 13:51:38 +00:00
Jędrzej Stuczyński 2a7fd71416 explicitly added old version number to 'oldconfig' 2023-03-22 13:51:38 +00:00
Jędrzej Stuczyński 6ffd211e51 backwards compatibility 2023-03-22 13:51:38 +00:00
Jędrzej Stuczyński f61ed48240 updated templates 2023-03-22 13:51:38 +00:00
Jędrzej Stuczyński 8d3dc405a5 clippy 2023-03-22 13:51:38 +00:00
Jędrzej Stuczyński 21bf0fb27b wasm changes 2023-03-22 13:51:36 +00:00
Jędrzej Stuczyński 7313f56c01 grouped debug config options inside client-core into substructs 2023-03-22 13:49:30 +00:00
Jon Häggblad cfef9e96e6 chore: update nym-connect mobile lock file 2023-03-22 12:17:21 +01:00
Jędrzej Stuczyński 8b9a5cf500 updated installed wasm-opt version to v112 2023-03-22 10:38:39 +00:00
Jędrzej Stuczyński ce94ce058f disabling sign-ext 2023-03-22 10:37:52 +00:00
farbanas 018e4d6079 chore: update lock files 2023-03-22 11:29:27 +01:00
farbanas ebadd9799f fix: add contracts-common back to dependencies 2023-03-22 11:29:25 +01:00
Jędrzej Stuczyński 268fa02b83 fix: restored 'nym-contracts-common' dependency in the mixnet contract 2023-03-22 10:25:42 +00:00
farbanas cb525477e5 fix: update CHANGELOG for contracts 2023-03-22 10:39:48 +01:00
farbanas 4d6d2f0d33 Merge branch 'master' into develop 2023-03-22 10:31:12 +01:00
farbanas c7f8b05604 fix: wallet CHANGELOG 2023-03-22 10:23:19 +01:00
farbanas 2878e9be9d Merge branch 'release/v1.1.13' 2023-03-22 10:15:32 +01:00
farbanas 7b419c2b12 bump version of contracts 2023-03-22 10:12:33 +01:00
Fran Arbanas 0049126a91 Merge pull request #3200 from nymtech/jon/chore/explicit-cosmwasm-versions-across-workspaces
Set cosmwasm versions on workspace and strictly use 1.0.0
2023-03-22 10:06:18 +01:00
Jon Häggblad 80c5194d8b Add explicit cosmwasm-crypto 1.0.0 dev-dependency 2023-03-21 16:34:06 +01:00
Jon Häggblad 27a6b99453 Even more workspace version missed earlier 2023-03-21 16:34:06 +01:00
Jon Häggblad 61982de511 A few more workspace versions 2023-03-21 16:34:06 +01:00
Jon Häggblad efd9883197 Use workspace deps for coconut contracts 2023-03-21 16:34:06 +01:00
Jon Häggblad ce4ae8d90c Set cosmwasm versions on workspace and strictly use 1.0.0 2023-03-21 16:34:06 +01:00
farbanas 1d2722f994 update workflows with specific wasm-opt version 2023-03-21 16:30:40 +01:00
Drazen Urch 7e109e7f2d Generalise MessageReceiver (#3042)
* Generalise MessageReceiver

* Generics all the way

* Generalise MessageReceiver

* Generics all the way

* Fix Cargo.lock

---------

Co-authored-by: benedettadavico <benedetta.davico@gmail.com>
2023-03-21 15:25:51 +01:00
farbanas f7a0b305df update common crate version in contracts 2023-03-21 11:10:55 +01:00
farbanas 746ec71a0d update package versions 2023-03-21 10:54:18 +01:00
Jon Häggblad 41a63a0985 Tidy top-level Makefile (#3192)
* Reorder Makefile

* split out the fmt targets

* split cargo test

* Split up clippy targets

* Add commit

* Use env variable for no-mobile instead

* Extract out target generation to use function

* Remove commented out code

* Add comment

* Minor tidy
2023-03-20 15:44:13 +01:00
Pierre Dommerc 5a149c5492 feat(nc-mobile): select service provider (#3196)
* feat: select service provider ui

* refactor: adjust ui

* fix: remove dead code
2023-03-20 13:53:29 +01:00
farbanas cdfa5ee540 chore: update versions for release/v1.1.13 2023-03-15 15:23:55 +01:00
farbanas 71853f69f3 chore: update changelogs for release/v1.1.13 2023-03-15 15:23:15 +01:00
Tommy Verrall bedff1f258 Merge pull request #3153 from nymtech/oak-14
Validating new interval config parameters to prevent division by zero
2023-03-14 12:38:43 +02:00
Fouad 71a10a9a8b add blockstream green to sp list (#3180) 2023-03-13 17:05:21 +01:00
Jon Häggblad 605aed6f20 mock-nym-api: fix .storybook lint error (#3178) 2023-03-13 12:23:17 +01:00
Tommy Verrall 5aee4b1660 Merge pull request #3167 from nymtech/feature/wallet-3132
Feature/wallet 3132
2023-03-10 17:56:09 +02:00
Tommy Verrall 68a7bb67de Merge pull request #3169 from nymtech/feature/explorer-3168
Feature/explorer 3168
2023-03-10 17:32:22 +02:00
fmtabbara 31e93428cf use new locked rewards and locked coins endpoints 2023-03-09 16:48:05 +00:00
fmtabbara 5f56b3eeea add bond % tooltip 2023-03-09 16:34:22 +00:00
fmtabbara e69b05693a switch avg and routing score table positions 2023-03-09 16:30:58 +00:00
fmtabbara 8ae2451340 add y-axis label 2023-03-09 16:28:30 +00:00
fmtabbara b3b3279345 fix gateway click thorough from gateway version field 2023-03-09 14:45:45 +00:00
farbanas 94a451c79b fix: updated build-and-upload-binaries-ci workflow with explorer-api and the new contracts 2023-03-09 13:41:22 +01:00
Jędrzej Stuczyński ec7b959028 removed source of future clippy complaints 2023-03-09 11:30:30 +00:00
Jędrzej Stuczyński 7061beea6e exposing tauri operations for spendable vested and reward coins 2023-03-09 11:28:50 +00:00
Fran Arbanas e408162e26 Merge pull request #2747 from nymtech/339-net-switch-bttn
339 net switch bttn
2023-03-09 10:52:00 +01:00
Gala 25ae3895cb updating branch 2023-03-09 10:39:30 +01:00
fmtabbara 60296f2a41 update vesting schedule ui 2023-03-08 17:51:30 +00:00
Fouad 3b97844310 Feature/explorer 2979 (#3147)
* additional unfiltered endpoints for nym-api

* add poor performance UI

* display appropriate UI when node is blacklisted

* update explorer api with blacklisted nodes

* add new unfiltered endpoint

add new unfiltered endpoint

* show blacklisted detail even when node description is unavailable

remove console.log

---------

Co-authored-by: Jędrzej Stuczyński <jedrzej.stuczynski@gmail.com>
2023-03-08 16:15:32 +01:00
Jon Häggblad 8e6d3c34e2 Merge branch 'jon/fix/docs-rs-build' 2023-03-08 09:37:31 +01:00
Jędrzej Stuczyński b1fb8bb18c Validating new interval config parameters to prevent division by zero 2023-03-07 09:51:18 +00:00
Gala 4f59678ded center layout 2022-12-22 15:31:35 +01:00
Gala 8a1d2af3cf adding changes 2022-12-22 14:44:58 +01:00
1007 changed files with 51696 additions and 44354 deletions
+17 -22
View File
@@ -11,30 +11,25 @@
# In each subsection folders are ordered first by depth, then alphabetically.
# This should make it easy to add new rules without breaking existing ones.
# Something weird not covered by anything else
* @futurechimp @mmsinclair
# contracts
/contracts/mixnet @durch @jstuczyn
/contracts/vesting @durch @jstuczyn
/contracts/service-provider-directory @octol
# Rust rules:
*.rs @durch @futurechimp @jstuczyn @neacsu @octol
Cargo.* @durch @futurechimp @jstuczyn @neacsu @octol
# crypto code
/common/crypto/ @jstuczyn
/common/nymcoconut/ @jstuczyn
/common/dkg/ @jstuczyn
/common/nymsphinx/ @jstuczyn
# JS rules:
*.js @mmsinclair @fmtabbara
*.ts @mmsinclair @fmtabbara
*.tsx @mmsinclair @fmtabbara
*.jsx @mmsinclair @fmtabbara
# rust sdk
/sdk/rust/ @octol
# Something looking like possible documentation rules:
*.md @mfahampshire
# nym-connect (rust)
/nym-connect/desktop/src-tauri/ @octol
# our docker scripts
/docker/ @neacsu
# nym-wallet (rust)
/nym-wallet/src-tauri/ @octol
# if there are any changes in the core crypto, I feel like Ania should take a look:
/common/crypto/ @aniampio
/common/nymsphinx/ @aniampio
# Explorer and wallet should probably get looked by the product team
/explorer/ @nymtech/product
/nym-wallet/ @nymtech/product
/wallet-web/ @nymtech/product
# documentation
/documentation @mfahampshire
+16
View File
@@ -0,0 +1,16 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
version: 2
updates:
# Maintain dependencies for GitHub Actions
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "daily"
commit-message:
prefix: build
prefix-development: chore
include: scope
@@ -4,34 +4,11 @@ on:
workflow_dispatch:
push:
paths:
- 'clients/**'
- 'common/**'
- 'contracts/**'
- 'explorer-api/**'
- 'gateway/**'
- 'integrations/**'
- 'mixnode/**'
- 'sdk/rust/nym-sdk/**'
- 'service-providers/**'
- 'nym-api/**'
- 'nym-outfox/**'
- 'tools/nym-cli/**'
- 'tools/ts-rs-cli/**'
pull_request:
paths:
- 'clients/**'
- 'common/**'
- 'contracts/**'
- 'explorer-api/**'
- 'gateway/**'
- 'integrations/**'
- 'mixnode/**'
- 'sdk/rust/nym-sdk/**'
- 'service-providers/**'
- 'nym-api/**'
- 'nym-outfox/**'
- 'tools/nym-cli/**'
- 'tools/ts-rs-cli/**'
env:
NETWORK: mainnet
@@ -65,11 +42,11 @@ jobs:
with:
toolchain: stable
- name: Build all binaries
- name: Build all mixnode binary
uses: actions-rs/cargo@v1
with:
command: build
args: --workspace --release --all
args: --manifest-path mixnode/Cargo.toml --release --features cpucycles
- name: Install Rust stable
uses: actions-rs/toolchain@v1
@@ -79,29 +56,12 @@ jobs:
override: true
components: rustfmt, clippy
- name: Install wasm-opt
run: cargo install wasm-opt
- name: Build release contracts
run: make wasm
- name: Prepare build output
shell: bash
env:
OUTPUT_DIR: ci-builds/${{ github.ref_name }}
run: |
cp target/release/nym-client $OUTPUT_DIR
cp target/release/nym-gateway $OUTPUT_DIR
cp target/release/nym-mixnode $OUTPUT_DIR
cp target/release/nym-socks5-client $OUTPUT_DIR
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/nym-cli $OUTPUT_DIR
cp target/release/credential $OUTPUT_DIR
cp contracts/target/wasm32-unknown-unknown/release/mixnet_contract.wasm $OUTPUT_DIR
cp contracts/target/wasm32-unknown-unknown/release/vesting_contract.wasm $OUTPUT_DIR
- name: Deploy branch to CI www
continue-on-error: true
+76
View File
@@ -0,0 +1,76 @@
name: CD dev-portal
on:
push:
branches: master
paths:
- 'documentation/dev-portal/**'
jobs:
build:
runs-on: custom-runner-linux
steps:
- uses: actions/checkout@v3
- name: Install rsync
run: sudo apt-get install rsync
- uses: rlespinasse/github-slug-action@v3.x
- uses: actions/setup-node@v3
with:
node-version: "16"
- name: Install Rust stable
uses: actions-rs/toolchain@v1
with:
toolchain: stable
- name: Install mdbook
run: (test -x $HOME/.cargo/bin/mdbook || cargo install --vers "^0.4" mdbook)
- name: Install mdbook plugins
run: |
cargo install --vers "^0.2.0" mdbook-variables && cargo install \
--vers "^1.8.0" mdbook-admonish && cargo install --vers \
"^0.1.2" mdbook-last-changed && cargo install --vers "^0.1.2" \
mdbook-theme && cargo install --vers "^0.7.7" mdbook-linkcheck
- name: Clean website
run: cd documentation/dev-portal && mdbook clean
- name: Build website
run: cd documentation/dev-portal && mdbook build
- name: Deploy branch master to dev
continue-on-error: true
uses: easingthemes/ssh-deploy@main
env:
SSH_PRIVATE_KEY: ${{ secrets.CD_WWW_SSH_PRIVATE_KEY }}
ARGS: "-rltgoDzvO --delete"
SOURCE: "documentation/dev-portal/book/html/"
REMOTE_HOST: ${{ secrets.CD_WWW_REMOTE_HOST_DEV }}
REMOTE_USER: ${{ secrets.CD_WWW_REMOTE_USER }}
TARGET: ${{ secrets.CD_WWW_REMOTE_TARGET_DEVP }}/
EXCLUDE: "/dist/, /node_modules/"
- name: Deploy branch master to prod
uses: easingthemes/ssh-deploy@main
env:
SSH_PRIVATE_KEY: ${{ secrets.CD_WWW_SSH_PRIVATE_KEY }}
ARGS: "-rltgoDzvO --delete"
SOURCE: "documentation/dev-portal/book/html/"
REMOTE_HOST: ${{ secrets.CD_WWW_REMOTE_HOST_PROD }}
REMOTE_USER: ${{ secrets.CD_WWW_REMOTE_USER }}
TARGET: ${{ secrets.CD_WWW_REMOTE_TARGET_DEVP }}/
EXCLUDE: "/dist/, /node_modules/"
- name: Matrix - Node Install
run: npm install
working-directory: .github/workflows/support-files
- name: Matrix - Send Notification
env:
NYM_NOTIFICATION_KIND: cd-dev
NYM_PROJECT_NAME: "Dev portal CD"
NYM_CI_WWW_BASE: "${{ secrets.NYM_CD_WWW_BASE }}"
NYM_CI_WWW_LOCATION: "${{ env.GITHUB_REF_SLUG }}"
GIT_COMMIT_MESSAGE: "${{ github.event.head_commit.message }}"
GIT_BRANCH: "${GITHUB_REF##*/}"
MATRIX_SERVER: "${{ secrets.MATRIX_SERVER }}"
MATRIX_ROOM: "${{ secrets.MATRIX_ROOM_DEVP }}"
MATRIX_USER_ID: "${{ secrets.MATRIX_USER_ID }}"
MATRIX_TOKEN: "${{ secrets.MATRIX_TOKEN }}"
MATRIX_DEVICE_ID: "${{ secrets.MATRIX_DEVICE_ID }}"
IS_SUCCESS: "${{ job.status == 'success' }}"
uses: docker://keybaseio/client:stable-node
with:
args: .github/workflows/support-files/notifications/entry_point.sh
+82
View File
@@ -0,0 +1,82 @@
name: CD docs
on:
push:
branches: master
paths:
- 'documentation/docs/**'
jobs:
build:
runs-on: custom-runner-linux
steps:
- uses: actions/checkout@v3
- name: Install rsync
run: sudo apt-get install rsync
- uses: rlespinasse/github-slug-action@v3.x
- uses: actions/setup-node@v3
with:
node-version: "16"
- 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 --all
- name: Install mdbook
run: (test -x $HOME/.cargo/bin/mdbook || cargo install --vers "^0.4" mdbook)
- name: Install mdbook plugins
run: |
cargo install --vers "^0.2.0" mdbook-variables && cargo install \
--vers "^1.8.0" mdbook-admonish && cargo install --vers \
"^0.1.2" mdbook-last-changed && cargo install --vers "^0.1.2" \
mdbook-theme && cargo install --vers "^0.7.7" mdbook-linkcheck && \
cargo install --vers "^0.5.0" mdbook-cmdrun
- name: Clean website
run: cd documentation/docs && mdbook clean
- name: Build website
run: cd documentation/docs && mdbook build
- name: Deploy branch master to dev
continue-on-error: true
uses: easingthemes/ssh-deploy@main
env:
SSH_PRIVATE_KEY: ${{ secrets.CD_WWW_SSH_PRIVATE_KEY }}
ARGS: "-rltgoDzvO --delete"
SOURCE: "documentation/docs/book/"
REMOTE_HOST: ${{ secrets.CD_WWW_REMOTE_HOST_DEV }}
REMOTE_USER: ${{ secrets.CD_WWW_REMOTE_USER }}
TARGET: ${{ secrets.CD_WWW_REMOTE_TARGET }}/
EXCLUDE: "/dist/, /node_modules/"
- name: Deploy branch master to prod
uses: easingthemes/ssh-deploy@main
env:
SSH_PRIVATE_KEY: ${{ secrets.CD_WWW_SSH_PRIVATE_KEY }}
ARGS: "-rltgoDzvO --delete"
SOURCE: "documentation/docs/book/"
REMOTE_HOST: ${{ secrets.CD_WWW_REMOTE_HOST_PROD }}
REMOTE_USER: ${{ secrets.CD_WWW_REMOTE_USER }}
TARGET: ${{ secrets.CD_WWW_REMOTE_TARGET }}/
EXCLUDE: "/dist/, /node_modules/"
- name: Matrix - Node Install
run: npm install
working-directory: .github/workflows/support-files
- name: Matrix - Send Notification
env:
NYM_NOTIFICATION_KIND: cd-docs
NYM_PROJECT_NAME: "Docs CD"
NYM_CI_WWW_BASE: "${{ secrets.NYM_CD_WWW_BASE }}"
NYM_CI_WWW_LOCATION: "${{ env.GITHUB_REF_SLUG }}"
GIT_COMMIT_MESSAGE: "${{ github.event.head_commit.message }}"
GIT_BRANCH: "${GITHUB_REF##*/}"
MATRIX_SERVER: "${{ secrets.MATRIX_SERVER }}"
MATRIX_ROOM: "${{ secrets.MATRIX_ROOM_DOCS }}"
MATRIX_USER_ID: "${{ secrets.MATRIX_USER_ID }}"
MATRIX_TOKEN: "${{ secrets.MATRIX_TOKEN }}"
MATRIX_DEVICE_ID: "${{ secrets.MATRIX_DEVICE_ID }}"
IS_SUCCESS: "${{ job.status == 'success' }}"
uses: docker://keybaseio/client:stable-node
with:
args: .github/workflows/support-files/notifications/entry_point.sh
+66
View File
@@ -0,0 +1,66 @@
name: CI dev-portal
on:
push:
branches-ignore: master
paths:
- 'documentation/dev-portal/**'
jobs:
build:
runs-on: custom-runner-linux
steps:
- uses: actions/checkout@v3
- name: Install rsync
run: sudo apt-get install rsync
- uses: rlespinasse/github-slug-action@v3.x
- uses: actions/setup-node@v3
with:
node-version: "16"
- name: Install Rust stable
uses: actions-rs/toolchain@v1
with:
toolchain: stable
- name: Install mdbook
run: (test -x $HOME/.cargo/bin/mdbook || cargo install --vers "^0.4" mdbook)
- name: Install mdbook plugins
run: |
cargo install --vers "^0.2.0" mdbook-variables && cargo install \
--vers "^1.8.0" mdbook-admonish && cargo install --vers \
"^0.1.2" mdbook-last-changed && cargo install --vers "^0.1.2" mdbook-theme \
&& cargo install --vers "^0.7.7" mdbook-linkcheck
- name: Clean website
run: cd documentation/dev-portal && mdbook clean
- name: Build website
run: cd documentation/dev-portal && mdbook build
- name: Deploy branch to CI www
continue-on-error: true
uses: easingthemes/ssh-deploy@main
env:
SSH_PRIVATE_KEY: ${{ secrets.CI_WWW_SSH_PRIVATE_KEY }}
ARGS: "-rltgoDzvO --delete"
SOURCE: "documentation/dev-portal/book/html/"
REMOTE_HOST: ${{ secrets.CI_WWW_REMOTE_HOST }}
REMOTE_USER: ${{ secrets.CI_WWW_REMOTE_USER }}
TARGET: ${{ secrets.CI_WWW_REMOTE_TARGET }}/dev-portal-${{ env.GITHUB_REF_SLUG }}
EXCLUDE: "/dist/, /node_modules/"
- name: Matrix - Node Install
run: npm install
working-directory: .github/workflows/support-files
- name: Matrix - Send Notification
env:
NYM_NOTIFICATION_KIND: ci-dev
NYM_PROJECT_NAME: "Dev portal CI"
NYM_CI_WWW_BASE: "${{ secrets.NYM_CI_WWW_BASE }}"
NYM_CI_WWW_LOCATION: "dev-portal-${{ env.GITHUB_REF_SLUG }}"
GIT_COMMIT_MESSAGE: "${{ github.event.head_commit.message }}"
GIT_BRANCH: "${GITHUB_REF##*/}"
MATRIX_SERVER: "${{ secrets.MATRIX_SERVER }}"
MATRIX_ROOM: "${{ secrets.MATRIX_ROOM_DEVP }}"
MATRIX_USER_ID: "${{ secrets.MATRIX_USER_ID }}"
MATRIX_TOKEN: "${{ secrets.MATRIX_TOKEN }}"
MATRIX_DEVICE_ID: "${{ secrets.MATRIX_DEVICE_ID }}"
IS_SUCCESS: "${{ job.status == 'success' }}"
uses: docker://keybaseio/client:stable-node
with:
args: .github/workflows/support-files/notifications/entry_point.sh
+72
View File
@@ -0,0 +1,72 @@
name: CI docs
on:
push:
branches-ignore: master
paths:
- 'documentation/docs/**'
jobs:
build:
runs-on: custom-runner-linux
steps:
- uses: actions/checkout@v3
- name: Install rsync
run: sudo apt-get install rsync
- uses: rlespinasse/github-slug-action@v3.x
- uses: actions/setup-node@v3
with:
node-version: "16"
- 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 --all
- name: Install mdbook
run: (test -x $HOME/.cargo/bin/mdbook || cargo install --vers "^0.4" mdbook)
- name: Install mdbook plugins
run: |
cargo install --vers "^0.2.0" mdbook-variables && cargo install \
--vers "^1.8.0" mdbook-admonish && cargo install --vers \
"^0.1.2" mdbook-last-changed && cargo install --vers "^0.1.2" \
mdbook-theme && cargo install --vers "^0.7.7" mdbook-linkcheck && \
cargo install --vers "^0.5.0" mdbook-cmdrun
- name: Clean website
run: cd documentation/docs && mdbook clean
- name: Build website
run: cd documentation/docs && mdbook build
- name: Deploy branch to CI www
continue-on-error: true
uses: easingthemes/ssh-deploy@main
env:
SSH_PRIVATE_KEY: ${{ secrets.CI_WWW_SSH_PRIVATE_KEY }}
ARGS: "-rltgoDzvO --delete"
SOURCE: "documentation/docs/book/"
REMOTE_HOST: ${{ secrets.CI_WWW_REMOTE_HOST }}
REMOTE_USER: ${{ secrets.CI_WWW_REMOTE_USER }}
TARGET: ${{ secrets.CI_WWW_REMOTE_TARGET }}/docs-${{ env.GITHUB_REF_SLUG }}
EXCLUDE: "/dist/, /node_modules/"
- name: Matrix - Node Install
run: npm install
working-directory: .github/workflows/support-files
- name: Matrix - Send Notification
env:
NYM_NOTIFICATION_KIND: ci-docs
NYM_PROJECT_NAME: "Docs CI"
NYM_CI_WWW_BASE: "${{ secrets.NYM_CI_WWW_BASE }}"
NYM_CI_WWW_LOCATION: "docs-${{ env.GITHUB_REF_SLUG }}"
GIT_COMMIT_MESSAGE: "${{ github.event.head_commit.message }}"
GIT_BRANCH: "${GITHUB_REF##*/}"
MATRIX_SERVER: "${{ secrets.MATRIX_SERVER }}"
MATRIX_ROOM: "${{ secrets.MATRIX_ROOM_DOCS }}"
MATRIX_USER_ID: "${{ secrets.MATRIX_USER_ID }}"
MATRIX_TOKEN: "${{ secrets.MATRIX_TOKEN }}"
MATRIX_DEVICE_ID: "${{ secrets.MATRIX_DEVICE_ID }}"
IS_SUCCESS: "${{ job.status == 'success' }}"
uses: docker://keybaseio/client:stable-node
with:
args: .github/workflows/support-files/notifications/entry_point.sh
+1 -1
View File
@@ -20,7 +20,7 @@ jobs:
components: rustfmt, clippy
- name: Install wasm-opt
run: cargo install wasm-opt
run: cargo install --version 0.112.0 wasm-opt
- name: Build release contracts
run: make wasm
+2 -1
View File
@@ -30,6 +30,7 @@ jobs:
continue-on-error: ${{ matrix.rust == 'nightly' }}
needs: matrix_prep
strategy:
fail-fast: false
matrix: ${{fromJson(needs.matrix_prep.outputs.matrix)}}
steps:
- uses: actions/checkout@v2
@@ -63,4 +64,4 @@ jobs:
if: ${{ matrix.rust != 'nightly' }}
with:
command: clippy
args: --manifest-path contracts/Cargo.toml --workspace -- -D warnings
args: --manifest-path contracts/Cargo.toml --workspace --all-targets -- -D warnings
+13
View File
@@ -0,0 +1,13 @@
name: Greetings
on: [pull_request_target, issues]
jobs:
greeting:
runs-on: ubuntu-latest
steps:
- uses: actions/first-interaction@v1
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
issue-message: 'Thank you for raising this issue'
pr-message: 'Thank you for making this first PR'
@@ -6,7 +6,7 @@
},
{
"os":"windows-latest",
"os":"windows10",
"rust":"stable",
"runOnEvent":"schedule"
},
@@ -22,7 +22,7 @@
"runOnEvent":"schedule"
},
{
"os":"windows-latest",
"os":"windows10",
"rust":"beta",
"runOnEvent":"schedule"
},
@@ -38,7 +38,7 @@
"runOnEvent":"schedule"
},
{
"os":"windows-latest",
"os":"windows10",
"rust":"nightly",
"runOnEvent":"schedule"
},
@@ -0,0 +1,29 @@
const Handlebars = require('handlebars');
const fs = require('fs');
const path = require('path');
async function addToContextAndValidate(context) {
if (!context.env.NYM_CI_WWW_LOCATION) {
throw new Error('Please ensure the env var NYM_CI_WWW_LOCATION is set');
}
if (!context.env.NYM_CI_WWW_BASE) {
throw new Error('Please ensure the env var NYM_CI_WWW_BASE is set');
}
}
async function getMessageBody(context) {
const source = fs
.readFileSync(
context.env.IS_SUCCESS === 'true'
? path.resolve(__dirname, 'templates', 'success')
: path.resolve(__dirname, 'templates', 'failure'),
)
.toString();
const template = Handlebars.compile(source);
return template(context);
}
module.exports = {
addToContextAndValidate,
getMessageBody,
};
@@ -0,0 +1,17 @@
🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥
> :rocket: {{ env.NYM_PROJECT_NAME }}
>
> 🔴 **FAILURE** :cry:
>
> `branch` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/tree/{{ env.GIT_BRANCH_NAME }}
>
> `commit` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/commit/{{ env.GITHUB_SHA }}
>
> `build ` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/actions/runs/{{ env.GITHUB_RUN_ID }}
>
Commit message:
```
{{ env.GIT_COMMIT_MESSAGE }}
```
@@ -0,0 +1,17 @@
🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩
> :rocket: {{ env.NYM_PROJECT_NAME }} ➡️➡️➡️➡️➡️ **View output:** https://{{ env.NYM_CI_WWW_BASE }}/developers/
>
> ✅ **SUCCESS**
>
> `branch` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/tree/{{ env.GIT_BRANCH_NAME }}
>
> `commit` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/commit/{{ env.GITHUB_SHA }}
>
> `build ` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/actions/runs/{{ env.GITHUB_RUN_ID }}
>
Commit message by `{{ env.GITHUB_ACTOR }}` at {{ timestamp }}:
```
{{ env.GIT_COMMIT_MESSAGE }}
```
@@ -0,0 +1,29 @@
const Handlebars = require('handlebars');
const fs = require('fs');
const path = require('path');
async function addToContextAndValidate(context) {
if (!context.env.NYM_CI_WWW_LOCATION) {
throw new Error('Please ensure the env var NYM_CI_WWW_LOCATION is set');
}
if (!context.env.NYM_CI_WWW_BASE) {
throw new Error('Please ensure the env var NYM_CI_WWW_BASE is set');
}
}
async function getMessageBody(context) {
const source = fs
.readFileSync(
context.env.IS_SUCCESS === 'true'
? path.resolve(__dirname, 'templates', 'success')
: path.resolve(__dirname, 'templates', 'failure'),
)
.toString();
const template = Handlebars.compile(source);
return template(context);
}
module.exports = {
addToContextAndValidate,
getMessageBody,
};
@@ -0,0 +1,11 @@
🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥
> :rocket: {{ env.NYM_PROJECT_NAME }}
> 🔴 **FAILURE** :cry:
> `branch` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/tree/{{ env.GIT_BRANCH_NAME }}
> `commit` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/commit/{{ env.GITHUB_SHA }}
> `build ` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/actions/runs/{{ env.GITHUB_RUN_ID }}
Commit message:
```
{{ env.GIT_COMMIT_MESSAGE }}
```
@@ -0,0 +1,17 @@
🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩
> :rocket: {{ env.NYM_PROJECT_NAME }} ➡️➡️➡️➡️➡️ **View output:** https://{{ env.NYM_CI_WWW_BASE }}/docs/
>
> ✅ **SUCCESS**
>
> `branch` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/tree/{{ env.GIT_BRANCH_NAME }}
>
> `commit` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/commit/{{ env.GITHUB_SHA }}
>
> `build ` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/actions/runs/{{ env.GITHUB_RUN_ID }}
>
Commit message by `{{ env.GITHUB_ACTOR }}` at {{ timestamp }}:
```
{{ env.GIT_COMMIT_MESSAGE }}
```
@@ -0,0 +1,29 @@
const Handlebars = require('handlebars');
const fs = require('fs');
const path = require('path');
async function addToContextAndValidate(context) {
if (!context.env.NYM_CI_WWW_LOCATION) {
throw new Error('Please ensure the env var NYM_CI_WWW_LOCATION is set');
}
if (!context.env.NYM_CI_WWW_BASE) {
throw new Error('Please ensure the env var NYM_CI_WWW_BASE is set');
}
}
async function getMessageBody(context) {
const source = fs
.readFileSync(
context.env.IS_SUCCESS === 'true'
? path.resolve(__dirname, 'templates', 'success')
: path.resolve(__dirname, 'templates', 'failure'),
)
.toString();
const template = Handlebars.compile(source);
return template(context);
}
module.exports = {
addToContextAndValidate,
getMessageBody,
};
@@ -0,0 +1,17 @@
🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥
> :rocket: {{ env.NYM_PROJECT_NAME }}
>
> 🔴 **FAILURE** :cry:
>
> `branch` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/tree/{{ env.GIT_BRANCH_NAME }}
>
> `commit` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/commit/{{ env.GITHUB_SHA }}
>
> `build ` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/actions/runs/{{ env.GITHUB_RUN_ID }}
>
Commit message:
```
{{ env.GIT_COMMIT_MESSAGE }}
```
@@ -0,0 +1,17 @@
🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩
> :rocket: {{ env.NYM_PROJECT_NAME }} ➡️➡️➡️➡️➡️ **View output:** https://{{ env.NYM_CI_WWW_LOCATION }}.{{ env.NYM_CI_WWW_BASE }}/
>
> ✅ **SUCCESS**
>
> `branch` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/tree/{{ env.GIT_BRANCH_NAME }}
>
> `commit` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/commit/{{ env.GITHUB_SHA }}
>
> `build ` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/actions/runs/{{ env.GITHUB_RUN_ID }}
>
Commit message by `{{ env.GITHUB_ACTOR }}` at {{ timestamp }}:
```
{{ env.GIT_COMMIT_MESSAGE }}
```
@@ -0,0 +1,29 @@
const Handlebars = require('handlebars');
const fs = require('fs');
const path = require('path');
async function addToContextAndValidate(context) {
if (!context.env.NYM_CI_WWW_LOCATION) {
throw new Error('Please ensure the env var NYM_CI_WWW_LOCATION is set');
}
if (!context.env.NYM_CI_WWW_BASE) {
throw new Error('Please ensure the env var NYM_CI_WWW_BASE is set');
}
}
async function getMessageBody(context) {
const source = fs
.readFileSync(
context.env.IS_SUCCESS === 'true'
? path.resolve(__dirname, 'templates', 'success')
: path.resolve(__dirname, 'templates', 'failure'),
)
.toString();
const template = Handlebars.compile(source);
return template(context);
}
module.exports = {
addToContextAndValidate,
getMessageBody,
};
@@ -0,0 +1,17 @@
🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥
> :rocket: {{ env.NYM_PROJECT_NAME }}
>
> 🔴 **FAILURE** :cry:
>
> `branch` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/tree/{{ env.GIT_BRANCH_NAME }}
>
> `commit` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/commit/{{ env.GITHUB_SHA }}
>
> `build ` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/actions/runs/{{ env.GITHUB_RUN_ID }}
>
Commit message:
```
{{ env.GIT_COMMIT_MESSAGE }}
```
@@ -0,0 +1,17 @@
🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩
> :rocket: {{ env.NYM_PROJECT_NAME }} ➡️➡️➡️➡️➡️ **View output:** https://{{ env.NYM_CI_WWW_LOCATION }}.{{ env.NYM_CI_WWW_BASE }}/
>
> ✅ **SUCCESS**
>
> `branch` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/tree/{{ env.GIT_BRANCH_NAME }}
>
> `commit` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/commit/{{ env.GITHUB_SHA }}
>
> `build ` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/actions/runs/{{ env.GITHUB_RUN_ID }}
>
Commit message by `{{ env.GITHUB_ACTOR }}` at {{ timestamp }}:
```
{{ env.GIT_COMMIT_MESSAGE }}
```
@@ -3,7 +3,7 @@ require('dotenv').config();
const { sendMatrixMessage } = require('./send_message_to_matrix');
let context = {
kinds: ['nym-wallet', 'ts-packages', 'network-explorer', 'nightly', 'nym-connect','security'],
kinds: ['nym-wallet', 'ts-packages', 'network-explorer', 'nightly', 'nym-connect','security','ci-docs','cd-docs','ci-dev','cd-dev'],
};
/**
+1 -1
View File
@@ -22,6 +22,6 @@
"unified": "^9.2.2"
},
"devDependencies": {
"prettier": "2.3.2"
"prettier": "^2.8.7"
}
}
+1 -1
View File
@@ -64,4 +64,4 @@ jobs:
uses: actions-rs/cargo@v1
with:
command: clippy
args: --manifest-path nym-wallet/Cargo.toml --workspace --all-features -- -D warnings
args: --manifest-path nym-wallet/Cargo.toml --workspace --all-features --all-targets -- -D warnings
+1 -2
View File
@@ -39,7 +39,6 @@ validator-api-config.toml
dist
storybook-static
envs/qwerty.env
Cargo.lock
nym-connect/Cargo.lock
.parcel-cache
**/.DS_Store
cpu-cycles/libcpucycles/build
+81
View File
@@ -4,6 +4,87 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
## [Unreleased]
## [v1.1.16] (2023-04-25)
- Explorer - Fix sorting function on Stake Saturation. It is currently working per page and not globally ([#3320])
- Poisson process gets stuck at too slow rate. Rework to more aggressively up-regulate ([#3309])
- decrease the logging level of warnings associated with clients dropping packets due to gateway being overloaded (I'd say reduce it to debug/trace) - there are few sources of those, e.g. in real and cover traffic streams ([#3299])
- Make the buffer size in `AvailableReader` depend on packet sizes the client is using + introduce read timeouts ([#3213])
- Rust SDK - Support coconut, credential storage etc ([#2755])
- version bump for next release ([#3349])
- added coconut credential generation example ([#3339])
- update mix-node setup docs with node description ([#3325])
- exposed missing gateway commands in nym-cli ([#3324])
- make sure to clear inner 'ack_map' in 'GatewaysReader' ([#3300])
[#3320]: https://github.com/nymtech/nym/issues/3320
[#3309]: https://github.com/nymtech/nym/issues/3309
[#3299]: https://github.com/nymtech/nym/issues/3299
[#3213]: https://github.com/nymtech/nym/issues/3213
[#2755]: https://github.com/nymtech/nym/issues/2755
[#3349]: https://github.com/nymtech/nym/pull/3349
[#3339]: https://github.com/nymtech/nym/pull/3339
[#3325]: https://github.com/nymtech/nym/pull/3325
[#3324]: https://github.com/nymtech/nym/pull/3324
[#3300]: https://github.com/nymtech/nym/pull/3300
## [v1.1.15] (2023-04-18)
- Fix verloc being stuck waiting for shutdown signal ([#3250])
- Introduce `--output json` flag to `sign` command to allow to more easily capture the output ([#3249])
- Explorer - Dont fetch Service Provider list on Testnet ([#3245])
- When determining active set, rather than weighting the nodes by just the `stake`, use `stake * performance` ([#3234])
- Introduce dual packet sizes to our clients (as in use two packet sizes at the same time depending on message size) ([#3189])
- Experiment with offline signing in our validator client ([#3174])
- Modify network requester binary to reload `allowed.list` periodically to pull in any changes made upstream without having to restart the service ([#3149])
- Standardise all `--output json` on binary inits, we pass the output json at different points for different binaries. ([#3080])
- Service provider directory contract: initial version ([#2759])
- Fix issue where network-requester run failed on fresh init due to missing allow file ([#3316])
[#3250]: https://github.com/nymtech/nym/issues/3250
[#3249]: https://github.com/nymtech/nym/issues/3249
[#3245]: https://github.com/nymtech/nym/issues/3245
[#3234]: https://github.com/nymtech/nym/issues/3234
[#3189]: https://github.com/nymtech/nym/issues/3189
[#3174]: https://github.com/nymtech/nym/issues/3174
[#3149]: https://github.com/nymtech/nym/issues/3149
[#3080]: https://github.com/nymtech/nym/issues/3080
[#2759]: https://github.com/nymtech/nym/issues/2759
[#3316]: https://github.com/nymtech/nym/pull/3316
## [v1.1.14] (2023-04-04)
- Investigate cause of qwerty validator being in invalid rewarding state ([#3224])
- Fix NR config due to changes in #3199 ([#3223])
- [Issue] Mixnodes and gateway do not close connections properly ([#3187])
- disable sign-ext when using wasm-opt + update wasm-opt ([#3203])
- chore: tidy up client `Debug` config section ([#3199])
[#3224]: https://github.com/nymtech/nym/issues/3224
[#3223]: https://github.com/nymtech/nym/issues/3223
[#3187]: https://github.com/nymtech/nym/issues/3187
[#3203]: https://github.com/nymtech/nym/pull/3203
[#3199]: https://github.com/nymtech/nym/pull/3199
>>>>>>> master
## [v1.1.13] (2023-03-15)
- NE - instead of throwing a "Mixnode/Gateway not found" error for blacklisted nodes due to bad performance, show their history but tag them as "Having poor performance" ([#2979])
- NE - Upgrade Sandbox and make below changes: ([#2332])
- Explorer - Updates ([#3168])
- Website v2 - deploy infrastructure for strapi and CI ([#2213])
- add blockstream green to sp list ([#3180])
- mock-nym-api: fix .storybook lint error ([#3178])
- Validating new interval config parameters to prevent division by zero ([#3153])
[#2979]: https://github.com/nymtech/nym/issues/2979
[#2332]: https://github.com/nymtech/nym/issues/2332
[#3168]: https://github.com/nymtech/nym/issues/3168
[#2213]: https://github.com/nymtech/nym/issues/2213
[#3180]: https://github.com/nymtech/nym/pull/3180
[#3178]: https://github.com/nymtech/nym/pull/3178
[#3153]: https://github.com/nymtech/nym/pull/3153
## [v1.1.12] (2023-03-07)
- Fix generated docs for mixnet and vesting contract on docs.rs ([#3093])
Generated
+1006 -729
View File
File diff suppressed because it is too large Load Diff
+17 -3
View File
@@ -17,12 +17,14 @@ opt-level = 3
resolver = "2"
members = [
"clients/client-core",
"clients/credential",
"clients/native",
"clients/native/websocket-requests",
"clients/socks5",
"common/async-file-watcher",
"common/bandwidth-controller",
"common/bin-common",
"common/client-core",
"common/client-libs/gateway-client",
"common/client-libs/mixnet-client",
"common/client-libs/validator-client",
@@ -35,8 +37,8 @@ members = [
"common/cosmwasm-smart-contracts/group-contract",
"common/cosmwasm-smart-contracts/mixnet-contract",
"common/cosmwasm-smart-contracts/multisig-contract",
"common/cosmwasm-smart-contracts/service-provider-directory",
"common/cosmwasm-smart-contracts/vesting-contract",
"common/mobile-storage",
"common/credential-storage",
"common/credentials",
"common/crypto",
@@ -46,6 +48,7 @@ members = [
"common/ledger",
"common/mixnode-common",
"common/network-defaults",
"common/node-tester-utils",
"common/nonexhaustive-delayqueue",
"common/nymcoconut",
"common/nymsphinx",
@@ -59,6 +62,7 @@ members = [
"common/nymsphinx/params",
"common/nymsphinx/types",
"common/pemstore",
"common/socks5-client-core",
"common/socks5/proxy-helpers",
"common/socks5/requests",
"common/statistics",
@@ -93,7 +97,7 @@ default-members = [
"explorer-api",
]
exclude = ["explorer", "contracts", "clients/webassembly", "nym-wallet", "nym-connect/mobile/src-tauri", "nym-connect/desktop"]
exclude = ["explorer", "contracts", "clients/webassembly", "nym-wallet", "nym-connect/mobile/src-tauri", "nym-connect/desktop", "cpu-cycles"]
[workspace.package]
authors = ["Nym Technologies SA"]
@@ -107,6 +111,16 @@ license = "Apache-2.0"
async-trait = "0.1.64"
bip39 = { version = "2.0.0", features = ["zeroize"] }
cfg-if = "1.0.0"
cosmwasm-derive = "=1.0.0"
cosmwasm-schema = "=1.0.0"
cosmwasm-std = "=1.0.0"
cosmwasm-storage = "=1.0.0"
cw-utils = "=0.13.4"
cw-storage-plus = "=0.13.4"
cw2 = { version = "=0.13.4" }
cw3 = { version = "=0.13.4" }
cw3-fixed-multisig = { version = "=0.13.4" }
cw4 = { version = "=0.13.4" }
dotenvy = "0.15.6"
lazy_static = "1.4.0"
log = "0.4"
+84 -107
View File
@@ -1,143 +1,120 @@
# Default target
all: test
test: clippy-all cargo-test wasm fmt
test-no-mobile: clippy-all-no-mobile cargo-test-no-mobile wasm fmt-no-mobile
test-all: test cargo-test-expensive
test-all-no-mobile: test-no-mobile cargo-test-expensive
no-clippy: build cargo-test wasm fmt
no-clippy-no-mobile: build-no-mobile cargo-test-no-mobile wasm fmt-no-mobile
happy: fmt clippy-happy test
happy-no-mobile: fmt-no-mobile clippy-happy-no-mobile test-no-mobile
clippy-all: clippy-all-no-mobile clippy-all-connect-mobile
clippy-all-no-mobile: clippy-main clippy-main-examples clippy-all-contracts clippy-all-wallet clippy-all-connect clippy-all-wasm-client
clippy-happy: clippy-happy-no-mobile clippy-happy-connect-mobile
clippy-happy-no-mobile: clippy-happy-main clippy-happy-contracts clippy-happy-wallet clippy-happy-connect
cargo-test: cargo-test-no-mobile test-connect-mobile
cargo-test-no-mobile: test-main test-contracts test-wallet test-connect
cargo-test-expensive: test-main-expensive test-contracts-expensive test-wallet-expensive test-connect-expensive
build: build-no-mobile build-connect-mobile
build-no-mobile: build-contracts build-wallet build-main build-main-examples build-connect build-wasm-client
fmt: fmt-no-mobile fmt-connect-mobile
fmt-no-mobile: fmt-main fmt-contracts fmt-wallet fmt-connect fmt-wasm-client
clippy-happy-main:
cargo clippy
# Building release binaries is a little manual as we can't just build --release
# on all workspaces.
build-release: build-release-main wasm
clippy-happy-contracts:
cargo clippy --manifest-path contracts/Cargo.toml --target wasm32-unknown-unknown
# Deprecated
# For backwards compatibility
clippy-all: clippy
clippy-happy-wallet:
cargo clippy --manifest-path nym-wallet/Cargo.toml
# -----------------------------------------------------------------------------
# Define targets for a given workspace
# $(1): name
# $(2): path to workspace
# $(3): extra arguments to cargo
# -----------------------------------------------------------------------------
define add_cargo_workspace
clippy-happy-connect:
cargo clippy --manifest-path nym-connect/desktop/Cargo.toml
clippy-happy-$(1):
cargo clippy --manifest-path $(2)/Cargo.toml $(3)
clippy-happy-connect-mobile:
cargo clippy --manifest-path nym-connect/mobile/src-tauri/Cargo.toml
clippy-$(1):
cargo clippy --manifest-path $(2)/Cargo.toml --workspace $(3) -- -D warnings
clippy-main:
cargo clippy --workspace -- -D warnings
clippy-examples-$(1):
cargo clippy --manifest-path $(2)/Cargo.toml --workspace --examples -- -D warnings
clippy-main-examples:
cargo clippy --workspace --examples -- -D warnings
check-$(1):
cargo check --manifest-path $(2)/Cargo.toml --workspace $(3)
clippy-wasm:
cargo clippy --manifest-path clients/webassembly/Cargo.toml --target wasm32-unknown-unknown --workspace -- -D warnings
test-$(1):
cargo test --manifest-path $(2)/Cargo.toml --workspace
test-expensive-$(1):
cargo test --manifest-path $(2)/Cargo.toml --workspace -- --ignored
clippy-all-contracts:
cargo clippy --workspace --manifest-path contracts/Cargo.toml --all-features --target wasm32-unknown-unknown -- -D warnings
build-$(1):
cargo build --manifest-path $(2)/Cargo.toml --workspace $(3)
clippy-all-wallet:
cargo clippy --workspace --manifest-path nym-wallet/Cargo.toml --all-features -- -D warnings
build-examples-$(1):
cargo build --manifest-path $(2)/Cargo.toml --workspace --examples
clippy-all-connect:
cargo clippy --workspace --manifest-path nym-connect/desktop/Cargo.toml --all-features -- -D warnings
build-release-$(1):
cargo build --manifest-path $(2)/Cargo.toml --workspace --release $(3)
clippy-all-connect-mobile:
cargo clippy --workspace --manifest-path nym-connect/mobile/src-tauri/Cargo.toml --all-features -- -D warnings
fmt-$(1):
cargo fmt --manifest-path $(2)/Cargo.toml --all
clippy-all-wasm-client:
cargo clippy --workspace --manifest-path clients/webassembly/Cargo.toml --all-features --target wasm32-unknown-unknown -- -D warnings
clippy-happy: clippy-happy-$(1)
clippy: clippy-$(1) clippy-examples-$(1)
check: check-$(1)
cargo-test: test-$(1)
cargo-test-expensive: test-expensive-$(1)
build: build-$(1) build-$(1)-examples
build-release-all: build-release-$(1)
fmt: fmt-$(1)
test-main:
cargo test --workspace
endef
test-main-expensive:
cargo test --workspace -- --ignored
# -----------------------------------------------------------------------------
# Rust workspaces
# -----------------------------------------------------------------------------
test-contracts:
cargo test --manifest-path contracts/Cargo.toml --all-features
# Generate targets for the various cargo workspaces
test-contracts-expensive:
cargo test --manifest-path contracts/Cargo.toml --all-features -- --ignored
$(eval $(call add_cargo_workspace,main,.))
$(eval $(call add_cargo_workspace,contracts,contracts,--target wasm32-unknown-unknown))
$(eval $(call add_cargo_workspace,wasm-client,clients/webassembly,--target wasm32-unknown-unknown))
$(eval $(call add_cargo_workspace,wallet,nym-wallet,))
$(eval $(call add_cargo_workspace,connect,nym-connect/desktop))
ifdef NYM_MOBILE
$(eval $(call add_cargo_workspace,connect-mobile,nym-connect/mobile/src-tauri))
endif
test-wallet:
cargo test --manifest-path nym-wallet/Cargo.toml --all-features
test-wallet-expensive:
cargo test --manifest-path nym-wallet/Cargo.toml --all-features -- --ignored
test-connect:
cargo test --manifest-path nym-connect/desktop/Cargo.toml --all-features
test-connect-expensive:
cargo test --manifest-path nym-connect/desktop/Cargo.toml --all-features -- --ignored
test-connect-mobile:
cargo test --manifest-path nym-connect/mobile/src-tauri/Cargo.toml --all-features
test-connect-mobile-expensive:
cargo test --manifest-path nym-connect/mobile/src-tauri/Cargo.toml --all-features -- --ignored
build-main:
cargo build --workspace
build-main-examples:
cargo build --workspace --examples
build-contracts:
cargo build --manifest-path contracts/Cargo.toml --workspace
build-wallet:
cargo build --manifest-path nym-wallet/Cargo.toml --workspace
build-connect:
cargo build --manifest-path nym-connect/desktop/Cargo.toml --workspace
build-connect-mobile:
cargo build --manifest-path nym-connect/mobile/src-tauri/Cargo.toml --workspace
# -----------------------------------------------------------------------------
# Convenience targets for crates that are already part of the main workspace
# -----------------------------------------------------------------------------
build-explorer-api:
cargo build --manifest-path explorer-api/Cargo.toml --workspace
build-wasm-client:
cargo build --manifest-path clients/webassembly/Cargo.toml --workspace --target wasm32-unknown-unknown
cargo build -p explorer-api
build-nym-cli:
cargo build --release --manifest-path tools/nym-cli/Cargo.toml
cargo build -p nym-cli --release
fmt-main:
cargo fmt --all
# -----------------------------------------------------------------------------
# Build contracts ready for deploy
# -----------------------------------------------------------------------------
fmt-contracts:
cargo fmt --manifest-path contracts/Cargo.toml --all
CONTRACTS_OUT_DIR=contracts/target/wasm32-unknown-unknown/release
VESTING_CONTRACT=$(CONTRACTS_OUT_DIR)/vesting_contract.wasm
MIXNET_CONTRACT=$(CONTRACTS_OUT_DIR)/mixnet_contract.wasm
SERVICE_PROVIDER_DIRECTORY_CONTRACT=$(CONTRACTS_OUT_DIR)/nym_service_provider_directory.wasm
fmt-wallet:
cargo fmt --manifest-path nym-wallet/Cargo.toml --all
wasm: wasm-build wasm-opt
fmt-connect:
cargo fmt --manifest-path nym-connect/desktop/Cargo.toml --all
fmt-connect-mobile:
cargo fmt --manifest-path nym-connect/mobile/src-tauri/Cargo.toml --all
fmt-wasm-client:
cargo fmt --manifest-path clients/webassembly/Cargo.toml --all
wasm:
wasm-build:
RUSTFLAGS='-C link-arg=-s' cargo build --manifest-path contracts/Cargo.toml --release --target wasm32-unknown-unknown
wasm-opt -Os contracts/target/wasm32-unknown-unknown/release/vesting_contract.wasm -o contracts/target/wasm32-unknown-unknown/release/vesting_contract.wasm
wasm-opt -Os contracts/target/wasm32-unknown-unknown/release/mixnet_contract.wasm -o contracts/target/wasm32-unknown-unknown/release/mixnet_contract.wasm
wasm-opt:
wasm-opt --disable-sign-ext -Os $(VESTING_CONTRACT) -o $(VESTING_CONTRACT)
wasm-opt --disable-sign-ext -Os $(MIXNET_CONTRACT) -o $(MIXNET_CONTRACT)
wasm-opt --disable-sign-ext -Os $(SERVICE_PROVIDER_DIRECTORY_CONTRACT) -o $(SERVICE_PROVIDER_DIRECTORY_CONTRACT)
# -----------------------------------------------------------------------------
# Misc
# -----------------------------------------------------------------------------
# NOTE: this seems deprecated an not needed anymore?
mixnet-opt: wasm
cd contracts/mixnet && make opt
+1 -1
View File
@@ -21,7 +21,7 @@ The platform is composed of multiple Rust crates. Top-level executable binary cr
### Building
Platform build instructions are available on [our docs site](https://nymtech.net/docs/stable/run-nym-nodes/build-nym).
Platform build instructions are available on [our docs site](https://nymtech.net/docs/binaries/building-nym.html).
Wallet build instructions are also available on [our docs site](https://nymtech.net/docs/stable/nym-apps/wallet#for-developers).
### Developing
+3 -3
View File
@@ -3,8 +3,8 @@ Critical bug or security issue 💥
If you're here because you're trying to figure out how to notify us of a security issue, go to Discord, and alert the core engineers:
Dave Hrycyszyn futurechimp#5430
Drazen Urch drazen#4873
Jedrzej Stuczynski "Jedrzej | Nym#5666"
Fran Arbanas | franarbanas#0995
Mark Sinclair | marknym#8088
Please avoid opening public issues on GitHub that contain information about a potential security vulnerability as this makes it difficult to reduce the impact and harm of valid security issues.
Please avoid opening public issues on GitHub that contain information about a potential security vulnerability as this makes it difficult to reduce the impact and harm of valid security issues.
+4 -8
View File
@@ -1,27 +1,23 @@
[package]
name = "credential"
name = "nym-credential-client"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
bip39 = { workspace = true }
clap = { version = "4.0", features = ["cargo", "derive"] }
log = "0.4"
rand = "0.7.3"
serde = { version = "1.0", features = ["derive"] }
serde = { workspace = true, features = ["derive"] }
thiserror = "1.0"
url = "2.2"
tokio = { version = "1.24.1", features = ["rt-multi-thread", "net", "signal", "macros"] } # async runtime
nym-coconut-interface = { path = "../../common/coconut-interface" }
nym-bandwidth-controller = { path = "../../common/bandwidth-controller" }
nym-config = { path = "../../common/config" }
nym-credentials = { path = "../../common/credentials" }
nym-credential-storage = { path = "../../common/credential-storage" }
nym-crypto = { path = "../../common/crypto", features = ["rand", "asymmetric", "symmetric", "aes", "hashing"] }
nym-bin-common = { path = "../../common/bin-common"}
nym-network-defaults = { path = "../../common/network-defaults" }
nym-pemstore = { path = "../../common/pemstore" }
validator-client = { path = "../../common/client-libs/validator-client", features = ["nyxd-client"] }
nym-validator-client = { path = "../../common/client-libs/validator-client", features = ["nyxd-client"] }
+32
View File
@@ -0,0 +1,32 @@
<!--
Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
SPDX-License-Identifier: Apache-2.0
-->
## Credential binary
The credential binary is used to acquire coconut bandwidth credentials in exchange for nym tokens. Those credentials are stored in the client's `data` directory, so that they can be used as the client sees fit.
### Warning
The credential binary is still experimental software. The infrastructure for using it is not yet deployed to mainnet and it's still in the process of being deployed to sandbox.
### Building
From the project's root directory, run:
```
cargo build -p credential
```
which generates the `credential` binary in `target/debug/credential`.
### Running
For example, you can get a credential worth 3 nym (3000000 unym) in a socks5 client that was already initialized like so:
```
./target/debug/credential --config-env-file envs/sandbox.env --client-home-directory ~/.nym/socks5-clients/cred_client --nyxd-url https://sandbox-validator1.nymtech.net --mnemonic $MNEMONIC --recovery-dir /tmp/recovery --amount 3000000
```
More information regarding how to run the binary can be found by running it with the `--help` argument.
+4 -4
View File
@@ -4,14 +4,14 @@
use crate::error::Result;
use bip39::Mnemonic;
use nym_network_defaults::{NymNetworkDetails, VOUCHER_INFO};
use nym_validator_client::nyxd;
use nym_validator_client::nyxd::traits::CoconutBandwidthSigningClient;
use nym_validator_client::nyxd::{Coin, DirectSigningNyxdClient, Fee, NyxdClient};
use std::str::FromStr;
use url::Url;
use validator_client::nyxd;
use validator_client::nyxd::traits::CoconutBandwidthSigningClient;
use validator_client::nyxd::{Coin, Fee, NyxdClient, SigningNyxdClient};
pub(crate) struct Client {
nyxd_client: NyxdClient<SigningNyxdClient>,
nyxd_client: NyxdClient<DirectSigningNyxdClient>,
mix_denom_base: String,
}
+11 -94
View File
@@ -3,26 +3,13 @@
use clap::{ArgGroup, Args, Subcommand};
use log::*;
use nym_bandwidth_controller::acquire::state::State;
use nym_bin_common::completions::ArgShell;
use rand::rngs::OsRng;
use std::str::FromStr;
use nym_credential_storage::persistent_storage::PersistentStorage;
use nym_validator_client::nyxd::traits::DkgQueryClient;
use nym_coconut_interface::{Base58, Parameters};
use nym_credential_storage::storage::Storage;
use nym_credential_storage::PersistentStorage;
use nym_credentials::coconut::bandwidth::{BandwidthVoucher, TOTAL_ATTRIBUTES};
use nym_credentials::coconut::utils::obtain_aggregate_signature;
use nym_crypto::asymmetric::{encryption, identity};
use nym_network_defaults::VOUCHER_INFO;
use validator_client::nyxd::traits::DkgQueryClient;
use validator_client::nyxd::tx::Hash;
use validator_client::nyxd::CosmWasmClient;
use validator_client::CoconutApiClient;
use crate::client::Client;
use crate::error::{CredentialClientError, Result};
use crate::error::Result;
use crate::recovery_storage::RecoveryStorage;
use crate::state::{KeyPair, State};
#[derive(Subcommand)]
pub(crate) enum Command {
@@ -47,10 +34,6 @@ pub(crate) struct Run {
#[clap(long)]
pub(crate) client_home_directory: std::path::PathBuf,
/// The nyxd URL that should be used
#[clap(long)]
pub(crate) nyxd_url: String,
/// A mnemonic for the account that buys the credential
#[clap(long)]
pub(crate) mnemonic: String,
@@ -69,82 +52,16 @@ pub(crate) struct Run {
pub(crate) recovery_mode: bool,
}
pub(crate) async fn deposit(nyxd_url: &str, mnemonic: &str, amount: u64) -> Result<State> {
let mut rng = OsRng;
let signing_keypair = KeyPair::from(identity::KeyPair::new(&mut rng));
let encryption_keypair = KeyPair::from(encryption::KeyPair::new(&mut rng));
let params = Parameters::new(TOTAL_ATTRIBUTES).unwrap();
let client = Client::new(nyxd_url, mnemonic);
let tx_hash = client
.deposit(
amount,
signing_keypair.public_key.clone(),
encryption_keypair.public_key.clone(),
None,
)
.await?;
let voucher = BandwidthVoucher::new(
&params,
amount.to_string(),
VOUCHER_INFO.to_string(),
Hash::from_str(&tx_hash).map_err(|_| CredentialClientError::InvalidTxHash)?,
identity::PrivateKey::from_base58_string(&signing_keypair.private_key)?,
encryption::PrivateKey::from_base58_string(&encryption_keypair.private_key)?,
);
let state = State { voucher, params };
Ok(state)
}
pub(crate) async fn get_credential<C: Clone + CosmWasmClient + Send + Sync>(
state: &State,
client: validator_client::Client<C>,
shared_storage: PersistentStorage,
) -> Result<()> {
let epoch_id = client.nyxd.get_current_epoch().await?.epoch_id;
let threshold = client
.nyxd
.get_current_epoch_threshold()
.await?
.ok_or(CredentialClientError::NoThreshold)?;
let coconut_api_clients = CoconutApiClient::all_coconut_api_clients(&client, epoch_id).await?;
let signature = obtain_aggregate_signature(
&state.params,
&state.voucher,
&coconut_api_clients,
threshold,
)
.await?;
info!("Signature: {:?}", signature.to_bs58());
shared_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(),
)
.await?;
Ok(())
}
pub(crate) async fn recover_credentials<C: Clone + CosmWasmClient + Send + Sync>(
client: validator_client::Client<C>,
pub(crate) async fn recover_credentials<C: DkgQueryClient + Send + Sync>(
client: &C,
recovery_storage: &RecoveryStorage,
shared_storage: PersistentStorage,
shared_storage: &PersistentStorage,
) -> Result<()> {
for voucher in recovery_storage.unconsumed_vouchers()? {
let state = State {
voucher,
params: Parameters::new(TOTAL_ATTRIBUTES).unwrap(),
};
if let Err(e) = get_credential(&state, client.clone(), shared_storage.clone()).await {
let state = State::new(voucher);
if let Err(e) =
nym_bandwidth_controller::acquire::get_credential(&state, client, shared_storage).await
{
error!(
"Could not recover deposit {} due to {:?}, try again later",
state.voucher.tx_hash(),
+5 -16
View File
@@ -6,10 +6,8 @@ use thiserror::Error;
use nym_credential_storage::error::StorageError;
use nym_credentials::error::Error as CredentialError;
use nym_crypto::asymmetric::encryption::KeyRecoveryError;
use nym_crypto::asymmetric::identity::Ed25519RecoveryError;
use validator_client::nyxd::error::NyxdError;
use validator_client::ValidatorClientError;
use nym_validator_client::nyxd::error::NyxdError;
use nym_validator_client::ValidatorClientError;
pub type Result<T> = std::result::Result<T, CredentialClientError>;
@@ -18,6 +16,9 @@ pub enum CredentialClientError {
#[error("IO error: {0}")]
IOError(#[from] std::io::Error),
#[error("Bandwidth controller error: {0}")]
BandwidthControllerError(#[from] nym_bandwidth_controller::error::BandwidthControllerError),
#[error("Nyxd error: {0}")]
Nyxd(#[from] NyxdError),
@@ -27,21 +28,9 @@ pub enum CredentialClientError {
#[error("Credential error: {0}")]
Credential(#[from] CredentialError),
#[error("The tx hash provided is not valid")]
InvalidTxHash,
#[error("Could not parse Ed25519 data")]
Ed25519ParseError(#[from] Ed25519RecoveryError),
#[error("Could not parse X25519 data")]
X25519ParseError(#[from] KeyRecoveryError),
#[error("Could not use shared storage")]
SharedStorageError(#[from] StorageError),
#[error("Could not get system time")]
SysTimeError(#[from] SystemTimeError),
#[error("Threshold not set yet")]
NoThreshold,
}
+28 -17
View File
@@ -1,11 +1,9 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
mod client;
mod commands;
mod error;
mod recovery_storage;
mod state;
use commands::*;
use error::Result;
@@ -18,9 +16,9 @@ use std::time::{Duration, SystemTime};
use clap::{CommandFactory, Parser};
use nym_bin_common::logging::setup_logging;
use validator_client::nyxd::traits::DkgQueryClient;
use validator_client::nyxd::CosmWasmClient;
use validator_client::Config;
use nym_validator_client::nyxd::traits::DkgQueryClient;
use nym_validator_client::nyxd::{Coin, CosmWasmClient};
use nym_validator_client::Config;
const SAFETY_BUFFER_SECS: u64 = 60; // 1 minute
@@ -35,8 +33,8 @@ struct Cli {
pub(crate) command: Command,
}
async fn block_until_coconut_is_available<C: Clone + CosmWasmClient + Send + Sync>(
client: &validator_client::Client<C>,
async fn block_until_coconut_is_available<C: CosmWasmClient + Send + Sync>(
client: &nym_validator_client::Client<C>,
) -> Result<()> {
loop {
let epoch = client.nyxd.get_current_epoch().await?;
@@ -77,21 +75,34 @@ async fn main() -> Result<()> {
.client_home_directory
.join(DATA_DIR)
.join(CRED_DB_FILE_NAME);
let shared_storage = nym_credential_storage::initialise_storage(db_path).await;
let shared_storage =
nym_credential_storage::initialise_persistent_storage(db_path).await;
let recovery_storage = recovery_storage::RecoveryStorage::new(r.recovery_dir)?;
let network_details = NymNetworkDetails::new_from_env();
let config = Config::try_from_nym_network_details(&network_details)?;
let client = validator_client::Client::new_query(config)?;
let config = Config::try_from_nym_network_details(&network_details).expect(
"failed to construct valid validator client config with the provided network",
);
let amount = Coin::new(
r.amount as u128,
network_details.chain_details.mix_denom.base,
);
let client =
nym_validator_client::Client::new_signing(config, r.mnemonic.parse().unwrap())?;
block_until_coconut_is_available(&client).await?;
info!("Starting depositing funds, don't kill the process");
if !r.recovery_mode {
let state = deposit(&r.nyxd_url, &r.mnemonic, r.amount).await?;
if get_credential(&state, client, shared_storage)
.await
.is_err()
let state =
nym_bandwidth_controller::acquire::deposit(&client.nyxd, amount).await?;
if nym_bandwidth_controller::acquire::get_credential(
&state,
&client,
&shared_storage,
)
.await
.is_err()
{
warn!("Failed to obtain credential. Dumping recovery data.",);
match recovery_storage.insert_voucher(&state.voucher) {
@@ -104,11 +115,11 @@ async fn main() -> Result<()> {
}
}
} else {
recover_credentials(client, &recovery_storage, shared_storage).await?;
recover_credentials(&client.nyxd, &recovery_storage, &shared_storage).await?;
}
}
Command::Completions(c) => c.generate(&mut crate::Cli::command(), bin_name),
Command::GenerateFigSpec => fig_generate(&mut crate::Cli::command(), bin_name),
Command::Completions(c) => c.generate(&mut Cli::command(), bin_name),
Command::GenerateFigSpec => fig_generate(&mut Cli::command(), bin_name),
}
Ok(())
+9 -10
View File
@@ -1,6 +1,6 @@
[package]
name = "nym-client"
version = "1.1.12"
version = "1.1.16"
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"]
description = "Implementation of the Nym Client"
edition = "2021"
@@ -26,30 +26,29 @@ 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 = { version = "1.0.104", features = ["derive"] } # for config serialization/deserialization
serde_json = "1.0"
serde = { workspace = true, features = ["derive"] } # for config serialization/deserialization
serde_json = { workspace = true }
thiserror = "1.0.34"
tap = "1.0.1"
tokio = { version = "1.24.1", features = ["rt-multi-thread", "net", "signal"] } # async runtime
tokio-tungstenite = "0.14" # websocket
## internal
nym-bin-common = { path = "../../common/bin-common" }
client-core = { path = "../client-core", features = ["fs-surb-storage"] }
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"] }
nym-coconut-interface = { path = "../../common/coconut-interface" }
nym-config = { path = "../../common/config" }
nym-credential-storage = { path = "../../common/credential-storage" }
nym-credentials = { path = "../../common/credentials" }
nym-crypto = { path = "../../common/crypto" }
gateway-client = { path = "../../common/client-libs/gateway-client" }
gateway-requests = { path = "../../gateway/gateway-requests" }
nym-gateway-requests = { path = "../../gateway/gateway-requests" }
nym-network-defaults = { path = "../../common/network-defaults" }
nym-sphinx = { path = "../../common/nymsphinx" }
nym-pemstore = { path = "../../common/pemstore" }
nym-task = { path = "../../common/task" }
nym-topology = { path = "../../common/topology" }
validator-client = { path = "../../common/client-libs/validator-client", features = ["nyxd-client"] }
websocket-requests = { path = "websocket-requests" }
nym-validator-client = { path = "../../common/client-libs/validator-client", features = ["nyxd-client"] }
nym-client-websocket-requests = { path = "websocket-requests" }
[dev-dependencies]
serde_json = "1.0" # for the "textsend" example
@@ -13,7 +13,7 @@
},
"devDependencies": {
"clean-webpack-plugin": "^4.0.0",
"webpack": "^5.70.0",
"webpack": "^5.76.0",
"webpack-cli": "^4.9.2",
"webpack-dev-server": "^4.7.4"
}
@@ -490,9 +490,9 @@
}
},
"node_modules/acorn": {
"version": "8.7.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz",
"integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==",
"version": "8.8.2",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz",
"integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==",
"bin": {
"acorn": "bin/acorn"
},
@@ -1327,9 +1327,9 @@
}
},
"node_modules/enhanced-resolve": {
"version": "5.9.2",
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.9.2.tgz",
"integrity": "sha512-GIm3fQfwLJ8YZx2smuHpBKkXC1yOk+OBEmKckVyL0i/ea8mqDEykK3ld5dgH1QYPNyT/lIllxV2LULnxCHaHkA==",
"version": "5.12.0",
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.12.0.tgz",
"integrity": "sha512-QHTXI/sZQmko1cbDoNAa3mJ5qhWUUNAq3vR0/YiD379fWQrcfuoX1+HW2S0MTt7XmoPLapdaDKUtelUSPic7hQ==",
"dependencies": {
"graceful-fs": "^4.2.4",
"tapable": "^2.2.0"
@@ -2380,10 +2380,10 @@
"node": ">= 10.13.0"
}
},
"node_modules/json-parse-better-errors": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz",
"integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw=="
"node_modules/json-parse-even-better-errors": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
"integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w=="
},
"node_modules/json-schema-traverse": {
"version": "0.4.1",
@@ -3824,9 +3824,9 @@
}
},
"node_modules/watchpack": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.3.1.tgz",
"integrity": "sha512-x0t0JuydIo8qCNctdDrn1OzH/qDzk2+rdCOC3YzumZ42fiMqmQ7T3xQurykYMhYfHaPHTp4ZxAx2NfUo1K6QaA==",
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz",
"integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==",
"dependencies": {
"glob-to-regexp": "^0.4.1",
"graceful-fs": "^4.1.2"
@@ -3845,33 +3845,33 @@
}
},
"node_modules/webpack": {
"version": "5.70.0",
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.70.0.tgz",
"integrity": "sha512-ZMWWy8CeuTTjCxbeaQI21xSswseF2oNOwc70QSKNePvmxE7XW36i7vpBMYZFAUHPwQiEbNGCEYIOOlyRbdGmxw==",
"version": "5.76.0",
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.76.0.tgz",
"integrity": "sha512-l5sOdYBDunyf72HW8dF23rFtWq/7Zgvt/9ftMof71E/yUb1YLOBmTgA2K4vQthB3kotMrSj609txVE0dnr2fjA==",
"dependencies": {
"@types/eslint-scope": "^3.7.3",
"@types/estree": "^0.0.51",
"@webassemblyjs/ast": "1.11.1",
"@webassemblyjs/wasm-edit": "1.11.1",
"@webassemblyjs/wasm-parser": "1.11.1",
"acorn": "^8.4.1",
"acorn": "^8.7.1",
"acorn-import-assertions": "^1.7.6",
"browserslist": "^4.14.5",
"chrome-trace-event": "^1.0.2",
"enhanced-resolve": "^5.9.2",
"enhanced-resolve": "^5.10.0",
"es-module-lexer": "^0.9.0",
"eslint-scope": "5.1.1",
"events": "^3.2.0",
"glob-to-regexp": "^0.4.1",
"graceful-fs": "^4.2.9",
"json-parse-better-errors": "^1.0.2",
"json-parse-even-better-errors": "^2.3.1",
"loader-runner": "^4.2.0",
"mime-types": "^2.1.27",
"neo-async": "^2.6.2",
"schema-utils": "^3.1.0",
"tapable": "^2.1.1",
"terser-webpack-plugin": "^5.1.3",
"watchpack": "^2.3.1",
"watchpack": "^2.4.0",
"webpack-sources": "^3.2.3"
},
"bin": {
@@ -4894,9 +4894,9 @@
}
},
"acorn": {
"version": "8.7.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz",
"integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ=="
"version": "8.8.2",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz",
"integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw=="
},
"acorn-import-assertions": {
"version": "1.8.0",
@@ -5527,9 +5527,9 @@
"dev": true
},
"enhanced-resolve": {
"version": "5.9.2",
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.9.2.tgz",
"integrity": "sha512-GIm3fQfwLJ8YZx2smuHpBKkXC1yOk+OBEmKckVyL0i/ea8mqDEykK3ld5dgH1QYPNyT/lIllxV2LULnxCHaHkA==",
"version": "5.12.0",
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.12.0.tgz",
"integrity": "sha512-QHTXI/sZQmko1cbDoNAa3mJ5qhWUUNAq3vR0/YiD379fWQrcfuoX1+HW2S0MTt7XmoPLapdaDKUtelUSPic7hQ==",
"requires": {
"graceful-fs": "^4.2.4",
"tapable": "^2.2.0"
@@ -6305,10 +6305,10 @@
"supports-color": "^8.0.0"
}
},
"json-parse-better-errors": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz",
"integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw=="
"json-parse-even-better-errors": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
"integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w=="
},
"json-schema-traverse": {
"version": "0.4.1",
@@ -7396,9 +7396,9 @@
"dev": true
},
"watchpack": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.3.1.tgz",
"integrity": "sha512-x0t0JuydIo8qCNctdDrn1OzH/qDzk2+rdCOC3YzumZ42fiMqmQ7T3xQurykYMhYfHaPHTp4ZxAx2NfUo1K6QaA==",
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz",
"integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==",
"requires": {
"glob-to-regexp": "^0.4.1",
"graceful-fs": "^4.1.2"
@@ -7414,33 +7414,33 @@
}
},
"webpack": {
"version": "5.70.0",
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.70.0.tgz",
"integrity": "sha512-ZMWWy8CeuTTjCxbeaQI21xSswseF2oNOwc70QSKNePvmxE7XW36i7vpBMYZFAUHPwQiEbNGCEYIOOlyRbdGmxw==",
"version": "5.76.0",
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.76.0.tgz",
"integrity": "sha512-l5sOdYBDunyf72HW8dF23rFtWq/7Zgvt/9ftMof71E/yUb1YLOBmTgA2K4vQthB3kotMrSj609txVE0dnr2fjA==",
"requires": {
"@types/eslint-scope": "^3.7.3",
"@types/estree": "^0.0.51",
"@webassemblyjs/ast": "1.11.1",
"@webassemblyjs/wasm-edit": "1.11.1",
"@webassemblyjs/wasm-parser": "1.11.1",
"acorn": "^8.4.1",
"acorn": "^8.7.1",
"acorn-import-assertions": "^1.7.6",
"browserslist": "^4.14.5",
"chrome-trace-event": "^1.0.2",
"enhanced-resolve": "^5.9.2",
"enhanced-resolve": "^5.10.0",
"es-module-lexer": "^0.9.0",
"eslint-scope": "5.1.1",
"events": "^3.2.0",
"glob-to-regexp": "^0.4.1",
"graceful-fs": "^4.2.9",
"json-parse-better-errors": "^1.0.2",
"json-parse-even-better-errors": "^2.3.1",
"loader-runner": "^4.2.0",
"mime-types": "^2.1.27",
"neo-async": "^2.6.2",
"schema-utils": "^3.1.0",
"tapable": "^2.1.1",
"terser-webpack-plugin": "^5.1.3",
"watchpack": "^2.3.1",
"watchpack": "^2.4.0",
"webpack-sources": "^3.2.3"
}
},
@@ -19,7 +19,7 @@
"license": "Apache-2.0",
"devDependencies": {
"clean-webpack-plugin": "^4.0.0",
"webpack": "^5.70.0",
"webpack": "^5.76.0",
"webpack-cli": "^4.9.2",
"webpack-dev-server": "^4.7.4"
},
@@ -1,10 +1,10 @@
use futures::{SinkExt, StreamExt};
use nym_client_websocket_requests::{requests::ClientRequest, responses::ServerResponse};
use nym_sphinx::addressing::clients::Recipient;
use tokio::net::TcpStream;
use tokio_tungstenite::{
connect_async, tungstenite::protocol::Message, MaybeTlsStream, WebSocketStream,
};
use websocket_requests::{requests::ClientRequest, responses::ServerResponse};
// just helpers functions that work in this very particular context because we are sending to ourselves
// and hence will always get a response back (i.e. the message we sent)
+11 -5
View File
@@ -2,7 +2,7 @@
// SPDX-License-Identifier: Apache-2.0
use crate::client::config::template::config_template;
use client_core::config::ClientCoreConfigTrait;
use nym_client_core::config::ClientCoreConfigTrait;
use nym_config::defaults::DEFAULT_WEBSOCKET_LISTENING_PORT;
use nym_config::{NymConfig, OptionalSet};
use serde::{Deserialize, Serialize};
@@ -11,10 +11,11 @@ use std::net::{IpAddr, Ipv4Addr};
use std::path::PathBuf;
use std::str::FromStr;
pub use client_core::config::Config as BaseConfig;
pub use client_core::config::MISSING_VALUE;
pub use client_core::config::{DebugConfig, GatewayEndpointConfig};
pub use nym_client_core::config::Config as BaseConfig;
pub use nym_client_core::config::MISSING_VALUE;
pub use nym_client_core::config::{DebugConfig, GatewayEndpointConfig};
pub mod old_config_v1_1_13;
mod template;
#[derive(Debug, Deserialize, PartialEq, Eq, Serialize, Clone, Copy)]
@@ -80,7 +81,7 @@ impl NymConfig for Config {
}
impl ClientCoreConfigTrait for Config {
fn get_gateway_endpoint(&self) -> &client_core::config::GatewayEndpointConfig {
fn get_gateway_endpoint(&self) -> &nym_client_core::config::GatewayEndpointConfig {
self.base.get_gateway_endpoint()
}
}
@@ -93,6 +94,11 @@ impl Config {
}
}
pub fn validate(&self) -> bool {
// no other sections have explicit requirements (yet)
self.base.validate()
}
pub fn with_socket(mut self, socket_type: SocketType) -> Self {
self.socket.socket_type = socket_type;
self
@@ -0,0 +1,60 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::client::config::{Config, Socket};
use nym_client_core::config::old_config_v1_1_13::OldConfigV1_1_13 as OldBaseConfigV1_1_13;
use nym_config::NymConfig;
use serde::{Deserialize, Serialize};
use std::path::PathBuf;
#[derive(Debug, Default, Deserialize, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct OldConfigV1_1_13 {
#[serde(flatten)]
base: OldBaseConfigV1_1_13<OldConfigV1_1_13>,
socket: Socket,
}
impl NymConfig for OldConfigV1_1_13 {
fn template() -> &'static str {
// not intended to be used
unimplemented!()
}
fn default_root_directory() -> PathBuf {
dirs::home_dir()
.expect("Failed to evaluate $HOME value")
.join(".nym")
.join("clients")
}
fn try_default_root_directory() -> Option<PathBuf> {
dirs::home_dir().map(|path| path.join(".nym").join("clients"))
}
fn root_directory(&self) -> PathBuf {
self.base.client.nym_root_directory.clone()
}
fn config_directory(&self) -> PathBuf {
self.root_directory()
.join(&self.base.client.id)
.join("config")
}
fn data_directory(&self) -> PathBuf {
self.root_directory()
.join(&self.base.client.id)
.join("data")
}
}
impl From<OldConfigV1_1_13> for Config {
fn from(value: OldConfigV1_1_13) -> Self {
Config {
base: value.base.into(),
socket: value.socket,
}
}
}
+9 -4
View File
@@ -110,10 +110,15 @@ host = '{{ socket.host }}'
[debug]
average_packet_delay = '{{ debug.average_packet_delay }}'
average_ack_delay = '{{ debug.average_ack_delay }}'
loop_cover_traffic_average_delay = '{{ debug.loop_cover_traffic_average_delay }}'
message_sending_average_delay = '{{ debug.message_sending_average_delay }}'
[debug.traffic]
average_packet_delay = '{{ debug.traffic.average_packet_delay }}'
message_sending_average_delay = '{{ debug.traffic.message_sending_average_delay }}'
[debug.acknowledgements]
average_ack_delay = '{{ debug.acknowledgements.average_ack_delay }}'
[debug.cover_traffic]
loop_cover_traffic_average_delay = '{{ debug.cover_traffic.loop_cover_traffic_average_delay }}'
"#
}
+24 -16
View File
@@ -1,31 +1,33 @@
// Copyright 2021-2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use std::error::Error;
use crate::client::config::Config;
use crate::error::ClientError;
use crate::websocket;
use client_core::client::base_client::{
use futures::channel::mpsc;
use log::*;
use nym_bandwidth_controller::BandwidthController;
use nym_client_core::client::base_client::{
non_wasm_helpers, BaseClientBuilder, ClientInput, ClientOutput, ClientState,
};
use client_core::client::inbound_messages::InputMessage;
use client_core::client::received_buffer::{
use nym_client_core::client::inbound_messages::InputMessage;
use nym_client_core::client::received_buffer::{
ReceivedBufferMessage, ReceivedBufferRequestSender, ReconstructedMessagesReceiver,
};
use client_core::config::persistence::key_pathfinder::ClientKeyPathfinder;
use futures::channel::mpsc;
use gateway_client::bandwidth::BandwidthController;
use log::*;
use nym_client_core::config::persistence::key_pathfinder::ClientKeyPathfinder;
use nym_sphinx::anonymous_replies::requests::AnonymousSenderTag;
use nym_task::connections::TransmissionLane;
use nym_task::TaskManager;
use nym_validator_client::nyxd::QueryNyxdClient;
use std::error::Error;
use tokio::sync::watch::error::SendError;
use validator_client::nyxd::QueryNyxdClient;
pub use client_core::client::key_manager::KeyManager;
pub use nym_client_core::client::key_manager::KeyManager;
use nym_credential_storage::persistent_storage::PersistentStorage;
pub use nym_sphinx::addressing::clients::Recipient;
pub use nym_sphinx::receiver::ReconstructedMessage;
use nym_validator_client::Client;
pub mod config;
pub struct SocketClient {
@@ -55,10 +57,13 @@ impl SocketClient {
}
}
async fn create_bandwidth_controller(config: &Config) -> BandwidthController<QueryNyxdClient> {
async fn create_bandwidth_controller(
config: &Config,
) -> BandwidthController<Client<QueryNyxdClient>, PersistentStorage> {
let details = nym_network_defaults::NymNetworkDetails::new_from_env();
let mut client_config = validator_client::Config::try_from_nym_network_details(&details)
.expect("failed to construct validator client config");
let mut client_config =
nym_validator_client::Config::try_from_nym_network_details(&details)
.expect("failed to construct validator client config");
let nyxd_url = config
.get_base()
.get_validator_endpoints()
@@ -71,10 +76,13 @@ impl SocketClient {
.expect("No validator api endpoint provided");
// overwrite env configuration with config URLs
client_config = client_config.with_urls(nyxd_url, api_url);
let client = validator_client::Client::new_query(client_config)
let client = nym_validator_client::Client::new_query(client_config)
.expect("Could not construct query client");
BandwidthController::new(
nym_credential_storage::initialise_storage(config.get_base().get_database_path()).await,
nym_credential_storage::initialise_persistent_storage(
config.get_base().get_database_path(),
)
.await,
client,
)
}
+23 -21
View File
@@ -1,13 +1,16 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::commands::try_upgrade_v1_1_13_config;
use crate::{
client::config::Config,
commands::{override_config, OverrideConfig},
error::ClientError,
};
use clap::Args;
use nym_bin_common::output_format::OutputFormat;
use nym_config::NymConfig;
use nym_credential_storage::persistent_storage::PersistentStorage;
use nym_crypto::asymmetric::identity;
use nym_sphinx::addressing::clients::Recipient;
use serde::Serialize;
@@ -70,9 +73,8 @@ pub(crate) struct Init {
#[clap(long, hide = true)]
enabled_credentials_mode: Option<bool>,
/// Save a summary of the initialization to a json file
#[clap(long)]
output_json: bool,
#[clap(short, long, default_value_t = OutputFormat::default())]
output: OutputFormat,
}
impl From<Init> for OverrideConfig {
@@ -94,15 +96,17 @@ impl From<Init> for OverrideConfig {
#[derive(Debug, Serialize)]
pub struct InitResults {
#[serde(flatten)]
client_core: client_core::init::InitResults,
client_core: nym_client_core::init::InitResults,
client_listening_port: String,
client_address: String,
}
impl InitResults {
fn new(config: &Config, address: &Recipient) -> Self {
Self {
client_core: client_core::init::InitResults::new(config.get_base(), address),
client_core: nym_client_core::init::InitResults::new(config.get_base(), address),
client_listening_port: config.get_listening_port().to_string(),
client_address: address.to_string(),
}
}
}
@@ -110,25 +114,29 @@ impl InitResults {
impl Display for InitResults {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
writeln!(f, "{}", self.client_core)?;
write!(f, "Client listening port: {}", self.client_listening_port)
writeln!(f, "Client listening port: {}", self.client_listening_port)?;
write!(f, "Address of this client: {}", self.client_address)
}
}
pub(crate) async fn execute(args: &Init) -> Result<(), ClientError> {
println!("Initialising client...");
eprintln!("Initialising client...");
let id = &args.id;
let already_init = Config::default_config_file_path(id).exists();
if already_init {
println!("Client \"{id}\" was already initialised before");
// in case we're using old config, try to upgrade it
// (if we're using the current version, it's a no-op)
try_upgrade_v1_1_13_config(id)?;
eprintln!("Client \"{id}\" was already initialised before");
}
// Usually you only register with the gateway on the first init, however you can force
// re-registering if wanted.
let user_wants_force_register = args.force_register_gateway;
if user_wants_force_register {
println!("Instructed to force registering gateway. This might overwrite keys!");
eprintln!("Instructed to force registering gateway. This might overwrite keys!");
}
// If the client was already initialized, don't generate new keys and don't re-register with
@@ -144,7 +152,7 @@ pub(crate) async fn execute(args: &Init) -> Result<(), ClientError> {
// 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 gateway = client_core::init::setup_gateway_from_config::<Config, _>(
let gateway = nym_client_core::init::setup_gateway_from_config::<Config, _, PersistentStorage>(
register_gateway,
user_chosen_gateway_id,
config.get_base(),
@@ -161,28 +169,22 @@ pub(crate) async fn execute(args: &Init) -> Result<(), ClientError> {
print_saved_config(&config);
let address = client_core::init::get_client_address_from_stored_keys(config.get_base())?;
let address = nym_client_core::init::get_client_address_from_stored_keys(config.get_base())?;
let init_results = InitResults::new(&config, &address);
println!("{init_results}");
println!("{}", args.output.format(&init_results));
// Output summary to a json file, if specified
if args.output_json {
client_core::init::output_to_json(&init_results, "client_init_results.json");
}
println!("\nThe address of this client is: {address}\n");
Ok(())
}
fn print_saved_config(config: &Config) {
let config_save_location = config.get_config_file_save_location();
println!("Saved configuration file to {config_save_location:?}");
println!("Using gateway: {}", config.get_base().get_gateway_id());
eprintln!("Saved configuration file to {config_save_location:?}");
eprintln!("Using gateway: {}", config.get_base().get_gateway_id());
log::debug!("Gateway id: {}", config.get_base().get_gateway_id());
log::debug!("Gateway owner: {}", config.get_base().get_gateway_owner());
log::debug!(
"Gateway listener: {}",
config.get_base().get_gateway_listener()
);
println!("Client configuration completed.\n");
eprintln!("Client configuration completed.\n");
}
+17 -1
View File
@@ -1,13 +1,15 @@
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::client::config::old_config_v1_1_13::OldConfigV1_1_13;
use crate::client::config::{BaseConfig, Config};
use clap::CommandFactory;
use clap::{Parser, Subcommand};
use lazy_static::lazy_static;
use log::info;
use nym_bin_common::build_information::BinaryBuildInformation;
use nym_bin_common::completions::{fig_generate, ArgShell};
use nym_config::OptionalSet;
use nym_config::{NymConfig, OptionalSet};
use std::error::Error;
use std::net::IpAddr;
@@ -102,6 +104,20 @@ pub(crate) fn override_config(config: Config, args: OverrideConfig) -> Config {
)
}
fn try_upgrade_v1_1_13_config(id: &str) -> std::io::Result<()> {
// explicitly load it as v1.1.13 (which is incompatible with the current, i.e. 1.1.14+)
let Ok(old_config) = OldConfigV1_1_13::load_from_file(id) else {
// if we failed to load it, there might have been nothing to upgrade
// or maybe it was an even older file. in either way. just ignore it and carry on with our day
return Ok(());
};
info!("It seems the client is using <= v1.1.13 config template.");
info!("It is going to get updated to the current specification.");
let updated: Config = old_config.into();
updated.save_to_file(None)
}
#[cfg(test)]
mod tests {
use super::*;
+9 -1
View File
@@ -4,12 +4,12 @@
use std::error::Error;
use std::net::IpAddr;
use crate::commands::try_upgrade_v1_1_13_config;
use crate::{
client::{config::Config, SocketClient},
commands::{override_config, OverrideConfig},
error::ClientError,
};
use clap::Args;
use log::*;
use nym_bin_common::version_checker::is_minor_version_compatible;
@@ -100,6 +100,10 @@ fn version_check(cfg: &Config) -> bool {
pub(crate) async fn execute(args: &Run) -> Result<(), Box<dyn Error + Send + Sync>> {
let id = &args.id;
// in case we're using old config, try to upgrade it
// (if we're using the current version, it's a no-op)
try_upgrade_v1_1_13_config(id)?;
let mut config = match Config::load_from_file(id) {
Ok(cfg) => cfg,
Err(err) => {
@@ -108,6 +112,10 @@ pub(crate) async fn execute(args: &Run) -> Result<(), Box<dyn Error + Send + Syn
}
};
if !config.validate() {
return Err(Box::new(ClientError::ConfigValidationFailure));
}
let override_config_fields = OverrideConfig::from(args.clone());
config = override_config(config, override_config_fields);
+5 -1
View File
@@ -1,4 +1,4 @@
use client_core::error::ClientCoreError;
use nym_client_core::error::ClientCoreError;
#[derive(thiserror::Error, Debug)]
pub enum ClientError {
@@ -11,6 +11,10 @@ pub enum ClientError {
#[error("Failed to load config for: {0}")]
FailedToLoadConfig(String),
// TODO: add more details here
#[error("Failed to validate the loaded config")]
ConfigValidationFailure,
#[error("Failed local version check, client and config mismatch")]
FailedLocalVersionCheck,
+2 -2
View File
@@ -4,7 +4,7 @@
use std::error::Error;
use clap::{crate_name, crate_version, Parser};
use nym_bin_common::logging::{banner, setup_logging};
use nym_bin_common::logging::{maybe_print_banner, setup_logging};
use nym_network_defaults::setup_env;
pub mod client;
@@ -15,7 +15,7 @@ pub mod websocket;
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
setup_logging();
println!("{}", banner(crate_name!(), crate_version!()));
maybe_print_banner(crate_name!(), crate_version!());
let args = commands::Cli::parse();
setup_env(args.config_env_file.as_ref());
+6 -6
View File
@@ -1,16 +1,17 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use client_core::client::replies::reply_controller::requests::ReplyControllerSender;
use client_core::client::{
use futures::channel::mpsc;
use futures::{SinkExt, StreamExt};
use log::*;
use nym_client_core::client::replies::reply_controller::requests::ReplyControllerSender;
use nym_client_core::client::{
inbound_messages::{InputMessage, InputMessageSender},
received_buffer::{
ReceivedBufferMessage, ReceivedBufferRequestSender, ReconstructedMessagesReceiver,
},
};
use futures::channel::mpsc;
use futures::{SinkExt, StreamExt};
use log::*;
use nym_client_websocket_requests::{requests::ClientRequest, responses::ServerResponse};
use nym_sphinx::addressing::clients::Recipient;
use nym_sphinx::anonymous_replies::requests::AnonymousSenderTag;
use nym_sphinx::receiver::ReconstructedMessage;
@@ -25,7 +26,6 @@ use tokio_tungstenite::{
tungstenite::{protocol::Message as WsMessage, Error as WsError},
WebSocketStream,
};
use websocket_requests::{requests::ClientRequest, responses::ServerResponse};
#[derive(Default)]
enum ReceivedResponseType {
+3 -3
View File
@@ -1,5 +1,5 @@
[package]
name = "websocket-requests"
name = "nym-client-websocket-requests"
version = "0.1.0"
authors = ["Jędrzej Stuczyński <andrew@nymtech.net>"]
edition = "2021"
@@ -7,7 +7,7 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true }
nym-sphinx = { path = "../../../common/nymsphinx" }
+7 -22
View File
@@ -1,24 +1,16 @@
[package]
name = "nym-socks5-client"
version = "1.1.12"
version = "1.1.16"
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"
rust-version = "1.56"
[lib]
name = "nym_socks5"
path = "src/lib.rs"
[dependencies]
clap = { version = "4.0", features = ["cargo", "derive"] }
dirs = "4.0"
futures = "0.3"
lazy_static = "1.4.0"
log = { workspace = true }
pin-project = "1.0"
pretty_env_logger = "0.4"
rand = { version = "0.7.3", features = ["wasm-bindgen"] }
serde = { workspace = true, features = ["derive"] } # for config serialization/deserialization
serde_json = { workspace = true }
tap = "1.0.1"
@@ -27,28 +19,21 @@ tokio = { version = "1.24.1", features = ["rt-multi-thread", "net", "signal"] }
url = "2.2"
# internal
nym-bin-common = { path = "../../common/bin-common" }
client-core = { path = "../client-core", features = ["fs-surb-storage"] }
nym-bin-common = { path = "../../common/bin-common", features = ["output_format"] }
nym-client-core = { path = "../../common/client-core", features = ["fs-surb-storage"] }
nym-coconut-interface = { path = "../../common/coconut-interface" }
nym-config = { path = "../../common/config" }
nym-credential-storage = { path = "../../common/credential-storage", optional = true }
mobile-storage = { path = "../../common/mobile-storage", optional = true }
nym-credentials = { path = "../../common/credentials" }
nym-crypto = { path = "../../common/crypto" }
gateway-client = { path = "../../common/client-libs/gateway-client" }
gateway-requests = { path = "../../gateway/gateway-requests" }
nym-gateway-requests = { path = "../../gateway/gateway-requests" }
nym-credential-storage = { path = "../../common/credential-storage" }
nym-network-defaults = { path = "../../common/network-defaults" }
nym-sphinx = { path = "../../common/nymsphinx" }
nym-ordered-buffer = { path = "../../common/socks5/ordered-buffer" }
nym-pemstore = { path = "../../common/pemstore" }
nym-socks5-proxy-helpers = { path = "../../common/socks5/proxy-helpers" }
nym-service-providers-common = { path = "../../service-providers/common" }
nym-socks5-requests = { path = "../../common/socks5/requests" }
nym-task = { path = "../../common/task" }
nym-topology = { path = "../../common/topology" }
validator-client = { path = "../../common/client-libs/validator-client", features = ["nyxd-client"] }
nym-socks5-client-core = { path = "../../common/socks5-client-core" }
[features]
default = ["nym-credential-storage"]
default = []
eth = []
mobile = ["mobile-storage", "gateway-client/mobile"]
+26 -24
View File
@@ -1,14 +1,17 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::commands::try_upgrade_v1_1_13_config;
use crate::{
client::config::Config,
commands::{override_config, OverrideConfig},
error::Socks5ClientError,
};
use clap::Args;
use nym_bin_common::output_format::OutputFormat;
use nym_config::NymConfig;
use nym_credential_storage::persistent_storage::PersistentStorage;
use nym_crypto::asymmetric::identity;
use nym_socks5_client_core::config::Config;
use nym_sphinx::addressing::clients::Recipient;
use serde::Serialize;
use std::fmt::Display;
@@ -74,9 +77,8 @@ pub(crate) struct Init {
#[clap(long, hide = true)]
enabled_credentials_mode: Option<bool>,
/// Save a summary of the initialization to a json file
#[clap(long)]
output_json: bool,
#[clap(short, long, default_value_t = OutputFormat::default())]
output: OutputFormat,
}
impl From<Init> for OverrideConfig {
@@ -96,15 +98,17 @@ impl From<Init> for OverrideConfig {
#[derive(Debug, Serialize)]
pub struct InitResults {
#[serde(flatten)]
client_core: client_core::init::InitResults,
client_core: nym_client_core::init::InitResults,
socks5_listening_port: String,
client_address: String,
}
impl InitResults {
fn new(config: &Config, address: &Recipient) -> Self {
Self {
client_core: client_core::init::InitResults::new(config.get_base(), address),
socks5_listening_port: config.get_listening_port().to_string(),
client_core: nym_client_core::init::InitResults::new(config.get_base(), address),
socks5_listening_port: config.get_socks5().get_listening_port().to_string(),
client_address: address.to_string(),
}
}
}
@@ -112,26 +116,30 @@ impl InitResults {
impl Display for InitResults {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
writeln!(f, "{}", self.client_core)?;
write!(f, "SOCKS5 listening port: {}", self.socks5_listening_port)
writeln!(f, "SOCKS5 listening port: {}", self.socks5_listening_port)?;
write!(f, "Address of this client: {}", self.client_address)
}
}
pub(crate) async fn execute(args: &Init) -> Result<(), Socks5ClientError> {
println!("Initialising client...");
eprintln!("Initialising client...");
let id = &args.id;
let provider_address = &args.provider;
let already_init = Config::default_config_file_path(id).exists();
if already_init {
println!("SOCKS5 client \"{id}\" was already initialised before");
// in case we're using old config, try to upgrade it
// (if we're using the current version, it's a no-op)
try_upgrade_v1_1_13_config(id)?;
eprintln!("SOCKS5 client \"{id}\" was already initialised before");
}
// Usually you only register with the gateway on the first init, however you can force
// re-registering if wanted.
let user_wants_force_register = args.force_register_gateway;
if user_wants_force_register {
println!("Instructed to force registering gateway. This might overwrite keys!");
eprintln!("Instructed to force registering gateway. This might overwrite keys!");
}
// If the client was already initialized, don't generate new keys and don't re-register with
@@ -150,7 +158,7 @@ pub(crate) async fn execute(args: &Init) -> Result<(), Socks5ClientError> {
// 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 gateway = client_core::init::setup_gateway_from_config::<Config, _>(
let gateway = nym_client_core::init::setup_gateway_from_config::<Config, _, PersistentStorage>(
register_gateway,
user_chosen_gateway_id,
config.get_base(),
@@ -169,28 +177,22 @@ pub(crate) async fn execute(args: &Init) -> Result<(), Socks5ClientError> {
print_saved_config(&config);
let address = client_core::init::get_client_address_from_stored_keys(config.get_base())?;
let address = nym_client_core::init::get_client_address_from_stored_keys(config.get_base())?;
let init_results = InitResults::new(&config, &address);
println!("{}", init_results);
println!("{}", args.output.format(&init_results));
// Output summary to a json file, if specified
if args.output_json {
client_core::init::output_to_json(&init_results, "socks5_client_init_results.json");
}
println!("\nThe address of this client is: {}\n", address);
Ok(())
}
fn print_saved_config(config: &Config) {
let config_save_location = config.get_config_file_save_location();
println!("Saved configuration file to {:?}", config_save_location);
println!("Using gateway: {}", config.get_base().get_gateway_id());
eprintln!("Saved configuration file to {:?}", config_save_location);
eprintln!("Using gateway: {}", config.get_base().get_gateway_id());
log::debug!("Gateway id: {}", config.get_base().get_gateway_id());
log::debug!("Gateway owner: {}", config.get_base().get_gateway_owner());
log::debug!(
"Gateway listener: {}",
config.get_base().get_gateway_listener()
);
println!("Client configuration completed.\n");
eprintln!("Client configuration completed.\n");
}
+18 -2
View File
@@ -1,13 +1,15 @@
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::client::config::{BaseConfig, Config};
use clap::CommandFactory;
use clap::{Parser, Subcommand};
use lazy_static::lazy_static;
use log::info;
use nym_bin_common::build_information::BinaryBuildInformation;
use nym_bin_common::completions::{fig_generate, ArgShell};
use nym_config::OptionalSet;
use nym_config::{NymConfig, OptionalSet};
use nym_socks5_client_core::config::old_config_v1_1_13::OldConfigV1_1_13;
use nym_socks5_client_core::config::{BaseConfig, Config};
use std::error::Error;
pub mod init;
@@ -101,6 +103,20 @@ pub(crate) fn override_config(config: Config, args: OverrideConfig) -> Config {
)
}
fn try_upgrade_v1_1_13_config(id: &str) -> std::io::Result<()> {
// explicitly load it as v1.1.13 (which is incompatible with the current, i.e. 1.1.14+)
let Ok(old_config) = OldConfigV1_1_13::load_from_file(id) else {
// if we failed to load it, there might have been nothing to upgrade
// or maybe it was an even older file. in either way. just ignore it and carry on with our day
return Ok(());
};
info!("It seems the client is using <= v1.1.13 config template.");
info!("It is going to get updated to the current specification.");
let updated: Config = old_config.into();
updated.save_to_file(None)
}
#[cfg(test)]
mod tests {
use super::*;
+10 -2
View File
@@ -1,17 +1,17 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::commands::try_upgrade_v1_1_13_config;
use crate::{
client::{config::Config, NymClient},
commands::{override_config, OverrideConfig},
error::Socks5ClientError,
};
use clap::Args;
use log::*;
use nym_bin_common::version_checker::is_minor_version_compatible;
use nym_config::NymConfig;
use nym_crypto::asymmetric::identity;
use nym_socks5_client_core::{config::Config, NymClient};
use nym_sphinx::addressing::clients::Recipient;
#[derive(Args, Clone)]
@@ -108,6 +108,10 @@ fn version_check(cfg: &Config) -> bool {
pub(crate) async fn execute(args: &Run) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let id = &args.id;
// in case we're using old config, try to upgrade it
// (if we're using the current version, it's a no-op)
try_upgrade_v1_1_13_config(id)?;
let mut config = match Config::load_from_file(id) {
Ok(cfg) => cfg,
Err(err) => {
@@ -118,6 +122,10 @@ pub(crate) async fn execute(args: &Run) -> Result<(), Box<dyn std::error::Error
}
};
if !config.validate() {
return Err(Box::new(Socks5ClientError::ConfigValidationFailure));
}
let override_config_fields = OverrideConfig::from(args.clone());
config = override_config(config, override_config_fields);
+1 -2
View File
@@ -1,10 +1,9 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::client::config::{Config, MISSING_VALUE};
use nym_bin_common::version_checker::Version;
use nym_config::NymConfig;
use nym_socks5_client_core::config::{Config, MISSING_VALUE};
use clap::Args;
use std::{fmt::Display, process};
+7 -23
View File
@@ -1,39 +1,23 @@
use crate::socks::types::SocksProxyError;
use client_core::error::ClientCoreError;
use nym_socks5_requests::{ConnectionError, ConnectionId};
use nym_client_core::error::ClientCoreError;
#[derive(thiserror::Error, Debug)]
pub enum Socks5ClientError {
#[error("I/O error: {0}")]
IoError(#[from] std::io::Error),
#[error("client-core error: {0}")]
ClientCoreError(#[from] ClientCoreError),
#[error("SOCKS proxy error")]
SocksProxyError(SocksProxyError),
#[error("Failed to load config for: {0}")]
FailedToLoadConfig(String),
// TODO: add more details here
#[error("Failed to validate the loaded config")]
ConfigValidationFailure,
#[error("Failed local version check, client and config mismatch")]
FailedLocalVersionCheck,
#[error("Fail to bind address")]
FailToBindAddress,
#[error("Network requester: connection id {connection_id}: {error}")]
NetworkRequesterError {
connection_id: ConnectionId,
error: String,
},
}
impl From<ConnectionError> for Socks5ClientError {
fn from(value: ConnectionError) -> Self {
Socks5ClientError::NetworkRequesterError {
connection_id: value.connection_id,
error: value.network_requester_error,
}
}
#[error("client-core error: {0}")]
ClientCoreError(#[from] ClientCoreError),
}
-6
View File
@@ -1,6 +0,0 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
pub mod client;
pub mod error;
pub mod socks;
+2 -4
View File
@@ -4,18 +4,16 @@
use std::error::Error;
use clap::{crate_name, crate_version, Parser};
use nym_bin_common::logging::{banner, setup_logging};
use nym_bin_common::logging::{maybe_print_banner, setup_logging};
use nym_network_defaults::setup_env;
pub mod client;
mod commands;
pub mod error;
pub mod socks;
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
setup_logging();
println!("{}", banner(crate_name!(), crate_version!()));
maybe_print_banner(crate_name!(), crate_version!());
let args = commands::Cli::parse();
setup_env(args.config_env_file.as_ref());
+1 -1
View File
@@ -48,7 +48,7 @@
"eslint-plugin-mocha": "^10.0.3",
"eslint-plugin-prettier": "^4.0.0",
"mocha": "^10.0.0",
"prettier": "^2.5.1",
"prettier": "^2.8.7",
"ts-mocha": "^10.0.0",
"typedoc": "^0.22.13",
"typescript": "^4.6.2",
+111 -7
View File
@@ -22,6 +22,7 @@ import {
MixNodeDetails,
MixNodeRewarding,
MixOwnershipResponse,
OriginalVestingResponse,
PagedAllDelegationsResponse,
PagedDelegatorDelegationsResponse,
PagedGatewayResponse,
@@ -32,10 +33,12 @@ import {
RewardingParams,
StakeSaturationResponse,
UnbondedMixnodeResponse,
VestingAccountInfo,
ContractState, VestingAccountsCoinPaged, VestingAccountsPaged, DelegationTimes, Delegations, Period, VestingAccountNode, DelegationBlock
} from '@nymproject/types';
import QueryClient from './query-client';
import SigningClient, { ISigningClient } from './signing-client';
import { ContractState } from './types/shared';
// import { DelegationBlock } from './types/shared';
export interface INymClient {
readonly mixnetContract: string;
@@ -204,7 +207,7 @@ export default class ValidatorClient implements INymClient {
let mixNodes: UnbondedMixnodeResponse[] = [];
const limit = 50;
let startAfter;
for (;;) {
for (; ;) {
// eslint-disable-next-line no-await-in-loop
const pagedResponse: PagedUnbondedMixnodesResponse = await this.client.getUnbondedMixNodes(
this.mixnetContract,
@@ -227,7 +230,7 @@ export default class ValidatorClient implements INymClient {
let mixNodes: MixNodeBond[] = [];
const limit = 50;
let startAfter;
for (;;) {
for (; ;) {
// eslint-disable-next-line no-await-in-loop
const pagedResponse: PagedMixNodeBondResponse = await this.client.getMixNodeBonds(
this.mixnetContract,
@@ -249,7 +252,7 @@ export default class ValidatorClient implements INymClient {
let mixNodes: MixNodeDetails[] = [];
const limit = 50;
let startAfter;
for (;;) {
for (; ;) {
// eslint-disable-next-line no-await-in-loop
const pagedResponse: PagedMixNodeDetailsResponse = await this.client.getMixNodesDetailed(
this.mixnetContract,
@@ -281,7 +284,7 @@ export default class ValidatorClient implements INymClient {
let delegations: Delegation[] = [];
const limit = 250;
let startAfter;
for (;;) {
for (; ;) {
// eslint-disable-next-line no-await-in-loop
const pagedResponse: PagedMixDelegationsResponse = await this.client.getMixNodeDelegationsPaged(
this.mixnetContract,
@@ -304,7 +307,7 @@ export default class ValidatorClient implements INymClient {
let delegations: Delegation[] = [];
const limit = 250;
let startAfter;
for (;;) {
for (; ;) {
// eslint-disable-next-line no-await-in-loop
const pagedResponse: PagedDelegatorDelegationsResponse = await this.client.getDelegatorDelegationsPaged(
this.mixnetContract,
@@ -327,7 +330,7 @@ export default class ValidatorClient implements INymClient {
let delegations: Delegation[] = [];
const limit = 250;
let startAfter;
for (;;) {
for (; ;) {
// eslint-disable-next-line no-await-in-loop
const pagedResponse: PagedAllDelegationsResponse = await this.client.getAllDelegationsPaged(
this.mixnetContract,
@@ -514,4 +517,105 @@ export default class ValidatorClient implements INymClient {
this.assertSigning();
return (this.client as ISigningClient).updateContractStateParams(this.mixnetContract, newParams, fee, memo);
}
// VESTING
// TODO - MOVE TO A DIFFERENT FILE
public async getVestingAccountsPaged(): Promise<VestingAccountsPaged> {
return this.client.getVestingAccountsPaged(this.vestingContract);
}
public async getVestingAmountsAccountsPaged(): Promise<VestingAccountsCoinPaged> {
return this.client.getVestingAmountsAccountsPaged(this.vestingContract);
}
public async getLockedTokens(vestingAccountAddress: string): Promise<Coin> {
return this.client.getLockedTokens(this.vestingContract, vestingAccountAddress);
}
public async getSpendableTokens(vestingAccountAddress: string): Promise<Coin> {
return this.client.getSpendableTokens(this.vestingContract, vestingAccountAddress);
}
public async getVestedTokens(vestingAccountAddress: string): Promise<Coin> {
return this.client.getVestedTokens(this.vestingContract, vestingAccountAddress);
}
public async getVestingTokens(vestingAccountAddress: string): Promise<Coin> {
return this.client.getVestingTokens(this.vestingContract, vestingAccountAddress);
}
public async getSpendableVestedTokens(vestingAccountAddress: string): Promise<Coin> {
return this.client.getSpendableVestedTokens(this.vestingContract, vestingAccountAddress);
}
public async getSpendableRewards(vestingAccountAddress: string): Promise<Coin> {
return this.client.getSpendableRewards(this.vestingContract, vestingAccountAddress);
}
public async getDelegatedCoins(vestingAccountAddress: string): Promise<Coin> {
return this.client.getDelegatedCoins(this.vestingContract, vestingAccountAddress);
}
public async getPledgedCoins(vestingAccountAddress: string): Promise<Coin> {
return this.client.getPledgedCoins(this.vestingContract, vestingAccountAddress);
}
public async getStakedCoins(vestingAccountAddress: string): Promise<Coin> {
return this.client.getStakedCoins(this.vestingContract, vestingAccountAddress);
}
public async getWithdrawnCoins(vestingAccountAddress: string): Promise<Coin> {
return this.client.getWithdrawnCoins(this.vestingContract, vestingAccountAddress);
}
public async getStartTime(vestingAccountAddress: string): Promise<string> {
return this.client.getStartTime(this.vestingContract, vestingAccountAddress);
}
public async getEndTime(vestingAccountAddress: string): Promise<string> {
return this.client.getEndTime(this.vestingContract, vestingAccountAddress);
}
public async getOriginalVestingDetails(vestingAccountAddress: string): Promise<OriginalVestingResponse> {
return this.client.getOriginalVestingDetails(this.vestingContract, vestingAccountAddress);
}
public async getHistoricStakingRewards(vestingAccountAddress: string): Promise<Coin> {
return this.client.getHistoricStakingRewards(this.vestingContract, vestingAccountAddress);
}
public async getAccountDetails(address: string): Promise<VestingAccountInfo> {
return this.client.getAccountDetails(this.vestingContract, address);
}
public async getMixnode(address: string): Promise<VestingAccountNode> {
return this.client.getMixnode(this.vestingContract, address);
}
public async getGateway(address: string): Promise<VestingAccountNode> {
return this.client.getGateway(this.vestingContract, address);
}
public async getDelegationTimes(mix_id: number, delegatorAddress: string): Promise<DelegationTimes> {
return this.client.getDelegationTimes(this.vestingContract, mix_id, delegatorAddress);
}
public async getAllDelegations(): Promise<Delegations> {
return this.client.getAllDelegations(this.vestingContract);
}
public async getDelegation(address: string, mix_id: number): Promise<DelegationBlock> {
return this.client.getDelegation(this.vestingContract, address, mix_id );
}
public async getTotalDelegationAmount(address: string, mix_id: number, block_timestamp_sec: number): Promise<Coin> {
return this.client.getTotalDelegationAmount(this.vestingContract, address, mix_id, block_timestamp_sec);
}
public async getCurrentVestingPeriod(address: string): Promise<Period> {
return this.client.getCurrentVestingPeriod(this.vestingContract, address);
}
}
+148 -2
View File
@@ -4,8 +4,8 @@
*/
// eslint-disable-next-line import/no-cycle
import { INyxdQuery } from './query-client';
import { Delegation, RewardingParams, StakeSaturationResponse } from '@nymproject/types';
import {
Delegation, OriginalVestingResponse, RewardingParams, StakeSaturationResponse, VestingAccountInfo,
UnbondedMixnodeResponse,
GatewayOwnershipResponse,
MixnetContractVersion,
@@ -18,8 +18,10 @@ import {
PagedMixNodeDetailsResponse,
PagedUnbondedMixnodesResponse,
LayerDistribution,
ContractState, VestingAccountsCoinPaged, VestingAccountsPaged, DelegationTimes, Delegations, Period, VestingAccountNode, DelegationBlock
} from '@nymproject/types';
import { ContractState, SmartContractQuery } from './types/shared';
import { SmartContractQuery } from './types/shared';
import { Coin } from 'cosmjs-types/cosmos/base/v1beta1/coin';
export default class NyxdQuerier implements INyxdQuery {
client: SmartContractQuery;
@@ -188,4 +190,148 @@ export default class NyxdQuerier implements INyxdQuery {
vesting_account_address: vestingAccountAddress,
});
}
getVestingAccountsPaged(vestingContractAddress: string): Promise<VestingAccountsPaged> {
return this.client.queryContractSmart(vestingContractAddress, {
get_accounts_paged: {}
});
}
getVestingAmountsAccountsPaged(vestingContractAddress: string): Promise<VestingAccountsCoinPaged> {
return this.client.queryContractSmart(vestingContractAddress, {
get_accounts_vesting_coins_paged: {}
});
}
getLockedTokens(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
return this.client.queryContractSmart(vestingContractAddress, {
locked_coins: { vesting_account_address: vestingAccountAddress }
});
}
getSpendableTokens(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
return this.client.queryContractSmart(vestingContractAddress, {
spendable_coins: { vesting_account_address: vestingAccountAddress }
});
}
getVestedTokens(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
return this.client.queryContractSmart(vestingContractAddress, {
get_vested_coins: { vesting_account_address: vestingAccountAddress }
});
}
getVestingTokens(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
return this.client.queryContractSmart(vestingContractAddress, {
get_vesting_coins: { vesting_account_address: vestingAccountAddress }
});
}
getSpendableVestedTokens(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
return this.client.queryContractSmart(vestingContractAddress, {
get_spendable_vested_coins: { vesting_account_address: vestingAccountAddress }
});
}
getSpendableRewards(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
return this.client.queryContractSmart(vestingContractAddress, {
get_spendable_reward_coins: { vesting_account_address: vestingAccountAddress }
});
}
getDelegatedCoins(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
return this.client.queryContractSmart(vestingContractAddress, {
get_delegated_coins: { vesting_account_address: vestingAccountAddress }
});
}
getPledgedCoins(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
return this.client.queryContractSmart(vestingContractAddress, {
get_pledged_coins: { vesting_account_address: vestingAccountAddress }
});
}
getStakedCoins(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
return this.client.queryContractSmart(vestingContractAddress, {
get_staked_coins: { vesting_account_address: vestingAccountAddress }
});
}
getWithdrawnCoins(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
return this.client.queryContractSmart(vestingContractAddress, {
get_withdrawn_coins: { vesting_account_address: vestingAccountAddress }
});
}
getStartTime(vestingContractAddress: string, vestingAccountAddress: string): Promise<string> {
return this.client.queryContractSmart(vestingContractAddress, {
get_start_time: { vesting_account_address: vestingAccountAddress }
});
}
getEndTime(vestingContractAddress: string, vestingAccountAddress: string): Promise<string> {
return this.client.queryContractSmart(vestingContractAddress, {
get_end_time: { vesting_account_address: vestingAccountAddress }
});
}
getOriginalVestingDetails(vestingContractAddress: string, vestingAccountAddress: string): Promise<OriginalVestingResponse> {
return this.client.queryContractSmart(vestingContractAddress, {
get_original_vesting: { vesting_account_address: vestingAccountAddress }
});
}
getHistoricStakingRewards(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
return this.client.queryContractSmart(vestingContractAddress, {
get_historical_vesting_staking_reward: { vesting_account_address: vestingAccountAddress }
});
}
getAccountDetails(vestingContractAddress: string, address: string): Promise<VestingAccountInfo> {
return this.client.queryContractSmart(vestingContractAddress, {
get_account: { address: address }
});
}
getMixnode(vestingContractAddress: string, address: string): Promise<VestingAccountNode> {
return this.client.queryContractSmart(vestingContractAddress, {
get_mixnode: { address: address }
});
}
getGateway(vestingContractAddress: string, address: string): Promise<VestingAccountNode> {
return this.client.queryContractSmart(vestingContractAddress, {
get_gateway: { address: address }
});
}
getDelegationTimes(vestingContractAddress: string, mix_id: number, address: string): Promise<DelegationTimes> {
return this.client.queryContractSmart(vestingContractAddress, {
get_delegation_times: { mix_id: mix_id, address: address }
});
}
getAllDelegations(vestingContractAddress: string): Promise<Delegations> {
return this.client.queryContractSmart(vestingContractAddress, {
get_all_delegations: {}
});
}
getDelegation(vestingContractAddress: string, address: string, mix_id: number): Promise<DelegationBlock> {
return this.client.queryContractSmart(vestingContractAddress, {
get_all_delegations: {address: address, mix_id: mix_id}
});
}
getTotalDelegationAmount(vestingContractAddress: string, address: string, mix_id: number, block_timestamp_sec: number): Promise<Coin> {
return this.client.queryContractSmart(vestingContractAddress, {
get_all_delegations: {address: address, mix_id: mix_id, block_timestamp_sec: block_timestamp_sec}
});
}
getCurrentVestingPeriod(vestingContractAddress: string, address: string): Promise<Period> {
return this.client.queryContractSmart(vestingContractAddress, {
get_current_vesting_period: { address: address }
});
}
}
+102 -2
View File
@@ -20,11 +20,15 @@ import {
UnbondedMixnodeResponse,
MixNodeBond,
MixNodeRewarding,
OriginalVestingResponse,
VestingAccountInfo,
ContractState, VestingAccountsCoinPaged, VestingAccountsPaged, DelegationTimes, Delegations, Period, VestingAccountNode, DelegationBlock
} from '@nymproject/types';
import NymApiQuerier, { INymApiQuery } from './nym-api-querier';
import { ContractState, ICosmWasmQuery } from './types/shared';
import { ICosmWasmQuery } from './types/shared';
import { RewardingParams } from '@nymproject/types';
import { Tendermint34Client } from '@cosmjs/tendermint-rpc';
import { Coin } from 'cosmjs-types/cosmos/base/v1beta1/coin';
export interface INyxdQuery {
// nym-specific implemented inside NymQuerier
@@ -68,7 +72,7 @@ export interface INyxdQuery {
getMixnodeRewardingDetails(mixnetContractAddress: string, mixId: number): Promise<MixNodeRewarding>;
}
export interface IQueryClient extends ICosmWasmQuery, INyxdQuery, INymApiQuery {}
export interface IQueryClient extends ICosmWasmQuery, INyxdQuery, INymApiQuery { }
export default class QueryClient extends CosmWasmClient implements IQueryClient {
private nyxdQuerier: NyxdQuerier;
@@ -199,4 +203,100 @@ export default class QueryClient extends CosmWasmClient implements IQueryClient
getSpendableCoins(vestingContractAddress: string, vestingAccountAddress: string): Promise<any> {
return this.nyxdQuerier.getSpendableCoins(vestingContractAddress, vestingAccountAddress);
}
getVestingAccountsPaged(vestingContractAddress: string): Promise<VestingAccountsPaged> {
return this.nyxdQuerier.getVestingAccountsPaged(vestingContractAddress);
}
getVestingAmountsAccountsPaged(vestingContractAddress: string): Promise<VestingAccountsCoinPaged> {
return this.nyxdQuerier.getVestingAmountsAccountsPaged(vestingContractAddress);
}
getLockedTokens(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
return this.nyxdQuerier.getLockedTokens(vestingContractAddress, vestingAccountAddress);
}
getSpendableTokens(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
return this.nyxdQuerier.getSpendableTokens(vestingContractAddress, vestingAccountAddress);
}
getVestedTokens(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
return this.nyxdQuerier.getVestedTokens(vestingContractAddress, vestingAccountAddress);
}
getVestingTokens(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
return this.nyxdQuerier.getVestingTokens(vestingContractAddress, vestingAccountAddress);
}
getSpendableVestedTokens(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
return this.nyxdQuerier.getSpendableVestedTokens(vestingContractAddress, vestingAccountAddress);
}
getSpendableRewards(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
return this.nyxdQuerier.getSpendableRewards(vestingContractAddress, vestingAccountAddress);
}
getDelegatedCoins(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
return this.nyxdQuerier.getDelegatedCoins(vestingContractAddress, vestingAccountAddress);
}
getPledgedCoins(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
return this.nyxdQuerier.getPledgedCoins(vestingContractAddress, vestingAccountAddress);
}
getStakedCoins(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
return this.nyxdQuerier.getStakedCoins(vestingContractAddress, vestingAccountAddress);
}
getWithdrawnCoins(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
return this.nyxdQuerier.getWithdrawnCoins(vestingContractAddress, vestingAccountAddress);
}
getStartTime(vestingContractAddress: string, vestingAccountAddress: string): Promise<string> {
return this.nyxdQuerier.getStartTime(vestingContractAddress, vestingAccountAddress);
}
getEndTime(vestingContractAddress: string, vestingAccountAddress: string): Promise<string> {
return this.nyxdQuerier.getEndTime(vestingContractAddress, vestingAccountAddress);
}
getOriginalVestingDetails(vestingContractAddress: string, vestingAccountAddress: string): Promise<OriginalVestingResponse> {
return this.nyxdQuerier.getOriginalVestingDetails(vestingContractAddress, vestingAccountAddress);
}
getHistoricStakingRewards(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
return this.nyxdQuerier.getHistoricStakingRewards(vestingContractAddress, vestingAccountAddress);
}
getAccountDetails(vestingContractAddress: string, address: string): Promise<VestingAccountInfo> {
return this.nyxdQuerier.getAccountDetails(vestingContractAddress, address);
}
getMixnode(vestingContractAddress: string, address: string): Promise<VestingAccountNode> {
return this.nyxdQuerier.getMixnode(vestingContractAddress, address);
}
getGateway(vestingContractAddress: string, address: string): Promise<VestingAccountNode> {
return this.nyxdQuerier.getGateway(vestingContractAddress, address);
}
getDelegationTimes(vestingContractAddress: string, mix_id: number, delegatorAddress: string): Promise<DelegationTimes> {
return this.nyxdQuerier.getDelegationTimes(vestingContractAddress, mix_id, delegatorAddress);
}
getAllDelegations(vestingContractAddress: string): Promise<Delegations> {
return this.nyxdQuerier.getAllDelegations(vestingContractAddress);
}
getDelegation(vestingContractAddress: string, vestingAccountAddress: string, mix_id: number): Promise<DelegationBlock> {
return this.nyxdQuerier.getDelegation(vestingContractAddress, vestingAccountAddress, mix_id);
}
getTotalDelegationAmount(vestingContractAddress: string, vestingAccountAddress: string, mix_id: number, block_timestamp_sec: number): Promise<Coin> {
return this.nyxdQuerier.getTotalDelegationAmount(vestingContractAddress, vestingAccountAddress, mix_id, block_timestamp_sec);
}
getCurrentVestingPeriod(vestingContractAddress: string, address: string): Promise<Period> {
return this.nyxdQuerier.getCurrentVestingPeriod(vestingContractAddress, address);
}
}
+102 -2
View File
@@ -29,6 +29,7 @@ import {
MixNodeDetails,
MixNodeRewarding,
MixOwnershipResponse,
OriginalVestingResponse,
PagedAllDelegationsResponse,
PagedDelegatorDelegationsResponse,
PagedGatewayResponse,
@@ -38,9 +39,10 @@ import {
PagedUnbondedMixnodesResponse,
RewardingParams,
UnbondedMixnodeResponse,
VestingAccountInfo,
ContractState, VestingAccountsCoinPaged, VestingAccountsPaged, DelegationTimes, Delegations, Period, VestingAccountNode, DelegationBlock
} from '@nymproject/types';
import NymApiQuerier from './nym-api-querier';
import { ContractState } from './types/shared';
// methods exposed by `SigningCosmWasmClient`
export interface ICosmWasmSigning {
@@ -243,7 +245,7 @@ export default class SigningClient extends SigningCosmWasmClient implements ISig
// query related:
getContractVersion(mixnetContractAddress: string): Promise<MixnetContractVersion> {
return this.getContractVersion(mixnetContractAddress);
return this.nyxdQuerier.getContractVersion(mixnetContractAddress);
}
getMixNodeBonds(
@@ -508,4 +510,102 @@ export default class SigningClient extends SigningCosmWasmClient implements ISig
memo,
);
}
// vesting related
getVestingAccountsPaged(vestingContractAddress: string): Promise<VestingAccountsPaged> {
return this.nyxdQuerier.getVestingAccountsPaged(vestingContractAddress);
};
getVestingAmountsAccountsPaged(vestingContractAddress: string): Promise<VestingAccountsCoinPaged> {
return this.nyxdQuerier.getVestingAmountsAccountsPaged(vestingContractAddress);
}
getLockedTokens(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
return this.nyxdQuerier.getLockedTokens(vestingContractAddress, vestingAccountAddress);
}
getSpendableTokens(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
return this.nyxdQuerier.getSpendableTokens(vestingContractAddress, vestingAccountAddress);
}
getVestedTokens(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
return this.nyxdQuerier.getVestedTokens(vestingContractAddress, vestingAccountAddress);
}
getVestingTokens(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
return this.nyxdQuerier.getVestingTokens(vestingContractAddress, vestingAccountAddress);
}
getSpendableVestedTokens(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
return this.nyxdQuerier.getSpendableVestedTokens(vestingContractAddress, vestingAccountAddress);
}
getSpendableRewards(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
return this.nyxdQuerier.getSpendableRewards(vestingContractAddress, vestingAccountAddress);
}
getDelegatedCoins(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
return this.nyxdQuerier.getDelegatedCoins(vestingContractAddress, vestingAccountAddress);
}
getPledgedCoins(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
return this.nyxdQuerier.getPledgedCoins(vestingContractAddress, vestingAccountAddress);
}
getStakedCoins(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
return this.nyxdQuerier.getStakedCoins(vestingContractAddress, vestingAccountAddress);
}
getWithdrawnCoins(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
return this.nyxdQuerier.getWithdrawnCoins(vestingContractAddress, vestingAccountAddress);
}
getStartTime(vestingContractAddress: string, vestingAccountAddress: string): Promise<string> {
return this.nyxdQuerier.getStartTime(vestingContractAddress, vestingAccountAddress);
}
getEndTime(vestingContractAddress: string, vestingAccountAddress: string): Promise<string> {
return this.nyxdQuerier.getEndTime(vestingContractAddress, vestingAccountAddress);
}
getOriginalVestingDetails(vestingContractAddress: string, vestingAccountAddress: string): Promise<OriginalVestingResponse> {
return this.nyxdQuerier.getOriginalVestingDetails(vestingContractAddress, vestingAccountAddress);
}
getHistoricStakingRewards(vestingContractAddress: string, vestingAccountAddress: string): Promise<Coin> {
return this.nyxdQuerier.getHistoricStakingRewards(vestingContractAddress, vestingAccountAddress);
}
getAccountDetails(vestingContractAddress: string, address: string): Promise<VestingAccountInfo> {
return this.nyxdQuerier.getAccountDetails(vestingContractAddress, address);
}
getMixnode(vestingContractAddress: string, address: string): Promise<VestingAccountNode> {
return this.nyxdQuerier.getMixnode(vestingContractAddress, address);
}
getGateway(vestingContractAddress: string, address: string): Promise<VestingAccountNode> {
return this.nyxdQuerier.getGateway(vestingContractAddress, address);
}
getDelegationTimes(vestingContractAddress: string, mix_id: number, delegatorAddress: string): Promise<DelegationTimes> {
return this.nyxdQuerier.getDelegationTimes(vestingContractAddress, mix_id, delegatorAddress);
}
getAllDelegations(vestingContractAddress: string): Promise<Delegations> {
return this.nyxdQuerier.getAllDelegations(vestingContractAddress);
}
getDelegation(vestingContractAddress: string, vestingAccountAddress: string, mix_id: number): Promise<DelegationBlock> {
return this.nyxdQuerier.getDelegation(vestingContractAddress, vestingAccountAddress, mix_id);
}
getTotalDelegationAmount(vestingContractAddress: string, vestingAccountAddress: string, mix_id: number, block_timestamp_sec: number): Promise<Coin> {
return this.nyxdQuerier.getTotalDelegationAmount(vestingContractAddress, vestingAccountAddress, mix_id, block_timestamp_sec);
}
getCurrentVestingPeriod(vestingContractAddress: string, address: string): Promise<Period> {
return this.nyxdQuerier.getCurrentVestingPeriod(vestingContractAddress, address);
}
}
@@ -1,8 +1,9 @@
import { Coin } from 'cosmjs-types/cosmos/base/v1beta1/coin';
import expect from 'expect';
export const amountDemon = {
amount: expect.any(String),
denom: expect.any(String)
denom: expect.any(String),
amount: expect.any(String)
}
export const delegation = {
@@ -159,7 +160,6 @@ export const layerDistribution = {
layer3: expect.any(Number)
}
export const intervalRewardParams = {
reward_pool: expect.any(Number),
staking_supply: expect.any(Number),
@@ -176,3 +176,79 @@ export const rewardingParams = {
rewarded_set_size: expect.any(Number),
active_set_size: expect.any(Number)
}
export const VestAccounts = [{
account_id: expect.any(String),
owner: expect.any(String)
}]
export const VestAccountCoin = [{
account_id: expect.any(String),
owner: expect.any(String),
still_vesting: Coin
}]
export const vestingAccountsPaged = {
accounts: VestAccounts,
start_next_after: expect.any(String)
}
export const VestingCoinAccounts = {
accounts: VestAccountCoin,
start_next_after: expect.any(String)
}
export const OriginalVestingDetails = {
amount: Coin,
number_of_periods: expect.any(Number),
period_duration: expect.any(Number)
}
export const PledgeCap = {
percent: expect.any(String) || null,
};
export const Periods = [{
period_seconds: expect.any(Number),
start_time: expect.any(Number),
}]
export const VestingAccountDetails = {
owner_address: expect.any(String),
staking_address: expect.any(String) || null,
start_time: expect.any(String),
periods: Periods,
coin: Coin,
storage_key: expect.any(Number),
pledge_cap: PledgeCap
}
export const Node = {
amount: Coin,
block_time: expect.any(String)
}
export type VestingPeriod = 'Before' | { In: number } | 'After';
export const DelegationTimestamps = [
expect.any(Number)
]
export const DelegatorTimes = {
owner: expect.any(String),
account_id: expect.any(Number),
mix_id: expect.any(Number),
delegation_timestamps: DelegationTimestamps
}
export const DelegationBlock = [{
account_id: expect.any(Number),
amount: expect.any(String),
block_timestamp: expect.any(Number),
mix_id: expect.any(Number)
}]
export const Delegations = {
delegations: DelegationBlock,
start_next_after: expect.any(String) || null
}
@@ -1,5 +1,6 @@
import expect from 'expect';
import ValidatorClient from '../../index';
import { amountDemon, Delegations, DelegatorTimes, Node, OriginalVestingDetails, VestingAccountDetails, vestingAccountsPaged, VestingCoinAccounts, VestingPeriod } from '../expectedResponses';
const dotenv = require('dotenv');
@@ -19,10 +20,149 @@ describe('Vesting queries', () => {
);
});
const vesting_account_address = 'n14juvj7llvx8eppypnqj6xlrgwss9wfrcuy0nkv';
const mixnodeowner = 'n1z93z44vf8ssvdhujjvxcj4rd5e3lz0l60wdk70';
const gatewayowner = 'n1un9cuvw9e3xqratmde4j55ucksev0dkeruq800';
const mix_id = 79;
it('can query for contract version', async () => {
const contract = await client.getVestingContractVersion();
expect(contract).toBeTruthy();
});
it('can get the balance on the account', () => {});
// TODO see if we can use AccountEntry type here instead
it('can get all accounts paged', async () => {
const accounts = await client.getVestingAccountsPaged();
expect(Object.keys(accounts)).toEqual(Object.keys(vestingAccountsPaged));
expect(accounts).toBeTruthy();
});
it('can get coins for all accounts paged', async () => {
const accounts = await client.getVestingAmountsAccountsPaged();
expect(Object.keys(accounts)).toEqual(Object.keys(VestingCoinAccounts));
expect(accounts).toBeTruthy();
});
it('can get locked tokens for an account', async () => {
const locked = await client.getLockedTokens(vesting_account_address);
expect(Object.keys(locked)).toEqual(Object.keys(amountDemon));
expect(locked).toBeTruthy();
});
it('can get spendable tokens for an account', async () => {
const spendable = await client.getSpendableTokens(vesting_account_address);
expect(Object.keys(spendable)).toEqual(Object.keys(amountDemon));
expect(spendable).toBeTruthy();
});
it('can get vested tokens for an account', async () => {
const vested = await client.getVestedTokens(vesting_account_address);
expect(Object.keys(vested)).toEqual(Object.keys(amountDemon));
expect(vested).toBeTruthy();
});
it('can get vesting tokens for an account', async () => {
const vesting = await client.getVestingTokens(vesting_account_address);
expect(Object.keys(vesting)).toEqual(Object.keys(amountDemon));
expect(vesting).toBeTruthy();
});
it('can get spendable vested tokens for an account', async () => {
const spendable = await client.getSpendableVestedTokens(vesting_account_address);
expect(Object.keys(spendable)).toEqual(Object.keys(amountDemon));
expect(spendable).toBeTruthy();
});
it('can get spendable rewards for an account', async () => {
const rewards = await client.getSpendableRewards(vesting_account_address);
expect(Object.keys(rewards)).toEqual(Object.keys(amountDemon));
expect(rewards).toBeTruthy();
});
it('can get delegated coins', async () => {
const delegated = await client.getDelegatedCoins(vesting_account_address);
expect(Object.keys(delegated)).toEqual(Object.keys(amountDemon));
expect(delegated).toBeTruthy();
});
it('can get pledged coins', async () => {
const pledged = await client.getPledgedCoins(vesting_account_address);
expect(Object.keys(pledged)).toEqual(Object.keys(amountDemon));
expect(pledged).toBeTruthy();
});
it('can get staked coins', async () => {
const staked = await client.getStakedCoins(vesting_account_address);
expect(Object.keys(staked)).toEqual(Object.keys(amountDemon));
expect(staked).toBeTruthy();
});
it('can get withdrawn coins', async () => {
const withdrawn = await client.getWithdrawnCoins(vesting_account_address);
expect(Object.keys(withdrawn)).toEqual(Object.keys(amountDemon));
expect(withdrawn).toBeTruthy();
});
it('can get start time of an account', async () => {
const time = await client.getStartTime(vesting_account_address);
expect(typeof time).toBe("string");
expect(time).toBeTruthy();
});
it('can get end time of an account', async () => {
const time = await client.getEndTime(vesting_account_address);
expect(typeof time).toBe("string");
expect(time).toBeTruthy();
});
it('can get account original vesting details', async () => {
const original = await client.getOriginalVestingDetails(vesting_account_address);
expect(Object.keys(original)).toEqual(Object.keys(OriginalVestingDetails));
expect(original).toBeTruthy();
});
it('can get historic vesting staking rewards', async () => {
const rewards = await client.getHistoricStakingRewards(vesting_account_address);
expect(Object.keys(rewards)).toEqual(Object.keys(amountDemon));
expect(rewards).toBeTruthy();
});
// TODO see if we can use "VestingAccountInfo" type here instead
it('can get account details', async () => {
const account = await client.getAccountDetails(vesting_account_address);
expect(Object.keys(account)).toEqual(Object.keys(VestingAccountDetails));
expect(account).toBeTruthy();
});
// TODO add option for if account has no mixnode and expected is null
it('can get mixnode', async () => {
const mixnode = await client.getMixnode(mixnodeowner);
expect(Object.keys(mixnode)).toEqual(Object.keys(Node));
expect(mixnode).toBeTruthy();
});
// TODO add option for if account has no gateway and expected is null
it.skip('can get gateway', async () => {
const gateway = await client.getGateway(gatewayowner);
expect(Object.keys(gateway)).toEqual(Object.keys(Node));
expect(gateway).toBeTruthy();
});
it('can get delegations times', async () => {
const delegation = await client.getDelegationTimes(mix_id, mixnodeowner);
expect(Object.keys(delegation)).toEqual(Object.keys(DelegatorTimes));
expect(delegation).toBeTruthy();
});
it('can get all delegations', async () => {
const delegation = await client.getAllDelegations();
expect(Object.keys(delegation)).toEqual(Object.keys(Delegations));
expect(delegation).toBeTruthy();
});
it('can get current vesting period', async () => {
const period = await client.getCurrentVestingPeriod(gatewayowner);
expect(period).toEqual(expect.anything() as unknown as VestingPeriod);
expect(period).toBeTruthy();
});
});
+2
View File
@@ -0,0 +1,2 @@
[build]
target = "wasm32-unknown-unknown"
+11 -3
View File
@@ -17,6 +17,7 @@ default = ["console_error_panic_hook"]
offline-test = []
[dependencies]
bs58 = "0.4.0"
futures = "0.3"
js-sys = "0.3"
rand = { version = "0.7.3", features = ["wasm-bindgen"] }
@@ -28,15 +29,22 @@ tokio = { version = "1.24.1", features = ["sync"] }
url = "2.2"
wasm-bindgen = { version = "=0.2.83", features = ["serde-serialize"] }
wasm-bindgen-futures = "0.4"
thiserror = "1.0.40"
wasm-timer = { git = "https://github.com/mmsinclair/wasm-timer", rev = "b9d1a54ad514c2f230a026afe0dde341e98cd7b6"}
# internal
client-core = { path = "../client-core", default-features = false, features = ["wasm"] }
nym-node-tester-utils = { path = "../../common/node-tester-utils" }
nym-client-core = { path = "../../common/client-core", default-features = false, features = ["wasm"] }
nym-bandwidth-controller = { path = "../../common/bandwidth-controller" }
nym-coconut-interface = { path = "../../common/coconut-interface" }
nym-credentials = { path = "../../common/credentials" }
nym-credential-storage = { path = "../../common/credential-storage" }
nym-crypto = { path = "../../common/crypto" }
nym-sphinx = { path = "../../common/nymsphinx" }
gateway-client = { path = "../../common/client-libs/gateway-client", default-features = false, features = ["wasm"] }
validator-client = { path = "../../common/client-libs/validator-client", default-features = false }
nym-topology = { path = "../../common/topology" }
nym-gateway-client = { path = "../../common/client-libs/gateway-client", default-features = false, features = ["wasm"] }
nym-validator-client = { path = "../../common/client-libs/validator-client", default-features = false }
wasm-utils = { path = "../../common/wasm-utils" }
nym-task = { path = "../../common/task" }
# The `console_error_panic_hook` crate provides better debugging of panics by
@@ -0,0 +1,2 @@
node_modules
dist
+5
View File
@@ -0,0 +1,5 @@
// A dependency graph that contains any wasm must all be imported
// asynchronously. This `bootstrap.js` file does the single async import, so
// that no one else needs to worry about it again.
import('./index.js')
.catch(e => console.error('Error importing `index.js`:', e));
@@ -0,0 +1,43 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Nym WebAssembly Demo</title>
</head>
<body>
<p>
<label>Sender: </label><input disabled="true" size="85" type="text" id="sender" value="">
</p>
<p>
<label>Recipient: </label><input size="85" type="text" id="recipient" value="">
</p>
<p>
<label>Message: </label><input type="text" id="message" value="Hello mixnet!">
</p>
<p>
<button id="send-button">Send</button>
</p>
<div>
<label>Mixnode Identity: </label>
<input type="text" size = "60" id="mixnode_identity" value="...">
<button id="magic-button">✨ Magic Test Button ✨</button>
</div>
<p>Send messages from your browser, through the mixnet, and to the recipient using the "send" button.</p>
<p><span style='color: blue;'>Sent</span> messages show in blue, <span style='color: green;'>received</span>
messages show in green.</p>
<hr>
<p>
<span id="output"></span>
</p>
<script src="./bootstrap.js"></script>
</body>
</html>
+170
View File
@@ -0,0 +1,170 @@
// Copyright 2020-2023 Nym Technologies SA
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
class WebWorkerClient {
worker = null;
constructor() {
this.worker = new Worker('./worker.js');
this.worker.onmessage = (ev) => {
if (ev.data && ev.data.kind) {
switch (ev.data.kind) {
case 'Ready':
const {selfAddress} = ev.data.args;
displaySenderAddress(selfAddress);
break;
case 'ReceiveMessage':
const {message, senderTag, isTestPacket } = ev.data.args;
displayReceived(message, senderTag, isTestPacket);
break;
case 'DisableMagicTestButton':
const magicButton = document.querySelector('#magic-button');
magicButton.setAttribute('disabled', "true")
break;
case 'DisplayTesterResults':
const {score, sentPackets, receivedPackets, receivedAcks, duplicatePackets, duplicateAcks} = ev.data.args;
const resultText = `Test score: ${score}. Sent ${sentPackets} packets. Received ${receivedPackets} packets and ${receivedAcks} acks back. We also got ${duplicatePackets} duplicate packets and ${duplicateAcks} duplicate acks.`
displayReceivedRawString(resultText)
break;
}
}
};
}
sendMessage = (message, recipient) => {
if (!this.worker) {
console.error('Could not send message because worker does not exist');
return;
}
this.worker.postMessage({
kind: 'SendMessage',
args: {
message, recipient,
},
});
};
sendTestPacket = (mixnodeIdentity) => {
if (!this.worker) {
console.error('Could not send message because worker does not exist');
return;
}
this.worker.postMessage({
kind: 'TestPacket',
args: {
mixnodeIdentity,
},
});
}
}
let client = null;
async function main() {
client = new WebWorkerClient();
const sendButton = document.querySelector('#send-button');
sendButton.onclick = function () {
sendMessageTo();
};
const magicButton = document.querySelector('#magic-button');
magicButton.onclick = function () {
sendTestPacket();
}
}
/**
* Create a Sphinx packet and send it to the mixnet through the gateway node.
*
* Message and recipient are taken from the values in the user interface.
*
*/
async function sendMessageTo() {
const message = document.getElementById('message').value;
const recipient = document.getElementById('recipient').value;
await client.sendMessage(message, recipient);
displaySend(message);
}
async function sendTestPacket() {
const mixnodeIdentity = document.getElementById('mixnode_identity').value;
await client.sendTestPacket(mixnodeIdentity)
displaySend(`sending test packets to: ${mixnodeIdentity}...`);
}
/**
* Display messages that have been sent up the websocket. Colours them blue.
*
* @param {string} message
*/
function displaySend(message) {
let timestamp = new Date().toISOString().substr(11, 12);
let sendDiv = document.createElement('div');
let paragraph = document.createElement('p');
paragraph.setAttribute('style', 'color: blue');
let paragraphContent = document.createTextNode(timestamp + ' sent >>> ' + message);
paragraph.appendChild(paragraphContent);
sendDiv.appendChild(paragraph);
document.getElementById('output').appendChild(sendDiv);
}
/**
* Display received text messages in the browser. Colour them green.
*
* @param {Uint8Array} raw
*/
function displayReceived(raw, sender_tag, isTestPacket) {
let content = new TextDecoder().decode(raw);
if (sender_tag !== undefined) {
console.log("this message also contained some surbs from", sender_tag)
}
if (isTestPacket) {
const decoded = JSON.parse(content)
content = `Received packet ${decoded.msg_id} / ${decoded.total_msgs} for node ${decoded.encoded_node_identity} (test: ${decoded.test_id})`
}
displayReceivedRawString(content)
}
function displayReceivedRawString(raw) {
let timestamp = new Date().toISOString().substr(11, 12);
let receivedDiv = document.createElement('div');
let paragraph = document.createElement('p');
paragraph.setAttribute('style', 'color: green');
let paragraphContent = document.createTextNode(timestamp + ' received >>> ' + raw);
paragraph.appendChild(paragraphContent);
receivedDiv.appendChild(paragraph);
document.getElementById('output').appendChild(receivedDiv);
}
/**
* Display the nymClient's sender address in the user interface
*
* @param {String} address
*/
function displaySenderAddress(address) {
document.getElementById('sender').value = address;
}
main();
@@ -0,0 +1,39 @@
{
"name": "create-wasm-app",
"version": "0.1.0",
"description": "create an app to consume rust-generated wasm packages",
"main": "index.js",
"bin": {
"create-wasm-app": ".bin/create-wasm-app.js"
},
"scripts": {
"build": "webpack --config webpack.config.js",
"start": "webpack-dev-server --port 8001"
},
"repository": {
"type": "git",
"url": "git+https://github.com/rustwasm/create-wasm-app.git"
},
"keywords": [
"webassembly",
"wasm",
"rust",
"webpack"
],
"author": "Dave Hrycyszyn <futurechimp@users.noreply.github.com>",
"license": "Apache-2.0",
"bugs": {
"url": "https://github.com/nymtech/nym/issues"
},
"homepage": "https://nymtech.net/docs",
"devDependencies": {
"copy-webpack-plugin": "^10.2.4",
"hello-wasm-pack": "^0.1.0",
"webpack": "^5.70.0",
"webpack-cli": "^4.9.2",
"webpack-dev-server": "^4.7.4"
},
"dependencies": {
"@nymproject/nym-client-wasm": "file:../pkg"
}
}
@@ -0,0 +1,33 @@
const CopyWebpackPlugin = require('copy-webpack-plugin');
const path = require('path');
module.exports = {
performance: {
hints: false,
maxEntrypointSize: 512000,
maxAssetSize: 512000
},
entry: {
bootstrap: './bootstrap.js',
worker: './worker.js',
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].js',
},
// mode: 'development',
mode: 'production',
plugins: [
new CopyWebpackPlugin({
patterns: [
'index.html',
{
from: 'node_modules/@nymproject/nym-client-wasm/*.(js|wasm)',
to: '[name][ext]',
},
],
}),
],
experiments: { syncWebAssembly: true },
};
+294
View File
@@ -0,0 +1,294 @@
// Copyright 2020-2023 Nym Technologies SA
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
importScripts('nym_client_wasm.js');
console.log('Initializing worker');
// wasm_bindgen creates a global variable (with the exports attached) that is in scope after `importScripts`
const {
NymNodeTester,
WasmGateway,
WasmMixNode,
WasmNymTopology,
default_debug,
NymClientBuilder,
NymClient,
set_panic_hook,
Config,
GatewayEndpointConfig,
current_network_topology,
} = wasm_bindgen;
let client = null;
let tester = null;
function dummyTopology() {
const l1Mixnode = new WasmMixNode(
1,
'n1fzv4jc7fanl9s0qj02ge2ezk3kts545kjtek47',
'178.79.143.65',
1789,
'4Yr4qmEHd9sgsuQ83191FR2hD88RfsbMmB4tzhhZWriz',
'8ndjk5oZ6HxUZNScLJJ7hk39XtUqGexdKgW7hSX6kpWG',
1,
'1.10.0',
);
const l2Mixnode = new WasmMixNode(
2,
'n1z93z44vf8ssvdhujjvxcj4rd5e3lz0l60wdk70',
'109.74.197.180',
1789,
'7sVjiMrPYZrDWRujku9QLxgE8noT7NTgBAqizCsu7AoK',
'GepXwRnKZDd8x2nBWAajGGBVvF3mrpVMQBkgfrGuqRCN',
2,
'1.10.0',
);
const l3Mixnode = new WasmMixNode(
3,
'n1ptg680vnmef2cd8l0s9uyc4f0hgf3x8sed6w77',
'176.58.101.80',
1789,
'FoM5Mx9Pxk1g3zEqkS3APgtBeTtTo3M8k7Yu4bV6kK1R',
'DeYjrDC2AcQRVFshiKnbUo6bRvPyZ33QGYR2DLeFJ9qD',
3,
'1.10.0',
);
const gateway = new WasmGateway(
'n16evnn8glr0sham3matj8rg2s24m6x56ayk87ts',
'85.159.212.96',
1789,
9000,
'336yuXAeGEgedRfqTJZsG2YV7P13QH1bHv1SjCZYarc9',
'BtYjoWihiuFihGKQypmpSspbhmWDPxzqeTVSd8ciCpWL',
'1.10.1',
);
const mixnodes = new Map();
mixnodes.set(1, [l1Mixnode]);
mixnodes.set(2, [l2Mixnode]);
mixnodes.set(3, [l3Mixnode]);
const gateways = [gateway];
return new WasmNymTopology(mixnodes, gateways)
}
function printAndDisplayTestResult(result) {
result.log_details();
self.postMessage({
kind: 'DisplayTesterResults',
args: {
score: result.score(),
sentPackets: result.sent_packets,
receivedPackets: result.received_packets,
receivedAcks: result.received_acks,
duplicatePackets: result.duplicate_packets,
duplicateAcks: result.duplicate_acks,
},
});
}
function dummyGatewayConfig() {
return new GatewayEndpointConfig(
'336yuXAeGEgedRfqTJZsG2YV7P13QH1bHv1SjCZYarc9',
'n1rqqw8km7a0rvf8lr6k8dsdqvvkyn2mglj7xxfm',
'ws://85.159.212.96:9000',
)
}
async function testWithTester() {
const gatewayConfig = dummyGatewayConfig();
// A) construct with hardcoded topology
const topology = dummyTopology()
const nodeTester = await new NymNodeTester(gatewayConfig, topology);
// B) first get topology directly from nym-api
// const validator = 'https://qwerty-validator-api.qa.nymte.ch/api';
// const topology = await current_network_topology(validator)
// const nodeTester = await new NymNodeTester(gatewayConfig, topology);
//
// C) use nym-api in the constructor (note: it does no filtering for 'good' nodes on other layers)
// const validator = 'https://qwerty-validator-api.qa.nymte.ch/api';
// const nodeTester = await NymNodeTester.new_with_api(gatewayConfig, validator)
self.onmessage = async event => {
if (event.data && event.data.kind) {
switch (event.data.kind) {
case 'TestPacket': {
const {mixnodeIdentity} = event.data.args;
console.log("starting node test...");
let result = await nodeTester.test_node(mixnodeIdentity);
printAndDisplayTestResult(result)
}
}
}
};
}
async function testWithNymClient() {
const gatewayConfig = dummyGatewayConfig();
const topology = dummyTopology()
let received = 0
const onMessageHandler = (message) => {
received += 1;
self.postMessage({
kind: 'ReceiveMessage',
args: {
message,
senderTag: undefined,
isTestPacket: true,
},
});
// it's really up to the user to create proper callback here...
console.log(`received ${received} packets so far`)
};
console.log('Instantiating WASM client...');
let clientBuilder = NymClientBuilder.new_tester(gatewayConfig, topology, onMessageHandler)
console.log('Web worker creating WASM client...');
let local_client = await clientBuilder.start_client();
console.log('WASM client running!');
const selfAddress = local_client.self_address();
// set the global (I guess we don't have to anymore?)
client = local_client;
console.log(`Client address is ${selfAddress}`);
self.postMessage({
kind: 'Ready',
args: {
selfAddress,
},
});
// Set callback to handle messages passed to the worker.
self.onmessage = async event => {
console.log(event)
if (event.data && event.data.kind) {
switch (event.data.kind) {
case 'SendMessage': {
const {message, recipient} = event.data.args;
let uint8Array = new TextEncoder().encode(message);
await client.send_regular_message(uint8Array, recipient);
break;
}
case 'TestPacket': {
const {mixnodeIdentity} = event.data.args;
const req = await client.try_construct_test_packet_request(mixnodeIdentity);
await client.change_hardcoded_topology(req.injectable_topology());
await client.try_send_test_packets(req);
break;
}
}
}
};
}
async function normalNymClientUsage() {
self.postMessage({kind: 'DisableMagicTestButton'});
// only really useful if you want to adjust some settings like traffic rate
// (if not needed you can just pass a null)
const debug = default_debug();
debug.disable_main_poisson_packet_distribution = true;
debug.disable_loop_cover_traffic_stream = true;
debug.use_extended_packet_size = false;
// debug.average_packet_delay_ms = BigInt(10);
// debug.average_ack_delay_ms = BigInt(10);
// debug.ack_wait_addition_ms = BigInt(3000);
// debug.ack_wait_multiplier = 10;
debug.topology_refresh_rate_ms = BigInt(60000)
const gatewayConfig = dummyGatewayConfig();
const validator = 'https://qwerty-validator-api.qa.nymte.ch/api';
const config = new Config('my-awesome-wasm-client', validator, gatewayConfig, debug);
const onMessageHandler = (message) => {
console.log(message);
self.postMessage({
kind: 'ReceiveMessage',
args: {
message,
},
});
};
console.log('Instantiating WASM client...');
let localClient = await new NymClient(config, onMessageHandler)
console.log('WASM client running!');
const selfAddress = localClient.self_address();
// set the global (I guess we don't have to anymore?)
client = localClient;
console.log(`Client address is ${selfAddress}`);
self.postMessage({
kind: 'Ready',
args: {
selfAddress,
},
});
// Set callback to handle messages passed to the worker.
self.onmessage = async event => {
console.log(event)
if (event.data && event.data.kind) {
switch (event.data.kind) {
case 'SendMessage': {
const {message, recipient} = event.data.args;
let uint8Array = new TextEncoder().encode(message);
await client.send_regular_message(uint8Array, recipient);
break;
}
}
}
};
}
async function main() {
// load WASM package
await wasm_bindgen('nym_client_wasm_bg.wasm');
console.log('Loaded WASM');
// sets up better stack traces in case of in-rust panics
set_panic_hook();
// run test on simplified and dedicated tester:
await testWithTester()
// hook-up the whole client for testing
// await testWithNymClient()
// 'Normal' client setup (to send 'normal' messages)
// await normalNymClientUsage()
}
// Let's get started!
main();
File diff suppressed because it is too large Load Diff
+259 -91
View File
@@ -3,8 +3,16 @@
// due to expansion of #[wasm_bindgen] macro on `Debug` Config struct
#![allow(clippy::drop_non_drop)]
// another issue due to #[wasm_bindgen] and `Copy` trait
#![allow(clippy::drop_copy)]
use client_core::config::{DebugConfig as ConfigDebug, ExtendedPacketSize, GatewayEndpointConfig};
use nym_client_core::config::{
Acknowledgements as ConfigAcknowledgements, CoverTraffic as ConfigCoverTraffic,
DebugConfig as ConfigDebug, GatewayConnection as ConfigGatewayConnection,
GatewayEndpointConfig, ReplySurbs as ConfigReplySurbs, Topology as ConfigTopology,
Traffic as ConfigTraffic,
};
use nym_sphinx::params::PacketSize;
use serde::{Deserialize, Serialize};
use std::time::Duration;
use url::Url;
@@ -17,7 +25,7 @@ pub struct Config {
/// ID specifies the human readable ID of this particular client.
pub(crate) id: String,
pub(crate) nym_api_url: Url,
pub(crate) nym_api_url: Option<Url>,
pub(crate) disabled_credentials_mode: bool,
@@ -38,9 +46,11 @@ impl Config {
) -> Self {
Config {
id,
nym_api_url: validator_server
.parse()
.expect("provided url was malformed"),
nym_api_url: Some(
validator_server
.parse()
.expect("provided url was malformed"),
),
disabled_credentials_mode: true,
gateway_endpoint,
debug: debug.map(Into::into).unwrap_or_default(),
@@ -48,15 +58,131 @@ impl Config {
}
}
// just a helper structure to more easily pass through the JS boundary
#[wasm_bindgen]
pub struct Debug {
#[derive(Debug, Copy, Clone)]
pub struct Traffic {
/// The parameter of Poisson distribution determining how long, on average,
/// sent packet is going to be delayed at any given mix node.
/// So for a packet going through three mix nodes, on average, it will take three times this value
/// until the packet reaches its destination.
pub average_packet_delay_ms: u64,
/// The parameter of Poisson distribution determining how long, on average,
/// it is going to take another 'real traffic stream' message to be sent.
/// If no real packets are available and cover traffic is enabled,
/// a loop cover message is sent instead in order to preserve the rate.
pub message_sending_average_delay_ms: u64,
/// Controls whether the main packet stream constantly produces packets according to the predefined
/// poisson distribution.
pub disable_main_poisson_packet_distribution: bool,
/// Controls whether the sent sphinx packet use the NON-DEFAULT bigger size.
pub use_extended_packet_size: bool,
}
impl From<Traffic> for ConfigTraffic {
fn from(traffic: Traffic) -> Self {
let use_extended_packet_size = traffic
.use_extended_packet_size
.then(|| PacketSize::ExtendedPacket32);
ConfigTraffic {
average_packet_delay: Duration::from_millis(traffic.average_packet_delay_ms),
message_sending_average_delay: Duration::from_millis(
traffic.message_sending_average_delay_ms,
),
disable_main_poisson_packet_distribution: traffic
.disable_main_poisson_packet_distribution,
primary_packet_size: PacketSize::RegularPacket,
secondary_packet_size: use_extended_packet_size,
}
}
}
impl From<ConfigTraffic> for Traffic {
fn from(traffic: ConfigTraffic) -> Self {
Traffic {
average_packet_delay_ms: traffic.average_packet_delay.as_millis() as u64,
message_sending_average_delay_ms: traffic.message_sending_average_delay.as_millis()
as u64,
disable_main_poisson_packet_distribution: traffic
.disable_main_poisson_packet_distribution,
use_extended_packet_size: traffic.secondary_packet_size.is_some(),
}
}
}
#[wasm_bindgen]
#[derive(Debug, Copy, Clone)]
pub struct CoverTraffic {
/// The parameter of Poisson distribution determining how long, on average,
/// it is going to take for another loop cover traffic message to be sent.
pub loop_cover_traffic_average_delay_ms: u64,
/// Specifies the ratio of `primary_packet_size` to `secondary_packet_size` used in cover traffic.
/// Only applicable if `secondary_packet_size` is enabled.
pub cover_traffic_primary_size_ratio: f64,
/// Controls whether the dedicated loop cover traffic stream should be enabled.
/// (and sending packets, on average, every [Self::loop_cover_traffic_average_delay])
pub disable_loop_cover_traffic_stream: bool,
}
impl From<CoverTraffic> for ConfigCoverTraffic {
fn from(cover_traffic: CoverTraffic) -> Self {
ConfigCoverTraffic {
loop_cover_traffic_average_delay: Duration::from_millis(
cover_traffic.loop_cover_traffic_average_delay_ms,
),
cover_traffic_primary_size_ratio: cover_traffic.cover_traffic_primary_size_ratio,
disable_loop_cover_traffic_stream: cover_traffic.disable_loop_cover_traffic_stream,
}
}
}
impl From<ConfigCoverTraffic> for CoverTraffic {
fn from(cover_traffic: ConfigCoverTraffic) -> Self {
CoverTraffic {
loop_cover_traffic_average_delay_ms: cover_traffic
.loop_cover_traffic_average_delay
.as_millis() as u64,
cover_traffic_primary_size_ratio: cover_traffic.cover_traffic_primary_size_ratio,
disable_loop_cover_traffic_stream: cover_traffic.disable_loop_cover_traffic_stream,
}
}
}
#[wasm_bindgen]
#[derive(Debug, Copy, Clone)]
pub struct GatewayConnection {
/// How long we're willing to wait for a response to a message sent to the gateway,
/// before giving up on it.
pub gateway_response_timeout_ms: u64,
}
impl From<GatewayConnection> for ConfigGatewayConnection {
fn from(gateway_connection: GatewayConnection) -> Self {
ConfigGatewayConnection {
gateway_response_timeout: Duration::from_millis(
gateway_connection.gateway_response_timeout_ms,
),
}
}
}
impl From<ConfigGatewayConnection> for GatewayConnection {
fn from(gateway_connection: ConfigGatewayConnection) -> Self {
GatewayConnection {
gateway_response_timeout_ms: gateway_connection.gateway_response_timeout.as_millis()
as u64,
}
}
}
#[wasm_bindgen]
#[derive(Debug, Copy, Clone)]
pub struct Acknowledgements {
/// The parameter of Poisson distribution determining how long, on average,
/// sent acknowledgement is going to be delayed at any given mix node.
/// So for an ack going through three mix nodes, on average, it will take three times this value
@@ -72,21 +198,31 @@ pub struct Debug {
/// it is assumed it was lost and retransmission of the data packet happens.
/// In an ideal network with 0 latency, this value would have been 0.
pub ack_wait_addition_ms: u64,
}
/// The parameter of Poisson distribution determining how long, on average,
/// it is going to take for another loop cover traffic message to be sent.
pub loop_cover_traffic_average_delay_ms: u64,
impl From<Acknowledgements> for ConfigAcknowledgements {
fn from(acknowledgements: Acknowledgements) -> Self {
ConfigAcknowledgements {
average_ack_delay: Duration::from_millis(acknowledgements.average_ack_delay_ms),
ack_wait_multiplier: acknowledgements.ack_wait_multiplier,
ack_wait_addition: Duration::from_millis(acknowledgements.ack_wait_addition_ms),
}
}
}
/// The parameter of Poisson distribution determining how long, on average,
/// it is going to take another 'real traffic stream' message to be sent.
/// If no real packets are available and cover traffic is enabled,
/// a loop cover message is sent instead in order to preserve the rate.
pub message_sending_average_delay_ms: u64,
/// How long we're willing to wait for a response to a message sent to the gateway,
/// before giving up on it.
pub gateway_response_timeout_ms: u64,
impl From<ConfigAcknowledgements> for Acknowledgements {
fn from(acknowledgements: ConfigAcknowledgements) -> Self {
Acknowledgements {
average_ack_delay_ms: acknowledgements.average_ack_delay.as_millis() as u64,
ack_wait_multiplier: acknowledgements.ack_wait_multiplier,
ack_wait_addition_ms: acknowledgements.ack_wait_addition.as_millis() as u64,
}
}
}
#[wasm_bindgen]
#[derive(Debug, Copy, Clone)]
pub struct Topology {
/// The uniform delay every which clients are querying the directory server
/// to try to obtain a compatible network topology to send sphinx packets through.
pub topology_refresh_rate_ms: u64,
@@ -96,17 +232,37 @@ pub struct Debug {
/// did not reach its destination.
pub topology_resolution_timeout_ms: u64,
/// Controls whether the dedicated loop cover traffic stream should be enabled.
/// (and sending packets, on average, every [Self::loop_cover_traffic_average_delay_ms])
pub disable_loop_cover_traffic_stream: bool,
/// Specifies whether the client should not refresh the network topology after obtaining
/// the first valid instance.
/// Supersedes `topology_refresh_rate_ms`.
pub disable_refreshing: bool,
}
/// Controls whether the main packet stream constantly produces packets according to the predefined
/// poisson distribution.
pub disable_main_poisson_packet_distribution: bool,
impl From<Topology> for ConfigTopology {
fn from(topology: Topology) -> Self {
ConfigTopology {
topology_refresh_rate: Duration::from_millis(topology.topology_refresh_rate_ms),
topology_resolution_timeout: Duration::from_millis(
topology.topology_resolution_timeout_ms,
),
disable_refreshing: topology.disable_refreshing,
}
}
}
/// Controls whether the sent sphinx packet use the NON-DEFAULT bigger size.
pub use_extended_packet_size: bool,
impl From<ConfigTopology> for Topology {
fn from(topology: ConfigTopology) -> Self {
Topology {
topology_refresh_rate_ms: topology.topology_refresh_rate.as_millis() as u64,
topology_resolution_timeout_ms: topology.topology_resolution_timeout.as_millis() as u64,
disable_refreshing: topology.disable_refreshing,
}
}
}
#[wasm_bindgen]
#[derive(Debug, Copy, Clone)]
pub struct ReplySurbs {
/// Defines the minimum number of reply surbs the client wants to keep in its storage at all times.
/// It can only allow to go below that value if its to request additional reply surbs.
pub minimum_reply_surb_storage_threshold: usize,
@@ -140,46 +296,80 @@ pub struct Debug {
pub maximum_reply_key_age_ms: u64,
}
impl From<Debug> for ConfigDebug {
fn from(debug: Debug) -> Self {
// For now we just always use the (older) 32kb extended size
let use_extended_packet_size = debug
.use_extended_packet_size
.then(|| ExtendedPacketSize::Extended32);
ConfigDebug {
average_packet_delay: Duration::from_millis(debug.average_packet_delay_ms),
average_ack_delay: Duration::from_millis(debug.average_ack_delay_ms),
ack_wait_multiplier: debug.ack_wait_multiplier,
ack_wait_addition: Duration::from_millis(debug.ack_wait_addition_ms),
loop_cover_traffic_average_delay: Duration::from_millis(
debug.loop_cover_traffic_average_delay_ms,
),
message_sending_average_delay: Duration::from_millis(
debug.message_sending_average_delay_ms,
),
gateway_response_timeout: Duration::from_millis(debug.gateway_response_timeout_ms),
topology_refresh_rate: Duration::from_millis(debug.topology_refresh_rate_ms),
topology_resolution_timeout: Duration::from_millis(
debug.topology_resolution_timeout_ms,
),
disable_loop_cover_traffic_stream: debug.disable_loop_cover_traffic_stream,
disable_main_poisson_packet_distribution: debug
.disable_main_poisson_packet_distribution,
use_extended_packet_size,
minimum_reply_surb_storage_threshold: debug.minimum_reply_surb_storage_threshold,
maximum_reply_surb_storage_threshold: debug.maximum_reply_surb_storage_threshold,
minimum_reply_surb_request_size: debug.minimum_reply_surb_request_size,
maximum_reply_surb_request_size: debug.maximum_reply_surb_request_size,
maximum_allowed_reply_surb_request_size: debug.maximum_allowed_reply_surb_request_size,
impl From<ReplySurbs> for ConfigReplySurbs {
fn from(reply_surbs: ReplySurbs) -> Self {
ConfigReplySurbs {
minimum_reply_surb_storage_threshold: reply_surbs.minimum_reply_surb_storage_threshold,
maximum_reply_surb_storage_threshold: reply_surbs.maximum_reply_surb_storage_threshold,
minimum_reply_surb_request_size: reply_surbs.minimum_reply_surb_request_size,
maximum_reply_surb_request_size: reply_surbs.maximum_reply_surb_request_size,
maximum_allowed_reply_surb_request_size: reply_surbs
.maximum_allowed_reply_surb_request_size,
maximum_reply_surb_rerequest_waiting_period: Duration::from_millis(
debug.maximum_reply_surb_rerequest_waiting_period_ms,
reply_surbs.maximum_reply_surb_rerequest_waiting_period_ms,
),
maximum_reply_surb_drop_waiting_period: Duration::from_millis(
debug.maximum_reply_surb_drop_waiting_period_ms,
reply_surbs.maximum_reply_surb_drop_waiting_period_ms,
),
maximum_reply_surb_age: Duration::from_millis(debug.maximum_reply_surb_age_ms),
maximum_reply_key_age: Duration::from_millis(debug.maximum_reply_key_age_ms),
maximum_reply_surb_age: Duration::from_millis(reply_surbs.maximum_reply_surb_age_ms),
maximum_reply_key_age: Duration::from_millis(reply_surbs.maximum_reply_key_age_ms),
}
}
}
impl From<ConfigReplySurbs> for ReplySurbs {
fn from(reply_surbs: ConfigReplySurbs) -> Self {
ReplySurbs {
minimum_reply_surb_storage_threshold: reply_surbs.minimum_reply_surb_storage_threshold,
maximum_reply_surb_storage_threshold: reply_surbs.maximum_reply_surb_storage_threshold,
minimum_reply_surb_request_size: reply_surbs.minimum_reply_surb_request_size,
maximum_reply_surb_request_size: reply_surbs.maximum_reply_surb_request_size,
maximum_allowed_reply_surb_request_size: reply_surbs
.maximum_allowed_reply_surb_request_size,
maximum_reply_surb_rerequest_waiting_period_ms: reply_surbs
.maximum_reply_surb_rerequest_waiting_period
.as_millis() as u64,
maximum_reply_surb_drop_waiting_period_ms: reply_surbs
.maximum_reply_surb_drop_waiting_period
.as_millis() as u64,
maximum_reply_surb_age_ms: reply_surbs.maximum_reply_surb_age.as_millis() as u64,
maximum_reply_key_age_ms: reply_surbs.maximum_reply_key_age.as_millis() as u64,
}
}
}
// just a helper structure to more easily pass through the JS boundary
#[wasm_bindgen]
#[derive(Debug, Copy, Clone)]
pub struct Debug {
/// Defines all configuration options related to traffic streams.
pub traffic: Traffic,
/// Defines all configuration options related to cover traffic stream(s).
pub cover_traffic: CoverTraffic,
/// Defines all configuration options related to the gateway connection.
pub gateway_connection: GatewayConnection,
/// Defines all configuration options related to acknowledgements, such as delays or wait timeouts.
pub acknowledgements: Acknowledgements,
/// Defines all configuration options related topology, such as refresh rates or timeouts.
pub topology: Topology,
/// Defines all configuration options related to reply SURBs.
pub reply_surbs: ReplySurbs,
}
impl From<Debug> for ConfigDebug {
fn from(debug: Debug) -> Self {
ConfigDebug {
traffic: debug.traffic.into(),
cover_traffic: debug.cover_traffic.into(),
gateway_connection: debug.gateway_connection.into(),
acknowledgements: debug.acknowledgements.into(),
topology: debug.topology.into(),
reply_surbs: debug.reply_surbs.into(),
}
}
}
@@ -187,34 +377,12 @@ impl From<Debug> for ConfigDebug {
impl From<ConfigDebug> for Debug {
fn from(debug: ConfigDebug) -> Self {
Debug {
average_packet_delay_ms: debug.average_packet_delay.as_millis() as u64,
average_ack_delay_ms: debug.average_ack_delay.as_millis() as u64,
ack_wait_multiplier: debug.ack_wait_multiplier,
ack_wait_addition_ms: debug.ack_wait_addition.as_millis() as u64,
loop_cover_traffic_average_delay_ms: debug.loop_cover_traffic_average_delay.as_millis()
as u64,
message_sending_average_delay_ms: debug.message_sending_average_delay.as_millis()
as u64,
gateway_response_timeout_ms: debug.gateway_response_timeout.as_millis() as u64,
topology_refresh_rate_ms: debug.topology_refresh_rate.as_millis() as u64,
topology_resolution_timeout_ms: debug.topology_resolution_timeout.as_millis() as u64,
disable_loop_cover_traffic_stream: debug.disable_loop_cover_traffic_stream,
disable_main_poisson_packet_distribution: debug
.disable_main_poisson_packet_distribution,
use_extended_packet_size: debug.use_extended_packet_size.is_some(),
minimum_reply_surb_storage_threshold: debug.minimum_reply_surb_storage_threshold,
maximum_reply_surb_storage_threshold: debug.maximum_reply_surb_storage_threshold,
minimum_reply_surb_request_size: debug.minimum_reply_surb_request_size,
maximum_reply_surb_request_size: debug.maximum_reply_surb_request_size,
maximum_allowed_reply_surb_request_size: debug.maximum_allowed_reply_surb_request_size,
maximum_reply_surb_rerequest_waiting_period_ms: debug
.maximum_reply_surb_rerequest_waiting_period
.as_millis() as u64,
maximum_reply_surb_drop_waiting_period_ms: debug
.maximum_reply_surb_drop_waiting_period
.as_millis() as u64,
maximum_reply_surb_age_ms: debug.maximum_reply_surb_age.as_millis() as u64,
maximum_reply_key_age_ms: debug.maximum_reply_key_age.as_millis() as u64,
traffic: debug.traffic.into(),
cover_traffic: debug.cover_traffic.into(),
gateway_connection: debug.gateway_connection.into(),
acknowledgements: debug.acknowledgements.into(),
topology: debug.topology.into(),
reply_surbs: debug.reply_surbs.into(),
}
}
}
+147 -8
View File
@@ -1,16 +1,42 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// Copyright 2022-2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use client_core::client::base_client::ClientInput;
use client_core::client::inbound_messages::InputMessage;
use crate::error::WasmClientError;
use crate::tester::helpers::WasmTestMessageExt;
use crate::tester::{NodeTestMessage, DEFAULT_TEST_PACKETS};
use crate::topology::WasmNymTopology;
use js_sys::Promise;
use nym_client_core::client::base_client::{ClientInput, ClientState};
use nym_client_core::client::inbound_messages::InputMessage;
use nym_topology::{MixLayer, NymTopology};
use std::sync::Arc;
use wasm_bindgen::prelude::*;
use wasm_bindgen::JsValue;
use wasm_bindgen_futures::future_to_promise;
use wasm_utils::{console_log, js_error, simple_js_error};
#[wasm_bindgen]
pub struct NymClientTestRequest {
// serialized NodeTestMessage
pub(crate) test_msgs: Vec<Vec<u8>>,
// specially constructed network topology that only contains the target
// node on the tested layer
pub(crate) testable_topology: NymTopology,
}
#[wasm_bindgen]
impl NymClientTestRequest {
pub fn injectable_topology(&self) -> WasmNymTopology {
self.testable_topology.clone().into()
}
}
// defining helper trait as we could directly call the method on the wrapper
pub(crate) trait InputSender {
fn send_message(&self, message: InputMessage) -> Promise;
fn send_messages(&self, messages: Vec<InputMessage>) -> Promise;
}
impl InputSender for Arc<ClientInput> {
@@ -19,12 +45,125 @@ impl InputSender for Arc<ClientInput> {
future_to_promise(async move {
match this.input_sender.send(message).await {
Ok(_) => Ok(JsValue::null()),
Err(_) => {
let js_error =
js_sys::Error::new("InputMessageReceiver has stopped receiving!");
Err(JsValue::from(js_error))
}
Err(_) => Err(simple_js_error(
"InputMessageReceiver has stopped receiving!",
)),
}
})
}
fn send_messages(&self, messages: Vec<InputMessage>) -> Promise {
let this = Arc::clone(self);
future_to_promise(async move {
for message in messages {
if this.input_sender.send(message).await.is_err() {
return Err(simple_js_error(
"InputMessageReceiver has stopped receiving!",
));
}
}
Ok(JsValue::null())
})
}
}
pub(crate) trait WasmTopologyExt {
/// Changes the current network topology to the provided value.
fn change_hardcoded_topology(&self, topology: WasmNymTopology) -> Promise;
/// Returns the current network topology.
fn current_topology(&self) -> Promise;
/// Checks whether the provided node exists in the known network topology and if so, returns its layer.
fn check_for_mixnode_existence(&self, mixnode_identity: String) -> Promise;
/// Creates a `NymClientTestRequest` with a variant of `this` topology where the target node is the only one on its layer.
fn mix_test_request(
&self,
test_id: u32,
mixnode_identity: String,
num_test_packets: Option<u32>,
) -> Promise;
}
impl WasmTopologyExt for Arc<ClientState> {
fn change_hardcoded_topology(&self, topology: WasmNymTopology) -> Promise {
let this = Arc::clone(self);
future_to_promise(async move {
let nym_topology: NymTopology = topology.into();
console_log!("changing topology to {nym_topology:?}");
this.topology_accessor
.manually_change_topology(nym_topology)
.await;
Ok(JsValue::null())
})
}
fn current_topology(&self) -> Promise {
let this = Arc::clone(self);
future_to_promise(async move {
match this.topology_accessor.current_topology().await {
Some(topology) => Ok(JsValue::from(WasmNymTopology::from(topology))),
None => Err(WasmClientError::UnavailableNetworkTopology.into()),
}
})
}
/// Checks whether the target mixnode exists in the known network topology and returns its layer.
fn check_for_mixnode_existence(&self, mixnode_identity: String) -> Promise {
let this = Arc::clone(self);
future_to_promise(async move {
let Some(current_topology) = this.topology_accessor.current_topology().await else {
return Err(WasmClientError::UnavailableNetworkTopology.into())
};
match current_topology.find_mix_by_identity(&mixnode_identity) {
None => Err(WasmClientError::NonExistentMixnode { mixnode_identity }.into()),
Some(node) => Ok(JsValue::from(MixLayer::from(node.layer))),
}
})
}
fn mix_test_request(
&self,
test_id: u32,
mixnode_identity: String,
num_test_packets: Option<u32>,
) -> Promise {
let num_test_packets = num_test_packets.unwrap_or(DEFAULT_TEST_PACKETS);
let this = Arc::clone(self);
future_to_promise(async move {
let Some(current_topology) = this.topology_accessor.current_topology().await else {
return Err(WasmClientError::UnavailableNetworkTopology.into())
};
let Some(mix) = current_topology.find_mix_by_identity(&mixnode_identity) else {
return Err(WasmClientError::NonExistentMixnode { mixnode_identity }.into());
};
let mut test_msgs = Vec::with_capacity(num_test_packets as usize);
for i in 1..=num_test_packets {
let msg = NodeTestMessage::new_mix(
mix,
i,
num_test_packets,
WasmTestMessageExt::new(test_id),
);
let serialized = match msg.as_bytes() {
Ok(bytes) => bytes,
Err(err) => return Err(js_error!("failed to serialize test message: {err}")),
};
test_msgs.push(serialized);
}
let mut updated = current_topology.clone();
updated.set_mixes_in_layer(mix.layer.into(), vec![mix.to_owned()]);
Ok(JsValue::from(NymClientTestRequest {
test_msgs,
testable_topology: updated,
}))
})
}
}
+186 -97
View File
@@ -1,26 +1,36 @@
// Copyright 2021-2022 - Nym Technologies SA <contact@nymtech.net>
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use self::config::Config;
use crate::client::helpers::InputSender;
use crate::client::helpers::{InputSender, NymClientTestRequest, WasmTopologyExt};
use crate::client::response_pusher::ResponsePusher;
use client_core::client::base_client::{
BaseClientBuilder, ClientInput, ClientOutput, CredentialsToggle,
use crate::error::WasmClientError;
use crate::helpers::{
parse_recipient, parse_sender_tag, setup_new_key_manager, setup_reply_surb_storage_backend,
};
use client_core::client::replies::reply_storage::browser_backend;
use client_core::client::{inbound_messages::InputMessage, key_manager::KeyManager};
use gateway_client::bandwidth::BandwidthController;
use gateway_client::wasm_mockups::SigningNyxdClient;
use crate::topology::WasmNymTopology;
use js_sys::Promise;
use nym_sphinx::addressing::clients::Recipient;
use nym_sphinx::anonymous_replies::requests::AnonymousSenderTag;
use nym_bandwidth_controller::wasm_mockups::{Client as FakeClient, DirectSigningNyxdClient};
use nym_bandwidth_controller::BandwidthController;
use nym_client_core::client::base_client::{
BaseClientBuilder, ClientInput, ClientOutput, ClientState, CredentialsToggle,
};
use nym_client_core::client::replies::reply_storage::browser_backend;
use nym_client_core::client::{inbound_messages::InputMessage, key_manager::KeyManager};
use nym_client_core::config::{
CoverTraffic, DebugConfig, GatewayEndpointConfig, Topology, Traffic,
};
use nym_credential_storage::ephemeral_storage::EphemeralStorage;
use nym_task::connections::TransmissionLane;
use nym_task::TaskManager;
use nym_topology::provider_trait::{HardcodedTopologyProvider, TopologyProvider};
use nym_topology::NymTopology;
use rand::rngs::OsRng;
use rand::RngCore;
use std::sync::Arc;
use wasm_bindgen::prelude::*;
use wasm_bindgen_futures::future_to_promise;
use wasm_utils::{console_error, console_log};
use wasm_utils::{check_promise_result, console_log, PromisableResult};
pub mod config;
mod helpers;
@@ -30,6 +40,11 @@ mod response_pusher;
pub struct NymClient {
self_address: String,
client_input: Arc<ClientInput>,
client_state: Arc<ClientState>,
// keep track of the "old" topology for the purposes of node tester
// so that it could be restored after the check is done
_full_topology: Option<NymTopology>,
// even though we don't use graceful shutdowns, other components rely on existence of this struct
// and if it's dropped, everything will start going offline
@@ -39,6 +54,7 @@ pub struct NymClient {
#[wasm_bindgen]
pub struct NymClientBuilder {
config: Config,
custom_topology: Option<NymTopology>,
/// KeyManager object containing smart pointers to all relevant keys used by the client.
key_manager: KeyManager,
@@ -48,7 +64,8 @@ pub struct NymClientBuilder {
on_message: js_sys::Function,
// unimplemented:
bandwidth_controller: Option<BandwidthController<SigningNyxdClient>>,
bandwidth_controller:
Option<BandwidthController<FakeClient<DirectSigningNyxdClient>, EphemeralStorage>>,
disabled_credentials: bool,
}
@@ -58,112 +75,190 @@ impl NymClientBuilder {
pub fn new(config: Config, on_message: js_sys::Function) -> Self {
//, key_manager: Option<KeyManager>) {
NymClientBuilder {
reply_surb_storage_backend: Self::setup_reply_surb_storage_backend(&config),
reply_surb_storage_backend: setup_reply_surb_storage_backend(config.debug.reply_surbs),
config,
key_manager: Self::setup_key_manager(),
custom_topology: None,
key_manager: setup_new_key_manager(),
on_message,
bandwidth_controller: None,
disabled_credentials: true,
}
}
// TODO: once we make keys persistent, we'll require some kind of `init` method to generate
// a prior shared keypair between the client and the gateway
// no cover traffic
// no poisson delay
// hardcoded topology
// NOTE: you most likely want to use `[NymNodeTester]` instead.
pub fn new_tester(
gateway_config: GatewayEndpointConfig,
topology: WasmNymTopology,
on_message: js_sys::Function,
) -> Self {
if !topology.ensure_contains(&gateway_config) {
panic!("the specified topology does not contain the gateway used by the client")
}
// perhaps this should be public?
fn setup_key_manager() -> KeyManager {
let mut rng = OsRng;
// for time being generate new keys each time...
console_log!("generated new set of keys");
KeyManager::new(&mut rng)
}
let full_config = Config {
id: "ephemeral-id".to_string(),
nym_api_url: None,
disabled_credentials_mode: true,
gateway_endpoint: gateway_config,
debug: DebugConfig {
traffic: Traffic {
disable_main_poisson_packet_distribution: true,
..Default::default()
},
cover_traffic: CoverTraffic {
disable_loop_cover_traffic_stream: true,
..Default::default()
},
topology: Topology {
disable_refreshing: true,
..Default::default()
},
..Default::default()
},
};
// don't get too excited about the name, under the hood it's just a big fat placeholder
// with no persistence
fn setup_reply_surb_storage_backend(config: &Config) -> browser_backend::Backend {
browser_backend::Backend::new(
config.debug.minimum_reply_surb_storage_threshold,
config.debug.maximum_reply_surb_storage_threshold,
)
NymClientBuilder {
reply_surb_storage_backend: setup_reply_surb_storage_backend(
full_config.debug.reply_surbs,
),
config: full_config,
custom_topology: Some(topology.into()),
// TODO: once we make keys persistent, we'll require some kind of `init` method to generate
// a prior shared keypair between the client and the gateway
key_manager: setup_new_key_manager(),
on_message,
bandwidth_controller: None,
disabled_credentials: true,
}
}
fn start_reconstructed_pusher(client_output: ClientOutput, on_message: js_sys::Function) {
ResponsePusher::new(client_output, on_message).start()
}
pub async fn start_client(self) -> Promise {
future_to_promise(async move {
console_log!("Starting the wasm client");
fn topology_provider(&mut self) -> Option<Box<dyn TopologyProvider>> {
if let Some(hardcoded_topology) = self.custom_topology.take() {
Some(Box::new(HardcodedTopologyProvider::new(hardcoded_topology)))
} else {
None
}
}
let disabled_credentials = if self.disabled_credentials {
CredentialsToggle::Disabled
} else {
CredentialsToggle::Enabled
};
async fn start_client_async(mut self) -> Result<NymClient, WasmClientError> {
console_log!("Starting the wasm client");
let base_builder = BaseClientBuilder::new(
&self.config.gateway_endpoint,
&self.config.debug,
self.key_manager,
self.bandwidth_controller,
self.reply_surb_storage_backend,
disabled_credentials,
vec![self.config.nym_api_url.clone()],
);
let maybe_topology_provider = self.topology_provider();
let self_address = base_builder.as_mix_recipient().to_string();
let mut started_client = match base_builder.start_base().await {
Ok(base_client) => base_client,
Err(err) => {
let error_msg = format!("failed to start the base client components - {err}");
console_error!("{}", error_msg);
let js_error = js_sys::Error::new(&error_msg);
return Err(JsValue::from(js_error));
}
};
let disabled_credentials = if self.disabled_credentials {
CredentialsToggle::Disabled
} else {
CredentialsToggle::Enabled
};
let client_input = started_client.client_input.register_producer();
let client_output = started_client.client_output.register_consumer();
let nym_api_endpoints = match self.config.nym_api_url {
Some(endpoint) => vec![endpoint],
None => Vec::new(),
};
let mut base_builder = BaseClientBuilder::new(
&self.config.gateway_endpoint,
&self.config.debug,
self.key_manager,
self.bandwidth_controller,
self.reply_surb_storage_backend,
disabled_credentials,
nym_api_endpoints,
);
if let Some(topology_provider) = maybe_topology_provider {
base_builder = base_builder.with_topology_provider(topology_provider);
}
Self::start_reconstructed_pusher(client_output, self.on_message);
let self_address = base_builder.as_mix_recipient().to_string();
let mut started_client = base_builder.start_base().await?;
Ok(JsValue::from(NymClient {
self_address,
client_input: Arc::new(client_input),
_task_manager: started_client.task_manager,
}))
let client_input = started_client.client_input.register_producer();
let client_output = started_client.client_output.register_consumer();
Self::start_reconstructed_pusher(client_output, self.on_message);
Ok(NymClient {
self_address,
client_input: Arc::new(client_input),
client_state: Arc::new(started_client.client_state),
_full_topology: None,
_task_manager: started_client.task_manager,
})
}
pub fn start_client(self) -> Promise {
future_to_promise(async move { self.start_client_async().await.into_promise_result() })
}
}
#[wasm_bindgen]
impl NymClient {
async fn _new(
config: Config,
on_message: js_sys::Function,
) -> Result<NymClient, WasmClientError> {
NymClientBuilder::new(config, on_message)
.start_client_async()
.await
}
#[wasm_bindgen(constructor)]
#[allow(clippy::new_ret_no_self)]
pub fn new(config: Config, on_message: js_sys::Function) -> Promise {
future_to_promise(async move { Self::_new(config, on_message).await.into_promise_result() })
}
pub fn self_address(&self) -> String {
self.self_address.clone()
}
fn parse_recipient(recipient: &str) -> Result<Recipient, JsValue> {
match Recipient::try_from_base58_string(recipient) {
Ok(recipient) => Ok(recipient),
Err(err) => {
let error_msg = format!("{recipient} is not a valid Nym network recipient - {err}");
console_error!("{}", error_msg);
let js_error = js_sys::Error::new(&error_msg);
Err(JsValue::from(js_error))
}
}
pub fn try_construct_test_packet_request(
&self,
mixnode_identity: String,
num_test_packets: Option<u32>,
) -> Promise {
// TODO: improve the source of rng (i.e. don't make it ephemeral...)
let mut ephemeral_rng = OsRng;
let test_id = ephemeral_rng.next_u32();
self.client_state
.mix_test_request(test_id, mixnode_identity, num_test_packets)
}
fn parse_sender_tag(tag: &str) -> Result<AnonymousSenderTag, JsValue> {
match AnonymousSenderTag::try_from_base58_string(tag) {
Ok(tag) => Ok(tag),
Err(err) => {
let error_msg = format!("{tag} is not a valid Nym AnonymousSenderTag - {err}");
console_error!("{}", error_msg);
let js_error = js_sys::Error::new(&error_msg);
Err(JsValue::from(js_error))
}
}
pub fn change_hardcoded_topology(&self, topology: WasmNymTopology) -> Promise {
self.client_state.change_hardcoded_topology(topology)
}
pub fn current_network_topology(&self) -> Promise {
self.client_state.current_topology()
}
/// Sends a test packet through the current network topology.
/// It's the responsibility of the caller to ensure the correct topology has been injected and
/// correct onmessage handlers have been setup.
pub fn try_send_test_packets(&mut self, request: NymClientTestRequest) -> Promise {
// TOOD: use the premade packets instead
console_log!(
"Attempting to send {} test packets",
request.test_msgs.len()
);
// our address MUST BE valid
let recipient = parse_recipient(&self.self_address()).unwrap();
let lane = TransmissionLane::General;
let input_msgs = request
.test_msgs
.into_iter()
.map(|p| InputMessage::new_regular(recipient, p, lane))
.collect();
self.client_input.send_messages(input_msgs)
}
/// The simplest message variant where no additional information is attached.
@@ -176,10 +271,8 @@ impl NymClient {
message.len() as f64 / 1024.0
);
let recipient = match Self::parse_recipient(&recipient) {
Ok(recipient) => recipient,
Err(err) => return Promise::reject(&err),
};
let recipient = check_promise_result!(parse_recipient(&recipient));
let lane = TransmissionLane::General;
let input_msg = InputMessage::new_regular(recipient, message, lane);
@@ -205,10 +298,8 @@ impl NymClient {
message.len() as f64 / 1024.0
);
let recipient = match Self::parse_recipient(&recipient) {
Ok(recipient) => recipient,
Err(err) => return Promise::reject(&err),
};
let recipient = check_promise_result!(parse_recipient(&recipient));
let lane = TransmissionLane::General;
let input_msg = InputMessage::new_anonymous(recipient, message, reply_surbs, lane);
@@ -225,10 +316,8 @@ impl NymClient {
message.len() as f64 / 1024.0
);
let sender_tag = match Self::parse_sender_tag(&recipient_tag) {
Ok(recipient) => recipient,
Err(err) => return Promise::reject(&err),
};
let sender_tag = check_promise_result!(parse_sender_tag(&recipient_tag));
let lane = TransmissionLane::General;
let input_msg = InputMessage::new_reply(sender_tag, message, lane);
@@ -1,11 +1,13 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use client_core::client::base_client::ClientOutput;
use client_core::client::received_buffer::{ReceivedBufferMessage, ReconstructedMessagesReceiver};
use futures::channel::mpsc;
use futures::StreamExt;
use js_sys::Uint8Array;
use nym_client_core::client::base_client::ClientOutput;
use nym_client_core::client::received_buffer::{
ReceivedBufferMessage, ReconstructedMessagesReceiver,
};
use wasm_bindgen::JsValue;
use wasm_bindgen_futures::spawn_local;
use wasm_utils::console_error;
+99
View File
@@ -0,0 +1,99 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::topology::WasmTopologyError;
use js_sys::Promise;
use nym_client_core::error::ClientCoreError;
use nym_crypto::asymmetric::identity::Ed25519RecoveryError;
use nym_gateway_client::error::GatewayClientError;
use nym_node_tester_utils::error::NetworkTestingError;
use nym_sphinx::addressing::clients::RecipientFormattingError;
use nym_sphinx::anonymous_replies::requests::InvalidAnonymousSenderTagRepresentation;
use nym_validator_client::ValidatorClientError;
use thiserror::Error;
use wasm_bindgen::JsValue;
use wasm_utils::simple_js_error;
// might as well start using well-defined error enum...
#[derive(Debug, Error)]
pub enum WasmClientError {
#[error(
"A node test is already in progress. Wait for it to finish before starting another one."
)]
TestInProgress,
#[error("experienced an issue with internal client components: {source}")]
BaseClientError {
#[from]
source: ClientCoreError,
},
#[error("The provided gateway identity is invalid: {source}")]
InvalidGatewayIdentity { source: Ed25519RecoveryError },
#[error("Gateway communication failure: {source}")]
GatewayClientError {
#[from]
source: GatewayClientError,
},
#[error("failed to query nym api: {source}")]
NymApiError {
#[from]
source: ValidatorClientError,
},
#[error("The provided topology was invalid: {source}")]
WasmTopologyError {
#[from]
source: WasmTopologyError,
},
#[error("failed to test the node: {source}")]
NodeTestingFailure {
#[from]
source: NetworkTestingError,
},
#[error("{raw} is not a valid url: {source}")]
MalformedUrl {
raw: String,
source: url::ParseError,
},
#[error("Network topology is currently unavailable")]
UnavailableNetworkTopology,
#[error("Mixnode {mixnode_identity} is not present in the current network topology")]
NonExistentMixnode { mixnode_identity: String },
#[error("{raw} is not a valid Nym network recipient: {source}")]
MalformedRecipient {
raw: String,
source: RecipientFormattingError,
},
#[error("{raw} is not a valid Nym AnonymousSenderTag: {source}")]
MalformedSenderTag {
raw: String,
source: InvalidAnonymousSenderTagRepresentation,
},
}
impl WasmClientError {
pub fn into_rejected_promise(self) -> Promise {
self.into()
}
}
impl From<WasmClientError> for JsValue {
fn from(value: WasmClientError) -> Self {
simple_js_error(value.to_string())
}
}
impl From<WasmClientError> for Promise {
fn from(value: WasmClientError) -> Self {
Promise::reject(&value.into())
}
}
+3 -2
View File
@@ -1,12 +1,13 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use client_core::config::GatewayEndpointConfig;
use nym_client_core::config::GatewayEndpointConfig;
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
pub async fn get_gateway(api_server: String, preferred: Option<String>) -> GatewayEndpointConfig {
let validator_client = validator_client::client::NymApiClient::new(api_server.parse().unwrap());
let validator_client =
nym_validator_client::client::NymApiClient::new(api_server.parse().unwrap());
let gateways = match validator_client.get_cached_gateways().await {
Err(err) => panic!("failed to obtain list of all gateways - {err}"),
+82
View File
@@ -0,0 +1,82 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::error::WasmClientError;
use crate::topology::WasmNymTopology;
use js_sys::Promise;
use nym_client_core::client::key_manager::KeyManager;
use nym_client_core::client::replies::reply_storage::browser_backend;
use nym_client_core::config;
use nym_sphinx::addressing::clients::Recipient;
use nym_sphinx::anonymous_replies::requests::AnonymousSenderTag;
use nym_topology::NymTopology;
use nym_validator_client::NymApiClient;
use rand::rngs::OsRng;
use url::Url;
use wasm_bindgen::prelude::wasm_bindgen;
use wasm_bindgen_futures::future_to_promise;
use wasm_utils::{console_log, PromisableResult};
pub(crate) fn setup_new_key_manager() -> KeyManager {
let mut rng = OsRng;
console_log!("generated new set of keys");
KeyManager::new(&mut rng)
}
// don't get too excited about the name, under the hood it's just a big fat placeholder
// with no persistence
pub(crate) fn setup_reply_surb_storage_backend(
config: config::ReplySurbs,
) -> browser_backend::Backend {
browser_backend::Backend::new(
config.minimum_reply_surb_storage_threshold,
config.maximum_reply_surb_storage_threshold,
)
}
pub(crate) fn parse_recipient(recipient: &str) -> Result<Recipient, WasmClientError> {
Recipient::try_from_base58_string(recipient).map_err(|source| {
WasmClientError::MalformedRecipient {
raw: recipient.to_string(),
source,
}
})
}
pub(crate) fn parse_sender_tag(tag: &str) -> Result<AnonymousSenderTag, WasmClientError> {
AnonymousSenderTag::try_from_base58_string(tag).map_err(|source| {
WasmClientError::MalformedSenderTag {
raw: tag.to_string(),
source,
}
})
}
pub(crate) async fn current_network_topology_async(
nym_api_url: String,
) -> Result<WasmNymTopology, WasmClientError> {
let url: Url = match nym_api_url.parse() {
Ok(url) => url,
Err(source) => {
return Err(WasmClientError::MalformedUrl {
raw: nym_api_url,
source,
})
}
};
let api_client = NymApiClient::new(url);
let mixnodes = api_client.get_cached_active_mixnodes().await?;
let gateways = api_client.get_cached_gateways().await?;
Ok(NymTopology::from_detailed(mixnodes, gateways).into())
}
#[wasm_bindgen]
pub fn current_network_topology(nym_api_url: String) -> Promise {
future_to_promise(async move {
current_network_topology_async(nym_api_url)
.await
.into_promise_result()
})
}
+8
View File
@@ -7,11 +7,19 @@ use wasm_bindgen::prelude::*;
mod client;
#[cfg(target_arch = "wasm32")]
pub mod encoded_payload_helper;
pub mod error;
#[cfg(target_arch = "wasm32")]
pub mod gateway_selector;
#[cfg(target_arch = "wasm32")]
pub mod tester;
#[cfg(target_arch = "wasm32")]
pub mod topology;
#[cfg(target_arch = "wasm32")]
pub mod validation;
#[cfg(target_arch = "wasm32")]
mod helpers;
#[wasm_bindgen]
pub fn set_panic_hook() {
// When the `console_error_panic_hook` feature is enabled, we can call the
@@ -0,0 +1,117 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::tester::helpers::NodeTestResult;
use crate::tester::NodeTestMessage;
use futures::StreamExt;
use nym_node_tester_utils::receiver::{Received, ReceivedReceiver};
use nym_sphinx::chunking::fragment::FragmentIdentifier;
use std::collections::HashSet;
use std::time::Duration;
use tokio::sync::MutexGuard as AsyncMutexGuard;
use wasm_utils::{console_error, console_log, console_warn};
pub(crate) struct EphemeralTestReceiver<'a> {
sent_packets: u32,
expected_acks: HashSet<FragmentIdentifier>,
received_valid_messages: HashSet<u32>,
received_valid_acks: HashSet<FragmentIdentifier>,
duplicate_packets: u32,
duplicate_acks: u32,
timeout_duration: Duration,
receiver_permit: AsyncMutexGuard<'a, ReceivedReceiver>,
}
impl<'a> EphemeralTestReceiver<'a> {
pub(crate) fn finish(self) -> NodeTestResult {
NodeTestResult {
sent_packets: self.sent_packets,
received_packets: self.received_valid_messages.len() as u32,
received_acks: self.received_valid_acks.len() as u32,
duplicate_packets: self.duplicate_packets,
duplicate_acks: self.duplicate_acks,
}
}
pub(crate) fn new(
sent_packets: u32,
expected_acks: HashSet<FragmentIdentifier>,
receiver_permit: AsyncMutexGuard<'a, ReceivedReceiver>,
timeout: Duration,
) -> Self {
EphemeralTestReceiver {
sent_packets,
expected_acks,
received_valid_messages: Default::default(),
received_valid_acks: Default::default(),
duplicate_packets: 0,
duplicate_acks: 0,
timeout_duration: timeout,
receiver_permit,
}
}
fn on_next_received_packet(&mut self, packet: Option<Received>) -> bool {
let Some(received_packet) = packet else {
// can't do anything more...
console_error!("packet receiver has stopped processing results!");
return true
};
match received_packet {
Received::Message(msg) => match NodeTestMessage::try_recover(msg) {
Ok(test_msg) => {
if !self.received_valid_messages.insert(test_msg.msg_id) {
self.duplicate_packets += 1;
}
}
Err(err) => {
console_warn!("failed to recover test message from received packet: {err}")
}
},
Received::Ack(frag_id) => {
if self.expected_acks.contains(&frag_id) {
if !self.received_valid_acks.insert(frag_id) {
self.duplicate_acks += 1
}
} else {
console_warn!("received an ack that was not part of the test! (id: {frag_id})")
}
}
}
if self.received_all() {
console_log!("already received all the packets! finishing the test...");
true
} else {
false
}
}
fn received_all(&self) -> bool {
self.received_valid_acks.len() == self.received_valid_messages.len()
&& self.received_valid_acks.len() == self.sent_packets as usize
}
pub(crate) async fn perform_test(mut self) -> NodeTestResult {
let mut timeout_fut = wasm_timer::Delay::new(self.timeout_duration);
loop {
tokio::select! {
_ = &mut timeout_fut => {
console_warn!("reached test timeout before receiving all packets.");
break
}
received_packet = self.receiver_permit.next() => {
let is_done = self.on_next_received_packet(received_packet);
if is_done {
break
}
}
}
}
self.finish()
}
}
+108
View File
@@ -0,0 +1,108 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
// due to expansion of #[wasm_bindgen] macro on NodeTestResult
#![allow(clippy::drop_non_drop)]
use nym_node_tester_utils::receiver::{Received, ReceivedReceiver};
use serde::{Deserialize, Serialize};
use std::fmt::{Display, Formatter};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use tokio::sync::{Mutex as AsyncMutex, MutexGuard as AsyncMutexGuard};
use wasm_bindgen::prelude::*;
use wasm_utils::{console_log, console_warn};
#[derive(Clone)]
pub(super) struct ReceivedReceiverWrapper(Arc<AsyncMutex<ReceivedReceiver>>);
impl ReceivedReceiverWrapper {
pub(super) fn new(inner: ReceivedReceiver) -> Self {
ReceivedReceiverWrapper(Arc::new(AsyncMutex::new(inner)))
}
pub(super) async fn clear_received_channel(&self) {
let mut lost_msgs = 0;
let mut lost_acks = 0;
let mut permit = self.0.lock().await;
while let Ok(Some(received)) = permit.try_next() {
match received {
Received::Message(_) => lost_msgs += 1,
Received::Ack(_) => lost_acks += 1,
}
}
if lost_msgs > 0 || lost_acks > 0 {
console_warn!("while preparing for the test run, we cleared {lost_msgs} messages and {lost_acks} acks that were received in the meantime.")
}
}
pub(super) async fn lock(&self) -> AsyncMutexGuard<'_, ReceivedReceiver> {
self.0.lock().await
}
}
#[derive(Serialize, Deserialize, Copy, Clone)]
pub struct WasmTestMessageExt {
pub test_id: u32,
}
impl WasmTestMessageExt {
pub fn new(test_id: u32) -> Self {
WasmTestMessageExt { test_id }
}
}
// TODO: maybe put it in the tester utils
#[wasm_bindgen]
pub struct NodeTestResult {
pub sent_packets: u32,
pub received_packets: u32,
pub received_acks: u32,
pub duplicate_packets: u32,
pub duplicate_acks: u32,
}
impl Display for NodeTestResult {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
writeln!(f, "Test results: ")?;
writeln!(f, "Total score: {:.2}%", self.score())?;
writeln!(f, "Sent packets: {}", self.sent_packets)?;
writeln!(f, "Received (valid) packets: {}", self.received_packets)?;
writeln!(f, "Received (valid) acks: {}", self.received_acks)?;
writeln!(f, "Received duplicate packets: {}", self.duplicate_packets)?;
write!(f, "Received duplicate acks: {}", self.duplicate_acks)
}
}
#[wasm_bindgen]
impl NodeTestResult {
pub fn log_details(&self) {
console_log!("{}", self)
}
pub fn score(&self) -> f32 {
let expected = self.sent_packets * 2;
let actual = (self.received_packets + self.received_acks)
.saturating_sub(self.duplicate_packets + self.duplicate_acks);
actual as f32 / expected as f32 * 100.
}
}
pub(crate) struct TestMarker {
value: Arc<AtomicBool>,
}
impl TestMarker {
pub fn new(value: Arc<AtomicBool>) -> Self {
Self { value }
}
}
impl Drop for TestMarker {
// make sure to clear the test flag when the marker is dropped
fn drop(&mut self) {
self.value.store(false, Ordering::SeqCst)
}
}
+316
View File
@@ -0,0 +1,316 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::error::WasmClientError;
use crate::helpers::{current_network_topology_async, setup_new_key_manager};
use crate::tester::ephemeral_receiver::EphemeralTestReceiver;
use crate::tester::helpers::{
NodeTestResult, ReceivedReceiverWrapper, TestMarker, WasmTestMessageExt,
};
use crate::topology::WasmNymTopology;
use futures::channel::mpsc;
use js_sys::Promise;
use nym_bandwidth_controller::wasm_mockups::{Client as FakeClient, DirectSigningNyxdClient};
use nym_bandwidth_controller::BandwidthController;
use nym_client_core::client::key_manager::KeyManager;
use nym_client_core::config::GatewayEndpointConfig;
use nym_credential_storage::ephemeral_storage::EphemeralStorage;
use nym_crypto::asymmetric::identity;
use nym_gateway_client::GatewayClient;
use nym_node_tester_utils::receiver::SimpleMessageReceiver;
use nym_node_tester_utils::{NodeTester, TestMessage};
use nym_sphinx::addressing::clients::Recipient;
use nym_sphinx::addressing::nodes::NodeIdentity;
use nym_sphinx::params::PacketSize;
use nym_sphinx::preparer::PreparedFragment;
use nym_task::TaskManager;
use nym_topology::NymTopology;
use rand::rngs::OsRng;
use std::collections::HashSet;
use std::sync::atomic::{AtomicBool, AtomicU32, Ordering};
use std::sync::{Arc, Mutex as SyncMutex};
use std::time::Duration;
use tokio::sync::Mutex as AsyncMutex;
use wasm_bindgen::prelude::*;
use wasm_bindgen_futures::future_to_promise;
use wasm_utils::{check_promise_result, console_log, console_warn, PromisableResult};
mod ephemeral_receiver;
pub(crate) mod helpers;
pub type NodeTestMessage = TestMessage<WasmTestMessageExt>;
type LockedGatewayClient =
Arc<AsyncMutex<GatewayClient<FakeClient<DirectSigningNyxdClient>, EphemeralStorage>>>;
pub(crate) const DEFAULT_TEST_TIMEOUT: Duration = Duration::from_secs(10);
pub(crate) const DEFAULT_TEST_PACKETS: u32 = 20;
#[wasm_bindgen]
pub struct NymNodeTester {
test_in_progress: Arc<AtomicBool>,
// we need to increment the nonce between tests to distinguish the packets
// but we can't make the tester mutable because of wasm...
// so we're using the atomics
current_test_nonce: AtomicU32,
// blame all those mutexes on being unable to have an async method with internal mutability...
tester: Arc<SyncMutex<NodeTester<OsRng>>>,
gateway_client: LockedGatewayClient,
// we have to put it behind the lock due to wasm limitations and borrowing...
// the mutex acquisition should be instant as there aren't going to be any threads attempting
// to get simultaneous access
processed_receiver: ReceivedReceiverWrapper,
// even though we don't use graceful shutdowns, other components rely on existence of this struct
// and if it's dropped, everything will start going offline
_task_manager: TaskManager,
}
#[wasm_bindgen]
pub struct NymNodeTesterBuilder {
gateway_config: GatewayEndpointConfig,
base_topology: NymTopology,
/// KeyManager object containing smart pointers to all relevant keys used by the client.
key_manager: KeyManager,
// unimplemented
bandwidth_controller:
Option<BandwidthController<FakeClient<DirectSigningNyxdClient>, EphemeralStorage>>,
}
fn address(keys: &KeyManager, gateway_identity: NodeIdentity) -> Recipient {
Recipient::new(
*keys.identity_keypair().public_key(),
*keys.encryption_keypair().public_key(),
gateway_identity,
)
}
#[wasm_bindgen]
impl NymNodeTesterBuilder {
#[wasm_bindgen(constructor)]
pub fn new(
gateway_config: GatewayEndpointConfig,
base_topology: WasmNymTopology,
) -> NymNodeTesterBuilder {
NymNodeTesterBuilder {
gateway_config,
base_topology: base_topology.into(),
key_manager: setup_new_key_manager(),
bandwidth_controller: None,
}
}
async fn _new_with_api(
gateway_config: GatewayEndpointConfig,
api_url: String,
) -> Result<Self, WasmClientError> {
let topology = current_network_topology_async(api_url).await?;
Ok(NymNodeTesterBuilder::new(gateway_config, topology))
}
pub fn new_with_api(gateway_config: GatewayEndpointConfig, api_url: String) -> Promise {
future_to_promise(async move {
Self::_new_with_api(gateway_config, api_url)
.await
.into_promise_result()
})
}
async fn _setup_client(mut self) -> Result<NymNodeTester, WasmClientError> {
let rng = OsRng;
let task_manager = TaskManager::default();
let gateway_identity =
identity::PublicKey::from_base58_string(self.gateway_config.gateway_id)
.map_err(|source| WasmClientError::InvalidGatewayIdentity { source })?;
// we **REALLY** need persistence...
let shared_key = if self.key_manager.is_gateway_key_set() {
Some(self.key_manager.gateway_shared_key())
} else {
console_warn!("Gateway key not set - will derive a fresh one.");
None
};
let (mixnet_message_sender, mixnet_message_receiver) = mpsc::unbounded();
let (ack_sender, ack_receiver) = mpsc::unbounded();
let mut gateway_client = GatewayClient::new(
self.gateway_config.gateway_listener,
self.key_manager.identity_keypair(),
gateway_identity,
shared_key,
mixnet_message_sender,
ack_sender,
Duration::from_secs(10),
self.bandwidth_controller.take(),
task_manager.subscribe(),
);
gateway_client.set_disabled_credentials_mode(true);
let shared_keys = gateway_client.authenticate_and_start().await?;
// currently pointless but might as well do it for the future ¯\_(ツ)_/¯
self.key_manager.insert_gateway_shared_key(shared_keys);
// TODO: make those values configurable later
let tester = NodeTester::new(
rng,
self.base_topology,
address(&self.key_manager, gateway_identity),
PacketSize::default(),
Duration::from_millis(5),
Duration::from_millis(5),
self.key_manager.ack_key(),
);
let (processed_sender, processed_receiver) = mpsc::unbounded();
let mut receiver = SimpleMessageReceiver::new_sphinx_receiver(
self.key_manager.encryption_keypair(),
self.key_manager.ack_key(),
mixnet_message_receiver,
ack_receiver,
processed_sender,
task_manager.subscribe(),
);
nym_task::spawn(async move { receiver.run().await });
Ok(NymNodeTester {
test_in_progress: Arc::new(AtomicBool::new(false)),
current_test_nonce: Default::default(),
tester: Arc::new(SyncMutex::new(tester)),
gateway_client: Arc::new(AsyncMutex::new(gateway_client)),
processed_receiver: ReceivedReceiverWrapper::new(processed_receiver),
_task_manager: task_manager,
})
}
pub fn setup_client(self) -> Promise {
future_to_promise(async move { self._setup_client().await.into_promise_result() })
}
}
async fn test_mixnode(
test_packets: Vec<PreparedFragment>,
gateway_client: LockedGatewayClient,
processed_receiver: ReceivedReceiverWrapper,
_test_marker: TestMarker,
timeout: Duration,
) -> Result<NodeTestResult, WasmClientError> {
let num_test_packets = test_packets.len() as u32;
let expected_ack_ids = test_packets
.iter()
.map(|p| p.fragment_identifier)
.collect::<HashSet<_>>();
let mix_packets = test_packets.into_iter().map(|p| p.mix_packet).collect();
// start by clearing any messages that might have been received between tests
processed_receiver.clear_received_channel().await;
// locking the gateway client so that we could get mutable access to data without having to declare
// self mutable
let mut gateway_permit = gateway_client.lock().await;
gateway_permit.batch_send_mix_packets(mix_packets).await?;
let receiver_permit = processed_receiver.lock().await;
let result =
EphemeralTestReceiver::new(num_test_packets, expected_ack_ids, receiver_permit, timeout)
.perform_test()
.await;
Ok(result)
}
#[wasm_bindgen]
impl NymNodeTester {
#[wasm_bindgen(constructor)]
#[allow(clippy::new_ret_no_self)]
pub fn new(gateway_config: GatewayEndpointConfig, topology: WasmNymTopology) -> Promise {
console_log!("constructing node tester!");
NymNodeTesterBuilder::new(gateway_config, topology).setup_client()
}
async fn _new_with_api(
gateway_config: GatewayEndpointConfig,
api_url: String,
) -> Result<Self, WasmClientError> {
NymNodeTesterBuilder::_new_with_api(gateway_config, api_url)
.await?
._setup_client()
.await
}
pub fn new_with_api(gateway_config: GatewayEndpointConfig, api_url: String) -> Promise {
future_to_promise(async move {
Self::_new_with_api(gateway_config, api_url)
.await
.into_promise_result()
})
}
fn prepare_test_packets(
&self,
mixnode_identity: String,
test_nonce: u32,
num_test_packets: u32,
) -> Result<Vec<PreparedFragment>, WasmClientError> {
let test_ext = WasmTestMessageExt::new(test_nonce);
let mut tester_permit = self.tester.lock().expect("mutex got poisoned");
tester_permit
.existing_identity_mixnode_test_packets(mixnode_identity, test_ext, num_test_packets)
.map_err(Into::into)
}
pub fn test_node(
&self,
mixnode_identity: String,
timeout_millis: Option<u64>,
num_test_packets: Option<u32>,
) -> Promise {
// establish test parameters
let timeout = timeout_millis
.map(Duration::from_millis)
.unwrap_or(DEFAULT_TEST_TIMEOUT);
let num_test_packets = num_test_packets.unwrap_or(DEFAULT_TEST_PACKETS);
// mark start of the test
if self.test_in_progress.swap(true, Ordering::SeqCst) {
return WasmClientError::TestInProgress.into_rejected_promise();
}
// prepare test packets
// (I simultaneously feel both disgusted and amazed by this workaround)
let test_nonce = self.current_test_nonce.fetch_add(1, Ordering::Relaxed);
let test_packets = check_promise_result!(self.prepare_test_packets(
mixnode_identity,
test_nonce,
num_test_packets
));
let processed_receiver_clone = self.processed_receiver.clone();
let gateway_client_clone = Arc::clone(&self.gateway_client);
let tester_marker = TestMarker::new(Arc::clone(&self.test_in_progress));
// start doing async things (send packets and watch for anything coming back)
future_to_promise(async move {
test_mixnode(
test_packets,
gateway_client_clone,
processed_receiver_clone,
tester_marker,
timeout,
)
.await
.into_promise_result()
})
}
}
+262
View File
@@ -0,0 +1,262 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use nym_client_core::config::GatewayEndpointConfig;
use nym_crypto::asymmetric::{encryption, identity};
use nym_topology::gateway::GatewayConversionError;
use nym_topology::mix::{Layer, MixnodeConversionError};
use nym_topology::{gateway, mix, MixLayer, NymTopology};
use nym_validator_client::client::MixId;
use serde::{Deserialize, Serialize};
use std::collections::BTreeMap;
use thiserror::Error;
use wasm_bindgen::prelude::wasm_bindgen;
use wasm_bindgen::JsValue;
use wasm_utils::{console_log, simple_js_error};
#[derive(Debug, Error)]
pub enum WasmTopologyError {
#[error("got invalid mix layer {value}. Expected 1, 2 or 3.")]
InvalidMixLayer { value: u8 },
#[error(transparent)]
GatewayConversion(#[from] GatewayConversionError),
#[error(transparent)]
MixnodeConversion(#[from] MixnodeConversionError),
#[error("The provided mixnode map was malformed: {source}")]
MalformedMixnodeMap { source: serde_wasm_bindgen::Error },
#[error("The provided gateway list was malformed: {source}")]
MalformedGatewayList { source: serde_wasm_bindgen::Error },
}
impl From<WasmTopologyError> for JsValue {
fn from(value: WasmTopologyError) -> Self {
simple_js_error(value.to_string())
}
}
#[wasm_bindgen]
#[derive(Debug)]
pub struct WasmNymTopology {
inner: NymTopology,
}
#[wasm_bindgen]
impl WasmNymTopology {
#[wasm_bindgen(constructor)]
pub fn new(
// expected: BTreeMap<MixLayer, Vec<WasmMixNode>>,
// HashMap<MixLayer, Vec<WasmMixNode>> will also work because it has the same json representation
mixnodes: JsValue,
// expected: Vec<WasmGateway>
gateways: JsValue,
) -> Result<WasmNymTopology, WasmTopologyError> {
let mixnodes: BTreeMap<MixLayer, Vec<WasmMixNode>> =
serde_wasm_bindgen::from_value(mixnodes)
.map_err(|source| WasmTopologyError::MalformedMixnodeMap { source })?;
let gateways: Vec<WasmGateway> = serde_wasm_bindgen::from_value(gateways)
.map_err(|source| WasmTopologyError::MalformedGatewayList { source })?;
let mut converted_mixes = BTreeMap::new();
for (layer, nodes) in mixnodes {
let layer_nodes = nodes
.into_iter()
.map(TryInto::try_into)
.collect::<Result<_, _>>()?;
converted_mixes.insert(layer, layer_nodes);
}
let gateways = gateways
.into_iter()
.map(TryInto::try_into)
.collect::<Result<_, _>>()?;
Ok(WasmNymTopology {
inner: NymTopology::new(converted_mixes, gateways),
})
}
pub(crate) fn ensure_contains(&self, gateway_config: &GatewayEndpointConfig) -> bool {
self.inner
.gateways()
.iter()
.any(|g| g.identity_key.to_base58_string() == gateway_config.gateway_id)
}
pub fn print(&self) {
if !self.inner.mixes().is_empty() {
console_log!("mixnodes:");
for (layer, nodes) in self.inner.mixes() {
console_log!("\tlayer {layer}:");
for node in nodes {
console_log!("\t\t{} - {}", node.mix_id, node.identity_key)
}
}
} else {
console_log!("NO MIXNODES")
}
if !self.inner.gateways().is_empty() {
console_log!("gateways:");
for gateway in self.inner.gateways() {
console_log!("\t{}", gateway.identity_key)
}
} else {
console_log!("NO GATEWAYS")
}
}
}
impl From<WasmNymTopology> for NymTopology {
fn from(value: WasmNymTopology) -> Self {
value.inner
}
}
impl From<NymTopology> for WasmNymTopology {
fn from(value: NymTopology) -> Self {
WasmNymTopology { inner: value }
}
}
#[wasm_bindgen]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct WasmMixNode {
pub mix_id: MixId,
#[wasm_bindgen(getter_with_clone)]
pub owner: String,
#[wasm_bindgen(getter_with_clone)]
pub host: String,
pub mix_port: u16,
#[wasm_bindgen(getter_with_clone)]
pub identity_key: String,
#[wasm_bindgen(getter_with_clone)]
pub sphinx_key: String,
pub layer: MixLayer,
#[wasm_bindgen(getter_with_clone)]
pub version: String,
}
#[wasm_bindgen]
impl WasmMixNode {
#[wasm_bindgen(constructor)]
#[allow(clippy::too_many_arguments)]
pub fn new(
mix_id: MixId,
owner: String,
host: String,
mix_port: u16,
identity_key: String,
sphinx_key: String,
layer: MixLayer,
version: String,
) -> Self {
Self {
mix_id,
owner,
host,
mix_port,
identity_key,
sphinx_key,
layer,
version,
}
}
}
impl TryFrom<WasmMixNode> for mix::Node {
type Error = WasmTopologyError;
fn try_from(value: WasmMixNode) -> Result<Self, Self::Error> {
let host = mix::Node::parse_host(&value.host)?;
// try to completely resolve the host in the mix situation to avoid doing it every
// single time we want to construct a path
let mix_host = mix::Node::extract_mix_host(&host, value.mix_port)?;
Ok(mix::Node {
mix_id: value.mix_id,
owner: value.owner,
host,
mix_host,
identity_key: identity::PublicKey::from_base58_string(&value.identity_key)
.map_err(MixnodeConversionError::from)?,
sphinx_key: encryption::PublicKey::from_base58_string(&value.sphinx_key)
.map_err(MixnodeConversionError::from)?,
layer: Layer::try_from(value.layer)
.map_err(|_| WasmTopologyError::InvalidMixLayer { value: value.layer })?,
version: value.version,
})
}
}
#[wasm_bindgen]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct WasmGateway {
#[wasm_bindgen(getter_with_clone)]
pub owner: String,
#[wasm_bindgen(getter_with_clone)]
pub host: String,
pub mix_port: u16,
pub clients_port: u16,
#[wasm_bindgen(getter_with_clone)]
pub identity_key: String,
#[wasm_bindgen(getter_with_clone)]
pub sphinx_key: String,
#[wasm_bindgen(getter_with_clone)]
pub version: String,
}
#[wasm_bindgen]
impl WasmGateway {
#[wasm_bindgen(constructor)]
pub fn new(
owner: String,
host: String,
mix_port: u16,
clients_port: u16,
identity_key: String,
sphinx_key: String,
version: String,
) -> Self {
Self {
owner,
host,
mix_port,
clients_port,
identity_key,
sphinx_key,
version,
}
}
}
impl TryFrom<WasmGateway> for gateway::Node {
type Error = WasmTopologyError;
fn try_from(value: WasmGateway) -> Result<Self, Self::Error> {
let host = gateway::Node::parse_host(&value.host)?;
// try to completely resolve the host in the mix situation to avoid doing it every
// single time we want to construct a path
let mix_host = gateway::Node::extract_mix_host(&host, value.mix_port)?;
Ok(gateway::Node {
owner: value.owner,
host,
mix_host,
clients_port: value.clients_port,
identity_key: identity::PublicKey::from_base58_string(&value.identity_key)
.map_err(GatewayConversionError::from)?,
sphinx_key: encryption::PublicKey::from_base58_string(&value.sphinx_key)
.map_err(GatewayConversionError::from)?,
version: value.version,
})
}
}
+12
View File
@@ -0,0 +1,12 @@
[package]
name = "async-file-watcher"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
log = "0.4"
tokio = { workspace = true, features = ["time"] }
futures = "0.3"
notify = "5.1.0"
+158
View File
@@ -0,0 +1,158 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use futures::channel::mpsc;
use futures::StreamExt;
use notify::event::{DataChange, MetadataKind, ModifyKind};
use notify::{Config, Event, EventKind, RecommendedWatcher, RecursiveMode, Watcher};
use std::collections::HashMap;
use std::path::{Path, PathBuf};
use std::time::Duration;
use tokio::time::Instant;
pub type FileWatcherEventSender = mpsc::UnboundedSender<Event>;
pub type FileWatcherEventReceiver = mpsc::UnboundedReceiver<Event>;
/// Simple file watcher that sends a notification whenever there was any changed in the watched file.
pub struct AsyncFileWatcher {
path: PathBuf,
watcher: RecommendedWatcher,
is_watching: bool,
filters: Option<Vec<EventKind>>,
last_received: HashMap<EventKind, Instant>,
tick_duration: Duration,
inner_rx: mpsc::UnboundedReceiver<notify::Result<Event>>,
event_sender: FileWatcherEventSender,
}
impl AsyncFileWatcher {
pub fn new_file_changes_watcher<P: AsRef<Path>>(
path: P,
event_sender: FileWatcherEventSender,
) -> notify::Result<Self> {
Self::new(
path,
event_sender,
Some(vec![
EventKind::Modify(ModifyKind::Data(DataChange::Content)),
EventKind::Modify(ModifyKind::Data(DataChange::Any)),
EventKind::Modify(ModifyKind::Metadata(MetadataKind::Any)),
]),
None,
)
}
pub fn new<P: AsRef<Path>>(
path: P,
event_sender: FileWatcherEventSender,
filters: Option<Vec<EventKind>>,
tick_duration: Option<Duration>,
) -> notify::Result<Self> {
let watcher_config = Config::default();
let (inner_tx, inner_rx) = mpsc::unbounded();
let watcher = RecommendedWatcher::new(
move |res| {
if let Err(_err) = inner_tx.unbounded_send(res) {
// I guess it's theoretically possible during shutdown?
log::error!(
"failed to send watched file event - the received must have been dropped!"
);
}
},
watcher_config,
)?;
Ok(AsyncFileWatcher {
path: path.as_ref().to_path_buf(),
watcher,
is_watching: false,
filters,
last_received: HashMap::new(),
tick_duration: tick_duration.unwrap_or(Duration::from_secs(5)),
inner_rx,
event_sender,
})
}
pub fn with_filters(mut self, filters: Option<Vec<EventKind>>) -> Self {
self.filters = filters;
self
}
pub fn with_filter(mut self, filter: EventKind) -> Self {
match &mut self.filters {
None => {
self.filters = Some(vec![filter]);
}
Some(filters) => filters.push(filter),
}
self
}
fn should_propagate(&self, event: &Event, now: Instant) -> bool {
// when testing I was consistently getting two `Modify(Data(Any))` events in quick succession
// (probably to modify content and metadata).
// we really only want to propagate one of them
if let Some(previous) = self.last_received.get(&event.kind) {
if now.duration_since(*previous) < self.tick_duration {
return false;
}
}
let Some(filters) = &self.filters else {
return true
};
for filter in filters {
if &event.kind == filter {
return true;
}
}
false
}
fn start_watching(&mut self) -> notify::Result<()> {
self.is_watching = true;
self.watcher.watch(&self.path, RecursiveMode::NonRecursive)
}
fn stop_watching(&mut self) -> notify::Result<()> {
self.is_watching = false;
self.watcher.unwatch(&self.path)
}
pub async fn watch(&mut self) -> notify::Result<()> {
self.start_watching()?;
while let Some(event) = self.inner_rx.next().await {
match event {
Ok(event) => {
let now = Instant::now();
if self.should_propagate(&event, now) {
self.last_received.insert(event.kind.clone(), now);
if let Err(_err) = self.event_sender.unbounded_send(event) {
log::error!("the file watcher receiver has been dropped!");
}
} else {
log::debug!("will not propagate information about {:?}", event);
}
}
Err(err) => {
// TODO: to be determined if this should stop the whole thing or not
// (need to know what kind of errors can be returned)
log::error!(
"encountered an error while watching {:?}: {err}",
self.path.as_path()
);
}
}
}
self.stop_watching()
}
pub fn is_watching(&self) -> bool {
self.is_watching
}
}
+24
View File
@@ -0,0 +1,24 @@
[package]
name = "nym-bandwidth-controller"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
bip39 = { workspace = true }
rand = "0.7.3"
thiserror = "1.0"
url = "2.2"
nym-coconut-interface = { path = "../coconut-interface" }
nym-credential-storage = { path = "../credential-storage" }
nym-credentials = { path = "../credentials" }
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 }
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.nym-validator-client]
path = "../client-libs/validator-client"
features = ["nyxd-client"]
@@ -0,0 +1,89 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::error::BandwidthControllerError;
use nym_coconut_interface::{Base58, Parameters};
use nym_credential_storage::storage::Storage;
use nym_credentials::coconut::bandwidth::{BandwidthVoucher, TOTAL_ATTRIBUTES};
use nym_credentials::coconut::utils::obtain_aggregate_signature;
use nym_crypto::asymmetric::{encryption, identity};
use nym_network_defaults::VOUCHER_INFO;
use nym_validator_client::nyxd::traits::CoconutBandwidthSigningClient;
use nym_validator_client::nyxd::traits::DkgQueryClient;
use nym_validator_client::nyxd::tx::Hash;
use nym_validator_client::nyxd::Coin;
use nym_validator_client::CoconutApiClient;
use rand::rngs::OsRng;
use state::{KeyPair, State};
use std::str::FromStr;
pub mod state;
pub async fn deposit<C>(client: &C, amount: Coin) -> Result<State, BandwidthControllerError>
where
C: CoconutBandwidthSigningClient,
{
let mut rng = OsRng;
let signing_keypair = KeyPair::from(identity::KeyPair::new(&mut rng));
let encryption_keypair = KeyPair::from(encryption::KeyPair::new(&mut rng));
let params = Parameters::new(TOTAL_ATTRIBUTES).unwrap();
let voucher_value = amount.amount.to_string();
let tx_hash = client
.deposit(
amount,
String::from(VOUCHER_INFO),
signing_keypair.public_key.clone(),
encryption_keypair.public_key.clone(),
None,
)
.await?
.transaction_hash
.to_string();
let voucher = BandwidthVoucher::new(
&params,
voucher_value,
VOUCHER_INFO.to_string(),
Hash::from_str(&tx_hash).map_err(|_| BandwidthControllerError::InvalidTxHash)?,
identity::PrivateKey::from_base58_string(&signing_keypair.private_key)?,
encryption::PrivateKey::from_base58_string(&encryption_keypair.private_key)?,
);
let state = State { voucher, params };
Ok(state)
}
pub async fn get_credential<C: DkgQueryClient + Send + Sync, St: Storage>(
state: &State,
client: &C,
storage: &St,
) -> Result<(), BandwidthControllerError> {
let epoch_id = client.get_current_epoch().await?.epoch_id;
let threshold = client
.get_current_epoch_threshold()
.await?
.ok_or(BandwidthControllerError::NoThreshold)?;
let coconut_api_clients = CoconutApiClient::all_coconut_api_clients(client, epoch_id).await?;
let signature = obtain_aggregate_signature(
&state.params,
&state.voucher,
&coconut_api_clients,
threshold,
)
.await?;
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(),
)
.await?;
Ok(())
}
@@ -1,8 +1,8 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// Copyright 2022-2023 - 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::{BandwidthVoucher, TOTAL_ATTRIBUTES};
use nym_crypto::asymmetric::{encryption, identity};
@@ -29,7 +29,16 @@ impl From<encryption::KeyPair> for KeyPair {
}
}
pub(crate) struct State {
pub struct State {
pub voucher: BandwidthVoucher,
pub params: Parameters,
}
impl State {
pub fn new(voucher: BandwidthVoucher) -> Self {
State {
voucher,
params: Parameters::new(TOTAL_ATTRIBUTES).unwrap(),
}
}
}
+41
View File
@@ -0,0 +1,41 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use nym_coconut_interface::CoconutError;
use nym_credential_storage::error::StorageError;
use nym_credentials::error::Error as CredentialsError;
use nym_crypto::asymmetric::encryption::KeyRecoveryError;
use nym_crypto::asymmetric::identity::Ed25519RecoveryError;
use nym_validator_client::error::ValidatorClientError;
use thiserror::Error;
#[derive(Debug, Error)]
pub enum BandwidthControllerError {
#[cfg(not(target_arch = "wasm32"))]
#[error("Nyxd error: {0}")]
Nyxd(#[from] nym_validator_client::nyxd::error::NyxdError),
#[error("There was a credential storage error - {0}")]
CredentialStorageError(#[from] StorageError),
#[error("Coconut error - {0}")]
CoconutError(#[from] CoconutError),
#[error("Validator client error - {0}")]
ValidatorError(#[from] ValidatorClientError),
#[error("Credential error - {0}")]
CredentialError(#[from] CredentialsError),
#[error("Could not parse Ed25519 data")]
Ed25519ParseError(#[from] Ed25519RecoveryError),
#[error("Could not parse X25519 data")]
X25519ParseError(#[from] KeyRecoveryError),
#[error("The tx hash provided is not valid")]
InvalidTxHash,
#[error("Threshold not set yet")]
NoThreshold,
}
@@ -1,34 +1,12 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::error::GatewayClientError;
use crate::error::BandwidthControllerError;
#[cfg(target_arch = "wasm32")]
use crate::wasm_mockups::Storage;
#[cfg(not(target_arch = "wasm32"))]
#[cfg(not(feature = "mobile"))]
use nym_credential_storage::error::StorageError;
use nym_credential_storage::storage::Storage;
#[cfg(not(target_arch = "wasm32"))]
#[cfg(feature = "mobile")]
use mobile_storage::Storage;
#[cfg(not(target_arch = "wasm32"))]
#[cfg(feature = "mobile")]
use mobile_storage::StorageError;
#[cfg(target_arch = "wasm32")]
use crate::wasm_mockups::StorageError;
#[cfg(not(target_arch = "wasm32"))]
#[cfg(not(feature = "mobile"))]
use nym_credential_storage::error::StorageError;
#[cfg(target_arch = "wasm32")]
use crate::wasm_mockups::{Client, CosmWasmClient};
use std::str::FromStr;
#[cfg(not(target_arch = "wasm32"))]
use validator_client::{nyxd::CosmWasmClient, Client};
use {
nym_coconut_interface::Base58,
nym_credentials::coconut::{
@@ -36,40 +14,38 @@ use {
},
};
// TODO: make it nicer for wasm (I don't want to touch it for this experiment)
#[cfg(not(target_arch = "wasm32"))]
use nym_validator_client::nyxd::traits::DkgQueryClient;
#[cfg(target_arch = "wasm32")]
use crate::wasm_mockups::PersistentStorage;
use crate::wasm_mockups::DkgQueryClient;
#[cfg(not(target_arch = "wasm32"))]
#[cfg(not(feature = "mobile"))]
use nym_credential_storage::PersistentStorage;
pub mod acquire;
pub mod error;
#[cfg(target_arch = "wasm32")]
pub mod wasm_mockups;
#[cfg(not(target_arch = "wasm32"))]
#[cfg(feature = "mobile")]
use mobile_storage::PersistentStorage;
#[derive(Clone)]
#[allow(dead_code)]
pub struct BandwidthController<C: Clone, St: Storage = PersistentStorage> {
pub struct BandwidthController<C, St: Storage> {
storage: St,
nyxd_client: Client<C>,
client: C,
}
impl<C, St> BandwidthController<C, St>
where
C: CosmWasmClient + Sync + Send + Clone,
St: Storage + Clone + 'static,
{
pub fn new(storage: St, nyxd_client: Client<C>) -> Self {
BandwidthController {
storage,
nyxd_client,
}
impl<C, St: Storage> BandwidthController<C, St> {
pub fn new(storage: St, client: C) -> Self {
BandwidthController { storage, client }
}
pub fn storage(&self) -> &St {
&self.storage
}
pub async fn prepare_coconut_credential(
&self,
) -> Result<(nym_coconut_interface::Credential, i64), GatewayClientError> {
) -> Result<(nym_coconut_interface::Credential, i64), BandwidthControllerError>
where
C: DkgQueryClient + Sync + Send,
{
let bandwidth_credential = self.storage.get_next_coconut_credential().await?;
let voucher_value = u64::from_str(&bandwidth_credential.voucher_value)
.map_err(|_| StorageError::InconsistentData)?;
@@ -84,12 +60,9 @@ where
.map_err(|_| StorageError::InconsistentData)?;
#[cfg(not(target_arch = "wasm32"))]
let coconut_api_clients = validator_client::CoconutApiClient::all_coconut_api_clients(
&self.nyxd_client,
epoch_id,
)
.await
.expect("Could not query api clients");
let coconut_api_clients =
nym_validator_client::CoconutApiClient::all_coconut_api_clients(&self.client, epoch_id)
.await?;
#[cfg(target_arch = "wasm32")]
let coconut_api_clients = vec![];
let verification_key = obtain_aggregate_verification_key(&coconut_api_clients).await?;
@@ -109,7 +82,22 @@ where
))
}
pub async fn consume_credential(&self, id: i64) -> Result<(), GatewayClientError> {
pub async fn consume_credential(&self, id: i64) -> Result<(), BandwidthControllerError> {
// JS: shouldn't we send some contract/validator/gateway message here to actually, you know,
// consume it?
Ok(self.storage.consume_coconut_credential(id).await?)
}
}
impl<C, St> Clone for BandwidthController<C, St>
where
C: Clone,
St: Storage + Clone,
{
fn clone(&self) -> Self {
BandwidthController {
storage: self.storage.clone(),
client: self.client.clone(),
}
}
}
@@ -0,0 +1,17 @@
// Copyright 2022-2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use std::marker::PhantomData;
pub struct DirectSigningNyxdClient {}
pub trait DkgQueryClient {}
// impl CosmWasmClient for DirectSigningNyxdClient {}
#[derive(Clone)]
pub struct Client<C> {
_phantom: PhantomData<C>,
}
impl<C> DkgQueryClient for Client<C> {}
+19 -2
View File
@@ -1,6 +1,6 @@
[package]
name = "nym-bin-common"
version = "0.2.0"
version = "0.5.0"
description = "Common code for nym binaries"
edition = { workspace = true }
authors = { workspace = true }
@@ -8,6 +8,7 @@ license = { workspace = true }
repository = { workspace = true }
[dependencies]
atty = "0.2"
clap = { version = "4.0", features = ["derive"] }
clap_complete = "4.0"
clap_complete_fig = "4.0"
@@ -15,9 +16,25 @@ log = { workspace = true }
pretty_env_logger = "0.4.0"
semver = "0.11"
serde = { workspace = true, features = ["derive"], optional = true }
serde_json = { workspace = true, optional = true }
## tracing
tracing-appender = { version = "0.2.2", optional = true }
tracing-subscriber = { version = "0.3.16", features = [
"env-filter",
], optional = true }
tracing-tree = { version = "0.2.2", optional = true }
[build-dependencies]
vergen = { version = "=7.4.3", default-features = false, features = ["build", "git", "rustc", "cargo"] }
vergen = { version = "=7.4.3", default-features = false, features = [
"build",
"git",
"rustc",
"cargo",
] }
[features]
default = []
output_format = ["serde", "serde_json"]
tracing = ["tracing-appender", "tracing-subscriber", "tracing-tree"]

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