Compare commits

...

233 Commits

Author SHA1 Message Date
Tommy Verrall e20ed854df check outputs 2023-08-29 11:46:14 +02:00
Tommy Verrall c6509c3a95 fix string 2023-08-29 11:35:31 +02:00
Tommy Verrall 8a9d242d03 check to see if this fixes strapi 2023-08-29 11:32:10 +02:00
Jon Häggblad 769a26fdeb Merge pull request #3815 from nymtech/jon/revert-clippy-change
Revert clippy fix for arc_with_non_send_sync in wasm client
2023-08-28 09:53:16 +02:00
Jon Häggblad 2e7ddcb195 Allow arc_with_non_send_sync in wasm client 2023-08-26 21:51:16 +02:00
Jon Häggblad 84d893198b Revert "Replace Arc with Rc on clippy's suggestion"
This reverts commit b050ae72de.
2023-08-26 21:09:33 +02:00
Fran Arbanas 2f6617daac Feature/issue credentials (#3691)
* Move the functionality to issue credentials from the credential binary and connect it with nym-cli

* finished CLI part, trying to fit SDK part

* finished Rust SDK

* fix: cleanup

* linting

* linting

* linting

* remove one layer of coconut in nym-cli

* linting

* Fixes based on PR comments

* formatting

* fixes based on PR comments

* formatting

* fixing clippy errors

* fixed post-rebasing issues and converted the lib into shared dep for other binaries

* removed credentials client in favour of moving the functionality to nym-cli

* removed redundant 'issue_credential' example (it did the same thing as 'bandwdith')

* removed credentials client from build server

* made the coconut cli also accept nym-api configs

* fixed support for socks5 and NR

---------

Co-authored-by: Jędrzej Stuczyński <jedrzej.stuczynski@gmail.com>
2023-08-25 17:13:52 +02:00
Tommy Verrall 9e483da802 Merge pull request #3814 from nymtech/jon/include-gateways-in-georouting
In geoaware routing, choose mixnodes close to exit gateway
2023-08-25 16:56:07 +02:00
Jon Häggblad d530e492ec Fix compilation 2023-08-25 16:13:41 +02:00
Jon Häggblad 6c67cff235 Allow clippy for now 2023-08-25 16:02:13 +02:00
Jon Häggblad 66f04d17b7 Select country group by the exit gateway 2023-08-25 15:52:43 +02:00
Jon Häggblad 492155d04a Also filter gateways on location 2023-08-25 15:52:43 +02:00
Jon Häggblad 069226125b Separate cfg wasm function 2023-08-25 15:42:40 +02:00
Jędrzej Stuczyński 1ce536c2fa [Manually reapplied] Merge pull request #3804 from nymtech/feature/explorer-gateway-iplocation
This was originally a commit 'b0a45c03b16c74697d8b46428fd83a25a5168add'.
However, we had to manually reapply it due to accidentally messing up the branch history.
2023-08-25 13:59:38 +01:00
Lorexia 2fbb901deb Update mixnode setup to return IPv4 2023-08-25 13:56:31 +01:00
Tommy Verrall 3c3ec9c831 Merge pull request #3812 from nymtech/jon/nym-connect-filter-gateway-version
nym-connect: filter gateways on compatible version
2023-08-25 11:58:35 +02:00
Jon Häggblad 6a34a99fee Merge pull request #3811 from nymtech/jon/clippy
Fix clippy for latest rustc
2023-08-25 11:44:57 +02:00
Jon Häggblad ec75a06c9d nym-connect: filter gateways on compatible version 2023-08-25 11:27:47 +02:00
Tommy Verrall 2fbe7bb350 Merge pull request #3810 from nymtech/jon/make-explorer-api-url-configurable-in-geo-aware
Add EXPLORER_API configurable url
2023-08-25 10:17:36 +02:00
Jon Häggblad ee67f3d0f0 rustfmt 2023-08-25 09:10:10 +02:00
Jon Häggblad 188650ea05 Stay on 1.71.0 for nym-wallet until the clippy crash is resolved 2023-08-25 09:09:05 +02:00
Jon Häggblad decae2b54d Clippy pub use shadowing warning 2023-08-25 09:01:27 +02:00
Jon Häggblad 8104761914 Update nym-connect Cargo.lock 2023-08-25 07:37:45 +02:00
Jon Häggblad 8503def37f Remove nym-connect mobile from Makefile 2023-08-25 07:37:29 +02:00
Jon Häggblad 48023eab41 Remove shadowing import 2023-08-25 07:33:49 +02:00
Jon Häggblad b050ae72de Replace Arc with Rc on clippy's suggestion 2023-08-25 07:33:32 +02:00
Jon Häggblad 377c9be790 clippy --fix 2023-08-24 17:58:51 +02:00
Jon Häggblad 5d7fd66cfc rustfmt 2023-08-24 17:55:19 +02:00
Jon Häggblad 5128aef193 Upgrade ts-rs to 7.0.0 2023-08-24 17:55:19 +02:00
Jon Häggblad 6a327b0bd6 No timeout for wasm 2023-08-24 16:01:47 +02:00
Jon Häggblad 8a38c61065 Fix wallet build 2023-08-24 15:43:48 +02:00
Jon Häggblad f0a888d59c Add EXPLORER_API configurable url 2023-08-24 15:34:49 +02:00
mfahampshire f1b9cf4d68 update minibolt pp 2023-08-23 20:56:43 +02:00
Tommy Verrall 392e7b5268 Merge pull request #3806 from nymtech/fix/wallet-gateway-form
fix(wallet): gateway bond form wrong helper text
2023-08-23 18:01:40 +02:00
pierre 776a9d508a fix wrong helper text 2023-08-23 17:44:53 +02:00
pierre 2f624d4f10 doc(nc-android): add notes for AAB build 2023-08-23 17:20:51 +02:00
Jędrzej Stuczyński 3c9faff4ec [hotfix]: don't assign invalid fields when crossing the JS boundary (#3805)
* [hotfix]: don't assign invalid fields when crossing the JS boundary

* eslint
2023-08-23 16:12:01 +01:00
pierre 026d52a218 print location in uppercase 2023-08-23 16:46:07 +02:00
pierre f8b70097d3 use geoip location for gateways 2023-08-23 16:17:07 +02:00
Tommy Verrall 0d3df4b58d Merge pull request #3802 from nymtech/bugfix/use-correct-tendermint-dialect
Bugfix/use correct tendermint dialect
2023-08-23 12:46:41 +02:00
Jędrzej Stuczyński 5241047f45 implemented compatibility mode for reqwest client 2023-08-23 11:05:31 +01:00
Jędrzej Stuczyński 2651784e8b fully delegating 'TendermintRpcClient' trait 2023-08-23 10:42:09 +01:00
Jędrzej Stuczyński 2cd2b1ccd4 always using http client in v034 compat mode 2023-08-23 10:08:33 +01:00
Jon Häggblad af4e8241e7 Fix rocksdb compilation (#3801)
* Fix rocksdb compilation

* Add ephemera to CI build

* Add nym-nr-query to CI build

* Fix clippy in ephemera rocksdb
2023-08-23 10:07:45 +02:00
Jon Häggblad 92350daca8 network-requester: disable poisson process by default (#3783)
* network-requester: disable poisson process by default

* network-requester: instead add new top-level config field

* Remove quoation marks in template
2023-08-22 14:17:03 +02:00
Jędrzej Stuczyński b429c64168 [demo] libp2p example with nym-sdk (#3763)
* imported libp2p to monorepo

* fixed vanilla ping example

* added libp2p client to workspace

* naively replaced dockerised client with the sdk

* moved libp2p code to sdk examples

* reduced number of dependencies required for libp2p example

* updated readmes

* added protobuf compiler to build dependencies

* added protoc dependency to readme for chat and ping examples

---------

Co-authored-by: mfahampshire <maxhampshire@pm.me>
2023-08-22 13:12:13 +02:00
Tommy Verrall f88622ac08 Delete upload-nyxd-ci.yml
not needed anymore removing
2023-08-22 12:21:44 +02:00
Jędrzej Stuczyński 0a5a2c6747 removed needless_pass_by_ref_mut in mixnet contract tests (#3798) 2023-08-22 11:56:23 +02:00
Tommy Verrall 824bd636f9 Merge pull request #3795 from nymtech/release/v1.1.28
Release/v1.1.28
2023-08-22 11:17:29 +02:00
Tommy Verrall cf6411ac08 Merge pull request #3794 from nymtech/qa/fix-windows-builder
Update nym-connect-publish-windows10.yml
2023-08-22 10:59:23 +02:00
Tommy Verrall 6428133122 Merge pull request #3793 from nymtech/qa/fix-api-tests
change ci to run against sandbox for tests
2023-08-22 10:55:24 +02:00
Tommy Verrall 3c69f9c2f9 Update nym-connect-publish-windows10.yml 2023-08-22 10:35:46 +02:00
Tommy Verrall c1e4b87744 change ci to run against sandbox for tests 2023-08-22 10:31:37 +02:00
benedettadavico 22246d0d5d bumping versions and updating changelog 2023-08-22 09:54:51 +02:00
Tommy Verrall 29593ef3c9 removing placeholders for the timebeing to enable windows build 2023-08-22 09:27:49 +02:00
Tommy Verrall 12f21185e3 Merge pull request #3791 from nymtech/feature/ephemera_upgrade
Feature/ephemera upgrade
2023-08-21 16:46:40 +02:00
Bogdan-Ștefan Neacșu 85ab3d5c80 Include 1.1.28 upgrade for ephemera config template 2023-08-21 16:51:32 +03:00
Pierre Dommerc dffe171b7f feat(explorer-api): add gateway geoip location (#3785)
* feat(explorer-api): add gateway geoip location

* fix lint
2023-08-21 15:50:18 +02:00
mfahampshire 6d3b198f00 change minibolt description 2023-08-21 14:04:21 +02:00
mfahampshire d4920b82f0 include 2faktor's PR material 2023-08-21 14:04:08 +02:00
mfahampshire 24099d159b change minibolt description 2023-08-21 14:02:29 +02:00
mfahampshire 463033aa64 version bump in toml files fr docs projects 2023-08-21 13:59:57 +02:00
mfahampshire c1ba56ab1c include 2faktor's PR material 2023-08-21 13:59:20 +02:00
mfahampshire 8dfe8f4678 version bump in toml files fr docs projects 2023-08-21 09:54:09 +02:00
Tommy Verrall c2a38c9b53 Merge branch 'develop' into release/v1.1.28 2023-08-21 09:35:39 +02:00
Tommy Verrall 33e7ce53fb Merge pull request #3723 from nymtech/feature/nc-desktop-userdata
refactor(nc-desktop): use userdata storage to save user gateway&sp
2023-08-21 09:34:46 +02:00
mx bdf18e30fb Merge pull request #3674 from nymtech/feature/operators-guide
feature/operators-guide
2023-08-18 16:03:18 +00:00
mfahampshire e0b32e1cc9 updated css font 2023-08-18 17:47:48 +02:00
Mark Sinclair 4ff69b77a9 Update general.css 2023-08-18 16:44:38 +01:00
Mark Sinclair 5f095d703d Update custom.css 2023-08-18 16:44:01 +01:00
Mark Sinclair ff4dbd09d0 Update general.css 2023-08-18 16:42:18 +01:00
Mark Sinclair 404d2d9857 Update build_all_to_dist.sh 2023-08-18 16:28:42 +01:00
Mark Sinclair b5f2ecd79e Update build_all_to_dist.sh 2023-08-18 16:24:57 +01:00
Mark Sinclair 38b9e14851 Update cd-docs.yml 2023-08-18 15:43:50 +01:00
mfahampshire 6ead19bd97 added conditional push for master branch 2023-08-18 15:55:59 +02:00
mfahampshire c169971287 fixed mdbook versions 2023-08-18 15:45:44 +02:00
mfahampshire 7b3cbdcd44 cont. work on cicd 2023-08-18 15:36:11 +02:00
mfahampshire 43dfb31eb2 modified ci script 2023-08-18 14:37:14 +02:00
mfahampshire ff4350ec90 changed name of script for staging to dist/ 2023-08-18 14:36:46 +02:00
mfahampshire c8516071fc removed developer portal specific files 2023-08-18 14:36:22 +02:00
Bogdan-Ștefan Neacşu ee5b55fab6 Feature/ephemera (#3731)
* Feature/ephemera compile (#3437)

* Include ephemera node code in repo

* Upgrade deps

* Bump minor version of cosmwasm-std

* Include ephemera in nym-api dep and downgrade rusqlite

* Fix clippy and ephemera docs code

* More clippy on ephemera

---------

Co-authored-by: Andrus Salumets <andrus@nymtech.net>

* Start ephemera components in nym-api (#3475)

* Start ephemera components in nym-api

* Pass nyxd client and use common metric structures

* Swap url endpoint with contract for sending rewarding messages

* Fix build after rebase

* Perform ephemera rewards computation before normal nym-api ones

* Remove contract mock from ephemera

* Take raw rewards from network monitor

* Remove ephemera old reward version

* Use nym shutdown procedure in ephemera

* Temporary fix for some warnings

* Umock contract membership of ephemera (#3574)

* Pass nyxd client to members provider

* Basic ephemera contract

* Add register peer tx

* Add query all peers

* Nyxd ephemera client

* Add registration of ephemera peer

* Replace epoch http api with actual contract

* Merge ephemera config into nym-api config

* Load cluster from contract

* Guard nym-outfox out of cosmwasm builds (#3650)

* Feature/fixes while testing (#3668)

* Commit local peer before querying contract

* Default to anyonline

* Remove string from template

* Fix avg computing

* Use updated qa env

* Fix clippy

* Add unit tests for ephemera contract

* Upload ephemera contract in CI

* Add group check for peer signup

* Peer registration unit test

* Start ephemera only on monitoring

* Remove old MixnodeToReward struct

* Move all ephemera config to its file

* Skip with serde ephemera config

* Fix default value in args

* Feature/add ephemera flag (#3727)

* Replace unwrap with error handling

* Add ephemera enable flag

* Fix template

* Add json schema to ephemera contract (#3735)

* Update lock files

* Update changelog

---------

Co-authored-by: Andrus Salumets <andrus@nymtech.net>
2023-08-18 14:14:13 +03:00
mfahampshire 11f3ce9224 Merge branch 'feature/operators-guide' of github.com:nymtech/nym into feature/operators-guide 2023-08-18 11:40:26 +02:00
mfahampshire 0f43521497 tweak 2023-08-18 11:22:58 +02:00
mfahampshire a1a1970dc1 updated readme with soon to be operator doc URL 2023-08-18 11:22:58 +02:00
mfahampshire 89ea3039d5 removed unnecessary linkcheck rendering output from dist/ 2023-08-18 11:22:58 +02:00
mfahampshire efa1e0353e rough staging sh script 2023-08-18 11:22:58 +02:00
mfahampshire 96e2712039 reintroduced linkchecker + fixed broken links 2023-08-18 11:22:58 +02:00
mfahampshire 84ad777c42 added workflow_dispatch to ci for dev-portal and docs 2023-08-18 11:22:58 +02:00
mfahampshire f569ba1c17 pull fix from ci-dev.yml to ci-docs.yml 2023-08-18 11:22:58 +02:00
serinko 54ff3ee987 applied theme changes:dev-portal -> docs 2023-08-18 11:22:58 +02:00
serinko 1f2a2c37ab picked theme changes:dev-portal -> operators; theme finished 2023-08-18 11:22:58 +02:00
serinko b0d5bacafd picked theme changes:dev-portal -> operators; theme finished 2023-08-18 11:22:58 +02:00
Jędrzej Stuczyński 8b65e44767 using stricter version requirements for mdbook and mdbook-variables 2023-08-18 11:22:58 +02:00
Gala a2445183bf theme change 2023-08-18 11:22:58 +02:00
mfahampshire 230d8aa170 changed out of date var 'mix_node_release_version' to 'platform_release_version 2023-08-18 11:22:58 +02:00
mfahampshire 035535058e fixed incorrect import path for chat app 2023-08-18 11:22:58 +02:00
mfahampshire df9aec1554 updated grantee info update link 2023-08-18 11:22:58 +02:00
mfahampshire 740846befc fixed links 2023-08-18 11:22:58 +02:00
mfahampshire 074e27291b updated links in operator binaries compilation list 2023-08-18 11:22:58 +02:00
mfahampshire b1c3264f69 removed doubled header 2023-08-18 11:22:58 +02:00
mfahampshire 905318ad27 final tweaks 2023-08-18 11:22:58 +02:00
mfahampshire 7065f870eb removed glossary file: needs rework 2023-08-18 11:22:58 +02:00
mfahampshire ee14dfc75e added coc and license 2023-08-18 11:22:58 +02:00
mfahampshire a93de8b4c5 updated vars in all books for next release version 2023-08-18 11:22:54 +02:00
mfahampshire 534c8f49d1 added notes to ws and socks client subsections re: rust sdk 2023-08-18 11:21:12 +02:00
mfahampshire 3da3f66ea3 * tweaked mixnode doc
* removed token diagram from nyx validator doc
2023-08-18 11:21:12 +02:00
mfahampshire 32bfceacb5 added custom 404 page for all books 2023-08-18 11:21:12 +02:00
mfahampshire 7a606e11f4 NR page 2023-08-18 11:21:12 +02:00
mfahampshire d3d5346cfe typo fix 2023-08-18 11:21:12 +02:00
mfahampshire 8fe549daa5 more links, fleshed out intro 2023-08-18 11:21:12 +02:00
mfahampshire f15be9456a added links 2023-08-18 11:21:12 +02:00
serinko 567d3c8173 socks5: new commands from #3699 2023-08-18 11:21:12 +02:00
serinko ce81f0c841 operators-guides final review of links and typos 2023-08-18 11:21:12 +02:00
serinko 9652060c57 correction of typos 2023-08-18 11:21:12 +02:00
serinko 9c0317ab28 correcting links, typos - doc finished 2023-08-18 11:21:12 +02:00
serinko d13116bda0 old typos edits 2023-08-18 11:21:12 +02:00
serinko 77f8eadd0e scp automation tested - doc finished 2023-08-18 11:21:12 +02:00
serinko 1e2de5067a correct go installation - guide finished 2023-08-18 11:21:12 +02:00
serinko c43344d489 remove reduntant nym/docs/ 2023-08-18 11:21:12 +02:00
serinko 2711e6f679 filled/docs/validators.md 2023-08-18 11:21:12 +02:00
mfahampshire c85f7d2565 skeleton of NR page 2023-08-18 11:21:12 +02:00
mfahampshire e8506f6d53 cont. 2023-08-18 11:21:12 +02:00
mfahampshire 6d5ff1146b * deleted old setup guides
* added new info on operator guides
* adding stubs for in-depth node pages
2023-08-18 11:21:08 +02:00
mfahampshire 1f226682f4 added custom 404 + updated platform version 2023-08-18 11:20:03 +02:00
mfahampshire f17d2cec0d typo fix 2023-08-18 11:18:00 +02:00
mfahampshire 089d5e6dbb * removed old wallet-address flag
* 'mixnode' -> 'mix node' for consistency in non-code / non-binary references
2023-08-18 11:18:00 +02:00
mfahampshire fca384fba2 tweaked intro page 2023-08-18 11:18:00 +02:00
serinko 3ae803a343 #3674 feedback implemented 2023-08-18 11:18:00 +02:00
serinko 99224310e9 operators: plugins work, ready for final review 2023-08-18 11:18:00 +02:00
serinko d2e59f12f6 operators: book built, no {comments} left, cmdrun and admonish not working 2023-08-18 11:18:00 +02:00
serinko 99a321c54d reinit the book, delete *.html in /src 2023-08-18 11:18:00 +02:00
serinko 8fd832e217 reinitialized the book - simplified book.toml 2023-08-18 11:17:59 +02:00
serinko 09c4df8448 operators guide: book built 2023-08-18 11:17:59 +02:00
serinko 09b15ae020 operators guide: add src/binaries/ files, fix links 2023-08-18 11:17:59 +02:00
serinko 585cf55026 operators: typo edit 2023-08-18 11:17:59 +02:00
serinko a0418daaea operators: comment missing info 2023-08-18 11:17:59 +02:00
serinko f0c0ddb1c2 operators: book build - minor issues remain 2023-08-18 11:17:59 +02:00
serinko b006e1820f faq.md: initial questions and answers - in progress 2023-08-18 11:17:59 +02:00
serinko 50b755cfde corrected scp -3 option 2023-08-18 11:17:59 +02:00
serinko a002ddda8d operators-guide:troubleshooting.md done - content ready to go out 2023-08-18 11:17:59 +02:00
serinko 49d909815d operators-guide: incorporated PR #3656 2023-08-18 11:17:59 +02:00
serinko 990f7d64dd operators-guide: create validator tutorial & add maintenance points 2023-08-18 11:17:59 +02:00
serinko d422741be4 operators-guide: create NR page & edit maintenance page 2023-08-18 11:17:59 +02:00
serinko 389ccffb63 operators-guide: moved repeating to maintenance.md, shortened and cleaned the existing guides 2023-08-18 11:17:59 +02:00
serinko 9a76db479b operator-guides: made todo notes 2023-08-18 11:17:59 +02:00
serinko 55cd1a8b91 operators-guide: created generic docs maintenance.md and preliminary-steps.md to avoid redundancy 2023-08-18 11:17:59 +02:00
serinko cbee6153bd mixnode-seup: minor edits 2023-08-18 11:17:59 +02:00
serinko 232032baf4 feature/operators-guide: coppied all configs from ../docs/ 2023-08-18 11:17:59 +02:00
serinko 17e1c5f970 initilizing operators guides mdbook 2023-08-18 11:17:59 +02:00
mfahampshire 85ab634d9c tweak 2023-08-18 10:10:36 +02:00
Tommy Verrall 3d245f745f Merge pull request #3756 from nymtech/feature/rust-sdk-concurrent-send-receive
[rust-sdk] feat: make it more convenient to send and receive messages in different tasks
2023-08-17 15:05:27 +02:00
Tommy Verrall c8cee9b56e Merge remote-tracking branch 'origin/develop' into feature/rust-sdk-concurrent-send-receive 2023-08-17 15:01:34 +02:00
mfahampshire 853d537e51 * added message types explainer
* added split task example
2023-08-17 13:45:36 +02:00
Jędrzej Stuczyński 2993e85c7a removed redundant notify and instead awaiting the task futures 2023-08-17 12:21:15 +01:00
pierre a2a887627d remove dev log 2023-08-17 11:50:00 +02:00
pierre 2b283090fa update log 2023-08-17 11:50:00 +02:00
pierre c097567f78 wip 2023-08-17 11:50:00 +02:00
pierre 93ec0f1984 add clear method to app data 2023-08-17 11:50:00 +02:00
pierre edf5050ba6 remove dead code 2023-08-17 11:50:00 +02:00
pierre 3317804a80 feat(nc-desktop): use userdata storage to save user gateway&sp 2023-08-17 11:50:00 +02:00
mfahampshire 6c83b88247 updated readme with soon to be operator doc URL 2023-08-11 13:08:19 +02:00
mfahampshire 6a54a6653c removed unnecessary linkcheck rendering output from dist/ 2023-08-11 12:30:41 +02:00
mfahampshire d11cf4c9a3 rough staging sh script 2023-08-11 12:29:30 +02:00
mfahampshire f9108ea400 reintroduced linkchecker + fixed broken links 2023-08-11 12:29:20 +02:00
mfahampshire 3714ee76ff added workflow_dispatch to ci for dev-portal and docs 2023-08-11 10:53:34 +02:00
mfahampshire b1b276e8ba pull fix from ci-dev.yml to ci-docs.yml 2023-08-11 10:16:37 +02:00
serinko 9966d0fa5f applied theme changes:dev-portal -> docs 2023-08-10 18:39:04 +02:00
serinko c5c6d3cc27 picked theme changes:dev-portal -> operators; theme finished 2023-08-10 18:32:13 +02:00
serinko 0f777204b8 picked theme changes:dev-portal -> operators; theme finished 2023-08-10 18:31:56 +02:00
Gala cbda950259 Merge pull request #3759 from nymtech/theme
Theme
2023-08-10 17:58:26 +02:00
Jędrzej Stuczyński ae79dc4ec6 using stricter version requirements for mdbook and mdbook-variables 2023-08-10 14:40:15 +01:00
Gala d49ba6e025 theme change 2023-08-09 17:56:36 +02:00
Jędrzej Stuczyński 75bb9140b0 fixed doc tests 2023-08-09 14:49:16 +01:00
Jędrzej Stuczyński b63f5409db cargo fmt 2023-08-09 14:43:43 +01:00
Jędrzej Stuczyński de6c1ba1f0 made the Stream return a single message at each call 2023-08-09 14:39:57 +01:00
Jędrzej Stuczyński e705b76b36 unified sending interface + example of split sending 2023-08-09 14:27:17 +01:00
mfahampshire 05259410b2 changed out of date var 'mix_node_release_version' to 'platform_release_version 2023-08-09 14:25:29 +02:00
mfahampshire 6be7c094be fixed incorrect import path for chat app 2023-08-09 14:24:57 +02:00
mfahampshire 2db3297d1e updated grantee info update link 2023-08-09 14:11:06 +02:00
Jędrzej Stuczyński a1295a316b utility 'Stream' implementation for MixnetClient 2023-08-09 12:50:34 +01:00
mfahampshire fc7e4be175 fixed links 2023-08-09 13:25:37 +02:00
mfahampshire 3dd3692e8d updated links in operator binaries compilation list 2023-08-09 12:51:34 +02:00
mfahampshire 4bb6f21faa Merge branch 'release/v1.1.27' into feature/operators-guide 2023-08-09 12:50:06 +02:00
mfahampshire 62c03b3136 removed doubled header 2023-08-09 11:47:11 +02:00
mfahampshire e9d10caaf8 final tweaks 2023-08-09 11:30:12 +02:00
mfahampshire 432f6a006f removed glossary file: needs rework 2023-08-09 11:29:57 +02:00
mfahampshire 4f05169361 added coc and license 2023-08-09 11:29:34 +02:00
mfahampshire 23a669c4de updated vars in all books for next release version 2023-08-08 14:19:29 +02:00
mfahampshire 88d2592a4e added notes to ws and socks client subsections re: rust sdk 2023-08-08 14:16:48 +02:00
mfahampshire 85c22525cf * tweaked mixnode doc
* removed token diagram from nyx validator doc
2023-08-08 14:10:44 +02:00
mfahampshire 7e27413a12 added custom 404 page for all books 2023-08-08 13:59:53 +02:00
mfahampshire 2eeb8bb590 NR page 2023-08-07 16:38:13 +02:00
mfahampshire 2565716816 typo fix 2023-08-07 16:38:02 +02:00
mfahampshire f954ce5c97 more links, fleshed out intro 2023-08-07 16:06:39 +02:00
mfahampshire baebbe4e4d added links 2023-08-07 15:52:48 +02:00
serinko 2dd3e031bd socks5: new commands from #3699 2023-08-07 13:13:11 +02:00
serinko 860ec74b59 operators-guides final review of links and typos 2023-08-07 12:47:29 +02:00
serinko bff806e5f5 correction of typos 2023-08-07 12:40:28 +02:00
serinko f8b9bb7e78 correcting links, typos - doc finished 2023-08-07 12:38:10 +02:00
serinko 913095ee60 old typos edits 2023-08-07 12:36:19 +02:00
serinko d44b88842e scp automation tested - doc finished 2023-08-07 12:19:34 +02:00
serinko a67092ad17 correct go installation - guide finished 2023-08-07 12:08:18 +02:00
serinko 0b29e28e3f remove reduntant nym/docs/ 2023-08-04 13:19:29 +02:00
serinko f26f159bb0 filled/docs/validators.md 2023-08-04 13:18:12 +02:00
mfahampshire a8ddaddaf4 skeleton of NR page 2023-08-03 21:15:58 +02:00
mfahampshire 84741f2020 cont. 2023-08-03 19:51:03 +02:00
mfahampshire cc65236085 * deleted old setup guides
* added new info on operator guides
* adding stubs for in-depth node pages
2023-08-03 19:28:37 +02:00
mfahampshire e18c541400 added custom 404 + updated platform version 2023-08-03 19:28:13 +02:00
mfahampshire c1e8ebd46a typo fix 2023-08-03 16:46:05 +02:00
mfahampshire 0b6eb17793 * removed old wallet-address flag
* 'mixnode' -> 'mix node' for consistency in non-code / non-binary references
2023-08-03 16:43:58 +02:00
mfahampshire 10696ae4dc tweaked intro page 2023-08-03 16:31:45 +02:00
serinko 6395303466 #3674 feedback implemented 2023-08-02 10:40:26 +02:00
serinko 502a2d6a23 operators: plugins work, ready for final review 2023-08-02 08:04:57 +02:00
serinko 974cee1f22 operators: book built, no {comments} left, cmdrun and admonish not working 2023-08-01 17:37:12 +02:00
serinko 7ac3bb10cb reinit the book, delete *.html in /src 2023-08-01 16:43:57 +02:00
serinko 20d51437b5 reinitialized the book - simplified book.toml 2023-08-01 16:30:07 +02:00
serinko 1965df05e7 operators guide: book built 2023-08-01 11:04:11 +02:00
serinko 615c65cb22 operators guide: add src/binaries/ files, fix links 2023-08-01 10:58:29 +02:00
serinko 432af5a204 operators: typo edit 2023-07-31 13:53:21 +02:00
serinko ce87df3026 operators: comment missing info 2023-07-31 13:47:57 +02:00
serinko db407847e3 operators: book build - minor issues remain 2023-07-31 13:25:11 +02:00
serinko 02f5fa6816 faq.md: initial questions and answers - in progress 2023-07-28 13:22:40 +02:00
serinko 3aa9ad0197 corrected scp -3 option 2023-07-27 13:01:09 +02:00
serinko 7ccadffdba operators-guide:troubleshooting.md done - content ready to go out 2023-07-27 12:41:22 +02:00
serinko c120196be0 operators-guide: incorporated PR #3656 2023-07-26 12:55:05 +02:00
serinko f2a395fe42 operators-guide: create validator tutorial & add maintenance points 2023-07-26 11:46:36 +02:00
serinko cf79bdc098 operators-guide: create NR page & edit maintenance page 2023-07-24 12:53:32 +02:00
serinko cf71d655e2 operators-guide: moved repeating to maintenance.md, shortened and cleaned the existing guides 2023-07-14 19:21:25 +02:00
serinko 141b9d396c operator-guides: made todo notes 2023-07-14 17:17:07 +02:00
serinko ff65d052b8 operators-guide: created generic docs maintenance.md and preliminary-steps.md to avoid redundancy 2023-07-14 13:25:12 +02:00
serinko 153e899e0e mixnode-seup: minor edits 2023-07-14 11:20:51 +02:00
serinko 7e5c79848f feature/operators-guide: coppied all configs from ../docs/ 2023-07-13 16:59:25 +02:00
serinko 92b4dbb250 initilizing operators guides mdbook 2023-07-13 16:51:04 +02:00
408 changed files with 31183 additions and 3003 deletions
@@ -57,7 +57,7 @@ jobs:
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
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
@@ -98,7 +98,6 @@ jobs:
cp target/release/nym-network-requester $OUTPUT_DIR
cp target/release/nym-network-statistics $OUTPUT_DIR
cp target/release/nym-cli $OUTPUT_DIR
cp target/release/nym-credential-client $OUTPUT_DIR
cp target/release/explorer-api $OUTPUT_DIR
cp contracts/target/wasm32-unknown-unknown/release/mixnet_contract.wasm $OUTPUT_DIR
@@ -109,6 +108,7 @@ jobs:
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
+5 -1
View File
@@ -6,6 +6,7 @@ on:
- 'clients/**'
- 'common/**'
- 'explorer-api/**'
- 'ephemera/**'
- 'gateway/**'
- 'integrations/**'
- 'mixnode/**'
@@ -15,6 +16,7 @@ on:
- 'nym-api/**'
- 'nym-outfox/**'
- 'tools/nym-cli/**'
- 'tools/nym-nr-query/**'
- 'tools/ts-rs-cli/**'
- 'Cargo.toml'
pull_request:
@@ -22,6 +24,7 @@ on:
- 'clients/**'
- 'common/**'
- 'explorer-api/**'
- 'ephemera/**'
- 'gateway/**'
- 'integrations/**'
- 'mixnode/**'
@@ -31,6 +34,7 @@ on:
- 'nym-api/**'
- 'nym-outfox/**'
- 'tools/nym-cli/**'
- 'tools/nym-nr-query/**'
- 'tools/ts-rs-cli/**'
- 'Cargo.toml'
@@ -42,7 +46,7 @@ jobs:
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
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: Check out repository code
-76
View File
@@ -1,76 +0,0 @@
name: CD dev-portal
on:
push:
branches: master
paths:
- 'documentation/dev-portal/**'
jobs:
build:
runs-on: custom-runner-linux
steps:
- uses: actions/checkout@v3
- name: Install rsync
run: sudo apt-get install rsync
- uses: rlespinasse/github-slug-action@v3.x
- uses: actions/setup-node@v3
with:
node-version: 18
- name: Install Rust stable
uses: actions-rs/toolchain@v1
with:
toolchain: stable
- name: Install mdbook
run: (test -x $HOME/.cargo/bin/mdbook || cargo install --vers "^0.4" mdbook)
- name: Install mdbook plugins
run: |
cargo install --vers "^0.2.0" mdbook-variables && cargo install \
--vers "^1.8.0" mdbook-admonish && cargo install --vers \
"^0.1.2" mdbook-last-changed && cargo install --vers "^0.1.2" \
mdbook-theme && cargo install --vers "^0.7.7" mdbook-linkcheck
- name: Clean website
run: cd documentation/dev-portal && mdbook clean
- name: Build website
run: cd documentation/dev-portal && mdbook build
- name: Deploy branch master to dev
continue-on-error: true
uses: easingthemes/ssh-deploy@main
env:
SSH_PRIVATE_KEY: ${{ secrets.CD_WWW_SSH_PRIVATE_KEY }}
ARGS: "-rltgoDzvO --delete"
SOURCE: "documentation/dev-portal/book/html/"
REMOTE_HOST: ${{ secrets.CD_WWW_REMOTE_HOST_DEV }}
REMOTE_USER: ${{ secrets.CD_WWW_REMOTE_USER }}
TARGET: ${{ secrets.CD_WWW_REMOTE_TARGET_DEVP }}/
EXCLUDE: "/dist/, /node_modules/"
- name: Deploy branch master to prod
uses: easingthemes/ssh-deploy@main
env:
SSH_PRIVATE_KEY: ${{ secrets.CD_WWW_SSH_PRIVATE_KEY }}
ARGS: "-rltgoDzvO --delete"
SOURCE: "documentation/dev-portal/book/html/"
REMOTE_HOST: ${{ secrets.CD_WWW_REMOTE_HOST_PROD }}
REMOTE_USER: ${{ secrets.CD_WWW_REMOTE_USER }}
TARGET: ${{ secrets.CD_WWW_REMOTE_TARGET_DEVP }}/
EXCLUDE: "/dist/, /node_modules/"
- name: Matrix - Node Install
run: npm install
working-directory: .github/workflows/support-files
- name: Matrix - Send Notification
env:
NYM_NOTIFICATION_KIND: cd-dev
NYM_PROJECT_NAME: "Dev portal CD"
NYM_CI_WWW_BASE: "${{ secrets.NYM_CD_WWW_BASE }}"
NYM_CI_WWW_LOCATION: "${{ env.GITHUB_REF_SLUG }}"
GIT_COMMIT_MESSAGE: "${{ github.event.head_commit.message }}"
GIT_BRANCH: "${GITHUB_REF##*/}"
MATRIX_SERVER: "${{ secrets.MATRIX_SERVER }}"
MATRIX_ROOM: "${{ secrets.MATRIX_ROOM_DEVP }}"
MATRIX_USER_ID: "${{ secrets.MATRIX_USER_ID }}"
MATRIX_TOKEN: "${{ secrets.MATRIX_TOKEN }}"
MATRIX_DEVICE_ID: "${{ secrets.MATRIX_DEVICE_ID }}"
IS_SUCCESS: "${{ job.status == 'success' }}"
uses: docker://keybaseio/client:stable-node
with:
args: .github/workflows/support-files/notifications/entry_point.sh
+13 -13
View File
@@ -1,6 +1,7 @@
name: CD docs
on:
workflow_dispatch:
push:
branches: master
paths:
@@ -27,39 +28,38 @@ jobs:
command: build
args: --workspace --release --all
- name: Install mdbook
run: (test -x $HOME/.cargo/bin/mdbook || cargo install --vers "^0.4" mdbook)
run: (test -x $HOME/.cargo/bin/mdbook || cargo install --vers "^0.4.33" mdbook)
- name: Install mdbook plugins
run: |
cargo install --vers "^0.2.0" mdbook-variables && cargo install \
cargo install --vers "=0.2.2" mdbook-variables && cargo install \
--vers "^1.8.0" mdbook-admonish && cargo install --vers \
"^0.1.2" mdbook-last-changed && cargo install --vers "^0.1.2" \
mdbook-theme && cargo install --vers "^0.7.7" mdbook-linkcheck && \
cargo install --vers "^0.5.0" mdbook-cmdrun
- name: Clean website
run: cd documentation/docs && mdbook clean
- name: Build website
run: cd documentation/docs && mdbook build
"^0.1.2" mdbook-last-changed && cargo install --vers "^0.1.2" mdbook-theme \
&& cargo install --vers "^0.7.7" mdbook-linkcheck
- name: Build all projects in documentation/ & move to ~/dist/docs/
run: cd documentation && ./build_all_to_dist.sh
continue-on-error: false
- name: Deploy branch master to dev
continue-on-error: true
uses: easingthemes/ssh-deploy@main
env:
SSH_PRIVATE_KEY: ${{ secrets.CD_WWW_SSH_PRIVATE_KEY }}
ARGS: "-rltgoDzvO --delete"
SOURCE: "documentation/docs/book/"
SOURCE: "dist/docs/"
REMOTE_HOST: ${{ secrets.CD_WWW_REMOTE_HOST_DEV }}
REMOTE_USER: ${{ secrets.CD_WWW_REMOTE_USER }}
TARGET: ${{ secrets.CD_WWW_REMOTE_TARGET }}/
EXCLUDE: "/dist/, /node_modules/"
EXCLUDE: "/node_modules/"
- name: Deploy branch master to prod
if: github.ref == 'refs/heads/master'
uses: easingthemes/ssh-deploy@main
env:
SSH_PRIVATE_KEY: ${{ secrets.CD_WWW_SSH_PRIVATE_KEY }}
ARGS: "-rltgoDzvO --delete"
SOURCE: "documentation/docs/book/"
SOURCE: "dist/docs/"
REMOTE_HOST: ${{ secrets.CD_WWW_REMOTE_HOST_PROD }}
REMOTE_USER: ${{ secrets.CD_WWW_REMOTE_USER }}
TARGET: ${{ secrets.CD_WWW_REMOTE_TARGET }}/
EXCLUDE: "/dist/, /node_modules/"
EXCLUDE: "/node_modules/"
- name: Matrix - Node Install
run: npm install
working-directory: .github/workflows/support-files
-67
View File
@@ -1,67 +0,0 @@
name: CI dev-portal
on:
workflow_dispatch:
push:
branches-ignore: master
paths:
- 'documentation/dev-portal/**'
jobs:
build:
runs-on: custom-runner-linux
steps:
- uses: actions/checkout@v3
- name: Install rsync
run: sudo apt-get install rsync
- uses: rlespinasse/github-slug-action@v3.x
- uses: actions/setup-node@v3
with:
node-version: 18
- name: Install Rust stable
uses: actions-rs/toolchain@v1
with:
toolchain: stable
- name: Install mdbook
run: (test -x $HOME/.cargo/bin/mdbook || cargo install --vers "^0.4" mdbook)
- name: Install mdbook plugins
run: |
cargo install --vers "^0.2.0" mdbook-variables && cargo install \
--vers "^1.8.0" mdbook-admonish && cargo install --vers \
"^0.1.2" mdbook-last-changed && cargo install --vers "^0.1.2" mdbook-theme \
&& cargo install --vers "^0.7.7" mdbook-linkcheck
- name: Clean website
run: cd documentation/dev-portal && mdbook clean
- name: Build website
run: cd documentation/dev-portal && mdbook build
- name: Deploy branch to CI www
continue-on-error: true
uses: easingthemes/ssh-deploy@main
env:
SSH_PRIVATE_KEY: ${{ secrets.CI_WWW_SSH_PRIVATE_KEY }}
ARGS: "-rltgoDzvO --delete"
SOURCE: "documentation/dev-portal/book/html/"
REMOTE_HOST: ${{ secrets.CI_WWW_REMOTE_HOST }}
REMOTE_USER: ${{ secrets.CI_WWW_REMOTE_USER }}
TARGET: ${{ secrets.CI_WWW_REMOTE_TARGET }}/dev-portal-${{ env.GITHUB_REF_SLUG }}
EXCLUDE: "/dist/, /node_modules/"
- name: Matrix - Node Install
run: npm install
working-directory: .github/workflows/support-files
- name: Matrix - Send Notification
env:
NYM_NOTIFICATION_KIND: ci-dev
NYM_PROJECT_NAME: "Dev portal CI"
NYM_CI_WWW_BASE: "${{ secrets.NYM_CI_WWW_BASE }}"
NYM_CI_WWW_LOCATION: "dev-portal-${{ env.GITHUB_REF_SLUG }}"
GIT_COMMIT_MESSAGE: "${{ github.event.head_commit.message }}"
GIT_BRANCH: "${GITHUB_REF##*/}"
MATRIX_SERVER: "${{ secrets.MATRIX_SERVER }}"
MATRIX_ROOM: "${{ secrets.MATRIX_ROOM_DEVP }}"
MATRIX_USER_ID: "${{ secrets.MATRIX_USER_ID }}"
MATRIX_TOKEN: "${{ secrets.MATRIX_TOKEN }}"
MATRIX_DEVICE_ID: "${{ secrets.MATRIX_DEVICE_ID }}"
IS_SUCCESS: "${{ job.status == 'success' }}"
uses: docker://keybaseio/client:stable-node
with:
args: .github/workflows/support-files/notifications/entry_point.sh
+10 -11
View File
@@ -1,6 +1,7 @@
name: CI docs
on:
workflow_dispatch:
push:
branches-ignore: master
paths:
@@ -27,29 +28,27 @@ jobs:
command: build
args: --workspace --release --all
- name: Install mdbook
run: (test -x $HOME/.cargo/bin/mdbook || cargo install --vers "^0.4" mdbook)
run: (test -x $HOME/.cargo/bin/mdbook || cargo install --vers "^0.4.33" mdbook)
- name: Install mdbook plugins
run: |
cargo install --vers "^0.2.0" mdbook-variables && cargo install \
cargo install --vers "=0.2.2" mdbook-variables && cargo install \
--vers "^1.8.0" mdbook-admonish && cargo install --vers \
"^0.1.2" mdbook-last-changed && cargo install --vers "^0.1.2" \
mdbook-theme && cargo install --vers "^0.7.7" mdbook-linkcheck && \
cargo install --vers "^0.5.0" mdbook-cmdrun
- name: Clean website
run: cd documentation/docs && mdbook clean
- name: Build website
run: cd documentation/docs && mdbook build
"^0.1.2" mdbook-last-changed && cargo install --vers "^0.1.2" mdbook-theme \
&& cargo install --vers "^0.7.7" mdbook-linkcheck
- name: Build all projects in documentation/ & move to ~/dist/docs/
run: cd documentation && ./build_all_to_dist.sh
continue-on-error: false
- name: Deploy branch to CI www
continue-on-error: true
uses: easingthemes/ssh-deploy@main
env:
SSH_PRIVATE_KEY: ${{ secrets.CI_WWW_SSH_PRIVATE_KEY }}
ARGS: "-rltgoDzvO --delete"
SOURCE: "documentation/docs/book/"
SOURCE: "dist/docs/"
REMOTE_HOST: ${{ secrets.CI_WWW_REMOTE_HOST }}
REMOTE_USER: ${{ secrets.CI_WWW_REMOTE_USER }}
TARGET: ${{ secrets.CI_WWW_REMOTE_TARGET }}/docs-${{ env.GITHUB_REF_SLUG }}
EXCLUDE: "/dist/, /node_modules/"
EXCLUDE: "/node_modules/"
- name: Matrix - Node Install
run: npm install
working-directory: .github/workflows/support-files
+1 -1
View File
@@ -24,7 +24,7 @@ jobs:
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
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'
+1 -1
View File
@@ -37,7 +37,7 @@ jobs:
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
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'
@@ -100,6 +100,7 @@ jobs:
nym-connect/desktop/target/release/bundle/msi/*.msi.zip*
- id: release-info
name: Prepare release info
shell: bash
run: |
ref=${{ github.ref_name }}
semver="${ref##nym-connect-}" && semver="${semver##v}"
+20 -1
View File
@@ -25,7 +25,7 @@ jobs:
outputs:
release_id: ${{ steps.create-release.outputs.id }}
release_date: ${{ fromJSON(steps.create-release.outputs.assets)[0].published_at }}
release_date: ${{ fromJSON(steps.create-release.outputs.assets)[0].created_at }}
client_hash: ${{ steps.binary-hashes.outputs.client_hash }}
mixnode_hash: ${{ steps.binary-hashes.outputs.mixnode_hash }}
gateway_hash: ${{ steps.binary-hashes.outputs.gateway_hash }}
@@ -40,6 +40,7 @@ jobs:
netreq_version: ${{ steps.binary-versions.outputs.netreq_version }}
cli_version: ${{ steps.binary-versions.outputs.cli_version }}
netstat_version: ${{ steps.binary-versions.outputs.netstat_version }}
platform: ${{ steps.get-platform-version.outputs.platform }}"
steps:
- uses: actions/checkout@v3
@@ -96,6 +97,11 @@ jobs:
target/release/nym-network-statistics
target/release/nym-cli
- id: echo-outputs
name: echo output for assets
run: |
echo "data from release: $ ${{ steps.create-release.outputs }}"
- id: release-info
name: Prepare release info
run: |
@@ -124,6 +130,12 @@ jobs:
v=$(rg '^version = "(.*)"' -or '$1' tools/nym-cli/Cargo.toml) && echo "cli_version=$v" >> "$GITHUB_OUTPUT"
v=$(rg '^version = "(.*)"' -or '$1' service-providers/network-statistics/Cargo.toml) && echo "netstat_version=$v" >> "$GITHUB_OUTPUT"
- id: get-platform-version
name: get platform version
run: |
echo "::set-output name=platform::$(uname -r)"
push-release-data-client:
if: ${{ (startsWith(github.ref, 'refs/tags/nym-binaries-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
uses: ./.github/workflows/push-release-data.yml
@@ -139,6 +151,7 @@ jobs:
file_hash: ${{ needs.publish-nym.outputs.client_hash }}
name: Client
category: binaries
platform: "${{ needs.publish-nym.outputs.platform }}"
secrets: inherit
push-release-data-mixnode:
@@ -156,6 +169,7 @@ jobs:
file_hash: ${{ needs.publish-nym.outputs.mixnode_hash }}
name: Mixnode
category: binaries
platform: "${{ needs.publish-nym.outputs.platform }}"
secrets: inherit
push-release-data-gateway:
@@ -173,6 +187,7 @@ jobs:
file_hash: ${{ needs.publish-nym.outputs.gateway_hash }}
name: Gateway
category: binaries
platform: "${{ needs.publish-nym.outputs.platform }}"
secrets: inherit
push-release-data-socks5:
@@ -190,6 +205,7 @@ jobs:
file_hash: ${{ needs.publish-nym.outputs.socks5_hash }}
name: Socks5 Client
category: binaries
platform: "${{ needs.publish-nym.outputs.platform }}"
secrets: inherit
push-release-data-network-requester:
@@ -207,6 +223,7 @@ jobs:
file_hash: ${{ needs.publish-nym.outputs.netreq_hash }}
name: Network Requester
category: binaries
platform: "${{ needs.publish-nym.outputs.platform }}"
secrets: inherit
push-release-data-cli:
@@ -224,6 +241,7 @@ jobs:
file_hash: ${{ needs.publish-nym.outputs.cli_hash }}
name: Cli
category: binaries
platform: "${{ needs.publish-nym.outputs.platform }}"
secrets: inherit
push-release-data-network-stat:
@@ -241,4 +259,5 @@ jobs:
file_hash: ${{ needs.publish-nym.outputs.netstat_hash }}
name: Network Statistics
category: binaries
platform: "${{ needs.publish-nym.outputs.platform }}"
secrets: inherit
+1 -1
View File
@@ -32,5 +32,5 @@ jobs:
run: yarn
- name: Run tests
run: yarn test:qa
run: yarn test:sandbox
working-directory: nym-api/tests
-79
View File
@@ -1,79 +0,0 @@
name: Upload nyxd to CI
on:
workflow_dispatch:
jobs:
publish-nyxd:
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-builds/nyxd
run: |
rm -rf ci-builds || true
mkdir -p $OUTPUT_DIR
echo $OUTPUT_DIR
- name: Install Dependencies (Linux)
run: sudo apt-get update && sudo apt-get -y install build-essential curl wget libssl-dev libgtk-3-dev libudev-dev squashfs-tools git
continue-on-error: true
- name: Update env variables to include go
run: |
sudo rm -rf /usr/local/go
curl https://dl.google.com/go/go1.19.2.linux-amd64.tar.gz | sudo tar -C/usr/local -zxvf -
cat <<'EOF' >>$HOME/.profile
export GOROOT=/usr/local/go
export GOPATH=$HOME/go
export GO111MODULE=on
export PATH=$PATH:/usr/local/go/bin:$HOME/go/bin
EOF
source $HOME/.profile
- name: Verify Go is installed
run: go version
- name: Clone nyxd repo
run: |
git clone https://github.com/tommyv1987/nyxd
cd nyxd
git checkout release/v0.30.2
- name: Run nyxd
run: |
pwd
cd nyxd && make build
sleep 10
ls /home/runner/work/nym/nym/nyxd/build
- name: Prepare build output
shell: bash
env:
OUTPUT_DIR: ci-builds/nyxd
run: |
cp /home/runner/work/nym/nym/nyxd/build/nyxd $OUTPUT_DIR
WASMVM_SO=$(ldd /home/runner/work/nym/nym/nyxd/build/nyxd | grep "libwasm*" | awk '{ print $3 }')
ls $WASMVM_SO
sleep 3
cp $(echo $WASMVM_SO) $OUTPUT_DIR
- name: Deploy nyxd 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-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 -1
View File
@@ -31,7 +31,7 @@ jobs:
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
toolchain: 1.71.0
override: true
components: rustfmt, clippy
+15
View File
@@ -4,6 +4,21 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
## [Unreleased]
## [1.1.28] (2023-08-22)
- [final step3]: add [rust] support to nyxd client in wasm ([#3743])
- Feature/ephemera upgrade ([#3791])
- [rust-sdk] feat: make it more convenient to send and receive messages in different tasks ([#3756])
- feat: validator client refactoring + wasm compatible nyxd client ([#3726])
- feat: retain connection between client init and run ([#3767])
[#3743]: https://github.com/nymtech/nym/issues/3743
[#3791]: https://github.com/nymtech/nym/pull/3791
[#3756]: https://github.com/nymtech/nym/pull/3756
[#3726]: https://github.com/nymtech/nym/pull/3726
[#3767]: https://github.com/nymtech/nym/pull/3767
## [1.1.27] (2023-08-16)
- fix serialisation of contract types ([#3752])
Generated
+3401 -85
View File
File diff suppressed because it is too large Load Diff
+3 -1
View File
@@ -17,7 +17,6 @@ opt-level = 3
resolver = "2"
members = [
"clients/credential",
"clients/native",
"clients/native/websocket-requests",
"clients/socks5",
@@ -34,6 +33,7 @@ members = [
"common/cosmwasm-smart-contracts/coconut-bandwidth-contract",
"common/cosmwasm-smart-contracts/coconut-dkg",
"common/cosmwasm-smart-contracts/contracts-common",
"common/cosmwasm-smart-contracts/ephemera",
"common/cosmwasm-smart-contracts/group-contract",
"common/cosmwasm-smart-contracts/mixnet-contract",
"common/cosmwasm-smart-contracts/multisig-contract",
@@ -42,6 +42,7 @@ members = [
"common/cosmwasm-smart-contracts/vesting-contract",
"common/credential-storage",
"common/credentials",
"common/credential-utils",
"common/crypto",
"common/dkg",
"common/execute",
@@ -149,6 +150,7 @@ tap = "1.0.1"
tendermint-rpc = "0.32" # same version as used by cosmrs
thiserror = "1.0.38"
tokio = "1.24.1"
ts-rs = "7.0.0"
url = "2.4"
zeroize = "1.6.0"
-3
View File
@@ -77,9 +77,6 @@ $(eval $(call add_cargo_workspace,contracts,contracts,--lib --target wasm32-unkn
$(eval $(call add_cargo_workspace,wasm-client,clients/webassembly,--target wasm32-unknown-unknown))
$(eval $(call add_cargo_workspace,wallet,nym-wallet,))
$(eval $(call add_cargo_workspace,connect,nym-connect/desktop))
ifdef NYM_MOBILE
$(eval $(call add_cargo_workspace,connect-mobile,nym-connect/mobile/src-tauri))
endif
# -----------------------------------------------------------------------------
# Convenience targets for crates that are already part of the main workspace
-32
View File
@@ -1,32 +0,0 @@
<!--
Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
SPDX-License-Identifier: Apache-2.0
-->
## Credential binary
The credential binary is used to acquire coconut bandwidth credentials in exchange for nym tokens. Those credentials are stored in the client's `data` directory, so that they can be used as the client sees fit.
### Warning
The credential binary is still experimental software. The infrastructure for using it is not yet deployed to mainnet and it's still in the process of being deployed to sandbox.
### Building
From the project's root directory, run:
```
cargo build -p nym-credential-client
```
which generates the `nym-credential-client` binary in `target/debug/nym-credential-client`.
### Running
For example, you can get a credential worth 3 nym (3000000 unym) in a socks5 client that was already initialized like so:
```
./target/debug/nym-credential-client --config-env-file envs/sandbox.env --client-home-directory ~/.nym/socks5-clients/cred_client --nyxd-url https://sandbox-validator1.nymtech.net --mnemonic $MNEMONIC --recovery-dir /tmp/recovery --amount 3000000
```
More information regarding how to run the binary can be found by running it with the `--help` argument.
-55
View File
@@ -1,55 +0,0 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::error::Result;
use bip39::Mnemonic;
use nym_network_defaults::{NymNetworkDetails, VOUCHER_INFO};
use nym_validator_client::nyxd::contract_traits::CoconutBandwidthSigningClient;
use nym_validator_client::nyxd::{self, DirectSigningHttpRpcNyxdClient};
use nym_validator_client::nyxd::{Coin, Fee, NyxdClient};
use std::str::FromStr;
use url::Url;
pub(crate) struct Client {
nyxd_client: DirectSigningHttpRpcNyxdClient,
mix_denom_base: String,
}
impl Client {
pub fn new(nyxd_url: &str, mnemonic: &str) -> Self {
let nyxd_url = Url::from_str(nyxd_url).unwrap();
let mnemonic = Mnemonic::from_str(mnemonic).unwrap();
let network_details = NymNetworkDetails::new_from_env();
let config = nyxd::Config::try_from_nym_network_details(&network_details)
.expect("failed to construct valid validator client config with the provided network");
let nyxd_client =
NyxdClient::connect_with_mnemonic(config, nyxd_url.as_ref(), mnemonic, None).unwrap();
Client {
nyxd_client,
mix_denom_base: network_details.chain_details.mix_denom.base,
}
}
pub async fn deposit(
&self,
amount: u64,
verification_key: String,
encryption_key: String,
fee: Option<Fee>,
) -> Result<String> {
let amount = Coin::new(amount as u128, self.mix_denom_base.clone());
Ok(self
.nyxd_client
.deposit(
amount,
String::from(VOUCHER_INFO),
verification_key,
encryption_key,
fee,
)
.await?
.transaction_hash
.to_string())
}
}
-82
View File
@@ -1,82 +0,0 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use clap::{ArgGroup, Args, Subcommand};
use log::*;
use nym_bandwidth_controller::acquire::state::State;
use nym_bin_common::completions::ArgShell;
use nym_credential_storage::persistent_storage::PersistentStorage;
use nym_validator_client::nyxd::contract_traits::DkgQueryClient;
use crate::error::Result;
use crate::recovery_storage::RecoveryStorage;
#[derive(Subcommand)]
pub(crate) enum Command {
/// Run the binary to obtain a credential
Run(Run),
/// Generate shell completions
Completions(ArgShell),
/// Generate Fig specification
GenerateFigSpec,
}
#[derive(Args)]
#[clap(group(
ArgGroup::new("recov")
.required(true)
.args(&["amount", "recovery_mode"]),
))]
pub(crate) struct Run {
/// Home directory of the client that is supposed to use the credential.
#[clap(long)]
pub(crate) client_home_directory: std::path::PathBuf,
/// A mnemonic for the account that buys the credential
#[clap(long)]
pub(crate) mnemonic: String,
/// The amount of utokens the credential will hold. If recovery mode is enabled, this value
/// is not needed
#[clap(long, default_value = "0")]
pub(crate) amount: u64,
/// Path to a directory used to store recovery files for unconsumed deposits
#[clap(long)]
pub(crate) recovery_dir: std::path::PathBuf,
/// Recovery mode, when enabled, tries to recover any deposit data dumped in recovery_dir
#[clap(long)]
pub(crate) recovery_mode: bool,
}
pub(crate) async fn recover_credentials<C: DkgQueryClient + Send + Sync>(
client: &C,
recovery_storage: &RecoveryStorage,
shared_storage: &PersistentStorage,
) -> Result<()> {
for voucher in recovery_storage.unconsumed_vouchers()? {
let state = State::new(voucher);
if let Err(e) =
nym_bandwidth_controller::acquire::get_credential(&state, client, shared_storage).await
{
error!(
"Could not recover deposit {} due to {:?}, try again later",
state.voucher.tx_hash(),
e
)
} else {
info!(
"Converted deposit {} to a credential, removing recovery data for it",
state.voucher.tx_hash()
);
if let Err(e) = recovery_storage.remove_voucher(state.voucher.tx_hash().to_string()) {
warn!("Could not remove recovery data - {:?}", e);
}
}
}
Ok(())
}
-36
View File
@@ -1,36 +0,0 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use std::time::SystemTimeError;
use thiserror::Error;
use nym_credential_storage::error::StorageError;
use nym_credentials::error::Error as CredentialError;
use nym_validator_client::nyxd::error::NyxdError;
use nym_validator_client::ValidatorClientError;
pub type Result<T> = std::result::Result<T, CredentialClientError>;
#[derive(Error, Debug)]
pub enum CredentialClientError {
#[error("IO error: {0}")]
IOError(#[from] std::io::Error),
#[error("Bandwidth controller error: {0}")]
BandwidthControllerError(#[from] nym_bandwidth_controller::error::BandwidthControllerError),
#[error("Nyxd error: {0}")]
Nyxd(#[from] NyxdError),
#[error("Validator client error: {0}")]
ValidatorClientError(#[from] ValidatorClientError),
#[error("Credential error: {0}")]
Credential(#[from] CredentialError),
#[error("Could not use shared storage")]
SharedStorageError(#[from] StorageError),
#[error("Could not get system time")]
SysTimeError(#[from] SystemTimeError),
}
-131
View File
@@ -1,131 +0,0 @@
// Copyright 2022-2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
mod commands;
mod error;
mod recovery_storage;
use commands::*;
use error::Result;
use log::*;
use nym_bin_common::completions::fig_generate;
use nym_config::DEFAULT_DATA_DIR;
use nym_network_defaults::{setup_env, NymNetworkDetails};
use std::process::exit;
use std::time::{Duration, SystemTime};
use clap::{CommandFactory, Parser};
use nym_bin_common::logging::setup_logging;
use nym_client_core::config::disk_persistence::CommonClientPaths;
use nym_validator_client::nyxd::contract_traits::DkgQueryClient;
use nym_validator_client::nyxd::{Coin, Config};
use nym_validator_client::DirectSigningHttpRpcNyxdClient;
const SAFETY_BUFFER_SECS: u64 = 60; // 1 minute
#[derive(Parser)]
#[clap(author = "Nymtech", version, about)]
struct Cli {
/// Path pointing to an env file that configures the client.
#[clap(short, long)]
pub(crate) config_env_file: Option<std::path::PathBuf>,
#[clap(subcommand)]
pub(crate) command: Command,
}
async fn block_until_coconut_is_available<C: DkgQueryClient + Send + Sync>(
client: &C,
) -> Result<()> {
loop {
let epoch = client.get_current_epoch().await?;
let current_timestamp_secs = SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH)?
.as_secs();
if epoch.state.is_final() {
if current_timestamp_secs + SAFETY_BUFFER_SECS >= epoch.finish_timestamp.seconds() {
info!("In the next {} minute(s), a transition will take place in the coconut system. Deposits should be halted in this time for safety reasons.", SAFETY_BUFFER_SECS / 60);
exit(0);
}
break;
} else {
// Use 1 additional second to not start the next iteration immediately and spam get_current_epoch queries
let secs_until_final = epoch
.final_timestamp_secs()
.saturating_sub(current_timestamp_secs)
+ 1;
info!("Approximately {} seconds until coconut is available. Sleeping until then. You can safely kill the process at any moment.", secs_until_final);
std::thread::sleep(Duration::from_secs(secs_until_final));
}
}
Ok(())
}
#[tokio::main]
async fn main() -> Result<()> {
let args = Cli::parse();
setup_logging();
setup_env(args.config_env_file.as_ref());
let bin_name = "nym-credential-client";
match args.command {
Command::Run(r) => {
// we assume the structure of <home-dir>/data
let data_dir = r.client_home_directory.join(DEFAULT_DATA_DIR);
let paths = CommonClientPaths::new_default(data_dir);
let db_path = paths.credentials_database;
let shared_storage =
nym_credential_storage::initialise_persistent_storage(db_path).await;
let recovery_storage = recovery_storage::RecoveryStorage::new(r.recovery_dir)?;
let network_details = NymNetworkDetails::new_from_env();
let config = Config::try_from_nym_network_details(&network_details).expect(
"failed to construct valid validator client config with the provided network",
);
let amount = Coin::new(
r.amount as u128,
network_details.chain_details.mix_denom.base,
);
let endpoint = network_details.endpoints[0].nyxd_url.as_str();
let client = DirectSigningHttpRpcNyxdClient::connect_with_mnemonic(
config,
endpoint,
r.mnemonic.parse().unwrap(),
)?;
block_until_coconut_is_available(&client).await?;
info!("Starting depositing funds, don't kill the process");
if !r.recovery_mode {
let state = nym_bandwidth_controller::acquire::deposit(&client, amount).await?;
if nym_bandwidth_controller::acquire::get_credential(
&state,
&client,
&shared_storage,
)
.await
.is_err()
{
warn!("Failed to obtain credential. Dumping recovery data.",);
match recovery_storage.insert_voucher(&state.voucher) {
Ok(file_path) => {
warn!("Dumped recovery data to {:?}. Try using recovery mode to convert it to a credential", file_path);
}
Err(e) => {
error!("Could not dump recovery data to file system due to {:?}, the deposit will be lost!", e)
}
}
}
} else {
recover_credentials(&client, &recovery_storage, &shared_storage).await?;
}
}
Command::Completions(c) => c.generate(&mut Cli::command(), bin_name),
Command::GenerateFigSpec => fig_generate(&mut Cli::command(), bin_name),
}
Ok(())
}
@@ -1,56 +0,0 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use nym_credentials::coconut::bandwidth::BandwidthVoucher;
use std::fs::{create_dir_all, read_dir, File};
use std::io::{Read, Write};
use std::path::PathBuf;
pub struct RecoveryStorage {
recovery_dir: PathBuf,
}
impl RecoveryStorage {
pub fn new(recovery_dir: PathBuf) -> std::io::Result<Self> {
create_dir_all(&recovery_dir)?;
Ok(Self { recovery_dir })
}
pub fn unconsumed_vouchers(&self) -> std::io::Result<impl Iterator<Item = BandwidthVoucher>> {
Ok(read_dir(&self.recovery_dir)?
.filter_map(|entry| entry.ok())
.filter_map(|entry| {
let path = entry.path();
if path.is_file() {
Some(path)
} else {
None
}
})
.filter_map(|path| File::open(path).ok())
.filter_map(|mut f| {
let mut buff = Vec::new();
if f.read_to_end(&mut buff).is_ok() {
Some(buff)
} else {
None
}
})
.filter_map(|buff| BandwidthVoucher::try_from_bytes(&buff).ok()))
}
pub fn insert_voucher(&self, voucher: &BandwidthVoucher) -> std::io::Result<PathBuf> {
let file_name = voucher.tx_hash().to_string();
let file_path = self.recovery_dir.join(file_name);
let mut file = File::create(&file_path)?;
let buff = voucher.to_bytes();
file.write_all(&buff)?;
Ok(file_path)
}
pub fn remove_voucher(&self, file_name: String) -> std::io::Result<()> {
let file_path = self.recovery_dir.join(file_name);
std::fs::remove_file(file_path)
}
}
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "nym-client"
version = "1.1.25"
version = "1.1.26"
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"]
description = "Implementation of the Nym Client"
edition = "2021"
@@ -105,10 +105,10 @@ impl ClientRequest {
let conn_id_bytes = connection_id.unwrap_or(0).to_be_bytes();
std::iter::once(ClientRequestTag::Send as u8)
.chain(recipient.to_bytes().into_iter()) // will not be length prefixed because the length is constant
.chain(conn_id_bytes.into_iter())
.chain(data_len_bytes.into_iter())
.chain(data.into_iter())
.chain(recipient.to_bytes()) // will not be length prefixed because the length is constant
.chain(conn_id_bytes)
.chain(data_len_bytes)
.chain(data)
.collect()
}
@@ -180,11 +180,11 @@ impl ClientRequest {
let conn_id_bytes = connection_id.unwrap_or(0).to_be_bytes();
std::iter::once(ClientRequestTag::SendAnonymous as u8)
.chain(reply_surbs.to_be_bytes().into_iter())
.chain(recipient.to_bytes().into_iter()) // will not be length prefixed because the length is constant
.chain(conn_id_bytes.into_iter())
.chain(data_len_bytes.into_iter())
.chain(data.into_iter())
.chain(reply_surbs.to_be_bytes())
.chain(recipient.to_bytes()) // will not be length prefixed because the length is constant
.chain(conn_id_bytes)
.chain(data_len_bytes)
.chain(data)
.collect()
}
@@ -258,10 +258,10 @@ impl ClientRequest {
let conn_id_bytes = connection_id.unwrap_or(0).to_be_bytes();
std::iter::once(ClientRequestTag::Reply as u8)
.chain(sender_tag.to_bytes().into_iter())
.chain(conn_id_bytes.into_iter())
.chain(message_len_bytes.into_iter())
.chain(message.into_iter())
.chain(sender_tag.to_bytes())
.chain(conn_id_bytes)
.chain(message_len_bytes)
.chain(message)
.collect()
}
@@ -332,7 +332,7 @@ impl ClientRequest {
fn serialize_closed_connection(connection_id: u64) -> Vec<u8> {
let conn_id_bytes = connection_id.to_be_bytes();
std::iter::once(ClientRequestTag::ClosedConnection as u8)
.chain(conn_id_bytes.into_iter())
.chain(conn_id_bytes)
.collect()
}
@@ -359,7 +359,7 @@ impl ClientRequest {
fn serialize_get_lane_queue_lengths(connection_id: u64) -> Vec<u8> {
let conn_id_bytes = connection_id.to_be_bytes();
std::iter::once(ClientRequestTag::GetLaneQueueLength as u8)
.chain(conn_id_bytes.into_iter())
.chain(conn_id_bytes)
.collect()
}
@@ -67,15 +67,15 @@ impl ServerResponse {
if let Some(sender_tag) = reconstructed_message.sender_tag {
std::iter::once(ServerResponseTag::Received as u8)
.chain(std::iter::once(true as u8))
.chain(sender_tag.to_bytes().into_iter())
.chain(sender_tag.to_bytes())
.chain(message_len_bytes.iter().cloned())
.chain(reconstructed_message.message.into_iter())
.chain(reconstructed_message.message)
.collect()
} else {
std::iter::once(ServerResponseTag::Received as u8)
.chain(std::iter::once(false as u8))
.chain(message_len_bytes.iter().cloned())
.chain(reconstructed_message.message.into_iter())
.chain(reconstructed_message.message)
.collect()
}
}
@@ -149,7 +149,7 @@ impl ServerResponse {
// SELF_ADDRESS_RESPONSE_TAG || self_address
fn serialize_self_address(address: Recipient) -> Vec<u8> {
std::iter::once(ServerResponseTag::SelfAddress as u8)
.chain(address.to_bytes().into_iter())
.chain(address.to_bytes())
.collect()
}
@@ -211,8 +211,8 @@ impl ServerResponse {
let message_len_bytes = (error.message.len() as u64).to_be_bytes();
std::iter::once(ServerResponseTag::Error as u8)
.chain(std::iter::once(error.kind as u8))
.chain(message_len_bytes.into_iter())
.chain(error.message.into_bytes().into_iter())
.chain(message_len_bytes)
.chain(error.message.into_bytes())
.collect()
}
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "nym-socks5-client"
version = "1.1.25"
version = "1.1.26"
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"
+12 -4
View File
@@ -17,7 +17,7 @@ use nym_client_core::client::base_client::storage::gateway_details::{
};
use nym_client_core::client::key_manager::persistence::OnDiskKeys;
use nym_client_core::client::topology_control::geo_aware_provider::CountryGroup;
use nym_client_core::config::{GatewayEndpointConfig, TopologyStructure};
use nym_client_core::config::{GatewayEndpointConfig, GroupBy, TopologyStructure};
use nym_client_core::error::ClientCoreError;
use nym_config::OptionalSet;
use nym_sphinx::params::{PacketSize, PacketType};
@@ -101,9 +101,17 @@ pub(crate) fn override_config(config: Config, args: OverrideConfig) -> Config {
let secondary_packet_size = args.medium_toggle.then_some(PacketSize::ExtendedPacket16);
let no_per_hop_delays = args.medium_toggle;
let topology_structure = if args.medium_toggle || args.geo_routing.is_some() {
// TODO: rethink the default group. I just picked one for now.
TopologyStructure::GeoAware(args.geo_routing.unwrap_or(CountryGroup::Europe))
let topology_structure = if args.medium_toggle {
// Use the location of the network-requester
let address = config
.core
.socks5
.provider_mix_address
.parse()
.expect("failed to parse provider mix address");
TopologyStructure::GeoAware(GroupBy::NymAddress(address))
} else if let Some(code) = args.geo_routing {
TopologyStructure::GeoAware(GroupBy::CountryGroup(code))
} else {
TopologyStructure::default()
};
+13
View File
@@ -2503,6 +2503,7 @@ version = "1.1.15"
dependencies = [
"async-trait",
"base64 0.21.2",
"cfg-if 1.0.0",
"dashmap",
"dirs 4.0.0",
"futures",
@@ -2676,6 +2677,7 @@ version = "0.1.0"
dependencies = [
"bls12_381 0.5.0",
"cosmrs",
"log",
"nym-api-requests",
"nym-coconut-interface",
"nym-crypto",
@@ -2729,6 +2731,16 @@ dependencies = [
"zeroize",
]
[[package]]
name = "nym-ephemera-common"
version = "0.1.0"
dependencies = [
"cosmwasm-schema",
"cosmwasm-std",
"cw-utils",
"nym-contracts-common",
]
[[package]]
name = "nym-explorer-api-requests"
version = "0.1.0"
@@ -3145,6 +3157,7 @@ dependencies = [
"nym-coconut-interface",
"nym-config",
"nym-contracts-common",
"nym-ephemera-common",
"nym-group-contract-common",
"nym-mixnet-contract-common",
"nym-multisig-contract-common",
+2 -2
View File
@@ -114,7 +114,7 @@ impl WasmTopologyExt for Arc<ClientState> {
let this = Arc::clone(self);
future_to_promise(async move {
let Some(current_topology) = this.topology_accessor.current_topology().await else {
return Err(WasmClientError::UnavailableNetworkTopology.into())
return Err(WasmClientError::UnavailableNetworkTopology.into());
};
match current_topology.find_mix_by_identity(&mixnode_identity) {
@@ -135,7 +135,7 @@ impl WasmTopologyExt for Arc<ClientState> {
let this = Arc::clone(self);
future_to_promise(async move {
let Some(current_topology) = this.topology_accessor.current_topology().await else {
return Err(WasmClientError::UnavailableNetworkTopology.into())
return Err(WasmClientError::UnavailableNetworkTopology.into());
};
let Some(mix) = current_topology.find_mix_by_identity(&mixnode_identity) else {
@@ -52,7 +52,7 @@ pub fn encode_payload_with_headers(
Ok(metadata) => {
let metadata = metadata.as_bytes().to_vec();
let size = (metadata.len() as u64).to_be_bytes().to_vec();
Ok(vec![size, metadata, payload].concat())
Ok([size, metadata, payload].concat())
}
Err(e) => Err(JsValue::from(JsError::new(
format!("Could not encode message: {}", e).as_str(),
+4
View File
@@ -1,6 +1,10 @@
// 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")]
@@ -58,7 +58,7 @@ impl<'a> EphemeralTestReceiver<'a> {
let Some(received_packet) = packet else {
// can't do anything more...
console_error!("packet receiver has stopped processing results!");
return true
return true;
};
match received_packet {
Received::Message(msg) => {
+1
View File
@@ -10,6 +10,7 @@ rust-version = "1.66"
[dependencies]
async-trait = { workspace = true }
base64 = "0.21.2"
cfg-if = "1.0.0"
dashmap = "5.4.0"
dirs = "4.0"
futures = { workspace = true }
@@ -354,11 +354,13 @@ where
nym_api_urls,
env!("CARGO_PKG_VERSION").to_string(),
)),
config::TopologyStructure::GeoAware(group) => Box::new(GeoAwareTopologyProvider::new(
nym_api_urls,
env!("CARGO_PKG_VERSION").to_string(),
group,
)),
config::TopologyStructure::GeoAware(group_by) => {
Box::new(GeoAwareTopologyProvider::new(
nym_api_urls,
env!("CARGO_PKG_VERSION").to_string(),
group_by,
))
}
})
}
@@ -1,23 +1,48 @@
use std::{collections::HashMap, fmt};
use log::{debug, error, info};
use nym_explorer_api_requests::PrettyDetailedMixNodeBond;
use nym_explorer_api_requests::{PrettyDetailedGatewayBond, PrettyDetailedMixNodeBond};
use nym_network_defaults::var_names::EXPLORER_API;
use nym_topology::{
nym_topology_from_detailed,
provider_trait::{async_trait, TopologyProvider},
NymTopology,
};
use nym_validator_client::client::MixId;
use nym_validator_client::client::{IdentityKey, MixId};
use rand::{prelude::SliceRandom, thread_rng};
use serde::{Deserialize, Serialize};
use tap::TapOptional;
use url::Url;
use crate::config::GroupBy;
const MIN_NODES_PER_LAYER: usize = 1;
const EXPLORER_API_MIXNODES_URL: &str = "https://explorer.nymtech.net/api/v1/mix-nodes";
#[cfg(target_arch = "wasm32")]
fn reqwest_client() -> Option<reqwest::Client> {
reqwest::Client::builder().build().ok()
}
#[cfg(not(target_arch = "wasm32"))]
fn reqwest_client() -> Option<reqwest::Client> {
reqwest::Client::builder()
.timeout(std::time::Duration::from_secs(5))
.build()
.ok()
}
// TODO: create a explorer-api-client
async fn fetch_mixnodes_from_explorer_api() -> Option<Vec<PrettyDetailedMixNodeBond>> {
reqwest::get(EXPLORER_API_MIXNODES_URL)
let explorer_api_url = std::env::var(EXPLORER_API).ok()?;
let explorer_api_url = Url::parse(&explorer_api_url)
.ok()?
.join("v1/mix-nodes")
.ok()?;
debug!("Fetching: {}", explorer_api_url);
reqwest_client()?
.get(explorer_api_url)
.send()
.await
.ok()?
.json::<Vec<PrettyDetailedMixNodeBond>>()
@@ -25,6 +50,25 @@ async fn fetch_mixnodes_from_explorer_api() -> Option<Vec<PrettyDetailedMixNodeB
.ok()
}
// TODO: create a explorer-api-client
async fn fetch_gateways_from_explorer_api() -> Option<Vec<PrettyDetailedGatewayBond>> {
let explorer_api_url = std::env::var(EXPLORER_API).ok()?;
let explorer_api_url = Url::parse(&explorer_api_url)
.ok()?
.join("v1/gateways")
.ok()?;
debug!("Fetching: {}", explorer_api_url);
reqwest_client()?
.get(explorer_api_url)
.send()
.await
.ok()?
.json::<Vec<PrettyDetailedGatewayBond>>()
.await
.ok()
}
#[derive(Copy, Clone, Hash, PartialEq, Eq, Serialize, Deserialize, Debug)]
pub enum CountryGroup {
Europe,
@@ -191,6 +235,23 @@ fn group_mixnodes_by_country_code(
})
}
fn group_gateways_by_country_code(
gateways: Vec<PrettyDetailedGatewayBond>,
) -> HashMap<CountryGroup, Vec<IdentityKey>> {
gateways.into_iter().fold(
HashMap::<CountryGroup, Vec<IdentityKey>>::new(),
|mut acc, g| {
if let Some(ref location) = g.location {
let country_code = location.two_letter_iso_country_code.clone();
let group_code = CountryGroup::new(country_code.as_str());
let gateways = acc.entry(group_code).or_insert_with(Vec::new);
gateways.push(g.gateway.identity_key)
}
acc
},
)
}
fn log_mixnode_distribution(mixnodes: &HashMap<CountryGroup, Vec<MixId>>) {
let mixnode_distribution = mixnodes
.iter()
@@ -200,6 +261,15 @@ fn log_mixnode_distribution(mixnodes: &HashMap<CountryGroup, Vec<MixId>>) {
debug!("Mixnode distribution - {}", mixnode_distribution);
}
fn log_gateway_distribution(gateways: &HashMap<CountryGroup, Vec<IdentityKey>>) {
let gateway_distribution = gateways
.iter()
.map(|(k, v)| format!("{}: {}", k, v.len()))
.collect::<Vec<_>>()
.join(", ");
debug!("Gateway distribution - {}", gateway_distribution);
}
fn check_layer_integrity(topology: NymTopology) -> Result<(), ()> {
let mixes = topology.mixes();
if mixes.keys().len() < 3 {
@@ -222,7 +292,7 @@ fn check_layer_integrity(topology: NymTopology) -> Result<(), ()> {
pub struct GeoAwareTopologyProvider {
validator_client: nym_validator_client::client::NymApiClient,
filter_on: CountryGroup,
filter_on: GroupBy,
client_version: String,
}
@@ -230,7 +300,7 @@ impl GeoAwareTopologyProvider {
pub fn new(
mut nym_api_urls: Vec<Url>,
client_version: String,
filter_on: CountryGroup,
filter_on: GroupBy,
) -> GeoAwareTopologyProvider {
log::info!(
"Creating geo-aware topology provider with filter on {:?}",
@@ -272,6 +342,38 @@ impl GeoAwareTopologyProvider {
return None;
};
debug!("Fetching gateways from explorer-api...");
let Some(gateways_from_explorer_api) = fetch_gateways_from_explorer_api().await else {
error!("failed to get mixnodes from explorer-api");
return None;
};
// Determine what we should filter around
let filter_on = match self.filter_on {
GroupBy::CountryGroup(group) => group,
GroupBy::NymAddress(recipient) => {
// Convert recipient into a country group by extracting out the gateway part and
// using that as the country code.
let gateway = recipient.gateway().to_base58_string();
// Lookup the location of this gateway by using the location data from the
// explorer-api
let gateway_location = gateways_from_explorer_api
.iter()
.find(|g| g.gateway.identity_key == gateway)
.and_then(|g| g.location.clone())
.map(|location| location.two_letter_iso_country_code)
.tap_none(|| error!("No location found for the gateway: {}", gateway))?;
debug!(
"Filtering on nym-address: {}, with location: {}",
recipient, gateway_location
);
CountryGroup::new(&gateway_location)
}
};
debug!("Filter group: {}", filter_on);
// Partition mixnodes_from_explorer_api according to the value of
// two_letter_iso_country_code.
// NOTE: we construct the full distribution here, but only use the one we're interested in.
@@ -280,8 +382,16 @@ impl GeoAwareTopologyProvider {
let mixnode_distribution = group_mixnodes_by_country_code(mixnodes_from_explorer_api);
log_mixnode_distribution(&mixnode_distribution);
let Some(filtered_mixnode_ids) = mixnode_distribution.get(&self.filter_on) else {
error!("no mixnodes found for: {}", self.filter_on);
let gateway_distribution = group_gateways_by_country_code(gateways_from_explorer_api);
log_gateway_distribution(&gateway_distribution);
let Some(filtered_mixnode_ids) = mixnode_distribution.get(&filter_on) else {
error!("no mixnodes found for: {}", filter_on);
return None;
};
let Some(filtered_gateway_ids) = gateway_distribution.get(&filter_on) else {
error!("no gateways found for: {}", filter_on);
return None;
};
@@ -290,6 +400,11 @@ impl GeoAwareTopologyProvider {
.filter(|m| filtered_mixnode_ids.contains(&m.mix_id()))
.collect::<Vec<_>>();
let gateways = gateways
.into_iter()
.filter(|g| filtered_gateway_ids.contains(g.identity()))
.collect::<Vec<_>>();
let topology = nym_topology_from_detailed(mixnodes, gateways)
.filter_system_version(&self.client_version);
+13 -2
View File
@@ -3,7 +3,10 @@
use nym_config::defaults::NymNetworkDetails;
use nym_crypto::asymmetric::identity;
use nym_sphinx::params::{PacketSize, PacketType};
use nym_sphinx::{
addressing::clients::Recipient,
params::{PacketSize, PacketType},
};
use serde::{Deserialize, Serialize};
use std::time::Duration;
use url::Url;
@@ -480,11 +483,19 @@ pub struct Topology {
pub topology_structure: TopologyStructure,
}
#[allow(clippy::large_enum_variant)]
#[derive(Default, Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum TopologyStructure {
#[default]
NymApi,
GeoAware(CountryGroup),
GeoAware(GroupBy),
}
#[allow(clippy::large_enum_variant)]
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum GroupBy {
CountryGroup(CountryGroup),
NymAddress(Recipient),
}
impl Default for Topology {
@@ -13,6 +13,7 @@ colored = "2.0"
nym-coconut-dkg-common = { path = "../../cosmwasm-smart-contracts/coconut-dkg" }
nym-contracts-common = { path = "../../cosmwasm-smart-contracts/contracts-common" }
nym-ephemera-common = { path = "../../cosmwasm-smart-contracts/ephemera" }
nym-mixnet-contract-common = { path = "../../cosmwasm-smart-contracts/mixnet-contract" }
nym-vesting-contract-common = { path = "../../cosmwasm-smart-contracts/vesting-contract" }
nym-coconut-bandwidth-contract-common = { path = "../../cosmwasm-smart-contracts/coconut-bandwidth-contract" }
@@ -64,7 +65,7 @@ features = ["tokio"]
[dev-dependencies]
bip39 = { workspace = true }
cosmrs = { workspace = true, features = ["bip32"] }
ts-rs = "6.1.2"
ts-rs = { workspace = true }
[[example]]
name = "offline_signing"
@@ -2,9 +2,9 @@
// SPDX-License-Identifier: Apache-2.0
use cosmrs::bank::MsgSend;
use cosmrs::rpc::HttpClient;
use cosmrs::tx::Msg;
use cosmrs::{tx, AccountId, Coin, Denom};
use nym_validator_client::http_client;
use nym_validator_client::nyxd::CosmWasmClient;
use nym_validator_client::signing::direct_wallet::DirectSecp256k1HdWallet;
use nym_validator_client::signing::tx_signer::TxSigner;
@@ -27,7 +27,7 @@ async fn main() {
// possibly remote client that doesn't do ANY signing
// (only broadcasts + queries for sequence numbers)
let broadcaster = HttpClient::new(validator).unwrap();
let broadcaster = http_client(validator).unwrap();
// get signer information
let sequence_response = broadcaster.get_sequence(&signer_address).await.unwrap();
@@ -9,7 +9,7 @@ use nym_validator_client::nyxd::contract_traits::{
#[tokio::main]
async fn main() {
setup_env(Some(&"../../../envs/qa-qwerty.env".parse().unwrap()));
setup_env(Some("../../../envs/qa-qwerty.env"));
let network_details = NymNetworkDetails::new_from_env();
let config =
nym_validator_client::Config::try_from_nym_network_details(&network_details).unwrap();
@@ -9,7 +9,7 @@ use nym_validator_client::nyxd::contract_traits::{
#[tokio::main]
async fn main() {
setup_env(Some(&"../../../envs/qa-qwerty.env".parse().unwrap()));
setup_env(Some("../../../envs/qa-qwerty.env"));
let network_details = NymNetworkDetails::new_from_env();
let config =
nym_validator_client::Config::try_from_nym_network_details(&network_details).unwrap();
@@ -26,6 +26,8 @@ pub use nym_mixnet_contract_common::{
// re-export the type to not break existing imports
pub use crate::coconut::CoconutApiClient;
#[cfg(feature = "http-client")]
use crate::rpc::http_client;
#[cfg(feature = "http-client")]
use crate::{DirectSigningHttpRpcValidatorClient, HttpRpcClient, QueryHttpRpcValidatorClient};
@@ -95,7 +97,7 @@ impl Client<HttpRpcClient, DirectSecp256k1HdWallet> {
config: Config,
mnemonic: bip39::Mnemonic,
) -> Result<DirectSigningHttpRpcValidatorClient, ValidatorClientError> {
let rpc_client = HttpRpcClient::new(config.nyxd_url.as_str())?;
let rpc_client = http_client(config.nyxd_url.as_str())?;
let prefix = &config.nyxd_config.chain_details.bech32_account_prefix;
let wallet = DirectSecp256k1HdWallet::from_mnemonic(prefix, mnemonic);
@@ -126,7 +128,7 @@ impl Client<ReqwestRpcClient, DirectSecp256k1HdWallet> {
#[cfg(feature = "http-client")]
impl Client<HttpRpcClient> {
pub fn new_query(config: Config) -> Result<QueryHttpRpcValidatorClient, ValidatorClientError> {
let rpc_client = HttpRpcClient::new(config.nyxd_url.as_str())?;
let rpc_client = http_client(config.nyxd_url.as_str())?;
Ok(Self::new_with_rpc_client(config, rpc_client))
}
@@ -170,6 +172,10 @@ impl<C, S> Client<C, S> {
// validator-api wrappers
impl<C, S> Client<C, S> {
pub fn api_url(&self) -> &Url {
self.nym_api.current_url()
}
pub fn change_nym_api(&mut self, new_endpoint: Url) {
self.nym_api.change_url(new_endpoint)
}
@@ -240,6 +246,10 @@ impl NymApiClient {
NymApiClient { nym_api }
}
pub fn api_url(&self) -> &Url {
self.nym_api.current_url()
}
pub fn change_nym_api(&mut self, new_endpoint: Url) {
self.nym_api.change_url(new_endpoint);
}
@@ -20,6 +20,8 @@ pub use nym_api_requests::*;
#[cfg(feature = "http-client")]
pub use cosmrs::rpc::HttpClient as HttpRpcClient;
#[cfg(feature = "http-client")]
pub use rpc::http_client;
// some type aliasing
@@ -0,0 +1,79 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::collect_paged;
use crate::nyxd::contract_traits::NymContractsProvider;
use crate::nyxd::error::NyxdError;
use crate::nyxd::CosmWasmClient;
use async_trait::async_trait;
use nym_ephemera_common::msg::QueryMsg as EphemeraQueryMsg;
use nym_ephemera_common::peers::PagedPeerResponse;
use nym_ephemera_common::types::JsonPeerInfo;
use serde::Deserialize;
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
pub trait EphemeraQueryClient {
async fn query_ephemera_contract<T>(&self, query: EphemeraQueryMsg) -> Result<T, NyxdError>
where
for<'a> T: Deserialize<'a>;
async fn get_peers_paged(
&self,
start_after: Option<String>,
limit: Option<u32>,
) -> Result<PagedPeerResponse, NyxdError> {
let request = EphemeraQueryMsg::GetPeers { start_after, limit };
self.query_ephemera_contract(request).await
}
}
// extension trait to the query client to deal with the paged queries
// (it didn't feel appropriate to combine it with the existing trait
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
pub trait PagedEphemeraQueryClient: EphemeraQueryClient {
async fn get_all_ephemera_peers(&self) -> Result<Vec<JsonPeerInfo>, NyxdError> {
collect_paged!(self, get_peers_paged, peers)
}
}
#[async_trait]
impl<T> PagedEphemeraQueryClient for T where T: EphemeraQueryClient {}
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
impl<C> EphemeraQueryClient for C
where
C: CosmWasmClient + NymContractsProvider + Send + Sync,
{
async fn query_ephemera_contract<T>(&self, query: EphemeraQueryMsg) -> Result<T, NyxdError>
where
for<'a> T: Deserialize<'a>,
{
let ephemera_contract_address = &self
.ephemera_contract_address()
.ok_or_else(|| NyxdError::unavailable_contract_address("ephemera contract"))?;
self.query_contract_smart(ephemera_contract_address, &query)
.await
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::nyxd::contract_traits::tests::IgnoreValue;
// it's enough that this compiles and clippy is happy about it
#[allow(dead_code)]
fn all_query_variants_are_covered<C: EphemeraQueryClient + Send + Sync>(
client: C,
msg: EphemeraQueryMsg,
) {
match msg {
EphemeraQueryMsg::GetPeers { limit, start_after } => {
client.get_peers_paged(start_after, limit).ignore()
}
};
}
}
@@ -0,0 +1,86 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::nyxd::contract_traits::NymContractsProvider;
use crate::nyxd::cosmwasm_client::types::ExecuteResult;
use crate::nyxd::error::NyxdError;
use crate::nyxd::{Coin, Fee, SigningCosmWasmClient};
use crate::signing::signer::OfflineSigner;
use async_trait::async_trait;
use nym_ephemera_common::msg::ExecuteMsg as EphemeraExecuteMsg;
use nym_ephemera_common::types::JsonPeerInfo;
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
pub trait EphemeraSigningClient {
async fn execute_ephemera_contract(
&self,
fee: Option<Fee>,
msg: EphemeraExecuteMsg,
memo: String,
funds: Vec<Coin>,
) -> Result<ExecuteResult, NyxdError>;
async fn register_as_peer(
&self,
peer_info: JsonPeerInfo,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
let req = EphemeraExecuteMsg::RegisterPeer { peer_info };
self.execute_ephemera_contract(fee, req, "registering as peer".to_string(), vec![])
.await
}
}
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
impl<C> EphemeraSigningClient for C
where
C: SigningCosmWasmClient + NymContractsProvider + Sync,
NyxdError: From<<Self as OfflineSigner>::Error>,
{
async fn execute_ephemera_contract(
&self,
fee: Option<Fee>,
msg: EphemeraExecuteMsg,
memo: String,
funds: Vec<Coin>,
) -> Result<ExecuteResult, NyxdError> {
let ephemera_contract_address = self
.ephemera_contract_address()
.ok_or_else(|| NyxdError::unavailable_contract_address("ephemera contract"))?;
let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier())));
let signer_address = &self.signer_addresses()?[0];
self.execute(
signer_address,
ephemera_contract_address,
&msg,
fee,
memo,
funds,
)
.await
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::nyxd::contract_traits::tests::IgnoreValue;
// it's enough that this compiles and clippy is happy about it
#[allow(dead_code)]
fn all_execute_variants_are_covered<C: EphemeraSigningClient + Send + Sync>(
client: C,
msg: EphemeraExecuteMsg,
) {
match msg {
EphemeraExecuteMsg::RegisterPeer { peer_info } => {
client.register_as_peer(peer_info, None).ignore()
}
};
}
}
@@ -10,6 +10,7 @@ use std::str::FromStr;
// query clients
mod coconut_bandwidth_query_client;
mod dkg_query_client;
mod ephemera_query_client;
mod group_query_client;
mod mixnet_query_client;
mod multisig_query_client;
@@ -20,6 +21,7 @@ mod vesting_query_client;
// signing clients
mod coconut_bandwidth_signing_client;
mod dkg_signing_client;
mod ephemera_signing_client;
mod group_signing_client;
mod mixnet_signing_client;
mod multisig_signing_client;
@@ -32,6 +34,7 @@ pub use coconut_bandwidth_query_client::{
CoconutBandwidthQueryClient, PagedCoconutBandwidthQueryClient,
};
pub use dkg_query_client::{DkgQueryClient, PagedDkgQueryClient};
pub use ephemera_query_client::{EphemeraQueryClient, PagedEphemeraQueryClient};
pub use group_query_client::{GroupQueryClient, PagedGroupQueryClient};
pub use mixnet_query_client::{MixnetQueryClient, PagedMixnetQueryClient};
pub use multisig_query_client::{MultisigQueryClient, PagedMultisigQueryClient};
@@ -42,6 +45,7 @@ pub use vesting_query_client::{PagedVestingQueryClient, VestingQueryClient};
// re-export signing traits
pub use coconut_bandwidth_signing_client::CoconutBandwidthSigningClient;
pub use dkg_signing_client::DkgSigningClient;
pub use ephemera_signing_client::EphemeraSigningClient;
pub use group_signing_client::GroupSigningClient;
pub use mixnet_signing_client::MixnetSigningClient;
pub use multisig_signing_client::MultisigSigningClient;
@@ -61,6 +65,9 @@ pub trait NymContractsProvider {
fn group_contract_address(&self) -> Option<&AccountId>;
fn multisig_contract_address(&self) -> Option<&AccountId>;
// ephemera-related
fn ephemera_contract_address(&self) -> Option<&AccountId>;
// SPs
fn name_service_contract_address(&self) -> Option<&AccountId>;
fn service_provider_contract_address(&self) -> Option<&AccountId>;
@@ -76,6 +83,8 @@ pub struct TypedNymContracts {
pub multisig_contract_address: Option<AccountId>,
pub coconut_dkg_contract_address: Option<AccountId>,
pub ephemera_contract_address: Option<AccountId>,
pub service_provider_directory_contract_address: Option<AccountId>,
pub name_service_contract_address: Option<AccountId>,
}
@@ -109,6 +118,10 @@ impl TryFrom<NymContracts> for TypedNymContracts {
.coconut_dkg_contract_address
.map(|addr| addr.parse())
.transpose()?,
ephemera_contract_address: value
.ephemera_contract_address
.map(|addr| addr.parse())
.transpose()?,
service_provider_directory_contract_address: value
.service_provider_directory_contract_address
.map(|addr| addr.parse())
@@ -3,18 +3,25 @@
use crate::nyxd::cosmwasm_client::client_traits::{CosmWasmClient, SigningCosmWasmClient};
use crate::nyxd::error::NyxdError;
use crate::nyxd::{Config, GasPrice};
use crate::nyxd::{Config, GasPrice, Hash, Height};
use crate::rpc::TendermintRpcClient;
use crate::signing::{
signer::{NoSigner, OfflineSigner},
AccountData,
};
use async_trait::async_trait;
use tendermint_rpc::{Error as TendermintRpcError, SimpleRequest};
use cosmrs::tendermint::{abci, evidence::Evidence, Genesis};
use cosmrs::tx::{Raw, SignDoc};
use serde::{de::DeserializeOwned, Serialize};
use std::fmt::Debug;
use tendermint_rpc::endpoint::*;
use tendermint_rpc::query::Query;
use tendermint_rpc::{Error as TendermintRpcError, Order, Paging, SimpleRequest};
#[cfg(feature = "http-client")]
use crate::http_client;
#[cfg(feature = "http-client")]
use cosmrs::rpc::{HttpClient, HttpClientUrl};
use cosmrs::tx::{Raw, SignDoc};
pub mod client_traits;
mod helpers;
@@ -73,7 +80,7 @@ impl<S> MaybeSigningClient<HttpClient, S> {
where
U: TryInto<HttpClientUrl, Error = TendermintRpcError>,
{
self.client = HttpClient::new(new_endpoint)?;
self.client = http_client(new_endpoint)?;
Ok(())
}
}
@@ -85,6 +92,216 @@ where
C: TendermintRpcClient + Send + Sync,
S: Send + Sync,
{
async fn abci_info(&self) -> Result<abci::response::Info, TendermintRpcError> {
self.client.abci_info().await
}
async fn abci_query<V>(
&self,
path: Option<String>,
data: V,
height: Option<Height>,
prove: bool,
) -> Result<abci_query::AbciQuery, TendermintRpcError>
where
V: Into<Vec<u8>> + Send,
{
self.client.abci_query(path, data, height, prove).await
}
async fn block<H>(&self, height: H) -> Result<block::Response, TendermintRpcError>
where
H: Into<Height> + Send,
{
self.client.block(height).await
}
async fn block_by_hash(
&self,
hash: Hash,
) -> Result<block_by_hash::Response, TendermintRpcError> {
self.client.block_by_hash(hash).await
}
async fn latest_block(&self) -> Result<block::Response, TendermintRpcError> {
self.client.latest_block().await
}
async fn header<H>(&self, height: H) -> Result<header::Response, TendermintRpcError>
where
H: Into<Height> + Send,
{
self.client.header(height).await
}
async fn header_by_hash(
&self,
hash: Hash,
) -> Result<header_by_hash::Response, TendermintRpcError> {
self.client.header_by_hash(hash).await
}
async fn block_results<H>(
&self,
height: H,
) -> Result<block_results::Response, TendermintRpcError>
where
H: Into<Height> + Send,
{
self.client.block_results(height).await
}
async fn latest_block_results(&self) -> Result<block_results::Response, TendermintRpcError> {
self.client.latest_block_results().await
}
async fn block_search(
&self,
query: Query,
page: u32,
per_page: u8,
order: Order,
) -> Result<block_search::Response, TendermintRpcError> {
self.client.block_search(query, page, per_page, order).await
}
async fn blockchain<H>(
&self,
min: H,
max: H,
) -> Result<blockchain::Response, TendermintRpcError>
where
H: Into<Height> + Send,
{
self.client.blockchain(min, max).await
}
async fn broadcast_tx_async<T>(
&self,
tx: T,
) -> Result<broadcast::tx_async::Response, TendermintRpcError>
where
T: Into<Vec<u8>> + Send,
{
self.client.broadcast_tx_async(tx).await
}
async fn broadcast_tx_sync<T>(
&self,
tx: T,
) -> Result<broadcast::tx_sync::Response, TendermintRpcError>
where
T: Into<Vec<u8>> + Send,
{
self.client.broadcast_tx_sync(tx).await
}
async fn broadcast_tx_commit<T>(
&self,
tx: T,
) -> Result<broadcast::tx_commit::Response, TendermintRpcError>
where
T: Into<Vec<u8>> + Send,
{
self.client.broadcast_tx_commit(tx).await
}
async fn commit<H>(&self, height: H) -> Result<commit::Response, TendermintRpcError>
where
H: Into<Height> + Send,
{
self.client.commit(height).await
}
async fn consensus_params<H>(
&self,
height: H,
) -> Result<consensus_params::Response, TendermintRpcError>
where
H: Into<Height> + Send,
{
self.client.consensus_params(height).await
}
async fn consensus_state(&self) -> Result<consensus_state::Response, TendermintRpcError> {
self.client.consensus_state().await
}
async fn validators<H>(
&self,
height: H,
paging: Paging,
) -> Result<validators::Response, TendermintRpcError>
where
H: Into<Height> + Send,
{
self.client.validators(height, paging).await
}
async fn latest_consensus_params(
&self,
) -> Result<consensus_params::Response, TendermintRpcError> {
self.client.latest_consensus_params().await
}
async fn latest_commit(&self) -> Result<commit::Response, TendermintRpcError> {
self.client.latest_commit().await
}
async fn health(&self) -> Result<(), TendermintRpcError> {
self.client.health().await
}
async fn genesis<AppState>(&self) -> Result<Genesis<AppState>, TendermintRpcError>
where
AppState: Debug + Serialize + DeserializeOwned + Send,
{
self.client.genesis().await
}
async fn net_info(&self) -> Result<net_info::Response, TendermintRpcError> {
self.client.net_info().await
}
async fn status(&self) -> Result<status::Response, TendermintRpcError> {
self.client.status().await
}
async fn broadcast_evidence(
&self,
e: Evidence,
) -> Result<evidence::Response, TendermintRpcError> {
self.client.broadcast_evidence(e).await
}
async fn tx(&self, hash: Hash, prove: bool) -> Result<tx::Response, TendermintRpcError> {
self.client.tx(hash, prove).await
}
async fn tx_search(
&self,
query: Query,
prove: bool,
page: u32,
per_page: u8,
order: Order,
) -> Result<tx_search::Response, TendermintRpcError> {
self.client
.tx_search(query, prove, page, per_page, order)
.await
}
#[cfg(any(
feature = "tendermint-rpc/http-client",
feature = "tendermint-rpc/websocket-client"
))]
async fn wait_until_healthy<T>(&self, timeout: T) -> Result<(), Error>
where
T: Into<core::time::Duration> + Send,
{
self.client.wait_until_healthy(timeout).await
}
async fn perform<R>(&self, request: R) -> Result<R::Output, TendermintRpcError>
where
R: SimpleRequest,
@@ -9,19 +9,25 @@ use crate::nyxd::cosmwasm_client::types::{
use crate::nyxd::cosmwasm_client::MaybeSigningClient;
use crate::nyxd::error::NyxdError;
use crate::nyxd::fee::DEFAULT_SIMULATED_GAS_MULTIPLIER;
use crate::signing::direct_wallet::DirectSecp256k1HdWallet;
use crate::signing::signer::NoSigner;
use crate::signing::signer::OfflineSigner;
use crate::signing::tx_signer::TxSigner;
use crate::signing::AccountData;
use crate::{DirectSigningReqwestRpcNyxdClient, QueryReqwestRpcNyxdClient, ReqwestRpcClient};
use async_trait::async_trait;
use cosmrs::cosmwasm;
use cosmrs::tendermint::{abci, evidence::Evidence, Genesis};
use cosmrs::tx::{Msg, Raw, SignDoc};
use cosmwasm_std::Addr;
use nym_network_defaults::{ChainDetails, NymNetworkDetails};
use serde::Serialize;
use serde::{de::DeserializeOwned, Serialize};
use std::fmt::Debug;
use std::time::SystemTime;
use tendermint_rpc::endpoint::block::Response as BlockResponse;
use tendermint_rpc::Error as TendermintRpcError;
use tendermint_rpc::endpoint::*;
use tendermint_rpc::{Error as TendermintRpcError, Order};
use url::Url;
pub use crate::nyxd::cosmwasm_client::client_traits::{CosmWasmClient, SigningCosmWasmClient};
pub use crate::nyxd::fee::Fee;
@@ -45,14 +51,13 @@ pub use tendermint_rpc::{
};
pub use tendermint_rpc::{Request, Response, SimpleRequest};
// #[cfg(feature = "http-client")]
use crate::signing::direct_wallet::DirectSecp256k1HdWallet;
#[cfg(feature = "http-client")]
use crate::http_client;
#[cfg(feature = "http-client")]
use crate::{DirectSigningHttpRpcNyxdClient, QueryHttpRpcNyxdClient};
use crate::{DirectSigningReqwestRpcNyxdClient, QueryReqwestRpcNyxdClient, ReqwestRpcClient};
#[cfg(feature = "http-client")]
use cosmrs::rpc::{HttpClient, HttpClientUrl};
use url::Url;
use tendermint_rpc::query::Query;
pub mod coin;
pub mod contract_traits;
@@ -97,7 +102,7 @@ impl NyxdClient<HttpClient> {
where
U: TryInto<HttpClientUrl, Error = TendermintRpcError>,
{
let client = HttpClient::new(endpoint)?;
let client = http_client(endpoint)?;
Ok(NyxdClient {
client: MaybeSigningClient::new(client, (&config).into()),
@@ -140,7 +145,7 @@ impl NyxdClient<HttpClient, DirectSecp256k1HdWallet> {
where
U: TryInto<HttpClientUrl, Error = TendermintRpcError>,
{
let client = HttpClient::new(endpoint)?;
let client = http_client(endpoint)?;
let prefix = &config.chain_details.bech32_account_prefix;
let wallet = DirectSecp256k1HdWallet::from_mnemonic(prefix, mnemonic);
@@ -259,6 +264,10 @@ impl<C, S> NymContractsProvider for NyxdClient<C, S> {
self.config.contracts.multisig_contract_address.as_ref()
}
fn ephemera_contract_address(&self) -> Option<&AccountId> {
self.config.contracts.ephemera_contract_address.as_ref()
}
fn name_service_contract_address(&self) -> Option<&AccountId> {
self.config.contracts.name_service_contract_address.as_ref()
}
@@ -564,6 +573,216 @@ where
C: TendermintRpcClient + Send + Sync,
S: Send + Sync,
{
async fn abci_info(&self) -> Result<abci::response::Info, TendermintRpcError> {
self.client.abci_info().await
}
async fn abci_query<V>(
&self,
path: Option<String>,
data: V,
height: Option<Height>,
prove: bool,
) -> Result<abci_query::AbciQuery, TendermintRpcError>
where
V: Into<Vec<u8>> + Send,
{
self.client.abci_query(path, data, height, prove).await
}
async fn block<H>(&self, height: H) -> Result<block::Response, TendermintRpcError>
where
H: Into<Height> + Send,
{
self.client.block(height).await
}
async fn block_by_hash(
&self,
hash: Hash,
) -> Result<block_by_hash::Response, TendermintRpcError> {
self.client.block_by_hash(hash).await
}
async fn latest_block(&self) -> Result<block::Response, TendermintRpcError> {
self.client.latest_block().await
}
async fn header<H>(&self, height: H) -> Result<header::Response, TendermintRpcError>
where
H: Into<Height> + Send,
{
self.client.header(height).await
}
async fn header_by_hash(
&self,
hash: Hash,
) -> Result<header_by_hash::Response, TendermintRpcError> {
self.client.header_by_hash(hash).await
}
async fn block_results<H>(
&self,
height: H,
) -> Result<block_results::Response, TendermintRpcError>
where
H: Into<Height> + Send,
{
self.client.block_results(height).await
}
async fn latest_block_results(&self) -> Result<block_results::Response, TendermintRpcError> {
self.client.latest_block_results().await
}
async fn block_search(
&self,
query: Query,
page: u32,
per_page: u8,
order: Order,
) -> Result<block_search::Response, TendermintRpcError> {
self.client.block_search(query, page, per_page, order).await
}
async fn blockchain<H>(
&self,
min: H,
max: H,
) -> Result<blockchain::Response, TendermintRpcError>
where
H: Into<Height> + Send,
{
self.client.blockchain(min, max).await
}
async fn broadcast_tx_async<T>(
&self,
tx: T,
) -> Result<broadcast::tx_async::Response, TendermintRpcError>
where
T: Into<Vec<u8>> + Send,
{
TendermintRpcClient::broadcast_tx_async(&self.client, tx).await
}
async fn broadcast_tx_sync<T>(
&self,
tx: T,
) -> Result<broadcast::tx_sync::Response, TendermintRpcError>
where
T: Into<Vec<u8>> + Send,
{
TendermintRpcClient::broadcast_tx_sync(&self.client, tx).await
}
async fn broadcast_tx_commit<T>(
&self,
tx: T,
) -> Result<broadcast::tx_commit::Response, TendermintRpcError>
where
T: Into<Vec<u8>> + Send,
{
TendermintRpcClient::broadcast_tx_commit(&self.client, tx).await
}
async fn commit<H>(&self, height: H) -> Result<commit::Response, TendermintRpcError>
where
H: Into<Height> + Send,
{
self.client.commit(height).await
}
async fn consensus_params<H>(
&self,
height: H,
) -> Result<consensus_params::Response, TendermintRpcError>
where
H: Into<Height> + Send,
{
self.client.consensus_params(height).await
}
async fn consensus_state(&self) -> Result<consensus_state::Response, TendermintRpcError> {
self.client.consensus_state().await
}
async fn validators<H>(
&self,
height: H,
paging: Paging,
) -> Result<validators::Response, TendermintRpcError>
where
H: Into<Height> + Send,
{
self.client.validators(height, paging).await
}
async fn latest_consensus_params(
&self,
) -> Result<consensus_params::Response, TendermintRpcError> {
self.client.latest_consensus_params().await
}
async fn latest_commit(&self) -> Result<commit::Response, TendermintRpcError> {
self.client.latest_commit().await
}
async fn health(&self) -> Result<(), TendermintRpcError> {
self.client.health().await
}
async fn genesis<AppState>(&self) -> Result<Genesis<AppState>, TendermintRpcError>
where
AppState: Debug + Serialize + DeserializeOwned + Send,
{
self.client.genesis().await
}
async fn net_info(&self) -> Result<net_info::Response, TendermintRpcError> {
self.client.net_info().await
}
async fn status(&self) -> Result<status::Response, TendermintRpcError> {
self.client.status().await
}
async fn broadcast_evidence(
&self,
e: Evidence,
) -> Result<evidence::Response, TendermintRpcError> {
self.client.broadcast_evidence(e).await
}
async fn tx(&self, hash: Hash, prove: bool) -> Result<TxResponse, TendermintRpcError> {
self.client.tx(hash, prove).await
}
async fn tx_search(
&self,
query: Query,
prove: bool,
page: u32,
per_page: u8,
order: Order,
) -> Result<tx_search::Response, TendermintRpcError> {
self.client
.tx_search(query, prove, page, per_page, order)
.await
}
#[cfg(any(
feature = "tendermint-rpc/http-client",
feature = "tendermint-rpc/websocket-client"
))]
async fn wait_until_healthy<T>(&self, timeout: T) -> Result<(), Error>
where
T: Into<core::time::Duration> + Send,
{
self.client.wait_until_healthy(timeout).await
}
async fn perform<R>(&self, request: R) -> Result<R::Output, TendermintRpcError>
where
R: SimpleRequest,
@@ -11,8 +11,27 @@ use tendermint_rpc::{
Error, Order, Paging, SimpleRequest,
};
#[cfg(feature = "http-client")]
use crate::error::TendermintRpcError;
#[cfg(feature = "http-client")]
use crate::HttpRpcClient;
#[cfg(feature = "http-client")]
use tendermint_rpc::client::CompatMode;
#[cfg(feature = "http-client")]
use tendermint_rpc::HttpClientUrl;
pub mod reqwest;
#[cfg(feature = "http-client")]
pub fn http_client<U>(url: U) -> Result<HttpRpcClient, TendermintRpcError>
where
U: TryInto<HttpClientUrl, Error = Error>,
{
HttpRpcClient::builder(url.try_into()?)
.compat_mode(CompatMode::V0_34)
.build()
}
// we have to create a sealed trait since `TendermintClient` needs T: Send (due to how async trait is created)
// which we can't do in wasm
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
@@ -3,12 +3,32 @@
use crate::rpc::TendermintRpcClient;
use async_trait::async_trait;
use cosmrs::tendermint::{block::Height, evidence::Evidence, Hash};
use reqwest::header::HeaderMap;
use reqwest::{header, RequestBuilder};
use tendermint_rpc::{Error, Response, SimpleRequest};
use tendermint_rpc::{
client::CompatMode,
dialect::{self, Dialect},
endpoint::{self, *},
query::Query,
Error, Order, Response, SimpleRequest,
};
use url::Url;
// copied macro from tendermint-rpc crate because that's exactly what we have to do here too
macro_rules! perform_with_compat {
($self:expr, $request:expr) => {{
let request = $request;
match $self.compat {
CompatMode::V0_37 => $self.perform_v0_37(request).await,
CompatMode::V0_34 => $self.perform_v0_34(request).await,
}
}};
}
pub struct ReqwestRpcClient {
compat: CompatMode,
inner: reqwest::Client,
url: Url,
}
@@ -16,12 +36,21 @@ pub struct ReqwestRpcClient {
impl ReqwestRpcClient {
pub fn new(url: Url) -> Self {
ReqwestRpcClient {
compat: CompatMode::V0_34,
inner: reqwest::Client::new(),
url,
}
}
fn build_request<R: SimpleRequest>(&self, request: R) -> RequestBuilder {
pub fn set_compat_mode(&mut self, compat: CompatMode) {
self.compat = compat;
}
fn build_request<R, S>(&self, request: R) -> RequestBuilder
where
R: SimpleRequest<S>,
S: Dialect,
{
let mut headers = HeaderMap::new();
headers.insert(header::CONTENT_TYPE, "application/json".parse().unwrap());
headers.insert(
@@ -39,6 +68,38 @@ impl ReqwestRpcClient {
.body(request.into_json().into_bytes())
.headers(headers)
}
async fn perform_request<R, S>(&self, request: R) -> Result<R::Output, Error>
where
R: SimpleRequest<S>,
S: Dialect,
{
let request = self.build_request(request);
// that's extremely unfortunate. the trait requires returning tendermint rpc error so we have to make best effort error mapping
let response = request
.send()
.await
.map_err(TendermintRpcErrorMap::into_rpc_err)?;
let bytes = response
.bytes()
.await
.map_err(TendermintRpcErrorMap::into_rpc_err)?;
R::Response::from_string(bytes).map(Into::into)
}
async fn perform_v0_34<R>(&self, request: R) -> Result<R::Output, Error>
where
R: SimpleRequest<dialect::v0_34::Dialect>,
{
self.perform_request(request).await
}
async fn perform_v0_37<R>(&self, request: R) -> Result<R::Output, Error>
where
R: SimpleRequest<dialect::v0_37::Dialect>,
{
self.perform_request(request).await
}
}
trait TendermintRpcErrorMap {
@@ -58,17 +119,81 @@ impl TendermintRpcClient for ReqwestRpcClient {
where
R: SimpleRequest,
{
let request = self.build_request(request);
// that's extremely unfortunate. the trait requires returning tendermint rpc error so we have to make best effort error mapping
let response = request
.send()
.await
.map_err(TendermintRpcErrorMap::into_rpc_err)?;
let bytes = response
.bytes()
.await
.map_err(TendermintRpcErrorMap::into_rpc_err)?;
R::Response::from_string(bytes).map(Into::into)
self.perform_request(request).await
}
async fn block_results<H>(&self, height: H) -> Result<block_results::Response, Error>
where
H: Into<Height> + Send,
{
perform_with_compat!(self, block_results::Request::new(height.into()))
}
async fn latest_block_results(&self) -> Result<block_results::Response, Error> {
perform_with_compat!(self, block_results::Request::default())
}
async fn header<H>(&self, height: H) -> Result<endpoint::header::Response, Error>
where
H: Into<Height> + Send,
{
let height = height.into();
match self.compat {
CompatMode::V0_37 => self.perform(endpoint::header::Request::new(height)).await,
CompatMode::V0_34 => {
// Back-fill with a request to /block endpoint and
// taking just the header from the response.
let resp = self.perform_v0_34(block::Request::new(height)).await?;
Ok(resp.into())
}
}
}
async fn header_by_hash(&self, hash: Hash) -> Result<header_by_hash::Response, Error> {
match self.compat {
CompatMode::V0_37 => self.perform(header_by_hash::Request::new(hash)).await,
CompatMode::V0_34 => {
// Back-fill with a request to /block_by_hash endpoint and
// taking just the header from the response.
let resp = self
.perform_v0_34(block_by_hash::Request::new(hash))
.await?;
Ok(resp.into())
}
}
}
/// `/broadcast_evidence`: broadcast an evidence.
async fn broadcast_evidence(&self, e: Evidence) -> Result<evidence::Response, Error> {
match self.compat {
CompatMode::V0_37 => self.perform(evidence::Request::new(e)).await,
CompatMode::V0_34 => self.perform_v0_34(evidence::Request::new(e)).await,
}
}
async fn tx(&self, hash: Hash, prove: bool) -> Result<tx::Response, Error> {
perform_with_compat!(self, tx::Request::new(hash, prove))
}
async fn tx_search(
&self,
query: Query,
prove: bool,
page: u32,
per_page: u8,
order: Order,
) -> Result<tx_search::Response, Error> {
perform_with_compat!(
self,
tx_search::Request::new(query, prove, page, per_page, order)
)
}
async fn broadcast_tx_commit<T>(&self, tx: T) -> Result<broadcast::tx_commit::Response, Error>
where
T: Into<Vec<u8>> + Send,
{
perform_with_compat!(self, broadcast::tx_commit::Request::new(tx))
}
}
@@ -199,16 +199,14 @@ mod tests {
#[test]
fn generating_account_addresses() {
// test vectors produced from our js wallet
let mnemonics = vec![
"crush minute paddle tobacco message debate cabin peace bar jacket execute twenty winner view sure mask popular couch penalty fragile demise fresh pizza stove",
let mnemonics = ["crush minute paddle tobacco message debate cabin peace bar jacket execute twenty winner view sure mask popular couch penalty fragile demise fresh pizza stove",
"acquire rebel spot skin gun such erupt pull swear must define ill chief turtle today flower chunk truth battle claw rigid detail gym feel",
"step income throw wheat mobile ship wave drink pool sudden upset jaguar bar globe rifle spice frost bless glimpse size regular carry aspect ball"
];
"step income throw wheat mobile ship wave drink pool sudden upset jaguar bar globe rifle spice frost bless glimpse size regular carry aspect ball"];
let prefix = NymNetworkDetails::new_mainnet()
.chain_details
.bech32_account_prefix;
let addrs = vec![
let addrs = [
"n1jw6mp7d5xqc7w6xm79lha27glmd0vdt3l9artf",
"n1h5hgn94nsq4kh99rjj794hr5h5q6yfm2lr52es",
"n17n9flp6jflljg6fp05dsy07wcprf2uuu8g40rf",
+11 -2
View File
@@ -8,7 +8,14 @@ use serde::{Deserialize, Serialize};
use error::CoconutInterfaceError;
pub use nym_coconut::*;
// We list these explicity instead of glob export due to shadowing warnings with the pub tests
// module.
pub use nym_coconut::{
aggregate_signature_shares, aggregate_verification_keys, blind_sign, hash_to_scalar,
prepare_blind_sign, prove_bandwidth_credential, Attribute, Base58, BlindSignRequest,
BlindedSignature, Bytable, CoconutError, KeyPair, Parameters, PrivateAttribute,
PublicAttribute, Signature, SignatureShare, Theta, VerificationKey,
};
#[derive(Debug, Serialize, Deserialize, Getters, CopyGetters, Clone, PartialEq, Eq)]
pub struct Credential {
@@ -57,7 +64,7 @@ impl Credential {
pub fn verify(&self, verification_key: &VerificationKey) -> bool {
let params = Parameters::new(self.n_params).unwrap();
let public_attributes = vec![
let public_attributes = [
self.voucher_value.to_string().as_bytes(),
self.voucher_info.as_bytes(),
]
@@ -138,6 +145,8 @@ impl Base58 for Credential {}
#[cfg(test)]
mod tests {
use nym_coconut::{prove_bandwidth_credential, Signature};
use super::*;
#[test]
+7
View File
@@ -5,6 +5,7 @@ authors.workspace = true
edition = "2021"
[dependencies]
anyhow = { workspace = true }
base64 = "0.13.0"
bip39 = { workspace = true }
bs58 = "0.4"
@@ -33,6 +34,7 @@ nym-bin-common = { path = "../../common/bin-common", features = ["output_format"
nym-crypto = { path = "../../common/crypto", features = ["asymmetric"] }
nym-network-defaults = { path = "../network-defaults" }
nym-contracts-common = { path = "../cosmwasm-smart-contracts/contracts-common" }
nym-bandwidth-controller = { path = "../../common/bandwidth-controller" }
nym-mixnet-contract-common = { path = "../cosmwasm-smart-contracts/mixnet-contract" }
nym-vesting-contract-common = { path = "../cosmwasm-smart-contracts/vesting-contract" }
nym-coconut-bandwidth-contract-common = { path = "../cosmwasm-smart-contracts/coconut-bandwidth-contract" }
@@ -41,6 +43,11 @@ nym-multisig-contract-common = { path = "../cosmwasm-smart-contracts/multisig-co
nym-service-provider-directory-common = { path = "../cosmwasm-smart-contracts/service-provider-directory" }
nym-name-service-common = { path = "../cosmwasm-smart-contracts/name-service" }
nym-sphinx = { path = "../../common/nymsphinx" }
nym-client-core = { path = "../../common/client-core" }
nym-config = { path = "../../common/config" }
nym-credentials = { path = "../../common/credentials" }
nym-credential-storage = { path = "../../common/credential-storage" }
nym-credential-utils = { path = "../../common/credential-utils" }
nym-pemstore = { path = "../../common/pemstore", version = "0.3.0" }
nym-types = { path = "../../common/types" }
@@ -0,0 +1,51 @@
// Copyright 2022-2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::context::SigningClient;
use crate::utils::CommonConfigsWrapper;
use anyhow::bail;
use clap::Parser;
use nym_credential_storage::initialise_persistent_storage;
use nym_credential_utils::utils;
use nym_validator_client::nyxd::Coin;
use std::path::PathBuf;
#[derive(Debug, Parser)]
pub struct Args {
/// Config file of the client that is supposed to use the credential.
#[clap(long)]
pub(crate) client_config: PathBuf,
/// The amount of utokens the credential will hold.
#[clap(long, default_value = "0")]
pub(crate) amount: u64,
/// Path to a directory used to store recovery files for unconsumed deposits
#[clap(long)]
pub(crate) recovery_dir: PathBuf,
}
pub async fn execute(args: Args, client: SigningClient) -> anyhow::Result<()> {
let loaded = CommonConfigsWrapper::try_load(args.client_config)?;
if let Ok(id) = loaded.try_get_id() {
println!("loaded config file for client '{id}'");
}
let Ok(credentials_store) = loaded.try_get_credentials_store() else {
bail!("the loaded config does not have a credentials store information")
};
println!(
"using credentials store at '{}'",
credentials_store.display()
);
let denom = &client.current_chain_details().mix_denom.base;
let coin = Coin::new(args.amount as u128, denom);
let persistent_storage = initialise_persistent_storage(credentials_store).await;
utils::issue_credential(&client, coin, &persistent_storage, args.recovery_dir).await?;
Ok(())
}
+17 -1
View File
@@ -1,4 +1,20 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
// TODO: add coconut commands here
use clap::{Args, Subcommand};
pub mod issue_credentials;
pub mod recover_credentials;
#[derive(Debug, Args)]
#[clap(args_conflicts_with_subcommands = true, subcommand_required = true)]
pub struct Coconut {
#[clap(subcommand)]
pub command: CoconutCommands,
}
#[derive(Debug, Subcommand)]
pub enum CoconutCommands {
IssueCredentials(issue_credentials::Args),
RecoverCredentials(recover_credentials::Args),
}
@@ -0,0 +1,48 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::context::QueryClient;
use crate::utils::CommonConfigsWrapper;
use anyhow::bail;
use clap::Parser;
use nym_credential_storage::initialise_persistent_storage;
use nym_credential_utils::{recovery_storage, utils};
use std::path::PathBuf;
#[derive(Debug, Parser)]
pub struct Args {
/// Config file of the client that is supposed to use the credential.
#[clap(long)]
pub(crate) client_config: PathBuf,
/// Path to a directory used to store recovery files for unconsumed deposits
#[clap(long)]
pub(crate) recovery_dir: PathBuf,
}
pub async fn execute(args: Args, client: QueryClient) -> anyhow::Result<()> {
let loaded = CommonConfigsWrapper::try_load(args.client_config)?;
if let Ok(id) = loaded.try_get_id() {
println!("loaded config file for client '{id}'");
}
let Ok(credentials_store) = loaded.try_get_credentials_store() else {
bail!("the loaded config does not have a credentials store information")
};
println!(
"using credentials store at '{}'",
credentials_store.display()
);
let persistent_storage = initialise_persistent_storage(credentials_store).await;
let recovery_storage = recovery_storage::RecoveryStorage::new(args.recovery_dir)?;
let recovered =
utils::recover_credentials(&client, &recovery_storage, &persistent_storage).await?;
// TODO: denom?
println!("recovered {recovered} worth of credentials");
Ok(())
}
+152 -1
View File
@@ -1,13 +1,17 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use anyhow::{anyhow, bail};
use cosmrs::AccountId;
use cosmwasm_std::{Addr, Coin as CosmWasmCoin, Decimal};
use log::error;
use nym_client_core::config::disk_persistence::CommonClientPaths;
use nym_validator_client::nyxd::Coin;
use serde::Serialize;
use serde::{Deserialize, Serialize};
use std::error::Error;
use std::fmt::{Display, Formatter};
use std::fs;
use std::path::{Path, PathBuf};
// TODO: perhaps it should be moved to some global common crate?
pub fn account_id_to_cw_addr(account_id: &AccountId) -> Addr {
@@ -75,3 +79,150 @@ impl<T> DataWrapper<T> {
DataWrapper { data }
}
}
fn find_toml_value<'a>(root: &'a toml::Value, key: &str) -> Option<&'a toml::Value> {
if let toml::Value::Table(table) = root {
for (k, v) in table {
if k == key {
return Some(v);
}
if v.is_table() {
if let Some(res) = find_toml_value(v, key) {
return Some(res);
}
}
}
}
None
}
#[derive(Deserialize, Debug)]
#[serde(untagged)]
pub(crate) enum CommonConfigsWrapper {
// native, socks5, NR, etc. clients
NymClients(Box<ClientConfigCommonWrapper>),
// nym-api
NymApi(NymApiConfigLight),
// anything else that might get get introduced
Unknown(UnknownConfigWrapper),
}
impl CommonConfigsWrapper {
pub(crate) fn try_load<P: AsRef<Path>>(path: P) -> anyhow::Result<CommonConfigsWrapper> {
let content = fs::read_to_string(path)?;
Ok(toml::from_str(&content)?)
}
pub(crate) fn try_get_id(&self) -> anyhow::Result<&str> {
match self {
CommonConfigsWrapper::NymClients(cfg) => cfg.try_get_id(),
CommonConfigsWrapper::NymApi(cfg) => Ok(&cfg.base.id),
CommonConfigsWrapper::Unknown(cfg) => cfg.try_get_id(),
}
}
pub(crate) fn try_get_credentials_store(&self) -> anyhow::Result<PathBuf> {
match self {
CommonConfigsWrapper::NymClients(cfg) => {
Ok(cfg.storage_paths.inner.credentials_database.clone())
}
CommonConfigsWrapper::NymApi(cfg) => Ok(cfg
.network_monitor
.storage_paths
.credentials_database_path
.clone()),
CommonConfigsWrapper::Unknown(cfg) => cfg.try_get_credentials_store(),
}
}
}
// ideally we would have just imported the full nym-api config structure, but that'd have been an overkill,
// because we'd have to import the whole crate
#[derive(Deserialize, Debug)]
pub(crate) struct NymApiConfigLight {
base: NymApiConfigBaseLight,
network_monitor: NymApiConfigNetworkMonitorLight,
}
#[derive(Deserialize, Debug)]
struct NymApiConfigBaseLight {
id: String,
}
#[derive(Deserialize, Debug)]
struct NymApiConfigNetworkMonitorLight {
storage_paths: NetworkMonitorPaths,
}
#[derive(Deserialize, Debug)]
struct NetworkMonitorPaths {
credentials_database_path: PathBuf,
}
// a hacky way of reading common data from client configs (native, socks5, etc.)
// it works because all clients follow the same structure for storage paths
// (or so I thought)
#[derive(Deserialize, Debug)]
pub(crate) struct ClientConfigCommonWrapper {
storage_paths: StoragePathsWrapper,
// ... but they have different structure for `nym_client_core::config::Client`
// native client has it on the top layer, whilsts socks5 has it under 'core' table
#[serde(flatten)]
other: toml::Value,
}
// wrapper to allow for any additional entries besides the common paths, like allow list for NR
#[derive(Deserialize, Debug)]
struct StoragePathsWrapper {
#[serde(flatten)]
inner: CommonClientPaths,
}
impl ClientConfigCommonWrapper {
pub(crate) fn try_get_id(&self) -> anyhow::Result<&str> {
let id_val = find_toml_value(&self.other, "id")
.ok_or_else(|| anyhow!("no id field present in the config"))?;
if let toml::Value::String(id) = id_val {
Ok(id)
} else {
bail!("no id field present in the config")
}
}
}
#[derive(Deserialize, Debug)]
pub(crate) struct UnknownConfigWrapper {
#[serde(flatten)]
inner: toml::Value,
}
impl UnknownConfigWrapper {
fn find_value(&self, key: &str) -> Option<&toml::Value> {
find_toml_value(&self.inner, key)
}
pub(crate) fn try_get_id(&self) -> anyhow::Result<&str> {
let id_val = self
.find_value("id")
.ok_or_else(|| anyhow!("no id field present in the config"))?;
if let toml::Value::String(id) = id_val {
Ok(id)
} else {
bail!("no id field present in the config")
}
}
pub(crate) fn try_get_credentials_store(&self) -> anyhow::Result<PathBuf> {
let id_val = self
.find_value("credentials_database_path")
.ok_or_else(|| anyhow!("no 'credentials_database_path' field present in the config"))?;
if let toml::Value::String(credentials_store) = id_val {
Ok(credentials_store.parse()?)
} else {
bail!("no 'credentials_database_path' field present in the config")
}
}
}
+1
View File
@@ -17,6 +17,7 @@ pub mod helpers;
pub mod legacy_helpers;
pub const NYM_DIR: &str = ".nym";
pub const DEFAULT_NYM_APIS_DIR: &str = "nym-api";
pub const DEFAULT_CONFIG_DIR: &str = "config";
pub const DEFAULT_DATA_DIR: &str = "data";
pub const DEFAULT_CONFIG_FILENAME: &str = "config.toml";
@@ -0,0 +1,16 @@
[package]
name = "nym-ephemera-common"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
cosmwasm-schema = { workspace = true }
cosmwasm-std = { workspace = true }
cw-utils = { workspace = true }
contracts-common = { path = "../contracts-common", package = "nym-contracts-common" }
[features]
schema = []
@@ -0,0 +1,3 @@
pub mod msg;
pub mod peers;
pub mod types;
@@ -0,0 +1,33 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
#[cfg(feature = "schema")]
use crate::peers::PagedPeerResponse;
use crate::types::JsonPeerInfo;
use cosmwasm_schema::cw_serde;
#[cfg(feature = "schema")]
use cosmwasm_schema::QueryResponses;
#[cw_serde]
pub struct InstantiateMsg {
pub group_addr: String,
pub mix_denom: String,
}
#[cw_serde]
pub enum ExecuteMsg {
RegisterPeer { peer_info: JsonPeerInfo },
}
#[cw_serde]
#[cfg_attr(feature = "schema", derive(QueryResponses))]
pub enum QueryMsg {
#[cfg_attr(feature = "schema", returns(PagedPeerResponse))]
GetPeers {
limit: Option<u32>,
start_after: Option<String>,
},
}
#[cw_serde]
pub struct MigrateMsg {}
@@ -0,0 +1,25 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::types::JsonPeerInfo;
use cosmwasm_schema::cw_serde;
use cosmwasm_std::Addr;
#[cw_serde]
pub struct PagedPeerResponse {
pub peers: Vec<JsonPeerInfo>,
pub per_page: usize,
/// Field indicating paging information for the following queries if the caller wishes to get further entries.
pub start_next_after: Option<Addr>,
}
impl PagedPeerResponse {
pub fn new(peers: Vec<JsonPeerInfo>, per_page: usize, start_next_after: Option<Addr>) -> Self {
PagedPeerResponse {
peers,
per_page,
start_next_after,
}
}
}
@@ -0,0 +1,29 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use cosmwasm_schema::cw_serde;
use cosmwasm_std::Addr;
#[cw_serde]
pub struct JsonPeerInfo {
/// The cosmos address of the peer, used in interacting with the chain.
pub cosmos_address: Addr,
/// The TCP/IP address of the peer.
/// Expected formats:
/// 1. `<IP>:<PORT>`
/// 2. `/ip4/<IP>/tcp/<PORT>` - this is the format used by libp2p multiaddr
pub ip_address: String,
///Serialized public key.
pub public_key: String,
}
impl JsonPeerInfo {
#[must_use]
pub fn new(cosmos_address: Addr, ip_address: String, public_key: String) -> Self {
Self {
cosmos_address,
ip_address,
public_key,
}
}
}
@@ -26,7 +26,7 @@ humantime-serde = "1.1.1"
# TO CHECK WHETHER STILL NEEDED:
log = { workspace = true }
time = { version = "0.3.6", features = ["parsing", "formatting"] }
ts-rs = { version = "6.1.2", optional = true }
ts-rs = { workspace = true, optional = true }
[dev-dependencies]
rand_chacha = "0.3"
@@ -15,7 +15,7 @@ mixnet-contract-common = { path = "../mixnet-contract", package = "nym-mixnet-co
contracts-common = { path = "../contracts-common", package = "nym-contracts-common", version = "0.5.0" }
serde = { version = "1.0", features = ["derive"] }
thiserror = "1.0"
ts-rs = {version = "6.1.2", optional = true}
ts-rs = { workspace = true, optional = true}
[features]
schema = ["cw2"]
@@ -1,25 +1,18 @@
[package]
name = "nym-credential-client"
name = "nym-credential-utils"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
clap = { version = "4.0", features = ["cargo", "derive"] }
log = "0.4"
serde = { workspace = true, features = ["derive"] }
thiserror = "1.0"
tokio = { version = "1.24.1", features = ["rt-multi-thread", "net", "signal", "macros"] } # async runtime
log = { workspace = true }
thiserror = { workspace = true }
tokio = { workspace = true }
nym-bandwidth-controller = { path = "../../common/bandwidth-controller" }
nym-client-core = { path = "../../common/client-core" }
nym-config = { path = "../../common/config" }
nym-credentials = { path = "../../common/credentials" }
nym-credential-storage = { path = "../../common/credential-storage" }
nym-bin-common = { path = "../../common/bin-common"}
nym-network-defaults = { path = "../../common/network-defaults" }
nym-pemstore = { path = "../../common/pemstore" }
nym-validator-client = { path = "../../common/client-libs/validator-client" }
nym-config = { path = "../../common/config" }
nym-client-core = { path = "../../common/client-core" }
+31
View File
@@ -0,0 +1,31 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use nym_credential_storage::error::StorageError;
use nym_credentials::error::Error as CredentialError;
use nym_validator_client::nyxd::error::NyxdError;
use std::num::ParseIntError;
use thiserror::Error;
pub type Result<T> = std::result::Result<T, Error>;
#[derive(Error, Debug)]
pub enum Error {
#[error(transparent)]
IOError(#[from] std::io::Error),
#[error(transparent)]
BandwidthControllerError(#[from] nym_bandwidth_controller::error::BandwidthControllerError),
#[error(transparent)]
Nyxd(#[from] NyxdError),
#[error(transparent)]
Credential(#[from] CredentialError),
#[error("Could not use shared storage: {0}")]
SharedStorageError(#[from] StorageError),
#[error("failed to parse credential value: {0}")]
MalformedCredentialValue(#[from] ParseIntError),
}
+5
View File
@@ -0,0 +1,5 @@
pub mod errors;
pub mod recovery_storage;
pub mod utils;
pub use errors::{Error, Result};
@@ -0,0 +1,64 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::errors::Result;
use log::error;
use nym_credentials::coconut::bandwidth::BandwidthVoucher;
use std::fs::{create_dir_all, read_dir, File};
use std::io::{Read, Write};
use std::path::PathBuf;
pub struct RecoveryStorage {
recovery_dir: PathBuf,
}
impl RecoveryStorage {
pub fn new(recovery_dir: PathBuf) -> Result<Self> {
create_dir_all(&recovery_dir)?;
Ok(Self { recovery_dir })
}
pub fn unconsumed_vouchers(&self) -> Result<Vec<BandwidthVoucher>> {
let entries = read_dir(&self.recovery_dir)?;
let mut paths = vec![];
for entry in entries.flatten() {
let path = entry.path();
if path.is_file() {
paths.push(path)
}
}
let mut vouchers = vec![];
for path in paths {
if let Ok(mut file) = File::open(&path) {
let mut buff = Vec::new();
if file.read_to_end(&mut buff).is_ok() {
match BandwidthVoucher::try_from_bytes(&buff) {
Ok(voucher) => vouchers.push(voucher),
Err(err) => {
error!("failed to parse the voucher at {}: {err}", path.display())
}
}
}
}
}
Ok(vouchers)
}
pub fn insert_voucher(&self, voucher: &BandwidthVoucher) -> Result<PathBuf> {
let file_name = voucher.tx_hash().to_string();
let file_path = self.recovery_dir.join(file_name);
let mut file = File::create(&file_path)?;
let buff = voucher.to_bytes();
file.write_all(&buff)?;
Ok(file_path)
}
pub fn remove_voucher(&self, file_name: String) -> Result<()> {
let file_path = self.recovery_dir.join(file_name);
Ok(std::fs::remove_file(file_path)?)
}
}
+139
View File
@@ -0,0 +1,139 @@
use crate::errors::{Error, Result};
use crate::recovery_storage::RecoveryStorage;
use log::*;
use nym_bandwidth_controller::acquire::state::State;
use nym_client_core::config::disk_persistence::CommonClientPaths;
use nym_config::DEFAULT_DATA_DIR;
use nym_credential_storage::persistent_storage::PersistentStorage;
use nym_validator_client::nyxd::contract_traits::{CoconutBandwidthSigningClient, DkgQueryClient};
use nym_validator_client::nyxd::Coin;
use std::path::PathBuf;
use std::process::exit;
use std::time::{Duration, SystemTime};
const SAFETY_BUFFER_SECS: u64 = 60; // 1 minute
pub async fn issue_credential<C>(
client: &C,
amount: Coin,
persistent_storage: &PersistentStorage,
recovery_storage_path: PathBuf,
) -> Result<()>
where
C: DkgQueryClient + CoconutBandwidthSigningClient + Send + Sync,
{
let recovery_storage = setup_recovery_storage(recovery_storage_path).await;
block_until_coconut_is_available(client).await?;
info!("Starting to deposit funds, don't kill the process");
if let Ok(recovered_amount) =
recover_credentials(client, &recovery_storage, persistent_storage).await
{
if recovered_amount != 0 {
info!(
"Recovered credentials in the amount of {}",
recovered_amount
);
return Ok(());
}
};
let state = nym_bandwidth_controller::acquire::deposit(client, amount.clone()).await?;
if nym_bandwidth_controller::acquire::get_credential(&state, client, persistent_storage)
.await
.is_err()
{
warn!("Failed to obtain credential. Dumping recovery data.",);
match recovery_storage.insert_voucher(&state.voucher) {
Ok(file_path) => {
warn!("Dumped recovery data to {}. Try using recovery mode to convert it to a credential", file_path.to_str().unwrap());
}
Err(e) => {
error!("Could not dump recovery data to file system due to {:?}, the deposit will be lost!", e)
}
}
return Err(Error::Credential(
nym_credentials::error::Error::BandwidthCredentialError,
));
}
info!("Succeeded adding a credential with amount {amount}");
Ok(())
}
pub async fn setup_recovery_storage(recovery_dir: PathBuf) -> RecoveryStorage {
RecoveryStorage::new(recovery_dir).expect("")
}
pub async fn setup_persistent_storage(client_home_directory: PathBuf) -> PersistentStorage {
let data_dir = client_home_directory.join(DEFAULT_DATA_DIR);
let paths = CommonClientPaths::new_default(data_dir);
let db_path = paths.credentials_database;
nym_credential_storage::initialise_persistent_storage(db_path).await
}
pub async fn block_until_coconut_is_available<C>(client: &C) -> Result<()>
where
C: DkgQueryClient + Send + Sync,
{
loop {
let epoch = client.get_current_epoch().await?;
let current_timestamp_secs = SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH)
.expect("the system clock is set to 01/01/1970 (or earlier)")
.as_secs();
if epoch.state.is_final() {
if current_timestamp_secs + SAFETY_BUFFER_SECS >= epoch.finish_timestamp.seconds() {
info!("In the next {} minute(s), a transition will take place in the coconut system. Deposits should be halted in this time for safety reasons.", SAFETY_BUFFER_SECS / 60);
exit(0);
}
break;
} else {
// Use 1 additional second to not start the next iteration immediately and spam get_current_epoch queries
let secs_until_final = epoch
.final_timestamp_secs()
.saturating_sub(current_timestamp_secs)
+ 1;
info!("Approximately {} seconds until coconut is available. Sleeping until then. You can safely kill the process at any moment.", secs_until_final);
tokio::time::sleep(Duration::from_secs(secs_until_final)).await;
}
}
Ok(())
}
pub async fn recover_credentials<C>(
client: &C,
recovery_storage: &RecoveryStorage,
shared_storage: &PersistentStorage,
) -> Result<u128>
where
C: DkgQueryClient + Send + Sync,
{
let mut recovered_amount: u128 = 0;
for voucher in recovery_storage.unconsumed_vouchers()? {
let voucher_value = voucher.get_voucher_value();
recovered_amount += voucher_value.parse::<u128>()?;
let state = State::new(voucher);
let voucher = state.voucher.tx_hash();
if let Err(e) =
nym_bandwidth_controller::acquire::get_credential(&state, client, shared_storage).await
{
error!("Could not recover deposit {voucher} due to {e}, try again later",)
} else {
info!("Converted deposit {voucher} to a credential, removing recovery data for it",);
if let Err(e) = recovery_storage.remove_voucher(voucher.to_string()) {
warn!("Could not remove recovery data: {e}");
}
}
}
Ok(recovered_amount)
}
+2 -1
View File
@@ -8,7 +8,8 @@ edition = "2021"
[dependencies]
bls12_381 = { version = "0.5", default-features = false, features = ["pairings", "alloc", "experimental"] }
cosmrs = { workspace = true }
thiserror = "1.0"
thiserror = { workspace = true }
log = { workspace = true }
# I guess temporarily until we get serde support in coconut up and running
nym-coconut-interface = { path = "../coconut-interface" }
+21 -8
View File
@@ -1,6 +1,10 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::coconut::bandwidth::{BandwidthVoucher, PRIVATE_ATTRIBUTES, PUBLIC_ATTRIBUTES};
use crate::coconut::params::{NymApiCredentialEncryptionAlgorithm, NymApiCredentialHkdfAlgorithm};
use crate::error::Error;
use log::{debug, warn};
use nym_api_requests::coconut::BlindSignRequestBody;
use nym_coconut_interface::{
aggregate_signature_shares, aggregate_verification_keys, prove_bandwidth_credential, Attribute,
@@ -11,10 +15,6 @@ use nym_crypto::shared_key::recompute_shared_key;
use nym_crypto::symmetric::stream_cipher;
use nym_validator_client::client::CoconutApiClient;
use crate::coconut::bandwidth::{BandwidthVoucher, PRIVATE_ATTRIBUTES, PUBLIC_ATTRIBUTES};
use crate::coconut::params::{NymApiCredentialEncryptionAlgorithm, NymApiCredentialHkdfAlgorithm};
use crate::error::Error;
pub async fn obtain_aggregate_verification_key(
api_clients: &[CoconutApiClient],
) -> Result<VerificationKey, Error> {
@@ -107,7 +107,12 @@ pub async fn obtain_aggregate_signature(
aggregate_verification_keys(&validators_partial_vks, Some(indices.as_ref()))?;
for coconut_api_client in coconut_api_clients.iter() {
if let Ok(signature) = obtain_partial_credential(
debug!(
"attempting to obtain partial credential from {}",
coconut_api_client.api_client.api_url()
);
match obtain_partial_credential(
params,
attributes,
&coconut_api_client.api_client,
@@ -115,9 +120,17 @@ pub async fn obtain_aggregate_signature(
)
.await
{
let share = SignatureShare::new(signature, coconut_api_client.node_id);
shares.push(share)
}
Ok(signature) => {
let share = SignatureShare::new(signature, coconut_api_client.node_id);
shares.push(share)
}
Err(err) => {
warn!(
"failed to obtain partial credential from {}: {err}",
coconut_api_client.api_client.api_url()
);
}
};
}
if shares.len() < threshold as usize {
return Err(Error::NotEnoughShares);
+23 -2
View File
@@ -4,11 +4,11 @@
use crate::var_names::{DEPRECATED_API_VALIDATOR, DEPRECATED_NYMD_VALIDATOR, NYM_API, NYXD};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use std::path::Path;
use std::{
env::{var, VarError},
ffi::OsStr,
ops::Not,
path::PathBuf,
};
use url::Url;
@@ -30,6 +30,7 @@ pub struct NymContracts {
pub group_contract_address: Option<String>,
pub multisig_contract_address: Option<String>,
pub coconut_dkg_contract_address: Option<String>,
pub ephemera_contract_address: Option<String>,
pub service_provider_directory_contract_address: Option<String>,
pub name_service_contract_address: Option<String>,
}
@@ -42,6 +43,7 @@ pub struct NymNetworkDetails {
pub chain_details: ChainDetails,
pub endpoints: Vec<ValidatorDetails>,
pub contracts: NymContracts,
pub explorer_api: Option<String>,
}
// by default we assume the same defaults as mainnet, i.e. same prefixes and denoms
@@ -70,6 +72,7 @@ impl NymNetworkDetails {
},
endpoints: Default::default(),
contracts: Default::default(),
explorer_api: Default::default(),
}
}
@@ -128,10 +131,14 @@ impl NymNetworkDetails {
.with_coconut_dkg_contract(Some(
var(var_names::COCONUT_DKG_CONTRACT_ADDRESS).expect("coconut dkg contract not set"),
))
.with_ephemera_contract(Some(
var(var_names::EPHEMERA_CONTRACT_ADDRESS).expect("ephemera contract not set"),
))
.with_service_provider_directory_contract(get_optional_env(
var_names::SERVICE_PROVIDER_DIRECTORY_CONTRACT_ADDRESS,
))
.with_name_service_contract(get_optional_env(var_names::NAME_SERVICE_CONTRACT_ADDRESS))
.with_explorer_api(get_optional_env(var_names::EXPLORER_API))
}
pub fn new_mainnet() -> Self {
@@ -159,9 +166,11 @@ impl NymNetworkDetails {
coconut_dkg_contract_address: parse_optional_str(
mainnet::COCONUT_DKG_CONTRACT_ADDRESS,
),
ephemera_contract_address: parse_optional_str(mainnet::EPHEMERA_CONTRACT_ADDRESS),
service_provider_directory_contract_address: None,
name_service_contract_address: None,
},
explorer_api: parse_optional_str(mainnet::EXPLORER_API),
}
}
@@ -253,6 +262,12 @@ impl NymNetworkDetails {
self
}
#[must_use]
pub fn with_ephemera_contract<S: Into<String>>(mut self, contract: Option<S>) -> Self {
self.contracts.ephemera_contract_address = contract.map(Into::into);
self
}
#[must_use]
pub fn with_service_provider_directory_contract<S: Into<String>>(
mut self,
@@ -267,6 +282,12 @@ impl NymNetworkDetails {
self.contracts.name_service_contract_address = contract.map(Into::into);
self
}
#[must_use]
pub fn with_explorer_api<S: Into<String>>(mut self, endpoint: Option<S>) -> Self {
self.explorer_api = endpoint.map(Into::into);
self
}
}
#[derive(Debug, Copy, Serialize, Deserialize, Clone, PartialEq, Eq)]
@@ -367,7 +388,7 @@ fn fix_deprecated_environmental_variables() {
}
}
pub fn setup_env(config_env_file: Option<&PathBuf>) {
pub fn setup_env<P: AsRef<Path>>(config_env_file: Option<P>) {
match std::env::var(var_names::CONFIGURED) {
// if the configuration is not already set in the env vars
Err(std::env::VarError::NotPresent) => {
+13
View File
@@ -20,11 +20,14 @@ pub(crate) const COCONUT_BANDWIDTH_CONTRACT_ADDRESS: &str =
pub(crate) const GROUP_CONTRACT_ADDRESS: &str = "n19lc9u84cz0yz3fww5283nucc9yvr8gsjmgeul0";
pub(crate) const MULTISIG_CONTRACT_ADDRESS: &str = "n19lc9u84cz0yz3fww5283nucc9yvr8gsjmgeul0";
pub(crate) const COCONUT_DKG_CONTRACT_ADDRESS: &str = "n19lc9u84cz0yz3fww5283nucc9yvr8gsjmgeul0";
pub(crate) const EPHEMERA_CONTRACT_ADDRESS: &str = "n19lc9u84cz0yz3fww5283nucc9yvr8gsjmgeul0";
pub(crate) const REWARDING_VALIDATOR_ADDRESS: &str = "n10yyd98e2tuwu0f7ypz9dy3hhjw7v772q6287gy";
pub const STATISTICS_SERVICE_DOMAIN_ADDRESS: &str = "https://mainnet-stats.nymte.ch:8090/";
pub const NYXD_URL: &str = "https://rpc.nymtech.net";
pub const NYM_API: &str = "https://validator.nymtech.net/api/";
pub const EXPLORER_API: &str = "https://explorer.nymtech.net/api/";
pub(crate) fn validators() -> Vec<ValidatorDetails> {
vec![ValidatorDetails::new(NYXD_URL, Some(NYM_API))]
}
@@ -84,6 +87,10 @@ pub fn export_to_env() {
var_names::COCONUT_DKG_CONTRACT_ADDRESS,
COCONUT_DKG_CONTRACT_ADDRESS,
);
set_var_to_default(
var_names::EPHEMERA_CONTRACT_ADDRESS,
EPHEMERA_CONTRACT_ADDRESS,
);
set_var_to_default(
var_names::REWARDING_VALIDATOR_ADDRESS,
REWARDING_VALIDATOR_ADDRESS,
@@ -94,6 +101,7 @@ pub fn export_to_env() {
);
set_var_to_default(var_names::NYXD, NYXD_URL);
set_var_to_default(var_names::NYM_API, NYM_API);
set_var_to_default(var_names::EXPLORER_API, EXPLORER_API);
}
pub fn export_to_env_if_not_set() {
@@ -126,6 +134,10 @@ pub fn export_to_env_if_not_set() {
var_names::COCONUT_DKG_CONTRACT_ADDRESS,
COCONUT_DKG_CONTRACT_ADDRESS,
);
set_var_conditionally_to_default(
var_names::EPHEMERA_CONTRACT_ADDRESS,
EPHEMERA_CONTRACT_ADDRESS,
);
set_var_conditionally_to_default(
var_names::REWARDING_VALIDATOR_ADDRESS,
REWARDING_VALIDATOR_ADDRESS,
@@ -136,4 +148,5 @@ pub fn export_to_env_if_not_set() {
);
set_var_conditionally_to_default(var_names::NYXD, NYXD_URL);
set_var_conditionally_to_default(var_names::NYM_API, NYM_API);
set_var_conditionally_to_default(var_names::EXPLORER_API, EXPLORER_API);
}
+2
View File
@@ -18,6 +18,7 @@ pub const COCONUT_BANDWIDTH_CONTRACT_ADDRESS: &str = "COCONUT_BANDWIDTH_CONTRACT
pub const GROUP_CONTRACT_ADDRESS: &str = "GROUP_CONTRACT_ADDRESS";
pub const MULTISIG_CONTRACT_ADDRESS: &str = "MULTISIG_CONTRACT_ADDRESS";
pub const COCONUT_DKG_CONTRACT_ADDRESS: &str = "COCONUT_DKG_CONTRACT_ADDRESS";
pub const EPHEMERA_CONTRACT_ADDRESS: &str = "EPHEMERA_CONTRACT_ADDRESS";
pub const REWARDING_VALIDATOR_ADDRESS: &str = "REWARDING_VALIDATOR_ADDRESS";
pub const STATISTICS_SERVICE_DOMAIN_ADDRESS: &str = "STATISTICS_SERVICE_DOMAIN_ADDRESS";
pub const SERVICE_PROVIDER_DIRECTORY_CONTRACT_ADDRESS: &str =
@@ -25,6 +26,7 @@ pub const SERVICE_PROVIDER_DIRECTORY_CONTRACT_ADDRESS: &str =
pub const NAME_SERVICE_CONTRACT_ADDRESS: &str = "NAME_SERVICE_CONTRACT_ADDRESS";
pub const NYXD: &str = "NYXD";
pub const NYM_API: &str = "NYM_API";
pub const EXPLORER_API: &str = "EXPLORER_API";
pub const DKG_TIME_CONFIGURATION: &str = "DKG_TIME_CONFIGURATION";
+2 -2
View File
@@ -354,7 +354,7 @@ impl ProofKappaZeta {
let witness_blinder = params.random_scalar();
let witness_serial_number = params.random_scalar();
let witness_binding_number = params.random_scalar();
let witness_attributes = vec![witness_serial_number, witness_binding_number];
let witness_attributes = [witness_serial_number, witness_binding_number];
let beta_bytes = verification_key
.beta_g2
@@ -417,7 +417,7 @@ impl ProofKappaZeta {
.map(|beta_i| beta_i.to_bytes())
.collect::<Vec<_>>();
let response_attributes = vec![self.response_serial_number, self.response_binding_number];
let response_attributes = [self.response_serial_number, self.response_binding_number];
// re-compute witnesses commitments
// Aw = (c * kappa) + (rt * g2) + ((1 - c) * alpha) + (rm[0] * beta[0]) + ... + (rm[i] * beta[i])
let commitment_kappa = kappa * self.challenge
@@ -17,7 +17,7 @@ pub fn prepare_identifier<R: RngCore + CryptoRng>(
let id_ciphertext = encrypt::<AckEncryptionAlgorithm>(key.inner(), &iv, &serialized_id);
// IV || ID_CIPHERTEXT
iv.into_iter().chain(id_ciphertext.into_iter()).collect()
iv.into_iter().chain(id_ciphertext).collect()
}
pub fn recover_identifier(
@@ -122,7 +122,7 @@ impl SurbAck {
.first_hop_address
.as_zero_padded_bytes(MAX_NODE_ADDRESS_UNPADDED_LEN)
.into_iter()
.chain(self.surb_ack_packet.to_bytes()?.into_iter())
.chain(self.surb_ack_packet.to_bytes()?)
.collect();
Ok((self.expected_total_delay, surb_bytes))
}
@@ -130,7 +130,7 @@ impl ReplySurb {
self.encryption_key
.to_bytes()
.into_iter()
.chain(self.surb.to_bytes().into_iter())
.chain(self.surb.to_bytes())
.collect()
}
@@ -275,7 +275,7 @@ impl RepliableMessageContent {
.to_be_bytes()
.into_iter()
.chain(reply_surbs.into_iter().flat_map(|s| s.to_bytes()))
.chain(message.into_iter())
.chain(message)
.collect()
}
RepliableMessageContent::AdditionalSurbs { reply_surbs } => {
@@ -465,7 +465,7 @@ impl ReplyMessageContent {
ReplyMessageContent::SurbRequest { recipient, amount } => recipient
.to_bytes()
.into_iter()
.chain(amount.to_be_bytes().into_iter())
.chain(amount.to_be_bytes())
.collect(),
}
}
+1 -1
View File
@@ -204,7 +204,7 @@ impl Fragment {
self.header
.to_bytes()
.into_iter()
.chain(self.payload.into_iter())
.chain(self.payload)
.collect()
}
+1 -1
View File
@@ -115,7 +115,7 @@ where
let packet_payload: Vec<_> = ack_bytes
.into_iter()
.chain(ephemeral_keypair.public_key().to_bytes().iter().cloned())
.chain(cover_content.into_iter())
.chain(cover_content)
.collect();
let route =
+2 -2
View File
@@ -106,8 +106,8 @@ impl MixPacket {
pub fn into_bytes(self) -> Result<Vec<u8>, MixPacketFormattingError> {
Ok(std::iter::once(self.packet_type as u8)
.chain(self.next_hop.as_bytes().into_iter())
.chain(self.packet.to_bytes()?.into_iter())
.chain(self.next_hop.as_bytes())
.chain(self.packet.to_bytes()?)
.collect())
}
}
+3 -6
View File
@@ -50,8 +50,8 @@ impl NymPayloadBuilder {
Ok(NymPayload(
surb_ack_bytes
.into_iter()
.chain(variant_data.into_iter())
.chain(fragment_data.into_iter())
.chain(variant_data)
.chain(fragment_data)
.collect(),
))
}
@@ -61,10 +61,7 @@ impl NymPayloadBuilder {
packet_encryption_key: &SurbEncryptionKey,
) -> Result<NymPayload, SurbAckRecoveryError> {
let key_digest = packet_encryption_key.compute_digest();
self.build::<ReplySurbEncryptionAlgorithm>(
packet_encryption_key.inner(),
key_digest.into_iter(),
)
self.build::<ReplySurbEncryptionAlgorithm>(packet_encryption_key.inner(), key_digest)
}
pub fn build_regular<R>(
+5 -9
View File
@@ -73,7 +73,7 @@ impl SocketDataHeader {
.to_be_bytes()
.into_iter()
.chain(std::iter::once(self.local_socket_closed as u8))
.chain(self.seq.to_be_bytes().into_iter())
.chain(self.seq.to_be_bytes())
}
pub fn try_from_response_bytes(
@@ -107,8 +107,8 @@ impl SocketDataHeader {
pub fn into_response_bytes_iter(self) -> impl Iterator<Item = u8> {
std::iter::once(self.local_socket_closed as u8)
.chain(self.connection_id.to_be_bytes().into_iter())
.chain(self.seq.to_be_bytes().into_iter())
.chain(self.connection_id.to_be_bytes())
.chain(self.seq.to_be_bytes())
}
}
@@ -170,9 +170,7 @@ impl SocketData {
}
pub fn into_request_bytes_iter(self) -> impl Iterator<Item = u8> {
self.header
.into_request_bytes_iter()
.chain(self.data.into_iter())
self.header.into_request_bytes_iter().chain(self.data)
}
pub fn try_from_response_bytes(b: &[u8]) -> Result<SocketData, InsufficientSocketDataError> {
@@ -190,9 +188,7 @@ impl SocketData {
}
pub fn into_response_bytes_iter(self) -> impl Iterator<Item = u8> {
self.header
.into_response_bytes_iter()
.chain(self.data.into_iter())
self.header.into_response_bytes_iter().chain(self.data)
}
}
+9 -15
View File
@@ -113,7 +113,7 @@ impl Serializable for Socks5Request {
fn into_bytes(self) -> Vec<u8> {
if let Some(version) = self.protocol_version.as_u8() {
std::iter::once(version)
.chain(self.content.into_bytes().into_iter())
.chain(self.content.into_bytes())
.collect()
} else {
std::iter::once(Self::LEGACY_TYPE_TAG)
@@ -335,12 +335,12 @@ impl Socks5RequestContent {
let remote_address_bytes_len = remote_address_bytes.len() as u16;
let iter = std::iter::once(RequestFlag::Connect as u8)
.chain(req.conn_id.to_be_bytes().into_iter())
.chain(remote_address_bytes_len.to_be_bytes().into_iter())
.chain(remote_address_bytes.into_iter());
.chain(req.conn_id.to_be_bytes())
.chain(remote_address_bytes_len.to_be_bytes())
.chain(remote_address_bytes);
if let Some(return_address) = req.return_address {
iter.chain(return_address.to_bytes().into_iter()).collect()
iter.chain(return_address.to_bytes()).collect()
} else {
iter.collect()
}
@@ -358,7 +358,7 @@ impl Socks5RequestContent {
})
.unwrap_or_default();
std::iter::once(RequestFlag::Query as u8)
.chain(query_bytes.into_iter())
.chain(query_bytes)
.collect()
}
}
@@ -495,7 +495,7 @@ mod request_deserialization_tests {
let request_bytes: Vec<_> = request_bytes_prefix
.iter()
.cloned()
.chain(recipient_bytes.into_iter())
.chain(recipient_bytes)
.collect();
assert!(Socks5RequestContent::try_from_bytes(&request_bytes)
.unwrap_err()
@@ -530,10 +530,7 @@ mod request_deserialization_tests {
let recipient = Recipient::try_from_base58_string("CytBseW6yFXUMzz4SGAKdNLGR7q3sJLLYxyBGvutNEQV.4QXYyEVc5fUDjmmi8PrHN9tdUFV4PCvSJE1278cHyvoe@4sBbL1ngf1vtNqykydQKTFh26sQCw888GpUqvPvyNB4f").unwrap();
let recipient_bytes = recipient.to_bytes();
let request_bytes: Vec<_> = request_bytes
.into_iter()
.chain(recipient_bytes.into_iter())
.collect();
let request_bytes: Vec<_> = request_bytes.into_iter().chain(recipient_bytes).collect();
let request = Socks5RequestContent::try_from_bytes(&request_bytes).unwrap();
match request {
@@ -577,10 +574,7 @@ mod request_deserialization_tests {
let recipient = Recipient::try_from_base58_string("CytBseW6yFXUMzz4SGAKdNLGR7q3sJLLYxyBGvutNEQV.4QXYyEVc5fUDjmmi8PrHN9tdUFV4PCvSJE1278cHyvoe@4sBbL1ngf1vtNqykydQKTFh26sQCw888GpUqvPvyNB4f").unwrap();
let recipient_bytes = recipient.to_bytes();
let request_bytes: Vec<_> = request_bytes
.into_iter()
.chain(recipient_bytes.into_iter())
.collect();
let request_bytes: Vec<_> = request_bytes.into_iter().chain(recipient_bytes).collect();
let request = Socks5RequestContent::try_from_bytes(&request_bytes).unwrap();
match request {
+5 -5
View File
@@ -84,7 +84,7 @@ impl Serializable for Socks5Response {
fn into_bytes(self) -> Vec<u8> {
if let Some(version) = self.protocol_version.as_u8() {
std::iter::once(version)
.chain(self.content.into_bytes().into_iter())
.chain(self.content.into_bytes())
.collect()
} else {
self.content.into_bytes()
@@ -192,7 +192,7 @@ impl Socks5ResponseContent {
}
Socks5ResponseContent::ConnectionError(res) => {
std::iter::once(ResponseFlag::ConnectionError as u8)
.chain(res.into_bytes().into_iter())
.chain(res.into_bytes())
.collect()
}
Socks5ResponseContent::Query(query) => {
@@ -204,7 +204,7 @@ impl Socks5ResponseContent {
})
.unwrap_or_default();
std::iter::once(ResponseFlag::Query as u8)
.chain(query_bytes.into_iter())
.chain(query_bytes)
.collect()
}
}
@@ -290,7 +290,7 @@ impl ConnectionError {
.to_be_bytes()
.iter()
.copied()
.chain(self.network_requester_error.into_bytes().into_iter())
.chain(self.network_requester_error.into_bytes())
.collect()
}
}
@@ -339,7 +339,7 @@ mod tests {
let bytes: Vec<u8> = 42u64
.to_be_bytes()
.into_iter()
.chain([0, 159, 146, 150].into_iter())
.chain([0, 159, 146, 150])
.collect();
let err = ConnectionError::try_from_bytes(&bytes).err().unwrap();
assert!(matches!(
+1 -1
View File
@@ -131,7 +131,7 @@ impl NymTopology {
}
pub fn mixes_in_layer(&self, layer: MixLayer) -> Vec<mix::Node> {
assert!(vec![1, 2, 3].contains(&layer));
assert!([1, 2, 3].contains(&layer));
self.mixes.get(&layer).unwrap().to_owned()
}
+1 -1
View File
@@ -17,7 +17,7 @@ serde_json = { workspace = true }
strum = { version = "0.23", features = ["derive"] }
thiserror = { workspace = true }
url = { workspace = true }
ts-rs = "6.1.2"
ts-rs = { workspace = true }
cosmwasm-std = { workspace = true }
cosmrs = { workspace = true }
-1
View File
@@ -5,7 +5,6 @@ use crate::console_log;
use crate::storage::cipher_export::StoredExportedStoreCipher;
use crate::storage::error::StorageError;
use futures::TryFutureExt;
use indexed_db_futures::IdbDatabase;
use nym_store_cipher::{
Aes256Gcm, Algorithm, EncryptedData, KdfInfo, KeySizeUser, Params, StoreCipher, Unsigned,
Version,
+30
View File
@@ -1259,6 +1259,36 @@ dependencies = [
"zeroize",
]
[[package]]
name = "nym-ephemera"
version = "0.1.0"
dependencies = [
"cosmwasm-schema",
"cosmwasm-std",
"cosmwasm-storage",
"cw-controllers",
"cw-multi-test",
"cw-storage-plus",
"cw4",
"cw4-group",
"lazy_static",
"nym-ephemera-common",
"nym-group-contract-common",
"rusty-fork",
"serde",
"thiserror",
]
[[package]]
name = "nym-ephemera-common"
version = "0.1.0"
dependencies = [
"cosmwasm-schema",
"cosmwasm-std",
"cw-utils",
"nym-contracts-common",
]
[[package]]
name = "nym-group-contract-common"
version = "0.1.0"
+1
View File
@@ -3,6 +3,7 @@ members = [
"coconut-bandwidth",
"coconut-dkg",
"coconut-test",
"ephemera",
"mixnet",
"mixnet-vesting-integration-tests",
"multisig/cw3-flex-multisig",
+5
View File
@@ -0,0 +1,5 @@
[alias]
wasm = "build --release --lib --target wasm32-unknown-unknown"
wasm-debug = "build --target wasm32-unknown-unknown"
unit-test = "test --lib"
schema = "run --bin schema --features=schema-gen"
+36
View File
@@ -0,0 +1,36 @@
[package]
name = "nym-ephemera"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[[bin]]
name = "schema"
required-features = ["schema-gen"]
[lib]
crate-type = ["cdylib", "rlib"]
[dependencies]
nym-ephemera-common = { path = "../../common/cosmwasm-smart-contracts/ephemera" }
cosmwasm-schema = { workspace = true, optional = true }
cosmwasm-std = { workspace = true }
cosmwasm-storage = { workspace = true }
cw-storage-plus = { workspace = true }
cw-controllers = { workspace = true }
cw4 = { workspace = true }
serde = { version = "1.0.103", default-features = false, features = ["derive"] }
thiserror = "1.0.23"
[dev-dependencies]
cw-multi-test = { workspace = true }
cw4-group = { path = "../multisig/cw4-group" }
nym-group-contract-common = { path = "../../common/cosmwasm-smart-contracts/group-contract" }
lazy_static = "1.4"
rusty-fork = "0.3"
[features]
schema-gen = ["nym-ephemera-common/schema", "cosmwasm-schema"]
+2
View File
@@ -0,0 +1,2 @@
generate-schema:
cargo schema
+194
View File
@@ -0,0 +1,194 @@
{
"contract_name": "nym-ephemera",
"contract_version": "0.1.0",
"idl_version": "1.0.0",
"instantiate": {
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "InstantiateMsg",
"type": "object",
"required": [
"group_addr",
"mix_denom"
],
"properties": {
"group_addr": {
"type": "string"
},
"mix_denom": {
"type": "string"
}
},
"additionalProperties": false
},
"execute": {
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "ExecuteMsg",
"oneOf": [
{
"type": "object",
"required": [
"register_peer"
],
"properties": {
"register_peer": {
"type": "object",
"required": [
"peer_info"
],
"properties": {
"peer_info": {
"$ref": "#/definitions/JsonPeerInfo"
}
},
"additionalProperties": false
}
},
"additionalProperties": false
}
],
"definitions": {
"Addr": {
"description": "A human readable address.\n\nIn Cosmos, this is typically bech32 encoded. But for multi-chain smart contracts no assumptions should be made other than being UTF-8 encoded and of reasonable length.\n\nThis type represents a validated address. It can be created in the following ways 1. Use `Addr::unchecked(input)` 2. Use `let checked: Addr = deps.api.addr_validate(input)?` 3. Use `let checked: Addr = deps.api.addr_humanize(canonical_addr)?` 4. Deserialize from JSON. This must only be done from JSON that was validated before such as a contract's state. `Addr` must not be used in messages sent by the user because this would result in unvalidated instances.\n\nThis type is immutable. If you really need to mutate it (Really? Are you sure?), create a mutable copy using `let mut mutable = Addr::to_string()` and operate on that `String` instance.",
"type": "string"
},
"JsonPeerInfo": {
"type": "object",
"required": [
"cosmos_address",
"ip_address",
"public_key"
],
"properties": {
"cosmos_address": {
"description": "The cosmos address of the peer, used in interacting with the chain.",
"allOf": [
{
"$ref": "#/definitions/Addr"
}
]
},
"ip_address": {
"description": "The TCP/IP address of the peer. Expected formats: 1. `<IP>:<PORT>` 2. `/ip4/<IP>/tcp/<PORT>` - this is the format used by libp2p multiaddr",
"type": "string"
},
"public_key": {
"description": "Serialized public key.",
"type": "string"
}
},
"additionalProperties": false
}
}
},
"query": {
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "QueryMsg",
"oneOf": [
{
"type": "object",
"required": [
"get_peers"
],
"properties": {
"get_peers": {
"type": "object",
"properties": {
"limit": {
"type": [
"integer",
"null"
],
"format": "uint32",
"minimum": 0.0
},
"start_after": {
"type": [
"string",
"null"
]
}
},
"additionalProperties": false
}
},
"additionalProperties": false
}
]
},
"migrate": {
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "MigrateMsg",
"type": "object",
"additionalProperties": false
},
"sudo": null,
"responses": {
"get_peers": {
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "PagedPeerResponse",
"type": "object",
"required": [
"peers",
"per_page"
],
"properties": {
"peers": {
"type": "array",
"items": {
"$ref": "#/definitions/JsonPeerInfo"
}
},
"per_page": {
"type": "integer",
"format": "uint",
"minimum": 0.0
},
"start_next_after": {
"description": "Field indicating paging information for the following queries if the caller wishes to get further entries.",
"anyOf": [
{
"$ref": "#/definitions/Addr"
},
{
"type": "null"
}
]
}
},
"additionalProperties": false,
"definitions": {
"Addr": {
"description": "A human readable address.\n\nIn Cosmos, this is typically bech32 encoded. But for multi-chain smart contracts no assumptions should be made other than being UTF-8 encoded and of reasonable length.\n\nThis type represents a validated address. It can be created in the following ways 1. Use `Addr::unchecked(input)` 2. Use `let checked: Addr = deps.api.addr_validate(input)?` 3. Use `let checked: Addr = deps.api.addr_humanize(canonical_addr)?` 4. Deserialize from JSON. This must only be done from JSON that was validated before such as a contract's state. `Addr` must not be used in messages sent by the user because this would result in unvalidated instances.\n\nThis type is immutable. If you really need to mutate it (Really? Are you sure?), create a mutable copy using `let mut mutable = Addr::to_string()` and operate on that `String` instance.",
"type": "string"
},
"JsonPeerInfo": {
"type": "object",
"required": [
"cosmos_address",
"ip_address",
"public_key"
],
"properties": {
"cosmos_address": {
"description": "The cosmos address of the peer, used in interacting with the chain.",
"allOf": [
{
"$ref": "#/definitions/Addr"
}
]
},
"ip_address": {
"description": "The TCP/IP address of the peer. Expected formats: 1. `<IP>:<PORT>` 2. `/ip4/<IP>/tcp/<PORT>` - this is the format used by libp2p multiaddr",
"type": "string"
},
"public_key": {
"description": "Serialized public key.",
"type": "string"
}
},
"additionalProperties": false
}
}
}
}
}
@@ -0,0 +1,60 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "ExecuteMsg",
"oneOf": [
{
"type": "object",
"required": [
"register_peer"
],
"properties": {
"register_peer": {
"type": "object",
"required": [
"peer_info"
],
"properties": {
"peer_info": {
"$ref": "#/definitions/JsonPeerInfo"
}
},
"additionalProperties": false
}
},
"additionalProperties": false
}
],
"definitions": {
"Addr": {
"description": "A human readable address.\n\nIn Cosmos, this is typically bech32 encoded. But for multi-chain smart contracts no assumptions should be made other than being UTF-8 encoded and of reasonable length.\n\nThis type represents a validated address. It can be created in the following ways 1. Use `Addr::unchecked(input)` 2. Use `let checked: Addr = deps.api.addr_validate(input)?` 3. Use `let checked: Addr = deps.api.addr_humanize(canonical_addr)?` 4. Deserialize from JSON. This must only be done from JSON that was validated before such as a contract's state. `Addr` must not be used in messages sent by the user because this would result in unvalidated instances.\n\nThis type is immutable. If you really need to mutate it (Really? Are you sure?), create a mutable copy using `let mut mutable = Addr::to_string()` and operate on that `String` instance.",
"type": "string"
},
"JsonPeerInfo": {
"type": "object",
"required": [
"cosmos_address",
"ip_address",
"public_key"
],
"properties": {
"cosmos_address": {
"description": "The cosmos address of the peer, used in interacting with the chain.",
"allOf": [
{
"$ref": "#/definitions/Addr"
}
]
},
"ip_address": {
"description": "The TCP/IP address of the peer. Expected formats: 1. `<IP>:<PORT>` 2. `/ip4/<IP>/tcp/<PORT>` - this is the format used by libp2p multiaddr",
"type": "string"
},
"public_key": {
"description": "Serialized public key.",
"type": "string"
}
},
"additionalProperties": false
}
}
}
@@ -0,0 +1,18 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "InstantiateMsg",
"type": "object",
"required": [
"group_addr",
"mix_denom"
],
"properties": {
"group_addr": {
"type": "string"
},
"mix_denom": {
"type": "string"
}
},
"additionalProperties": false
}
@@ -0,0 +1,6 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "MigrateMsg",
"type": "object",
"additionalProperties": false
}

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