Compare commits

..

211 Commits

Author SHA1 Message Date
Jon Häggblad f9fb3f6988 Upgrade to latest sqlite everywhere 2023-10-03 11:25:10 +02:00
Jędrzej Stuczyński 56a384ea09 [wasm-client] keeping ownership over 'ReceivedBufferRequestSender' channel when spawning 'ResponsePusher' (#3945)
* [wasm-client] keeping ownership over 'ReceivedBufferRequestSender' channel when spawning 'ResponsePusher'

* Bump version of Typescript SDK to RC.10

* GitHub Actions workflow to publish SDK to NPM

* Bump package version manually

---------

Co-authored-by: Mark Sinclair <mmsinclair@users.noreply.github.com>
2023-10-03 09:36:25 +01:00
Jon Häggblad c7da8a7594 ci: reorder nightly build matrix to group on toolchain 2023-10-03 09:09:51 +02:00
Jon Häggblad da404b636d Add sdk example for geo-aware topology provider (#3941)
* Add sdk example for geo-aware topology provider

* Re-export geo topology types
2023-10-02 14:21:53 +02:00
Jon Häggblad d8821c26bc ci: move nightly-nym-wallet to custom-linux 2023-10-02 14:07:13 +02:00
Jon Häggblad a06c2fb70c ci: fail-fast set to false 2023-10-02 12:59:04 +02:00
Jon Häggblad 908191914f ci: use continue-on-error so we get notifications 2023-10-02 08:29:22 +02:00
Jon Häggblad b05ce4c733 ci: don't fail-fast on nightly build 2023-10-02 08:17:19 +02:00
Jon Häggblad 382464a143 ci: nightly nym-wallet reorder steps to fix cwd 2023-10-01 23:35:49 +02:00
Jon Häggblad 05f3af765b ci: nightly nym-wallet install deps 2023-10-01 23:32:44 +02:00
Jon Häggblad a9d3e5047d ci: add workflow_dispatch to ci-contracts-schema 2023-10-01 23:09:56 +02:00
Jon Häggblad c424f7d3f7 ci: fix bug in trigger 2023-10-01 23:09:37 +02:00
Jon Häggblad 093bb18119 ci: move work in progress files to subdirectory 2023-10-01 23:04:58 +02:00
Jon Häggblad 4d5bd0ddf4 ci: remove old unused nightly build files 2023-10-01 23:02:09 +02:00
Jon Häggblad 48d7e934b7 ci: remove commented out code in nightly 2023-10-01 23:00:47 +02:00
Jon Häggblad ff7c359d0e ci: try using normal matrix build 2023-10-01 22:54:05 +02:00
Jon Häggblad d0b91444a0 ci: revert back to debug mode for nightly 2023-10-01 22:43:07 +02:00
Jon Häggblad 8c39cdf434 ci: nightly build in release mode 2023-10-01 21:42:17 +02:00
Jon Häggblad fef164bf93 ci: nightly-build tidy 2023-10-01 21:17:15 +02:00
Jon Häggblad 759cb4b9b4 ci: fix workflow_dispatch for nightly build 2023-10-01 19:54:31 +02:00
Jon Häggblad a800cbae02 Merge pull request #3943 from nymtech/jon/ci-work
Optimize some CI builds
2023-09-30 17:11:38 +02:00
Jon Häggblad e4a2c639fc Add names to contract job steps 2023-09-30 17:05:46 +02:00
Jon Häggblad a67a9c4b32 Try adding conditional to avoid duplicate builds 2023-09-30 16:58:19 +02:00
Jon Häggblad a450e2910f Add workflow_dispatch to nightly build 2023-09-30 16:58:19 +02:00
Jon Häggblad bd75c9c78d ci: disable sccache
sccache keeps randomly failing, try disabling to see the impact on CI
build times
2023-09-30 16:58:19 +02:00
Jon Häggblad fbfec25228 Remove nightly toolchain from contracts and nightly build
Building with the beta toolchain should be enough to alert us to
impending compiler and clippy changes.
2023-09-30 16:58:19 +02:00
Tommy Verrall 81db915401 Merge pull request #3933 from nymtech/feature/nym-api-tests
Adding missing tests and cleaning up Types files
2023-09-30 11:30:56 +02:00
Jon Häggblad b27c7d0b14 ci: fix contracts-wasm target rename 2023-09-29 23:51:20 +02:00
Jon Häggblad ed3a58b6a2 Tidy up Makefile (#3934)
* Attempt at simplifying top-level Makefile

* Another sweep at tidying up Makefile

* Further refinements

* Remove deprecated clippy-happy and no-clippy targets
2023-09-29 22:40:01 +02:00
mx 93733e73a2 Merge pull request #3911 from nymtech/feature/documentation/events-page
DOC/dev-portal: Initialize events page & prep HCPP23 pages
2023-09-28 17:03:57 +00:00
serinko d7f69433d6 finished - ready for final review 2023-09-28 17:22:07 +02:00
serinko ee282cfe9d finished - ready for final review 2023-09-28 17:15:10 +02:00
serinko 1c13d466b1 spell checks 2023-09-28 16:14:53 +02:00
serinko 238dd533a8 finish ircd configuration guide 2023-09-28 16:11:42 +02:00
serinko 2d925c24c7 edit ircd_config.toml configuration 2023-09-28 10:28:23 +02:00
serinko e6d5c5ec8c add ircd_config.toml configuration 2023-09-28 10:21:14 +02:00
serinko b4a7b9ed75 Merge branch 'feature/documentation/events-page' of github_serinko:nymtech/nym into feature/documentation/events-page 2023-09-26 23:16:10 +02:00
serinko 7bed01902e add allow.list setup 2023-09-26 23:15:47 +02:00
mfahampshire a77980a0da added event links page 2023-09-26 22:53:25 +02:00
mfahampshire d328bc15f8 add max hcpp event page to summary 2023-09-26 22:53:13 +02:00
serinko 871d88e3ed add ircd intro 2023-09-26 22:15:53 +02:00
serinko 3904afa747 change comments above commands 2023-09-26 15:25:25 +02:00
serinko 2f8442760f add wget command to download binary 2023-09-26 13:56:47 +02:00
serinko ecdd3648ae small edits 2023-09-26 12:50:12 +02:00
serinko 0218f436b2 edits in build nym section 2023-09-25 12:52:55 +02:00
serinko 3c26a4d4f6 added mac setup to matrix user guide 2023-09-25 12:43:18 +02:00
serinko bedbe34f17 added matrix NC guide 2023-09-25 12:40:50 +02:00
serinko 26c822d637 added monero wallet NC guide 2023-09-25 12:31:46 +02:00
serinko 359be442bc add monero setup giff 2023-09-25 11:52:51 +02:00
serinko 6f14c3b0fd intro edits & flow change 2023-09-25 11:31:28 +02:00
benedettadavico 8bb0e8c510 Adding missing tests and cleaning up Types files 2023-09-22 17:38:03 +02:00
Jon Häggblad 27d7f043e7 Add missing toolchain in ci-build-upload-binaries.yml 2023-09-22 17:12:12 +02:00
Jon Häggblad 806476d4b4 Rename the files for release workflows (#3932) 2023-09-22 16:46:45 +02:00
Jędrzej Stuczyński 5a0db2aea4 always using port 443 for tls gateway connection (#3927)
* always using port 443 for tls gateway connection

* bumping up rc version

* hack: additional hardcoded gateways

it disables topology refresh

* Add NPM packages to tool for bumping versions

* Bump RC versions of SDK packages

* Use manual gateway details

* Add progress to `publish.sh` script

* Add docs for WSS workaround

---------

Co-authored-by: Mark Sinclair <mmsinclair@users.noreply.github.com>
2023-09-22 15:35:14 +01:00
Jon Häggblad f8733f59c5 Another round of tidy gh workflows (#3931)
* Remove unused Makefile target

* Split out ci-contracts-upload-binaries

* Remove the contracts from the main workflow

* Rename build-and-upload-binaries-ci

* Rename network-explorer name

* Rename network-explorer filename and check-merge-conflicts

* Rename three more workflows

* Rename sdk-publish

* Remove deprecated clippy-all

* Rename matrix includes json and delete one that is unused

* Typo in filename

* Delete nym-wallet-release.yml
2023-09-22 16:12:33 +02:00
Jędrzej Stuczyński 56f351538b custom Debug impl for mix::Node and gateway::Node (#3930) 2023-09-22 14:32:27 +01:00
Raphaël Walther 36bcfc132d Merge pull request #3929 from nymtech/move_workflow_custom_runner
Github Actions: Move nightly builds to custom runner
2023-09-22 14:09:11 +02:00
Raphaël Walther 6e245208ac Github Actions: Move nightly builds to custom runner 2023-09-22 14:01:07 +02:00
Jon Häggblad a3eb274a3b Reverse naming for a whole bunch of workflows (#3928) 2023-09-22 11:53:05 +02:00
Jon Häggblad 0ddc6c4bc8 Update some CI workflow names (#3926)
* Rename two workflows to fit naming scheme

* ci-build name change

* Rename 3 more workflows to ci- names

* Rename wallet.yml and nym-wallet-nightly-build to reverse naming scheme

* Rename to ci-contracts.yml

* Delete nym-wallet webdriverio workflow

* Update some workflow names
2023-09-22 11:32:49 +02:00
Jędrzej Stuczyński eccd6e16e2 Feature/mixfetch disconnect (#3890)
* js error message

* Ability to explicitly disconnect mixfetch

* removed unused import

* added disconnect method directly to sdk package

* simplifying error throw

Co-authored-by: Mark Sinclair <14054343+mmsinclair@users.noreply.github.com>

* added onunload event listener handler

* Using global instance of mixfetch to disconnect

Co-authored-by: Mark Sinclair <14054343+mmsinclair@users.noreply.github.com>

* Bump RC versions

* MixFetch, move unload handler to creation and check for undefined `window`

* Bump RC version

* Force TLS on mixFetch demo

* Add info about working around mixed content errors for mixFetch

---------

Co-authored-by: Mark Sinclair <14054343+mmsinclair@users.noreply.github.com>
Co-authored-by: Mark Sinclair <mmsinclair@users.noreply.github.com>
2023-09-22 10:25:46 +01:00
Jon Häggblad 3ccec3857e nym-wallet-nightly-build: enable notification 2023-09-22 10:17:02 +02:00
Raphaël Walther 5fd68ae909 Merge pull request #3925 from nymtech/move_workflow_macos
Github Actions: Move nightly builds on dispatch to custom MacOS runner
2023-09-22 10:03:22 +02:00
Jon Häggblad fb04a85b5a nm-wallet-nightly-build: reenable steps 2023-09-22 09:54:15 +02:00
Jon Häggblad 825e190c37 Fix nym-wallet-nightly-build toolchain 2023-09-22 09:45:44 +02:00
Raphaël Walther 7e60dea257 Github Actions: Move nightly builds on dispatch to custom MacOS runner 2023-09-22 09:37:35 +02:00
Jon Häggblad 014e5486a8 Initial work on splitting out nym-wallet nightliy build (#3924) 2023-09-22 09:26:24 +02:00
Tommy Verrall 33c8b2e963 Merge pull request #3923 from nymtech/move_custom_runner 2023-09-21 18:06:12 +02:00
Raphaël Walther a727d96fe7 Github Actions: Move nightly to custom-linux 2023-09-21 17:58:42 +02:00
Jędrzej Stuczyński d3325c176f added forceTls argument to 'MixFetchOptsSimple' (#3907)
* Squashing commits

added forceTls argument to 'MixFetchOptsSimple'

made forceTls flag optional in mix fetch opts

whacking those moles

* GitHub Actions: install node

---------

Co-authored-by: Mark Sinclair <mmsinclair@users.noreply.github.com>
2023-09-21 16:13:31 +01:00
Tommy Verrall de47061558 Merge pull request #3921 from nymtech/tommy-feat/print-gateway-nr-config-path
printing initialised gateway-NR's config path to stderr
2023-09-21 17:02:49 +02:00
Tommy Verrall f1947d1370 Merge pull request #3922 from nymtech/add_nightly_build_on_trigger
Add a separate nightly workflow with a trigger
2023-09-21 17:00:22 +02:00
Raphaël Walther fba694f61a Add a separate nightly workflow with a trigger 2023-09-21 16:52:01 +02:00
Jędrzej Stuczyński 1c1d02f15a using correct method for converting PathBuf to impl Display 2023-09-21 15:20:41 +01:00
Jędrzej Stuczyński cb910f41bd printing initialised gateway-NR's config path to stderr 2023-09-21 15:17:35 +01:00
Raphaël Walther e6d3083eea Merge pull request #3920 from nymtech/enable_trigger_on_workflow
Github Actions: enable trigger on nightly workflow
2023-09-21 16:10:55 +02:00
Mark Sinclair b97f8c1145 Mix Fetch RC Release (#3910)
* Bug fix `mixFetch` build

* Batch integration tests for mixFetch

* Bump RC version

* Tidy up READMEs

* Bump version to RC4 and fix up a few interfaces

* Bump version to RC5 and fix opts

* NodeJS SDK

* mixFetch usage example

* Update internal dev tester readme

* Add NodeJS packages to publish script

* Update lock file

* Upgrade `lerna`

---------

Co-authored-by: Mark Sinclair <mmsinclair@users.noreply.github.com>
2023-09-21 15:09:34 +01:00
Raphaël Walther 0c678553af Github Actions: enable trigger on nightly workflow 2023-09-21 15:59:39 +02:00
Mark Sinclair 96e740ec22 Update wasm_sdk.yml 2023-09-21 14:55:52 +01:00
Tommy Verrall 8affba8be4 Merge pull request #3908 from nymtech/jon/remove-growth-test-and-earn
Remove unused test-and-earn from nym-connect
2023-09-21 15:37:32 +02:00
fmtabbara 81a0729f52 fix linting 2023-09-21 13:30:15 +01:00
fmtabbara e85c7b6f5f remove test and earn from bundle 2023-09-21 12:48:42 +01:00
fmtabbara 33838eae8c remove test and earn context provider 2023-09-21 12:35:33 +01:00
fmtabbara 1c2e3c754e Revert "Remove unused test-and-earn from nym-connect"
This reverts commit cd3d4ffc9f.
2023-09-21 12:33:17 +01:00
Tommy Verrall a9a1eecfff Merge pull request #3885 from nymtech/update/issue-3884/delegations-page-updates
Update/issue 3884/delegations page updates
2023-09-21 12:45:12 +02:00
Tommy Verrall 95e3971b9c Merge pull request #3912 from nymtech/jessgess-copyedit-1
Explorer copyedits
2023-09-20 18:34:55 +02:00
Jess 21cf6c974f Update index.tsx 2023-09-20 17:20:17 +01:00
Jess f536a204ba Update index.tsx 2023-09-20 17:16:31 +01:00
serinko 5eb935a079 guide to electrum setup 2023-09-20 17:18:44 +02:00
Jędrzej Stuczyński 114d92f93f Feature/gateway inbuilt nr (#3877)
* changed NymConfigTemplate trait to call 'template' by reference

* network requester lib

* introduced generic parameter to 'MixTrafficController' to allow non-remote gateways

* allowing for custom gateway sender

* types cleanup

* minor gateway cmds refactor + initial NR work

* wip

* running a NR inside gateway

note: this NR isnt tied to the gateway yet

* rebase fixes

* propagating same shutdown handle

* wip

* starting NR with appropriate local transceiver

* fixed premature shutdown

* wiring up PacketRouter

* both ends wired together

* actually working

so much cleanup to do now

* started removing dead code

* wip

* temp: hardcode gateway

* further cleanup

* fixed build of other binaries

* setup-network-requester subcmd

* overriding NR config in gateway init/run

* wip making it wasm-compatible [again]

* refactored 'GatewaySetup'

* clippy and friends

* removed debug code

* rust 1.72 lints

* ensuring local gateway is available + some comments

* correctly putting network requester data in the same underlying details struct

* improved gateway errors

* changed 'network_requester_config' deserialization

* missing clap annotation for 'enabled' flag in 'setup-network-requester' command

* saving config file after 'setup-network-requester'

* removed dead code

* review comments

* make embedded NR wait for gateway to come online (for at most 70min)

* fixed shutdown on successful gateway wait

* updated NR config override
2023-09-20 15:47:05 +01:00
serinko c7be467685 DOC: dev-portal: initializ events page 2023-09-20 14:46:25 +02:00
Tommy Verrall 6dc8148372 Merge pull request #3904 from nymtech/jon/nr-enable-loop-cover-traffic-by-default
Enable loop cover traffic by default in NR
2023-09-20 13:27:01 +02:00
Jon Häggblad cd3d4ffc9f Remove unused test-and-earn from nym-connect 2023-09-20 13:20:25 +02:00
Tommy Verrall d6c27c0985 Merge pull request #3901 from nymtech/jon/handle-socks5-udp-not-supported
Error instead of crash on UDP and BIND not supported
2023-09-20 10:22:20 +02:00
Tommy Verrall 9d8280986d Merge pull request #3899 from nymtech/jon/fix-profile-warnings
Fix all the cargo warnings
2023-09-20 09:34:16 +02:00
serinko 8aa8f07cb8 DOC: smoosh-faq.md - quotation syntax fix 2023-09-19 16:47:24 +00:00
serinko 98c03ffa56 DOC: smoosh-faq.md - quotation syntax fix 2023-09-19 16:41:44 +00:00
serinko 0a3a31dedc DOC: smoosh-faq.md - quotation syntax fix 2023-09-19 16:40:27 +00:00
serinko 79ae9b69ef DOC: smoosh-faq.md - quotation syntax fix 2023-09-19 16:39:17 +00:00
serinko 549b58311d Merge pull request #3906 from nymtech/patch/documentation/syntax-fix
Fixing bugs in mdbook build errors (links, admonish, path) -> CI/CD runs without a problem.
2023-09-19 15:52:57 +00:00
serinko 279b494a60 corrected surbs line 2023-09-19 12:54:36 +02:00
serinko 3be0a6cf65 fixed broken code path 2023-09-19 10:51:03 +02:00
serinko 9b8add1daa fixed broken links 2023-09-19 10:36:25 +02:00
Mark Sinclair 2193378d42 Merge pull request #3905 from nymtech/bugfix/ci-cd-docs
Docs: make shell scripts exit on errors so that CI jobs fail on build errors
2023-09-19 09:28:33 +01:00
Mark Sinclair c57263e91b Docs: make shell scripts exit on errors so that CI jobs fail on build errors 2023-09-19 09:22:33 +01:00
Jon Häggblad 74d8d82b74 Tweak comments in template.rs 2023-09-18 23:08:21 +02:00
Jon Häggblad 397e8223bc Enable loop cover traffic by default in NR 2023-09-18 23:04:20 +02:00
Mark Sinclair 685f26792f Typescript SDK Nextra Docs (#3880)
* Remove pnpm-lock.yaml

* Add initial documentation

* updating packages and disconnecting on mixFetch when unmount

* handle the mixFetch error

* remove the mixfetch disconexion

* using now rc5 version

* Update overview

* Update installation page

* wip startong

* Copy edits and improving some of the formatting and styling

* Improve naming

* Add CosmosKit example

* Linting

* Update next.js

* Remove lock file

* More CosmosKit docs

* wip

* cleaninig a bit

* quick fix for wallet error

* wip wallet ui

* wip wallet ui

* more wallet ui

* fixing key error

* wip

* Example code

* Add custom style for code blocks to limit their height and scroll

* Change bg on darkmode

* Add styling to darkmode

* Reorg CSS - tbc

* Move example code

* Ledger support in Cosmos Kit - wip

* Change default app to Typescript

* Remove static export

* Tidy up wallet UI

* Set theme colour by hue

* Force dark mode theme

* some wallet ui

* Style buttons sidebar

* Sidebar colors

* Links styling

* Style callouts

* Add styling to button, chips, progress motion component

* Style agenda

* adding loaders

* wallet loaders

* traffic styles

* Fix colours

* Add links to methods

* Add execute code block

* Add traffic codeblock

* Add mixfetch codeblock

* Add Cosmokit codeblock

* Update info on getting started

* fixing build

* Fix build error

* Fix theme

* Fix filenames on examples

* Add copy to CosmosKit example

---------

Co-authored-by: Mark Sinclair <mmsinclair@users.noreply.github.com>
Co-authored-by: Gala <calero.vg@gmail.com>
Co-authored-by: Lorexia <alexia.lorenza.martinel@protonmail.com>
2023-09-18 19:46:32 +01:00
Jon Häggblad 109659152d Remove leftover .faq files 2023-09-18 17:11:18 +02:00
benedetta davico 73a75f7aef Master (#3888)
* removed old wallet address flag again

* Add updates to community list projects

* Update cd-docs.yml

* Update cd-docs.yml

* [hotfix]: don't assign invalid fields when crossing the JS boundary (#3805)

* [hotfix]: don't assign invalid fields when crossing the JS boundary

* eslint

* changelog update and version bump

* changed last vers. checkout to master

* corrected path of config

* make binaries executable

* docs: typescript.md - changing variables

* docs: rust.md - changing variables

* docs: vesting-contract.md - changing variables

* docs: mixnet-contract.md - changing variables

* docs: all variables changed

* operators: all variables finished

* dev-portal: mixnet-integration.md - variable changed

* dev-portal: faq.md - variable changed

* dev-portal: moredo.md up to date w NC default

* dev-portal: telegram.md - added banner & minor fix

* dev-portal: matrix.md - added banner

* PR finished - ready for review and merge

* removed all instances of platform_release_version var

* removed all instances of platform_release_version var

* changed version bumper script: removed platform_release_version references

* changed comment

* updating changelog and bumping versions

* Docs: new post-processing for books so that assets stay relative

This commit has the same content as https://github.com/nymtech/nym/pull/3842

* Docs: add prod deploy settings

* fixed ChangeMixCostParams event deserialization (#3873)

* Merge pull request #3892 from nymtech/feature/operators/smoosh-faq

Create smoosh FAQ section & re-organize operators/faq accordingly

* corrected faq dir path

* added integrations-faq page

---------

Co-authored-by: mfahampshire <maxhampshire@pm.me>
Co-authored-by: Lorexia <alexia.lorenza.martinel@protonmail.com>
Co-authored-by: Tommy Verrall <tommy@nymtech.net>
Co-authored-by: Tommy Verrall <60836166+tommyv1987@users.noreply.github.com>
Co-authored-by: Mark Sinclair <14054343+mmsinclair@users.noreply.github.com>
Co-authored-by: Jędrzej Stuczyński <jedrzej.stuczynski@gmail.com>
Co-authored-by: serinko <97586125+serinko@users.noreply.github.com>
Co-authored-by: mx <33262279+mfahampshire@users.noreply.github.com>
Co-authored-by: Mark Sinclair <mmsinclair@users.noreply.github.com>
Co-authored-by: Tommy Verrall <tommyvez@protonmail.com>
2023-09-18 17:06:10 +02:00
benedettadavico 06956efa3f Deleting faq.md on develop 2023-09-18 17:04:58 +02:00
Jon Häggblad 604657c1dc Error instead of crash on UDP and BIND not supported 2023-09-18 15:41:56 +02:00
serinko f130ff73ad Merge pull request #3900 from nymtech/patch/dev-portal/integrations-faq-fix
integrations added to developers/faq section
2023-09-18 13:40:45 +00:00
serinko ddaabdc856 Merge pull request #3892 from nymtech/feature/operators/smoosh-faq
Create smoosh FAQ section & re-organize operators/faq accordingly
2023-09-18 13:38:54 +00:00
serinko 65de9d146d removed redundant .faq dir 2023-09-18 12:20:19 +02:00
serinko ec3aa7d8eb time frame in intro & ETA delete 2023-09-18 11:58:00 +02:00
serinko 805e1b8759 add NymAPI codebase link 2023-09-18 11:52:53 +02:00
serinko 53db649e84 steps timing explained & italic removed 2023-09-18 11:44:50 +02:00
serinko f76092e8e7 clarified new smooshed gateway 2023-09-18 11:40:58 +02:00
serinko c75fda0eb1 fix SUMMARY.md & links 2023-09-18 10:48:27 +02:00
serinko 9dfbc8c9c8 integrations added to developers/faq section 2023-09-18 10:20:48 +02:00
serinko 0171791188 syntax fix 2023-09-18 07:59:19 +00:00
serinko f6a9d0b843 formatting quotes 2023-09-18 07:45:14 +00:00
Jon Häggblad 9654cbf87e Remove ignored profile directives for contracts 2023-09-17 22:41:50 +02:00
Jon Häggblad fc8ac8956d Use resolver = 2 for contract workspace 2023-09-17 22:40:20 +02:00
Jon Häggblad 359a4e5bbd Remove default-features where they are ignored anyway 2023-09-17 22:38:58 +02:00
Jon Häggblad 42d2ecca3c Fix all the rust warnings about ignored profile directives
You can't specify profile in the manifest of a crate when it's part of a
workspace. Move the profile directives that cargo complains about to the
top-level workspace Cargo.toml
2023-09-17 22:29:08 +02:00
serinko 3c750f61e5 syntax fix 2023-09-15 19:14:31 +02:00
serinko a8e7c3ca49 syntax fix 2023-09-15 19:13:11 +02:00
serinko 4f39630861 spell check 2023-09-15 13:39:34 +02:00
serinko 63714092df gathered community questions & nym team answers 2023-09-15 13:33:26 +02:00
serinko cd89f4866a initialize faq/smoosh-faq.md page 2023-09-15 11:58:32 +02:00
serinko a94c4c0895 initialize FAQ section & move faq -> mixnodes-faq 2023-09-15 11:51:24 +02:00
fmtabbara 56ef23b7d1 fix linting 2023-09-14 17:23:56 +01:00
Jędrzej Stuczyński 63b0658c65 [feat] Socks5 and Native client: run with hardcoded topology (#3866)
* allow running clients using hardcoded topology

* fixed sdk/lib/socks5-listener build

* fixed nym-connect build

* allow for both snake_case and camelCase deserialization
2023-09-14 14:26:11 +02:00
Tommy Verrall 6b161700f6 Merge pull request #3882 from nymtech/remove_unecessary_workflows
Github actions: remove nightly builds workflows on latest releases
2023-09-14 13:52:59 +02:00
fmtabbara 339244a1fb update lock file 2023-09-14 11:30:22 +01:00
fmtabbara 6aa984621e add tooltips 2023-09-14 11:29:31 +01:00
fmtabbara ba0b5e2120 add total delegations to rewards summary 2023-09-14 11:29:06 +01:00
fmtabbara b48e2af2c4 rename redeem to claim 2023-09-14 11:28:19 +01:00
fmtabbara 03736cc209 fix background color on account modal 2023-09-14 11:27:30 +01:00
Tommy Verrall dcfe5f7c5b Merge pull request #3883 from nymtech/ci/fix-clippy-error
fix ci failing builds on clippy errors
2023-09-14 11:31:02 +02:00
Tommy Verrall cd89e26b74 fix ci failing builds on clippy errors 2023-09-14 10:13:32 +02:00
Jon Häggblad 4f9df2a8b1 Update Cargo.lock that was missed during release 2023-09-13 22:28:26 +02:00
Jędrzej Stuczyński f6a4fc3b6f updated mixnet contract schema files 2023-09-13 15:16:08 +01:00
Raphaël Walther 899db660ce Github actions: remove nightly builds workflows on latest releases 2023-09-13 10:22:41 +02:00
Jon Häggblad ec0ac56b8a Improve error handling in wireguard listener (#3881) 2023-09-13 08:19:52 +02:00
Jędrzej Stuczyński 8981ffdcf9 removed queued mixnet migration that was already run (#3872) 2023-09-12 14:10:44 +01:00
Tommy Verrall df25c01771 Merge pull request #3876 from nymtech/mixnet-version
updating mixnet contract version to 1.5.1
2023-09-12 15:08:52 +02:00
Tommy Verrall a11dead84a Merge pull request #3875 from nymtech/release/v1.1.31-kitkat
bump versions and update changelog
2023-09-12 15:08:29 +02:00
benedettadavico 5aa999643f updating mixnet contract version to 1.5.1 2023-09-12 15:06:32 +02:00
Jon Häggblad 96b54db060 Wireguard listener (#3868)
* wip

* wip

* Most channels are in place

* tidy

* Send data to tunnel

* wip: adding in boringtun

* Handle timers

* Add consume_wg

* Split into mod

* Reorder

* Comments

* Refine channel handling

* Sort out dependency conflict

* Move wireguard listener in gateway beind a feature flag
2023-09-12 14:14:46 +02:00
benedettadavico 5bd4295164 bump versions and update changelog 2023-09-12 10:20:34 +02:00
Jędrzej Stuczyński b07627d57e fixed ChangeMixCostParams event deserialization (#3871) 2023-09-11 23:13:18 +01:00
Tommy Verrall c4667a6792 Merge pull request #3846 from nymtech/jon/handle-unable-upgrade-config
clients: handle config upgrade failure
2023-09-08 11:11:43 +02:00
Tommy Verrall 2e2d258e53 Merge pull request #3860 from nymtech/feature/add-nc-wg-android
feat(nc-wireguard): bootstrap android client app
2023-09-08 10:05:00 +02:00
Tommy Verrall 843c74db63 Merge pull request #3865 from nymtech/fix_workflow_on_latest_release
Github actions: fix nightly build workflow
2023-09-08 10:01:41 +02:00
Tommy Verrall 142443b87e Merge pull request #3863 from nymtech/patch/documentation/minor-fix-serinko
DOCS: Fix broken links and syntax flaws
2023-09-08 10:01:20 +02:00
Raphaël Walther ec4765c9c6 Github actions: fix nightly build workflow 2023-09-08 08:47:56 +02:00
pierre 77a56600f0 fix build, add icon launcher 2023-09-07 16:34:37 +02:00
Mark Sinclair 90027dc525 Merge pull request #3864 from nymtech/bugfix/linting
Remove unused import
2023-09-07 15:02:37 +01:00
serinko 6a39e19f2e CLI upgrade link correction 2023-09-07 16:00:34 +02:00
serinko 48140647b7 wallet & port link correction 2023-09-07 15:58:53 +02:00
Mark Sinclair 7d1cb6ca19 Remove unused import 2023-09-07 14:51:55 +01:00
serinko d1f7066eb5 socks-proxy: link correction 2023-09-07 15:01:46 +02:00
serinko 2789951d9a integration-faq: link correction 2023-09-07 14:58:33 +02:00
serinko faab815c79 overview: link correction 2023-09-07 14:57:11 +02:00
serinko a205fecece mixnet-integration: link correction 2023-09-07 14:54:53 +02:00
serinko f3116993d8 note-types: link correction 2023-09-07 14:41:03 +02:00
serinko 4fae075dae wallet-bonding: url correction 2023-09-07 14:39:27 +02:00
serinko da46955817 glossary: links correction 2023-09-07 14:35:43 +02:00
serinko f2fc837811 nym-vs-others: link correction 2023-09-07 14:33:28 +02:00
Jędrzej Stuczyński e7929d6f6b Feature/wasm client nodejs (#3769)
* wip

* post-cherry pick fixes

* wip

* wip

* using sqlite-based indexeddb shim

* running nymClient in worker thread

* improved received handling

* building node mix-fetch

* fixed mix fetch request constructor if args[1] == undefined

* fixed build target

* nodejs origin bypass

* mix fetch in node

but I dont think anyone should use it over normal client...

* target locking

* fixed post-rebasing issues
2023-09-07 13:30:04 +01:00
serinko e8f99cfdbe websocket-client: link correction 2023-09-07 14:26:04 +02:00
serinko b4ccd16d8b ledger-live: link correction 2023-09-07 14:14:32 +02:00
serinko f7974c5db8 rpc-node: link correction 2023-09-07 14:13:46 +02:00
Mark Sinclair 90a925ee62 Add auto-generated contract client (#3861)
* Add auto-generated contract client

* Use HTTPS instead of websockets

---------

Co-authored-by: Mark Sinclair <mmsinclair@users.noreply.github.com>
2023-09-07 12:45:48 +01:00
Jędrzej Stuczyński 4890c528bc feat: mixFetch - the final countdown (#3737)
* mixFetch

* clippy

* removed redundant Arc over 'WasmStorage' in the 'ClientStorage'

---------

Co-authored-by: Fouad <fmtabbara@hotmail.co.uk>
2023-09-07 12:45:03 +01:00
serinko d96de448d0 operators/maintenance page: syntax corrections 2023-09-07 13:28:04 +02:00
serinko 74cd6f0198 docs: correcting links to operators pages 2023-09-07 13:27:47 +02:00
Tommy Verrall e71ae7198f Merge pull request #3843 from nymtech/fix/nc-selected-nr
fix(nc): refresh nr list on privacy switch
2023-09-07 12:58:59 +02:00
Tommy Verrall 273f612d46 Merge pull request #3844 from nymtech/feature/named-task-client
feat: add name to `TaskClient`
2023-09-07 12:58:16 +02:00
Mark Sinclair 2e8d318587 Merge pull request #3845 from nymtech/feature/fix_updater_url
Fix updater.json URL
2023-09-07 11:04:41 +01:00
Jędrzej Stuczyński 17bd44f840 added optional name to TaskManager 2023-09-07 10:22:14 +01:00
serinko c1076f81a6 Merge pull request #3857 from nymtech/feature/documentation/dev-portal/faq2
DOCS: dev-portal FAQ section
2023-09-07 09:06:27 +00:00
serinko 26507ee7d3 minor syntax correction 2023-09-07 10:58:38 +02:00
serinko 4677312cad fixed ls command for unknown/allowed.list 2023-09-07 10:42:23 +02:00
serinko 07eddc8187 added link to faq to all intros 2023-09-07 10:34:59 +02:00
pierre b9a9a407e9 init 2023-09-06 20:01:58 +02:00
Mark Sinclair 3c482eff6e Docs: add prod deploy settings 2023-09-06 18:08:56 +01:00
Mark Sinclair 2880049196 Revert "init"
This reverts commit 8d2e8b3d26.
2023-09-06 18:08:17 +01:00
pierre 8d2e8b3d26 init 2023-09-06 18:36:01 +02:00
serinko 33bf344d63 initialized faq section, moved existing faqs, started general faq page 2023-09-06 14:09:48 +02:00
Jędrzej Stuczyński 0efa78c4a8 adjusted logging on TaskClient Drop 2023-09-06 12:52:09 +01:00
Jędrzej Stuczyński 32ee16bf0b added task name to 'UnexpectedHalt' error 2023-09-06 12:52:08 +01:00
Jędrzej Stuczyński a8f70fe4a2 few named examples for mixnode 2023-09-06 12:52:08 +01:00
Jędrzej Stuczyński f6fe5d41ea introduced named TaskClient and including the name for logs 2023-09-06 12:52:08 +01:00
Jędrzej Stuczyński 2a87533b12 added 'open_proxy', 'enabled_statistics' and 'statistics_recipient' to NR config (#3839)
* added 'open_proxy', 'enabled_statistics' and 'statistics_recipient' to NR config

* Update template.rs

fixed missing quotation marks
2023-09-06 12:58:39 +02:00
Jon Häggblad 499fd8a91d Fix clippy unused import (#3848) 2023-09-06 11:24:17 +02:00
Jon Häggblad e336b9948e Collapse conditional 2023-09-06 10:44:04 +02:00
Jon Häggblad 1cf2b10e31 clients: handle config upgrade failure 2023-09-06 10:09:25 +02:00
Bogdan-Ștefan Neacșu b3cd42de58 Fix updater.json URL 2023-09-05 18:46:57 +03:00
pierre f16498915a fix types 2023-09-05 17:02:24 +02:00
pierre d364510400 typo 2023-09-05 16:23:26 +02:00
pierre 96f9e39e1d refresh nr list on privacy mode switch 2023-09-05 16:20:17 +02:00
Mark Sinclair e083bfcfe4 Docs: post process to adjust URLs in index.html files for hosting in subdirectories (#3842)
* Docs: post process output to fix paths so that many mdbooks can be served from sub-directories

* Prevent theme from being modified

* Upload docs to Vercel

* Post process docs

* Process local links

* Docs: only process `index.html` files from the root,

All other files have the correct relative paths to serve assets properly and link to files relatively.

---------

Co-authored-by: Mark Sinclair <mmsinclair@users.noreply.github.com>
2023-09-05 14:57:23 +01:00
Tommy Verrall 22c59be82c Release/v1.1.30 twix (#3836)
* changed last vers. checkout to master

* corrected path of config

* make binaries executable

* docs: typescript.md - changing variables

* docs: rust.md - changing variables

* docs: vesting-contract.md - changing variables

* docs: mixnet-contract.md - changing variables

* docs: all variables changed

* operators: all variables finished

* dev-portal: mixnet-integration.md - variable changed

* dev-portal: faq.md - variable changed

* dev-portal: moredo.md up to date w NC default

* dev-portal: telegram.md - added banner & minor fix

* dev-portal: matrix.md - added banner

* PR finished - ready for review and merge

* removed all instances of platform_release_version var

* removed all instances of platform_release_version var

* changed version bumper script: removed platform_release_version references

* changed comment

* updating changelog and bumping versions

---------

Co-authored-by: serinko <97586125+serinko@users.noreply.github.com>
Co-authored-by: mfahampshire <maxhampshire@pm.me>
Co-authored-by: mx <33262279+mfahampshire@users.noreply.github.com>
Co-authored-by: benedettadavico <benedetta.davico@gmail.com>
2023-09-05 11:58:21 +02:00
Tommy Verrall f17e7378f7 Merge pull request #3835 from nymtech/feature/vpn-dirs
feat: init vpn clients directories
2023-09-05 09:51:02 +02:00
pierre 1bb455675e init dirs 2023-09-05 09:24:24 +02:00
Mark Sinclair 73076a2b26 Merge branch 'feature/gh-actions-hash-release' into develop 2023-09-04 20:49:54 +01:00
Jon Häggblad 1e1bf25514 gateway: disconnect inactive duplicate clients (#3796)
* gateway: disconnect inactive duplicate clients

* wip: see if we can switch to single ping at a time

* Finish reworking ping pong request flow

* Use workspace version of tokio

* Bundle active client channels into struct

* Fix typo
2023-09-04 16:41:58 +02:00
977 changed files with 65434 additions and 15246 deletions
@@ -1,19 +0,0 @@
[
{
"os":"ubuntu-20.04",
"rust":"stable",
"runOnEvent":"always"
},
{
"os":"windows-latest",
"rust":"stable",
"runOnEvent":"pull_request"
},
{
"os":"macos-latest",
"rust":"stable",
"runOnEvent":"pull_request"
}
]
@@ -1,4 +1,4 @@
name: CI for ts-packages
name: ci-build-ts
on:
push:
@@ -1,4 +1,4 @@
name: Build and upload binaries to CI
name: ci-build-upload-binaries
on:
workflow_dispatch:
@@ -6,7 +6,6 @@ on:
paths:
- 'clients/**'
- 'common/**'
- 'contracts/**'
- 'explorer-api/**'
- 'gateway/**'
- 'integrations/**'
@@ -21,7 +20,6 @@ on:
paths:
- 'clients/**'
- 'common/**'
- 'contracts/**'
- 'explorer-api/**'
- 'gateway/**'
- 'integrations/**'
@@ -44,6 +42,8 @@ jobs:
platform: [ubuntu-20.04]
runs-on: ${{ matrix.platform }}
# a push event from the origin repo, or a PR from external repo
if: ${{ github.event_name == 'push' || github.event.pull_request.head.repo.full_name != 'nymtech/nym' }}
steps:
- uses: actions/checkout@v3
@@ -63,27 +63,13 @@ jobs:
- name: Install Rust stable
uses: actions-rs/toolchain@v1
with:
toolchain: 1.69.0
toolchain: stable
- name: Build all binaries
uses: actions-rs/cargo@v1
with:
command: build
args: --workspace --release --all
- name: Install Rust stable
uses: actions-rs/toolchain@v1
with:
toolchain: 1.69.0
target: wasm32-unknown-unknown
override: true
components: rustfmt, clippy
- name: Install wasm-opt
run: cargo install --version 0.112.0 wasm-opt
- name: Build release contracts
run: make wasm
args: --workspace --release
- name: Prepare build output
shell: bash
@@ -99,16 +85,6 @@ jobs:
cp target/release/nym-network-statistics $OUTPUT_DIR
cp target/release/nym-cli $OUTPUT_DIR
cp target/release/explorer-api $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
cp contracts/target/wasm32-unknown-unknown/release/nym_coconut_bandwidth.wasm $OUTPUT_DIR
cp contracts/target/wasm32-unknown-unknown/release/nym_coconut_dkg.wasm $OUTPUT_DIR
cp contracts/target/wasm32-unknown-unknown/release/cw3_flex_multisig.wasm $OUTPUT_DIR
cp contracts/target/wasm32-unknown-unknown/release/cw4_group.wasm $OUTPUT_DIR
cp contracts/target/wasm32-unknown-unknown/release/nym_service_provider_directory.wasm $OUTPUT_DIR
cp contracts/target/wasm32-unknown-unknown/release/nym_name_service.wasm $OUTPUT_DIR
cp contracts/target/wasm32-unknown-unknown/release/nym_ephemera.wasm $OUTPUT_DIR
- name: Deploy branch to CI www
continue-on-error: true
@@ -1,4 +1,4 @@
name: Continuous integration
name: ci-build
on:
push:
@@ -42,8 +42,8 @@ jobs:
build:
runs-on: [ self-hosted, custom-linux ]
# Enable sccache via environment variable
env:
RUSTC_WRAPPER: /home/ubuntu/.cargo/bin/sccache
# env:
# RUSTC_WRAPPER: /home/ubuntu/.cargo/bin/sccache
steps:
- name: Install Dependencies (Linux)
run: sudo apt-get update && sudo apt-get -y install libwebkit2gtk-4.0-dev build-essential curl wget libssl-dev libgtk-3-dev libudev-dev squashfs-tools protobuf-compiler
@@ -91,14 +91,14 @@ jobs:
command: test
args: --workspace -- --ignored
- uses: actions-rs/clippy-check@v1
name: Clippy checks
- name: Annotate with clippy checks
uses: actions-rs/clippy-check@v1
continue-on-error: true
with:
token: ${{ secrets.GITHUB_TOKEN }}
args: --workspace
- name: Run clippy
- name: Clippy
uses: actions-rs/cargo@v1
with:
command: clippy
@@ -6,9 +6,5 @@
{
"rust":"beta",
"runOnEvent":"pull_request"
},
{
"rust":"nightly",
"runOnEvent":"pull_request"
}
]
]
@@ -1,6 +1,7 @@
name: Check Contract Schema
name: ci-contracts-schema
on:
workflow_dispatch:
push:
paths:
- 'contracts/**'
@@ -0,0 +1,79 @@
name: ci-contracts-upload-binaries
on:
workflow_dispatch:
push:
paths:
- 'common/**'
- 'contracts/**'
pull_request:
paths:
- 'common/**'
- 'contracts/**'
env:
NETWORK: mainnet
jobs:
publish-nym-contracts:
strategy:
fail-fast: false
matrix:
platform: [ubuntu-20.04]
runs-on: ${{ matrix.platform }}
steps:
- uses: actions/checkout@v3
- name: Prepare build output directory
shell: bash
env:
OUTPUT_DIR: ci-contract-builds/${{ github.ref_name }}
run: |
rm -rf ci-contract-builds || true
mkdir -p $OUTPUT_DIR
echo $OUTPUT_DIR
- name: Install Dependencies (Linux)
run: sudo apt-get update && sudo apt-get -y install libwebkit2gtk-4.0-dev build-essential curl wget libssl-dev libgtk-3-dev libudev-dev squashfs-tools protobuf-compiler
continue-on-error: true
- name: Install Rust stable
uses: actions-rs/toolchain@v1
with:
toolchain: 1.69.0
target: wasm32-unknown-unknown
override: true
- name: Install wasm-opt
run: cargo install --version 0.112.0 wasm-opt
- name: Build release contracts
run: make contracts
- name: Prepare build output
shell: bash
env:
OUTPUT_DIR: ci-contract-builds/${{ github.ref_name }}
run: |
cp contracts/target/wasm32-unknown-unknown/release/mixnet_contract.wasm $OUTPUT_DIR
cp contracts/target/wasm32-unknown-unknown/release/vesting_contract.wasm $OUTPUT_DIR
cp contracts/target/wasm32-unknown-unknown/release/nym_coconut_bandwidth.wasm $OUTPUT_DIR
cp contracts/target/wasm32-unknown-unknown/release/nym_coconut_dkg.wasm $OUTPUT_DIR
cp contracts/target/wasm32-unknown-unknown/release/cw3_flex_multisig.wasm $OUTPUT_DIR
cp contracts/target/wasm32-unknown-unknown/release/cw4_group.wasm $OUTPUT_DIR
cp contracts/target/wasm32-unknown-unknown/release/nym_service_provider_directory.wasm $OUTPUT_DIR
cp contracts/target/wasm32-unknown-unknown/release/nym_name_service.wasm $OUTPUT_DIR
cp contracts/target/wasm32-unknown-unknown/release/nym_ephemera.wasm $OUTPUT_DIR
- 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: "-avzr"
SOURCE: "ci-contract-builds/"
REMOTE_HOST: ${{ secrets.CI_WWW_REMOTE_HOST }}
REMOTE_USER: ${{ secrets.CI_WWW_REMOTE_USER }}
TARGET: ${{ secrets.CI_WWW_REMOTE_TARGET }}/builds/
EXCLUDE: "/dist/, /node_modules/"
@@ -1,4 +1,4 @@
name: Contracts
name: ci-contracts
on:
push:
@@ -6,7 +6,7 @@ on:
- 'contracts/**'
- 'common/**'
pull_request:
paths-ignore:
paths:
- 'contracts/**'
- 'common/**'
@@ -16,18 +16,17 @@ jobs:
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
steps:
# creates the matrix strategy from build_matrix_includes.json
# creates the matrix strategy from ci-contracts-matrix-includes.json
- uses: actions/checkout@v2
- id: set-matrix
uses: JoshuaTheMiller/conditional-build-matrix@main
with:
inputFile: '.github/workflows/contract_matrix_includes.json'
inputFile: '.github/workflows/ci-contracts-matrix-includes.json'
filter: '[?runOnEvent==`${{ github.event_name }}` || runOnEvent==`always`]'
contracts:
build:
# since it's going to be compiled into wasm, there's absolutely
# no point in running CI on different OS-es
runs-on: ubuntu-20.04
continue-on-error: ${{ matrix.rust == 'nightly' }}
needs: matrix_prep
strategy:
fail-fast: false
@@ -35,7 +34,8 @@ jobs:
steps:
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
- name: Setup rust
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: ${{ matrix.rust }}
@@ -43,25 +43,28 @@ jobs:
override: true
components: rustfmt, clippy
- uses: actions-rs/cargo@v1
- name: Build contracts
uses: actions-rs/cargo@v1
env:
RUSTFLAGS: '-C link-arg=-s'
with:
command: build
args: --manifest-path contracts/Cargo.toml --workspace --lib --target wasm32-unknown-unknown
- uses: actions-rs/cargo@v1
- name: Run unit tests
uses: actions-rs/cargo@v1
with:
command: test
args: --lib --manifest-path contracts/Cargo.toml
- uses: actions-rs/cargo@v1
- name: Check formatting
uses: actions-rs/cargo@v1
with:
command: fmt
args: --manifest-path contracts/Cargo.toml --all -- --check
- uses: actions-rs/cargo@v1
if: ${{ matrix.rust != 'nightly' }}
- name: Run clippy
uses: actions-rs/cargo@v1
with:
command: clippy
args: --lib --manifest-path contracts/Cargo.toml --workspace --all-targets -- -D warnings
+1 -1
View File
@@ -1,4 +1,4 @@
name: CI docs
name: ci-docs
on:
workflow_dispatch:
@@ -1,4 +1,4 @@
name: CI for linting Typescript
name: ci-lint-typescript
on:
push:
@@ -25,27 +25,37 @@ jobs:
runs-on: custom-runner-linux
steps:
- uses: actions/checkout@v2
- name: Install rsync
run: sudo apt-get install rsync
continue-on-error: true
- uses: rlespinasse/github-slug-action@v3.x
- uses: actions/setup-node@v3
with:
node-version: 18
- name: Setup yarn
run: npm install -g yarn
- name: Install Rust stable
uses: actions-rs/toolchain@v1
with:
toolchain: stable
- name: Install wasm-pack
run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
- name: Setup yarn
run: npm install -g yarn
- name: Set up Go
uses: actions/setup-go@v4
with:
go-version: '1.20'
- name: Install
run: yarn
- name: Build packages
run: yarn build
run: yarn build:ci:sdk
- name: Lint
run: yarn lint && yarn tsc
run: yarn lint
- name: Typecheck with tsc
run: yarn tsc
- name: Matrix - Node Install
run: npm install
working-directory: .github/workflows/support-files
@@ -1,4 +1,4 @@
name: Nym Connect - desktop (Rust)
name: ci-nym-connect-desktop-rust
on:
push:
@@ -25,8 +25,8 @@ on:
jobs:
build:
runs-on: [self-hosted, custom-linux]
env:
RUSTC_WRAPPER: /home/ubuntu/.cargo/bin/sccache
# env:
# RUSTC_WRAPPER: /home/ubuntu/.cargo/bin/sccache
steps:
- name: Install Dependencies (Linux)
run: sudo apt-get update && sudo apt-get -y install libwebkit2gtk-4.0-dev build-essential curl wget libssl-dev libgtk-3-dev squashfs-tools libayatana-appindicator3-dev
@@ -1,4 +1,4 @@
name: CI for nym-connect - Desktop
name: ci-nym-connect-desktop
on:
push:
@@ -1,4 +1,4 @@
name: CI for Network Explorer
name: ci-nym-network-explorer
on:
workflow_dispatch:
@@ -1,4 +1,4 @@
name: Nym Wallet (rust)
name: ci-nym-wallet-rust
on:
push:
@@ -17,8 +17,8 @@ on:
jobs:
build:
runs-on: [ self-hosted, custom-linux ]
env:
RUSTC_WRAPPER: /home/ubuntu/.cargo/bin/sccache
# env:
# RUSTC_WRAPPER: /home/ubuntu/.cargo/bin/sccache
steps:
- name: Install Dependencies (Linux)
run: sudo apt-get update && sudo apt-get -y install libwebkit2gtk-4.0-dev build-essential curl wget libssl-dev libgtk-3-dev squashfs-tools
@@ -1,12 +1,14 @@
name: Typescript SDK docs
name: ci-sdk-docs-typescript
on:
push:
paths:
- "sdk/typescript/**"
- "wasm/**"
pull_request:
paths:
- "sdk/typescript/**"
- "wasm/**"
jobs:
build:
@@ -26,17 +28,39 @@ jobs:
toolchain: stable
- name: Setup yarn
run: npm install -g yarn
- name: Set up Go
uses: actions/setup-go@v4
with:
go-version: '1.20'
- name: Build branch WASM packages
run: make sdk-wasm-build
- name: Install
run: yarn
- name: Build
run: yarn docs:prod:build
- name: Deploy branch to CI www (docs)
continue-on-error: true
uses: easingthemes/ssh-deploy@main
env:
SSH_PRIVATE_KEY: ${{ secrets.CI_WWW_SSH_PRIVATE_KEY }}
ARGS: "-rltgoDzvO --delete"
SOURCE: "dist/ts/"
REMOTE_HOST: ${{ secrets.CI_WWW_REMOTE_HOST }}
REMOTE_USER: ${{ secrets.CI_WWW_REMOTE_USER }}
TARGET: ${{ secrets.CI_WWW_REMOTE_TARGET }}/sdk-ts-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: ts-packages
NYM_PROJECT_NAME: "ts-packages"
NYM_CI_WWW_BASE: "${{ secrets.NYM_CI_WWW_BASE }}"
NYM_CI_WWW_LOCATION: "ts-${{ env.GITHUB_REF_SLUG }}"
NYM_PROJECT_NAME: "sdk-ts-docs"
NYM_CI_WWW_BASE: "${{ secrets.NYM_CI_WWW_BASE }}/docs/sdk/typescript"
NYM_CI_WWW_LOCATION: "sdk-ts-docs-${{ env.GITHUB_REF_SLUG }}"
GIT_COMMIT_MESSAGE: "${{ github.event.head_commit.message }}"
GIT_BRANCH: "${GITHUB_REF##*/}"
IS_SUCCESS: "${{ job.status == 'success' }}"
+50
View File
@@ -0,0 +1,50 @@
name: ci-sdk-wasm
on:
pull_request:
paths:
- 'wasm/**'
- 'clients/client-core/**'
- 'common/**'
jobs:
wasm:
runs-on: [custom-runner-linux]
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v3
with:
node-version: 18
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
target: wasm32-unknown-unknown
override: true
components: rustfmt, clippy
- name: Set up Go
uses: actions/setup-go@v4
with:
go-version: '1.20'
- name: Install wasm-pack
run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
- name: Install wasm-opt
run: cargo install wasm-opt
- name: Install wasm-bindgen-cli
run: cargo install wasm-bindgen-cli
- name: "Build"
run: make sdk-wasm-build
- name: "Test"
run: make sdk-wasm-test
- name: "Lint"
run: make sdk-wasm-lint
+102
View File
@@ -0,0 +1,102 @@
name: nightly-build
on:
workflow_dispatch:
schedule:
- cron: '14 1 * * *'
jobs:
build:
strategy:
fail-fast: false
matrix:
rust: [stable, beta]
os: [custom-linux, windows10, custom-runner-mac-m1]
runs-on: ${{ matrix.os }}
continue-on-error: true
steps:
- name: Install Dependencies (Linux)
run: sudo apt-get update && sudo apt-get install -y build-essential curl wget libssl-dev libudev-dev squashfs-tools protobuf-compiler
continue-on-error: true
if: matrix.os == 'custom-linux'
- name: Check out repository code
uses: actions/checkout@v3
- name: Install Rust toolchain
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: ${{ matrix.rust }}
override: true
components: rustfmt, clippy
- name: Check formatting
uses: actions-rs/cargo@v1
with:
command: fmt
args: --all -- --check
- name: Build binaries
uses: actions-rs/cargo@v1
with:
command: build
args: --workspace
- name: Build examples
uses: actions-rs/cargo@v1
with:
command: build
args: --workspace --examples
- name: Run unit tests
uses: actions-rs/cargo@v1
with:
command: test
args: --workspace
- name: Run slow unit tests
uses: actions-rs/cargo@v1
with:
command: test
args: --workspace -- --ignored
- name: Clippy
uses: actions-rs/cargo@v1
with:
command: clippy
args: --workspace --all-targets -- -D warnings
notification:
needs: build
runs-on: custom-runner-linux
steps:
- name: Collect jobs status
uses: technote-space/workflow-conclusion-action@v2
- name: Check out repository code
uses: actions/checkout@v3
- name: install npm
uses: actions/setup-node@v3
if: env.WORKFLOW_CONCLUSION == 'failure'
with:
node-version: 18
- name: Matrix - Node Install
if: env.WORKFLOW_CONCLUSION == 'failure'
run: npm install
working-directory: .github/workflows/support-files
- name: Matrix - Send Notification
if: env.WORKFLOW_CONCLUSION == 'failure'
env:
NYM_NOTIFICATION_KIND: nightly
NYM_PROJECT_NAME: "Nym nightly build"
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
GIT_COMMIT_MESSAGE: "${{ github.event.head_commit.message }}"
GIT_BRANCH: "${GITHUB_REF##*/}"
IS_SUCCESS: "${{ env.WORKFLOW_CONCLUSION == 'success' }}"
MATRIX_SERVER: "${{ secrets.MATRIX_SERVER }}"
MATRIX_ROOM: "${{ secrets.MATRIX_ROOM_NIGHTLY }}"
MATRIX_USER_ID: "${{ secrets.MATRIX_USER_ID }}"
MATRIX_TOKEN: "${{ secrets.MATRIX_TOKEN }}"
MATRIX_DEVICE_ID: "${{ secrets.MATRIX_DEVICE_ID }}"
uses: docker://keybaseio/client:stable-node
with:
args: .github/workflows/support-files/notifications/entry_point.sh
@@ -1,4 +1,4 @@
name: check-merge-conflicts
name: nightly-check-merge-conflicts
# Check that the latest release branch merges into master and develop without
# any conflicts that git is not able to resolve
@@ -0,0 +1,101 @@
name: nightly-nym-wallet-build
on:
workflow_dispatch:
schedule:
- cron: '14 1 * * *'
defaults:
run:
working-directory: nym-wallet
jobs:
build:
strategy:
fail-fast: false
matrix:
os: [custom-linux, macos-latest, windows10]
runs-on: ${{ matrix.os }}
continue-on-error: true
steps:
- name: Check out repository code
uses: actions/checkout@v3
- name: Install Dependencies (Linux)
run: sudo apt-get update && sudo apt-get install -y libwebkit2gtk-4.0-dev build-essential curl wget libssl-dev libgtk-3-dev libudev-dev squashfs-tools protobuf-compiler
if: matrix.os == 'custom-linux'
- name: Install rust toolchain
uses: actions-rs/toolchain@v1
with:
profile: minimal
# There is an issue with 1.72.0 where clippy crashes on nym-wallet-types. Pin to 1.71.0 for now
toolchain: 1.71.0
override: true
components: rustfmt, clippy
- name: Check formatting
uses: actions-rs/cargo@v1
with:
command: fmt
args: --all -- --check
- name: Build
uses: actions-rs/cargo@v1
with:
command: build
args: --workspace
- name: Unit tests
uses: actions-rs/cargo@v1
with:
command: test
args: --workspace
- name: Annotate with clippy warnings
uses: actions-rs/clippy-check@v1
continue-on-error: true
with:
token: ${{ secrets.GITHUB_TOKEN }}
args: --workspace
- name: Clippy
uses: actions-rs/cargo@v1
with:
command: clippy
args: --workspace --all-targets -- -D warnings
notification:
needs: build
runs-on: custom-runner-linux
steps:
- name: Collect jobs status
uses: technote-space/workflow-conclusion-action@v2
- name: Check out repository code
uses: actions/checkout@v3
- name: install npm
uses: actions/setup-node@v3
if: env.WORKFLOW_CONCLUSION == 'failure'
with:
node-version: 18
- name: Matrix - Node Install
if: env.WORKFLOW_CONCLUSION == 'failure'
run: npm install
working-directory: .github/workflows/support-files
- name: Matrix - Send Notification
if: env.WORKFLOW_CONCLUSION == 'failure'
env:
NYM_NOTIFICATION_KIND: nightly
NYM_PROJECT_NAME: "nym-wallet-nightly-build"
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
GIT_COMMIT_MESSAGE: "${{ github.event.head_commit.message }}"
GIT_BRANCH: "${GITHUB_REF##*/}"
IS_SUCCESS: "${{ env.WORKFLOW_CONCLUSION == 'success' }}"
MATRIX_SERVER: "${{ secrets.MATRIX_SERVER }}"
MATRIX_ROOM: "${{ secrets.MATRIX_ROOM_NIGHTLY }}"
MATRIX_USER_ID: "${{ secrets.MATRIX_USER_ID }}"
MATRIX_TOKEN: "${{ secrets.MATRIX_TOKEN }}"
MATRIX_DEVICE_ID: "${{ secrets.MATRIX_DEVICE_ID }}"
uses: docker://keybaseio/client:stable-node
with:
args: .github/workflows/support-files/notifications/entry_point.sh
-176
View File
@@ -1,176 +0,0 @@
name: Nightly builds
on:
schedule:
- cron: '14 1 * * *'
jobs:
matrix_prep:
runs-on: ubuntu-20.04
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
steps:
# creates the matrix strategy from nightly_build_matrix_includes.json
- uses: actions/checkout@v3
- id: set-matrix
uses: JoshuaTheMiller/conditional-build-matrix@main
with:
inputFile: '.github/workflows/nightly_build_matrix_includes.json'
filter: '[?runOnEvent==`${{ github.event_name }}` || runOnEvent==`always`]'
build:
needs: matrix_prep
strategy:
matrix: ${{fromJson(needs.matrix_prep.outputs.matrix)}}
runs-on: ${{ matrix.os }}
continue-on-error: ${{ matrix.rust == 'nightly' || matrix.rust == 'beta' || matrix.rust == 'stable' }}
steps:
- name: Install Dependencies (Linux)
run: sudo apt-get update && sudo apt-get install libwebkit2gtk-4.0-dev build-essential curl wget libssl-dev libgtk-3-dev libudev-dev squashfs-tools protobuf-compiler
continue-on-error: true
if: matrix.os == 'ubuntu-20.04'
- name: Check out repository code
uses: actions/checkout@v3
- name: Install rust toolchain
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: ${{ matrix.rust }}
override: true
components: rustfmt, clippy
- name: Check formatting
uses: actions-rs/cargo@v1
with:
command: fmt
args: --all -- --check
- name: Build all binaries
uses: actions-rs/cargo@v1
with:
command: build
args: --workspace
- name: Reclaim some disk space
uses: actions-rs/cargo@v1
if: ${{ matrix.os == 'windows-latest' || matrix.os == 'ubuntu-20.04' }}
with:
command: clean
- name: Build all examples
uses: actions-rs/cargo@v1
with:
command: build
args: --workspace --examples
- name: Reclaim some disk space
uses: actions-rs/cargo@v1
if: ${{ matrix.os == 'windows-latest' || matrix.os == 'ubuntu-20.04' }}
with:
command: clean
- name: Run all tests
uses: actions-rs/cargo@v1
with:
command: test
args: --workspace
- name: Reclaim some disk space
uses: actions-rs/cargo@v1
if: ${{ matrix.os == 'windows-latest' || matrix.os == 'ubuntu-20.04' }}
with:
command: clean
- name: Run expensive tests
if: github.ref == 'refs/heads/develop' || github.event.pull_request.base.ref == 'develop' || github.event.pull_request.base.ref == 'master'
uses: actions-rs/cargo@v1
with:
command: test
args: --workspace -- --ignored
- name: Reclaim some disk space
uses: actions-rs/cargo@v1
if: ${{ matrix.os == 'windows-latest' || matrix.os == 'ubuntu-20.04' }}
with:
command: clean
- uses: actions-rs/clippy-check@v1
name: Clippy checks
continue-on-error: true
with:
token: ${{ secrets.GITHUB_TOKEN }}
args: --workspace
- name: Run clippy
uses: actions-rs/cargo@v1
if: ${{ matrix.rust != 'nightly' }}
with:
command: clippy
args: --workspace --all-targets -- -D warnings
- name: Reclaim some disk space
uses: actions-rs/cargo@v1
if: ${{ matrix.os == 'windows-latest' || matrix.os == 'ubuntu-20.04' }}
with:
command: clean
# nym-wallet (the rust part)
- name: Build nym-wallet rust code
uses: actions-rs/cargo@v1
with:
command: build
args: --manifest-path nym-wallet/Cargo.toml --workspace
- name: Run nym-wallet tests
uses: actions-rs/cargo@v1
with:
command: test
args: --manifest-path nym-wallet/Cargo.toml --workspace
- name: Check nym-wallet formatting
uses: actions-rs/cargo@v1
with:
command: fmt
args: --manifest-path nym-wallet/Cargo.toml --all -- --check
- name: Run clippy for nym-wallet
uses: actions-rs/cargo@v1
if: ${{ matrix.rust != 'nightly' }}
with:
command: clippy
args: --manifest-path nym-wallet/Cargo.toml --workspace --all-targets -- -D warnings
notification:
needs: build
runs-on: custom-runner-linux
steps:
- name: Collect jobs status
uses: technote-space/workflow-conclusion-action@v2
- name: Check out repository code
uses: actions/checkout@v3
- name: install npm
uses: actions/setup-node@v3
if: env.WORKFLOW_CONCLUSION == 'failure'
with:
node-version: 18
- name: Matrix - Node Install
if: env.WORKFLOW_CONCLUSION == 'failure'
run: npm install
working-directory: .github/workflows/support-files
- name: Matrix - Send Notification
if: env.WORKFLOW_CONCLUSION == 'failure'
env:
NYM_NOTIFICATION_KIND: nightly
NYM_PROJECT_NAME: "Nym nightly build"
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
GIT_COMMIT_MESSAGE: "${{ github.event.head_commit.message }}"
GIT_BRANCH: "${GITHUB_REF##*/}"
IS_SUCCESS: "${{ env.WORKFLOW_CONCLUSION == 'success' }}"
MATRIX_SERVER: "${{ secrets.MATRIX_SERVER }}"
MATRIX_ROOM: "${{ secrets.MATRIX_ROOM_NIGHTLY }}"
MATRIX_USER_ID: "${{ secrets.MATRIX_USER_ID }}"
MATRIX_TOKEN: "${{ secrets.MATRIX_TOKEN }}"
MATRIX_DEVICE_ID: "${{ secrets.MATRIX_DEVICE_ID }}"
uses: docker://keybaseio/client:stable-node
with:
args: .github/workflows/support-files/notifications/entry_point.sh
@@ -1,50 +0,0 @@
[
{
"os":"ubuntu-20.04",
"rust":"stable",
"runOnEvent":"schedule"
},
{
"os":"windows10",
"rust":"stable",
"runOnEvent":"schedule"
},
{
"os":"macos-latest",
"rust":"stable",
"runOnEvent":"schedule"
},
{
"os":"ubuntu-20.04",
"rust":"beta",
"runOnEvent":"schedule"
},
{
"os":"windows10",
"rust":"beta",
"runOnEvent":"schedule"
},
{
"os":"macos-latest",
"rust":"beta",
"runOnEvent":"schedule"
},
{
"os":"ubuntu-20.04",
"rust":"nightly",
"runOnEvent":"schedule"
},
{
"os":"windows10",
"rust":"nightly",
"runOnEvent":"schedule"
},
{
"os":"macos-latest",
"rust":"nightly",
"runOnEvent":"schedule"
}
]
-191
View File
@@ -1,191 +0,0 @@
name: Nightly builds on latest release
on:
schedule:
- cron: '14 2 * * *'
jobs:
matrix_prep:
runs-on: ubuntu-20.04
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
steps:
# creates the matrix strategy from nightly_build_matrix_includes.json
- uses: actions/checkout@v3
- id: set-matrix
uses: JoshuaTheMiller/conditional-build-matrix@main
with:
inputFile: '.github/workflows/nightly_build_matrix_includes.json'
filter: '[?runOnEvent==`${{ github.event_name }}` || runOnEvent==`always`]'
get_release:
runs-on: ubuntu-20.04
needs: matrix_prep
outputs:
output1: ${{ steps.step2.outputs.latest_release }}
steps:
- name: Check out repository code
uses: actions/checkout@v3
- name: Fetch all branches
run: git fetch --all
- name: Set output variable to latest release branch
id: step2
run: echo "latest_release=$(git branch -r | grep -E 'release/v[0-9]+\.[0-9]+\.[0-9]+$' | sort -V | tail -n 1 | sed 's/ origin\///')" >> $GITHUB_OUTPUT
build:
needs: [get_release,matrix_prep]
strategy:
matrix: ${{fromJson(needs.matrix_prep.outputs.matrix)}}
runs-on: ${{ matrix.os }}
continue-on-error: ${{ matrix.rust == 'nightly' || matrix.rust == 'beta' || matrix.rust == 'stable' }}
steps:
- name: Install Dependencies (Linux)
run: sudo apt-get update && sudo apt-get install libwebkit2gtk-4.0-dev build-essential curl wget libssl-dev libgtk-3-dev libudev-dev squashfs-tools protobuf-compiler
continue-on-error: true
if: matrix.os == 'ubuntu-20.04'
- name: Check out latest release branch
uses: actions/checkout@v3
with:
ref: ${{needs.get_release.outputs.output1}}
- name: Install rust toolchain
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: ${{ matrix.rust }}
override: true
components: rustfmt, clippy
- name: Check formatting
uses: actions-rs/cargo@v1
with:
command: fmt
args: --all -- --check
- name: Build all binaries
uses: actions-rs/cargo@v1
with:
command: build
args: --workspace
- name: Reclaim some disk space
uses: actions-rs/cargo@v1
if: ${{ matrix.os == 'windows-latest' || matrix.os == 'ubuntu-20.04' }}
with:
command: clean
- name: Build all examples
uses: actions-rs/cargo@v1
with:
command: build
args: --workspace --examples
- name: Reclaim some disk space
uses: actions-rs/cargo@v1
if: ${{ matrix.os == 'windows-latest' || matrix.os == 'ubuntu-20.04' }}
with:
command: clean
- name: Run all tests
uses: actions-rs/cargo@v1
with:
command: test
args: --workspace
- name: Reclaim some disk space
uses: actions-rs/cargo@v1
if: ${{ matrix.os == 'windows-latest' || matrix.os == 'ubuntu-20.04' }}
with:
command: clean
- name: Run expensive tests
if: github.ref == 'refs/heads/develop' || github.event.pull_request.base.ref == 'develop' || github.event.pull_request.base.ref == 'master'
uses: actions-rs/cargo@v1
with:
command: test
args: --workspace -- --ignored
- name: Reclaim some disk space
uses: actions-rs/cargo@v1
if: ${{ matrix.os == 'windows-latest' || matrix.os == 'ubuntu-20.04' }}
with:
command: clean
- uses: actions-rs/clippy-check@v1
name: Clippy checks
continue-on-error: true
with:
token: ${{ secrets.GITHUB_TOKEN }}
args: --workspace
- name: Run clippy
uses: actions-rs/cargo@v1
if: ${{ matrix.rust != 'nightly' }}
with:
command: clippy
args: --workspace --all-targets -- -D warnings
- name: Reclaim some disk space
uses: actions-rs/cargo@v1
if: ${{ matrix.os == 'windows-latest' || matrix.os == 'ubuntu-20.04' }}
with:
command: clean
# nym-wallet (the rust part)
- name: Build nym-wallet rust code
uses: actions-rs/cargo@v1
with:
command: build
args: --manifest-path nym-wallet/Cargo.toml --workspace
- name: Run nym-wallet tests
uses: actions-rs/cargo@v1
with:
command: test
args: --manifest-path nym-wallet/Cargo.toml --workspace
- name: Check nym-wallet formatting
uses: actions-rs/cargo@v1
with:
command: fmt
args: --manifest-path nym-wallet/Cargo.toml --all -- --check
- name: Run clippy for nym-wallet
uses: actions-rs/cargo@v1
if: ${{ matrix.rust != 'nightly' }}
with:
command: clippy
args: --manifest-path nym-wallet/Cargo.toml --workspace --all-targets -- -D warnings
notification:
needs: [build,get_release]
runs-on: custom-runner-linux
steps:
- name: Collect jobs status
uses: technote-space/workflow-conclusion-action@v2
- name: Check out repository code
uses: actions/checkout@v3
- name: install npm
uses: actions/setup-node@v3
if: env.WORKFLOW_CONCLUSION == 'failure'
with:
node-version: 18
- name: Matrix - Node Install
if: env.WORKFLOW_CONCLUSION == 'failure'
run: npm install
working-directory: .github/workflows/support-files
- name: Matrix - Send Notification
if: env.WORKFLOW_CONCLUSION == 'failure'
env:
NYM_NOTIFICATION_KIND: nightly
NYM_PROJECT_NAME: "Nym nightly build on latest release"
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
GIT_COMMIT_MESSAGE: "${{ github.event.head_commit.message }}"
GIT_BRANCH_NAME: "${{needs.get_release.outputs.output1}}"
IS_SUCCESS: "${{ env.WORKFLOW_CONCLUSION == 'success' }}"
MATRIX_SERVER: "${{ secrets.MATRIX_SERVER }}"
MATRIX_ROOM: "${{ secrets.MATRIX_ROOM_NIGHTLY }}"
MATRIX_USER_ID: "${{ secrets.MATRIX_USER_ID }}"
MATRIX_TOKEN: "${{ secrets.MATRIX_TOKEN }}"
MATRIX_DEVICE_ID: "${{ secrets.MATRIX_DEVICE_ID }}"
uses: docker://keybaseio/client:stable-node
with:
args: .github/workflows/support-files/notifications/entry_point.sh
@@ -1,191 +0,0 @@
name: Nightly builds on second latest release
on:
schedule:
- cron: '24 2 * * *'
jobs:
matrix_prep:
runs-on: ubuntu-20.04
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
steps:
# creates the matrix strategy from nightly_build_matrix_includes.json
- uses: actions/checkout@v3
- id: set-matrix
uses: JoshuaTheMiller/conditional-build-matrix@main
with:
inputFile: '.github/workflows/nightly_build_matrix_includes.json'
filter: '[?runOnEvent==`${{ github.event_name }}` || runOnEvent==`always`]'
get_release:
runs-on: ubuntu-20.04
needs: matrix_prep
outputs:
output1: ${{ steps.step2.outputs.latest_release }}
steps:
- name: Check out repository code
uses: actions/checkout@v3
- name: Fetch all branches
run: git fetch --all
- name: Set output variable to latest release branch
id: step2
run: echo "latest_release=$(git branch -r | grep -E 'release/v[0-9]+\.[0-9]+\.[0-9]+$' | sort -V | tail -n 2 | head -n 1 | sed 's/ origin\///')" >> $GITHUB_OUTPUT
build:
needs: [get_release,matrix_prep]
strategy:
matrix: ${{fromJson(needs.matrix_prep.outputs.matrix)}}
runs-on: ${{ matrix.os }}
continue-on-error: ${{ matrix.rust == 'nightly' || matrix.rust == 'beta' || matrix.rust == 'stable' }}
steps:
- name: Install Dependencies (Linux)
run: sudo apt-get update && sudo apt-get install libwebkit2gtk-4.0-dev build-essential curl wget libssl-dev libgtk-3-dev libudev-dev squashfs-tools
continue-on-error: true
if: matrix.os == 'ubuntu-20.04'
- name: Check out latest release branch
uses: actions/checkout@v3
with:
ref: ${{needs.get_release.outputs.output1}}
- name: Install rust toolchain
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: ${{ matrix.rust }}
override: true
components: rustfmt, clippy
- name: Check formatting
uses: actions-rs/cargo@v1
with:
command: fmt
args: --all -- --check
- name: Build all binaries
uses: actions-rs/cargo@v1
with:
command: build
args: --workspace
- name: Reclaim some disk space (because Windows is being annoying)
uses: actions-rs/cargo@v1
if: ${{ matrix.os == 'windows-latest' }}
with:
command: clean
- name: Build all examples
uses: actions-rs/cargo@v1
with:
command: build
args: --workspace --examples
- name: Reclaim some disk space (because Windows is being annoying)
uses: actions-rs/cargo@v1
if: ${{ matrix.os == 'windows-latest' }}
with:
command: clean
- name: Run all tests
uses: actions-rs/cargo@v1
with:
command: test
args: --workspace
- name: Reclaim some disk space (because Windows is being annoying)
uses: actions-rs/cargo@v1
if: ${{ matrix.os == 'windows-latest' || matrix.os == 'ubuntu-20.04' }}
with:
command: clean
- name: Run expensive tests
if: github.ref == 'refs/heads/develop' || github.event.pull_request.base.ref == 'develop' || github.event.pull_request.base.ref == 'master'
uses: actions-rs/cargo@v1
with:
command: test
args: --workspace -- --ignored
- name: Reclaim some disk space (because Windows is being annoying)
uses: actions-rs/cargo@v1
if: ${{ matrix.os == 'windows-latest' }}
with:
command: clean
- uses: actions-rs/clippy-check@v1
name: Clippy checks
continue-on-error: true
with:
token: ${{ secrets.GITHUB_TOKEN }}
args: --workspace
- name: Run clippy
uses: actions-rs/cargo@v1
if: ${{ matrix.rust != 'nightly' }}
with:
command: clippy
args: --workspace --all-targets -- -D warnings
- name: Reclaim some disk space
uses: actions-rs/cargo@v1
if: ${{ matrix.os == 'windows-latest' || matrix.os == 'ubuntu-20.04' }}
with:
command: clean
# nym-wallet (the rust part)
- name: Build nym-wallet rust code
uses: actions-rs/cargo@v1
with:
command: build
args: --manifest-path nym-wallet/Cargo.toml --workspace
- name: Run nym-wallet tests
uses: actions-rs/cargo@v1
with:
command: test
args: --manifest-path nym-wallet/Cargo.toml --workspace
- name: Check nym-wallet formatting
uses: actions-rs/cargo@v1
with:
command: fmt
args: --manifest-path nym-wallet/Cargo.toml --all -- --check
- name: Run clippy for nym-wallet
uses: actions-rs/cargo@v1
if: ${{ matrix.rust != 'nightly' }}
with:
command: clippy
args: --manifest-path nym-wallet/Cargo.toml --workspace --all-targets -- -D warnings
notification:
needs: [build,get_release]
runs-on: custom-runner-linux
steps:
- name: Collect jobs status
uses: technote-space/workflow-conclusion-action@v2
- name: Check out repository code
uses: actions/checkout@v3
- name: install npm
uses: actions/setup-node@v3
if: env.WORKFLOW_CONCLUSION == 'failure'
with:
node-version: 18
- name: Matrix - Node Install
if: env.WORKFLOW_CONCLUSION == 'failure'
run: npm install
working-directory: .github/workflows/support-files
- name: Matrix - Send Notification
if: env.WORKFLOW_CONCLUSION == 'failure'
env:
NYM_NOTIFICATION_KIND: nightly
NYM_PROJECT_NAME: "Nym nightly build on latest release"
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
GIT_COMMIT_MESSAGE: "${{ github.event.head_commit.message }}"
GIT_BRANCH_NAME: "${{needs.get_release.outputs.output1}}"
IS_SUCCESS: "${{ env.WORKFLOW_CONCLUSION == 'success' }}"
MATRIX_SERVER: "${{ secrets.MATRIX_SERVER }}"
MATRIX_ROOM: "${{ secrets.MATRIX_ROOM_NIGHTLY }}"
MATRIX_USER_ID: "${{ secrets.MATRIX_USER_ID }}"
MATRIX_TOKEN: "${{ secrets.MATRIX_TOKEN }}"
MATRIX_DEVICE_ID: "${{ secrets.MATRIX_DEVICE_ID }}"
uses: docker://keybaseio/client:stable-node
with:
args: .github/workflows/support-files/notifications/entry_point.sh
-32
View File
@@ -1,32 +0,0 @@
name: Release Nym Wallet
on:
workflow_dispatch:
inputs:
nym_wallet_version:
description: 'The version of the Nym Wallet to release'
default: '1.0.x'
required: true
type: string
jobs:
create-release:
strategy:
fail-fast: false
matrix:
platform: [ubuntu-20.04]
runs-on: ${{ matrix.platform }}
steps:
- uses: actions/checkout@v2
- name: Create release
uses: softprops/action-gh-release@v1
with:
body: >-
This is a pre-release
Download the wallet for your platform:
- [Linux](https://github.com/nymtech/nym/releases/download/nym-wallet-v${{ inputs.nym_wallet_version}}/nym-wallet_v${{ inputs.nym_wallet_version}}_amd64_ubuntu20.04.AppImage)
- [MacOS](https://github.com/nymtech/nym/releases/download/nym-wallet-v${{ inputs.nym_wallet_version}}/nym-wallet_v${{ inputs.nym_wallet_version}}_x64_macos_11.dmg)
- [Windows](https://github.com/nymtech/nym/releases/download/nym-wallet-v${{ inputs.nym_wallet_version}}/nym-wallet_v${{ inputs.nym_wallet_version}}_x64_windows.msi)
prerelease: true
name: Nym Wallet v${{ inputs.nym_wallet_version}}
tag_name: nym-wallet-v${{ inputs.nym_wallet_version}}
-78
View File
@@ -1,78 +0,0 @@
name: Webdriverio tests for nym wallet
on:
push:
paths:
- "nym-wallet/**"
defaults:
run:
working-directory: nym-wallet
jobs:
test:
name: wallet tests
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v2
- name: Tauri dependencies
run: >
sudo apt-get update &&
sudo apt-get install -y
libgtk-3-dev
libgtksourceview-3.0-dev
webkit2gtk-4.0
libappindicator3-dev
webkit2gtk-driver
xvfb
continue-on-error: true
- name: Install minimal stable
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
- name: Node
uses: actions/setup-node@v3
with:
node-version: 18
- name: Install yarn for building application
run: yarn install
- name: Build application
run: yarn run webpack:build & yarn run tauri:build
- name: Check binary exists
run: |
cd target/release/
(test -f nym-wallet && echo nym binary exists) || echo wallet does not exist
- name: Install dependencies
run: yarn install
working-directory: nym-wallet/webdriver
- name: Remove existing user datafile
uses: JesseTG/rm@v1.0.2
with:
path: nym-wallet/webdriver/common/data/user-data.json
- name: Create user data json file
id: create-json
uses: jsdaniell/create-json@1.1.2
with:
name: "user-data.json"
json: ${{ secrets.WALLET_USERDATA }}
dir: "nym-wallet/webdriver/common/data/"
- name: Install tauri-driver
uses: actions-rs/cargo@v1
with:
command: install
args: tauri-driver
- name: Launch tests
run: xvfb-run yarn test:runall
working-directory: nym-wallet/webdriver
@@ -10,7 +10,7 @@ jobs:
runs-on: [self-hosted, custom-runner-linux]
steps:
- uses: actions/checkout@v2
- name: Install Rust stable
uses: actions-rs/toolchain@v1
with:
@@ -23,7 +23,7 @@ jobs:
run: cargo install --version 0.112.0 wasm-opt
- name: Build release contracts
run: make wasm
run: make contracts
- name: Upload Mixnet Contract Artifact
uses: actions/upload-artifact@v3
@@ -1,4 +1,4 @@
name: Publish SDK to NPM
name: Publish Typescript SDK
on:
workflow_dispatch:
@@ -28,8 +28,10 @@ jobs:
- name: Install dependencies
run: yarn
- name: Build and publish
- name: Build WASM and Typescript SDK
run: yarn sdk:build
- name: Publish to NPM
env:
NODE_AUTH_TOKEN: ${{ secrets.NODE_AUTH_TOKEN }}
working-directory: ./sdk/typescript/packages/sdk
run: scripts/publish.sh
run: ./sdk/typescript/scripts/publish.sh
-40
View File
@@ -1,40 +0,0 @@
name: Wasm Client
on:
pull_request:
paths:
- 'clients/webassembly/**'
- 'clients/client-core/**'
- 'common/**'
- 'contracts/**'
- 'gateway/gateway-requests/**'
- 'nym-api/nym-api-requests/**'
jobs:
wasm:
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
target: wasm32-unknown-unknown
override: true
components: rustfmt, clippy
- uses: actions-rs/cargo@v1
with:
command: build
args: --manifest-path clients/webassembly/Cargo.toml --target wasm32-unknown-unknown
- uses: actions-rs/cargo@v1
with:
command: fmt
args: --manifest-path clients/webassembly/Cargo.toml -- --check
- uses: actions-rs/cargo@v1
with:
command: clippy
args: --manifest-path clients/webassembly/Cargo.toml --target wasm32-unknown-unknown -- -D warnings
+3 -1
View File
@@ -43,4 +43,6 @@ envs/qwerty.env
.parcel-cache
**/.DS_Store
cpu-cycles/libcpucycles/build
foxyfox.env
foxyfox.env
.next
+16
View File
@@ -4,6 +4,22 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
## [Unreleased]
## [v1.1.31-kitkat] (2023-09-12)
- feat: add name to `TaskClient` ([#3844])
- added 'open_proxy', 'enabled_statistics' and 'statistics_recipient' to NR config ([#3839])
- MixFetch: initial prototype for insecure HTTP ([#3645])
- MixFetch: prototype implementing TLS in WASM for HTTPS ([#3644])
- SDK: build package for NodeJS ([#3558])
- [Issue] There is already an open connection to this client ([#2845])
[#3844]: https://github.com/nymtech/nym/pull/3844
[#3839]: https://github.com/nymtech/nym/pull/3839
[#3645]: https://github.com/nymtech/nym/issues/3645
[#3644]: https://github.com/nymtech/nym/issues/3644
[#3558]: https://github.com/nymtech/nym/issues/3558
[#2845]: https://github.com/nymtech/nym/issues/2845
## [v1.1.30-twix] (2023-09-05)
- geo_aware_provider: fix too much filtering of gateways ([#3826])
Generated
+1100 -298
View File
File diff suppressed because it is too large Load Diff
+47 -4
View File
@@ -46,6 +46,7 @@ members = [
"common/crypto",
"common/dkg",
"common/execute",
"common/http-requests",
"common/inclusion-probability",
"common/ledger",
"common/mixnode-common",
@@ -73,7 +74,10 @@ members = [
"common/task",
"common/topology",
"common/types",
"common/wasm-utils",
"common/wasm/client-core",
"common/wasm/storage",
"common/wasm/utils",
"common/wireguard",
"explorer-api",
"explorer-api/explorer-api-requests",
"explorer-api/explorer-client",
@@ -87,11 +91,18 @@ members = [
"service-providers/network-requester",
"service-providers/network-statistics",
"nym-api",
"nym-browser-extension/storage",
"nym-api/nym-api-requests",
"nym-outfox",
"tools/internal/ssl-inject",
"tools/internal/sdk-version-bump",
"tools/nym-cli",
"tools/nym-nr-query",
"tools/ts-rs-cli"
"tools/ts-rs-cli",
"wasm/client",
"wasm/full-nym-wasm",
"wasm/mix-fetch",
"wasm/node-tester",
]
default-members = [
@@ -105,7 +116,7 @@ default-members = [
"explorer-api",
]
exclude = ["explorer", "contracts", "clients/webassembly", "nym-wallet", "nym-connect/mobile/src-tauri", "nym-connect/desktop", "nym-browser-extension/storage", "cpu-cycles"]
exclude = ["explorer", "contracts", "nym-wallet", "nym-connect/mobile/src-tauri", "nym-connect/desktop", "cpu-cycles"]
[workspace.package]
authors = ["Nym Technologies SA"]
@@ -117,7 +128,7 @@ license = "Apache-2.0"
[workspace.dependencies]
anyhow = "1.0.71"
async-trait = "0.1.64"
async-trait = "0.1.68"
bip39 = { version = "2.0.0", features = ["zeroize"] }
cfg-if = "1.0.0"
cosmwasm-derive = "=1.3.0"
@@ -135,6 +146,7 @@ cw2 = { version = "=1.1.0" }
cw3 = { version = "=1.1.0" }
cw4 = { version = "=1.1.0" }
cw-controllers = { version = "=1.1.0" }
dashmap = "5.5.3"
dotenvy = "0.15.6"
futures = "0.3.28"
generic-array = "0.14.7"
@@ -143,10 +155,12 @@ k256 = "0.13"
lazy_static = "1.4.0"
log = "0.4"
once_cell = "1.7.2"
parking_lot = "0.12.1"
rand = "0.8.5"
reqwest = "0.11.18"
serde = "1.0.152"
serde_json = "1.0.91"
sqlx = "0.7.2"
tap = "1.0.1"
tendermint-rpc = "0.32" # same version as used by cosmrs
thiserror = "1.0.38"
@@ -156,4 +170,33 @@ url = "2.4"
zeroize = "1.6.0"
# wasm-related dependencies
gloo-utils = "0.1.7"
js-sys = "0.3.63"
serde-wasm-bindgen = "0.5.0"
tsify = "0.4.5"
wasm-bindgen = "0.2.86"
wasm-bindgen-futures = "0.4.37"
wasmtimer = "0.2.0"
web-sys = "0.3.63"
# Profile settings for individual crates
[profile.release.package.nym-socks5-listener]
strip = true
codegen-units = 1
[profile.release.package.nym-client-wasm]
# lto = true
opt-level = 'z'
[profile.release.package.nym-node-tester-wasm]
# lto = true
opt-level = 'z'
[profile.release.package.nym-wasm-sdk]
# lto = true
opt-level = 'z'
[profile.release.package.mix-fetch-wasm]
# lto = true
opt-level = 'z'
+105 -55
View File
@@ -1,38 +1,56 @@
# Default target
# Top-level Makefile for the nym monorepo
# Default target. Probably what you want to run in normal day-to-day usage when
# you want to check all backend code in one step.
all: test
test: clippy-all cargo-test wasm fmt
help:
@echo "The main targets are"
@echo " all: the default target. Alias for test"
@echo " build: build all binaries"
@echo " build-release: build platform binaries and contracts in release mode"
@echo " clippy: run clippy for all workspaces"
@echo " test: run clippy, unit tests, and formatting."
@echo " test-all: like test, but also includes the expensive tests"
# -----------------------------------------------------------------------------
# Meta targets
# -----------------------------------------------------------------------------
# Run clippy for all workspaces, run all tests, format all Rust code
test: clippy cargo-test fmt
# Same as test, but also runs slow tests
test-all: test cargo-test-expensive
no-clippy: build cargo-test wasm fmt
# Build release binaries for the main workspace (platform binaries) and the
# contracts, including running wasm-opt.
# Producing release versions of other components is deferred to their
# respective toolchains.
build-release: build-release-main contracts
happy: fmt clippy-happy test
# Not a meta target, more of a top-level target for building all binaries (in
# debug mode). Listed here for visibility. The deps are appended successively
build:
# Building release binaries is a little manual as we can't just build --release
# on all workspaces.
build-release: build-release-main wasm
# Deprecated
# For backwards compatibility
clippy-all: clippy
# Not a meta target, more of a top-level target for clippy. Listed here for
# visibility. The deps are appended successively.
clippy:
# -----------------------------------------------------------------------------
# Define targets for a given workspace
# $(1): name
# $(2): path to workspace
# $(3): extra arguments to cargo
# $(4): RUSTFLAGS prefix env
# -----------------------------------------------------------------------------
define add_cargo_workspace
clippy-happy-$(1):
cargo clippy --manifest-path $(2)/Cargo.toml $(3)
clippy-$(1):
cargo clippy --manifest-path $(2)/Cargo.toml --workspace $(3) -- -D warnings
cargo $$($(1)_CLIPPY_TOOLCHAIN) clippy --manifest-path $(2)/Cargo.toml --workspace $(3) -- -D warnings
clippy-examples-$(1):
cargo clippy --manifest-path $(2)/Cargo.toml --workspace --examples -- -D warnings
clippy-extra-$(1):
cargo $$($(1)_CLIPPY_TOOLCHAIN) clippy --manifest-path $(2)/Cargo.toml --workspace --examples --tests -- -D warnings
check-$(1):
cargo check --manifest-path $(2)/Cargo.toml --workspace $(3)
@@ -46,24 +64,22 @@ test-expensive-$(1):
build-$(1):
cargo build --manifest-path $(2)/Cargo.toml --workspace $(3)
build-examples-$(1):
cargo build --manifest-path $(2)/Cargo.toml --workspace --examples
build-extra-$(1):
cargo build --manifest-path $(2)/Cargo.toml --workspace --examples --tests
build-release-$(1):
cargo build --manifest-path $(2)/Cargo.toml --workspace --release $(3)
$(4) cargo $$($(1)_BUILD_RELEASE_TOOLCHAIN) build --manifest-path $(2)/Cargo.toml --workspace --release $(3)
fmt-$(1):
cargo fmt --manifest-path $(2)/Cargo.toml --all
clippy-happy: clippy-happy-$(1)
clippy: clippy-$(1) clippy-examples-$(1)
clippy: clippy-$(1) clippy-extra-$(1)
check: check-$(1)
cargo-test: test-$(1)
cargo-test-expensive: test-expensive-$(1)
build: build-$(1) build-examples-$(1)
build: build-$(1) build-extra-$(1)
build-release-all: build-release-$(1)
fmt: fmt-$(1)
endef
# -----------------------------------------------------------------------------
@@ -73,11 +89,72 @@ endef
# Generate targets for the various cargo workspaces
$(eval $(call add_cargo_workspace,main,.))
$(eval $(call add_cargo_workspace,contracts,contracts,--lib --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,contracts,contracts,--lib --target wasm32-unknown-unknown,RUSTFLAGS='-C link-arg=-s'))
$(eval $(call add_cargo_workspace,wallet,nym-wallet))
$(eval $(call add_cargo_workspace,connect,nym-connect/desktop))
# OVERRIDE: there is an issue where clippy crashes on nym-wallet-types with the latest
# stable toolchain. So pin to 1.71.0 until that is resolved.
wallet_CLIPPY_TOOLCHAIN := +1.71.0
# OVERRIDE: wasm-opt fails if the binary has been built with the latest rustc.
# Pin to the last working version.
contracts_BUILD_RELEASE_TOOLCHAIN := +1.69.0
# -----------------------------------------------------------------------------
# SDK
# -----------------------------------------------------------------------------
sdk-wasm: sdk-wasm-build sdk-wasm-test sdk-wasm-lint
sdk-wasm-build:
$(MAKE) -C nym-browser-extension/storage wasm-pack
$(MAKE) -C wasm/client
$(MAKE) -C wasm/node-tester
$(MAKE) -C wasm/mix-fetch
$(MAKE) -C wasm/full-nym-wasm
# run this from npm/yarn to ensure tools are in the path, e.g. yarn build:sdk from root of repo
sdk-typescript-build:
npx lerna run --scope @nymproject/sdk build --stream
npx lerna run --scope @nymproject/mix-fetch build --stream
npx lerna run --scope @nymproject/node-tester build --stream
yarn --cwd sdk/typescript/codegen/contract-clients build
# NOTE: These targets are part of the main workspace (but not as wasm32-unknown-unknown)
WASM_CRATES = extension-storage nym-client-wasm nym-node-tester-wasm nym-wasm-sdk
sdk-wasm-test:
#cargo test $(addprefix -p , $(WASM_CRATES)) --target wasm32-unknown-unknown -- -Dwarnings
sdk-wasm-lint:
cargo clippy $(addprefix -p , $(WASM_CRATES)) --target wasm32-unknown-unknown -- -Dwarnings
$(MAKE) -C wasm/mix-fetch check-fmt
# Add to top-level targets
build: sdk-wasm-build
cargo-test: sdk-wasm-test
clippy: sdk-wasm-lint
# -----------------------------------------------------------------------------
# Build contracts ready for deploy
# -----------------------------------------------------------------------------
CONTRACTS=vesting_contract mixnet_contract nym_service_provider_directory nym_name_service
CONTRACTS_WASM=$(addsuffix .wasm, $(CONTRACTS))
CONTRACTS_OUT_DIR=contracts/target/wasm32-unknown-unknown/release
contracts: build-release-contracts wasm-opt-contracts
wasm-opt-contracts:
for contract in $(CONTRACTS_WASM); do \
wasm-opt --disable-sign-ext -Os $(CONTRACTS_OUT_DIR)/$$contract -o $(CONTRACTS_OUT_DIR)/$$contract; \
done
# Consider adding 's' to make plural consistent (beware: used in github workflow)
contract-schema:
$(MAKE) -C contracts schema
# -----------------------------------------------------------------------------
# Convenience targets for crates that are already part of the main workspace
# -----------------------------------------------------------------------------
@@ -88,41 +165,14 @@ build-explorer-api:
build-nym-cli:
cargo build -p nym-cli --release
# -----------------------------------------------------------------------------
# Build contracts ready for deploy
# -----------------------------------------------------------------------------
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
NAME_SERVICE_CONTRACT=$(CONTRACTS_OUT_DIR)/nym_name_service.wasm
wasm: wasm-build wasm-opt
wasm-build:
RUSTFLAGS='-C link-arg=-s' cargo build --lib --manifest-path contracts/Cargo.toml --release --target wasm32-unknown-unknown
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)
wasm-opt --disable-sign-ext -Os $(NAME_SERVICE_CONTRACT) -o $(NAME_SERVICE_CONTRACT)
contract-schema:
$(MAKE) -C contracts schema
# -----------------------------------------------------------------------------
# Misc
# -----------------------------------------------------------------------------
# NOTE: this seems deprecated an not needed anymore?
mixnet-opt: wasm
cd contracts/mixnet && make opt
generate-typescript:
cd tools/ts-rs-cli && cargo run && cd ../..
yarn types:lint:fix
run-api-tests:
cd nym-api/tests/functional_test && yarn test:qa
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "nym-client"
version = "1.1.28"
version = "1.1.29"
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"]
description = "Implementation of the Nym Client"
edition = "2021"
+1 -1
View File
@@ -67,7 +67,7 @@ pub struct Config {
}
impl NymConfigTemplate for Config {
fn template() -> &'static str {
fn template(&self) -> &'static str {
CONFIG_TEMPLATE
}
}
@@ -1,8 +1,13 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::client::config::persistence::ClientPaths;
use crate::client::config::{default_config_filepath, Config, Socket, SocketType};
use crate::{
client::config::{
default_config_filepath, persistence::ClientPaths, Config, Socket, SocketType,
},
error::ClientError,
};
use nym_bin_common::logging::LoggingSettings;
use nym_client_core::config::disk_persistence::old_v1_1_20_2::CommonClientPathsV1_1_20_2;
use nym_client_core::config::old_config_v1_1_20_2::ConfigV1_1_20_2 as BaseConfigV1_1_20_2;
@@ -43,18 +48,18 @@ impl ConfigV1_1_20_2 {
// in this upgrade, gateway endpoint configuration was moved out of the config file,
// so its returned to be stored elsewhere.
pub fn upgrade(self) -> (Config, GatewayEndpointConfig) {
pub fn upgrade(self) -> Result<(Config, GatewayEndpointConfig), ClientError> {
let gateway_details = self.base.client.gateway_endpoint.clone().into();
let config = Config {
base: self.base.into(),
socket: self.socket.into(),
storage_paths: ClientPaths {
common_paths: self.storage_paths.common_paths.upgrade_default(),
common_paths: self.storage_paths.common_paths.upgrade_default()?,
},
logging: self.logging,
};
(config, gateway_details)
Ok((config, gateway_details))
}
}
@@ -14,7 +14,7 @@ pub struct ClientPaths {
impl ClientPaths {
pub fn new_default<P: AsRef<Path>>(base_data_directory: P) -> Self {
ClientPaths {
common_paths: CommonClientPaths::new_default(base_data_directory),
common_paths: CommonClientPaths::new_base(base_data_directory),
}
}
}
+19 -145
View File
@@ -4,27 +4,19 @@
use crate::client::config::Config;
use crate::error::ClientError;
use crate::websocket;
use futures::channel::mpsc;
use log::*;
use nym_client_core::client::base_client::non_wasm_helpers::default_query_dkg_client_from_config;
use nym_client_core::client::base_client::storage::OnDiskPersistent;
use nym_client_core::client::base_client::{
BaseClientBuilder, ClientInput, ClientOutput, ClientState,
};
use nym_client_core::client::inbound_messages::InputMessage;
use nym_client_core::client::received_buffer::{
ReceivedBufferMessage, ReceivedBufferRequestSender, ReconstructedMessagesReceiver,
};
use nym_sphinx::anonymous_replies::requests::AnonymousSenderTag;
use nym_sphinx::params::PacketType;
use nym_task::connections::TransmissionLane;
use nym_task::TaskManager;
use nym_task::TaskHandle;
use nym_validator_client::QueryHttpRpcNyxdClient;
use std::error::Error;
use tokio::sync::watch::error::SendError;
use std::path::PathBuf;
pub use nym_sphinx::addressing::clients::Recipient;
pub use nym_sphinx::receiver::ReconstructedMessage;
pub mod config;
@@ -34,11 +26,17 @@ pub struct SocketClient {
/// Client configuration options, including, among other things, packet sending rates,
/// key filepaths, etc.
config: Config,
/// Optional path to a .json file containing standalone network details.
custom_mixnet: Option<PathBuf>,
}
impl SocketClient {
pub fn new(config: Config) -> Self {
SocketClient { config }
pub fn new(config: Config, custom_mixnet: Option<PathBuf>) -> Self {
SocketClient {
config,
custom_mixnet,
}
}
fn start_websocket_listener(
@@ -85,7 +83,7 @@ impl SocketClient {
pub async fn run_socket_forever(self) -> Result<(), Box<dyn Error + Send + Sync>> {
let shutdown = self.start_socket().await?;
let res = shutdown.catch_interrupt().await;
let res = shutdown.wait_for_shutdown().await;
log::info!("Stopping nym-client");
res
}
@@ -109,12 +107,16 @@ impl SocketClient {
let storage = self.initialise_storage().await?;
let base_client = BaseClientBuilder::new(&self.config.base, storage, dkg_query_client);
let mut base_client = BaseClientBuilder::new(&self.config.base, storage, dkg_query_client);
if let Some(custom_mixnet) = &self.custom_mixnet {
base_client = base_client.with_stored_topology(custom_mixnet)?;
}
Ok(base_client)
}
pub async fn start_socket(self) -> Result<TaskManager, ClientError> {
pub async fn start_socket(self) -> Result<TaskHandle, ClientError> {
if !self.config.socket.socket_type.is_websocket() {
return Err(ClientError::InvalidSocketMode);
}
@@ -133,141 +135,13 @@ impl SocketClient {
client_output,
client_state,
&self_address,
started_client.task_manager.subscribe(),
started_client.task_handle.get_handle(),
packet_type,
);
info!("Client startup finished!");
info!("The address of this client is: {self_address}");
Ok(started_client.task_manager)
}
pub async fn start_direct(self) -> Result<DirectClient, ClientError> {
if self.config.socket.socket_type.is_websocket() {
return Err(ClientError::InvalidSocketMode);
}
let base_builder = self.create_base_client_builder().await?;
let packet_type = self.config.base.debug.traffic.packet_type;
let mut started_client = base_builder.start_base().await?;
let address = started_client.address;
let client_input = started_client.client_input.register_producer();
let client_output = started_client.client_output.register_consumer();
// register our receiver
let (reconstructed_sender, reconstructed_receiver) = mpsc::unbounded();
// tell the buffer to start sending stuff to us
client_output
.received_buffer_request_sender
.unbounded_send(ReceivedBufferMessage::ReceiverAnnounce(
reconstructed_sender,
))
.expect("the buffer request failed!");
Ok(DirectClient {
client_input,
_received_buffer_request_sender: client_output.received_buffer_request_sender,
reconstructed_receiver,
address,
shutdown_notifier: started_client.task_manager,
packet_type,
})
}
}
pub struct DirectClient {
client_input: ClientInput,
// make sure to not drop the channel
_received_buffer_request_sender: ReceivedBufferRequestSender,
reconstructed_receiver: ReconstructedMessagesReceiver,
address: Recipient,
// we need to keep reference to this guy otherwise things will start dropping
shutdown_notifier: TaskManager,
packet_type: PacketType,
}
impl DirectClient {
pub fn address(&self) -> &Recipient {
&self.address
}
pub fn signal_shutdown(&self) -> Result<(), SendError<()>> {
self.shutdown_notifier.signal_shutdown()
}
pub async fn wait_for_shutdown(&mut self) {
self.shutdown_notifier.wait_for_shutdown().await
}
/// EXPERIMENTAL DIRECT RUST API
/// It's untested and there are absolutely no guarantees about it (but seems to have worked
/// well enough in local tests)
pub async fn send_regular_message(&mut self, recipient: Recipient, message: Vec<u8>) {
let lane = TransmissionLane::General;
let input_msg = InputMessage::new_regular(recipient, message, lane, Some(self.packet_type));
self.client_input
.input_sender
.send(input_msg)
.await
.expect("InputMessageReceiver has stopped receiving!");
}
/// EXPERIMENTAL DIRECT RUST API
/// It's untested and there are absolutely no guarantees about it (but seems to have worked
/// well enough in local tests)
pub async fn send_anonymous_message(
&mut self,
recipient: Recipient,
message: Vec<u8>,
reply_surbs: u32,
) {
let lane = TransmissionLane::General;
let input_msg = InputMessage::new_anonymous(
recipient,
message,
reply_surbs,
lane,
Some(self.packet_type),
);
self.client_input
.input_sender
.send(input_msg)
.await
.expect("InputMessageReceiver has stopped receiving!");
}
/// EXPERIMENTAL DIRECT RUST API
/// It's untested and there are absolutely no guarantees about it (but seems to have worked
/// well enough in local tests)
pub async fn send_reply(&mut self, recipient_tag: AnonymousSenderTag, message: Vec<u8>) {
let lane = TransmissionLane::General;
let input_msg =
InputMessage::new_reply(recipient_tag, message, lane, Some(self.packet_type));
self.client_input
.input_sender
.send(input_msg)
.await
.expect("InputMessageReceiver has stopped receiving!");
}
/// EXPERIMENTAL DIRECT RUST API
/// It's untested and there are absolutely no guarantees about it (but seems to have worked
/// well enough in local tests)
/// Note: it waits for the first occurrence of messages being sent to ourselves. If you expect multiple
/// messages, you might have to call this function repeatedly.
// TODO: I guess this should really return something that `impl Stream<Item=ReconstructedMessage>`
pub async fn wait_for_messages(&mut self) -> Vec<ReconstructedMessage> {
use futures::StreamExt;
self.reconstructed_receiver
.next()
.await
.expect("buffer controller seems to have somehow died!")
Ok(started_client.task_handle)
}
}
+52 -18
View File
@@ -15,12 +15,16 @@ use nym_bin_common::output_format::OutputFormat;
use nym_client_core::client::base_client::storage::gateway_details::OnDiskGatewayDetails;
use nym_client_core::client::key_manager::persistence::OnDiskKeys;
use nym_client_core::config::GatewayEndpointConfig;
use nym_client_core::init::GatewaySetup;
use nym_client_core::error::ClientCoreError;
use nym_client_core::init::helpers::current_gateways;
use nym_client_core::init::types::{GatewayDetails, GatewaySelectionSpecification, GatewaySetup};
use nym_crypto::asymmetric::identity;
use nym_sphinx::addressing::clients::Recipient;
use nym_topology::NymTopology;
use serde::Serialize;
use std::fmt::Display;
use std::net::IpAddr;
use std::path::PathBuf;
use std::{fs, io};
use tap::TapFallible;
@@ -49,7 +53,12 @@ pub(crate) struct Init {
nyxd_urls: Option<Vec<url::Url>>,
/// Comma separated list of rest endpoints of the API validators
#[clap(long, alias = "api_validators", value_delimiter = ',')]
#[clap(
long,
alias = "api_validators",
value_delimiter = ',',
group = "network"
)]
// the alias here is included for backwards compatibility (1.1.4 and before)
nym_apis: Option<Vec<url::Url>>,
@@ -65,6 +74,10 @@ pub(crate) struct Init {
#[clap(long)]
host: Option<IpAddr>,
/// Path to .json file containing custom network specification.
#[clap(long, group = "network", hide = true)]
custom_mixnet: Option<PathBuf>,
/// Mostly debug-related option to increase default traffic rate so that you would not need to
/// modify config post init
#[clap(long, hide = true)]
@@ -102,7 +115,7 @@ impl From<Init> for OverrideConfig {
#[derive(Debug, Serialize)]
pub struct InitResults {
#[serde(flatten)]
client_core: nym_client_core::init::InitResults,
client_core: nym_client_core::init::types::InitResults,
client_listening_port: u16,
client_address: String,
}
@@ -110,7 +123,11 @@ pub struct InitResults {
impl InitResults {
fn new(config: &Config, address: &Recipient, gateway: &GatewayEndpointConfig) -> Self {
Self {
client_core: nym_client_core::init::InitResults::new(&config.base, address, gateway),
client_core: nym_client_core::init::types::InitResults::new(
&config.base,
address,
gateway,
),
client_listening_port: config.socket.listening_port,
client_address: address.to_string(),
}
@@ -130,7 +147,7 @@ fn init_paths(id: &str) -> io::Result<()> {
fs::create_dir_all(default_config_directory(id))
}
pub(crate) async fn execute(args: &Init) -> Result<(), ClientError> {
pub(crate) async fn execute(args: Init) -> Result<(), ClientError> {
eprintln!("Initialising client...");
let id = &args.id;
@@ -150,7 +167,7 @@ pub(crate) async fn execute(args: &Init) -> Result<(), ClientError> {
// re-registering if wanted.
let user_wants_force_register = args.force_register_gateway;
if user_wants_force_register {
eprintln!("Instructed to force registering gateway. This might overwrite keys!");
eprintln!("Instructed to force registering gateway. This will overwrite keys!");
}
// If the client was already initialized, don't generate new keys and don't re-register with
@@ -160,9 +177,10 @@ pub(crate) async fn execute(args: &Init) -> Result<(), ClientError> {
// Attempt to use a user-provided gateway, if possible
let user_chosen_gateway_id = args.gateway;
let gateway_setup = GatewaySetup::new_fresh(
let selection_spec = GatewaySelectionSpecification::new(
user_chosen_gateway_id.map(|id| id.to_base58_string()),
Some(args.latency_based_selection),
false,
);
// Load and potentially override config
@@ -173,16 +191,29 @@ pub(crate) async fn execute(args: &Init) -> Result<(), ClientError> {
let key_store = OnDiskKeys::new(config.storage_paths.common_paths.keys.clone());
let details_store =
OnDiskGatewayDetails::new(&config.storage_paths.common_paths.gateway_details);
let init_details = nym_client_core::init::setup_gateway(
gateway_setup,
&key_store,
&details_store,
register_gateway,
Some(&config.base.client.nym_api_urls),
)
.await
.tap_err(|err| eprintln!("Failed to setup gateway\nError: {err}"))?
.details;
let available_gateways = if let Some(hardcoded_topology) = args
.custom_mixnet
.map(NymTopology::new_from_file)
.transpose()?
{
// hardcoded_topology
hardcoded_topology.get_gateways()
} else {
let mut rng = rand::thread_rng();
current_gateways(&mut rng, &config.base.client.nym_api_urls).await?
};
let gateway_setup = GatewaySetup::New {
specification: selection_spec,
available_gateways,
overwrite_data: register_gateway,
};
let init_details =
nym_client_core::init::setup_gateway(gateway_setup, &key_store, &details_store)
.await
.tap_err(|err| eprintln!("Failed to setup gateway\nError: {err}"))?;
let config_save_location = config.default_location();
config.save_to_default_location().tap_err(|_| {
@@ -197,7 +228,10 @@ pub(crate) async fn execute(args: &Init) -> Result<(), ClientError> {
eprintln!("Client configuration completed.\n");
let init_results = InitResults::new(&config, &address, &init_details.gateway_details);
let GatewayDetails::Configured(gateway_details) = init_details.gateway_details else {
return Err(ClientCoreError::UnexpectedPersistedCustomGatewayDetails)?;
};
let init_results = InitResults::new(&config, &address, &gateway_details);
println!("{}", args.output.format(&init_results));
Ok(())
+6 -6
View File
@@ -84,8 +84,8 @@ pub(crate) async fn execute(args: Cli) -> Result<(), Box<dyn Error + Send + Sync
let bin_name = "nym-native-client";
match args.command {
Commands::Init(m) => init::execute(&m).await?,
Commands::Run(m) => run::execute(&m).await?,
Commands::Init(m) => init::execute(m).await?,
Commands::Run(m) => run::execute(m).await?,
Commands::BuildInfo(m) => build_info::execute(m),
Commands::Completions(s) => s.generate(&mut Cli::command(), bin_name),
Commands::GenerateFigSpec => fig_generate(&mut Cli::command(), bin_name),
@@ -133,7 +133,7 @@ fn persist_gateway_details(
source: Box::new(source),
})
})?;
let persisted_details = PersistedGatewayDetails::new(details, &shared_keys);
let persisted_details = PersistedGatewayDetails::new(details.into(), Some(&shared_keys))?;
details_store
.store_to_disk(&persisted_details)
.map_err(|source| {
@@ -157,7 +157,7 @@ fn try_upgrade_v1_1_13_config(id: &str) -> Result<bool, ClientError> {
let updated_step1: ConfigV1_1_20 = old_config.into();
let updated_step2: ConfigV1_1_20_2 = updated_step1.into();
let (updated, gateway_config) = updated_step2.upgrade();
let (updated, gateway_config) = updated_step2.upgrade()?;
persist_gateway_details(&updated, gateway_config)?;
updated.save_to_default_location()?;
@@ -177,7 +177,7 @@ fn try_upgrade_v1_1_20_config(id: &str) -> Result<bool, ClientError> {
info!("It is going to get updated to the current specification.");
let updated_step1: ConfigV1_1_20_2 = old_config.into();
let (updated, gateway_config) = updated_step1.upgrade();
let (updated, gateway_config) = updated_step1.upgrade()?;
persist_gateway_details(&updated, gateway_config)?;
updated.save_to_default_location()?;
@@ -194,7 +194,7 @@ fn try_upgrade_v1_1_20_2_config(id: &str) -> Result<bool, ClientError> {
info!("It seems the client is using <= v1.1.20_2 config template.");
info!("It is going to get updated to the current specification.");
let (updated, gateway_config) = old_config.upgrade();
let (updated, gateway_config) = old_config.upgrade()?;
persist_gateway_details(&updated, gateway_config)?;
updated.save_to_default_location()?;
+15 -3
View File
@@ -13,6 +13,7 @@ use nym_bin_common::version_checker::is_minor_version_compatible;
use nym_crypto::asymmetric::identity;
use std::error::Error;
use std::net::IpAddr;
use std::path::PathBuf;
#[derive(Args, Clone)]
pub(crate) struct Run {
@@ -25,7 +26,12 @@ pub(crate) struct Run {
nyxd_urls: Option<Vec<url::Url>>,
/// Comma separated list of rest endpoints of the API validators
#[clap(long, alias = "api_validators", value_delimiter = ',')]
#[clap(
long,
alias = "api_validators",
value_delimiter = ',',
group = "network"
)]
// the alias here is included for backwards compatibility (1.1.4 and before)
nym_apis: Option<Vec<url::Url>>,
@@ -46,6 +52,10 @@ pub(crate) struct Run {
#[clap(long)]
host: Option<IpAddr>,
/// Path to .json file containing custom network specification.
#[clap(long, group = "network", hide = true)]
custom_mixnet: Option<PathBuf>,
/// Mostly debug-related option to increase default traffic rate so that you would not need to
/// modify config post init
#[clap(long, hide = true)]
@@ -95,7 +105,7 @@ fn version_check(cfg: &Config) -> bool {
}
}
pub(crate) async fn execute(args: &Run) -> Result<(), Box<dyn Error + Send + Sync>> {
pub(crate) async fn execute(args: Run) -> Result<(), Box<dyn Error + Send + Sync>> {
eprintln!("Starting client {}...", args.id);
let mut config = try_load_current_config(&args.id)?;
@@ -106,5 +116,7 @@ pub(crate) async fn execute(args: &Run) -> Result<(), Box<dyn Error + Send + Syn
return Err(Box::new(ClientError::FailedLocalVersionCheck));
}
SocketClient::new(config).run_socket_forever().await
SocketClient::new(config, args.custom_mixnet)
.run_socket_forever()
.await
}
@@ -230,8 +230,7 @@ impl ServerResponse {
let error_kind = ErrorKind::try_from(b[1])?;
let message_len =
u64::from_be_bytes(b[2..2 + size_of::<u64>()].as_ref().try_into().unwrap());
let message_len = u64::from_be_bytes(b[2..2 + size_of::<u64>()].try_into().unwrap());
let message = &b[2 + size_of::<u64>()..];
if message.len() as u64 != message_len {
return Err(error::Error::new(
+2 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "nym-socks5-client"
version = "1.1.28"
version = "1.1.29"
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"
@@ -16,6 +16,7 @@ serde_json = { workspace = true }
tap = "1.0.1"
thiserror = { workspace = true }
tokio = { version = "1.24.1", features = ["rt-multi-thread", "net", "signal"] }
rand = "0.7.3"
url = { workspace = true }
# internal
+41 -16
View File
@@ -14,11 +14,15 @@ use nym_bin_common::output_format::OutputFormat;
use nym_client_core::client::base_client::storage::gateway_details::OnDiskGatewayDetails;
use nym_client_core::client::key_manager::persistence::OnDiskKeys;
use nym_client_core::config::GatewayEndpointConfig;
use nym_client_core::init::GatewaySetup;
use nym_client_core::error::ClientCoreError;
use nym_client_core::init::helpers::current_gateways;
use nym_client_core::init::types::{GatewayDetails, GatewaySelectionSpecification, GatewaySetup};
use nym_crypto::asymmetric::identity;
use nym_sphinx::addressing::clients::Recipient;
use nym_topology::NymTopology;
use serde::Serialize;
use std::fmt::Display;
use std::path::PathBuf;
use std::{fs, io};
use tap::TapFallible;
@@ -68,6 +72,10 @@ pub(crate) struct Init {
#[clap(short, long)]
port: Option<u16>,
/// Path to .json file containing custom network specification.
#[clap(long, group = "network", hide = true)]
custom_mixnet: Option<PathBuf>,
/// Mostly debug-related option to increase default traffic rate so that you would not need to
/// modify config post init
#[clap(long, hide = true)]
@@ -106,7 +114,7 @@ impl From<Init> for OverrideConfig {
#[derive(Debug, Serialize)]
pub struct InitResults {
#[serde(flatten)]
client_core: nym_client_core::init::InitResults,
client_core: nym_client_core::init::types::InitResults,
socks5_listening_port: u16,
client_address: String,
}
@@ -114,7 +122,7 @@ pub struct InitResults {
impl InitResults {
fn new(config: &Config, address: &Recipient, gateway: &GatewayEndpointConfig) -> Self {
Self {
client_core: nym_client_core::init::InitResults::new(
client_core: nym_client_core::init::types::InitResults::new(
&config.core.base,
address,
gateway,
@@ -138,7 +146,7 @@ fn init_paths(id: &str) -> io::Result<()> {
fs::create_dir_all(default_config_directory(id))
}
pub(crate) async fn execute(args: &Init) -> Result<(), Socks5ClientError> {
pub(crate) async fn execute(args: Init) -> Result<(), Socks5ClientError> {
eprintln!("Initialising client...");
let id = &args.id;
@@ -169,9 +177,10 @@ pub(crate) async fn execute(args: &Init) -> Result<(), Socks5ClientError> {
// Attempt to use a user-provided gateway, if possible
let user_chosen_gateway_id = args.gateway;
let gateway_setup = GatewaySetup::new_fresh(
let selection_spec = GatewaySelectionSpecification::new(
user_chosen_gateway_id.map(|id| id.to_base58_string()),
Some(args.latency_based_selection),
false,
);
// Load and potentially override config
@@ -185,16 +194,29 @@ pub(crate) async fn execute(args: &Init) -> Result<(), Socks5ClientError> {
let key_store = OnDiskKeys::new(config.storage_paths.common_paths.keys.clone());
let details_store =
OnDiskGatewayDetails::new(&config.storage_paths.common_paths.gateway_details);
let init_details = nym_client_core::init::setup_gateway(
gateway_setup,
&key_store,
&details_store,
register_gateway,
Some(&config.core.base.client.nym_api_urls),
)
.await
.tap_err(|err| eprintln!("Failed to setup gateway\nError: {err}"))?
.details;
let available_gateways = if let Some(hardcoded_topology) = args
.custom_mixnet
.map(NymTopology::new_from_file)
.transpose()?
{
// hardcoded_topology
hardcoded_topology.get_gateways()
} else {
let mut rng = rand::thread_rng();
current_gateways(&mut rng, &config.core.base.client.nym_api_urls).await?
};
let gateway_setup = GatewaySetup::New {
specification: selection_spec,
available_gateways,
overwrite_data: register_gateway,
};
let init_details =
nym_client_core::init::setup_gateway(gateway_setup, &key_store, &details_store)
.await
.tap_err(|err| eprintln!("Failed to setup gateway\nError: {err}"))?;
// TODO: ask the service provider we specified for its interface version and set it in the config
@@ -209,7 +231,10 @@ pub(crate) async fn execute(args: &Init) -> Result<(), Socks5ClientError> {
let address = init_details.client_address()?;
let init_results = InitResults::new(&config, &address, &init_details.gateway_details);
let GatewayDetails::Configured(gateway_details) = init_details.gateway_details else {
return Err(ClientCoreError::UnexpectedPersistedCustomGatewayDetails)?;
};
let init_results = InitResults::new(&config, &address, &gateway_details);
println!("{}", args.output.format(&init_results));
Ok(())
+6 -6
View File
@@ -87,8 +87,8 @@ pub(crate) async fn execute(args: Cli) -> Result<(), Box<dyn Error + Send + Sync
let bin_name = "nym-socks5-client";
match args.command {
Commands::Init(m) => init::execute(&m).await?,
Commands::Run(m) => run::execute(&m).await?,
Commands::Init(m) => init::execute(m).await?,
Commands::Run(m) => run::execute(m).await?,
Commands::BuildInfo(m) => build_info::execute(m),
Commands::Completions(s) => s.generate(&mut Cli::command(), bin_name),
Commands::GenerateFigSpec => fig_generate(&mut Cli::command(), bin_name),
@@ -175,7 +175,7 @@ fn persist_gateway_details(
source: Box::new(source),
})
})?;
let persisted_details = PersistedGatewayDetails::new(details, &shared_keys);
let persisted_details = PersistedGatewayDetails::new(details.into(), Some(&shared_keys))?;
details_store
.store_to_disk(&persisted_details)
.map_err(|source| {
@@ -199,7 +199,7 @@ fn try_upgrade_v1_1_13_config(id: &str) -> Result<bool, Socks5ClientError> {
let updated_step1: ConfigV1_1_20 = old_config.into();
let updated_step2: ConfigV1_1_20_2 = updated_step1.into();
let (updated, gateway_config) = updated_step2.upgrade();
let (updated, gateway_config) = updated_step2.upgrade()?;
persist_gateway_details(&updated, gateway_config)?;
updated.save_to_default_location()?;
@@ -219,7 +219,7 @@ fn try_upgrade_v1_1_20_config(id: &str) -> Result<bool, Socks5ClientError> {
info!("It is going to get updated to the current specification.");
let updated_step1: ConfigV1_1_20_2 = old_config.into();
let (updated, gateway_config) = updated_step1.upgrade();
let (updated, gateway_config) = updated_step1.upgrade()?;
persist_gateway_details(&updated, gateway_config)?;
updated.save_to_default_location()?;
@@ -236,7 +236,7 @@ fn try_upgrade_v1_1_20_2_config(id: &str) -> Result<bool, Socks5ClientError> {
info!("It seems the client is using <= v1.1.20_2 config template.");
info!("It is going to get updated to the current specification.");
let (updated, gateway_config) = old_config.upgrade();
let (updated, gateway_config) = old_config.upgrade()?;
persist_gateway_details(&updated, gateway_config)?;
updated.save_to_default_location()?;
+11 -4
View File
@@ -15,6 +15,7 @@ use nym_client_core::client::topology_control::geo_aware_provider::CountryGroup;
use nym_crypto::asymmetric::identity;
use nym_socks5_client_core::NymClient;
use nym_sphinx::addressing::clients::Recipient;
use std::path::PathBuf;
#[derive(Args, Clone)]
pub(crate) struct Run {
@@ -45,13 +46,17 @@ pub(crate) struct Run {
nyxd_urls: Option<Vec<url::Url>>,
/// Comma separated list of rest endpoints of the Nym APIs
#[clap(long, value_delimiter = ',')]
#[clap(long, value_delimiter = ',', group = "network")]
nym_apis: Option<Vec<url::Url>>,
/// Port for the socket to listen on
#[clap(short, long)]
port: Option<u16>,
/// Path to .json file containing custom network specification.
#[clap(long, group = "network", group = "routing", hide = true)]
custom_mixnet: Option<PathBuf>,
/// Mostly debug-related option to increase default traffic rate so that you would not need to
/// modify config post init
#[clap(long, hide = true)]
@@ -62,7 +67,7 @@ pub(crate) struct Run {
no_cover: bool,
/// Set geo-aware mixnode selection when sending mixnet traffic, for experiments only.
#[clap(long, hide = true, value_parser = validate_country_group)]
#[clap(long, hide = true, value_parser = validate_country_group, group="routing")]
geo_routing: Option<CountryGroup>,
/// Enable medium mixnet traffic, for experiments only.
@@ -124,7 +129,7 @@ fn version_check(cfg: &Config) -> bool {
}
}
pub(crate) async fn execute(args: &Run) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
pub(crate) async fn execute(args: Run) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
eprintln!("Starting client {}...", args.id);
let mut config = try_load_current_config(&args.id)?;
@@ -138,5 +143,7 @@ pub(crate) async fn execute(args: &Run) -> Result<(), Box<dyn std::error::Error
let storage =
OnDiskPersistent::from_paths(config.storage_paths.common_paths, &config.core.base.debug)
.await?;
NymClient::new(config.core, storage).run_forever().await
NymClient::new(config.core, storage, args.custom_mixnet)
.run_forever()
.await
}
+1 -1
View File
@@ -62,7 +62,7 @@ pub struct Config {
}
impl NymConfigTemplate for Config {
fn template() -> &'static str {
fn template(&self) -> &'static str {
CONFIG_TEMPLATE
}
}
@@ -1,17 +1,21 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::config::persistence::SocksClientPaths;
use crate::config::{default_config_filepath, Config};
use crate::{
config::{default_config_filepath, persistence::SocksClientPaths, Config},
error::Socks5ClientError,
};
use nym_bin_common::logging::LoggingSettings;
use nym_client_core::config::disk_persistence::old_v1_1_20_2::CommonClientPathsV1_1_20_2;
use nym_client_core::config::GatewayEndpointConfig;
use nym_config::read_config_from_toml_file;
pub use nym_socks5_client_core::config::old_config_v1_1_20_2::ConfigV1_1_20_2 as CoreConfigV1_1_20_2;
use serde::{Deserialize, Serialize};
use std::io;
use std::path::Path;
pub use nym_socks5_client_core::config::old_config_v1_1_20_2::ConfigV1_1_20_2 as CoreConfigV1_1_20_2;
#[derive(Debug, Deserialize, PartialEq, Eq, Serialize, Clone)]
pub struct SocksClientPathsV1_1_20_2 {
#[serde(flatten)]
@@ -39,16 +43,16 @@ impl ConfigV1_1_20_2 {
// in this upgrade, gateway endpoint configuration was moved out of the config file,
// so its returned to be stored elsewhere.
pub fn upgrade(self) -> (Config, GatewayEndpointConfig) {
pub fn upgrade(self) -> Result<(Config, GatewayEndpointConfig), Socks5ClientError> {
let gateway_details = self.core.base.client.gateway_endpoint.clone().into();
let config = Config {
core: self.core.into(),
storage_paths: SocksClientPaths {
common_paths: self.storage_paths.common_paths.upgrade_default(),
common_paths: self.storage_paths.common_paths.upgrade_default()?,
},
logging: self.logging,
};
(config, gateway_details)
Ok((config, gateway_details))
}
}
+1 -1
View File
@@ -14,7 +14,7 @@ pub struct SocksClientPaths {
impl SocksClientPaths {
pub fn new_default<P: AsRef<Path>>(base_data_directory: P) -> Self {
SocksClientPaths {
common_paths: CommonClientPaths::new_default(base_data_directory),
common_paths: CommonClientPaths::new_base(base_data_directory),
}
}
}
-11
View File
@@ -1,11 +0,0 @@
install:
- appveyor-retry appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe
- if not defined RUSTFLAGS rustup-init.exe -y --default-host x86_64-pc-windows-msvc --default-toolchain nightly
- set PATH=%PATH%;C:\Users\appveyor\.cargo\bin
- rustc -V
- cargo -V
build: false
test_script:
- cargo test --locked
-2
View File
@@ -1,2 +0,0 @@
[build]
target = "wasm32-unknown-unknown"
-6
View File
@@ -1,6 +0,0 @@
/target
**/*.rs.bk
bin/
pkg/
wasm-pack.log
node_modules
-69
View File
@@ -1,69 +0,0 @@
language: rust
sudo: false
cache: cargo
matrix:
include:
# Builds with wasm-pack.
- rust: beta
env: RUST_BACKTRACE=1
addons:
firefox: latest
chrome: stable
before_script:
- (test -x $HOME/.cargo/bin/cargo-install-update || cargo install cargo-update)
- (test -x $HOME/.cargo/bin/cargo-generate || cargo install --vers "^0.2" cargo-generate)
- cargo install-update -a
- curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh -s -- -f
script:
- cargo generate --git . --name testing
# Having a broken Cargo.toml (in that it has curlies in fields) anywhere
# in any of our parent dirs is problematic.
- mv Cargo.toml Cargo.toml.tmpl
- cd testing
- wasm-pack build
- wasm-pack test --chrome --firefox --headless
# Builds on nightly.
- rust: nightly
env: RUST_BACKTRACE=1
before_script:
- (test -x $HOME/.cargo/bin/cargo-install-update || cargo install cargo-update)
- (test -x $HOME/.cargo/bin/cargo-generate || cargo install --vers "^0.2" cargo-generate)
- cargo install-update -a
- rustup target add wasm32-unknown-unknown
script:
- cargo generate --git . --name testing
- mv Cargo.toml Cargo.toml.tmpl
- cd testing
- cargo check
- cargo check --target wasm32-unknown-unknown
- cargo check --no-default-features
- cargo check --target wasm32-unknown-unknown --no-default-features
- cargo check --no-default-features --features console_error_panic_hook
- cargo check --target wasm32-unknown-unknown --no-default-features --features console_error_panic_hook
- cargo check --no-default-features --features "console_error_panic_hook wee_alloc"
- cargo check --target wasm32-unknown-unknown --no-default-features --features "console_error_panic_hook wee_alloc"
# Builds on beta.
- rust: beta
env: RUST_BACKTRACE=1
before_script:
- (test -x $HOME/.cargo/bin/cargo-install-update || cargo install cargo-update)
- (test -x $HOME/.cargo/bin/cargo-generate || cargo install --vers "^0.2" cargo-generate)
- cargo install-update -a
- rustup target add wasm32-unknown-unknown
script:
- cargo generate --git . --name testing
- mv Cargo.toml Cargo.toml.tmpl
- cd testing
- cargo check
- cargo check --target wasm32-unknown-unknown
- cargo check --no-default-features
- cargo check --target wasm32-unknown-unknown --no-default-features
- cargo check --no-default-features --features console_error_panic_hook
- cargo check --target wasm32-unknown-unknown --no-default-features --features console_error_panic_hook
# Note: no enabling the `wee_alloc` feature here because it requires
# nightly for now.
-5559
View File
File diff suppressed because it is too large Load Diff
-74
View File
@@ -1,74 +0,0 @@
[package]
name = "nym-client-wasm"
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jedrzej Stuczynski <andrew@nymtech.net>"]
version = "1.1.1"
edition = "2021"
keywords = ["nym", "sphinx", "wasm", "webassembly", "privacy"]
license = "Apache-2.0"
repository = "https://github.com/nymtech/nym"
description = "A webassembly client which can be used to interact with the the Nym privacy platform. Wasm is used for Sphinx packet generation."
rust-version = "1.56"
[lib]
crate-type = ["cdylib", "rlib"]
[features]
default = ["console_error_panic_hook"]
offline-test = []
[dependencies]
async-trait = "0.1.68"
bs58 = "0.4.0"
futures = "0.3"
js-sys = "0.3"
rand = { version = "0.7.3", features = ["wasm-bindgen"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
anyhow = "1.0"
serde-wasm-bindgen = "0.5"
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"
zeroize = "1.6.0"
wasmtimer = { version = "0.2.0", features = ["tokio"] }
# internal
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", features = ["asymmetric", "serde"] }
nym-sphinx = { path = "../../common/nymsphinx" }
nym-sphinx-acknowledgements = { path = "../../common/nymsphinx/acknowledgements", features = ["serde"]}
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 }
nym-task = { path = "../../common/task" }
wasm-utils = { path = "../../common/wasm-utils", features = ["storage"], default-features = false }
# The `console_error_panic_hook` crate provides better debugging of panics by
# logging them with `console.error`. This is great for development, but requires
# all the `std::fmt` and `std::panicking` infrastructure, so isn't great for
# code size when deploying.
console_error_panic_hook = { version = "0.1", optional = true }
# `wee_alloc` is a tiny allocator for wasm that is only ~1K in code size
# compared to the default allocator's ~10K. It is slower than the default
# allocator, however.
#
# Unfortunately, `wee_alloc` requires nightly Rust when targeting wasm for now.
wee_alloc = { version = "0.4", optional = true }
[dev-dependencies]
wasm-bindgen-test = "0.3"
[package.metadata.wasm-pack.profile.release]
wasm-opt = false
[profile.release]
lto = true
opt-level = 'z'
-176
View File
@@ -1,176 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
-8
View File
@@ -1,8 +0,0 @@
clippy:
cargo clippy --all-features --target wasm32-unknown-unknown -- -D warnings
test:
wasm-pack test --node
wasm-build:
wasm-pack build
-382
View File
@@ -1,382 +0,0 @@
// 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,
ClientStorage,
current_network_topology,
make_key,
make_key2,
} = wasm_bindgen;
let client = null;
let tester = null;
const preferredGateway = "336yuXAeGEgedRfqTJZsG2YV7P13QH1bHv1SjCZYarc9";
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,
},
});
}
async function testWithTester() {
// A) construct with hardcoded topology
const topology = dummyTopology();
const nodeTester = await new NymNodeTester(topology, preferredGateway);
// 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(topology, preferredGateway);
//
// 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(validator, preferredGateway)
// 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(topology, undefined, preferredGateway);
//
// 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(validator, undefined, preferredGateway)
// D, E, F) you also don't have to specify the gateway. if you don't, a random one (from your topology) will be used
// const topology = dummyTopology()
// const nodeTester = await new NymNodeTester(topology);
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 testerReconnection() {
const validator = "https://qwerty-validator-api.qa.nymte.ch/api";
const nodeTester = await NymNodeTester.new_with_api(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 result1 = await nodeTester.test_node(mixnodeIdentity);
console.log("sleeping for 5s");
await new Promise((r) => setTimeout(r, 5000));
await nodeTester.disconnect_from_gateway();
console.log("sleeping for 5s");
await new Promise((r) => setTimeout(r, 5000));
await nodeTester.reconnect_to_gateway();
let result2 = await nodeTester.test_node(mixnodeIdentity);
printAndDisplayTestResult(result1);
printAndDisplayTestResult(result2);
}
}
}
};
}
async function testWithNymClient() {
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(
topology,
onMessageHandler,
preferredGateway
);
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 preferredGateway = "336yuXAeGEgedRfqTJZsG2YV7P13QH1bHv1SjCZYarc9";
const validator = "https://qwerty-validator-api.qa.nymte.ch/api";
const config = new Config("my-awesome-wasm-client", validator, 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 messWithStorage() {
self.onmessage = async (event) => {
if (event.data && event.data.kind) {
switch (event.data.kind) {
case "TestPacket": {
const { mixnodeIdentity } = event.data.args;
console.log("button clicked...", mixnodeIdentity);
let id1 = "one";
let id2 = "two";
console.log("making store1 NO-ENC");
let _storage1 = await ClientStorage.new_unencrypted(id1);
console.log("making store2 ENC");
let _storage2 = await new ClientStorage(id2, "my-secret-password");
//
//
//
// console.log("attempting to use store1 WITH PASSWORD")
// let _storage1_alt = await new ClientStorage(id1, "password");
//
//
//
// console.log("attempting to use store2 WITHOUT PASSWORD")
// let _storage2_alt = await ClientStorage.new_unencrypted(id2);
//
//
//
// console.log("attempting to use store2 with WRONG PASSWORD")
// let _storage2_bad = await new ClientStorage(id2, "bad-password")
//
// console.log("read1: ", await storage1.read());
// console.log("read2: ", await storage2.read());
//
// console.log("store1: ", await storage1.store("FOOMP"));
//
// console.log("read1: ", await storage1.read());
// console.log("read2: ", await storage2.read());
}
}
}
};
}
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();
// show reconnection capabilities
// await testerReconnection()
// run test on simplified and dedicated tester:
await testWithTester();
// 'Normal' client setup (to send 'normal' messages)
// await normalNymClientUsage()
}
// Let's get started!
main();
-5
View File
@@ -1,5 +0,0 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
pub(crate) const NODE_TESTER_ID: &str = "_nym-node-tester";
pub(crate) const NODE_TESTER_CLIENT_ID: &str = "_nym-node-tester-client";
@@ -1,45 +0,0 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
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 =
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}"),
Ok(gateways) => gateways,
};
if let Some(preferred) = preferred {
if let Some(details) = gateways
.iter()
.find(|g| g.gateway.identity_key == preferred)
{
return GatewayEndpointConfig {
gateway_id: details.gateway.identity_key.clone(),
gateway_owner: details.owner.to_string(),
gateway_listener: format!(
"ws://{}:{}",
details.gateway.host, details.gateway.clients_port
),
};
}
}
let details = gateways
.first()
.expect("current topology holds no gateways");
GatewayEndpointConfig {
gateway_id: details.gateway.identity_key.clone(),
gateway_owner: details.owner.to_string(),
gateway_listener: format!(
"ws://{}:{}",
details.gateway.host, details.gateway.clients_port
),
}
}
-42
View File
@@ -1,42 +0,0 @@
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
// After reading https://github.com/rust-lang/rust-clippy/issues/11382
// I suspect we *maybe* have hit a false positive, but I'm not sure.
#![allow(clippy::arc_with_non_send_sync)]
use wasm_bindgen::prelude::*;
#[cfg(target_arch = "wasm32")]
mod client;
#[cfg(target_arch = "wasm32")]
pub mod encoded_payload_helper;
#[cfg(target_arch = "wasm32")]
pub mod error;
#[cfg(target_arch = "wasm32")]
pub mod gateway_selector;
#[cfg(target_arch = "wasm32")]
pub mod storage;
#[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;
mod constants;
#[wasm_bindgen]
pub fn set_panic_hook() {
// When the `console_error_panic_hook` feature is enabled, we can call the
// `set_panic_hook` function at least once during initialization, and then
// we will get better error messages if our code ever panics.
//
// For more details see
// https://github.com/rustwasm/console_error_panic_hook#readme
#[cfg(feature = "console_error_panic_hook")]
console_error_panic_hook::set_once();
}
-28
View File
@@ -1,28 +0,0 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use thiserror::Error;
use wasm_bindgen::JsValue;
use wasm_utils::simple_js_error;
use wasm_utils::storage::error::StorageError;
#[derive(Debug, Error)]
pub enum ClientStorageError {
#[error("failed to use the storage: {source}")]
StorageError {
#[from]
source: StorageError,
},
#[error("{typ} cryptographic key is not available in storage")]
CryptoKeyNotInStorage { typ: String },
#[error("the prior gateway details are not available in the storage")]
GatewayDetailsNotInStorage,
}
impl From<ClientStorageError> for JsValue {
fn from(value: ClientStorageError) -> Self {
simple_js_error(value.to_string())
}
}
-294
View File
@@ -1,294 +0,0 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::client::config::Config;
use crate::storage::error::ClientStorageError;
use js_sys::Promise;
use nym_client_core::client::base_client::storage::gateway_details::PersistedGatewayDetails;
use nym_crypto::asymmetric::{encryption, identity};
use nym_gateway_client::SharedKeys;
use nym_sphinx::acknowledgements::AckKey;
use std::sync::Arc;
use wasm_bindgen::prelude::*;
use wasm_bindgen_futures::future_to_promise;
use wasm_utils::storage::{IdbVersionChangeEvent, WasmStorage};
use wasm_utils::PromisableResult;
use zeroize::Zeroizing;
pub(crate) mod error;
pub(crate) mod traits;
const STORAGE_NAME_PREFIX: &str = "wasm-client-storage";
const STORAGE_VERSION: u32 = 1;
// v1 tables
mod v1 {
// stores
pub const KEYS_STORE: &str = "keys";
pub const CORE_STORE: &str = "core";
// keys
pub const CONFIG: &str = "config";
pub const GATEWAY_DETAILS: &str = "gateway_details";
pub const ED25519_IDENTITY_KEYPAIR: &str = "ed25519_identity_keypair";
pub const X25519_ENCRYPTION_KEYPAIR: &str = "x25519_encryption_keypair";
// TODO: for those we could actually use the subtle crypto storage
pub const AES128CTR_ACK_KEY: &str = "aes128ctr_ack_key";
pub const AES128CTR_BLAKE3_HMAC_GATEWAY_KEYS: &str = "aes128ctr_blake3_hmac_gateway_keys";
}
#[wasm_bindgen]
pub struct ClientStorage {
#[allow(dead_code)]
pub(crate) name: String,
pub(crate) inner: Arc<WasmStorage>,
}
#[wasm_bindgen]
impl ClientStorage {
fn db_name(client_id: &str) -> String {
format!("{STORAGE_NAME_PREFIX}-{client_id}")
}
pub(crate) async fn new_async(
client_id: &str,
passphrase: Option<String>,
) -> Result<Self, ClientStorageError> {
let name = Self::db_name(client_id);
// make sure the password is zeroized when no longer used, especially if we error out.
// special care must be taken on JS side to ensure it's correctly used there.
let passphrase = Zeroizing::new(passphrase);
let migrate_fn = Some(|evt: &IdbVersionChangeEvent| -> Result<(), JsValue> {
// Even if the web-sys bindings expose the version as a f64, the IndexedDB API
// works with an unsigned integer.
// See <https://github.com/rustwasm/wasm-bindgen/issues/1149>
let old_version = evt.old_version() as u32;
if old_version < 1 {
// migrating to version 1
let db = evt.db();
db.create_object_store(v1::KEYS_STORE)?;
db.create_object_store(v1::CORE_STORE)?;
}
Ok(())
});
let inner = WasmStorage::new(
&name,
STORAGE_VERSION,
migrate_fn,
passphrase.as_ref().map(|p| p.as_bytes()),
)
.await?;
Ok(ClientStorage {
inner: Arc::new(inner),
name,
})
}
#[wasm_bindgen(constructor)]
#[allow(clippy::new_ret_no_self)]
pub fn new(client_id: String, passphrase: String) -> Promise {
future_to_promise(async move {
Self::new_async(&client_id, Some(passphrase))
.await
.into_promise_result()
})
}
pub fn new_unencrypted(client_id: String) -> Promise {
future_to_promise(async move {
Self::new_async(&client_id, None)
.await
.into_promise_result()
})
}
// TODO: persist client's config
#[allow(dead_code)]
pub(crate) async fn read_config(&self) -> Result<Option<Config>, ClientStorageError> {
self.inner
.read_value(v1::CORE_STORE, JsValue::from_str(v1::CONFIG))
.await
.map_err(Into::into)
}
pub(crate) async fn may_read_gateway_details(
&self,
) -> Result<Option<PersistedGatewayDetails>, ClientStorageError> {
self.inner
.read_value(v1::CORE_STORE, JsValue::from_str(v1::GATEWAY_DETAILS))
.await
.map_err(Into::into)
}
pub(crate) async fn must_read_gateway_details(
&self,
) -> Result<PersistedGatewayDetails, ClientStorageError> {
self.may_read_gateway_details()
.await?
.ok_or(ClientStorageError::GatewayDetailsNotInStorage)
}
async fn may_read_identity_keypair(
&self,
) -> Result<Option<identity::KeyPair>, ClientStorageError> {
self.inner
.read_value(
v1::KEYS_STORE,
JsValue::from_str(v1::ED25519_IDENTITY_KEYPAIR),
)
.await
.map_err(Into::into)
}
async fn may_read_encryption_keypair(
&self,
) -> Result<Option<encryption::KeyPair>, ClientStorageError> {
self.inner
.read_value(
v1::KEYS_STORE,
JsValue::from_str(v1::X25519_ENCRYPTION_KEYPAIR),
)
.await
.map_err(Into::into)
}
async fn may_read_ack_key(&self) -> Result<Option<AckKey>, ClientStorageError> {
self.inner
.read_value(v1::KEYS_STORE, JsValue::from_str(v1::AES128CTR_ACK_KEY))
.await
.map_err(Into::into)
}
async fn may_read_gateway_shared_key(&self) -> Result<Option<SharedKeys>, ClientStorageError> {
self.inner
.read_value(
v1::KEYS_STORE,
JsValue::from_str(v1::AES128CTR_BLAKE3_HMAC_GATEWAY_KEYS),
)
.await
.map_err(Into::into)
}
async fn must_read_identity_keypair(&self) -> Result<identity::KeyPair, ClientStorageError> {
self.may_read_identity_keypair()
.await?
.ok_or(ClientStorageError::CryptoKeyNotInStorage {
typ: v1::ED25519_IDENTITY_KEYPAIR.to_string(),
})
}
async fn must_read_encryption_keypair(
&self,
) -> Result<encryption::KeyPair, ClientStorageError> {
self.may_read_encryption_keypair()
.await?
.ok_or(ClientStorageError::CryptoKeyNotInStorage {
typ: v1::X25519_ENCRYPTION_KEYPAIR.to_string(),
})
}
async fn must_read_ack_key(&self) -> Result<AckKey, ClientStorageError> {
self.may_read_ack_key()
.await?
.ok_or(ClientStorageError::CryptoKeyNotInStorage {
typ: v1::AES128CTR_ACK_KEY.to_string(),
})
}
async fn must_read_gateway_shared_key(&self) -> Result<SharedKeys, ClientStorageError> {
self.may_read_gateway_shared_key()
.await?
.ok_or(ClientStorageError::CryptoKeyNotInStorage {
typ: v1::AES128CTR_BLAKE3_HMAC_GATEWAY_KEYS.to_string(),
})
}
async fn store_identity_keypair(
&self,
keypair: &identity::KeyPair,
) -> Result<(), ClientStorageError> {
self.inner
.store_value(
v1::KEYS_STORE,
JsValue::from_str(v1::ED25519_IDENTITY_KEYPAIR),
keypair,
)
.await
.map_err(Into::into)
}
async fn store_encryption_keypair(
&self,
keypair: &encryption::KeyPair,
) -> Result<(), ClientStorageError> {
self.inner
.store_value(
v1::KEYS_STORE,
JsValue::from_str(v1::X25519_ENCRYPTION_KEYPAIR),
keypair,
)
.await
.map_err(Into::into)
}
async fn store_ack_key(&self, key: &AckKey) -> Result<(), ClientStorageError> {
self.inner
.store_value(
v1::KEYS_STORE,
JsValue::from_str(v1::AES128CTR_ACK_KEY),
key,
)
.await
.map_err(Into::into)
}
async fn store_gateway_shared_key(&self, key: &SharedKeys) -> Result<(), ClientStorageError> {
self.inner
.store_value(
v1::KEYS_STORE,
JsValue::from_str(v1::AES128CTR_BLAKE3_HMAC_GATEWAY_KEYS),
key,
)
.await
.map_err(Into::into)
}
pub(crate) async fn store_gateway_details(
&self,
gateway_endpoint: &PersistedGatewayDetails,
) -> Result<(), ClientStorageError> {
self.inner
.store_value(
v1::CORE_STORE,
JsValue::from_str(v1::GATEWAY_DETAILS),
gateway_endpoint,
)
.await
.map_err(Into::into)
}
// TODO: persist client's config
#[allow(dead_code)]
pub(crate) async fn store_config(&self, config: &Config) -> Result<(), ClientStorageError> {
self.inner
.store_value(v1::CORE_STORE, JsValue::from_str(v1::CONFIG), config)
.await
.map_err(Into::into)
}
pub(crate) async fn has_full_gateway_info(&self) -> Result<bool, ClientStorageError> {
let has_keys = self.may_read_gateway_shared_key().await?.is_some();
let has_details = self.may_read_gateway_details().await?.is_some();
Ok(has_keys && has_details)
}
}
-267
View File
@@ -1,267 +0,0 @@
// 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::{IdentityKeyRef, 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),
})
}
#[allow(dead_code)]
pub(crate) fn ensure_contains(&self, gateway_config: &GatewayEndpointConfig) -> bool {
self.ensure_contains_gateway_id(&gateway_config.gateway_id)
}
pub(crate) fn ensure_contains_gateway_id(&self, gateway_id: IdentityKeyRef) -> bool {
self.inner
.gateways()
.iter()
.any(|g| g.identity_key.to_base58_string() == 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,
})
}
}
-35
View File
@@ -1,35 +0,0 @@
use nym_sphinx::addressing::clients::Recipient;
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
pub fn validate_recipient(recipient: String) -> Result<(), JsError> {
match Recipient::try_from_base58_string(recipient) {
Ok(_) => Ok(()),
Err(e) => Err(JsError::new(format!("{}", e).as_str())),
}
}
#[cfg(test)]
mod tests {
use super::validate_recipient;
use wasm_bindgen_test::*;
#[wasm_bindgen_test]
fn test_recipient_validation_ok() {
let res = validate_recipient("DyQmXnst5NGGjzUZxRC5Bjs5bd7CBF3xMpsSmbRiizr2.GH6YTBP2NXU3AVqd8WjiTMVyeMjunXMEsp7gVCMEJqpD@336yuXAeGEgedRfqTJZsG2YV7P13QH1bHv1SjCZYarc9".to_string());
assert!(res.is_ok())
}
#[wasm_bindgen_test]
fn test_recipient_validation_fails() {
assert!(validate_recipient(" DyQmXnst5NGGjzUZxRC5Bjs5bd7CBF3xMpsSmbRiizr2.GH6YTBP2NXU3AVqd8WjiTMVyeMjunXMEsp7gVCMEJqpD@336yuXAeGEgedRfqTJZsG2YV7P13QH1bHv1SjCZYarc9".to_string()).is_err());
assert!(validate_recipient(
"DyQmXnst5NGGjzUZxRC5BjbRiizr2.GH6YTBP2NXU3AVqd8WD@336yuXAeGEgedRfqTJZQH1bHv1SjCZYarc9"
.to_string()
)
.is_err());
assert!(validate_recipient("🙀🙀🙀🙀".to_string()).is_err());
assert!(validate_recipient("".to_string()).is_err());
assert!(validate_recipient(" ".to_string()).is_err());
}
}
-13
View File
@@ -1,13 +0,0 @@
//! Test suite for the Web and headless browsers.
#![cfg(target_arch = "wasm32")]
extern crate wasm_bindgen_test;
use wasm_bindgen_test::*;
wasm_bindgen_test_configure!(run_in_browser);
#[wasm_bindgen_test]
fn pass() {
assert_eq!(1 + 1, 2);
}
@@ -32,4 +32,14 @@ impl OutputFormat {
OutputFormat::Json => serde_json::to_string(data).unwrap(),
}
}
#[cfg(feature = "output_format")]
pub fn to_stdout<T: serde::Serialize + ToString>(&self, data: &T) {
println!("{}", self.format(data))
}
#[cfg(feature = "output_format")]
pub fn to_stderr<T: serde::Serialize + ToString>(&self, data: &T) {
eprintln!("{}", self.format(data))
}
}
+13 -14
View File
@@ -11,7 +11,7 @@ rust-version = "1.66"
async-trait = { workspace = true }
base64 = "0.21.2"
cfg-if = "1.0.0"
dashmap = "5.4.0"
dashmap = { workspace = true }
dirs = "4.0"
futures = { workspace = true }
humantime-serde = "1.0"
@@ -22,11 +22,11 @@ serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true }
sha2 = "0.10.6"
tap = "1.0.1"
thiserror = "1.0.34"
time = "0.3.17"
tokio = { version = "1.24.1", features = ["macros"]}
tungstenite = { version = "0.13.0", default-features = false }
thiserror = { workspace = true }
url = { workspace = true, features = ["serde"] }
tungstenite = { version = "0.13.0", default-features = false }
tokio = { workspace = true, features = ["macros"]}
time = "0.3.17"
zeroize = { workspace = true }
# internal
@@ -35,12 +35,11 @@ nym-config = { path = "../config" }
nym-crypto = { path = "../crypto" }
nym-explorer-client = { path = "../../explorer-api/explorer-client" }
nym-gateway-client = { path = "../client-libs/gateway-client" }
#gateway-client = { path = "../../common/client-libs/gateway-client", default-features = false, features = ["wasm", "coconut"] }
nym-gateway-requests = { path = "../../gateway/gateway-requests" }
nym-nonexhaustive-delayqueue = { path = "../nonexhaustive-delayqueue" }
nym-sphinx = { path = "../nymsphinx" }
nym-pemstore = { path = "../pemstore" }
nym-topology = { path = "../topology" }
nym-topology = { path = "../topology", features = ["serializable"] }
nym-validator-client = { path = "../client-libs/validator-client", default-features = false }
nym-task = { path = "../task" }
nym-credential-storage = { path = "../credential-storage" }
@@ -51,22 +50,22 @@ version = "0.1.11"
features = ["time"]
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.tokio]
version = "1.24.1"
workspace = true
features = ["time"]
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.tokio-tungstenite]
version = "0.14"
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.sqlx]
version = "0.6.2"
workspace = true
features = ["runtime-tokio-rustls", "sqlite", "macros", "migrate"]
optional = true
[target."cfg(target_arch = \"wasm32\")".dependencies.wasm-bindgen-futures]
version = "0.4"
workspace = true
[target."cfg(target_arch = \"wasm32\")".dependencies.wasm-bindgen]
version = "0.2.83"
workspace = true
[target."cfg(target_arch = \"wasm32\")".dependencies.wasmtimer]
workspace = true
@@ -77,7 +76,7 @@ version = "0.2.4"
features = ["futures"]
[target."cfg(target_arch = \"wasm32\")".dependencies.wasm-utils]
path = "../wasm-utils"
path = "../wasm/utils"
features = ["websocket"]
[target."cfg(target_arch = \"wasm32\")".dependencies.time]
@@ -88,8 +87,8 @@ features = ["wasm-bindgen"]
tempfile = "3.1.0"
[build-dependencies]
tokio = { version = "1.24.1", features = ["rt-multi-thread", "macros"] }
sqlx = { version = "0.6.2", features = ["runtime-tokio-rustls", "sqlite", "macros", "migrate"] }
tokio = { workspace = true, features = ["rt-multi-thread", "macros"] }
sqlx = { workspace = true, features = ["runtime-tokio-rustls", "sqlite", "macros", "migrate"] }
[features]
default = []
+179 -85
View File
@@ -8,6 +8,7 @@ use crate::client::base_client::storage::MixnetClientStorage;
use crate::client::cover_traffic_stream::LoopCoverTrafficStream;
use crate::client::inbound_messages::{InputMessage, InputMessageReceiver, InputMessageSender};
use crate::client::key_manager::persistence::KeyStore;
use crate::client::mix_traffic::transceiver::{GatewayReceiver, GatewayTransceiver, RemoteGateway};
use crate::client::mix_traffic::{BatchMixMessageSender, MixTrafficController};
use crate::client::real_messages_control;
use crate::client::real_messages_control::RealMessagesController;
@@ -25,16 +26,18 @@ use crate::client::topology_control::{
};
use crate::config::{Config, DebugConfig};
use crate::error::ClientCoreError;
use crate::init::{setup_gateway, GatewaySetup, InitialisationDetails, InitialisationResult};
use crate::init::{
setup_gateway,
types::{GatewayDetails, GatewaySetup, InitialisationResult},
};
use crate::{config, spawn_future};
use futures::channel::mpsc;
use log::{debug, info};
use log::{debug, error, info};
use nym_bandwidth_controller::BandwidthController;
use nym_credential_storage::storage::Storage as CredentialStorage;
use nym_crypto::asymmetric::{encryption, identity};
use nym_crypto::asymmetric::encryption;
use nym_gateway_client::{
AcknowledgementReceiver, AcknowledgementSender, GatewayClient, MixnetMessageReceiver,
MixnetMessageSender,
AcknowledgementReceiver, GatewayClient, MixnetMessageReceiver, PacketRouter,
};
use nym_sphinx::acknowledgements::AckKey;
use nym_sphinx::addressing::clients::Recipient;
@@ -42,9 +45,12 @@ use nym_sphinx::addressing::nodes::NodeIdentity;
use nym_sphinx::params::PacketType;
use nym_sphinx::receiver::{ReconstructedMessage, SphinxMessageReceiver};
use nym_task::connections::{ConnectionCommandReceiver, ConnectionCommandSender, LaneQueueLengths};
use nym_task::{TaskClient, TaskManager};
use nym_task::{TaskClient, TaskHandle};
use nym_topology::provider_trait::TopologyProvider;
use nym_topology::HardcodedTopologyProvider;
use nym_validator_client::nyxd::contract_traits::DkgQueryClient;
use std::fmt::Debug;
use std::path::Path;
use std::sync::Arc;
use url::Url;
@@ -155,7 +161,12 @@ pub struct BaseClientBuilder<'a, C, S: MixnetClientStorage> {
config: &'a Config,
client_store: S,
dkg_query_client: Option<C>,
wait_for_gateway: bool,
custom_topology_provider: Option<Box<dyn TopologyProvider + Send + Sync>>,
custom_gateway_transceiver: Option<Box<dyn GatewayTransceiver + Send>>,
shutdown: Option<TaskClient>,
setup_method: GatewaySetup,
}
@@ -173,16 +184,27 @@ where
config: base_config,
client_store,
dkg_query_client,
wait_for_gateway: false,
custom_topology_provider: None,
custom_gateway_transceiver: None,
shutdown: None,
setup_method: GatewaySetup::MustLoad,
}
}
#[must_use]
pub fn with_gateway_setup(mut self, setup: GatewaySetup) -> Self {
self.setup_method = setup;
self
}
#[must_use]
pub fn with_wait_for_gateway(mut self, wait_for_gateway: bool) -> Self {
self.wait_for_gateway = wait_for_gateway;
self
}
#[must_use]
pub fn with_topology_provider(
mut self,
provider: Box<dyn TopologyProvider + Send + Sync>,
@@ -191,15 +213,36 @@ where
self
}
#[must_use]
pub fn with_gateway_transceiver(mut self, sender: Box<dyn GatewayTransceiver + Send>) -> Self {
self.custom_gateway_transceiver = Some(sender);
self
}
#[must_use]
pub fn with_shutdown(mut self, shutdown: TaskClient) -> Self {
self.shutdown = Some(shutdown);
self
}
pub fn with_stored_topology<P: AsRef<Path>>(
mut self,
file: P,
) -> Result<Self, ClientCoreError> {
self.custom_topology_provider =
Some(Box::new(HardcodedTopologyProvider::new_from_file(file)?));
Ok(self)
}
// note: do **NOT** make this method public as its only valid usage is from within `start_base`
// because it relies on the crypto keys being already loaded
fn mix_address(details: &InitialisationDetails) -> Recipient {
fn mix_address(details: &InitialisationResult) -> Recipient {
Recipient::new(
*details.managed_keys.identity_public_key(),
*details.managed_keys.encryption_public_key(),
// TODO: below only works under assumption that gateway address == gateway id
// (which currently is true)
NodeIdentity::from_base58_string(&details.gateway_details.gateway_id).unwrap(),
NodeIdentity::from_base58_string(details.gateway_details.gateway_id()).unwrap(),
)
}
@@ -286,50 +329,37 @@ where
config: &Config,
initialisation_result: InitialisationResult,
bandwidth_controller: Option<BandwidthController<C, S::CredentialStore>>,
mixnet_message_sender: MixnetMessageSender,
ack_sender: AcknowledgementSender,
packet_router: PacketRouter,
shutdown: TaskClient,
) -> Result<GatewayClient<C, S::CredentialStore>, ClientCoreError>
where
<S::KeyStore as KeyStore>::StorageError: Send + Sync + 'static,
<S::CredentialStore as CredentialStorage>::StorageError: Send + Sync + 'static,
{
let managed_keys = initialisation_result.details.managed_keys;
let managed_keys = initialisation_result.managed_keys;
let GatewayDetails::Configured(gateway_config) = initialisation_result.gateway_details
else {
return Err(ClientCoreError::UnexpectedPersistedCustomGatewayDetails);
};
let mut gateway_client =
if let Some(existing_client) = initialisation_result.authenticated_ephemeral_client {
existing_client.upgrade(
mixnet_message_sender,
ack_sender,
config.debug.gateway_connection.gateway_response_timeout,
bandwidth_controller,
shutdown,
)
existing_client.upgrade(packet_router, bandwidth_controller, shutdown)
} else {
let gateway_config = initialisation_result.details.gateway_details;
let gateway_address = gateway_config.gateway_listener.clone();
let gateway_id = gateway_config.gateway_id;
// TODO: in theory, at this point, this should be infallible
let gateway_identity = identity::PublicKey::from_base58_string(gateway_id)
.map_err(ClientCoreError::UnableToCreatePublicKeyFromGatewayId)?;
let cfg = gateway_config.try_into()?;
GatewayClient::new(
gateway_address,
cfg,
managed_keys.identity_keypair(),
gateway_identity,
Some(managed_keys.must_get_gateway_shared_key()),
mixnet_message_sender,
ack_sender,
config.debug.gateway_connection.gateway_response_timeout,
packet_router,
bandwidth_controller,
shutdown,
)
.with_disabled_credentials_mode(config.client.disabled_credentials_mode)
.with_response_timeout(config.debug.gateway_connection.gateway_response_timeout)
};
let gateway_id = gateway_client.gateway_identity();
gateway_client.set_disabled_credentials_mode(config.client.disabled_credentials_mode);
let shared_key = gateway_client
.authenticate_and_start()
@@ -342,11 +372,48 @@ where
}
})?;
managed_keys.ensure_gateway_key(shared_key);
managed_keys.ensure_gateway_key(Some(shared_key));
Ok(gateway_client)
}
async fn setup_gateway_transceiver(
custom_gateway_transceiver: Option<Box<dyn GatewayTransceiver + Send>>,
config: &Config,
initialisation_result: InitialisationResult,
bandwidth_controller: Option<BandwidthController<C, S::CredentialStore>>,
packet_router: PacketRouter,
mut shutdown: TaskClient,
) -> Result<Box<dyn GatewayTransceiver + Send>, ClientCoreError>
where
<S::KeyStore as KeyStore>::StorageError: Send + Sync + 'static,
<S::CredentialStore as CredentialStorage>::StorageError: Send + Sync + 'static,
{
// if we have setup custom gateway sender and persisted details agree with it, return it
if let Some(mut custom_gateway_transceiver) = custom_gateway_transceiver {
return if !initialisation_result.gateway_details.is_custom() {
Err(ClientCoreError::CustomGatewaySelectionExpected)
} else {
// and make sure to invalidate the task client so we wouldn't cause premature shutdown
shutdown.mark_as_success();
custom_gateway_transceiver.set_packet_router(packet_router)?;
Ok(custom_gateway_transceiver)
};
}
// otherwise, setup normal gateway client, etc
let gateway_client = Self::start_gateway_client(
config,
initialisation_result,
bandwidth_controller,
packet_router,
shutdown,
)
.await?;
Ok(Box::new(RemoteGateway::new(gateway_client)))
}
fn setup_topology_provider(
custom_provider: Option<Box<dyn TopologyProvider + Send + Sync>>,
provider_from_config: config::TopologyStructure,
@@ -374,6 +441,8 @@ where
topology_provider: Box<dyn TopologyProvider + Send + Sync>,
topology_config: config::Topology,
topology_accessor: TopologyAccessor,
local_gateway: &NodeIdentity,
wait_for_gateway: bool,
mut shutdown: TaskClient,
) -> Result<(), ClientCoreError> {
let topology_refresher_config =
@@ -397,6 +466,32 @@ where
return Err(ClientCoreError::InsufficientNetworkTopology(err));
}
let gateway_wait_timeout = if wait_for_gateway {
Some(topology_config.max_startup_gateway_waiting_period)
} else {
None
};
if let Err(err) = topology_refresher
.ensure_contains_gateway(local_gateway)
.await
{
if let Some(waiting_timeout) = gateway_wait_timeout {
if let Err(err) = topology_refresher
.wait_for_gateway(local_gateway, waiting_timeout)
.await
{
error!(
"the gateway did not come back online within the specified timeout: {err}"
);
return Err(err.into());
}
} else {
error!("the gateway we're supposedly connected to does not exist. We'll not be able to send any packets to ourselves: {err}");
return Err(err.into());
}
}
if topology_config.disable_refreshing {
// if we're not spawning the refresher, don't cause shutdown immediately
info!("The topology refesher is not going to be started");
@@ -411,19 +506,12 @@ where
Ok(())
}
// controller for sending packets to mixnet (either real traffic or cover traffic)
// TODO: if we want to send control messages to gateway_client, this CAN'T take the ownership
// over it. Perhaps GatewayClient needs to be thread-shareable or have some channel for
// requests?
fn start_mix_traffic_controller(
gateway_client: GatewayClient<C, S::CredentialStore>,
gateway_transceiver: Box<dyn GatewayTransceiver + Send>,
shutdown: TaskClient,
) -> BatchMixMessageSender
where
<S::CredentialStore as CredentialStorage>::StorageError: Send + Sync + 'static,
{
) -> BatchMixMessageSender {
info!("Starting mix traffic controller...");
let (mix_traffic_controller, mix_tx) = MixTrafficController::new(gateway_client);
let (mix_traffic_controller, mix_tx) = MixTrafficController::new(gateway_transceiver);
mix_traffic_controller.start_with_shutdown(shutdown);
mix_tx
}
@@ -460,21 +548,12 @@ where
setup_method: GatewaySetup,
key_store: &S::KeyStore,
details_store: &S::GatewayDetailsStore,
overwrite_data: bool,
validator_servers: Option<&[Url]>,
) -> Result<InitialisationResult, ClientCoreError>
where
<S::KeyStore as KeyStore>::StorageError: Sync + Send,
<S::GatewayDetailsStore as GatewayDetailsStore>::StorageError: Sync + Send,
{
setup_gateway(
setup_method,
key_store,
details_store,
overwrite_data,
validator_servers,
)
.await
setup_gateway(setup_method, key_store, details_store).await
}
pub async fn start_base(mut self) -> Result<BaseClient, ClientCoreError>
@@ -492,17 +571,11 @@ where
self.setup_method,
self.client_store.key_store(),
self.client_store.gateway_details_store(),
false,
Some(&self.config.client.nym_api_urls),
)
.await?;
let (reply_storage_backend, credential_store) = self.client_store.into_runtime_stores();
let bandwidth_controller = self
.dkg_query_client
.map(|client| BandwidthController::new(credential_store, client));
// channels for inter-component communication
// TODO: make the channels be internally created by the relevant components
// rather than creating them here, so say for example the buffer controller would create the request channels
@@ -523,31 +596,25 @@ where
let shared_topology_accessor = TopologyAccessor::new();
// Shutdown notifier for signalling tasks to stop
let task_manager = TaskManager::default();
let shutdown = self
.shutdown
.map(Into::<TaskHandle>::into)
.unwrap_or_default()
.name_if_unnamed("BaseNymClient");
// channels responsible for dealing with reply-related fun
let (reply_controller_sender, reply_controller_receiver) =
reply_controller::requests::new_control_channels();
let self_address = Self::mix_address(&init_res.details);
let ack_key = init_res.details.managed_keys.ack_key();
let encryption_keys = init_res.details.managed_keys.encryption_keypair();
let self_address = Self::mix_address(&init_res);
let ack_key = init_res.managed_keys.ack_key();
let encryption_keys = init_res.managed_keys.encryption_keypair();
// the components are started in very specific order. Unless you know what you are doing,
// do not change that.
let gateway_client = Self::start_gateway_client(
self.config,
init_res,
bandwidth_controller,
mixnet_messages_sender,
ack_sender,
task_manager.subscribe(),
)
.await?;
let reply_storage =
Self::setup_persistent_reply_storage(reply_storage_backend, task_manager.subscribe())
.await?;
let bandwidth_controller = self
.dkg_query_client
.map(|client| BandwidthController::new(credential_store, client));
let topology_provider = Self::setup_topology_provider(
self.custom_topology_provider.take(),
@@ -555,11 +622,36 @@ where
self.config.get_nym_api_endpoints(),
);
// needs to be started as the first thing to block if required waiting for the gateway
Self::start_topology_refresher(
topology_provider,
self.config.debug.topology,
shared_topology_accessor.clone(),
task_manager.subscribe(),
self_address.gateway(),
self.wait_for_gateway,
shutdown.fork("topology_refresher"),
)
.await?;
let gateway_packet_router = PacketRouter::new(
ack_sender,
mixnet_messages_sender,
shutdown.get_handle().named("gateway-packet-router"),
);
let gateway_transceiver = Self::setup_gateway_transceiver(
self.custom_gateway_transceiver,
self.config,
init_res,
bandwidth_controller,
gateway_packet_router,
shutdown.fork("gateway_transceiver"),
)
.await?;
let reply_storage = Self::setup_persistent_reply_storage(
reply_storage_backend,
shutdown.fork("persistent_reply_storage"),
)
.await?;
@@ -569,15 +661,17 @@ where
mixnet_messages_receiver,
reply_storage.key_storage(),
reply_controller_sender.clone(),
task_manager.subscribe(),
shutdown.fork("received_messages_buffer"),
);
// The message_sender is the transmitter for any component generating sphinx packets
// that are to be sent to the mixnet. They are used by cover traffic stream and real
// traffic stream.
// The MixTrafficController then sends the actual traffic
let message_sender =
Self::start_mix_traffic_controller(gateway_client, task_manager.subscribe());
let message_sender = Self::start_mix_traffic_controller(
gateway_transceiver,
shutdown.fork("mix_traffic_controller"),
);
// Channels that the websocket listener can use to signal downstream to the real traffic
// controller that connections are closed.
@@ -604,7 +698,7 @@ where
reply_controller_receiver,
shared_lane_queue_lengths.clone(),
client_connection_rx,
task_manager.subscribe(),
shutdown.fork("real_traffic_controller"),
self.config.debug.traffic.packet_type,
);
@@ -620,7 +714,7 @@ where
self_address,
shared_topology_accessor.clone(),
message_sender,
task_manager.subscribe(),
shutdown.fork("cover_traffic_stream"),
);
}
@@ -645,7 +739,7 @@ where
reply_controller_sender,
topology_accessor: shared_topology_accessor,
},
task_manager,
task_handle: shutdown,
})
}
}
@@ -656,5 +750,5 @@ pub struct BaseClient {
pub client_output: ClientOutputStatus,
pub client_state: ClientState,
pub task_manager: TaskManager,
pub task_handle: TaskHandle,
}
@@ -2,8 +2,12 @@
// SPDX-License-Identifier: Apache-2.0
use crate::config::GatewayEndpointConfig;
use crate::error::ClientCoreError;
use crate::init::types::{EmptyCustomDetails, GatewayDetails};
use async_trait::async_trait;
use log::error;
use nym_gateway_requests::registration::handshake::SharedKeys;
use serde::de::DeserializeOwned;
use serde::{Deserialize, Serialize};
use sha2::{Digest, Sha256};
use std::error::Error;
@@ -13,19 +17,61 @@ use zeroize::Zeroizing;
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
pub trait GatewayDetailsStore {
pub trait GatewayDetailsStore<T = EmptyCustomDetails> {
type StorageError: Error;
async fn load_gateway_details(&self) -> Result<PersistedGatewayDetails, Self::StorageError>;
async fn load_gateway_details(&self) -> Result<PersistedGatewayDetails<T>, Self::StorageError>
where
T: DeserializeOwned + Send + Sync;
async fn store_gateway_details(
&self,
details: &PersistedGatewayDetails,
) -> Result<(), Self::StorageError>;
details: &PersistedGatewayDetails<T>,
) -> Result<(), Self::StorageError>
where
T: Serialize + Send + Sync;
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PersistedGatewayDetails {
#[serde(untagged)]
pub enum PersistedGatewayDetails<T = EmptyCustomDetails> {
/// Standard details of a remote gateway
Default(PersistedGatewayConfig),
/// Custom gateway setup, such as for a client embedded inside gateway itself
Custom(PersistedCustomGatewayDetails<T>),
}
impl<T> PersistedGatewayDetails<T> {
// TODO: this should probably allow for custom verification over T
pub fn validate(&self, shared_key: Option<&SharedKeys>) -> Result<(), ClientCoreError> {
match self {
PersistedGatewayDetails::Default(details) => {
if !details.verify(
shared_key
.ok_or(ClientCoreError::UnavailableSharedKey)?
.deref(),
) {
Err(ClientCoreError::MismatchedGatewayDetails {
gateway_id: details.details.gateway_id.clone(),
})
} else {
Ok(())
}
}
PersistedGatewayDetails::Custom(_) => {
if shared_key.is_some() {
error!("using custom persisted gateway setup with shared key present - are you sure that's what you want?");
// but technically we could still continue. just ignore the key
}
Ok(())
}
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct PersistedGatewayConfig {
// TODO: should we also verify correctness of the details themselves?
// i.e. we could include a checksum or tag (via the shared keys)
// counterargument: if we wanted to modify, say, the host information in the stored file on disk,
@@ -38,13 +84,16 @@ pub struct PersistedGatewayDetails {
pub(crate) details: GatewayEndpointConfig,
}
impl From<PersistedGatewayDetails> for GatewayEndpointConfig {
fn from(value: PersistedGatewayDetails) -> Self {
value.details
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PersistedCustomGatewayDetails<T> {
// whatever custom method is used, gateway's identity must be known
pub gateway_id: String,
#[serde(flatten)]
pub additional_data: T,
}
impl PersistedGatewayDetails {
impl PersistedGatewayConfig {
pub fn new(details: GatewayEndpointConfig, shared_key: &SharedKeys) -> Self {
let key_bytes = Zeroizing::new(shared_key.to_bytes());
@@ -52,7 +101,7 @@ impl PersistedGatewayDetails {
key_hasher.update(&key_bytes);
let key_hash = key_hasher.finalize().to_vec();
PersistedGatewayDetails { key_hash, details }
PersistedGatewayConfig { key_hash, details }
}
pub fn verify(&self, shared_key: &SharedKeys) -> bool {
@@ -66,6 +115,50 @@ impl PersistedGatewayDetails {
}
}
impl<T> PersistedGatewayDetails<T> {
pub fn new(
details: GatewayDetails<T>,
shared_key: Option<&SharedKeys>,
) -> Result<Self, ClientCoreError> {
match details {
GatewayDetails::Configured(cfg) => {
let shared_key = shared_key.ok_or(ClientCoreError::UnavailableSharedKey)?;
Ok(PersistedGatewayDetails::Default(
PersistedGatewayConfig::new(cfg, shared_key),
))
}
GatewayDetails::Custom(custom) => Ok(PersistedGatewayDetails::Custom(custom.into())),
}
}
pub fn is_custom(&self) -> bool {
matches!(self, PersistedGatewayDetails::Custom(..))
}
pub fn matches(&self, other: &GatewayDetails<T>) -> bool
where
T: PartialEq,
{
match self {
PersistedGatewayDetails::Default(default) => {
if let GatewayDetails::Configured(other_configured) = other {
&default.details == other_configured
} else {
false
}
}
PersistedGatewayDetails::Custom(custom) => {
if let GatewayDetails::Custom(other_custom) = other {
custom.gateway_id == other_custom.gateway_id
&& custom.additional_data == other_custom.additional_data
} else {
false
}
}
}
}
}
// helper to make Vec<u8> serialization use base64 representation to make it human readable
// so that it would be easier for users to copy contents from the disk if they wanted to use it elsewhere
mod base64 {
@@ -116,7 +209,10 @@ impl OnDiskGatewayDetails {
}
}
pub fn load_from_disk(&self) -> Result<PersistedGatewayDetails, OnDiskGatewayDetailsError> {
pub fn load_from_disk<T>(&self) -> Result<PersistedGatewayDetails<T>, OnDiskGatewayDetailsError>
where
T: DeserializeOwned,
{
let file = std::fs::File::open(&self.file_location).map_err(|err| {
OnDiskGatewayDetailsError::LoadFailure {
path: self.file_location.display().to_string(),
@@ -127,10 +223,13 @@ impl OnDiskGatewayDetails {
Ok(serde_json::from_reader(file)?)
}
pub fn store_to_disk(
pub fn store_to_disk<T>(
&self,
details: &PersistedGatewayDetails,
) -> Result<(), OnDiskGatewayDetailsError> {
details: &PersistedGatewayDetails<T>,
) -> Result<(), OnDiskGatewayDetailsError>
where
T: Serialize,
{
// ensure the whole directory structure exists
if let Some(parent_dir) = &self.file_location.parent() {
std::fs::create_dir_all(parent_dir).map_err(|err| {
@@ -170,8 +269,8 @@ impl GatewayDetailsStore for OnDiskGatewayDetails {
}
#[derive(Default)]
pub struct InMemGatewayDetails {
details: Mutex<Option<PersistedGatewayDetails>>,
pub struct InMemGatewayDetails<T = EmptyCustomDetails> {
details: Mutex<Option<PersistedGatewayDetails<T>>>,
}
#[derive(Debug, thiserror::Error)]
@@ -38,9 +38,6 @@ pub trait MixnetClientStorage {
type CredentialStore: CredentialStorage;
type GatewayDetailsStore: GatewayDetailsStore;
// this is a TERRIBLE name...
// fn into_split(self) -> (Self::KeyStore, Self::ReplyStore, Self::CredentialStore, Self::GatewayDetailsStore);
fn into_runtime_stores(self) -> (Self::ReplyStore, Self::CredentialStore);
fn key_store(&self) -> &Self::KeyStore;
@@ -103,7 +103,7 @@ impl ManagedKeys {
pub fn gateway_shared_key(&self) -> Option<Arc<SharedKeys>> {
match self {
ManagedKeys::Initial(_) => None,
ManagedKeys::FullyDerived(keys) => Some(keys.gateway_shared_key()),
ManagedKeys::FullyDerived(keys) => keys.gateway_shared_key(),
ManagedKeys::Invalidated => unreachable!("the managed keys got invalidated"),
}
}
@@ -124,10 +124,26 @@ impl ManagedKeys {
}
}
pub fn ensure_gateway_key(&self, gateway_shared_key: Arc<SharedKeys>) {
pub fn ensure_gateway_key(&self, gateway_shared_key: Option<Arc<SharedKeys>>) {
if let ManagedKeys::FullyDerived(key_manager) = &self {
if !Arc::ptr_eq(&key_manager.gateway_shared_key, &gateway_shared_key)
|| key_manager.gateway_shared_key != gateway_shared_key
if self.gateway_shared_key().is_none() && gateway_shared_key.is_none() {
// the key doesn't exist in either state
return;
}
if gateway_shared_key.is_some() && self.gateway_shared_key().is_none()
|| gateway_shared_key.is_none() && self.gateway_shared_key().is_some()
{
// if one is provided whilst the other is not...
// TODO: should this actually panic or return an error? would this branch be possible
// under normal operation?
panic!("inconsistent re-derived gateway key")
}
// here we know both keys MUST exist
let provided = gateway_shared_key.unwrap();
if !Arc::ptr_eq(key_manager.must_get_gateway_shared_key(), &provided)
|| *key_manager.must_get_gateway_shared_key() != provided
{
// this should NEVER happen thus panic here
panic!("derived fresh gateway shared key whilst already holding one!")
@@ -137,12 +153,12 @@ impl ManagedKeys {
pub async fn deal_with_gateway_key<S: KeyStore>(
&mut self,
gateway_shared_key: Arc<SharedKeys>,
gateway_shared_key: Option<Arc<SharedKeys>>,
key_store: &S,
) -> Result<(), S::StorageError> {
let key_manager = match std::mem::replace(self, ManagedKeys::Invalidated) {
ManagedKeys::Initial(keys) => {
let key_manager = keys.insert_gateway_shared_key(gateway_shared_key);
let key_manager = keys.insert_maybe_gateway_shared_key(gateway_shared_key);
key_manager.persist_keys(key_store).await?;
key_manager
}
@@ -184,7 +200,10 @@ impl KeyManagerBuilder {
}
}
pub fn insert_gateway_shared_key(self, gateway_shared_key: Arc<SharedKeys>) -> KeyManager {
pub fn insert_maybe_gateway_shared_key(
self,
gateway_shared_key: Option<Arc<SharedKeys>>,
) -> KeyManager {
KeyManager {
identity_keypair: self.identity_keypair,
encryption_keypair: self.encryption_keypair,
@@ -222,7 +241,11 @@ pub struct KeyManager {
encryption_keypair: Arc<encryption::KeyPair>,
/// shared key derived with the gateway during "registration handshake"
gateway_shared_key: Arc<SharedKeys>,
// I'm not a fan of how we broke the nice transition of `KeyManagerBuilder` -> `KeyManager`
// by making this field optional.
// However, it has to be optional for when we use embedded NR inside a gateway,
// since it won't have a shared key (because why would it?)
gateway_shared_key: Option<Arc<SharedKeys>>,
/// key used for producing and processing acknowledgement packets.
ack_key: Arc<AckKey>,
@@ -232,13 +255,13 @@ impl KeyManager {
pub fn from_keys(
id_keypair: identity::KeyPair,
enc_keypair: encryption::KeyPair,
gateway_shared_key: SharedKeys,
gateway_shared_key: Option<SharedKeys>,
ack_key: AckKey,
) -> Self {
Self {
identity_keypair: Arc::new(id_keypair),
encryption_keypair: Arc::new(enc_keypair),
gateway_shared_key: Arc::new(gateway_shared_key),
gateway_shared_key: gateway_shared_key.map(Arc::new),
ack_key: Arc::new(ack_key),
}
}
@@ -265,13 +288,23 @@ impl KeyManager {
Arc::clone(&self.ack_key)
}
fn must_get_gateway_shared_key(&self) -> &Arc<SharedKeys> {
self.gateway_shared_key
.as_ref()
.expect("gateway shared key is unavailable")
}
pub fn uses_custom_gateway(&self) -> bool {
self.gateway_shared_key.is_none()
}
/// Gets an atomically reference counted pointer to [`SharedKey`].
pub fn gateway_shared_key(&self) -> Arc<SharedKeys> {
Arc::clone(&self.gateway_shared_key)
pub fn gateway_shared_key(&self) -> Option<Arc<SharedKeys>> {
self.gateway_shared_key.as_ref().map(Arc::clone)
}
pub fn remove_gateway_key(self) -> KeyManagerBuilder {
if Arc::strong_count(&self.gateway_shared_key) > 1 {
if Arc::strong_count(self.must_get_gateway_shared_key()) > 1 {
panic!("attempted to remove gateway key whilst still holding multiple references!")
}
KeyManagerBuilder {
@@ -88,20 +88,20 @@ impl OnDiskKeys {
pub fn ephemeral_load_gateway_keys(
&self,
) -> Result<zeroize::Zeroizing<SharedKeys>, OnDiskKeysError> {
self.load_key(self.paths.gateway_shared_key(), "gateway shared keys")
self.load_key(self.paths.gateway_shared_key(), "gateway shared")
.map(zeroize::Zeroizing::new)
}
#[doc(hidden)]
pub fn load_encryption_keypair(&self) -> Result<encryption::KeyPair, OnDiskKeysError> {
let encryption_paths = self.paths.encryption_key_pair_path();
self.load_keypair(encryption_paths, "encryption keys")
self.load_keypair(encryption_paths, "encryption")
}
#[doc(hidden)]
pub fn load_identity_keypair(&self) -> Result<identity::KeyPair, OnDiskKeysError> {
let identity_paths = self.paths.identity_key_pair_path();
self.load_keypair(identity_paths, "identity keys")
self.load_keypair(identity_paths, "identity")
}
fn load_key<T: PemStorableKey>(
@@ -161,8 +161,9 @@ impl OnDiskKeys {
let encryption_keypair = self.load_encryption_keypair()?;
let ack_key: AckKey = self.load_key(self.paths.ack_key(), "ack key")?;
let gateway_shared_key: SharedKeys =
self.load_key(self.paths.gateway_shared_key(), "gateway shared keys")?;
let gateway_shared_key: Option<SharedKeys> = self
.load_key(self.paths.gateway_shared_key(), "gateway shared keys")
.ok();
Ok(KeyManager::from_keys(
identity_keypair,
@@ -173,6 +174,8 @@ impl OnDiskKeys {
}
fn store_keys(&self, keys: &KeyManager) -> Result<(), OnDiskKeysError> {
use std::ops::Deref;
let identity_paths = self.paths.identity_key_pair_path();
let encryption_paths = self.paths.encryption_key_pair_path();
@@ -188,11 +191,14 @@ impl OnDiskKeys {
)?;
self.store_key(keys.ack_key.as_ref(), self.paths.ack_key(), "ack key")?;
self.store_key(
keys.gateway_shared_key.as_ref(),
self.paths.gateway_shared_key(),
"gateway shared keys",
)?;
if let Some(shared_keys) = &keys.gateway_shared_key {
self.store_key(
shared_keys.deref(),
self.paths.gateway_shared_key(),
"gateway shared keys",
)?;
}
Ok(())
}
@@ -1,24 +1,26 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::client::mix_traffic::transceiver::GatewayTransceiver;
use crate::spawn_future;
use log::*;
use nym_credential_storage::storage::Storage;
use nym_gateway_client::GatewayClient;
use nym_sphinx::forwarding::packet::MixPacket;
use nym_validator_client::nyxd::contract_traits::DkgQueryClient;
pub type BatchMixMessageSender = tokio::sync::mpsc::Sender<Vec<MixPacket>>;
pub type BatchMixMessageReceiver = tokio::sync::mpsc::Receiver<Vec<MixPacket>>;
pub mod transceiver;
// We remind ourselves that 32 x 32kb = 1024kb, a reasonable size for a network buffer.
pub const MIX_MESSAGE_RECEIVER_BUFFER_SIZE: usize = 32;
const MAX_FAILURE_COUNT: usize = 100;
pub struct MixTrafficController<C, St: Storage> {
// TODO: most likely to be replaced by some higher level construct as
// later on gateway_client will need to be accessible by other entities
gateway_client: GatewayClient<C, St>,
// that's also disgusting.
pub struct Empty;
pub struct MixTrafficController {
gateway_transceiver: Box<dyn GatewayTransceiver + Send>,
mix_rx: BatchMixMessageReceiver,
// TODO: this is temporary work-around.
@@ -26,20 +28,31 @@ pub struct MixTrafficController<C, St: Storage> {
consecutive_gateway_failure_count: usize,
}
impl<C, St> MixTrafficController<C, St>
where
C: DkgQueryClient + Sync + Send + 'static,
St: Storage + 'static,
<St as Storage>::StorageError: Send + Sync + 'static,
{
pub fn new(
gateway_client: GatewayClient<C, St>,
) -> (MixTrafficController<C, St>, BatchMixMessageSender) {
impl MixTrafficController {
pub fn new<T>(gateway_transceiver: T) -> (MixTrafficController, BatchMixMessageSender)
where
T: GatewayTransceiver + Send + 'static,
{
let (message_sender, message_receiver) =
tokio::sync::mpsc::channel(MIX_MESSAGE_RECEIVER_BUFFER_SIZE);
(
MixTrafficController {
gateway_client,
gateway_transceiver: Box::new(gateway_transceiver),
mix_rx: message_receiver,
consecutive_gateway_failure_count: 0,
},
message_sender,
)
}
pub fn new_dynamic(
gateway_transceiver: Box<dyn GatewayTransceiver + Send>,
) -> (MixTrafficController, BatchMixMessageSender) {
let (message_sender, message_receiver) =
tokio::sync::mpsc::channel(MIX_MESSAGE_RECEIVER_BUFFER_SIZE);
(
MixTrafficController {
gateway_transceiver,
mix_rx: message_receiver,
consecutive_gateway_failure_count: 0,
},
@@ -52,16 +65,16 @@ where
let result = if mix_packets.len() == 1 {
let mix_packet = mix_packets.pop().unwrap();
self.gateway_client.send_mix_packet(mix_packet).await
self.gateway_transceiver.send_mix_packet(mix_packet).await
} else {
self.gateway_client
self.gateway_transceiver
.batch_send_mix_packets(mix_packets)
.await
};
match result {
Err(err) => {
error!("Failed to send sphinx packet(s) to the gateway! - {err}");
error!("Failed to send sphinx packet(s) to the gateway: {err}");
self.consecutive_gateway_failure_count += 1;
if self.consecutive_gateway_failure_count == MAX_FAILURE_COUNT {
// todo: in the future this should initiate a 'graceful' shutdown or try
@@ -0,0 +1,262 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use async_trait::async_trait;
use log::{debug, error};
use nym_crypto::asymmetric::identity;
use nym_gateway_client::GatewayClient;
pub use nym_gateway_client::{GatewayPacketRouter, PacketRouter};
use nym_sphinx::forwarding::packet::MixPacket;
use std::fmt::Debug;
use thiserror::Error;
#[cfg(not(target_arch = "wasm32"))]
use futures::channel::{mpsc, oneshot};
// we need to type erase the error type since we can't have dynamic associated types alongside dynamic dispatch
#[derive(Debug, Error)]
#[error(transparent)]
pub struct ErasedGatewayError(Box<dyn std::error::Error + Send + Sync>);
fn erase_err<E: std::error::Error + Send + Sync + 'static>(err: E) -> ErasedGatewayError {
ErasedGatewayError(Box::new(err))
}
/// This combines combines the functionalities of being able to send and receive mix packets.
pub trait GatewayTransceiver: GatewaySender + GatewayReceiver {
fn gateway_identity(&self) -> identity::PublicKey;
}
/// This trait defines the functionality of sending `MixPacket` into the mixnet,
/// usually through a gateway.
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
pub trait GatewaySender {
async fn send_mix_packet(&mut self, packet: MixPacket) -> Result<(), ErasedGatewayError>;
async fn batch_send_mix_packets(
&mut self,
packets: Vec<MixPacket>,
) -> Result<(), ErasedGatewayError> {
// allow for optimisation when sending multiple packets
for packet in packets {
self.send_mix_packet(packet).await?;
}
Ok(())
}
}
/// this trait defines the functionality of being able to correctly route
/// packets received from the mixnet, i.e. acks and 'proper' messages.
pub trait GatewayReceiver {
// ughhhh I really dislike this method, but couldn't come up wih anything better
// ideally this would have been an associated type, but heh. we can't.
fn set_packet_router(
&mut self,
_packet_router: PacketRouter,
) -> Result<(), ErasedGatewayError> {
debug!("no-op packet router setup");
Ok(())
}
}
// to allow for dynamic dispatch
impl<G: GatewayTransceiver + ?Sized + Send> GatewayTransceiver for Box<G> {
#[inline]
fn gateway_identity(&self) -> identity::PublicKey {
(**self).gateway_identity()
}
}
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
impl<G: GatewaySender + ?Sized + Send> GatewaySender for Box<G> {
#[inline]
async fn send_mix_packet(&mut self, packet: MixPacket) -> Result<(), ErasedGatewayError> {
(**self).send_mix_packet(packet).await
}
#[inline]
async fn batch_send_mix_packets(
&mut self,
packets: Vec<MixPacket>,
) -> Result<(), ErasedGatewayError> {
(**self).batch_send_mix_packets(packets).await
}
}
impl<G: GatewayReceiver + ?Sized> GatewayReceiver for Box<G> {
#[inline]
fn set_packet_router(&mut self, packet_router: PacketRouter) -> Result<(), ErasedGatewayError> {
(**self).set_packet_router(packet_router)
}
}
/// Gateway to which the client is connected through a socket.
/// Most likely through a websocket.
pub struct RemoteGateway<C, St> {
gateway_client: GatewayClient<C, St>,
}
impl<C, St> RemoteGateway<C, St> {
pub fn new(gateway_client: GatewayClient<C, St>) -> Self {
Self { gateway_client }
}
}
impl<C, St> GatewayTransceiver for RemoteGateway<C, St>
where
C: Send,
St: Send,
{
fn gateway_identity(&self) -> identity::PublicKey {
self.gateway_client.gateway_identity()
}
}
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
impl<C, St> GatewaySender for RemoteGateway<C, St>
where
C: Send,
St: Send,
{
async fn send_mix_packet(&mut self, packet: MixPacket) -> Result<(), ErasedGatewayError> {
self.gateway_client
.send_mix_packet(packet)
.await
.map_err(erase_err)
}
async fn batch_send_mix_packets(
&mut self,
packets: Vec<MixPacket>,
) -> Result<(), ErasedGatewayError> {
self.gateway_client
.batch_send_mix_packets(packets)
.await
.map_err(erase_err)
}
}
impl<C, St> GatewayReceiver for RemoteGateway<C, St> {}
#[derive(Debug, Error)]
pub enum LocalGatewayError {
#[error("attempted to set the packet router for the second time")]
PacketRouterAlreadySet,
#[error("failed to setup packet router - has the receiver been dropped?")]
FailedPacketRouterSetup,
}
/// Gateway running within the same process.
#[cfg(not(target_arch = "wasm32"))]
pub struct LocalGateway {
/// Identity of the locally managed gateway
local_identity: identity::PublicKey,
// 'sender' part
/// Channel responsible for taking mix packets and forwarding them further into the further mixnet layers.
packet_forwarder: mpsc::UnboundedSender<MixPacket>,
// 'receiver' part
packet_router_tx: Option<oneshot::Sender<PacketRouter>>,
}
#[cfg(not(target_arch = "wasm32"))]
impl LocalGateway {
pub fn new(
local_identity: identity::PublicKey,
packet_forwarder: mpsc::UnboundedSender<MixPacket>,
packet_router_tx: oneshot::Sender<PacketRouter>,
) -> Self {
LocalGateway {
local_identity,
packet_forwarder,
packet_router_tx: Some(packet_router_tx),
}
}
}
#[cfg(not(target_arch = "wasm32"))]
mod nonwasm_sealed {
use super::*;
impl GatewayTransceiver for LocalGateway {
fn gateway_identity(&self) -> identity::PublicKey {
self.local_identity
}
}
#[async_trait]
impl GatewaySender for LocalGateway {
async fn send_mix_packet(&mut self, packet: MixPacket) -> Result<(), ErasedGatewayError> {
self.packet_forwarder
.unbounded_send(packet)
.map_err(|err| err.into_send_error())
.map_err(erase_err)
}
}
impl GatewayReceiver for LocalGateway {
fn set_packet_router(
&mut self,
packet_router: PacketRouter,
) -> Result<(), ErasedGatewayError> {
let Some(packet_routex_tx) = self.packet_router_tx.take() else {
return Err(erase_err(LocalGatewayError::PacketRouterAlreadySet));
};
packet_routex_tx
.send(packet_router)
.map_err(|_| erase_err(LocalGatewayError::FailedPacketRouterSetup))
}
}
}
// if we ever decided to start writing unit tests... : )
pub struct MockGateway {
dummy_identity: identity::PublicKey,
packet_router: Option<PacketRouter>,
sent: Vec<MixPacket>,
}
impl Default for MockGateway {
fn default() -> Self {
MockGateway {
dummy_identity: "3ebjp1Fb9hdcS1AR6AZihgeJiMHkB5jjJUsvqNnfQwU7"
.parse()
.unwrap(),
packet_router: None,
sent: vec![],
}
}
}
#[derive(Debug, Error)]
#[error("mock gateway error")]
pub struct MockGatewayError;
impl GatewayReceiver for MockGateway {
// TODO: that's frustrating. can't do anything about the behaviour here since all the routing is in the `PacketRouter`...
fn set_packet_router(&mut self, packet_router: PacketRouter) -> Result<(), ErasedGatewayError> {
self.packet_router = Some(packet_router);
Ok(())
}
}
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
impl GatewaySender for MockGateway {
async fn send_mix_packet(&mut self, packet: MixPacket) -> Result<(), ErasedGatewayError> {
self.sent.push(packet);
Ok(())
}
}
impl GatewayTransceiver for MockGateway {
fn gateway_identity(&self) -> identity::PublicKey {
self.dummy_identity
}
}
@@ -71,7 +71,7 @@ impl AcknowledgementListener {
while !shutdown.is_shutdown() {
tokio::select! {
acks = self.ack_receiver.next() => match acks {
Some(acks) => {self.handle_ack_receiver_item(acks).await}
Some(acks) => self.handle_ack_receiver_item(acks).await,
None => {
log::trace!("AcknowledgementListener: Stopping since channel closed");
break;
@@ -260,7 +260,7 @@ where
let mut sent_notification_listener = self.sent_notification_listener;
let mut action_controller = self.action_controller;
let shutdown_handle = shutdown.clone();
let shutdown_handle = shutdown.fork("acknowledgement_listener");
spawn_future(async move {
acknowledgement_listener
.run_with_shutdown(shutdown_handle)
@@ -268,7 +268,7 @@ where
debug!("The acknowledgement listener has finished execution!");
});
let shutdown_handle = shutdown.clone();
let shutdown_handle = shutdown.fork("input_message_listener");
spawn_future(async move {
input_message_listener
.run_with_shutdown(shutdown_handle)
@@ -276,7 +276,7 @@ where
debug!("The input listener has finished execution!");
});
let shutdown_handle = shutdown.clone();
let shutdown_handle = shutdown.fork("retransmission_request_listener");
spawn_future(async move {
retransmission_request_listener
.run_with_shutdown(shutdown_handle, packet_type)
@@ -284,7 +284,7 @@ where
debug!("The retransmission request listener has finished execution!");
});
let shutdown_handle = shutdown.clone();
let shutdown_handle = shutdown.fork("sent_notification_listener");
spawn_future(async move {
sent_notification_listener
.run_with_shutdown(shutdown_handle)
@@ -293,7 +293,9 @@ where
});
spawn_future(async move {
action_controller.run_with_shutdown(shutdown).await;
action_controller
.run_with_shutdown(shutdown.with_suffix("action_controller"))
.await;
debug!("The controller has finished execution!");
});
}
@@ -213,17 +213,17 @@ impl RealMessagesController<OsRng> {
let ack_control = self.ack_control;
let mut reply_control = self.reply_control;
let shutdown_handle = shutdown.clone();
let shutdown_handle = shutdown.fork("out_queue_control");
spawn_future(async move {
out_queue_control.run_with_shutdown(shutdown_handle).await;
debug!("The out queue controller has finished execution!");
});
let shutdown_handle = shutdown.clone();
let shutdown_handle = shutdown.fork("reply_control");
spawn_future(async move {
reply_control.run_with_shutdown(shutdown_handle).await;
debug!("The reply controller has finished execution!");
});
ack_control.start_with_shutdown(shutdown, packet_type);
ack_control.start_with_shutdown(shutdown.with_suffix("ack_control"), packet_type);
}
}
@@ -500,7 +500,7 @@ impl<R: MessageReceiver + Clone + Send + 'static> ReceivedMessagesBufferControll
let mut fragmented_message_receiver = self.fragmented_message_receiver;
let mut request_receiver = self.request_receiver;
let shutdown_handle = shutdown.clone();
let shutdown_handle = shutdown.fork("fragmented_message_receiver");
spawn_future(async move {
match fragmented_message_receiver
.run_with_shutdown(shutdown_handle)
@@ -511,7 +511,9 @@ impl<R: MessageReceiver + Clone + Send + 'static> ReceivedMessagesBufferControll
}
});
spawn_future(async move {
request_receiver.run_with_shutdown(shutdown).await;
request_receiver
.run_with_shutdown(shutdown.with_suffix("request_receiver"))
.await;
});
}
}
@@ -30,11 +30,11 @@ impl StorageManager {
})?;
}
let mut opts = sqlx::sqlite::SqliteConnectOptions::new()
let opts = sqlx::sqlite::SqliteConnectOptions::new()
.filename(database_path)
.create_if_missing(fresh);
opts.disable_statement_logging();
let opts = opts.disable_statement_logging();
let connection_pool = match sqlx::SqlitePool::connect_with(opts).await {
Ok(pool) => pool,
@@ -6,7 +6,7 @@ use async_trait::async_trait;
use std::error::Error;
use thiserror::Error;
#[cfg(target_arch = "wasm32")]
// TODO: this should now live inside our wasm/client-core
pub mod browser_backend;
#[cfg(all(not(target_arch = "wasm32"), feature = "fs-surb-storage"))]
@@ -5,10 +5,17 @@ use crate::spawn_future;
pub(crate) use accessor::{TopologyAccessor, TopologyReadPermit};
use futures::StreamExt;
use log::*;
use nym_sphinx::addressing::nodes::NodeIdentity;
use nym_topology::provider_trait::TopologyProvider;
use nym_topology::NymTopologyError;
use std::time::Duration;
#[cfg(not(target_arch = "wasm32"))]
use tokio::time::sleep;
#[cfg(target_arch = "wasm32")]
use wasmtimer::tokio::sleep;
mod accessor;
pub mod geo_aware_provider;
pub(crate) mod nym_api_provider;
@@ -86,6 +93,54 @@ impl TopologyRefresher {
self.topology_accessor.ensure_is_routable().await
}
pub async fn ensure_contains_gateway(
&self,
gateway: &NodeIdentity,
) -> Result<(), NymTopologyError> {
let topology = self
.topology_accessor
.current_topology()
.await
.ok_or(NymTopologyError::EmptyNetworkTopology)?;
if !topology.gateway_exists(gateway) {
return Err(NymTopologyError::NonExistentGatewayError {
identity_key: gateway.to_base58_string(),
});
}
Ok(())
}
pub async fn wait_for_gateway(
&mut self,
gateway: &NodeIdentity,
timeout_duration: Duration,
) -> Result<(), NymTopologyError> {
info!(
"going to wait for at most {timeout_duration:?} for gateway '{gateway}' to come online"
);
let deadline = sleep(timeout_duration);
tokio::pin!(deadline);
loop {
tokio::select! {
_ = &mut deadline => {
return Err(NymTopologyError::TimedOutWaitingForGateway {
identity_key: gateway.to_base58_string()
})
}
_ = self.try_refresh() => {
if self.ensure_contains_gateway(gateway).await.is_ok() {
return Ok(())
}
info!("gateway '{gateway}' is still not online...");
sleep(self.refresh_rate).await
}
}
}
}
pub fn start_with_shutdown(mut self, mut shutdown: nym_task::TaskClient) {
spawn_future(async move {
debug!("Started TopologyRefresher with graceful shutdown support");
@@ -35,7 +35,7 @@ pub struct ClientKeysPaths {
}
impl ClientKeysPaths {
pub fn new_default<P: AsRef<Path>>(base_data_directory: P) -> Self {
pub fn new_base<P: AsRef<Path>>(base_data_directory: P) -> Self {
let base_dir = base_data_directory.as_ref();
ClientKeysPaths {
@@ -29,14 +29,14 @@ pub struct CommonClientPaths {
}
impl CommonClientPaths {
pub fn new_default<P: AsRef<Path>>(base_data_directory: P) -> Self {
pub fn new_base<P: AsRef<Path>>(base_data_directory: P) -> Self {
let base_dir = base_data_directory.as_ref();
CommonClientPaths {
credentials_database: base_dir.join(DEFAULT_CREDENTIALS_DB_FILENAME),
reply_surb_database: base_dir.join(DEFAULT_REPLY_SURB_DB_FILENAME),
gateway_details: base_dir.join(DEFAULT_GATEWAY_DETAILS_FILENAME),
keys: ClientKeysPaths::new_default(base_data_directory),
keys: ClientKeysPaths::new_base(base_data_directory),
}
}
}
@@ -3,6 +3,7 @@
use crate::config::disk_persistence::keys_paths::ClientKeysPaths;
use crate::config::disk_persistence::{CommonClientPaths, DEFAULT_GATEWAY_DETAILS_FILENAME};
use crate::error::ClientCoreError;
use serde::{Deserialize, Serialize};
use std::path::PathBuf;
@@ -15,16 +16,17 @@ pub struct CommonClientPathsV1_1_20_2 {
}
impl CommonClientPathsV1_1_20_2 {
pub fn upgrade_default(self) -> CommonClientPaths {
let data_dir = self
.reply_surb_database
.parent()
.expect("client paths upgrade failure");
CommonClientPaths {
pub fn upgrade_default(self) -> Result<CommonClientPaths, ClientCoreError> {
let data_dir = self.reply_surb_database.parent().ok_or_else(|| {
ClientCoreError::UnableToUpgradeConfigFile {
new_version: "1.1.20-2".to_string(),
}
})?;
Ok(CommonClientPaths {
keys: self.keys,
gateway_details: data_dir.join(DEFAULT_GATEWAY_DETAILS_FILENAME),
credentials_database: self.credentials_database,
reply_surb_database: self.reply_surb_database,
}
})
}
}
+62 -7
View File
@@ -3,6 +3,7 @@
use nym_config::defaults::NymNetworkDetails;
use nym_crypto::asymmetric::identity;
use nym_gateway_client::client::GatewayConfig;
use nym_sphinx::{
addressing::clients::Recipient,
params::{PacketSize, PacketType},
@@ -29,6 +30,8 @@ const DEFAULT_MESSAGE_STREAM_AVERAGE_DELAY: Duration = Duration::from_millis(20)
const DEFAULT_AVERAGE_PACKET_DELAY: Duration = Duration::from_millis(50);
const DEFAULT_TOPOLOGY_REFRESH_RATE: Duration = Duration::from_secs(5 * 60); // every 5min
const DEFAULT_TOPOLOGY_RESOLUTION_TIMEOUT: Duration = Duration::from_millis(5_000);
const DEFAULT_MAX_STARTUP_GATEWAY_WAITING_PERIOD: Duration = Duration::from_secs(70 * 60); // 70min -> full epoch (1h) + a bit of overhead
// Set this to a high value for now, so that we don't risk sporadic timeouts that might cause
// bought bandwidth tokens to not have time to be spent; Once we remove the gateway from the
// bandwidth bridging protocol, we can come back to a smaller timeout value
@@ -69,7 +72,11 @@ pub struct Config {
}
impl Config {
pub fn new<S: Into<String>>(id: S, version: S) -> Self {
pub fn new<S1, S2>(id: S1, version: S2) -> Self
where
S1: Into<String>,
S2: Into<String>,
{
Config {
client: Client::new_default(id, version),
debug: Default::default(),
@@ -133,6 +140,17 @@ impl Config {
self.debug.traffic.message_sending_average_delay = Duration::from_millis(4);
}
pub fn with_disabled_poisson_process(mut self, disabled: bool) -> Self {
if disabled {
self.set_no_poisson_process()
}
self
}
pub fn set_no_poisson_process(&mut self) {
self.debug.traffic.disable_main_poisson_packet_distribution = true;
}
pub fn with_disabled_cover_traffic(mut self, disabled: bool) -> Self {
if disabled {
self.set_no_cover_traffic()
@@ -226,6 +244,19 @@ pub struct GatewayEndpointConfig {
pub gateway_listener: String,
}
impl TryFrom<GatewayEndpointConfig> for GatewayConfig {
type Error = ClientCoreError;
fn try_from(value: GatewayEndpointConfig) -> Result<Self, Self::Error> {
Ok(GatewayConfig {
gateway_identity: identity::PublicKey::from_base58_string(value.gateway_id)
.map_err(ClientCoreError::UnableToCreatePublicKeyFromGatewayId)?,
gateway_owner: Some(value.gateway_owner),
gateway_listener: value.gateway_listener,
})
}
}
#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
impl GatewayEndpointConfig {
#[cfg_attr(target_arch = "wasm32", wasm_bindgen(constructor))]
@@ -248,15 +279,29 @@ impl GatewayEndpointConfig {
identity::PublicKey::from_base58_string(&self.gateway_id)
.map_err(ClientCoreError::UnableToCreatePublicKeyFromGatewayId)
}
}
impl From<nym_topology::gateway::Node> for GatewayEndpointConfig {
fn from(node: nym_topology::gateway::Node) -> GatewayEndpointConfig {
let gateway_listener = node.clients_address();
pub fn from_node(node: nym_topology::gateway::Node, use_tls: bool) -> Self {
// TODO: in the future this shall return a Result and explicit `use_tls` will be removed in favour of the tls info being available on the struct
if use_tls {
Self::from_topology_node_tls(node)
} else {
Self::from_topology_node_no_tls(node)
}
}
pub fn from_topology_node_no_tls(node: nym_topology::gateway::Node) -> Self {
GatewayEndpointConfig {
gateway_id: node.identity_key.to_base58_string(),
gateway_listener: node.clients_address(),
gateway_owner: node.owner,
}
}
pub fn from_topology_node_tls(node: nym_topology::gateway::Node) -> Self {
GatewayEndpointConfig {
gateway_id: node.identity_key.to_base58_string(),
gateway_listener: node.clients_address_tls(),
gateway_owner: node.owner,
gateway_listener,
}
}
}
@@ -287,7 +332,11 @@ pub struct Client {
}
impl Client {
pub fn new_default<S: Into<String>>(id: S, version: S) -> Self {
pub fn new_default<S1, S2>(id: S1, version: S2) -> Self
where
S1: Into<String>,
S2: Into<String>,
{
let network = NymNetworkDetails::new_mainnet();
let nyxd_urls = network
.endpoints
@@ -479,6 +528,11 @@ pub struct Topology {
/// Supersedes `topology_refresh_rate_ms`.
pub disable_refreshing: bool,
/// Defines how long the client is going to wait on startup for its gateway to come online,
/// before abandoning the procedure.
#[serde(with = "humantime_serde")]
pub max_startup_gateway_waiting_period: Duration,
/// Specifies the mixnode topology to be used for sending packets.
pub topology_structure: TopologyStructure,
}
@@ -513,6 +567,7 @@ impl Default for Topology {
topology_refresh_rate: DEFAULT_TOPOLOGY_REFRESH_RATE,
topology_resolution_timeout: DEFAULT_TOPOLOGY_RESOLUTION_TIMEOUT,
disable_refreshing: false,
max_startup_gateway_waiting_period: DEFAULT_MAX_STARTUP_GATEWAY_WAITING_PERIOD,
topology_structure: TopologyStructure::default(),
}
}
@@ -267,7 +267,7 @@ impl From<TopologyV1_1_20_2> for Topology {
topology_refresh_rate: value.topology_refresh_rate,
topology_resolution_timeout: value.topology_resolution_timeout,
disable_refreshing: value.disable_refreshing,
topology_structure: Default::default(),
..Default::default()
}
}
}
+23 -16
View File
@@ -1,6 +1,7 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// Copyright 2022-2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::client::mix_traffic::transceiver::ErasedGatewayError;
use nym_crypto::asymmetric::identity::Ed25519RecoveryError;
use nym_gateway_client::error::GatewayClientError;
use nym_topology::gateway::GatewayConversionError;
@@ -19,6 +20,12 @@ pub enum ClientCoreError {
source: GatewayClientError,
},
#[error("Custom gateway client error: {source}")]
ErasedGatewayClientError {
#[from]
source: ErasedGatewayError,
},
#[error("Ed25519 error: {0}")]
Ed25519RecoveryError(#[from] Ed25519RecoveryError),
@@ -31,15 +38,9 @@ pub enum ClientCoreError {
#[error("No gateways on network")]
NoGatewaysOnNetwork,
#[error("Failed to setup gateway")]
FailedToSetupGateway,
#[error("List of nym apis is empty")]
ListOfNymApisIsEmpty,
#[error("Could not load existing gateway configuration: {0}")]
CouldNotLoadExistingGatewayConfiguration(std::io::Error),
#[error("The current network topology seem to be insufficient to route any packets through")]
InsufficientNetworkTopology(#[from] NymTopologyError),
@@ -61,15 +62,6 @@ pub enum ClientCoreError {
#[error("The gateway id is invalid - {0}")]
UnableToCreatePublicKeyFromGatewayId(Ed25519RecoveryError),
#[error("The identity of the gateway is unknown - did you run init?")]
GatewayIdUnknown,
#[error("The owner of the gateway is unknown - did you run init?")]
GatewayOwnerUnknown,
#[error("The address of the gateway is unknown - did you run init?")]
GatewayAddressUnknown,
#[error("The gateway is malformed: {source}")]
MalformedGateway {
#[from]
@@ -119,6 +111,21 @@ pub enum ClientCoreError {
#[error("the provided gateway details (for gateway {gateway_id}) do not correspond to the shared keys")]
MismatchedGatewayDetails { gateway_id: String },
#[error("unable to upgrade config file to `{new_version}`")]
UnableToUpgradeConfigFile { new_version: String },
#[error("the provided gateway details don't much the stored data")]
MismatchedStoredGatewayDetails,
#[error("custom selection of gateway was expected")]
CustomGatewaySelectionExpected,
#[error("the persisted gateway details were set for a custom setup")]
UnexpectedPersistedCustomGatewayDetails,
#[error("this client has performed gateway initialisation in another session")]
NoInitClientPresent,
}
/// Set of messages that the client can send to listeners via the task manager

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