Compare commits

..

161 Commits

Author SHA1 Message Date
Sachin Kamath 1bdcf9c3cf fix review comments 2024-11-06 14:16:13 +05:30
Sachin Kamath 4ebb9cd239 clippy 2024-11-05 16:01:18 +05:30
Sachin Kamath 620d68ea2f nyxd-scraper: add config to make pre-commit storage optional 2024-11-05 15:49:30 +05:30
Dinko Zdravac b747308f74 Add subcommand to image (#5056) 2024-10-29 10:52:33 +01:00
Dinko Zdravac afdd721cc3 Ns agent workflow (#5055)
* feat: add dockerfile

* add github workflow for node status agent

---------

Co-authored-by: Fran Arbanas <arbanasfran@gmail.com>
2024-10-29 10:39:58 +01:00
Dinko Zdravac 9f5c4c5968 Merge pull request #5050 from nymtech/dz-node-status-api
Node Status API
2024-10-29 00:43:33 +01:00
dynco-nym 9583a5c6c8 Fix build script 2024-10-29 00:24:18 +01:00
Tommy Verrall da60fc0ade Merge pull request #5052 from nymtech/feat/add-node-status-agent-workflow
feat: add simple node-status-agent
2024-10-28 19:30:52 +00:00
Fran Arbanas 96b54c455e feat: add simple node-status-agent 2024-10-28 19:16:46 +01:00
Dinko Zdravac cc983963d4 Fully functional network scores (#5048)
* Compile & copy wg probe

* Node status agent WIP

* Enable debug logging

* Agent submits results
- add clap to agent
- agent runs network probe
- /submit endpoint on NS API

* Build clients with timeouts

* Update logging and dev scripts

* Replace /blaclisted endpoint

* Testruns fully functional
- task that queues testruns periodically
- testruns read/write in DB

* Probe scores fully working
- testruns are assigned on API
- submit updates testruns correctly on NS API side
- agent registers with API
- agent submits results correctly

* Clippy fixes

* PR feedback

* Clippy again

* PR feedback

* Run clippy earlier in CI

* Make refresh delay configurable in server & agent
2024-10-28 17:31:43 +01:00
Fran Arbanas 40d9321aec Node status API dockerfile and env vars (#4986)
* feat: add dockerfile and env variables

* Added workflow for pushing node status api on harbor

* Misc changes to pathing and using yq instead of jq

* fix: change the way we read env vars for nyxd, nym api and explorer

* fix: docker build workflow

* Remove config in favor of clap args

* Added naming and tags

* change from value to result

---------

Co-authored-by: Lawrence Stalder <lawrence@nymtech.net>
Co-authored-by: dynco-nym <173912580+dynco-nym@users.noreply.github.com>
2024-10-28 17:07:38 +01:00
dynco-nym e5a29cc76e Work with directory pre-v2.1
Rebase + point to earlier network client code

Adjust to new Nym API types

Refer to earlier client code

Revert "Rebase + point to earlier network client code"

This reverts commit dd75e7dc0695c25b0883e2f5dd15b7d70165e9e8.

Point to earlier commit
2024-10-28 17:04:22 +01:00
Dinko Zdravac 56c55f6b95 Working HTTP server (#4941)
* Server file structure

* Create HTTP server
- graceful shutdown
- routes
- logging, CORS

* gateways WIP

* gateways API + swagger docs complete

* Mixnodes API + swagger docs complete

* Services API + swagger docs complete

* Commit summary insert

* Make troubleshooting DB easier

* Summary API + swagger docs

* Client log changes

* QOL improvements

- remove implicit panics via `as`
- safer DTO conversions
- add logging
- new config
2024-10-28 16:59:12 +01:00
Dinko Zdravac 2f051fd943 Node Status API background task (#4854)
* Setup new package

* Setup DB

* Fetch & store mixnodes/GWs
- refactor db package structure
- finally solve DATABASE_URL: absolute path works best

* Additional query functionality
- missing only daily summary, which requires type refactoring

* Replace type alias tuples with structs

* Insert summary

* Add github job to build package

* Build script for sqlx

* Remove data dir
- useless now that sqlx DB sits in OUT_DIR

* PR feedback
2024-10-28 16:54:26 +01:00
Bogdan-Ștefan Neacşu c03cf86000 Authenticator CLI client mode (#5044) 2024-10-28 16:42:05 +02:00
Simon Wicky ab11508235 [Product Data] Introduce data persistence on gateways (#5022)
* add stats storage to gateways

* config fix

* add stats storage model and logic

* adapt stats collection to new storage

* stats cleanup on start

* change to linux only code

* tweaks

* modified stats cleanup + change session started

* change wrong table name

* store crashed session as 0 duration

* adapt for sqlx 0.7

* remove unused dependencies

* revert changes from gateway config, as it is broken anyway

* copyright and misc stuff

---------

Co-authored-by: Simon Wicky <simon@linode2-2.net>
2024-10-28 09:25:37 +01:00
Fran Arbanas e65bfaeb31 Fix/nym data observatory dockerfile (#5021)
* fix: added needed env vars to dockerfile, updated db env for a bit

* feat: add github workflow for pushing data observatory

* feat: split the postgresql connection string into multiple variables

* fix docker compose

* fix workflow

* fix: short in clap
2024-10-24 18:10:34 +02:00
Jędrzej Stuczyński 5a6982fd10 Merge pull request #5011 from nymtech/dependabot/cargo/patch-updates-9a83837eff
Bump the patch-updates group across 1 directory with 10 updates
2024-10-23 10:51:55 +01:00
dependabot[bot] 7abe1f505c Bump the patch-updates group across 1 directory with 10 updates
Bumps the patch-updates group with 9 updates in the / directory:

| Package | From | To |
| --- | --- | --- |
| [anyhow](https://github.com/dtolnay/anyhow) | `1.0.89` | `1.0.90` |
| [clap](https://github.com/clap-rs/clap) | `4.5.18` | `4.5.20` |
| [clap_complete](https://github.com/clap-rs/clap) | `4.5.29` | `4.5.33` |
| [pin-project](https://github.com/taiki-e/pin-project) | `1.1.5` | `1.1.6` |
| [serde](https://github.com/serde-rs/serde) | `1.0.210` | `1.0.211` |
| [serde_json](https://github.com/serde-rs/json) | `1.0.128` | `1.0.132` |
| [wasm-bindgen](https://github.com/rustwasm/wasm-bindgen) | `0.2.93` | `0.2.95` |
| [wasm-bindgen-futures](https://github.com/rustwasm/wasm-bindgen) | `0.4.43` | `0.4.45` |
| [web-sys](https://github.com/rustwasm/wasm-bindgen) | `0.3.70` | `0.3.72` |



Updates `anyhow` from 1.0.89 to 1.0.90
- [Release notes](https://github.com/dtolnay/anyhow/releases)
- [Commits](https://github.com/dtolnay/anyhow/compare/1.0.89...1.0.90)

Updates `clap` from 4.5.18 to 4.5.20
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v4.5.18...clap_complete-v4.5.20)

Updates `clap_complete` from 4.5.29 to 4.5.33
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v4.5.29...clap_complete-v4.5.33)

Updates `pin-project` from 1.1.5 to 1.1.6
- [Release notes](https://github.com/taiki-e/pin-project/releases)
- [Changelog](https://github.com/taiki-e/pin-project/blob/main/CHANGELOG.md)
- [Commits](https://github.com/taiki-e/pin-project/compare/v1.1.5...v1.1.6)

Updates `serde` from 1.0.210 to 1.0.211
- [Release notes](https://github.com/serde-rs/serde/releases)
- [Commits](https://github.com/serde-rs/serde/compare/v1.0.210...v1.0.211)

Updates `serde_derive` from 1.0.210 to 1.0.211
- [Release notes](https://github.com/serde-rs/serde/releases)
- [Commits](https://github.com/serde-rs/serde/compare/v1.0.210...v1.0.211)

Updates `serde_json` from 1.0.128 to 1.0.132
- [Release notes](https://github.com/serde-rs/json/releases)
- [Commits](https://github.com/serde-rs/json/compare/1.0.128...1.0.132)

Updates `wasm-bindgen` from 0.2.93 to 0.2.95
- [Release notes](https://github.com/rustwasm/wasm-bindgen/releases)
- [Changelog](https://github.com/rustwasm/wasm-bindgen/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rustwasm/wasm-bindgen/compare/0.2.93...0.2.95)

Updates `wasm-bindgen-futures` from 0.4.43 to 0.4.45
- [Release notes](https://github.com/rustwasm/wasm-bindgen/releases)
- [Changelog](https://github.com/rustwasm/wasm-bindgen/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rustwasm/wasm-bindgen/commits)

Updates `web-sys` from 0.3.70 to 0.3.72
- [Release notes](https://github.com/rustwasm/wasm-bindgen/releases)
- [Changelog](https://github.com/rustwasm/wasm-bindgen/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rustwasm/wasm-bindgen/commits)

---
updated-dependencies:
- dependency-name: anyhow
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: patch-updates
- dependency-name: clap
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: patch-updates
- dependency-name: clap_complete
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: patch-updates
- dependency-name: pin-project
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: patch-updates
- dependency-name: serde
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: patch-updates
- dependency-name: serde_derive
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: patch-updates
- dependency-name: serde_json
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: patch-updates
- dependency-name: wasm-bindgen
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: patch-updates
- dependency-name: wasm-bindgen-futures
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: patch-updates
- dependency-name: web-sys
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: patch-updates
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-22 14:56:39 +00:00
Fran Arbanas 0ec2514edf fix: working directory for nym-credential-proxy (#4997) 2024-10-22 15:58:45 +02:00
Jędrzej Stuczyński d6435a8270 Merge pull request #5012 from nymtech/merge/release/2024.12-aero
Merge/release/2024.12 aero
2024-10-22 14:32:56 +01:00
Jędrzej Stuczyński 9efc50e067 Merge branch 'release/2024.12-aero' into merge/release/2024.12-aero 2024-10-22 13:03:07 +01:00
Tommy Verrall 1532547e2b Merge pull request #4948 from nymtech/nym-api-container
nym-api container
2024-10-22 13:19:17 +02:00
Tommy Verrall 0cb11632e6 Merge pull request #4957 from nymtech/feat/nym-api-env-vars
Add env feature to clap and make clap parameters available as env variables
2024-10-22 13:18:52 +02:00
Tommy Verrall f71ea52d5d Merge pull request #4972 from nymtech/feat/nym-node-dockerfile
feat: add Dockerfile for nym node
2024-10-22 13:17:54 +02:00
Jędrzej Stuczyński 338835698c feature: adjusted ticket sizes to the agreed amounts (#5009)
* feature: adjusted ticket sizes to the agreed amounts

* adjusted MiB values to MB
2024-10-22 11:47:31 +01:00
Bogdan-Ștefan Neacşu e65e261cd3 Push private ip before inserting (#5008) 2024-10-22 12:31:25 +03:00
Bogdan-Ștefan Neacşu 2d78f6939e Remove as stale instead of erroring (#5007) 2024-10-22 11:51:04 +03:00
Bogdan-Ștefan Neacşu 9a45de5874 Remove stale free riders after 24 hours (#5002) 2024-10-21 13:15:08 +03:00
Bogdan-Ștefan Neacşu 2f894b9be3 Remove race on initial req processing (#5001) 2024-10-21 13:15:01 +03:00
Jędrzej Stuczyński d36ea20366 bugfix: dont store sent/received fragments unless explicitly enabled (#4991) 2024-10-21 09:27:48 +01:00
Fran Arbanas 7b1200f338 fix: add ca-certificates to ubuntu dockerfiles (#4998) 2024-10-18 18:39:13 +02:00
Bogdan-Ștefan Neacşu d291582128 Separate storage from wg_api (#4988) 2024-10-18 19:34:09 +03:00
Fran Arbanas 9800411990 fix: revert the removal of checking if tag exists (#4996) 2024-10-18 17:55:58 +02:00
Jędrzej Stuczyński 0e47b88dd8 chore: update itertools in compact ecash (#4994) 2024-10-18 16:34:38 +01:00
Jędrzej Stuczyński 795350ae8a feature: make accepting t&c a hard requirement for rewarded set selection (#4993) 2024-10-18 16:34:23 +01:00
Fran Arbanas ac9a9827b9 feat: credential proxy GHA for pushing to harbor (#4995) 2024-10-18 17:31:58 +02:00
Jon Häggblad 15fd6a2212 Fix rustfmt in nym-credential-proxy (#4992) 2024-10-18 16:20:59 +02:00
Lawrence Stalder 85a93f59e8 Added empty workflows for branch work 2024-10-18 14:37:27 +02:00
Mark Sinclair 0cb80d06a7 nym-credential-proxy: fix up OpenAPI spect name 2024-10-18 13:28:13 +01:00
Mark Sinclair 6d3ce3a1c9 nym-credential-proxy: improve naming of env vars 2024-10-18 12:29:22 +01:00
Dinko Zdravac 4e65617f08 Bump sqlx to 0.7.4 (#4959)
* Upgrade to v0.7

More goodies

Revert cargo.toml

Fix cargo toml

* Generate offline sqlx schemas

Fix data-observatory

Fix credential-storage

Fix gateway-storage

Fix client-core/-gateways-storage

Generate offline schemas for nym-api as well

* Update nym-api after rebase

---------

Co-authored-by: Andrej Mihajlov <andrej@nymtech.net>
2024-10-18 12:51:41 +02:00
Jędrzej Stuczyński e6d2cbbed7 Merge pull request #4982 from nymtech/cure53_SI86_SI87
Fix critical issues SI86 and SI87 from Cure53
2024-10-18 10:53:11 +01:00
Bogdan-Ștefan Neacşu 18c6fd3e3e Gateway peer fixes (#4985)
* Create bandwidth entry

* Remove mismatch possibilities
2024-10-18 12:43:36 +03:00
import this 50c6ac0870 [DOCs;/operators]: Release notes for v2024.12 aero (#4984)
* initialise aero changelog

* add DP update

* add F&F info to release notes

* bump version in header

* address review comments
2024-10-18 09:04:54 +00:00
aniampio 25326e5f9b Fixes following cargo fmt 2024-10-18 09:32:27 +01:00
aniampio f37eb9db23 Fixes following cargo clippy 2024-10-18 09:32:27 +01:00
aniampio c5b74353f3 Add infinity checks to fix SI-87 2024-10-18 09:32:22 +01:00
aniampio 871b54e314 Fix computation of h for the SI-86 2024-10-18 09:11:45 +01:00
Jędrzej Stuczyński 5af6ee763c Merge pull request #4758 from nymtech/ania/cure53_SI84_SI85
Fix critical issues SI84 and SI85 from Cure53
2024-10-18 09:09:07 +01:00
Jędrzej Stuczyński dabbe8ba7f removed additional sources of copying secrets and introduced extra error variants 2024-10-17 15:23:40 +01:00
Bogdan-Ștefan Neacşu 31f1037d44 Add topup req constructor (#4983) 2024-10-17 16:03:48 +02:00
Bogdan-Ștefan Neacşu e675e3937a Top up bandwidth (#4975)
* Top up wg bandwidth

* Introduce v3 with top up

* Verify and increase cred bw

* Add log

* Fix clippy
2024-10-17 16:34:52 +03:00
Simon Wicky 355991adc9 [Product Data] Add session type based on ecash ticket received (#4974)
* add session type based on ecash ticket collection

* avoid setting session type if already set

* change duration type to duration

* add a cap for finished sessions
2024-10-17 14:11:05 +02:00
Jon Häggblad 7d55d03925 Merge pull request #4981 from nymtech/jon/rename-credential-proxy
Rename nym-vpn-api to nym-credential-proxy
2024-10-17 11:17:57 +02:00
Gala f455b7c720 Migrate Legacy Node (Frontend) (#4826)
* refactor bonding requests

* use migrate node modal

* disable node settings for legacy nodes

* refine bonded node types

* start migration and bonding work

* update types and requests

* clean up bonding context

* move old forms to legacy directory

* create nymnode bonding flow

---------

Co-authored-by: fmtabbara <fmtabbara@hotmail.co.uk>
2024-10-17 10:08:05 +01:00
Jędrzej Stuczyński 20bc305fb9 Merge pull request #4976 from nymtech/feature/active-set-selection-criteria
feature: require reporting using nym-node binary for rewarded set selection
2024-10-17 09:10:37 +01:00
Jędrzej Stuczyński 72c54e0057 Merge pull request #4980 from nymtech/feature/nym-api-always-expose-global-ecash-data
enable global ecash routes even if api is not a signer
2024-10-17 09:10:20 +01:00
benedettadavico d75c7eaaaf update changelog and bump binaries 2024-10-17 08:51:39 +02:00
Jon Häggblad 97fbd7db17 Update gh workflows 2024-10-16 22:42:49 +02:00
Jon Häggblad 9a94e40b36 Update paths in various build and deployment files 2024-10-16 22:35:59 +02:00
Jon Häggblad 06b5347200 Update paths 2024-10-16 22:30:23 +02:00
Jon Häggblad 561203572d Update Cargo.toml 2024-10-16 22:27:56 +02:00
Jon Häggblad 8f45649daa Rename crate directories 2024-10-16 22:26:57 +02:00
Jon Häggblad fa879baeab Rename directory to nym-credential-proxy 2024-10-16 22:23:53 +02:00
Jon Häggblad b6ab25a7aa Update crate references 2024-10-16 22:22:56 +02:00
Jon Häggblad 0b6f652709 Rename crate to nym-credential-proxy 2024-10-16 22:19:34 +02:00
Jędrzej Stuczyński ed2fbc588f allow to overwrite contract state with explicit config flag 2024-10-16 17:34:34 +01:00
Jędrzej Stuczyński 9f80d95f75 re-disabled bloomfilters 2024-10-16 17:17:48 +01:00
Jędrzej Stuczyński 9bcf48f7dc expose all ecash routes but return error if nym-api is not a signer 2024-10-16 17:09:17 +01:00
Jędrzej Stuczyński 6446e43322 Merge pull request #4977 from nymtech/bugfix/vested-delegation-migration
Re-enable vested delegation migration
2024-10-16 16:51:28 +01:00
Jędrzej Stuczyński 86eb06048a ci: update 'publish-nym-contracts' runner 2024-10-16 16:31:16 +01:00
Jędrzej Stuczyński 02dd16bcc6 added unit tests for the migration and fixed rounding errors 2024-10-16 16:31:16 +01:00
Jędrzej Stuczyński 14fd7c77d0 added unit tests for vested migrations and fixed additional issues 2024-10-16 16:31:16 +01:00
Jędrzej Stuczyński e08e9fcb50 Merge pull request #4978 from nymtech/chore/beta-clippy
resolve beta clippy issues in contracts
2024-10-16 16:30:58 +01:00
Jędrzej Stuczyński 7964e6204b elided extra lifetimes 2024-10-16 16:26:50 +01:00
Jędrzej Stuczyński 56fb46cd69 removed old coconut-bandwidth contract from the workspace 2024-10-16 16:24:58 +01:00
Jędrzej Stuczyński 973d51eeec resolved beta clippy issues in DKG contract 2024-10-16 16:16:22 +01:00
Jędrzej Stuczyński 24773f68a4 Merge pull request #4966 from nymtech/feature/contract-state-tools-mixnet-vesting
feature: importer-cli to correctly handle mixnet/vesting import
2024-10-16 15:09:57 +01:00
Jędrzej Stuczyński 083ee8386e Merge pull request #4968 from nymtech/chore/remove-dead-code
chore: remove unused rocket code
2024-10-16 15:09:48 +01:00
Jędrzej Stuczyński 3158a67445 Merge pull request #4973 from nymtech/bugfix/additional-directory-fixes
Bugfix/additional directory fixes
2024-10-16 15:09:38 +01:00
Jędrzej Stuczyński a26ba3d9f1 feature: require reporting using nym-node binary for rewarded set selection 2024-10-16 15:02:16 +01:00
Fran Arbanas b88bc188c6 Merge pull request #4970 from nymtech/feat/nym-data-observatory-docker
feat: add clap and env vars through clap, add Dockerfile
2024-10-16 14:39:16 +02:00
Fran Arbanas bccbc99448 Merge pull request #4971 from nymtech/feat/nym-credentials-proxy-dockerfile
feat: added dockerfile for nym-credentials-proxy
2024-10-16 13:36:11 +02:00
Fran Arbanas 5d445d6b47 fix: comments on PR, removing stuff that's not needed 2024-10-16 13:10:01 +02:00
Simon Wicky 435f236812 [Product Data] First step in gateway usage data collection (#4963)
* add stats model

* add stats collection

* add stats route

* propagate stuff and run stuff

* cargo stuff

* sqlx unused what?

* add sessions started stat

* session durations in miliseconds

* apply Jon's comments

* [Product Data] Second step in gateway usage data collection  (#4964)

* turn stats collection into event based

* move events into a common crate for future use elsewhere

* apply Jon's comments
2024-10-15 09:18:02 +02:00
Jędrzej Stuczyński ca4523025e missing update to the integration test 2024-10-14 19:16:13 +01:00
Jędrzej Stuczyński 01db51e492 updated mixnet schema 2024-10-14 18:52:19 +01:00
Jędrzej Stuczyński 3320da2060 fixed testnet-manager tool to work with the updated binaries 2024-10-14 18:52:04 +01:00
Jędrzej Stuczyński d04331a5df updated clients to use 'new' endpoints 2024-10-14 18:12:56 +01:00
Jędrzej Stuczyński 0713869666 fixed swagger route arguments for skimmed endpoints 2024-10-14 18:12:27 +01:00
Jędrzej Stuczyński 27775a29c4 added additional logs when refreshing self-described cache 2024-10-14 18:12:09 +01:00
Jędrzej Stuczyński 652f2db5c0 exposed announce ports to nym-node CLI 2024-10-14 17:55:00 +01:00
Fran Arbanas a1c33bbae3 fix: CMD -> ENTRYPOINT 2024-10-14 18:05:03 +02:00
Fran Arbanas 62c94d58e8 Fix: CMD -> ENTRYPOINT 2024-10-14 18:04:05 +02:00
Fran Arbanas 99cf7d1eec feat: add Dockerfile for nym node 2024-10-14 18:03:22 +02:00
Fran Arbanas 6717951037 feat: added dockerfile for nym-credentials-proxy 2024-10-14 17:31:03 +02:00
Fran Arbanas 1219dd9719 changed debian for ubuntu docker image 2024-10-14 16:59:09 +02:00
Jędrzej Stuczyński e87b00bce5 add the nym-nodes count to refresher log 2024-10-14 15:14:12 +01:00
Jędrzej Stuczyński 11f6db5304 fixed compatibility with 'skimmed' endpoints by making "no_legacy" argument optional 2024-10-14 14:51:02 +01:00
Jędrzej Stuczyński c14481bb77 allow nym-api to control bind address with CLI 2024-10-14 14:50:36 +01:00
Jędrzej Stuczyński 16edca21b0 allow to optionally skip state migration 2024-10-14 11:41:36 +01:00
Fran Arbanas b68fca0efa feat: add clap and env vars through clap, add Dockerfile 2024-10-14 12:32:29 +02:00
Jon Häggblad 1fc7e07028 Merge pull request #4967 from nymtech/jon/import-vpn-api
Import nym-vpn-api crates
2024-10-14 12:23:14 +02:00
Bogdan-Ștefan Neacşu 8758bea17c Use ticket type when retrieving from storage (#4947) 2024-10-14 12:39:12 +03:00
Jędrzej Stuczyński 845b5df14c chore: remove unused rocket code 2024-10-14 10:27:59 +01:00
Jędrzej Stuczyński f786dbeaa7 Merge pull request #4960 from nymtech/chore/remove-bloomfilters-for-double-spending
nym-node: don't use bloomfilters for double spending checks
2024-10-14 09:44:33 +01:00
Jon Häggblad 9d8a686760 Add common to trigger paths for CI 2024-10-12 12:10:16 +02:00
Jon Häggblad 435d9d3115 Update to don't use removed default ticket type 2024-10-12 12:10:16 +02:00
Jon Häggblad 275cd9ff92 rustfmt 2024-10-12 12:10:16 +02:00
Jon Häggblad 8435cf91e5 Add CI workflows 2024-10-12 12:10:16 +02:00
Jon Häggblad 3460ce70a3 Remove workspace deps for nym 2024-10-12 11:54:09 +02:00
Jon Häggblad 0ddaf3b50b Import Cargo workspace files 2024-10-12 11:49:04 +02:00
Jon Häggblad a103acaf70 Import vpn-api from a414f4a2ee0 2024-10-12 11:29:41 +02:00
Jędrzej Stuczyński 08aa0af562 Merge pull request #4965 from nymtech/bugfix/invalid-gateways-response
bugfix: fix expected return type on /v1/gateways endpoint
2024-10-11 17:50:16 +01:00
Jędrzej Stuczyński e333aca8a1 introduced specialised subcommand to importer-cli to import mixnet/vesting contracts 2024-10-11 17:34:37 +01:00
Jędrzej Stuczyński 67462a9f47 split the existing tools into separate modules 2024-10-11 16:27:49 +01:00
Jędrzej Stuczyński 493390d92b bugfix: fix expected return type on /v1/gateways endpoint 2024-10-11 16:05:53 +01:00
Jędrzej Stuczyński eae76cce10 disabled bloomfilter exporting in nym-api 2024-10-11 08:54:50 +01:00
Jędrzej Stuczyński 8113948f48 Merge pull request #4903 from nymtech/feature/directory-v3-purge-base
Directory Sevices v2.1
2024-10-11 08:22:07 +01:00
Jędrzej Stuczyński 9341db5d08 removed gateway/nym-node using global double spending bloomfilter 2024-10-10 17:09:51 +01:00
Jędrzej Stuczyński c3e3ef1737 removed axum feature from ci-build.yml for clippy 2024-10-10 15:42:01 +01:00
Jędrzej Stuczyński 45f4eeeff2 fixed linter issues and outdated tests 2024-10-10 15:38:00 +01:00
Jędrzej Stuczyński f76d677f64 additional rewarding-related unit tests 2024-10-10 13:27:35 +01:00
Jędrzej Stuczyński 050a58affa fixed cli command for updating node cost params 2024-10-10 13:27:35 +01:00
Jędrzej Stuczyński 065b3891f2 removed unused error variant 2024-10-10 13:27:35 +01:00
Jędrzej Stuczyński 59da117e8f fixed wallet's lock file 2024-10-10 13:27:35 +01:00
Jędrzej Stuczyński 3d13274219 changed CI to no longer build with 'axum' feature since it was removed 2024-10-10 13:27:35 +01:00
Jędrzej Stuczyński 561566f3c4 fixed wasm sdk build 2024-10-10 13:27:34 +01:00
Jędrzej Stuczyński 6879c211ee cleaning up mixnet contract in preperation for merging 2024-10-10 13:27:34 +01:00
Jędrzej Stuczyński c7f2ef7074 regenerated typescript types 2024-10-10 13:27:34 +01:00
Jędrzej Stuczyński fb43e917cb updated ts_rs and derived it for more types 2024-10-10 13:27:34 +01:00
Jędrzej Stuczyński e79450a082 cargo fmt 2024-10-10 13:27:34 +01:00
Jędrzej Stuczyński 2e365026b7 implemented the noise route 2024-10-10 13:27:33 +01:00
Jędrzej Stuczyński cd706aa67e extracted common functionalities and implemented remaining skimmed routes 2024-10-10 13:27:33 +01:00
Jędrzej Stuczyński 304b192f52 basic handlers with a lot of repeated code 2024-10-10 13:27:33 +01:00
Jędrzej Stuczyński 8c979e3bac scaffolding additional skimmed endpoints + strenghten key types 2024-10-10 13:27:32 +01:00
Jędrzej Stuczyński 279b00d833 exposing node role in nym node annotation 2024-10-10 13:27:07 +01:00
Jędrzej Stuczyński 49fd0dc9e1 wip: additional nym-nodes routes 2024-10-10 13:27:07 +01:00
Jędrzej Stuczyński 9a9d91cb4f additional unit tests for compatibility-based txs + bug fixes 2024-10-10 13:27:07 +01:00
Jędrzej Stuczyński 5c08a89be3 exposed nym-node related operations in the wallet backend 2024-10-10 13:27:06 +01:00
Jędrzej Stuczyński fd88776998 fix legacy test 2024-10-10 13:27:06 +01:00
Jędrzej Stuczyński 1339e20420 typo 2024-10-10 13:27:06 +01:00
Jędrzej Stuczyński 51b511b27e Rebased the branch one more time
WIP; rebasing

Another branch squash

Squashing the v3 branch

changing min pledge amounts

logic for adding new nymnode into the contract

converting mixnode/gateway bonding into nym-node bonding

logic for migrating gateways into nymnodes

ibid for mixnodes

further nym-node work + fixed most existing unit tests

forbid nymnode migration with pending cost params changes

preassign nodeid for gateways

changing role assignment and epoch progression

changing role assignment and epoch progression

optional custom http port

logic for unbonding a nym-node

updating Delegation struct

logic for increasing pledge of either mixnode or nymnode

logic for decreasing pledge of either mixnode or a nym node

logic for changing cost params of either mixnode or a nym node

wip

initialise nymnodes storage

fixing transaction tests

fixed naive family tests

reward-compatibility related works

resolving delegation events

introduced rewarded set metadata

another iteration of restoring old tests

updated rewarding part of nym-api

parking the branch

unparking the branch

wip

purged families

added 'ExitGateway' role

passing explicit work factor for rewarding function

remove legacy layers storage

wip: node description queries

added announced ports to self-described api

step1 in gruelling journey of adding node_id to gateways

ensure epoch work never goes above 1.0

changed active set to contain role distribution

[theoretically] sending rewarding messages for the new rewarded set

[theoretically] assigning new rewarded set

reimplementing more nym-api features

remove legacy types

re-implement legacy network monitor

restoring further routes + minor refactor of NodeStatusCache

skimmed routes now return legacy nodes alongside nym-nodes

seemingly restored all functionalities in nym-api

removing more legacy things from the contract

initial contract cleanup

added nym-api endpoints to return generic annotations regardless of type

updated simulator to use new rewarding parameters

more contract cleanup

made existing mixnet contract tests compile

extra validation of nym-node bonding parameters

fixed additional compilation issues

fixed nym-api v3 database migration failure

added additional nym-node contract queries

updated the schema

made additional delegation/rewards queries compatible with both legacy mixnodes and nym-nodes

fixing existing unit tests in mixnet contract

wip

resolved first batch of 500 compiler errors

re-deprecating routes

making wallet's rust backend compile

fixed non-determinism in contract + nym-api build

fixes to the build

populating cotracts-cache with nym-nodes data

more missing nymnodes queries

temp mixnet contract methods + restored result submission in nym-api

allow deprecated routes

submitting correct results for mixnode results

removed deprecated re-export of AxumAppState and removed smurf naming

moved axum modules into support::http

cleaning up nym-api warnings

determine entry gateways before exits

exposed transaction to update nym-node config

missing memo for updating node config

 new routes

added routes to swagger and fixed relative paths

fixed some macro derivations

added nym-node commands to nym-cli
2024-10-10 13:27:05 +01:00
Jędrzej Stuczyński 75a5192c6d Merge pull request #4958 from nymtech/bugfix/websocket-message-handling
bugfix: replace unreachable macro with an error return
2024-10-09 17:24:17 +01:00
Jędrzej Stuczyński 25ad0920cf bugfix: replace unreachable macro with an error return 2024-10-09 17:15:41 +01:00
Fran Arbanas a1e75e1dff change env var naming to be consistent with nym-node 2024-10-09 13:24:28 +02:00
Fran Arbanas e59a9a59b6 feat: add env feature to clap and change variables to be available as env variables as well 2024-10-09 13:15:38 +02:00
Jędrzej Stuczyński 27ac34522c Merge pull request #4954 from nymtech/feature/contract-state-tools
Feature/contract state tools
2024-10-08 15:32:28 +01:00
durch 4c51a8975c Initial stab 2024-10-01 16:39:47 +02:00
Bogdan-Ștefan Neacşu a4c6f51fe0 Don't kill gateway on handle drop (#4934) 2024-09-27 11:02:39 +02:00
aniampio 4957d9dbf2 Fix clippy 2024-08-12 22:09:18 +01:00
aniampio 96ead0b19e Fix function input 2024-08-12 21:51:16 +01:00
aniampio 47a3c53cfb Run fmt in ecash files 2024-08-12 21:43:32 +01:00
aniampio 29bfd544f1 Fix checks for non identity h in offline ecash 2024-08-09 00:29:29 +01:00
aniampio eff725e8ec Run cargo fmt 2024-08-09 00:11:27 +01:00
aniampio 5743624948 Add check for identity point in all required Coconut functions 2024-08-09 00:11:03 +01:00
aniampio 07de1868ff Coconut: add check if h is not identity in the prepare_blind_sign function 2024-08-08 17:54:18 +01:00
aniampio 6ea746e7f3 Add test for check if h is identity in the verify_partial_blind_signature 2024-08-08 16:47:17 +01:00
aniampio 7722a7080c RequestVerify: check if h is non-identity 2024-08-08 12:36:48 +01:00
aniampio bbe3917c8f WithdrawalRequest: make sure h is non-identity 2024-08-08 12:22:38 +01:00
966 changed files with 56576 additions and 19807 deletions
@@ -0,0 +1,41 @@
name: ci-build-vpn-api-wasm
on:
pull_request:
paths:
- 'common/**'
- 'nym-credential-proxy/**'
- '.github/workflows/ci-build-vpn-api-wasm.yml'
jobs:
wasm:
runs-on: arc-ubuntu-22.04
env:
CARGO_TERM_COLOR: always
steps:
- name: Check out repository code
uses: actions/checkout@v4
- name: Install Rust toolchain
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
target: wasm32-unknown-unknown
override: true
components: rustfmt, clippy
- name: Install wasm-pack
run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
- name: Install wasm-opt
uses: ./.github/actions/install-wasm-opt
with:
version: '116'
- name: Install wasm-bindgen-cli
run: cargo install wasm-bindgen-cli
- name: "Build"
run: make
working-directory: nym-credential-proxy/vpn-api-lib-wasm
+7 -15
View File
@@ -30,7 +30,7 @@ jobs:
strategy:
fail-fast: false
matrix:
os: [arc-ubuntu-20.04, custom-runner-mac-m1]
os: [ arc-ubuntu-20.04, custom-runner-mac-m1 ]
runs-on: ${{ matrix.os }}
env:
CARGO_TERM_COLOR: always
@@ -57,19 +57,17 @@ jobs:
command: fmt
args: --all -- --check
- name: Clippy
uses: actions-rs/cargo@v1
with:
command: clippy
args: --workspace --all-targets -- -D warnings
- name: Build all binaries
uses: actions-rs/cargo@v1
with:
command: build
# while disabled by default, this build ensures nothing is broken within
# `axum` feature
- name: Build with `axum` feature
uses: actions-rs/cargo@v1
with:
command: build
args: --features axum
- name: Build all examples
if: contains(matrix.os, 'ubuntu')
uses: actions-rs/cargo@v1
@@ -90,9 +88,3 @@ jobs:
with:
command: test
args: --workspace -- --ignored
- name: Clippy
uses: actions-rs/cargo@v1
with:
command: clippy
args: --workspace --all-targets --features axum -- -D warnings
@@ -16,7 +16,7 @@ jobs:
strategy:
fail-fast: false
matrix:
platform: arc-ubuntu-20.04
platform: [ arc-ubuntu-20.04 ]
runs-on: ${{ matrix.platform }}
env:
@@ -0,0 +1,45 @@
name: ci-nym-credential-proxy
on:
pull_request:
paths:
- 'common/**'
- 'nym-credential-proxy/**'
- '.github/workspace/ci-nym-credential-proxy.yml'
workflow_dispatch:
jobs:
build:
runs-on: arc-ubuntu-22.04
env:
CARGO_TERM_COLOR: always
MANIFEST_PATH: "--manifest-path nym-credential-proxy/Cargo.toml"
steps:
- name: Check out repository code
uses: actions/checkout@v4
- name: Install rust toolchain
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
override: true
components: rustfmt, clippy
- name: Check formatting
uses: actions-rs/cargo@v1
with:
command: fmt
args: ${{ env.MANIFEST_PATH }} --all -- --check
- name: Build
uses: actions-rs/cargo@v1
with:
command: build
args: ${{ env.MANIFEST_PATH }} --workspace --all-targets
- name: Clippy
uses: actions-rs/cargo@v1
with:
command: clippy
args: ${{ env.MANIFEST_PATH }} --workspace --all-targets -- -D warnings
+11
View File
@@ -0,0 +1,11 @@
name: Hello world
on:
workflow_dispatch:
jobs:
my-job:
runs-on: arc-ubuntu-22.04
steps:
- name: my-step
run: echo "Hello World!"
@@ -0,0 +1,55 @@
name: Build and upload Credential Proxy container to harbor.nymte.ch
on:
workflow_dispatch:
env:
WORKING_DIRECTORY: "nym-credential-proxy"
CONTAINER_NAME: "credential-proxy"
jobs:
build-container:
runs-on: arc-ubuntu-22.04-dind
steps:
- name: Login to Harbor
uses: docker/login-action@v3
with:
registry: harbor.nymte.ch
username: ${{ secrets.HARBOR_ROBOT_USERNAME }}
password: ${{ secrets.HARBOR_ROBOT_SECRET }}
- name: Checkout repo
uses: actions/checkout@v4
- name: Configure git identity
run: |
git config --global user.email "lawrence@nymtech.net"
git config --global user.name "Lawrence Stalder"
- name: Get version from cargo.toml
uses: mikefarah/yq@v4.44.3
id: get_version
with:
cmd: yq -oy '.package.version' ${{ env.WORKING_DIRECTORY }}/nym-credential-proxy/Cargo.toml
- name: Check if tag exists
run: |
if git rev-parse ${{ steps.get_version.outputs.value }} >/dev/null 2>&1; then
echo "Tag ${{ steps.get_version.outputs.value }} already exists"
fi
- name: Remove existing tag if exists
run: |
if git rev-parse ${{ env.WORKING_DIRECTORY }}-${{ steps.get_version.outputs.result }} >/dev/null 2>&1; then
git push --delete origin ${{ env.WORKING_DIRECTORY }}-${{ steps.get_version.outputs.result }}
git tag -d ${{ env.WORKING_DIRECTORY }}-${{ steps.get_version.outputs.result }}
fi
- name: Create tag
run: |
git tag -a ${{ env.WORKING_DIRECTORY }}-${{ steps.get_version.outputs.result }} -m "Version ${{ steps.get_version.outputs.result }}"
git push origin ${{ env.WORKING_DIRECTORY }}-${{ steps.get_version.outputs.result }}
- name: BuildAndPushImageOnHarbor
run: |
docker build -f ${{ env.WORKING_DIRECTORY }}/nym-credential-proxy/Dockerfile . -t harbor.nymte.ch/nym/${{ env.CONTAINER_NAME }}:${{ steps.get_version.outputs.result }} -t harbor.nymte.ch/nym/${{ env.CONTAINER_NAME }}:latest
docker push harbor.nymte.ch/nym/${{ env.CONTAINER_NAME }} --all-tags
@@ -0,0 +1,55 @@
name: Build and upload Data observatory container to harbor.nymte.ch
on:
workflow_dispatch:
env:
WORKING_DIRECTORY: "nym-data-observatory"
CONTAINER_NAME: "data-observatory"
jobs:
build-container:
runs-on: arc-ubuntu-22.04-dind
steps:
- name: Login to Harbor
uses: docker/login-action@v3
with:
registry: harbor.nymte.ch
username: ${{ secrets.HARBOR_ROBOT_USERNAME }}
password: ${{ secrets.HARBOR_ROBOT_SECRET }}
- name: Checkout repo
uses: actions/checkout@v4
- name: Configure git identity
run: |
git config --global user.email "lawrence@nymtech.net"
git config --global user.name "Lawrence Stalder"
- name: Get version from cargo.toml
uses: mikefarah/yq@v4.44.3
id: get_version
with:
cmd: yq -oy '.package.version' ${{ env.WORKING_DIRECTORY }}/Cargo.toml
- name: Check if tag exists
run: |
if git rev-parse ${{ steps.get_version.outputs.value }} >/dev/null 2>&1; then
echo "Tag ${{ steps.get_version.outputs.value }} already exists"
fi
- name: Remove existing tag if exists
run: |
if git rev-parse ${{ env.WORKING_DIRECTORY }}-${{ steps.get_version.outputs.result }} >/dev/null 2>&1; then
git push --delete origin ${{ env.WORKING_DIRECTORY }}-${{ steps.get_version.outputs.result }}
git tag -d ${{ env.WORKING_DIRECTORY }}-${{ steps.get_version.outputs.result }}
fi
- name: Create tag
run: |
git tag -a ${{ env.WORKING_DIRECTORY }}-${{ steps.get_version.outputs.result }} -m "Version ${{ steps.get_version.outputs.result }}"
git push origin ${{ env.WORKING_DIRECTORY }}-${{ steps.get_version.outputs.result }}
- name: BuildAndPushImageOnHarbor
run: |
docker build -f ${{ env.WORKING_DIRECTORY }}/Dockerfile . -t harbor.nymte.ch/nym/${{ env.CONTAINER_NAME }}:${{ steps.get_version.outputs.result }} -t harbor.nymte.ch/nym/${{ env.CONTAINER_NAME }}:latest
docker push harbor.nymte.ch/nym/${{ env.CONTAINER_NAME }} --all-tags
@@ -0,0 +1,56 @@
name: Build and upload Node Status agent container to harbor.nymte.ch
on:
workflow_dispatch:
env:
WORKING_DIRECTORY: "nym-node-status-agent"
CONTAINER_NAME: "node-status-agent"
jobs:
build-container:
runs-on: arc-ubuntu-22.04-dind
steps:
- name: Login to Harbor
uses: docker/login-action@v3
with:
registry: harbor.nymte.ch
username: ${{ secrets.HARBOR_ROBOT_USERNAME }}
password: ${{ secrets.HARBOR_ROBOT_SECRET }}
- name: Checkout repo
uses: actions/checkout@v4
- name: Configure git identity
run: |
git config --global user.email "lawrence@nymtech.net"
git config --global user.name "Lawrence Stalder"
- name: Get version from cargo.toml
uses: mikefarah/yq@v4.44.3
id: get_version
with:
cmd: yq -oy '.package.version' ${{ env.WORKING_DIRECTORY }}/Cargo.toml
- name: Check if tag exists
run: |
if git rev-parse ${{ steps.get_version.outputs.value }} >/dev/null 2>&1; then
echo "Tag ${{ steps.get_version.outputs.value }} already exists"
fi
- name: Remove existing tag if exists
run: |
if git rev-parse ${{ env.WORKING_DIRECTORY }}-${{ steps.get_version.outputs.result }} >/dev/null 2>&1; then
git push --delete origin ${{ env.WORKING_DIRECTORY }}-${{ steps.get_version.outputs.result }}
git tag -d ${{ env.WORKING_DIRECTORY }}-${{ steps.get_version.outputs.result }}
fi
- name: Create tag
run: |
git tag -a ${{ env.WORKING_DIRECTORY }}-${{ steps.get_version.outputs.result }} -m "Version ${{ steps.get_version.outputs.result }}"
git push origin ${{ env.WORKING_DIRECTORY }}-${{ steps.get_version.outputs.result }}
- name: BuildAndPushImageOnHarbor
run: |
docker build -f ${{ env.WORKING_DIRECTORY }}/Dockerfile . -t harbor.nymte.ch/nym/${{ env.CONTAINER_NAME }}:${{ steps.get_version.outputs.result }} -t harbor.nymte.ch/nym/${{ env.CONTAINER_NAME }}:latest
docker push harbor.nymte.ch/nym/${{ env.CONTAINER_NAME }} --all-tags
@@ -0,0 +1,55 @@
name: Build and upload Node Status API container to harbor.nymte.ch
on:
workflow_dispatch:
env:
WORKING_DIRECTORY: "nym-node-status-api"
CONTAINER_NAME: "node-status-api"
jobs:
build-container:
runs-on: arc-ubuntu-22.04-dind
steps:
- name: Login to Harbor
uses: docker/login-action@v3
with:
registry: harbor.nymte.ch
username: ${{ secrets.HARBOR_ROBOT_USERNAME }}
password: ${{ secrets.HARBOR_ROBOT_SECRET }}
- name: Checkout repo
uses: actions/checkout@v4
- name: Configure git identity
run: |
git config --global user.email "lawrence@nymtech.net"
git config --global user.name "Lawrence Stalder"
- name: Get version from cargo.toml
uses: mikefarah/yq@v4.44.3
id: get_version
with:
cmd: yq -oy '.package.version' ${{ env.WORKING_DIRECTORY }}/Cargo.toml
- name: Check if tag exists
run: |
if git rev-parse ${{ env.WORKING_DIRECTORY }}-${{ steps.get_version.outputs.result }} >/dev/null 2>&1; then
echo "Tag ${{ steps.get_version.outputs.result }} already exists"
fi
- name: Remove existing tag if exists
run: |
if git rev-parse ${{ env.WORKING_DIRECTORY }}-${{ steps.get_version.outputs.result }} >/dev/null 2>&1; then
git push --delete origin ${{ env.WORKING_DIRECTORY }}-${{ steps.get_version.outputs.result }}
git tag -d ${{ env.WORKING_DIRECTORY }}-${{ steps.get_version.outputs.result }}
fi
- name: Create tag
run: |
git tag -a ${{ env.WORKING_DIRECTORY }}-${{ steps.get_version.outputs.result }} -m "Version ${{ steps.get_version.outputs.result }}"
git push origin ${{ env.WORKING_DIRECTORY }}-${{ steps.get_version.outputs.result }}
- name: BuildAndPushImageOnHarbor
run: |
docker build -f ${{ env.WORKING_DIRECTORY }}/Dockerfile . -t harbor.nymte.ch/nym/${{ env.CONTAINER_NAME }}:${{ steps.get_version.outputs.result }} -t harbor.nymte.ch/nym/${{ env.CONTAINER_NAME }}:latest
docker push harbor.nymte.ch/nym/${{ env.CONTAINER_NAME }} --all-tags
+74
View File
@@ -4,6 +4,80 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
## [Unreleased]
## [2024.12-aero] (2024-10-17)
- nym-node: don't use bloomfilters for double spending checks ([#4960])
- bugfix: replace unreachable macro with an error return ([#4958])
- [DOCs:/operators]: Update FAQ sphinx size ([#4946])
- [DOCs/operators]: Release notes v2024.11-wedel ([#4939])
- Fix handle drop ([#4934])
- Assume offline mode ([#4926])
- Make ip-packet-request VERSION pub ([#4925])
- Expose error type ([#4924])
- Fix argument to cargo-deny action ([#4922])
- Fix nymvpn.com url in mainnet defaults ([#4920])
- Check both version and type in message header ([#4918])
- Bump http-api-client default timeout to 30 sec ([#4917])
- Max/proxy ffi ([#4906])
- Data Observatory stub ([#4905])
- Fix missing duplication of modified tables ([#4904])
- Update cargo deny ([#4901])
- docs: add hostname instructions for wss ([#4900])
- build(deps): bump the patch-updates group across 1 directory with 9 updates ([#4898])
- Fix clippy for beta toolchain ([#4897])
- Remove clippy github PR annotations ([#4896])
- Fix apt install in ci-build-upload-binaries.yml ([#4894])
- Update network monitor entrypoint ([#4893])
- Update nym-vpn metapackage and replace nymvpn-x with nym-vpn-app ([#4889])
- Entry wireguard tickets ([#4888])
- Build and Push CI ([#4887])
- Feature/updated gateway registration ([#4885])
- Few fixes to NNM pre deploy ([#4883])
- Fix sql serde with enum ([#4875])
- allow clients to send stateless gateway requests without prior registration ([#4873])
- chore: remove queued migration for adding explicit admin ([#4871])
- Gateway database modifications for different modes ([#4868])
- build(deps): bump strum from 0.25.0 to 0.26.3 ([#4848])
- Use serde from workspace ([#4833])
- build(deps): bump toml from 0.5.11 to 0.8.14 ([#4805])
- Max/rust sdk stream abstraction ([#4743])
[#4960]: https://github.com/nymtech/nym/pull/4960
[#4958]: https://github.com/nymtech/nym/pull/4958
[#4946]: https://github.com/nymtech/nym/pull/4946
[#4939]: https://github.com/nymtech/nym/pull/4939
[#4934]: https://github.com/nymtech/nym/pull/4934
[#4926]: https://github.com/nymtech/nym/pull/4926
[#4925]: https://github.com/nymtech/nym/pull/4925
[#4924]: https://github.com/nymtech/nym/pull/4924
[#4922]: https://github.com/nymtech/nym/pull/4922
[#4920]: https://github.com/nymtech/nym/pull/4920
[#4918]: https://github.com/nymtech/nym/pull/4918
[#4917]: https://github.com/nymtech/nym/pull/4917
[#4906]: https://github.com/nymtech/nym/pull/4906
[#4905]: https://github.com/nymtech/nym/pull/4905
[#4904]: https://github.com/nymtech/nym/pull/4904
[#4901]: https://github.com/nymtech/nym/pull/4901
[#4900]: https://github.com/nymtech/nym/pull/4900
[#4898]: https://github.com/nymtech/nym/pull/4898
[#4897]: https://github.com/nymtech/nym/pull/4897
[#4896]: https://github.com/nymtech/nym/pull/4896
[#4894]: https://github.com/nymtech/nym/pull/4894
[#4893]: https://github.com/nymtech/nym/pull/4893
[#4889]: https://github.com/nymtech/nym/pull/4889
[#4888]: https://github.com/nymtech/nym/pull/4888
[#4887]: https://github.com/nymtech/nym/pull/4887
[#4885]: https://github.com/nymtech/nym/pull/4885
[#4883]: https://github.com/nymtech/nym/pull/4883
[#4875]: https://github.com/nymtech/nym/pull/4875
[#4873]: https://github.com/nymtech/nym/pull/4873
[#4871]: https://github.com/nymtech/nym/pull/4871
[#4868]: https://github.com/nymtech/nym/pull/4868
[#4848]: https://github.com/nymtech/nym/pull/4848
[#4833]: https://github.com/nymtech/nym/pull/4833
[#4805]: https://github.com/nymtech/nym/pull/4805
[#4743]: https://github.com/nymtech/nym/pull/4743
## [2024.11-wedel] (2024-09-23)
- Backport #4894 to fix ci ([#4899])
Generated
+1460 -647
View File
File diff suppressed because it is too large Load Diff
+32 -10
View File
@@ -54,12 +54,14 @@ members = [
"common/exit-policy",
"common/gateway-requests",
"common/gateway-storage",
"common/gateway-stats-storage",
"common/http-api-client",
"common/http-api-common",
"common/inclusion-probability",
"common/ip-packet-requests",
"common/ledger",
"common/mixnode-common",
"common/models",
"common/network-defaults",
"common/node-tester-utils",
"common/nonexhaustive-delayqueue",
@@ -85,6 +87,7 @@ members = [
"common/socks5-client-core",
"common/socks5/proxy-helpers",
"common/socks5/requests",
"common/statistics",
"common/store-cipher",
"common/task",
"common/topology",
@@ -118,6 +121,8 @@ members = [
"nym-node",
"nym-node/nym-node-http-api",
"nym-node/nym-node-requests",
"nym-node-status-api",
"nym-node-status-agent",
"nym-outfox",
"nym-validator-rewarder",
"tools/echo-server",
@@ -145,13 +150,16 @@ members = [
default-members = [
"clients/native",
"clients/socks5",
"common/models",
"explorer-api",
"gateway",
"mixnode",
"nym-api",
"nym-data-observatory",
"nym-node",
"nym-node-status-api",
"nym-validator-rewarder",
"nym-node-status-api",
"service-providers/authenticator",
"service-providers/ip-packet-router",
"service-providers/network-requester",
@@ -182,7 +190,7 @@ aes = "0.8.1"
aes-gcm = "0.10.1"
aes-gcm-siv = "0.11.1"
aead = "0.5.2"
anyhow = "1.0.89"
anyhow = "1.0.90"
argon2 = "0.5.0"
async-trait = "0.1.83"
axum = "0.7.5"
@@ -207,7 +215,7 @@ chacha20 = "0.9.0"
chacha20poly1305 = "0.10.1"
chrono = "0.4.31"
cipher = "0.4.3"
clap = "4.5.18"
clap = "4.5.20"
clap_complete = "4.5"
clap_complete_fig = "4.5"
colored = "2.0"
@@ -232,10 +240,12 @@ dotenvy = "0.15.6"
ecdsa = "0.16"
ed25519-dalek = "2.1"
etherparse = "0.13.0"
envy = "0.4"
eyre = "0.6.9"
fastrand = "2.1.1"
flate2 = "1.0.34"
futures = "0.3.28"
futures-util = "0.3"
generic-array = "0.14.7"
getrandom = "0.2.10"
getset = "0.1.3"
@@ -265,6 +275,7 @@ ledger-transport-hid = "0.10.0"
log = "0.4"
maxminddb = "0.23.0"
mime = "0.3.17"
moka = { version = "0.12", features = ["future"] }
nix = "0.27.1"
notify = "5.1.0"
okapi = "0.7.0"
@@ -274,7 +285,8 @@ opentelemetry-jaeger = "0.18.0"
parking_lot = "0.12.3"
pem = "0.8"
petgraph = "0.6.5"
pin-project = "1.0"
pin-project = "1.1"
pin-project-lite = "0.2.14"
pretty_env_logger = "0.4.0"
publicsuffix = "2.2.3"
quote = "1"
@@ -293,18 +305,20 @@ rocket_okapi = "0.8.0"
safer-ffi = "0.1.13"
schemars = "0.8.21"
semver = "1.0.23"
serde = "1.0.210"
serde = "1.0.211"
serde_bytes = "0.11.15"
serde_derive = "1.0"
serde_json = "1.0.128"
serde_json = "1.0.132"
serde_json_path = "0.6.7"
serde_repr = "0.1"
serde_with = "3.9.0"
serde_yaml = "0.9.25"
sha2 = "0.10.8"
si-scale = "0.2.3"
sphinx-packet = "0.1.1"
sqlx = "0.6.3"
sqlx = "0.7.4"
strum = "0.26"
strum_macros = "0.26"
subtle-encoding = "0.5"
syn = "1"
sysinfo = "0.30.13"
@@ -326,7 +340,8 @@ tracing = "0.1.37"
tracing-opentelemetry = "0.19.0"
tracing-subscriber = "0.3.16"
tracing-tree = "0.2.2"
ts-rs = "7.0.0"
tracing-log = "0.2"
ts-rs = "10.0.0"
tungstenite = { version = "0.20.1", default-features = false }
url = "2.5"
utoipa = "4.2"
@@ -348,6 +363,7 @@ prometheus = { version = "0.13.0" }
bls12_381 = { git = "https://github.com/jstuczyn/bls12_381", default-features = false, branch = "temp/experimental-serdect" }
group = { version = "0.13.0", default-features = false }
ff = { version = "0.13.0", default-features = false }
subtle = "2.5.0"
# cosmwasm-related
cosmwasm-schema = "=1.4.3"
@@ -386,14 +402,20 @@ indexed_db_futures = { git = "https://github.com/TiemenSch/rust-indexed-db", bra
js-sys = "0.3.70"
serde-wasm-bindgen = "0.6.5"
tsify = "0.4.5"
wasm-bindgen = "0.2.93"
wasm-bindgen-futures = "0.4.43"
wasm-bindgen = "0.2.95"
wasm-bindgen-futures = "0.4.45"
wasmtimer = "0.2.0"
web-sys = "0.3.70"
web-sys = "0.3.72"
# Profile settings for individual crates
# Compile-time verified queries do quite a bit of work at compile time. Incremental
# actions like cargo check and cargo build can be significantly faster when
# using an optimized build
[profile.dev.package.sqlx-macros]
opt-level = 3
[profile.release.package.nym-socks5-listener]
strip = true
codegen-units = 1
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "nym-client"
version = "1.1.41"
version = "1.1.42"
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"]
description = "Implementation of the Nym Client"
edition = "2021"
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "nym-socks5-client"
version = "1.1.41"
version = "1.1.42"
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"
+1
View File
@@ -45,3 +45,4 @@ tracing = [
"opentelemetry",
]
clap = [ "dep:clap", "dep:clap_complete", "dep:clap_complete_fig" ]
models = []
@@ -0,0 +1,20 @@
{
"db_name": "SQLite",
"query": "SELECT EXISTS (SELECT 1 FROM registered_gateway WHERE gateway_id_bs58 = ?) AS 'exists'",
"describe": {
"columns": [
{
"name": "exists",
"ordinal": 0,
"type_info": "Int"
}
],
"parameters": {
"Right": 1
},
"nullable": [
null
]
},
"hash": "06e743d143fcc4be20ca2af5e99b19f15d22fff72490473587a14cdc046fda32"
}
@@ -0,0 +1,44 @@
{
"db_name": "SQLite",
"query": "SELECT * FROM remote_gateway_details WHERE gateway_id_bs58 = ?",
"describe": {
"columns": [
{
"name": "gateway_id_bs58",
"ordinal": 0,
"type_info": "Text"
},
{
"name": "gateway_owner_address",
"ordinal": 1,
"type_info": "Text"
},
{
"name": "gateway_listener",
"ordinal": 2,
"type_info": "Text"
},
{
"name": "derived_aes128_ctr_blake3_hmac_keys_bs58",
"ordinal": 3,
"type_info": "Text"
},
{
"name": "derived_aes256_gcm_siv_key",
"ordinal": 4,
"type_info": "Blob"
}
],
"parameters": {
"Right": 1
},
"nullable": [
false,
true,
false,
true,
true
]
},
"hash": "0e85ec18da67cf4e3df04ad80136571f6e920eb2290f20b1b8c5b0ab4b489985"
}
@@ -0,0 +1,12 @@
{
"db_name": "SQLite",
"query": "\n UPDATE remote_gateway_details\n SET\n derived_aes128_ctr_blake3_hmac_keys_bs58 = ?,\n derived_aes256_gcm_siv_key = ?\n WHERE gateway_id_bs58 = ?\n ",
"describe": {
"columns": [],
"parameters": {
"Right": 3
},
"nullable": []
},
"hash": "0f1dfb89f1eb39f4a58787af0f53a7a93afb7e4d2e54e2d38fd79d31c8575a54"
}
@@ -0,0 +1,12 @@
{
"db_name": "SQLite",
"query": "DELETE FROM remote_gateway_details WHERE gateway_id_bs58 = ?",
"describe": {
"columns": [],
"parameters": {
"Right": 1
},
"nullable": []
},
"hash": "1da6904e72b5abb9abf75affb13af7974d7795b4cbdba234273345fe161df233"
}
@@ -0,0 +1,12 @@
{
"db_name": "SQLite",
"query": "DELETE FROM custom_gateway_details WHERE gateway_id_bs58 = ?",
"describe": {
"columns": [],
"parameters": {
"Right": 1
},
"nullable": []
},
"hash": "4f78619aca933484cd67cb89a376b2a5bec1c191993ff58f0c71c03e3ef6d92d"
}
@@ -0,0 +1,26 @@
{
"db_name": "SQLite",
"query": "SELECT * FROM custom_gateway_details WHERE gateway_id_bs58 = ?",
"describe": {
"columns": [
{
"name": "gateway_id_bs58",
"ordinal": 0,
"type_info": "Text"
},
{
"name": "data",
"ordinal": 1,
"type_info": "Blob"
}
],
"parameters": {
"Right": 1
},
"nullable": [
false,
true
]
},
"hash": "54f552a9dbe95236f946ac2b6615e03504afa58e345ae16a128629d8e76f0a11"
}
@@ -0,0 +1,20 @@
{
"db_name": "SQLite",
"query": "SELECT gateway_id_bs58 FROM registered_gateway",
"describe": {
"columns": [
{
"name": "gateway_id_bs58",
"ordinal": 0,
"type_info": "Text"
}
],
"parameters": {
"Right": 0
},
"nullable": [
false
]
},
"hash": "5661cf1ad8bd5ca062e855e1971a8787133ee41814bd3efdd501f9ee0c050f2b"
}
@@ -0,0 +1,12 @@
{
"db_name": "SQLite",
"query": "UPDATE active_gateway SET active_gateway_id_bs58 = ?",
"describe": {
"columns": [],
"parameters": {
"Right": 1
},
"nullable": []
},
"hash": "80476cf2906eb0ecf7f66c16bc5682169b87f488b6927fa67fade6bf5abf7582"
}
@@ -0,0 +1,12 @@
{
"db_name": "SQLite",
"query": "\n INSERT INTO registered_gateway(gateway_id_bs58, registration_timestamp, gateway_type) \n VALUES (?, ?, ?)\n ",
"describe": {
"columns": [],
"parameters": {
"Right": 3
},
"nullable": []
},
"hash": "8909fd329e7e5fb16c4989b15b3d3a12bba1569520e01f6f074178e23d6ee89e"
}
@@ -0,0 +1,12 @@
{
"db_name": "SQLite",
"query": "\n INSERT INTO remote_gateway_details(gateway_id_bs58, derived_aes128_ctr_blake3_hmac_keys_bs58, derived_aes256_gcm_siv_key, gateway_owner_address, gateway_listener)\n VALUES (?, ?, ?, ?, ?)\n ",
"describe": {
"columns": [],
"parameters": {
"Right": 5
},
"nullable": []
},
"hash": "a6939bea03b10cde810a9a099bd597b4f51092e30a41c4085a8f8668f039f7c0"
}
@@ -0,0 +1,12 @@
{
"db_name": "SQLite",
"query": "\n INSERT INTO custom_gateway_details(gateway_id_bs58, data) \n VALUES (?, ?)\n ",
"describe": {
"columns": [],
"parameters": {
"Right": 2
},
"nullable": []
},
"hash": "b059bc3688b6b7f83f47048db9897720fd4e6f3211bf74030a9638f7bf6738e4"
}
@@ -0,0 +1,20 @@
{
"db_name": "SQLite",
"query": "SELECT active_gateway_id_bs58 FROM active_gateway",
"describe": {
"columns": [
{
"name": "active_gateway_id_bs58",
"ordinal": 0,
"type_info": "Text"
}
],
"parameters": {
"Right": 0
},
"nullable": [
true
]
},
"hash": "bf249752f08c283bf5942b6ff48125c24750b523cfcad1e5e9069dbf7050e2a1"
}
@@ -0,0 +1,12 @@
{
"db_name": "SQLite",
"query": "DELETE FROM registered_gateway WHERE gateway_id_bs58 = ?",
"describe": {
"columns": [],
"parameters": {
"Right": 1
},
"nullable": []
},
"hash": "f3ebe259e26c05ecdd33bd9085dbb91cd5046a8c9d4434cf085a4fa2ebf03e93"
}
@@ -29,11 +29,10 @@ impl StorageManager {
})?;
}
let mut opts = sqlx::sqlite::SqliteConnectOptions::new()
let opts = sqlx::sqlite::SqliteConnectOptions::new()
.filename(database_path)
.create_if_missing(true);
opts.disable_statement_logging();
.create_if_missing(true)
.disable_statement_logging();
let connection_pool = sqlx::SqlitePool::connect_with(opts)
.await
@@ -82,7 +81,7 @@ impl StorageManager {
sqlx::query!("SELECT EXISTS (SELECT 1 FROM registered_gateway WHERE gateway_id_bs58 = ?) AS 'exists'", gateway_id)
.fetch_one(&self.connection_pool)
.await
.map(|result| result.exists == 1)
.map(|result| result.exists == Some(1))
}
pub(crate) async fn maybe_get_registered_gateway(
@@ -3,11 +3,11 @@ use log::{debug, error};
use nym_explorer_client::{ExplorerClient, PrettyDetailedMixNodeBond};
use nym_network_defaults::var_names::EXPLORER_API;
use nym_topology::{
nym_topology_from_detailed,
nym_topology_from_basic_info,
provider_trait::{async_trait, TopologyProvider},
NymTopology,
};
use nym_validator_client::client::MixId;
use nym_validator_client::client::NodeId;
use rand::{prelude::SliceRandom, thread_rng};
use std::collections::HashMap;
use tap::TapOptional;
@@ -39,10 +39,10 @@ fn create_explorer_client() -> Option<ExplorerClient> {
fn group_mixnodes_by_country_code(
mixnodes: Vec<PrettyDetailedMixNodeBond>,
) -> HashMap<CountryGroup, Vec<MixId>> {
) -> HashMap<CountryGroup, Vec<NodeId>> {
mixnodes
.into_iter()
.fold(HashMap::<CountryGroup, Vec<MixId>>::new(), |mut acc, m| {
.fold(HashMap::<CountryGroup, Vec<NodeId>>::new(), |mut acc, m| {
if let Some(ref location) = m.location {
let country_code = location.two_letter_iso_country_code.clone();
let group_code = CountryGroup::new(country_code.as_str());
@@ -53,7 +53,7 @@ fn group_mixnodes_by_country_code(
})
}
fn log_mixnode_distribution(mixnodes: &HashMap<CountryGroup, Vec<MixId>>) {
fn log_mixnode_distribution(mixnodes: &HashMap<CountryGroup, Vec<NodeId>>) {
let mixnode_distribution = mixnodes
.iter()
.map(|(k, v)| format!("{}: {}", k, v.len()))
@@ -110,7 +110,11 @@ impl GeoAwareTopologyProvider {
}
async fn get_topology(&self) -> Option<NymTopology> {
let mixnodes = match self.validator_client.get_cached_active_mixnodes().await {
let mixnodes = match self
.validator_client
.get_basic_active_mixing_assigned_nodes(Some(self.client_version.clone()))
.await
{
Err(err) => {
error!("failed to get network mixnodes - {err}");
return None;
@@ -118,7 +122,11 @@ impl GeoAwareTopologyProvider {
Ok(mixes) => mixes,
};
let gateways = match self.validator_client.get_cached_gateways().await {
let gateways = match self
.validator_client
.get_all_basic_entry_assigned_nodes(Some(self.client_version.clone()))
.await
{
Err(err) => {
error!("failed to get network gateways - {err}");
return None;
@@ -182,11 +190,10 @@ impl GeoAwareTopologyProvider {
let mixnodes = mixnodes
.into_iter()
.filter(|m| filtered_mixnode_ids.contains(&m.mix_id()))
.filter(|m| filtered_mixnode_ids.contains(&m.node_id))
.collect::<Vec<_>>();
let topology = nym_topology_from_detailed(mixnodes, gateways)
.filter_system_version(&self.client_version);
let topology = nym_topology_from_basic_info(&mixnodes, &gateways);
// TODO: return real error type
check_layer_integrity(topology.clone()).ok()?;
@@ -98,7 +98,7 @@ impl NymApiTopologyProvider {
async fn get_current_compatible_topology(&mut self) -> Option<NymTopology> {
let mixnodes = match self
.validator_client
.get_basic_mixnodes(Some(self.client_version.clone()))
.get_basic_active_mixing_assigned_nodes(Some(self.client_version.clone()))
.await
{
Err(err) => {
@@ -110,7 +110,7 @@ impl NymApiTopologyProvider {
let gateways = match self
.validator_client
.get_basic_gateways(Some(self.client_version.clone()))
.get_all_basic_entry_assigned_nodes(Some(self.client_version.clone()))
.await
{
Err(err) => {
@@ -134,7 +134,6 @@ impl NymApiTopologyProvider {
g.performance.round_to_integer() >= self.config.min_gateway_performance
}),
);
if let Err(err) = self.check_layer_distribution(&topology) {
warn!("The current filtered active topology has extremely skewed layer distribution. It cannot be used: {err}");
self.use_next_nym_api();
-10
View File
@@ -187,16 +187,6 @@ pub enum ClientCoreError {
source: Ed25519RecoveryError,
},
#[error("the account owner of gateway {gateway_id} ({raw_owner}) is malformed: {err}")]
MalformedGatewayOwnerAccountAddress {
gateway_id: String,
raw_owner: String,
// just use the string formatting as opposed to underlying type to avoid having to import cosmrs
err: String,
},
#[error(
"the listening address of gateway {gateway_id} ({raw_listener}) is malformed: {source}"
)]
+19 -26
View File
@@ -7,7 +7,7 @@ use futures::{SinkExt, StreamExt};
use log::{debug, info, trace, warn};
use nym_crypto::asymmetric::identity;
use nym_gateway_client::GatewayClient;
use nym_topology::{filter::VersionFilterable, gateway, mix};
use nym_topology::{gateway, mix};
use nym_validator_client::client::IdentityKeyRef;
use nym_validator_client::UserAgent;
use rand::{seq::SliceRandom, Rng};
@@ -53,7 +53,7 @@ pub trait ConnectableGateway {
fn is_wss(&self) -> bool;
}
impl ConnectableGateway for gateway::Node {
impl ConnectableGateway for gateway::LegacyNode {
fn identity(&self) -> &identity::PublicKey {
self.identity()
}
@@ -82,7 +82,7 @@ pub async fn current_gateways<R: Rng>(
rng: &mut R,
nym_apis: &[Url],
user_agent: Option<UserAgent>,
) -> Result<Vec<gateway::Node>, ClientCoreError> {
) -> Result<Vec<gateway::LegacyNode>, ClientCoreError> {
let nym_api = nym_apis
.choose(rng)
.ok_or(ClientCoreError::ListOfNymApisIsEmpty)?;
@@ -94,31 +94,26 @@ pub async fn current_gateways<R: Rng>(
log::debug!("Fetching list of gateways from: {nym_api}");
let gateways = client.get_cached_described_gateways().await?;
let gateways = client.get_all_basic_entry_assigned_nodes(None).await?;
log::debug!("Found {} gateways", gateways.len());
log::trace!("Gateways: {:#?}", gateways);
let valid_gateways = gateways
.into_iter()
.iter()
.filter_map(|gateway| gateway.try_into().ok())
.collect::<Vec<gateway::Node>>();
log::debug!("Ater checking validity: {}", valid_gateways.len());
.collect::<Vec<gateway::LegacyNode>>();
log::debug!("After checking validity: {}", valid_gateways.len());
log::trace!("Valid gateways: {:#?}", valid_gateways);
// we were always filtering by version so I'm not removing that 'feature'
let filtered_gateways = valid_gateways.filter_by_version(env!("CARGO_PKG_VERSION"));
log::debug!("After filtering for version: {}", filtered_gateways.len());
log::trace!("Filtered gateways: {:#?}", filtered_gateways);
log::info!("nym-api reports {} valid gateways", valid_gateways.len());
log::info!("nym-api reports {} valid gateways", filtered_gateways.len());
Ok(filtered_gateways)
Ok(valid_gateways)
}
pub async fn current_mixnodes<R: Rng>(
rng: &mut R,
nym_apis: &[Url],
) -> Result<Vec<mix::Node>, ClientCoreError> {
) -> Result<Vec<mix::LegacyNode>, ClientCoreError> {
let nym_api = nym_apis
.choose(rng)
.ok_or(ClientCoreError::ListOfNymApisIsEmpty)?;
@@ -126,15 +121,13 @@ pub async fn current_mixnodes<R: Rng>(
log::trace!("Fetching list of mixnodes from: {nym_api}");
let mixnodes = client.get_cached_mixnodes().await?;
let mixnodes = client.get_basic_active_mixing_assigned_nodes(None).await?;
let valid_mixnodes = mixnodes
.into_iter()
.filter_map(|mixnode| (&mixnode.bond_information).try_into().ok())
.collect::<Vec<mix::Node>>();
.iter()
.filter_map(|mixnode| mixnode.try_into().ok())
.collect::<Vec<mix::LegacyNode>>();
// we were always filtering by version so I'm not removing that 'feature'
let filtered_mixnodes = valid_mixnodes.filter_by_version(env!("CARGO_PKG_VERSION"));
Ok(filtered_mixnodes)
Ok(valid_mixnodes)
}
#[cfg(not(target_arch = "wasm32"))]
@@ -273,9 +266,9 @@ fn filter_by_tls<G: ConnectableGateway>(
pub(super) fn uniformly_random_gateway<R: Rng>(
rng: &mut R,
gateways: &[gateway::Node],
gateways: &[gateway::LegacyNode],
must_use_tls: bool,
) -> Result<gateway::Node, ClientCoreError> {
) -> Result<gateway::LegacyNode, ClientCoreError> {
filter_by_tls(gateways, must_use_tls)?
.choose(rng)
.ok_or(ClientCoreError::NoGatewaysOnNetwork)
@@ -284,9 +277,9 @@ pub(super) fn uniformly_random_gateway<R: Rng>(
pub(super) fn get_specified_gateway(
gateway_identity: IdentityKeyRef,
gateways: &[gateway::Node],
gateways: &[gateway::LegacyNode],
must_use_tls: bool,
) -> Result<gateway::Node, ClientCoreError> {
) -> Result<gateway::LegacyNode, ClientCoreError> {
log::debug!("Requesting specified gateway: {}", gateway_identity);
let user_gateway = identity::PublicKey::from_base58_string(gateway_identity)
.map_err(ClientCoreError::UnableToCreatePublicKeyFromGatewayId)?;
+1 -1
View File
@@ -50,7 +50,7 @@ async fn setup_new_gateway<K, D>(
key_store: &K,
details_store: &D,
selection_specification: GatewaySelectionSpecification,
available_gateways: Vec<gateway::Node>,
available_gateways: Vec<gateway::LegacyNode>,
) -> Result<InitialisationResult, ClientCoreError>
where
K: KeyStore,
+3 -18
View File
@@ -18,7 +18,6 @@ use nym_validator_client::client::IdentityKey;
use nym_validator_client::nyxd::AccountId;
use serde::Serialize;
use std::fmt::Display;
use std::str::FromStr;
use std::sync::Arc;
use time::OffsetDateTime;
use url::Url;
@@ -39,7 +38,7 @@ pub enum SelectedGateway {
impl SelectedGateway {
pub fn from_topology_node(
node: gateway::Node,
node: gateway::LegacyNode,
must_use_tls: bool,
) -> Result<Self, ClientCoreError> {
let gateway_listener = if must_use_tls {
@@ -51,20 +50,6 @@ impl SelectedGateway {
node.clients_address()
};
let gateway_owner_address = node
.owner
.as_ref()
.map(|raw_owner| {
AccountId::from_str(raw_owner).map_err(|source| {
ClientCoreError::MalformedGatewayOwnerAccountAddress {
gateway_id: node.identity_key.to_base58_string(),
raw_owner: raw_owner.clone(),
err: source.to_string(),
}
})
})
.transpose()?;
let gateway_listener =
Url::parse(&gateway_listener).map_err(|source| ClientCoreError::MalformedListener {
gateway_id: node.identity_key.to_base58_string(),
@@ -74,7 +59,7 @@ impl SelectedGateway {
Ok(SelectedGateway::Remote {
gateway_id: node.identity_key,
gateway_owner_address,
gateway_owner_address: None,
gateway_listener,
})
}
@@ -215,7 +200,7 @@ pub enum GatewaySetup {
specification: GatewaySelectionSpecification,
// TODO: seems to be a bit inefficient to pass them by value
available_gateways: Vec<gateway::Node>,
available_gateways: Vec<gateway::LegacyNode>,
},
ReuseConnection {
@@ -1,9 +1,12 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::backend::fs_backend::error::StorageError;
use crate::backend::fs_backend::models::{
ReplySurbStorageMetadata, StoredReplyKey, StoredReplySurb, StoredSenderTag, StoredSurbSender,
use crate::backend::fs_backend::{
error::StorageError,
models::{
ReplySurbStorageMetadata, StoredReplyKey, StoredReplySurb, StoredSenderTag,
StoredSurbSender,
},
};
use log::{error, info};
use sqlx::ConnectOptions;
@@ -27,11 +30,10 @@ impl StorageManager {
})?;
}
let mut opts = sqlx::sqlite::SqliteConnectOptions::new()
let opts = sqlx::sqlite::SqliteConnectOptions::new()
.filename(database_path)
.create_if_missing(fresh);
opts.disable_statement_logging();
.create_if_missing(fresh)
.disable_statement_logging();
let connection_pool = match sqlx::SqlitePool::connect_with(opts).await {
Ok(pool) => pool,
@@ -25,7 +25,7 @@ serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true }
nym-http-api-client = { path = "../../../common/http-api-client" }
thiserror = { workspace = true }
log = { workspace = true }
tracing = { workspace = true }
url = { workspace = true, features = ["serde"] }
tokio = { workspace = true, features = ["sync", "time"] }
time = { workspace = true, features = ["formatting"] }
@@ -17,11 +17,11 @@ use nym_api_requests::ecash::{
BlindSignRequestBody, BlindedSignatureResponse, PartialCoinIndicesSignatureResponse,
PartialExpirationDateSignatureResponse, VerificationKeyResponse,
};
use nym_api_requests::models::{DescribedGateway, MixNodeBondAnnotated};
use nym_api_requests::models::{
GatewayCoreStatusResponse, MixnodeCoreStatusResponse, MixnodeStatusResponse,
RewardEstimationResponse, StakeSaturationResponse,
};
use nym_api_requests::models::{LegacyDescribedGateway, MixNodeBondAnnotated};
use nym_api_requests::nym_nodes::SkimmedNode;
use nym_coconut_dkg_common::types::EpochId;
use nym_http_api_client::UserAgent;
@@ -31,7 +31,7 @@ use url::Url;
pub use crate::nym_api::NymApiClientExt;
pub use nym_mixnet_contract_common::{
mixnode::MixNodeDetails, GatewayBond, IdentityKey, IdentityKeyRef, MixId,
mixnode::MixNodeDetails, GatewayBond, IdentityKey, IdentityKeyRef, NodeId,
};
// re-export the type to not break existing imports
@@ -265,6 +265,13 @@ impl NymApiClient {
NymApiClient { nym_api }
}
#[cfg(not(target_arch = "wasm32"))]
pub fn new_with_timeout(api_url: Url, timeout: std::time::Duration) -> Self {
let nym_api = nym_api::Client::new(api_url, Some(timeout));
NymApiClient { nym_api }
}
pub fn new_with_user_agent(api_url: Url, user_agent: UserAgent) -> Self {
let nym_api = nym_api::Client::builder::<_, ValidatorClientError>(api_url)
.expect("invalid api url")
@@ -283,6 +290,7 @@ impl NymApiClient {
self.nym_api.change_base_url(new_endpoint);
}
#[deprecated(note = "use get_basic_active_mixing_assigned_nodes instead")]
pub async fn get_basic_mixnodes(
&self,
semver_compatibility: Option<String>,
@@ -294,6 +302,7 @@ impl NymApiClient {
.nodes)
}
#[deprecated(note = "use get_all_basic_entry_assigned_nodes instead")]
pub async fn get_basic_gateways(
&self,
semver_compatibility: Option<String>,
@@ -305,6 +314,70 @@ impl NymApiClient {
.nodes)
}
/// retrieve basic information for nodes are capable of operating as an entry gateway
/// this includes legacy gateways and nym-nodes
pub async fn get_all_basic_entry_assigned_nodes(
&self,
semver_compatibility: Option<String>,
) -> Result<Vec<SkimmedNode>, ValidatorClientError> {
// TODO: deal with paging in macro or some helper function or something, because it's the same pattern everywhere
let mut page = 0;
let mut nodes = Vec::new();
loop {
let mut res = self
.nym_api
.get_all_basic_entry_assigned_nodes(
semver_compatibility.clone(),
false,
Some(page),
None,
)
.await?;
nodes.append(&mut res.nodes.data);
if nodes.len() < res.nodes.pagination.total {
page += 1
} else {
break;
}
}
Ok(nodes)
}
/// retrieve basic information for nodes that got assigned 'mixing' node in this epoch
/// this includes legacy mixnodes and nym-nodes
pub async fn get_basic_active_mixing_assigned_nodes(
&self,
semver_compatibility: Option<String>,
) -> Result<Vec<SkimmedNode>, ValidatorClientError> {
// TODO: deal with paging in macro or some helper function or something, because it's the same pattern everywhere
let mut page = 0;
let mut nodes = Vec::new();
loop {
let mut res = self
.nym_api
.get_basic_active_mixing_assigned_nodes(
semver_compatibility.clone(),
false,
Some(page),
None,
)
.await?;
nodes.append(&mut res.nodes.data);
if nodes.len() < res.nodes.pagination.total {
page += 1
} else {
break;
}
}
Ok(nodes)
}
pub async fn get_cached_active_mixnodes(
&self,
) -> Result<Vec<MixNodeDetails>, ValidatorClientError> {
@@ -327,7 +400,7 @@ impl NymApiClient {
pub async fn get_cached_described_gateways(
&self,
) -> Result<Vec<DescribedGateway>, ValidatorClientError> {
) -> Result<Vec<LegacyDescribedGateway>, ValidatorClientError> {
Ok(self.nym_api.get_gateways_described().await?)
}
@@ -344,7 +417,7 @@ impl NymApiClient {
pub async fn get_mixnode_core_status_count(
&self,
mix_id: MixId,
mix_id: NodeId,
since: Option<i64>,
) -> Result<MixnodeCoreStatusResponse, ValidatorClientError> {
Ok(self
@@ -355,21 +428,21 @@ impl NymApiClient {
pub async fn get_mixnode_status(
&self,
mix_id: MixId,
mix_id: NodeId,
) -> Result<MixnodeStatusResponse, ValidatorClientError> {
Ok(self.nym_api.get_mixnode_status(mix_id).await?)
}
pub async fn get_mixnode_reward_estimation(
&self,
mix_id: MixId,
mix_id: NodeId,
) -> Result<RewardEstimationResponse, ValidatorClientError> {
Ok(self.nym_api.get_mixnode_reward_estimation(mix_id).await?)
}
pub async fn get_mixnode_stake_saturation(
&self,
mix_id: MixId,
mix_id: NodeId,
) -> Result<StakeSaturationResponse, ValidatorClientError> {
Ok(self.nym_api.get_mixnode_stake_saturation(mix_id).await?)
}
@@ -121,36 +121,36 @@ async fn test_nyxd_connection(
{
Ok(Err(NyxdError::TendermintErrorRpc(e))) => {
// If we get a tendermint-rpc error, we classify the node as not contactable
log::warn!("Checking: nyxd url: {url}: {}: {}", "failed".red(), e);
tracing::warn!("Checking: nyxd url: {url}: {}: {}", "failed".red(), e);
false
}
Ok(Err(NyxdError::AbciError { code, log, .. })) => {
// We accept the mixnet contract not found as ok from a connection standpoint. This happens
// for example on a pre-launch network.
log::debug!(
tracing::debug!(
"Checking: nyxd url: {url}: {}, but with abci error: {code}: {log}",
"success".green()
);
code == 18
}
Ok(Err(error @ NyxdError::NoContractAddressAvailable(_))) => {
log::warn!("Checking: nyxd url: {url}: {}: {error}", "failed".red());
tracing::warn!("Checking: nyxd url: {url}: {}: {error}", "failed".red());
false
}
Ok(Err(e)) => {
// For any other error, we're optimistic and just try anyway.
log::warn!(
tracing::warn!(
"Checking: nyxd_url: {url}: {}, but with error: {e}",
"success".green()
);
true
}
Ok(Ok(_)) => {
log::debug!("Checking: nyxd_url: {url}: {}", "success".green());
tracing::debug!("Checking: nyxd_url: {url}: {}", "success".green());
true
}
Err(e) => {
log::warn!("Checking: nyxd_url: {url}: {}: {e}", "failed".red());
tracing::warn!("Checking: nyxd_url: {url}: {}: {e}", "failed".red());
false
}
};
@@ -169,15 +169,15 @@ async fn test_nym_api_connection(
.await
{
Ok(Ok(_)) => {
log::debug!("Checking: api_url: {url}: {}", "success".green());
tracing::debug!("Checking: api_url: {url}: {}", "success".green());
true
}
Ok(Err(e)) => {
log::debug!("Checking: api_url: {url}: {}: {e}", "failed".red());
tracing::debug!("Checking: api_url: {url}: {}: {e}", "failed".red());
false
}
Err(e) => {
log::debug!("Checking: api_url: {url}: {}: {e}", "failed".red());
tracing::debug!("Checking: api_url: {url}: {}: {e}", "failed".red());
false
}
};
@@ -10,8 +10,10 @@ use nym_api_requests::ecash::models::{
VerifyEcashTicketBody,
};
use nym_api_requests::ecash::VerificationKeyResponse;
use nym_api_requests::models::DescribedMixNode;
use nym_api_requests::nym_nodes::{CachedNodesResponse, SkimmedNode};
use nym_api_requests::models::{
AnnotationResponse, LegacyDescribedMixNode, NodePerformanceResponse,
};
use nym_api_requests::nym_nodes::PaginatedCachedNodesResponse;
pub use nym_api_requests::{
ecash::{
models::{
@@ -23,21 +25,23 @@ pub use nym_api_requests::{
VerifyEcashCredentialBody,
},
models::{
ComputeRewardEstParam, DescribedGateway, GatewayBondAnnotated, GatewayCoreStatusResponse,
ComputeRewardEstParam, GatewayBondAnnotated, GatewayCoreStatusResponse,
GatewayStatusReportResponse, GatewayUptimeHistoryResponse, InclusionProbabilityResponse,
MixNodeBondAnnotated, MixnodeCoreStatusResponse, MixnodeStatusReportResponse,
MixnodeStatusResponse, MixnodeUptimeHistoryResponse, RewardEstimationResponse,
StakeSaturationResponse, UptimeResponse,
LegacyDescribedGateway, MixNodeBondAnnotated, MixnodeCoreStatusResponse,
MixnodeStatusReportResponse, MixnodeStatusResponse, MixnodeUptimeHistoryResponse,
RewardEstimationResponse, StakeSaturationResponse, UptimeResponse,
},
nym_nodes::{CachedNodesResponse, SkimmedNode},
};
pub use nym_coconut_dkg_common::types::EpochId;
use nym_contracts_common::IdentityKey;
pub use nym_http_api_client::Client;
use nym_http_api_client::{ApiClient, NO_PARAMS};
use nym_mixnet_contract_common::mixnode::MixNodeDetails;
use nym_mixnet_contract_common::{GatewayBond, IdentityKeyRef, MixId};
use nym_mixnet_contract_common::{GatewayBond, IdentityKeyRef, NodeId};
use time::format_description::BorrowedFormatItem;
use time::Date;
use tracing::instrument;
pub mod error;
pub mod routes;
@@ -49,11 +53,13 @@ pub fn rfc_3339_date() -> Vec<BorrowedFormatItem<'static>> {
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
pub trait NymApiClientExt: ApiClient {
#[instrument(level = "debug", skip(self))]
async fn get_mixnodes(&self) -> Result<Vec<MixNodeDetails>, NymAPIError> {
self.get_json(&[routes::API_VERSION, routes::MIXNODES], NO_PARAMS)
.await
}
#[instrument(level = "debug", skip(self))]
async fn get_mixnodes_detailed(&self) -> Result<Vec<MixNodeBondAnnotated>, NymAPIError> {
self.get_json(
&[
@@ -67,6 +73,7 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[instrument(level = "debug", skip(self))]
async fn get_gateways_detailed(&self) -> Result<Vec<GatewayBondAnnotated>, NymAPIError> {
self.get_json(
&[
@@ -80,6 +87,7 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[instrument(level = "debug", skip(self))]
async fn get_mixnodes_detailed_unfiltered(
&self,
) -> Result<Vec<MixNodeBondAnnotated>, NymAPIError> {
@@ -95,12 +103,14 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[instrument(level = "debug", skip(self))]
async fn get_gateways(&self) -> Result<Vec<GatewayBond>, NymAPIError> {
self.get_json(&[routes::API_VERSION, routes::GATEWAYS], NO_PARAMS)
.await
}
async fn get_gateways_described(&self) -> Result<Vec<DescribedGateway>, NymAPIError> {
#[instrument(level = "debug", skip(self))]
async fn get_gateways_described(&self) -> Result<Vec<LegacyDescribedGateway>, NymAPIError> {
self.get_json(
&[routes::API_VERSION, routes::GATEWAYS, routes::DESCRIBED],
NO_PARAMS,
@@ -108,7 +118,8 @@ pub trait NymApiClientExt: ApiClient {
.await
}
async fn get_mixnodes_described(&self) -> Result<Vec<DescribedMixNode>, NymAPIError> {
#[instrument(level = "debug", skip(self))]
async fn get_mixnodes_described(&self) -> Result<Vec<LegacyDescribedMixNode>, NymAPIError> {
self.get_json(
&[routes::API_VERSION, routes::MIXNODES, routes::DESCRIBED],
NO_PARAMS,
@@ -116,6 +127,7 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[tracing::instrument(level = "debug", skip_all)]
async fn get_basic_mixnodes(
&self,
semver_compatibility: Option<String>,
@@ -139,6 +151,7 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[instrument(level = "debug", skip(self))]
async fn get_basic_gateways(
&self,
semver_compatibility: Option<String>,
@@ -162,6 +175,91 @@ pub trait NymApiClientExt: ApiClient {
.await
}
/// retrieve basic information for nodes are capable of operating as an entry gateway
/// this includes legacy gateways and nym-nodes
#[instrument(level = "debug", skip(self))]
async fn get_all_basic_entry_assigned_nodes(
&self,
semver_compatibility: Option<String>,
no_legacy: bool,
page: Option<u32>,
per_page: Option<u32>,
) -> Result<PaginatedCachedNodesResponse<SkimmedNode>, NymAPIError> {
let mut params = Vec::new();
if let Some(arg) = &semver_compatibility {
params.push(("semver_compatibility", arg.clone()))
}
if no_legacy {
params.push(("no_legacy", "true".to_string()))
}
if let Some(page) = page {
params.push(("page", page.to_string()))
}
if let Some(per_page) = per_page {
params.push(("per_page", per_page.to_string()))
}
self.get_json(
&[
routes::API_VERSION,
"unstable",
"nym-nodes",
"skimmed",
"entry-gateways",
"all",
],
&params,
)
.await
}
/// retrieve basic information for nodes that got assigned 'mixing' node in this epoch
/// this includes legacy mixnodes and nym-nodes
#[instrument(level = "debug", skip(self))]
async fn get_basic_active_mixing_assigned_nodes(
&self,
semver_compatibility: Option<String>,
no_legacy: bool,
page: Option<u32>,
per_page: Option<u32>,
) -> Result<PaginatedCachedNodesResponse<SkimmedNode>, NymAPIError> {
let mut params = Vec::new();
if let Some(arg) = &semver_compatibility {
params.push(("semver_compatibility", arg.clone()))
}
if no_legacy {
params.push(("no_legacy", "true".to_string()))
}
if let Some(page) = page {
params.push(("page", page.to_string()))
}
if let Some(per_page) = per_page {
params.push(("per_page", per_page.to_string()))
}
self.get_json(
&[
routes::API_VERSION,
"unstable",
"nym-nodes",
"skimmed",
"mixnodes",
"active",
],
&params,
)
.await
}
#[instrument(level = "debug", skip(self))]
async fn get_active_mixnodes(&self) -> Result<Vec<MixNodeDetails>, NymAPIError> {
self.get_json(
&[routes::API_VERSION, routes::MIXNODES, routes::ACTIVE],
@@ -170,6 +268,7 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[instrument(level = "debug", skip(self))]
async fn get_active_mixnodes_detailed(&self) -> Result<Vec<MixNodeBondAnnotated>, NymAPIError> {
self.get_json(
&[
@@ -184,6 +283,7 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[instrument(level = "debug", skip(self))]
async fn get_rewarded_mixnodes(&self) -> Result<Vec<MixNodeDetails>, NymAPIError> {
self.get_json(
&[routes::API_VERSION, routes::MIXNODES, routes::REWARDED],
@@ -192,9 +292,10 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[instrument(level = "debug", skip(self))]
async fn get_mixnode_report(
&self,
mix_id: MixId,
mix_id: NodeId,
) -> Result<MixnodeStatusReportResponse, NymAPIError> {
self.get_json(
&[
@@ -209,6 +310,7 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[instrument(level = "debug", skip(self))]
async fn get_gateway_report(
&self,
identity: IdentityKeyRef<'_>,
@@ -226,9 +328,10 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[instrument(level = "debug", skip(self))]
async fn get_mixnode_history(
&self,
mix_id: MixId,
mix_id: NodeId,
) -> Result<MixnodeUptimeHistoryResponse, NymAPIError> {
self.get_json(
&[
@@ -243,6 +346,7 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[instrument(level = "debug", skip(self))]
async fn get_gateway_history(
&self,
identity: IdentityKeyRef<'_>,
@@ -260,6 +364,7 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[instrument(level = "debug", skip(self))]
async fn get_rewarded_mixnodes_detailed(
&self,
) -> Result<Vec<MixNodeBondAnnotated>, NymAPIError> {
@@ -276,6 +381,7 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[instrument(level = "debug", skip(self))]
async fn get_gateway_core_status_count(
&self,
identity: IdentityKeyRef<'_>,
@@ -307,9 +413,10 @@ pub trait NymApiClientExt: ApiClient {
}
}
#[instrument(level = "debug", skip(self))]
async fn get_mixnode_core_status_count(
&self,
mix_id: MixId,
mix_id: NodeId,
since: Option<i64>,
) -> Result<MixnodeCoreStatusResponse, NymAPIError> {
if let Some(since) = since {
@@ -339,9 +446,10 @@ pub trait NymApiClientExt: ApiClient {
}
}
#[instrument(level = "debug", skip(self))]
async fn get_mixnode_status(
&self,
mix_id: MixId,
mix_id: NodeId,
) -> Result<MixnodeStatusResponse, NymAPIError> {
self.get_json(
&[
@@ -356,9 +464,10 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[instrument(level = "debug", skip(self))]
async fn get_mixnode_reward_estimation(
&self,
mix_id: MixId,
mix_id: NodeId,
) -> Result<RewardEstimationResponse, NymAPIError> {
self.get_json(
&[
@@ -373,9 +482,10 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[instrument(level = "debug", skip(self))]
async fn compute_mixnode_reward_estimation(
&self,
mix_id: MixId,
mix_id: NodeId,
request_body: &ComputeRewardEstParam,
) -> Result<RewardEstimationResponse, NymAPIError> {
self.post_json(
@@ -392,9 +502,10 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[instrument(level = "debug", skip(self))]
async fn get_mixnode_stake_saturation(
&self,
mix_id: MixId,
mix_id: NodeId,
) -> Result<StakeSaturationResponse, NymAPIError> {
self.get_json(
&[
@@ -409,9 +520,10 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[instrument(level = "debug", skip(self))]
async fn get_mixnode_inclusion_probability(
&self,
mix_id: MixId,
mix_id: NodeId,
) -> Result<InclusionProbabilityResponse, NymAPIError> {
self.get_json(
&[
@@ -426,7 +538,24 @@ pub trait NymApiClientExt: ApiClient {
.await
}
async fn get_mixnode_avg_uptime(&self, mix_id: MixId) -> Result<UptimeResponse, NymAPIError> {
#[instrument(level = "debug", skip(self))]
async fn get_current_node_performance(
&self,
node_id: NodeId,
) -> Result<NodePerformanceResponse, NymAPIError> {
self.get_json_from(format!("/v1/nym-nodes/performance/{node_id}"))
.await
}
async fn get_node_annotation(
&self,
node_id: NodeId,
) -> Result<AnnotationResponse, NymAPIError> {
self.get_json_from(format!("/v1/nym-nodes/annotation/{node_id}"))
.await
}
async fn get_mixnode_avg_uptime(&self, mix_id: NodeId) -> Result<UptimeResponse, NymAPIError> {
self.get_json(
&[
routes::API_VERSION,
@@ -440,7 +569,8 @@ pub trait NymApiClientExt: ApiClient {
.await
}
async fn get_mixnodes_blacklisted(&self) -> Result<Vec<MixId>, NymAPIError> {
#[instrument(level = "debug", skip(self))]
async fn get_mixnodes_blacklisted(&self) -> Result<Vec<NodeId>, NymAPIError> {
self.get_json(
&[routes::API_VERSION, routes::MIXNODES, routes::BLACKLISTED],
NO_PARAMS,
@@ -448,6 +578,7 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[instrument(level = "debug", skip(self))]
async fn get_gateways_blacklisted(&self) -> Result<Vec<IdentityKey>, NymAPIError> {
self.get_json(
&[routes::API_VERSION, routes::GATEWAYS, routes::BLACKLISTED],
@@ -456,6 +587,7 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[instrument(level = "debug", skip(self, request_body))]
async fn blind_sign(
&self,
request_body: &BlindSignRequestBody,
@@ -472,6 +604,7 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[instrument(level = "debug", skip(self, request_body))]
async fn verify_ecash_ticket(
&self,
request_body: &VerifyEcashTicketBody,
@@ -488,6 +621,7 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[instrument(level = "debug", skip(self, request_body))]
async fn batch_redeem_ecash_tickets(
&self,
request_body: &BatchRedeemTicketsBody,
@@ -504,6 +638,7 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[instrument(level = "debug", skip(self))]
async fn double_spending_filter_v1(&self) -> Result<SpentCredentialsResponse, NymAPIError> {
self.get_json(
&[
@@ -516,6 +651,7 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[instrument(level = "debug", skip(self))]
async fn partial_expiration_date_signatures(
&self,
expiration_date: Option<Date>,
@@ -539,6 +675,7 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[instrument(level = "debug", skip(self))]
async fn partial_coin_indices_signatures(
&self,
epoch_id: Option<EpochId>,
@@ -559,6 +696,7 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[instrument(level = "debug", skip(self))]
async fn global_expiration_date_signatures(
&self,
expiration_date: Option<Date>,
@@ -582,6 +720,7 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[instrument(level = "debug", skip(self))]
async fn global_coin_indices_signatures(
&self,
epoch_id: Option<EpochId>,
@@ -602,6 +741,7 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[instrument(level = "debug", skip(self))]
async fn master_verification_key(
&self,
epoch_id: Option<EpochId>,
@@ -621,6 +761,7 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[instrument(level = "debug", skip(self))]
async fn epoch_credentials(
&self,
dkg_epoch: EpochId,
@@ -637,6 +778,7 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[instrument(level = "debug", skip(self))]
async fn issued_credential(
&self,
credential_id: i64,
@@ -653,6 +795,7 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[instrument(level = "debug", skip(self))]
async fn issued_credentials(
&self,
credential_ids: Vec<i64>,
@@ -38,6 +38,7 @@ pub mod ecash {
pub const STATUS_ROUTES: &str = "status";
pub const MIXNODE: &str = "mixnode";
pub const GATEWAY: &str = "gateway";
pub const NYM_NODES: &str = "nym-nodes";
pub const CORE_STATUS_COUNT: &str = "core-status-count";
pub const SINCE_ARG: &str = "since";
@@ -52,5 +53,6 @@ pub const STAKE_SATURATION: &str = "stake-saturation";
pub const INCLUSION_CHANCE: &str = "inclusion-probability";
pub const SUBMIT_GATEWAY: &str = "submit-gateway-monitoring-results";
pub const SUBMIT_NODE: &str = "submit-node-monitoring-results";
pub const PERFORMANCE: &str = "performance";
pub const SERVICE_PROVIDERS: &str = "services";
@@ -8,9 +8,9 @@ use crate::nyxd::CosmWasmClient;
use async_trait::async_trait;
use cosmrs::AccountId;
use cosmwasm_std::Addr;
use log::trace;
use nym_coconut_dkg_common::types::{ChunkIndex, NodeIndex, StateAdvanceResponse};
use serde::Deserialize;
use tracing::trace;
use nym_coconut_dkg_common::dealer::RegisteredDealerDetails;
pub use nym_coconut_dkg_common::{
@@ -8,28 +8,33 @@ use crate::nyxd::CosmWasmClient;
use async_trait::async_trait;
use cosmrs::AccountId;
use nym_contracts_common::signing::Nonce;
use nym_mixnet_contract_common::gateway::{PreassignedGatewayIdsResponse, PreassignedId};
use nym_mixnet_contract_common::nym_node::{
EpochAssignmentResponse, NodeDetailsByIdentityResponse, NodeOwnershipResponse,
NodeRewardingDetailsResponse, PagedNymNodeBondsResponse, PagedNymNodeDetailsResponse,
PagedUnbondedNymNodesResponse, Role, RolesMetadataResponse, StakeSaturationResponse,
UnbondedNodeResponse, UnbondedNymNode,
};
use nym_mixnet_contract_common::reward_params::WorkFactor;
use nym_mixnet_contract_common::{
delegation,
delegation::{MixNodeDelegationResponse, OwnerProxySubKey},
families::{Family, FamilyHead},
delegation::{NodeDelegationResponse, OwnerProxySubKey},
mixnode::{
MixnodeRewardingDetailsResponse, PagedMixnodesDetailsResponse,
PagedUnbondedMixnodesResponse, StakeSaturationResponse, UnbondedMixnodeResponse,
MixStakeSaturationResponse, MixnodeRewardingDetailsResponse, PagedMixnodesDetailsResponse,
PagedUnbondedMixnodesResponse, UnbondedMixnodeResponse,
},
reward_params::{Performance, RewardingParams},
rewarding::{EstimatedCurrentEpochRewardResponse, PendingRewardResponse},
ContractBuildInformation, ContractState, ContractStateParams, CurrentIntervalResponse,
Delegation, EpochEventId, EpochStatus, FamilyByHeadResponse, FamilyByLabelResponse,
FamilyMembersByHeadResponse, FamilyMembersByLabelResponse, GatewayBond, GatewayBondResponse,
GatewayOwnershipResponse, IdentityKey, IdentityKeyRef, IntervalEventId, LayerDistribution,
MixId, MixNodeBond, MixNodeDetails, MixOwnershipResponse, MixnodeDetailsByIdentityResponse,
MixnodeDetailsResponse, NumberOfPendingEventsResponse, PagedAllDelegationsResponse,
PagedDelegatorDelegationsResponse, PagedFamiliesResponse, PagedGatewayResponse,
PagedMembersResponse, PagedMixNodeDelegationsResponse, PagedMixnodeBondsResponse,
PagedRewardedSetResponse, PendingEpochEvent, PendingEpochEventResponse,
PendingEpochEventsResponse, PendingIntervalEvent, PendingIntervalEventResponse,
PendingIntervalEventsResponse, QueryMsg as MixnetQueryMsg, RewardedSetNodeStatus,
UnbondedMixnode,
Delegation, EpochEventId, EpochStatus, GatewayBond, GatewayBondResponse,
GatewayOwnershipResponse, IdentityKey, IdentityKeyRef, IntervalEventId, MixNodeBond,
MixNodeDetails, MixOwnershipResponse, MixnodeDetailsByIdentityResponse, MixnodeDetailsResponse,
NodeId, NumberOfPendingEventsResponse, NymNodeBond, NymNodeDetails,
PagedAllDelegationsResponse, PagedDelegatorDelegationsResponse, PagedGatewayResponse,
PagedMixnodeBondsResponse, PagedNodeDelegationsResponse, PendingEpochEvent,
PendingEpochEventResponse, PendingEpochEventsResponse, PendingIntervalEvent,
PendingIntervalEventResponse, PendingIntervalEventsResponse, QueryMsg as MixnetQueryMsg,
RewardedSet, UnbondedMixnode,
};
use serde::Deserialize;
@@ -91,56 +96,11 @@ pub trait MixnetQueryClient {
.await
}
async fn get_rewarded_set_paged(
&self,
start_after: Option<MixId>,
limit: Option<u32>,
) -> Result<PagedRewardedSetResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetRewardedSet { limit, start_after })
.await
}
async fn get_all_node_families_paged(
&self,
start_after: Option<String>,
limit: Option<u32>,
) -> Result<PagedFamiliesResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetAllFamiliesPaged { limit, start_after })
.await
}
async fn get_all_family_members_paged(
&self,
start_after: Option<String>,
limit: Option<u32>,
) -> Result<PagedMembersResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetAllMembersPaged { limit, start_after })
.await
}
async fn get_family_members_by_head<S: Into<String> + Send>(
&self,
head: S,
) -> Result<FamilyMembersByHeadResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetFamilyMembersByHead { head: head.into() })
.await
}
async fn get_family_members_by_label<S: Into<String> + Send>(
&self,
label: S,
) -> Result<FamilyMembersByLabelResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetFamilyMembersByLabel {
label: label.into(),
})
.await
}
// mixnode-related:
async fn get_mixnode_bonds_paged(
&self,
start_after: Option<MixId>,
start_after: Option<NodeId>,
limit: Option<u32>,
) -> Result<PagedMixnodeBondsResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetMixNodeBonds { limit, start_after })
@@ -149,26 +109,26 @@ pub trait MixnetQueryClient {
async fn get_mixnodes_detailed_paged(
&self,
start_after: Option<MixId>,
start_after: Option<NodeId>,
limit: Option<u32>,
) -> Result<PagedMixnodesDetailsResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetMixNodesDetailed { limit, start_after })
.await
}
async fn get_unbonded_paged(
async fn get_unbonded_mixnodes_paged(
&self,
start_after: Option<MixId>,
start_after: Option<NodeId>,
limit: Option<u32>,
) -> Result<PagedUnbondedMixnodesResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetUnbondedMixNodes { limit, start_after })
.await
}
async fn get_unbonded_by_owner_paged(
async fn get_unbonded_mixnodes_by_owner_paged(
&self,
owner: &AccountId,
start_after: Option<MixId>,
start_after: Option<NodeId>,
limit: Option<u32>,
) -> Result<PagedUnbondedMixnodesResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetUnbondedMixNodesByOwner {
@@ -179,10 +139,10 @@ pub trait MixnetQueryClient {
.await
}
async fn get_unbonded_by_identity_paged(
async fn get_unbonded_mixnodes_by_identity_paged(
&self,
identity_key: IdentityKeyRef<'_>,
start_after: Option<MixId>,
start_after: Option<NodeId>,
limit: Option<u32>,
) -> Result<PagedUnbondedMixnodesResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetUnbondedMixNodesByIdentityKey {
@@ -205,7 +165,7 @@ pub trait MixnetQueryClient {
async fn get_mixnode_details(
&self,
mix_id: MixId,
mix_id: NodeId,
) -> Result<MixnodeDetailsResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetMixnodeDetails { mix_id })
.await
@@ -223,7 +183,7 @@ pub trait MixnetQueryClient {
async fn get_mixnode_rewarding_details(
&self,
mix_id: MixId,
mix_id: NodeId,
) -> Result<MixnodeRewardingDetailsResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetMixnodeRewardingDetails { mix_id })
.await
@@ -231,24 +191,24 @@ pub trait MixnetQueryClient {
async fn get_mixnode_stake_saturation(
&self,
mix_id: MixId,
) -> Result<StakeSaturationResponse, NyxdError> {
mix_id: NodeId,
) -> Result<MixStakeSaturationResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetStakeSaturation { mix_id })
.await
}
async fn get_unbonded_mixnode_information(
&self,
mix_id: MixId,
mix_id: NodeId,
) -> Result<UnbondedMixnodeResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetUnbondedMixNodeInformation { mix_id })
.await
}
async fn get_layer_distribution(&self) -> Result<LayerDistribution, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetLayerDistribution {})
.await
}
// async fn get_layer_distribution(&self) -> Result<LayerDistribution, NyxdError> {
// self.query_mixnet_contract(MixnetQueryMsg::GetRoleDistribution {})
// .await
// }
// gateway-related:
@@ -281,17 +241,142 @@ pub trait MixnetQueryClient {
.await
}
async fn get_preassigned_gateway_ids_paged(
&self,
start_after: Option<IdentityKey>,
limit: Option<u32>,
) -> Result<PreassignedGatewayIdsResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetPreassignedGatewayIds { start_after, limit })
.await
}
// nym-nodes related:
async fn get_nymnode_bonds_paged(
&self,
start_after: Option<NodeId>,
limit: Option<u32>,
) -> Result<PagedNymNodeBondsResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetNymNodeBondsPaged { limit, start_after })
.await
}
async fn get_nymnodes_detailed_paged(
&self,
start_after: Option<NodeId>,
limit: Option<u32>,
) -> Result<PagedNymNodeDetailsResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetNymNodesDetailedPaged { limit, start_after })
.await
}
async fn get_unbonded_nymnodes_paged(
&self,
start_after: Option<NodeId>,
limit: Option<u32>,
) -> Result<PagedUnbondedNymNodesResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetUnbondedNymNodesPaged { limit, start_after })
.await
}
async fn get_unbonded_nymnodes_by_owner_paged(
&self,
owner: &AccountId,
start_after: Option<NodeId>,
limit: Option<u32>,
) -> Result<PagedUnbondedNymNodesResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetUnbondedNymNodesByOwnerPaged {
owner: owner.to_string(),
limit,
start_after,
})
.await
}
async fn get_unbonded_nymnodes_by_identity_paged(
&self,
identity_key: IdentityKeyRef<'_>,
start_after: Option<NodeId>,
limit: Option<u32>,
) -> Result<PagedUnbondedNymNodesResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetUnbondedNymNodesByIdentityKeyPaged {
identity_key: identity_key.to_string(),
limit,
start_after,
})
.await
}
async fn get_owned_nymnode(
&self,
address: &AccountId,
) -> Result<NodeOwnershipResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetOwnedNymNode {
address: address.to_string(),
})
.await
}
async fn get_nymnode_details(
&self,
node_id: NodeId,
) -> Result<NodeOwnershipResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetNymNodeDetails { node_id })
.await
}
async fn get_nymnode_details_by_identity(
&self,
node_identity: IdentityKey,
) -> Result<NodeDetailsByIdentityResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetNymNodeDetailsByIdentityKey { node_identity })
.await
}
async fn get_nymnode_rewarding_details(
&self,
node_id: NodeId,
) -> Result<NodeRewardingDetailsResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetNodeRewardingDetails { node_id })
.await
}
async fn get_node_stake_saturation(
&self,
node_id: NodeId,
) -> Result<StakeSaturationResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetNodeStakeSaturation { node_id })
.await
}
async fn get_unbonded_nymnode_information(
&self,
node_id: NodeId,
) -> Result<UnbondedNodeResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetUnbondedNymNode { node_id })
.await
}
async fn get_role_assignment(&self, role: Role) -> Result<EpochAssignmentResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetRoleAssignment { role })
.await
}
async fn get_rewarded_set_metadata(&self) -> Result<RolesMetadataResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetRewardedSetMetadata {})
.await
}
// delegation-related:
/// Gets list of all delegations towards particular mixnode on particular page.
async fn get_mixnode_delegations_paged(
&self,
mix_id: MixId,
node_id: NodeId,
start_after: Option<String>,
limit: Option<u32>,
) -> Result<PagedMixNodeDelegationsResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetMixnodeDelegations {
mix_id,
) -> Result<PagedNodeDelegationsResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetNodeDelegations {
node_id,
start_after,
limit,
})
@@ -302,7 +387,7 @@ pub trait MixnetQueryClient {
async fn get_delegator_delegations_paged(
&self,
delegator: &AccountId,
start_after: Option<(MixId, OwnerProxySubKey)>,
start_after: Option<(NodeId, OwnerProxySubKey)>,
limit: Option<u32>,
) -> Result<PagedDelegatorDelegationsResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetDelegatorDelegations {
@@ -316,12 +401,12 @@ pub trait MixnetQueryClient {
/// Checks value of delegation of given client towards particular mixnode.
async fn get_delegation_details(
&self,
mix_id: MixId,
node_id: NodeId,
delegator: &AccountId,
proxy: Option<String>,
) -> Result<MixNodeDelegationResponse, NyxdError> {
) -> Result<NodeDelegationResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetDelegationDetails {
mix_id,
node_id,
delegator: delegator.to_string(),
proxy,
})
@@ -351,21 +436,21 @@ pub trait MixnetQueryClient {
async fn get_pending_mixnode_operator_reward(
&self,
mix_id: MixId,
node_id: NodeId,
) -> Result<PendingRewardResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetPendingMixNodeOperatorReward { mix_id })
self.query_mixnet_contract(MixnetQueryMsg::GetPendingNodeOperatorReward { node_id })
.await
}
async fn get_pending_delegator_reward(
&self,
delegator: &AccountId,
mix_id: MixId,
node_id: NodeId,
proxy: Option<String>,
) -> Result<PendingRewardResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetPendingDelegatorReward {
address: delegator.to_string(),
mix_id,
node_id,
proxy,
})
.await
@@ -374,12 +459,14 @@ pub trait MixnetQueryClient {
// given the provided performance, estimate the reward at the end of the current epoch
async fn get_estimated_current_epoch_operator_reward(
&self,
mix_id: MixId,
node_id: NodeId,
estimated_performance: Performance,
estimated_work: Option<WorkFactor>,
) -> Result<EstimatedCurrentEpochRewardResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetEstimatedCurrentEpochOperatorReward {
mix_id,
node_id,
estimated_performance,
estimated_work,
})
.await
}
@@ -388,15 +475,15 @@ pub trait MixnetQueryClient {
async fn get_estimated_current_epoch_delegator_reward(
&self,
delegator: &AccountId,
mix_id: MixId,
proxy: Option<String>,
node_id: NodeId,
estimated_performance: Performance,
estimated_work: Option<WorkFactor>,
) -> Result<EstimatedCurrentEpochRewardResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetEstimatedCurrentEpochDelegatorReward {
address: delegator.to_string(),
mix_id,
proxy,
node_id,
estimated_performance,
estimated_work,
})
.await
}
@@ -450,22 +537,6 @@ pub trait MixnetQueryClient {
})
.await
}
async fn get_node_family_by_label(
&self,
label: String,
) -> Result<FamilyByLabelResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetFamilyByLabel { label })
.await
}
async fn get_node_family_by_head(
&self,
head: String,
) -> Result<FamilyByHeadResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetFamilyByHead { head })
.await
}
}
// extension trait to the query client to deal with the paged queries
@@ -473,18 +544,35 @@ pub trait MixnetQueryClient {
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
pub trait PagedMixnetQueryClient: MixnetQueryClient {
async fn get_all_node_families(&self) -> Result<Vec<Family>, NyxdError> {
collect_paged!(self, get_all_node_families_paged, families)
async fn get_all_nymnode_bonds(&self) -> Result<Vec<NymNodeBond>, NyxdError> {
collect_paged!(self, get_nymnode_bonds_paged, nodes)
}
async fn get_all_family_members(&self) -> Result<Vec<(IdentityKey, FamilyHead)>, NyxdError> {
collect_paged!(self, get_all_family_members_paged, members)
async fn get_all_nymnodes_detailed(&self) -> Result<Vec<NymNodeDetails>, NyxdError> {
collect_paged!(self, get_nymnodes_detailed_paged, nodes)
}
async fn get_all_rewarded_set_mixnodes(
async fn get_all_unbonded_nymnodes(&self) -> Result<Vec<UnbondedNymNode>, NyxdError> {
collect_paged!(self, get_unbonded_nymnodes_paged, nodes)
}
async fn get_all_unbonded_nymnodes_by_owner(
&self,
) -> Result<Vec<(MixId, RewardedSetNodeStatus)>, NyxdError> {
collect_paged!(self, get_rewarded_set_paged, nodes)
owner: &AccountId,
) -> Result<Vec<UnbondedNymNode>, NyxdError> {
collect_paged!(self, get_unbonded_nymnodes_by_owner_paged, nodes, owner)
}
async fn get_all_unbonded_nymnodes_by_identity(
&self,
identity_key: IdentityKeyRef<'_>,
) -> Result<Vec<UnbondedNymNode>, NyxdError> {
collect_paged!(
self,
get_unbonded_nymnodes_by_identity_paged,
nodes,
identity_key
)
}
async fn get_all_mixnode_bonds(&self) -> Result<Vec<MixNodeBond>, NyxdError> {
@@ -495,31 +583,40 @@ pub trait PagedMixnetQueryClient: MixnetQueryClient {
collect_paged!(self, get_mixnodes_detailed_paged, nodes)
}
async fn get_all_unbonded_mixnodes(&self) -> Result<Vec<(MixId, UnbondedMixnode)>, NyxdError> {
collect_paged!(self, get_unbonded_paged, nodes)
async fn get_all_unbonded_mixnodes(&self) -> Result<Vec<(NodeId, UnbondedMixnode)>, NyxdError> {
collect_paged!(self, get_unbonded_mixnodes_paged, nodes)
}
async fn get_all_unbonded_mixnodes_by_owner(
&self,
owner: &AccountId,
) -> Result<Vec<(MixId, UnbondedMixnode)>, NyxdError> {
collect_paged!(self, get_unbonded_by_owner_paged, nodes, owner)
) -> Result<Vec<(NodeId, UnbondedMixnode)>, NyxdError> {
collect_paged!(self, get_unbonded_mixnodes_by_owner_paged, nodes, owner)
}
async fn get_all_unbonded_mixnodes_by_identity(
&self,
identity_key: IdentityKeyRef<'_>,
) -> Result<Vec<(MixId, UnbondedMixnode)>, NyxdError> {
collect_paged!(self, get_unbonded_by_identity_paged, nodes, identity_key)
) -> Result<Vec<(NodeId, UnbondedMixnode)>, NyxdError> {
collect_paged!(
self,
get_unbonded_mixnodes_by_identity_paged,
nodes,
identity_key
)
}
async fn get_all_gateways(&self) -> Result<Vec<GatewayBond>, NyxdError> {
collect_paged!(self, get_gateways_paged, nodes)
}
async fn get_all_preassigned_gateway_ids(&self) -> Result<Vec<PreassignedId>, NyxdError> {
collect_paged!(self, get_preassigned_gateway_ids_paged, ids)
}
async fn get_all_single_mixnode_delegations(
&self,
mix_id: MixId,
mix_id: NodeId,
) -> Result<Vec<Delegation>, NyxdError> {
collect_paged!(self, get_mixnode_delegations_paged, delegations, mix_id)
}
@@ -554,6 +651,65 @@ pub trait PagedMixnetQueryClient: MixnetQueryClient {
#[async_trait]
impl<T> PagedMixnetQueryClient for T where T: MixnetQueryClient {}
// extension help to provide extra functionalities based on existing queries:
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
pub trait MixnetQueryClientExt: MixnetQueryClient {
async fn get_rewarded_set(&self) -> Result<RewardedSet, NyxdError> {
let error_response = |message| Err(NyxdError::extension_query_failure("mixnet", message));
let metadata = self.get_rewarded_set_metadata().await?;
if !metadata.metadata.fully_assigned {
return error_response("the rewarded set hasn't been fully assigned for this epoch");
}
let expected_epoch_id = metadata.metadata.epoch_id;
// if we have to query those things more frequently, we could do it concurrently,
// but as it stands now, it happens so infrequently it might as well be sequential
let entry = self.get_role_assignment(Role::EntryGateway).await?;
if entry.epoch_id != expected_epoch_id {
return error_response("the nodes assigned for 'entry' returned unexpected epoch_id");
}
let exit = self.get_role_assignment(Role::ExitGateway).await?;
if exit.epoch_id != expected_epoch_id {
return error_response("the nodes assigned for 'exit' returned unexpected epoch_id");
}
let layer1 = self.get_role_assignment(Role::Layer1).await?;
if layer1.epoch_id != expected_epoch_id {
return error_response("the nodes assigned for 'layer1' returned unexpected epoch_id");
}
let layer2 = self.get_role_assignment(Role::Layer2).await?;
if layer2.epoch_id != expected_epoch_id {
return error_response("the nodes assigned for 'layer2' returned unexpected epoch_id");
}
let layer3 = self.get_role_assignment(Role::Layer3).await?;
if layer3.epoch_id != expected_epoch_id {
return error_response("the nodes assigned for 'layer3' returned unexpected epoch_id");
}
let standby = self.get_role_assignment(Role::Standby).await?;
if standby.epoch_id != expected_epoch_id {
return error_response("the nodes assigned for 'standby' returned unexpected epoch_id");
}
Ok(RewardedSet {
entry_gateways: entry.nodes,
exit_gateways: exit.nodes,
layer1: layer1.nodes,
layer2: layer2.nodes,
layer3: layer3.nodes,
standby: standby.nodes,
})
}
}
#[async_trait]
impl<T> MixnetQueryClientExt for T where T: MixnetQueryClient {}
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
impl<C> MixnetQueryClient for C
@@ -585,24 +741,6 @@ mod tests {
) -> u32 {
match msg {
MixnetQueryMsg::Admin {} => client.admin().ignore(),
MixnetQueryMsg::GetAllFamiliesPaged { limit, start_after } => client
.get_all_family_members_paged(start_after, limit)
.ignore(),
MixnetQueryMsg::GetAllMembersPaged { limit, start_after } => client
.get_all_family_members_paged(start_after, limit)
.ignore(),
MixnetQueryMsg::GetFamilyByHead { head } => {
client.get_node_family_by_head(head).ignore()
}
MixnetQueryMsg::GetFamilyByLabel { label } => {
client.get_node_family_by_label(label).ignore()
}
MixnetQueryMsg::GetFamilyMembersByHead { head } => {
client.get_family_members_by_head(head).ignore()
}
MixnetQueryMsg::GetFamilyMembersByLabel { label } => {
client.get_family_members_by_label(label).ignore()
}
MixnetQueryMsg::GetContractVersion {} => client.get_mixnet_contract_version().ignore(),
MixnetQueryMsg::GetCW2ContractVersion {} => {
client.get_mixnet_contract_cw2_version().ignore()
@@ -617,31 +755,28 @@ mod tests {
MixnetQueryMsg::GetCurrentIntervalDetails {} => {
client.get_current_interval_details().ignore()
}
MixnetQueryMsg::GetRewardedSet { limit, start_after } => {
client.get_rewarded_set_paged(start_after, limit).ignore()
}
MixnetQueryMsg::GetMixNodeBonds { limit, start_after } => {
client.get_mixnode_bonds_paged(start_after, limit).ignore()
}
MixnetQueryMsg::GetMixNodesDetailed { limit, start_after } => client
.get_mixnodes_detailed_paged(start_after, limit)
.ignore(),
MixnetQueryMsg::GetUnbondedMixNodes { limit, start_after } => {
client.get_unbonded_paged(start_after, limit).ignore()
}
MixnetQueryMsg::GetUnbondedMixNodes { limit, start_after } => client
.get_unbonded_mixnodes_paged(start_after, limit)
.ignore(),
MixnetQueryMsg::GetUnbondedMixNodesByOwner {
owner,
limit,
start_after,
} => client
.get_unbonded_by_owner_paged(&owner.parse().unwrap(), start_after, limit)
.get_unbonded_mixnodes_by_owner_paged(&owner.parse().unwrap(), start_after, limit)
.ignore(),
MixnetQueryMsg::GetUnbondedMixNodesByIdentityKey {
identity_key,
limit,
start_after,
} => client
.get_unbonded_by_identity_paged(&identity_key, start_after, limit)
.get_unbonded_mixnodes_by_identity_paged(&identity_key, start_after, limit)
.ignore(),
MixnetQueryMsg::GetOwnedMixnode { address } => {
client.get_owned_mixnode(&address.parse().unwrap()).ignore()
@@ -661,7 +796,6 @@ mod tests {
MixnetQueryMsg::GetBondedMixnodeDetailsByIdentity { mix_identity } => client
.get_mixnode_details_by_identity(mix_identity)
.ignore(),
MixnetQueryMsg::GetLayerDistribution {} => client.get_layer_distribution().ignore(),
MixnetQueryMsg::GetGateways { start_after, limit } => {
client.get_gateways_paged(start_after, limit).ignore()
}
@@ -671,8 +805,8 @@ mod tests {
MixnetQueryMsg::GetOwnedGateway { address } => {
client.get_owned_gateway(&address.parse().unwrap()).ignore()
}
MixnetQueryMsg::GetMixnodeDelegations {
mix_id,
MixnetQueryMsg::GetNodeDelegations {
node_id: mix_id,
start_after,
limit,
} => client
@@ -686,7 +820,7 @@ mod tests {
.get_delegator_delegations_paged(&delegator.parse().unwrap(), start_after, limit)
.ignore(),
MixnetQueryMsg::GetDelegationDetails {
mix_id,
node_id: mix_id,
delegator,
proxy,
} => client
@@ -698,33 +832,38 @@ mod tests {
MixnetQueryMsg::GetPendingOperatorReward { address } => client
.get_pending_operator_reward(&address.parse().unwrap())
.ignore(),
MixnetQueryMsg::GetPendingMixNodeOperatorReward { mix_id } => {
MixnetQueryMsg::GetPendingNodeOperatorReward { node_id: mix_id } => {
client.get_pending_mixnode_operator_reward(mix_id).ignore()
}
MixnetQueryMsg::GetPendingDelegatorReward {
address,
mix_id,
node_id: mix_id,
proxy,
} => client
.get_pending_delegator_reward(&address.parse().unwrap(), mix_id, proxy)
.ignore(),
MixnetQueryMsg::GetEstimatedCurrentEpochOperatorReward {
mix_id,
node_id,
estimated_performance,
estimated_work,
} => client
.get_estimated_current_epoch_operator_reward(mix_id, estimated_performance)
.get_estimated_current_epoch_operator_reward(
node_id,
estimated_performance,
estimated_work,
)
.ignore(),
MixnetQueryMsg::GetEstimatedCurrentEpochDelegatorReward {
address,
mix_id,
proxy,
node_id,
estimated_performance,
estimated_work,
} => client
.get_estimated_current_epoch_delegator_reward(
&address.parse().unwrap(),
mix_id,
proxy,
node_id,
estimated_performance,
estimated_work,
)
.ignore(),
MixnetQueryMsg::GetPendingEpochEvents { limit, start_after } => client
@@ -745,6 +884,54 @@ mod tests {
MixnetQueryMsg::GetSigningNonce { address } => {
client.get_signing_nonce(&address.parse().unwrap()).ignore()
}
MixnetQueryMsg::GetPreassignedGatewayIds { start_after, limit } => client
.get_preassigned_gateway_ids_paged(start_after, limit)
.ignore(),
MixnetQueryMsg::GetNymNodeBondsPaged { limit, start_after } => {
client.get_nymnode_bonds_paged(limit, start_after).ignore()
}
MixnetQueryMsg::GetNymNodesDetailedPaged { limit, start_after } => client
.get_nymnodes_detailed_paged(limit, start_after)
.ignore(),
MixnetQueryMsg::GetUnbondedNymNode { node_id } => {
client.get_unbonded_nymnode_information(node_id).ignore()
}
MixnetQueryMsg::GetUnbondedNymNodesPaged { limit, start_after } => client
.get_unbonded_nymnodes_paged(limit, start_after)
.ignore(),
MixnetQueryMsg::GetUnbondedNymNodesByOwnerPaged {
owner,
limit,
start_after,
} => client
.get_unbonded_nymnodes_by_owner_paged(&owner.parse().unwrap(), limit, start_after)
.ignore(),
MixnetQueryMsg::GetUnbondedNymNodesByIdentityKeyPaged {
identity_key,
limit,
start_after,
} => client
.get_unbonded_nymnodes_by_identity_paged(&identity_key, limit, start_after)
.ignore(),
MixnetQueryMsg::GetOwnedNymNode { address } => {
client.get_owned_nymnode(&address.parse().unwrap()).ignore()
}
MixnetQueryMsg::GetNymNodeDetails { node_id } => {
client.get_nymnode_details(node_id).ignore()
}
MixnetQueryMsg::GetNymNodeDetailsByIdentityKey { node_identity } => client
.get_nymnode_details_by_identity(node_identity)
.ignore(),
MixnetQueryMsg::GetNodeRewardingDetails { node_id } => {
client.get_nymnode_rewarding_details(node_id).ignore()
}
MixnetQueryMsg::GetNodeStakeSaturation { node_id } => {
client.get_node_stake_saturation(node_id).ignore()
}
MixnetQueryMsg::GetRoleAssignment { role } => client.get_role_assignment(role).ignore(),
MixnetQueryMsg::GetRewardedSetMetadata {} => {
client.get_rewarded_set_metadata().ignore()
}
}
}
}
@@ -10,13 +10,15 @@ use crate::signing::signer::OfflineSigner;
use async_trait::async_trait;
use cosmrs::AccountId;
use nym_contracts_common::signing::MessageSignature;
use nym_mixnet_contract_common::families::FamilyHead;
use nym_mixnet_contract_common::gateway::GatewayConfigUpdate;
use nym_mixnet_contract_common::mixnode::{MixNodeConfigUpdate, MixNodeCostParams};
use nym_mixnet_contract_common::reward_params::{IntervalRewardingParamsUpdate, Performance};
use nym_mixnet_contract_common::mixnode::{MixNodeConfigUpdate, NodeCostParams};
use nym_mixnet_contract_common::nym_node::NodeConfigUpdate;
use nym_mixnet_contract_common::reward_params::{
ActiveSetUpdate, IntervalRewardingParamsUpdate, NodeRewardingParameters,
};
use nym_mixnet_contract_common::{
ContractStateParams, ExecuteMsg as MixnetExecuteMsg, Gateway, Layer, LayerAssignment, MixId,
MixNode,
ContractStateParams, ExecuteMsg as MixnetExecuteMsg, Gateway, MixNode, NodeId, NymNode,
RoleAssignment,
};
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
@@ -70,14 +72,14 @@ pub trait MixnetSigningClient {
async fn update_active_set_size(
&self,
active_set_size: u32,
update: ActiveSetUpdate,
force_immediately: bool,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract(
fee,
MixnetExecuteMsg::UpdateActiveSetSize {
active_set_size,
MixnetExecuteMsg::UpdateActiveSetDistribution {
update,
force_immediately,
},
vec![],
@@ -126,37 +128,6 @@ pub trait MixnetSigningClient {
.await
}
async fn advance_current_epoch(
&self,
new_rewarded_set: Vec<LayerAssignment>,
expected_active_set_size: u32,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract(
fee,
MixnetExecuteMsg::AdvanceCurrentEpoch {
new_rewarded_set,
expected_active_set_size,
},
vec![],
)
.await
}
async fn assign_node_layer(
&self,
mix_id: MixId,
layer: Layer,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract(
fee,
MixnetExecuteMsg::AssignNodeLayer { mix_id, layer },
vec![],
)
.await
}
async fn reconcile_epoch_events(
&self,
limit: Option<u32>,
@@ -170,126 +141,21 @@ pub trait MixnetSigningClient {
.await
}
// family related
async fn create_family(
async fn assign_roles(
&self,
label: String,
assignment: RoleAssignment,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract(fee, MixnetExecuteMsg::CreateFamily { label }, vec![])
self.execute_mixnet_contract(fee, MixnetExecuteMsg::AssignRoles { assignment }, vec![])
.await
}
async fn create_family_on_behalf(
&self,
owner_address: String,
label: String,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract(
fee,
MixnetExecuteMsg::CreateFamilyOnBehalf {
owner_address,
label,
},
vec![],
)
.await
}
async fn join_family(
&self,
join_permit: MessageSignature,
family_head: FamilyHead,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract(
fee,
MixnetExecuteMsg::JoinFamily {
join_permit,
family_head,
},
vec![],
)
.await
}
async fn join_family_on_behalf(
&self,
member_address: String,
join_permit: MessageSignature,
family_head: FamilyHead,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract(
fee,
MixnetExecuteMsg::JoinFamilyOnBehalf {
member_address,
join_permit,
family_head,
},
vec![],
)
.await
}
async fn leave_family(
&self,
family_head: FamilyHead,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract(fee, MixnetExecuteMsg::LeaveFamily { family_head }, vec![])
.await
}
async fn leave_family_on_behalf(
&self,
member_address: String,
family_head: FamilyHead,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract(
fee,
MixnetExecuteMsg::LeaveFamilyOnBehalf {
member_address,
family_head,
},
vec![],
)
.await
}
async fn kick_family_member(
&self,
member: String,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract(fee, MixnetExecuteMsg::KickFamilyMember { member }, vec![])
.await
}
async fn kick_family_member_on_behalf(
&self,
head_address: String,
member: String,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract(
fee,
MixnetExecuteMsg::KickFamilyMemberOnBehalf {
head_address,
member,
},
vec![],
)
.await
}
// mixnode-related:
async fn bond_mixnode(
&self,
mix_node: MixNode,
cost_params: MixNodeCostParams,
cost_params: NodeCostParams,
owner_signature: MessageSignature,
pledge: Coin,
fee: Option<Fee>,
@@ -310,7 +176,7 @@ pub trait MixnetSigningClient {
&self,
owner: AccountId,
mix_node: MixNode,
cost_params: MixNodeCostParams,
cost_params: NodeCostParams,
owner_signature: MessageSignature,
pledge: Coin,
fee: Option<Fee>,
@@ -409,14 +275,14 @@ pub trait MixnetSigningClient {
.await
}
async fn update_mixnode_cost_params(
async fn update_cost_params(
&self,
new_costs: MixNodeCostParams,
new_costs: NodeCostParams,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract(
fee,
MixnetExecuteMsg::UpdateMixnodeCostParams { new_costs },
MixnetExecuteMsg::UpdateCostParams { new_costs },
vec![],
)
.await
@@ -425,7 +291,7 @@ pub trait MixnetSigningClient {
async fn update_mixnode_cost_params_on_behalf(
&self,
owner: AccountId,
new_costs: MixNodeCostParams,
new_costs: NodeCostParams,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract(
@@ -559,26 +425,75 @@ pub trait MixnetSigningClient {
.await
}
// delegation-related:
// nym-node related:
async fn migrate_legacy_mixnode(&self, fee: Option<Fee>) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract(fee, MixnetExecuteMsg::MigrateMixnode {}, vec![])
.await
}
async fn delegate_to_mixnode(
async fn migrate_legacy_gateway(
&self,
mix_id: MixId,
amount: Coin,
cost_params: Option<NodeCostParams>,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract(
fee,
MixnetExecuteMsg::DelegateToMixnode { mix_id },
vec![amount],
MixnetExecuteMsg::MigrateGateway { cost_params },
vec![],
)
.await
}
async fn bond_nymnode(
&self,
node: NymNode,
cost_params: NodeCostParams,
owner_signature: MessageSignature,
pledge: Coin,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract(
fee,
MixnetExecuteMsg::BondNymNode {
node,
cost_params,
owner_signature,
},
vec![pledge],
)
.await
}
async fn unbond_nymnode(&self, fee: Option<Fee>) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract(fee, MixnetExecuteMsg::UnbondNymNode {}, vec![])
.await
}
async fn update_nymnode_config(
&self,
update: NodeConfigUpdate,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract(fee, MixnetExecuteMsg::UpdateNodeConfig { update }, vec![])
.await
}
// delegation-related:
async fn delegate(
&self,
node_id: NodeId,
amount: Coin,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract(fee, MixnetExecuteMsg::Delegate { node_id }, vec![amount])
.await
}
async fn delegate_to_mixnode_on_behalf(
&self,
delegate: AccountId,
mix_id: MixId,
mix_id: NodeId,
amount: Coin,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
@@ -593,23 +508,19 @@ pub trait MixnetSigningClient {
.await
}
async fn undelegate_from_mixnode(
async fn undelegate(
&self,
mix_id: MixId,
node_id: NodeId,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract(
fee,
MixnetExecuteMsg::UndelegateFromMixnode { mix_id },
vec![],
)
.await
self.execute_mixnet_contract(fee, MixnetExecuteMsg::Undelegate { node_id }, vec![])
.await
}
async fn undelegate_to_mixnode_on_behalf(
&self,
delegate: AccountId,
mix_id: MixId,
mix_id: NodeId,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract(
@@ -625,18 +536,15 @@ pub trait MixnetSigningClient {
// reward-related
async fn reward_mixnode(
async fn reward_node(
&self,
mix_id: MixId,
performance: Performance,
node_id: NodeId,
params: NodeRewardingParameters,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract(
fee,
MixnetExecuteMsg::RewardMixnode {
mix_id,
performance,
},
MixnetExecuteMsg::RewardNode { node_id, params },
vec![],
)
.await
@@ -664,12 +572,12 @@ pub trait MixnetSigningClient {
async fn withdraw_delegator_reward(
&self,
mix_id: MixId,
node_id: NodeId,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract(
fee,
MixnetExecuteMsg::WithdrawDelegatorReward { mix_id },
MixnetExecuteMsg::WithdrawDelegatorReward { node_id },
vec![],
)
.await
@@ -678,7 +586,7 @@ pub trait MixnetSigningClient {
async fn withdraw_delegator_reward_on_behalf(
&self,
owner: AccountId,
mix_id: MixId,
mix_id: NodeId,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract(
@@ -699,7 +607,7 @@ pub trait MixnetSigningClient {
async fn migrate_vested_delegation(
&self,
mix_id: MixId,
mix_id: NodeId,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract(
@@ -761,6 +669,7 @@ where
mod tests {
use super::*;
use crate::nyxd::contract_traits::tests::{mock_coin, IgnoreValue};
use nym_mixnet_contract_common::ExecuteMsg;
// it's enough that this compiles and clippy is happy about it
#[allow(dead_code)]
@@ -770,56 +679,17 @@ mod tests {
) {
match msg {
MixnetExecuteMsg::UpdateAdmin { admin } => client.update_admin(admin, None).ignore(),
MixnetExecuteMsg::AssignNodeLayer { mix_id, layer } => {
client.assign_node_layer(mix_id, layer, None).ignore()
}
MixnetExecuteMsg::CreateFamily { label } => client.create_family(label, None).ignore(),
MixnetExecuteMsg::JoinFamily {
join_permit,
family_head,
} => client.join_family(join_permit, family_head, None).ignore(),
MixnetExecuteMsg::LeaveFamily { family_head } => {
client.leave_family(family_head, None).ignore()
}
MixnetExecuteMsg::KickFamilyMember { member } => {
client.kick_family_member(member, None).ignore()
}
MixnetExecuteMsg::CreateFamilyOnBehalf {
owner_address,
label,
} => client
.create_family_on_behalf(owner_address, label, None)
.ignore(),
MixnetExecuteMsg::JoinFamilyOnBehalf {
member_address,
join_permit,
family_head,
} => client
.join_family_on_behalf(member_address, join_permit, family_head, None)
.ignore(),
MixnetExecuteMsg::LeaveFamilyOnBehalf {
member_address,
family_head,
} => client
.leave_family_on_behalf(member_address, family_head, None)
.ignore(),
MixnetExecuteMsg::KickFamilyMemberOnBehalf {
head_address,
member,
} => client
.kick_family_member_on_behalf(head_address, member, None)
.ignore(),
MixnetExecuteMsg::UpdateRewardingValidatorAddress { address } => client
.update_rewarding_validator_address(address.parse().unwrap(), None)
.ignore(),
MixnetExecuteMsg::UpdateContractStateParams { updated_parameters } => client
.update_contract_state_params(updated_parameters, None)
.ignore(),
MixnetExecuteMsg::UpdateActiveSetSize {
active_set_size,
MixnetExecuteMsg::UpdateActiveSetDistribution {
update,
force_immediately,
} => client
.update_active_set_size(active_set_size, force_immediately, None)
.update_active_set_size(update, force_immediately, None)
.ignore(),
MixnetExecuteMsg::UpdateRewardingParams {
updated_params,
@@ -842,12 +712,6 @@ mod tests {
MixnetExecuteMsg::BeginEpochTransition {} => {
client.begin_epoch_transition(None).ignore()
}
MixnetExecuteMsg::AdvanceCurrentEpoch {
new_rewarded_set,
expected_active_set_size,
} => client
.advance_current_epoch(new_rewarded_set, expected_active_set_size, None)
.ignore(),
MixnetExecuteMsg::ReconcileEpochEvents { limit } => {
client.reconcile_epoch_events(limit, None).ignore()
}
@@ -887,8 +751,8 @@ mod tests {
MixnetExecuteMsg::UnbondMixnodeOnBehalf { owner } => client
.unbond_mixnode_on_behalf(owner.parse().unwrap(), None)
.ignore(),
MixnetExecuteMsg::UpdateMixnodeCostParams { new_costs } => {
client.update_mixnode_cost_params(new_costs, None).ignore()
MixnetExecuteMsg::UpdateCostParams { new_costs } => {
client.update_cost_params(new_costs, None).ignore()
}
MixnetExecuteMsg::UpdateMixnodeCostParamsOnBehalf { new_costs, owner } => client
.update_mixnode_cost_params_on_behalf(owner.parse().unwrap(), new_costs, None)
@@ -928,29 +792,28 @@ mod tests {
MixnetExecuteMsg::UpdateGatewayConfigOnBehalf { new_config, owner } => client
.update_gateway_config_on_behalf(owner.parse().unwrap(), new_config, None)
.ignore(),
MixnetExecuteMsg::DelegateToMixnode { mix_id } => client
.delegate_to_mixnode(mix_id, mock_coin(), None)
.ignore(),
MixnetExecuteMsg::Delegate { node_id: mix_id } => {
client.delegate(mix_id, mock_coin(), None).ignore()
}
MixnetExecuteMsg::DelegateToMixnodeOnBehalf { mix_id, delegate } => client
.delegate_to_mixnode_on_behalf(delegate.parse().unwrap(), mix_id, mock_coin(), None)
.ignore(),
MixnetExecuteMsg::UndelegateFromMixnode { mix_id } => {
client.undelegate_from_mixnode(mix_id, None).ignore()
MixnetExecuteMsg::Undelegate { node_id: mix_id } => {
client.undelegate(mix_id, None).ignore()
}
MixnetExecuteMsg::UndelegateFromMixnodeOnBehalf { mix_id, delegate } => client
.undelegate_to_mixnode_on_behalf(delegate.parse().unwrap(), mix_id, None)
.ignore(),
MixnetExecuteMsg::RewardMixnode {
mix_id,
performance,
} => client.reward_mixnode(mix_id, performance, None).ignore(),
MixnetExecuteMsg::RewardNode { node_id, params } => {
client.reward_node(node_id, params, None).ignore()
}
MixnetExecuteMsg::WithdrawOperatorReward {} => {
client.withdraw_operator_reward(None).ignore()
}
MixnetExecuteMsg::WithdrawOperatorRewardOnBehalf { owner } => client
.withdraw_operator_reward_on_behalf(owner.parse().unwrap(), None)
.ignore(),
MixnetExecuteMsg::WithdrawDelegatorReward { mix_id } => {
MixnetExecuteMsg::WithdrawDelegatorReward { node_id: mix_id } => {
client.withdraw_delegator_reward(mix_id, None).ignore()
}
MixnetExecuteMsg::WithdrawDelegatorRewardOnBehalf { mix_id, owner } => client
@@ -963,6 +826,25 @@ mod tests {
client.migrate_vested_delegation(mix_id, None).ignore()
}
ExecuteMsg::AssignRoles { assignment } => {
client.assign_roles(assignment, None).ignore()
}
ExecuteMsg::MigrateMixnode {} => client.migrate_legacy_mixnode(None).ignore(),
ExecuteMsg::MigrateGateway { cost_params } => {
client.migrate_legacy_gateway(cost_params, None).ignore()
}
ExecuteMsg::BondNymNode {
node,
cost_params,
owner_signature,
} => client
.bond_nymnode(node, cost_params, owner_signature, mock_coin(), None)
.ignore(),
ExecuteMsg::UnbondNymNode {} => client.unbond_nymnode(None).ignore(),
ExecuteMsg::UpdateNodeConfig { update } => {
client.update_nymnode_config(update, None).ignore()
}
#[cfg(feature = "contract-testing")]
MixnetExecuteMsg::TestingResolveAllPendingEvents { .. } => {
client.testing_resolve_all_pending_events(None).ignore()
@@ -9,7 +9,7 @@ use crate::nyxd::CosmWasmClient;
use async_trait::async_trait;
use cosmwasm_std::{Coin as CosmWasmCoin, Timestamp};
use nym_contracts_common::ContractBuildInformation;
use nym_mixnet_contract_common::MixId;
use nym_mixnet_contract_common::NodeId;
use nym_vesting_contract_common::{
messages::QueryMsg as VestingQueryMsg, Account, AccountVestingCoins, AccountsResponse,
AllDelegationsResponse, BaseVestingAccountInfo, DelegationTimesResponse,
@@ -238,7 +238,7 @@ pub trait VestingQueryClient {
async fn get_vesting_delegation(
&self,
address: &str,
mix_id: MixId,
mix_id: NodeId,
block_timestamp_secs: u64,
) -> Result<VestingDelegation, NyxdError> {
self.query_vesting_contract(VestingQueryMsg::GetDelegation {
@@ -252,7 +252,7 @@ pub trait VestingQueryClient {
async fn get_total_delegation_amount(
&self,
address: &str,
mix_id: MixId,
mix_id: NodeId,
) -> Result<Coin, NyxdError> {
self.query_vesting_contract(VestingQueryMsg::GetTotalDelegationAmount {
address: address.to_string(),
@@ -264,7 +264,7 @@ pub trait VestingQueryClient {
async fn get_delegation_timestamps(
&self,
address: &str,
mix_id: MixId,
mix_id: NodeId,
) -> Result<DelegationTimesResponse, NyxdError> {
self.query_vesting_contract(VestingQueryMsg::GetDelegationTimes {
address: address.to_string(),
@@ -275,7 +275,7 @@ pub trait VestingQueryClient {
async fn get_all_vesting_delegations_paged(
&self,
start_after: Option<(u32, MixId, u64)>,
start_after: Option<(u32, NodeId, u64)>,
limit: Option<u32>,
) -> Result<AllDelegationsResponse, NyxdError> {
self.query_vesting_contract(VestingQueryMsg::GetAllDelegations { start_after, limit })
@@ -9,10 +9,9 @@ use crate::signing::signer::OfflineSigner;
use async_trait::async_trait;
use cosmrs::AccountId;
use nym_contracts_common::signing::MessageSignature;
use nym_mixnet_contract_common::families::FamilyHead;
use nym_mixnet_contract_common::gateway::GatewayConfigUpdate;
use nym_mixnet_contract_common::mixnode::{MixNodeConfigUpdate, MixNodeCostParams};
use nym_mixnet_contract_common::{Gateway, MixId, MixNode};
use nym_mixnet_contract_common::mixnode::{MixNodeConfigUpdate, NodeCostParams};
use nym_mixnet_contract_common::{Gateway, MixNode, NodeId};
use nym_vesting_contract_common::messages::ExecuteMsg as VestingExecuteMsg;
use nym_vesting_contract_common::{PledgeCap, VestingSpecification};
@@ -28,7 +27,7 @@ pub trait VestingSigningClient {
async fn vesting_update_mixnode_cost_params(
&self,
new_costs: MixNodeCostParams,
new_costs: NodeCostParams,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_vesting_contract(
@@ -124,7 +123,7 @@ pub trait VestingSigningClient {
async fn vesting_bond_mixnode(
&self,
mix_node: MixNode,
cost_params: MixNodeCostParams,
cost_params: NodeCostParams,
owner_signature: MessageSignature,
pledge: Coin,
fee: Option<Fee>,
@@ -204,7 +203,7 @@ pub trait VestingSigningClient {
async fn vesting_track_undelegation(
&self,
address: &str,
mix_id: MixId,
mix_id: NodeId,
amount: Coin,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
@@ -222,7 +221,7 @@ pub trait VestingSigningClient {
async fn vesting_delegate_to_mixnode(
&self,
mix_id: MixId,
mix_id: NodeId,
amount: Coin,
on_behalf_of: Option<String>,
fee: Option<Fee>,
@@ -241,7 +240,7 @@ pub trait VestingSigningClient {
async fn vesting_undelegate_from_mixnode(
&self,
mix_id: MixId,
mix_id: NodeId,
on_behalf_of: Option<String>,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
@@ -301,7 +300,7 @@ pub trait VestingSigningClient {
async fn vesting_withdraw_delegator_reward(
&self,
mix_id: MixId,
mix_id: NodeId,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_vesting_contract(
@@ -354,50 +353,6 @@ pub trait VestingSigningClient {
)
.await
}
async fn vesting_create_family(
&self,
label: String,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_vesting_contract(fee, VestingExecuteMsg::CreateFamily { label }, vec![])
.await
}
async fn vesting_join_family(
&self,
join_permit: MessageSignature,
family_head: FamilyHead,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_vesting_contract(
fee,
VestingExecuteMsg::JoinFamily {
join_permit,
family_head,
},
vec![],
)
.await
}
async fn vesting_leave_family(
&self,
family_head: FamilyHead,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_vesting_contract(fee, VestingExecuteMsg::LeaveFamily { family_head }, vec![])
.await
}
async fn vesting_kick_family_member(
&self,
member: String,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_vesting_contract(fee, VestingExecuteMsg::KickFamilyMember { member }, vec![])
.await
}
}
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
@@ -446,21 +401,6 @@ mod tests {
msg: VestingExecuteMsg,
) {
match msg {
VestingExecuteMsg::CreateFamily { label } => {
client.vesting_create_family(label, None).ignore()
}
VestingExecuteMsg::JoinFamily {
join_permit,
family_head,
} => client
.vesting_join_family(join_permit, family_head, None)
.ignore(),
VestingExecuteMsg::LeaveFamily { family_head } => {
client.vesting_leave_family(family_head, None).ignore()
}
VestingExecuteMsg::KickFamilyMember { member } => {
client.vesting_kick_family_member(member, None).ignore()
}
VestingExecuteMsg::TrackReward { amount, address } => client
.vesting_track_reward(amount.into(), address, None)
.ignore(),
@@ -29,7 +29,6 @@ use cosmrs::proto::cosmwasm::wasm::v1::{
};
use cosmrs::tendermint::{block, chain, Hash};
use cosmrs::{AccountId, Coin as CosmosCoin, Tx};
use log::trace;
use prost::Message;
use serde::{Deserialize, Serialize};
@@ -68,7 +67,7 @@ pub trait CosmWasmClient: TendermintRpcClient {
Res: Message + Default,
{
if let Some(ref abci_path) = path {
trace!("performing query on abci path {abci_path}")
tracing::trace!("performing query on abci path {abci_path}")
}
let mut buf = Vec::with_capacity(req.encoded_len());
req.encode(&mut buf)?;
@@ -297,7 +296,7 @@ pub trait CosmWasmClient: TendermintRpcClient {
let start = Instant::now();
loop {
log::debug!(
tracing::debug!(
"Polling for result of including {} in a block...",
broadcasted.hash
);
@@ -522,7 +521,7 @@ pub trait CosmWasmClient: TendermintRpcClient {
.make_abci_query::<_, QuerySmartContractStateResponse>(path, req)
.await?;
trace!("raw query response: {}", String::from_utf8_lossy(&res.data));
tracing::trace!("raw query response: {}", String::from_utf8_lossy(&res.data));
Ok(serde_json::from_slice(&res.data)?)
}
@@ -25,12 +25,12 @@ use cosmrs::proto::cosmos::tx::signing::v1beta1::SignMode;
use cosmrs::staking::{MsgDelegate, MsgUndelegate};
use cosmrs::tx::{self, Msg};
use cosmrs::{cosmwasm, AccountId, Any, Tx};
use log::debug;
use serde::Serialize;
use sha2::Digest;
use sha2::Sha256;
use std::time::SystemTime;
use tendermint_rpc::endpoint::broadcast;
use tracing::debug;
fn empty_fee() -> tx::Fee {
tx::Fee {
@@ -7,9 +7,9 @@ use base64::Engine;
use cosmrs::abci::TxMsgData;
use cosmrs::cosmwasm::MsgExecuteContractResponse;
use cosmrs::proto::cosmos::base::query::v1beta1::{PageRequest, PageResponse};
use log::error;
use prost::bytes::Bytes;
use tendermint_rpc::endpoint::broadcast;
use tracing::error;
pub use cosmrs::abci::MsgResponse;
@@ -154,6 +154,23 @@ pub enum NyxdError {
#[error("the response data has invalid size. got {got} bytes, but expected {expected} bytes instead")]
MalformedResponseData { got: usize, expected: usize },
#[error(
"one of the extension query for {contract} failed with the following message: {message}"
)]
ExtensionQueryFailure { contract: String, message: String },
}
impl NyxdError {
pub fn extension_query_failure(
contract: impl Into<String>,
message: impl Into<String>,
) -> Self {
NyxdError::ExtensionQueryFailure {
contract: contract.into(),
message: message.into(),
}
}
}
// The purpose of parsing the abci query result is that we want to generate the `pretty_log` if
@@ -4,6 +4,7 @@
use clap::Parser;
use cosmwasm_std::Decimal;
use log::{debug, info};
use nym_mixnet_contract_common::reward_params::RewardedSetParams;
use nym_mixnet_contract_common::{
InitialRewardingParams, InstantiateMsg, OperatingCostRange, Percent, ProfitMarginRange,
};
@@ -56,11 +57,17 @@ pub struct Args {
#[clap(long, default_value_t = 2)]
pub interval_pool_emission: u64,
#[clap(long, default_value_t = 240)]
pub rewarded_set_size: u32,
#[clap(long, default_value_t = 50)]
pub(crate) entry_gateways: u32,
#[clap(long, default_value_t = 240)]
pub active_set_size: u32,
#[clap(long, default_value_t = 70)]
pub(crate) exit_gateways: u32,
#[clap(long, default_value_t = 120)]
pub(crate) mixnodes: u32,
#[clap(long, default_value_t = 0)]
pub(crate) standby: u32,
#[clap(long, default_value_t = Percent::zero())]
pub minimum_profit_margin_percent: Percent,
@@ -95,8 +102,13 @@ pub async fn generate(args: Args) {
.expect("active_set_work_factor can't be converted to Decimal"),
interval_pool_emission: Percent::from_percentage_value(args.interval_pool_emission)
.expect("interval_pool_emission can't be converted to Percent"),
rewarded_set_size: args.rewarded_set_size,
active_set_size: args.active_set_size,
rewarded_set_params: RewardedSetParams {
entry_gateways: args.entry_gateways,
exit_gateways: args.exit_gateways,
mixnodes: args.mixnodes,
standby: args.standby,
},
};
debug!("initial_rewarding_params: {:?}", initial_rewarding_params);
@@ -4,13 +4,13 @@
use crate::context::SigningClient;
use clap::Parser;
use log::info;
use nym_mixnet_contract_common::{Coin, MixId};
use nym_mixnet_contract_common::{Coin, NodeId};
use nym_validator_client::nyxd::contract_traits::{MixnetQueryClient, MixnetSigningClient};
#[derive(Debug, Parser)]
pub struct Args {
#[clap(long)]
pub mix_id: Option<MixId>,
pub mix_id: Option<NodeId>,
#[clap(long)]
pub identity_key: Option<String>,
@@ -43,7 +43,7 @@ pub async fn delegate_to_mixnode(args: Args, client: SigningClient) {
let coin = Coin::new(args.amount, denom);
let res = client
.delegate_to_mixnode(mix_id, coin.into(), None)
.delegate(mix_id, coin.into(), None)
.await
.expect("failed to delegate to mixnode!");
@@ -1,21 +1,18 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use std::cmp::Ordering;
use std::collections::{HashMap, HashSet};
use std::fs;
use std::fs::OpenOptions;
use clap::Parser;
use comfy_table::Table;
use csv::WriterBuilder;
use log::info;
use nym_mixnet_contract_common::ExecuteMsg;
use nym_mixnet_contract_common::ExecuteMsg::{DelegateToMixnode, UndelegateFromMixnode};
use nym_mixnet_contract_common::PendingEpochEventKind::{Delegate, Undelegate};
use nym_mixnet_contract_common::PendingEpochEventKind;
use nym_validator_client::nyxd::contract_traits::{NymContractsProvider, PagedMixnetQueryClient};
use nym_validator_client::nyxd::Coin;
use std::cmp::Ordering;
use std::collections::{HashMap, HashSet};
use std::fs;
use std::fs::OpenOptions;
use crate::context::SigningClient;
use crate::utils::pretty_coin;
@@ -40,7 +37,7 @@ pub struct Args {
#[derive(Debug)]
pub struct InputFileRow {
pub mix_id: String,
pub node_id: String,
pub amount: Coin,
}
#[derive(Debug)]
@@ -76,7 +73,7 @@ impl InputFileReader {
}
rows.push(InputFileRow {
mix_id,
node_id: mix_id,
amount: Coin {
amount: micro_nym_amount,
denom: "unym".to_string(),
@@ -140,8 +137,10 @@ async fn fetch_delegation_data(
let mut pending_delegation_map: HashMap<String, Coin> = HashMap::new();
for delegation in delegations {
existing_delegation_map
.insert(delegation.mix_id.to_string(), Coin::from(delegation.amount));
existing_delegation_map.insert(
delegation.node_id.to_string(),
Coin::from(delegation.amount),
);
}
// Look for pending delegate / undelegate events which might be of interest to us
@@ -155,27 +154,27 @@ async fn fetch_delegation_data(
for event in pending_events {
match event.event.kind {
// If a pending undelegate tx is found, remove it from delegation map
Undelegate { owner, mix_id, .. } => {
PendingEpochEventKind::Undelegate { owner, node_id, .. } => {
if owner == address.as_ref()
&& existing_delegation_map.contains_key(&mix_id.to_string())
&& existing_delegation_map.contains_key(&node_id.to_string())
{
existing_delegation_map.remove(&mix_id.to_string());
existing_delegation_map.remove(&node_id.to_string());
}
}
// If a pending delegation event is found, gather them to consolidate later
Delegate {
PendingEpochEventKind::Delegate {
owner,
mix_id,
node_id,
amount,
..
} => {
if owner == address.as_ref() {
let mut amount = Coin::from(amount);
if let Some(pending_record) = pending_delegation_map.get(&mix_id.to_string()) {
if let Some(pending_record) = pending_delegation_map.get(&node_id.to_string()) {
amount.amount += pending_record.amount;
}
pending_delegation_map.insert(mix_id.to_string(), amount);
pending_delegation_map.insert(node_id.to_string(), amount);
}
}
_ => {}
@@ -217,7 +216,7 @@ pub async fn delegate_to_multiple_mixnodes(args: Args, client: SigningClient) {
for row in &records.rows {
let input_amount = row.amount.amount;
let existing_delegation_amount = existing_delegation_map
.get(&row.mix_id)
.get(&row.node_id)
.map_or(0, |coin| coin.amount);
match existing_delegation_amount.cmp(&input_amount) {
@@ -229,25 +228,26 @@ pub async fn delegate_to_multiple_mixnodes(args: Args, client: SigningClient) {
amount: input_amount - existing_delegation_amount,
denom: row.amount.denom.clone(),
};
let mix_id = row.mix_id.clone().parse::<u32>().unwrap();
delegation_msgs.push((DelegateToMixnode { mix_id }, vec![difference.clone()]));
let node_id = row.node_id.clone().parse::<u32>().unwrap();
delegation_msgs.push((ExecuteMsg::Delegate { node_id }, vec![difference.clone()]));
delegation_table.add_row(&[
row.mix_id.clone(),
row.node_id.clone(),
pretty_coin(&row.amount),
pretty_coin(&difference),
]);
}
Ordering::Greater => {
let mix_id = row.mix_id.clone().parse::<u32>().unwrap();
let node_id = row.node_id.clone().parse::<u32>().unwrap();
let coins: Vec<Coin> = vec![];
undelegation_msgs.push((UndelegateFromMixnode { mix_id }, coins));
undelegation_table.add_row(&[row.mix_id.clone()]);
undelegation_msgs.push((ExecuteMsg::Undelegate { node_id }, coins));
undelegation_table.add_row(&[row.node_id.clone()]);
if row.amount.amount > 0 {
delegation_msgs.push((DelegateToMixnode { mix_id }, vec![row.amount.clone()]));
delegation_msgs
.push((ExecuteMsg::Delegate { node_id }, vec![row.amount.clone()]));
delegation_table.add_row(&[
row.mix_id.clone(),
row.node_id.clone(),
pretty_coin(&row.amount),
pretty_coin(&row.amount),
]);
@@ -4,13 +4,13 @@
use crate::context::SigningClient;
use clap::Parser;
use log::info;
use nym_mixnet_contract_common::MixId;
use nym_mixnet_contract_common::NodeId;
use nym_validator_client::nyxd::contract_traits::{MixnetQueryClient, MixnetSigningClient};
#[derive(Debug, Parser)]
pub struct Args {
#[clap(long)]
pub mix_id: Option<MixId>,
pub mix_id: Option<NodeId>,
#[clap(long)]
pub identity_key: Option<String>,
@@ -66,7 +66,7 @@ async fn print_delegations(delegations: Vec<Delegation>, client: &SigningClientW
for delegation in delegations {
table.add_row(vec![
to_iso_timestamp(delegation.height as u32, client).await,
delegation.mix_id.to_string(),
delegation.node_id.to_string(),
pretty_cosmwasm_coin(&delegation.amount),
delegation
.proxy
@@ -93,7 +93,7 @@ async fn print_delegation_events(events: Vec<PendingEpochEvent>, client: &Signin
match event.event.kind {
PendingEpochEventKind::Delegate {
owner,
mix_id,
node_id: mix_id,
amount,
proxy,
..
@@ -110,7 +110,7 @@ async fn print_delegation_events(events: Vec<PendingEpochEvent>, client: &Signin
}
PendingEpochEventKind::Undelegate {
owner,
mix_id,
node_id: mix_id,
proxy,
..
} => {
@@ -4,13 +4,13 @@
use crate::context::SigningClient;
use clap::Parser;
use log::info;
use nym_mixnet_contract_common::MixId;
use nym_mixnet_contract_common::NodeId;
use nym_validator_client::nyxd::contract_traits::{MixnetQueryClient, MixnetSigningClient};
#[derive(Debug, Parser)]
pub struct Args {
#[clap(long)]
pub mix_id: Option<MixId>,
pub mix_id: Option<NodeId>,
#[clap(long)]
pub identity_key: Option<String>,
@@ -4,13 +4,13 @@
use crate::context::SigningClient;
use clap::Parser;
use log::info;
use nym_mixnet_contract_common::MixId;
use nym_mixnet_contract_common::NodeId;
use nym_validator_client::nyxd::contract_traits::{MixnetQueryClient, MixnetSigningClient};
#[derive(Debug, Parser)]
pub struct Args {
#[clap(long)]
pub mix_id: Option<MixId>,
pub mix_id: Option<NodeId>,
#[clap(long)]
pub identity_key: Option<String>,
@@ -4,13 +4,13 @@
use crate::context::SigningClient;
use clap::Parser;
use log::info;
use nym_mixnet_contract_common::MixId;
use nym_mixnet_contract_common::NodeId;
use nym_validator_client::nyxd::contract_traits::{MixnetQueryClient, MixnetSigningClient};
#[derive(Debug, Parser)]
pub struct Args {
#[clap(long)]
pub mix_id: Option<MixId>,
pub mix_id: Option<NodeId>,
#[clap(long)]
pub identity_key: Option<String>,
@@ -36,7 +36,7 @@ pub async fn undelegate_from_mixnode(args: Args, client: SigningClient) {
};
let res = client
.undelegate_from_mixnode(mix_id, None)
.undelegate(mix_id, None)
.await
.expect("failed to remove stake from mixnode!");
@@ -4,7 +4,7 @@
use clap::Parser;
use log::info;
use nym_mixnet_contract_common::{Coin, MixId};
use nym_mixnet_contract_common::{Coin, NodeId};
use nym_validator_client::nyxd::contract_traits::MixnetQueryClient;
use nym_validator_client::nyxd::contract_traits::VestingSigningClient;
@@ -13,7 +13,7 @@ use crate::context::SigningClient;
#[derive(Debug, Parser)]
pub struct Args {
#[clap(long)]
pub mix_id: Option<MixId>,
pub mix_id: Option<NodeId>,
#[clap(long)]
pub identity_key: Option<String>,
@@ -3,7 +3,7 @@
use clap::Parser;
use log::info;
use nym_mixnet_contract_common::MixId;
use nym_mixnet_contract_common::NodeId;
use nym_validator_client::nyxd::contract_traits::MixnetQueryClient;
use nym_validator_client::nyxd::contract_traits::VestingSigningClient;
@@ -12,7 +12,7 @@ use crate::context::SigningClient;
#[derive(Debug, Parser)]
pub struct Args {
#[clap(long)]
pub mix_id: Option<MixId>,
pub mix_id: Option<NodeId>,
#[clap(long)]
pub identity_key: Option<String>,
@@ -5,6 +5,7 @@ use clap::{Args, Subcommand};
pub mod bond_gateway;
pub mod gateway_bonding_sign_payload;
pub mod nymnode_migration;
pub mod settings;
pub mod unbond_gateway;
pub mod vesting_bond_gateway;
@@ -31,4 +32,6 @@ pub enum MixnetOperatorsGatewayCommands {
VestingUnbond(vesting_unbond_gateway::Args),
/// Create base58-encoded payload required for producing valid bonding signature.
CreateGatewayBondingSignPayload(gateway_bonding_sign_payload::Args),
/// Migrate the gateway into a Nym Node
MigrateToNymnode(nymnode_migration::Args),
}
@@ -0,0 +1,56 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::context::SigningClient;
use clap::Parser;
use cosmwasm_std::Uint128;
use log::info;
use nym_contracts_common::Percent;
use nym_mixnet_contract_common::{
NodeCostParams, DEFAULT_INTERVAL_OPERATING_COST_AMOUNT, DEFAULT_PROFIT_MARGIN_PERCENT,
};
use nym_validator_client::nyxd::contract_traits::MixnetSigningClient;
use nym_validator_client::nyxd::CosmWasmCoin;
#[derive(Debug, Parser)]
pub struct Args {
#[clap(long)]
pub profit_margin_percent: Option<u64>,
#[clap(
long,
help = "operating cost in current DENOMINATION (so it would be 'unym', rather than 'nym')"
)]
pub interval_operating_cost: Option<u128>,
}
pub async fn migrate_to_nymnode(args: Args, client: SigningClient) {
let denom = client.current_chain_details().mix_denom.base.as_str();
let cost_params =
if args.profit_margin_percent.is_some() || args.interval_operating_cost.is_some() {
Some(NodeCostParams {
profit_margin_percent: Percent::from_percentage_value(
args.profit_margin_percent
.unwrap_or(DEFAULT_PROFIT_MARGIN_PERCENT),
)
.unwrap(),
interval_operating_cost: CosmWasmCoin {
denom: denom.into(),
amount: Uint128::new(
args.interval_operating_cost
.unwrap_or(DEFAULT_INTERVAL_OPERATING_COST_AMOUNT),
),
},
})
} else {
None
};
let res = client
.migrate_legacy_gateway(cost_params, None)
.await
.expect("failed to migrate gateway!");
info!("migration result: {:?}", res)
}
@@ -1,20 +1,21 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::context::SigningClient;
use clap::Parser;
use cosmwasm_std::Uint128;
use log::{info, warn};
use nym_contracts_common::signing::MessageSignature;
use nym_mixnet_contract_common::{Coin, MixNodeCostParams, Percent};
use nym_mixnet_contract_common::{
Coin, NodeCostParams, Percent, DEFAULT_INTERVAL_OPERATING_COST_AMOUNT,
DEFAULT_PROFIT_MARGIN_PERCENT,
};
use nym_network_defaults::{
DEFAULT_HTTP_API_LISTENING_PORT, DEFAULT_MIX_LISTENING_PORT, DEFAULT_VERLOC_LISTENING_PORT,
};
use nym_validator_client::nyxd::contract_traits::MixnetSigningClient;
use nym_validator_client::nyxd::CosmWasmCoin;
use crate::context::SigningClient;
#[derive(Debug, Parser)]
pub struct Args {
#[clap(long)]
@@ -42,7 +43,7 @@ pub struct Args {
pub version: String,
#[clap(long)]
pub profit_margin_percent: Option<u8>,
pub profit_margin_percent: Option<u64>,
#[clap(
long,
@@ -85,14 +86,18 @@ pub async fn bond_mixnode(args: Args, client: SigningClient) {
let coin = Coin::new(args.amount, denom);
let cost_params = MixNodeCostParams {
let cost_params = NodeCostParams {
profit_margin_percent: Percent::from_percentage_value(
args.profit_margin_percent.unwrap_or(10) as u64,
args.profit_margin_percent
.unwrap_or(DEFAULT_PROFIT_MARGIN_PERCENT),
)
.unwrap(),
interval_operating_cost: CosmWasmCoin {
denom: denom.into(),
amount: Uint128::new(args.interval_operating_cost.unwrap_or(40_000_000)),
amount: Uint128::new(
args.interval_operating_cost
.unwrap_or(DEFAULT_INTERVAL_OPERATING_COST_AMOUNT),
),
},
};
@@ -1,25 +0,0 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::context::SigningClient;
use clap::Parser;
use log::info;
use nym_validator_client::nyxd::contract_traits::MixnetSigningClient;
#[derive(Debug, Parser)]
pub struct Args {
/// Label that is going to be used for creating the family
#[arg(long)]
pub family_label: String,
}
pub async fn create_family(args: Args, client: SigningClient) {
info!("Create family");
let res = client
.create_family(args.family_label, None)
.await
.expect("failed to create family");
info!("Family creation result: {:?}", res);
}
@@ -1,72 +0,0 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::context::QueryClient;
use crate::utils::DataWrapper;
use clap::Parser;
use cosmrs::AccountId;
use log::info;
use nym_bin_common::output_format::OutputFormat;
use nym_crypto::asymmetric::identity;
use nym_mixnet_contract_common::construct_family_join_permit;
use nym_mixnet_contract_common::families::FamilyHead;
use nym_validator_client::nyxd::contract_traits::MixnetQueryClient;
#[derive(Debug, Parser)]
pub struct Args {
/// Account address (i.e. owner of the family head) which will be used for issuing the permit
#[arg(long)]
pub address: AccountId,
// might as well validate the value when parsing the arguments
/// Identity of the member for whom we're issuing the permit
#[arg(long)]
pub member: identity::PublicKey,
#[clap(short, long, default_value_t = OutputFormat::default())]
output: OutputFormat,
}
pub async fn create_family_join_permit_sign_payload(args: Args, client: QueryClient) {
info!("Create family join permit sign payload");
// get the address of our mixnode to recover the family head information
let Some(mixnode) = client
.get_owned_mixnode(&args.address)
.await
.unwrap()
.mixnode_details
else {
eprintln!("{} does not seem to even own a mixnode!", args.address);
return;
};
// make sure this mixnode is actually a family head
if client
.get_node_family_by_head(mixnode.bond_information.identity().to_string())
.await
.unwrap()
.family
.is_none()
{
eprintln!("{} does not even seem to own a family!", args.address);
return;
}
let nonce = match client.get_signing_nonce(&args.address).await {
Ok(nonce) => nonce,
Err(err) => {
eprint!(
"failed to query for the signing nonce of {}: {err}",
args.address
);
return;
}
};
let head = FamilyHead::new(mixnode.bond_information.identity());
let payload = construct_family_join_permit(nonce, head, args.member.to_base58_string());
let wrapper = DataWrapper::new(payload.to_base58_string().unwrap());
println!("{}", args.output.format(&wrapper))
}
@@ -1,34 +0,0 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::context::SigningClient;
use clap::Parser;
use log::info;
use nym_contracts_common::signing::MessageSignature;
use nym_crypto::asymmetric::identity;
use nym_mixnet_contract_common::families::FamilyHead;
use nym_validator_client::nyxd::contract_traits::MixnetSigningClient;
#[derive(Debug, Parser)]
pub struct Args {
/// The head of the family that we intend to join
#[arg(long)]
pub family_head: identity::PublicKey,
/// Permission, as provided by the family head, for joining the family
#[arg(long)]
pub join_permit: MessageSignature,
}
pub async fn join_family(args: Args, client: SigningClient) {
info!("Join family");
let family_head = FamilyHead::new(args.family_head.to_base58_string());
let res = client
.join_family(args.join_permit, family_head, None)
.await
.expect("failed to join family");
info!("Family join result: {:?}", res);
}
@@ -1,40 +0,0 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::context::SigningClient;
use clap::Parser;
use log::info;
use nym_crypto::asymmetric::identity;
use nym_validator_client::nyxd::contract_traits::MixnetSigningClient;
use nym_validator_client::nyxd::contract_traits::VestingSigningClient;
#[derive(Debug, Parser)]
pub struct Args {
/// The member of the family that we intend to kick
#[arg(long)]
pub member: identity::PublicKey,
/// Indicates whether the family was created (and managed) via the vesting contract
#[arg(long)]
pub with_vesting_account: bool,
}
pub async fn kick_family_member(args: Args, client: SigningClient) {
info!("Leave family");
let member = args.member.to_base58_string();
let res = if args.with_vesting_account {
client
.vesting_kick_family_member(member, None)
.await
.expect("failed to kick family member with vesting account")
} else {
client
.kick_family_member(member, None)
.await
.expect("failed to kick family member")
};
info!("Family leave result: {:?}", res);
}
@@ -1,29 +0,0 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::context::SigningClient;
use clap::Parser;
use log::info;
use nym_crypto::asymmetric::identity;
use nym_mixnet_contract_common::families::FamilyHead;
use nym_validator_client::nyxd::contract_traits::MixnetSigningClient;
#[derive(Debug, Parser)]
pub struct Args {
/// The head of the family that we intend to leave
#[arg(long)]
pub family_head: identity::PublicKey,
}
pub async fn leave_family(args: Args, client: SigningClient) {
info!("Leave family");
let family_head = FamilyHead::new(args.family_head.to_base58_string());
let res = client
.leave_family(family_head, None)
.await
.expect("failed to leave family");
info!("Family leave result: {:?}", res);
}
@@ -1,35 +0,0 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use clap::{Args, Subcommand};
pub mod create_family;
pub mod create_family_join_permit_sign_payload;
pub mod join_family;
pub mod kick_family_member;
pub mod leave_family;
#[derive(Debug, Args)]
#[clap(args_conflicts_with_subcommands = true, subcommand_required = true)]
pub struct MixnetOperatorsMixnodeFamilies {
#[clap(subcommand)]
pub command: MixnetOperatorsMixnodeFamiliesCommands,
}
#[derive(Debug, Subcommand)]
pub enum MixnetOperatorsMixnodeFamiliesCommands {
/// Create family
CreateFamily(create_family::Args),
/// Join family
JoinFamily(join_family::Args),
/// Leave family,
LeaveFamily(leave_family::Args),
/// Kick family member
KickFamilyMember(kick_family_member::Args),
/// Create a message payload that is required to get signed in order to obtain a permit for joining family
CreateFamilyJoinPermitSignPayload(create_family_join_permit_sign_payload::Args),
}
@@ -8,7 +8,8 @@ use cosmwasm_std::{Coin, Uint128};
use nym_bin_common::output_format::OutputFormat;
use nym_contracts_common::Percent;
use nym_mixnet_contract_common::{
construct_legacy_mixnode_bonding_sign_payload, MixNodeCostParams,
construct_legacy_mixnode_bonding_sign_payload, NodeCostParams,
DEFAULT_INTERVAL_OPERATING_COST_AMOUNT, DEFAULT_PROFIT_MARGIN_PERCENT,
};
use nym_network_defaults::{
DEFAULT_HTTP_API_LISTENING_PORT, DEFAULT_MIX_LISTENING_PORT, DEFAULT_VERLOC_LISTENING_PORT,
@@ -40,7 +41,7 @@ pub struct Args {
pub version: String,
#[clap(long)]
pub profit_margin_percent: Option<u8>,
pub profit_margin_percent: Option<u64>,
#[clap(
long,
@@ -75,14 +76,18 @@ pub async fn create_payload(args: Args, client: SigningClient) {
let coin = Coin::new(args.amount, denom);
let cost_params = MixNodeCostParams {
let cost_params = NodeCostParams {
profit_margin_percent: Percent::from_percentage_value(
args.profit_margin_percent.unwrap_or(10) as u64,
args.profit_margin_percent
.unwrap_or(DEFAULT_PROFIT_MARGIN_PERCENT),
)
.unwrap(),
interval_operating_cost: CosmWasmCoin {
denom: denom.into(),
amount: Uint128::new(args.interval_operating_cost.unwrap_or(40_000_000)),
amount: Uint128::new(
args.interval_operating_cost
.unwrap_or(DEFAULT_INTERVAL_OPERATING_COST_AMOUNT),
),
},
};
@@ -5,10 +5,10 @@ use clap::{Args, Subcommand};
pub mod bond_mixnode;
pub mod decrease_pledge;
pub mod families;
pub mod keys;
pub mod migrate_vested_mixnode;
pub mod mixnode_bonding_sign_payload;
pub mod nymnode_migration;
pub mod pledge_more;
pub mod rewards;
pub mod settings;
@@ -33,8 +33,6 @@ pub enum MixnetOperatorsMixnodeCommands {
Rewards(rewards::MixnetOperatorsMixnodeRewards),
/// Manage your mixnode settings stored in the directory
Settings(settings::MixnetOperatorsMixnodeSettings),
/// Operations for mixnode families
Families(families::MixnetOperatorsMixnodeFamilies),
/// Bond to a mixnode
Bond(bond_mixnode::Args),
/// Unbond from a mixnode
@@ -55,4 +53,6 @@ pub enum MixnetOperatorsMixnodeCommands {
DecreasePledgeVesting(vesting_decrease_pledge::Args),
/// Migrate the mixnode to use liquid tokens
MigrateVestedNode(migrate_vested_mixnode::Args),
/// Migrate the mixnode into a Nym Node
MigrateToNymnode(nymnode_migration::Args),
}
@@ -0,0 +1,19 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::context::SigningClient;
use clap::Parser;
use log::info;
use nym_validator_client::nyxd::contract_traits::MixnetSigningClient;
#[derive(Debug, Parser)]
pub struct Args {}
pub async fn migrate_to_nymnode(_args: Args, client: SigningClient) {
let res = client
.migrate_legacy_mixnode(None)
.await
.expect("failed to migrate mixnode!");
info!("migration result: {:?}", res)
}
@@ -2,12 +2,8 @@
// SPDX-License-Identifier: Apache-2.0
use crate::context::SigningClient;
use crate::validator::mixnet::operators::nymnode;
use clap::Parser;
use cosmwasm_std::Uint128;
use log::info;
use nym_mixnet_contract_common::{MixNodeCostParams, Percent};
use nym_validator_client::nyxd::contract_traits::{MixnetQueryClient, MixnetSigningClient};
use nym_validator_client::nyxd::CosmWasmCoin;
#[derive(Debug, Parser)]
pub struct Args {
@@ -24,62 +20,14 @@ pub struct Args {
pub interval_operating_cost: Option<u128>,
}
pub async fn update_cost_params(args: Args, client: SigningClient) {
let denom = client.current_chain_details().mix_denom.base.as_str();
fn convert_to_percent(value: u64) -> Percent {
Percent::from_percentage_value(value).expect("Invalid value")
}
let default_profit_margin: Percent = convert_to_percent(20);
let mixownership_response = match client.get_owned_mixnode(&client.address()).await {
Ok(response) => response,
Err(_) => {
eprintln!("Failed to obtain owned mixnode");
return;
}
};
let mix_id = match mixownership_response.mixnode_details {
Some(details) => details.bond_information.mix_id,
None => {
eprintln!("Failed to obtain mixnode details");
return;
}
};
let rewarding_response = match client.get_mixnode_rewarding_details(mix_id).await {
Ok(details) => details,
Err(_) => {
eprintln!("Failed to obtain rewarding details");
return;
}
};
let profit_margin_percent = rewarding_response
.rewarding_details
.map(|rd| rd.cost_params.profit_margin_percent)
.unwrap_or(default_profit_margin);
let profit_margin_value = args
.profit_margin_percent
.map(|pm| convert_to_percent(pm as u64))
.unwrap_or(profit_margin_percent);
let cost_params = MixNodeCostParams {
profit_margin_percent: profit_margin_value,
interval_operating_cost: CosmWasmCoin {
denom: denom.into(),
amount: Uint128::new(args.interval_operating_cost.unwrap_or(40_000_000)),
pub async fn update_cost_params(args: Args, client: SigningClient) -> anyhow::Result<()> {
// the below can handle both, nymnode and legacy mixnode
nymnode::settings::update_cost_params::update_cost_params(
nymnode::settings::update_cost_params::Args {
profit_margin_percent: args.profit_margin_percent,
interval_operating_cost: args.interval_operating_cost,
},
};
info!("Starting mixnode params updating!");
let res = client
.update_mixnode_cost_params(cost_params, None)
.await
.expect("failed to update cost params");
info!("Cost params result: {:?}", res)
client,
)
.await
}
@@ -6,7 +6,9 @@ use clap::Parser;
use cosmwasm_std::Uint128;
use log::{info, warn};
use nym_contracts_common::signing::MessageSignature;
use nym_mixnet_contract_common::{Coin, MixNodeCostParams};
use nym_mixnet_contract_common::{
Coin, NodeCostParams, DEFAULT_INTERVAL_OPERATING_COST_AMOUNT, DEFAULT_PROFIT_MARGIN_PERCENT,
};
use nym_mixnet_contract_common::{MixNode, Percent};
use nym_network_defaults::{
DEFAULT_HTTP_API_LISTENING_PORT, DEFAULT_MIX_LISTENING_PORT, DEFAULT_VERLOC_LISTENING_PORT,
@@ -40,7 +42,7 @@ pub struct Args {
pub version: String,
#[clap(long)]
pub profit_margin_percent: Option<u8>,
pub profit_margin_percent: Option<u64>,
#[clap(
long,
@@ -84,14 +86,18 @@ pub async fn vesting_bond_mixnode(client: SigningClient, args: Args, denom: &str
let coin = Coin::new(args.amount, denom);
let cost_params = MixNodeCostParams {
let cost_params = NodeCostParams {
profit_margin_percent: Percent::from_percentage_value(
args.profit_margin_percent.unwrap_or(10) as u64,
args.profit_margin_percent
.unwrap_or(DEFAULT_PROFIT_MARGIN_PERCENT),
)
.unwrap(),
interval_operating_cost: CosmWasmCoin {
denom: denom.into(),
amount: Uint128::new(args.interval_operating_cost.unwrap_or(40_000_000)),
amount: Uint128::new(
args.interval_operating_cost
.unwrap_or(DEFAULT_INTERVAL_OPERATING_COST_AMOUNT),
),
},
};
@@ -6,6 +6,7 @@ use clap::{Args, Subcommand};
pub mod gateway;
pub mod identity_key;
pub mod mixnode;
pub mod nymnode;
#[derive(Debug, Args)]
#[clap(args_conflicts_with_subcommands = true, subcommand_required = true)]
@@ -17,9 +18,11 @@ pub struct MixnetOperators {
#[allow(clippy::large_enum_variant)]
#[derive(Debug, Subcommand)]
pub enum MixnetOperatorsCommands {
/// Manage your mixnode
/// Manage your Nym Node
Nymnode(nymnode::MixnetOperatorsNymNode),
/// Manage your legacy mixnode
Mixnode(mixnode::MixnetOperatorsMixnode),
/// Manage your gateway
/// Manage your legacy gateway
Gateway(gateway::MixnetOperatorsGateway),
/// Sign messages using your private identity key
IdentityKey(identity_key::MixnetOperatorsIdentityKey),
@@ -0,0 +1,89 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::context::SigningClient;
use clap::Parser;
use cosmwasm_std::Uint128;
use log::{info, warn};
use nym_contracts_common::signing::MessageSignature;
use nym_mixnet_contract_common::{
Coin, NodeCostParams, Percent, DEFAULT_INTERVAL_OPERATING_COST_AMOUNT,
DEFAULT_PROFIT_MARGIN_PERCENT,
};
use nym_validator_client::nyxd::contract_traits::MixnetSigningClient;
use nym_validator_client::nyxd::CosmWasmCoin;
#[derive(Debug, Parser)]
pub struct Args {
#[clap(long)]
pub host: String,
#[clap(long)]
pub signature: MessageSignature,
#[clap(long)]
pub http_api_port: Option<u16>,
#[clap(long)]
pub identity_key: String,
#[clap(long)]
pub profit_margin_percent: Option<u64>,
#[clap(
long,
help = "operating cost in current DENOMINATION (so it would be 'unym', rather than 'nym')"
)]
pub interval_operating_cost: Option<u128>,
#[clap(
long,
help = "bonding amount in current DENOMINATION (so it would be 'unym', rather than 'nym')"
)]
pub amount: u128,
#[clap(short, long)]
pub force: bool,
}
pub async fn bond_nymnode(args: Args, client: SigningClient) {
let denom = client.current_chain_details().mix_denom.base.as_str();
info!("Starting nym node bonding!");
// if we're trying to bond less than 1 token
if args.amount < 1_000_000 && !args.force {
warn!("You're trying to bond only {}{} which is less than 1 full token. Are you sure that's what you want? If so, run with `--force` or `-f` flag", args.amount, denom);
return;
}
let nymnode = nym_mixnet_contract_common::NymNode {
host: args.host,
custom_http_port: args.http_api_port,
identity_key: args.identity_key,
};
let coin = Coin::new(args.amount, denom);
let cost_params = NodeCostParams {
profit_margin_percent: Percent::from_percentage_value(
args.profit_margin_percent
.unwrap_or(DEFAULT_PROFIT_MARGIN_PERCENT),
)
.unwrap(),
interval_operating_cost: CosmWasmCoin {
denom: denom.into(),
amount: Uint128::new(
args.interval_operating_cost
.unwrap_or(DEFAULT_INTERVAL_OPERATING_COST_AMOUNT),
),
},
};
let res = client
.bond_nymnode(nymnode, cost_params, args.signature, coin.into(), None)
.await
.expect("failed to bond nymnode!");
info!("Bonding result: {:?}", res)
}
@@ -0,0 +1,20 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use base64::Engine;
use clap::Parser;
#[derive(Debug, Parser)]
pub struct Args {
#[clap(short, long)]
pub key: String,
}
pub fn decode_node_key(args: Args) {
let b64_decoded = base64::prelude::BASE64_STANDARD
.decode(args.key)
.expect("failed to decode base64 string");
let b58_encoded = bs58::encode(&b64_decoded).into_string();
println!("{b58_encoded}")
}
@@ -0,0 +1,19 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use clap::{Args, Subcommand};
pub mod decode_node_key;
#[derive(Debug, Args)]
#[clap(args_conflicts_with_subcommands = true, subcommand_required = true)]
pub struct MixnetOperatorsNymNodeKeys {
#[clap(subcommand)]
pub command: MixnetOperatorsNymNodeKeysCommands,
}
#[derive(Debug, Subcommand)]
pub enum MixnetOperatorsNymNodeKeysCommands {
/// Decode a Nym Node key
DecodeNodeKey(decode_node_key::Args),
}
@@ -0,0 +1,43 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use clap::{Args, Subcommand};
pub mod bond_nymnode;
pub mod keys;
pub mod nymnode_bonding_sign_payload;
pub mod pledge;
pub mod rewards;
pub mod settings;
pub mod unbond_nymnode;
#[derive(Debug, Args)]
#[clap(args_conflicts_with_subcommands = true, subcommand_required = true)]
pub struct MixnetOperatorsNymNode {
#[clap(subcommand)]
pub command: MixnetOperatorsNymNodeCommands,
}
#[derive(Debug, Subcommand)]
pub enum MixnetOperatorsNymNodeCommands {
/// Operations for Nym Node keys
Keys(keys::MixnetOperatorsNymNodeKeys),
/// Manage your Nym Node operator rewards
Rewards(rewards::MixnetOperatorsNymNodeRewards),
/// Manage your Nym Node settings stored in the directory
Settings(settings::MixnetOperatorsNymNodeSettings),
/// Manage your Nym Node pledge
Pledge(pledge::MixnetOperatorsNymNodePledge),
/// Bond to a Nym Node
Bond(bond_nymnode::Args),
/// Unbond from a Nym Node
Unbond(unbond_nymnode::Args),
/// Create base58-encoded payload required for producing valid bonding signature.
CreateNodeBondingSignPayload(nymnode_bonding_sign_payload::Args),
}
@@ -0,0 +1,90 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::context::SigningClient;
use crate::utils::{account_id_to_cw_addr, DataWrapper};
use clap::Parser;
use cosmwasm_std::{Coin, Uint128};
use nym_bin_common::output_format::OutputFormat;
use nym_contracts_common::Percent;
use nym_mixnet_contract_common::{
construct_nym_node_bonding_sign_payload, NodeCostParams,
DEFAULT_INTERVAL_OPERATING_COST_AMOUNT, DEFAULT_PROFIT_MARGIN_PERCENT,
};
use nym_validator_client::nyxd::contract_traits::MixnetQueryClient;
use nym_validator_client::nyxd::CosmWasmCoin;
#[derive(Debug, Parser)]
pub struct Args {
#[clap(long)]
pub host: String,
#[clap(long)]
pub identity_key: String,
#[clap(long)]
pub custom_http_api_port: Option<u16>,
#[clap(long)]
pub profit_margin_percent: Option<u64>,
#[clap(
long,
help = "operating cost in current DENOMINATION (so it would be 'unym', rather than 'nym')"
)]
pub interval_operating_cost: Option<u128>,
#[clap(
long,
help = "bonding amount in current DENOMINATION (so it would be 'unym', rather than 'nym')"
)]
pub amount: u128,
#[clap(short, long, default_value_t = OutputFormat::default())]
pub output: OutputFormat,
}
pub async fn create_payload(args: Args, client: SigningClient) {
let denom = client.current_chain_details().mix_denom.base.as_str();
let mixnode = nym_mixnet_contract_common::NymNode {
host: args.host,
custom_http_port: args.custom_http_api_port,
identity_key: args.identity_key,
};
let coin = Coin::new(args.amount, denom);
let cost_params = NodeCostParams {
profit_margin_percent: Percent::from_percentage_value(
args.profit_margin_percent
.unwrap_or(DEFAULT_PROFIT_MARGIN_PERCENT),
)
.unwrap(),
interval_operating_cost: CosmWasmCoin {
denom: denom.into(),
amount: Uint128::new(
args.interval_operating_cost
.unwrap_or(DEFAULT_INTERVAL_OPERATING_COST_AMOUNT),
),
},
};
let nonce = match client.get_signing_nonce(&client.address()).await {
Ok(nonce) => nonce,
Err(err) => {
eprint!(
"failed to query for the signing nonce of {}: {err}",
client.address()
);
return;
}
};
let address = account_id_to_cw_addr(&client.address());
let payload =
construct_nym_node_bonding_sign_payload(nonce, address, coin, mixnode, cost_params);
let wrapper = DataWrapper::new(payload.to_base58_string().unwrap());
println!("{}", args.output.format(&wrapper))
}
@@ -0,0 +1,29 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::context::SigningClient;
use clap::Parser;
use log::info;
use nym_mixnet_contract_common::Coin;
use nym_validator_client::nyxd::contract_traits::MixnetSigningClient;
#[derive(Debug, Parser)]
pub struct Args {
#[clap(long)]
pub decrease_by: u128,
}
pub async fn decrease_pledge(args: Args, client: SigningClient) {
let denom = client.current_chain_details().mix_denom.base.as_str();
info!("Starting to decrease pledge");
let coin = Coin::new(args.decrease_by, denom);
let res = client
.pledge_more(coin.into(), None)
.await
.expect("failed to decrease pledge!");
info!("decreasing pledge: {:?}", res);
}
@@ -0,0 +1,29 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::context::SigningClient;
use clap::Parser;
use log::info;
use nym_mixnet_contract_common::Coin;
use nym_validator_client::nyxd::contract_traits::MixnetSigningClient;
#[derive(Debug, Parser)]
pub struct Args {
#[clap(long)]
pub amount: u128,
}
pub async fn increase_pledge(args: Args, client: SigningClient) {
let denom = client.current_chain_details().mix_denom.base.as_str();
info!("Starting to pledge more");
let coin = Coin::new(args.amount, denom);
let res = client
.pledge_more(coin.into(), None)
.await
.expect("failed to pledge more!");
info!("pledging more: {:?}", res);
}
@@ -0,0 +1,22 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use clap::{Args, Subcommand};
pub mod decrease_pledge;
pub mod increase_pledge;
#[derive(Debug, Args)]
#[clap(args_conflicts_with_subcommands = true, subcommand_required = true)]
pub struct MixnetOperatorsNymNodePledge {
#[clap(subcommand)]
pub command: MixnetOperatorsNymNodePledgeCommands,
}
#[derive(Debug, Subcommand)]
pub enum MixnetOperatorsNymNodePledgeCommands {
/// Increase current pledge
Increase(increase_pledge::Args),
/// decrease current pledge
Decrease(decrease_pledge::Args),
}
@@ -0,0 +1,21 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::context::SigningClient;
use clap::Parser;
use log::info;
use nym_validator_client::nyxd::contract_traits::MixnetSigningClient;
#[derive(Debug, Parser)]
pub struct Args {}
pub async fn claim_operator_reward(_args: Args, client: SigningClient) {
info!("Claim operator reward");
let res = client
.withdraw_operator_reward(None)
.await
.expect("failed to claim operator reward");
info!("Claiming operator reward: {:?}", res)
}
@@ -0,0 +1,19 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use clap::{Args, Subcommand};
pub mod claim_operator_reward;
#[derive(Debug, Args)]
#[clap(args_conflicts_with_subcommands = true, subcommand_required = true)]
pub struct MixnetOperatorsNymNodeRewards {
#[clap(subcommand)]
pub command: MixnetOperatorsNymNodeRewardsCommands,
}
#[derive(Debug, Subcommand)]
pub enum MixnetOperatorsNymNodeRewardsCommands {
/// Claim rewards
Claim(claim_operator_reward::Args),
}
@@ -0,0 +1,22 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use clap::{Args, Subcommand};
pub mod update_config;
pub mod update_cost_params;
#[derive(Debug, Args)]
#[clap(args_conflicts_with_subcommands = true, subcommand_required = true)]
pub struct MixnetOperatorsNymNodeSettings {
#[clap(subcommand)]
pub command: MixnetOperatorsNymNodeSettingsCommands,
}
#[derive(Debug, Subcommand)]
pub enum MixnetOperatorsNymNodeSettingsCommands {
/// Update Nym Node configuration
UpdateConfig(update_config::Args),
/// Update Nym Node cost parameters
UpdateCostParameters(update_cost_params::Args),
}
@@ -0,0 +1,50 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::context::SigningClient;
use clap::Parser;
use log::info;
use nym_mixnet_contract_common::nym_node::NodeConfigUpdate;
use nym_validator_client::nyxd::contract_traits::{MixnetQueryClient, MixnetSigningClient};
#[derive(Debug, Parser)]
pub struct Args {
#[clap(long)]
pub host: Option<String>,
// ideally this would have been `Option<Option<u16>>`, but not sure if clap would have recognised it
#[clap(long)]
pub custom_http_port: Option<u16>,
// equivalent to setting `custom_http_port` to `None`
#[clap(long)]
pub restore_default_http_port: bool,
}
pub async fn update_config(args: Args, client: SigningClient) {
info!("Update nym node config!");
if client
.get_owned_nymnode(&client.address())
.await
.expect("failed to query the chain for nym node details")
.details
.is_none()
{
log::warn!("this operator does not own a nym node to update");
return;
}
let update = NodeConfigUpdate {
host: args.host,
custom_http_port: args.custom_http_port,
restore_default_http_port: args.restore_default_http_port,
};
let res = client
.update_nymnode_config(update, None)
.await
.expect("updating nym node config");
info!("nym node config updated: {:?}", res)
}
@@ -0,0 +1,73 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::context::SigningClient;
use anyhow::anyhow;
use clap::Parser;
use cosmwasm_std::Uint128;
use log::info;
use nym_mixnet_contract_common::{NodeCostParams, Percent};
use nym_validator_client::nyxd::contract_traits::{MixnetQueryClient, MixnetSigningClient};
use nym_validator_client::nyxd::CosmWasmCoin;
#[derive(Debug, Parser)]
pub struct Args {
#[clap(
long,
help = "input your profit margin as follows; (so it would be 20, rather than 0.2)"
)]
pub profit_margin_percent: Option<u8>,
#[clap(
long,
help = "operating cost in current DENOMINATION (so it would be 'unym', rather than 'nym')"
)]
pub interval_operating_cost: Option<u128>,
}
pub async fn update_cost_params(args: Args, client: SigningClient) -> anyhow::Result<()> {
let denom = client.current_chain_details().mix_denom.base.as_str();
let current_parameters = if let Some(client_mixnode) = client
.get_owned_mixnode(&client.address())
.await?
.mixnode_details
{
client_mixnode.rewarding_details.cost_params
} else {
client
.get_owned_nymnode(&client.address())
.await?
.details
.ok_or_else(|| anyhow!("the client does not own any nodes"))?
.rewarding_details
.cost_params
};
let profit_margin_percent = args
.profit_margin_percent
.map(|pm| Percent::from_percentage_value(pm as u64))
.unwrap_or(Ok(current_parameters.profit_margin_percent))?;
let interval_operating_cost = args
.interval_operating_cost
.map(|oc| CosmWasmCoin {
denom: denom.into(),
amount: Uint128::new(oc),
})
.unwrap_or(current_parameters.interval_operating_cost);
let cost_params = NodeCostParams {
profit_margin_percent,
interval_operating_cost,
};
info!("Starting cost params updating using {cost_params:?} !");
let res = client
.update_cost_params(cost_params, None)
.await
.expect("failed to update cost params");
info!("Cost params result: {:?}", res);
Ok(())
}
@@ -0,0 +1,22 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use clap::Parser;
use log::info;
use nym_validator_client::nyxd::contract_traits::MixnetSigningClient;
use crate::context::SigningClient;
#[derive(Debug, Parser)]
pub struct Args {}
pub async fn unbond_nymnode(_args: Args, client: SigningClient) {
info!("Starting Nym Node unbonding!");
let res = client
.unbond_nymnode(None)
.await
.expect("failed to unbond Nym Node!");
info!("Unbonding result: {:?}", res)
}
@@ -39,7 +39,7 @@ pub async fn query(args: Args, client: &QueryClientWithNyxd) {
node.owner.to_string(),
node.gateway.host.to_string(),
pretty_cosmwasm_coin(&node.pledge_amount),
node.gateway.version,
node.gateway.version.clone(),
]);
}
@@ -0,0 +1,27 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use cosmwasm_std::{BankMsg, Coin, CosmosMsg, Response};
pub trait ResponseExt<T> {
fn add_optional_message(self, msg: Option<impl Into<CosmosMsg<T>>>) -> Self;
fn send_tokens(self, to: impl AsRef<str>, amount: Coin) -> Self;
}
impl<T> ResponseExt<T> for Response<T> {
fn add_optional_message(self, msg: Option<impl Into<CosmosMsg<T>>>) -> Self {
if let Some(msg) = msg {
self.add_message(msg)
} else {
self
}
}
fn send_tokens(self, to: impl AsRef<str>, amount: Coin) -> Self {
self.add_message(BankMsg::Send {
to_address: to.as_ref().to_string(),
amount: vec![amount],
})
}
}
@@ -10,4 +10,6 @@ pub mod events;
pub mod signing;
pub mod types;
pub mod helpers;
pub use types::*;
@@ -8,7 +8,7 @@ use cosmwasm_std::Uint128;
use serde::de::Error;
use serde::{Deserialize, Deserializer};
use std::fmt::{self, Display, Formatter};
use std::ops::Mul;
use std::ops::{Deref, Mul};
use std::str::FromStr;
use thiserror::Error;
@@ -23,7 +23,7 @@ pub fn truncate_decimal(amount: Decimal) -> Uint128 {
#[derive(Error, Debug)]
pub enum ContractsCommonError {
#[error("Provided percent value ({0}) is greater than 100%")]
InvalidPercent(Decimal),
InvalidPercent(String),
#[error("{source}")]
StdErr {
@@ -41,7 +41,7 @@ pub struct Percent(#[serde(deserialize_with = "de_decimal_percent")] Decimal);
impl Percent {
pub fn new(value: Decimal) -> Result<Self, ContractsCommonError> {
if value > Decimal::one() {
Err(ContractsCommonError::InvalidPercent(value))
Err(ContractsCommonError::InvalidPercent(value.to_string()))
} else {
Ok(Percent(value))
}
@@ -51,11 +51,15 @@ impl Percent {
self.0 == Decimal::zero()
}
pub fn zero() -> Self {
pub fn is_hundred(&self) -> bool {
self == &Self::hundred()
}
pub const fn zero() -> Self {
Self(Decimal::zero())
}
pub fn hundred() -> Self {
pub const fn hundred() -> Self {
Self(Decimal::one())
}
@@ -117,6 +121,70 @@ impl Mul<Uint128> for Percent {
}
}
impl Deref for Percent {
type Target = Decimal;
fn deref(&self) -> &Self::Target {
&self.0
}
}
// this is not implemented via From traits due to its naive nature and loss of precision
#[cfg(not(target_arch = "wasm32"))]
pub trait NaiveFloat {
fn naive_to_f64(&self) -> f64;
fn naive_try_from_f64(val: f64) -> Result<Self, ContractsCommonError>
where
Self: Sized;
}
#[cfg(not(target_arch = "wasm32"))]
impl NaiveFloat for Percent {
fn naive_to_f64(&self) -> f64 {
use cosmwasm_std::Fraction;
// note: this conversion loses precision with too many decimal places,
// but for the purposes of displaying basic performance, that's not an issue
self.numerator().u128() as f64 / self.denominator().u128() as f64
}
fn naive_try_from_f64(val: f64) -> Result<Self, ContractsCommonError>
where
Self: Sized,
{
// we are only interested in positive values between 0 and 1
if !(0. ..=1.).contains(&val) {
return Err(ContractsCommonError::InvalidPercent(val.to_string()));
}
fn gcd(mut x: u64, mut y: u64) -> u64 {
while y > 0 {
let rem = x % y;
x = y;
y = rem;
}
x
}
fn to_rational(x: f64) -> (u64, u64) {
let log = x.log2().floor();
if log >= 0.0 {
(x as u64, 1)
} else {
let num: u64 = (x / f64::EPSILON) as _;
let den: u64 = (1.0 / f64::EPSILON) as _;
let gcd = gcd(num, den);
(num / gcd, den / gcd)
}
}
let (n, d) = to_rational(val);
Percent::new(Decimal::from_ratio(n, d))
}
}
// implement custom Deserialize because we want to validate Percent has the correct range
fn de_decimal_percent<'de, D>(deserializer: D) -> Result<Decimal, D::Error>
where
@@ -243,4 +311,19 @@ mod tests {
let p = serde_json::from_str::<'_, Percent>("\"1.00\"").unwrap();
assert_eq!(p.round_to_integer(), 100);
}
#[test]
fn naive_float_conversion() {
// around 15 decimal places is the maximum precision we can handle
// which is still way more than enough for what we use it for
let float: f64 = "0.546295475423853".parse().unwrap();
let percent: Percent = "0.546295475423853".parse().unwrap();
assert_eq!(float, percent.naive_to_f64());
let epsilon = Decimal::from_ratio(1u64, 1000000000000000u64);
let converted = Percent::naive_try_from_f64(float).unwrap();
assert!(converted.0 - converted.0 < epsilon);
}
}
@@ -12,6 +12,7 @@ repository = { workspace = true }
bs58 = { workspace = true }
cosmwasm-std = { workspace = true }
cosmwasm-schema = { workspace = true }
cw-storage-plus.workspace = true
cw-controllers = { workspace = true }
cw2 = { workspace = true, optional = true }
serde = { workspace = true, features = ["derive"] }
@@ -5,6 +5,9 @@ use cosmwasm_std::{Decimal, Uint128};
pub const TOKEN_SUPPLY: Uint128 = Uint128::new(1_000_000_000_000_000);
pub const DEFAULT_INTERVAL_OPERATING_COST_AMOUNT: u128 = 40_000_000;
pub const DEFAULT_PROFIT_MARGIN_PERCENT: u64 = 20;
// I'm still not 100% sure how to feel about existence of this file
// This is equivalent of representing our display coin with 6 decimal places.
// I'm using this one as opposed to "Decimal::one()", as this provides us with higher accuracy
@@ -3,14 +3,14 @@
use crate::constants::TOKEN_SUPPLY;
use crate::helpers::IntoBaseDecimal;
use crate::{Addr, MixId};
use crate::{Addr, NodeId};
use cosmwasm_schema::cw_serde;
use cosmwasm_std::{Coin, Decimal, StdResult};
// just use a string representation of those so that we wouldn't need to bother with decoding bytes
// and trying to figure out whether they're valid, etc
pub type OwnerProxySubKey = String;
pub type StorageKey = (MixId, OwnerProxySubKey);
pub type StorageKey = (NodeId, OwnerProxySubKey);
// throughout the contract we ensure that our proxy can ONLY ever be the vesting contract
// thus this method is equivalent to either using the existing address (for when there's no proxy)
@@ -40,8 +40,9 @@ pub struct Delegation {
/// Address of the owner of this delegation.
pub owner: Addr,
/// Id of the MixNode that this delegation was performed against.
pub mix_id: MixId,
/// Id of the Node that this delegation was performed against.
#[serde(alias = "mix_id")]
pub node_id: NodeId,
// Note to UI/UX devs: there's absolutely no point in displaying this value to the users,
// it would serve them no purpose. It's only used for calculating rewards
@@ -56,12 +57,13 @@ pub struct Delegation {
/// Proxy address used to delegate the funds on behalf of another address
pub proxy: Option<Addr>,
// TODO: perhaps add a field to indicate if it was made against old mixnode with #[serde(default)]?
}
impl Delegation {
pub fn new(
owner: Addr,
mix_id: MixId,
node_id: NodeId,
cumulative_reward_ratio: Decimal,
amount: Coin,
height: u64,
@@ -73,7 +75,7 @@ impl Delegation {
Delegation {
owner,
mix_id,
node_id,
cumulative_reward_ratio,
amount,
height,
@@ -82,7 +84,7 @@ impl Delegation {
}
pub fn generate_storage_key(
mix_id: MixId,
mix_id: NodeId,
owner_address: &Addr,
proxy: Option<&Addr>,
) -> StorageKey {
@@ -92,7 +94,7 @@ impl Delegation {
// this function might seem a bit redundant, but I'd rather explicitly keep it around in case
// some types change in the future
pub fn generate_storage_key_with_subkey(
mix_id: MixId,
mix_id: NodeId,
owner_proxy_subkey: OwnerProxySubKey,
) -> StorageKey {
(mix_id, owner_proxy_subkey)
@@ -107,13 +109,13 @@ impl Delegation {
}
pub fn storage_key(&self) -> StorageKey {
Self::generate_storage_key(self.mix_id, &self.owner, self.proxy.as_ref())
Self::generate_storage_key(self.node_id, &self.owner, self.proxy.as_ref())
}
}
/// Response containing paged list of all delegations made towards particular mixnode.
/// Response containing paged list of all delegations made towards particular node.
#[cw_serde]
pub struct PagedMixNodeDelegationsResponse {
pub struct PagedNodeDelegationsResponse {
/// Each individual delegation made.
pub delegations: Vec<Delegation>,
@@ -121,9 +123,9 @@ pub struct PagedMixNodeDelegationsResponse {
pub start_next_after: Option<OwnerProxySubKey>,
}
impl PagedMixNodeDelegationsResponse {
impl PagedNodeDelegationsResponse {
pub fn new(delegations: Vec<Delegation>, start_next_after: Option<OwnerProxySubKey>) -> Self {
PagedMixNodeDelegationsResponse {
PagedNodeDelegationsResponse {
delegations,
start_next_after,
}
@@ -137,13 +139,13 @@ pub struct PagedDelegatorDelegationsResponse {
pub delegations: Vec<Delegation>,
/// Field indicating paging information for the following queries if the caller wishes to get further entries.
pub start_next_after: Option<(MixId, OwnerProxySubKey)>,
pub start_next_after: Option<(NodeId, OwnerProxySubKey)>,
}
impl PagedDelegatorDelegationsResponse {
pub fn new(
delegations: Vec<Delegation>,
start_next_after: Option<(MixId, OwnerProxySubKey)>,
start_next_after: Option<(NodeId, OwnerProxySubKey)>,
) -> Self {
PagedDelegatorDelegationsResponse {
delegations,
@@ -154,19 +156,24 @@ impl PagedDelegatorDelegationsResponse {
/// Response containing delegation details.
#[cw_serde]
pub struct MixNodeDelegationResponse {
pub struct NodeDelegationResponse {
/// If the delegation exists, this field contains its detailed information.
pub delegation: Option<Delegation>,
/// Flag indicating whether the node towards which the delegation was made is still bonded in the network.
#[deprecated(note = "this field will be removed. use .node_still_bonded instead")]
pub mixnode_still_bonded: bool,
pub node_still_bonded: bool,
}
impl MixNodeDelegationResponse {
pub fn new(delegation: Option<Delegation>, mixnode_still_bonded: bool) -> Self {
MixNodeDelegationResponse {
impl NodeDelegationResponse {
pub fn new(delegation: Option<Delegation>, node_still_bonded: bool) -> Self {
#[allow(deprecated)]
NodeDelegationResponse {
delegation,
mixnode_still_bonded,
mixnode_still_bonded: node_still_bonded,
node_still_bonded,
}
}
}
@@ -1,7 +1,10 @@
// Copyright 2022-2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::{EpochEventId, EpochState, IdentityKey, MixId, OperatingCostRange, ProfitMarginRange};
use crate::nym_node::Role;
use crate::{
EpochEventId, EpochState, IntervalEventId, NodeId, OperatingCostRange, ProfitMarginRange,
};
use contracts_common::signing::verifier::ApiVerifierError;
use contracts_common::Percent;
use cosmwasm_std::{Addr, Coin, Decimal, Uint128};
@@ -34,6 +37,16 @@ pub enum MixnetContractError {
#[error("Not enough funds sent for node pledge. (received {received}, minimum {minimum})")]
InsufficientPledge { received: Coin, minimum: Coin },
#[error(
"the provided value for node host is too long. it must not be longer than 255 characters"
)]
HostTooLong,
#[error(
"the provided node identity public key is not a correctly encoded base58 slice of 32 bytes"
)]
InvalidPubKey,
#[error("Attempted to reduce node pledge ({current}{denom} - {decrease_by}{denom}) below the minimum amount: {minimum}{denom}")]
InvalidPledgeReduction {
current: Uint128,
@@ -45,11 +58,19 @@ pub enum MixnetContractError {
#[error("A pledge change is already pending in this epoch. The event id: {pending_event_id}")]
PendingPledgeChange { pending_event_id: EpochEventId },
#[error(
"A cost params change is already pending in this epoch. The event id: {pending_event_id}"
)]
PendingParamsChange { pending_event_id: IntervalEventId },
#[error("Not enough funds sent for node delegation. (received {received}, minimum {minimum})")]
InsufficientDelegation { received: Coin, minimum: Coin },
#[error("Node ({node_id}) does not exist")]
NymNodeBondNotFound { node_id: NodeId },
#[error("Mixnode ({mix_id}) does not exist")]
MixNodeBondNotFound { mix_id: MixId },
MixNodeBondNotFound { mix_id: NodeId },
#[error("{owner} does not seem to own any mixnodes")]
NoAssociatedMixNodeBond { owner: Addr },
@@ -57,12 +78,18 @@ pub enum MixnetContractError {
#[error("{owner} does not seem to own any gateways")]
NoAssociatedGatewayBond { owner: Addr },
#[error("{owner} does not seem to own any nodes")]
NoAssociatedNodeBond { owner: Addr },
#[error("This address has already bonded a mixnode")]
AlreadyOwnsMixnode,
#[error("This address has already bonded a gateway")]
AlreadyOwnsGateway,
#[error("This address has already bonded a nym-node")]
AlreadyOwnsNymNode,
#[error("Gateway with this identity already exists. Its owner is {owner}")]
DuplicateGateway { owner: Addr },
@@ -103,32 +130,35 @@ pub enum MixnetContractError {
epoch_end: i64,
},
#[error("Mixnode {mix_id} has already been rewarded during the current rewarding epoch ({absolute_epoch_id})")]
MixnodeAlreadyRewarded {
mix_id: MixId,
#[error("attempted to reward a gateway node - this has not been fully integrated yet")]
GatewayRewarding,
#[error("node {node_id} has already been rewarded during the current rewarding epoch ({absolute_epoch_id})")]
NodeAlreadyRewarded {
node_id: NodeId,
absolute_epoch_id: u32,
},
#[error("Mixnode {mix_id} hasn't been selected to the rewarding set in this epoch ({absolute_epoch_id})")]
MixnodeNotInRewardedSet {
mix_id: MixId,
absolute_epoch_id: u32,
},
#[error("node {node_id} hasn't been assigned the role of {role} for this epoch")]
IncorrectEpochRole { node_id: NodeId, role: Role },
#[error("Mixnode {mix_id} is currently in the process of unbonding")]
MixnodeIsUnbonding { mix_id: MixId },
MixnodeIsUnbonding { mix_id: NodeId },
#[error("Node {node_id} is currently in the process of unbonding")]
NodeIsUnbonding { node_id: NodeId },
#[error("Mixnode {mix_id} has already unbonded")]
MixnodeHasUnbonded { mix_id: MixId },
MixnodeHasUnbonded { mix_id: NodeId },
#[error("The contract has ended up in a state that was deemed impossible: {comment}")]
InconsistentState { comment: String },
#[error(
"Could not find any delegation information associated with mixnode {mix_id} for {address} (proxy: {proxy:?})"
"Could not find any delegation information associated with node {node_id} for {address} (proxy: {proxy:?})"
)]
NoMixnodeDelegationFound {
mix_id: MixId,
NodeDelegationNotFound {
node_id: NodeId,
address: String,
proxy: Option<String>,
},
@@ -136,63 +166,18 @@ pub enum MixnetContractError {
#[error("Provided message to update rewarding params did not contain any updates")]
EmptyParamsChangeMsg,
#[error("Provided active set size is bigger than the rewarded set")]
#[error("one of the roles in the new active set is empty")]
EmptyRoleAssignment,
#[error("the number of mixnodes in the rewarded set is not divisible by the number of mix-layers (3)")]
UnevenLayerAssignment,
#[error("provided active set is bigger than the rewarded set")]
InvalidActiveSetSize,
#[error("Provided rewarded set size is smaller than the active set")]
InvalidRewardedSetSize,
#[error("Provided active set size is zero")]
ZeroActiveSet,
#[error("Provided rewarded set size is zero")]
ZeroRewardedSet,
#[error("Received unexpected value for the active set. Got: {received}, expected: {expected}")]
UnexpectedActiveSetSize { received: u32, expected: u32 },
#[error("Received unexpected value for the rewarded set. Got: {received}, expected at most: {expected}")]
UnexpectedRewardedSetSize { received: u32, expected: u32 },
#[error("Mixnode {mix_id} appears multiple times in the provided rewarded set update!")]
DuplicateRewardedSetNode { mix_id: MixId },
#[error("Family with head {head} does not exist!")]
FamilyDoesNotExist { head: String },
#[error("Family with label {label} does not exist!")]
FamilyLabelDoesNotExist { label: String },
#[error("Family with label '{0}' already exists")]
FamilyWithLabelExists(String),
#[error("Invalid layer expected 1, 2 or 3, got {0}")]
InvalidLayer(u8),
#[error("Head already has a family")]
FamilyCanHaveOnlyOne,
#[error("Already member of family {0}")]
AlreadyMemberOfFamily(String),
#[error("Can't join own family, family head {head}, member {member}")]
CantJoinOwnFamily {
head: IdentityKey,
member: IdentityKey,
},
#[error("Can't leave own family, family head {head}, member {member}")]
CantLeaveOwnFamily {
head: IdentityKey,
member: IdentityKey,
},
#[error("{member} is not a member of family {head}")]
NotAMember {
head: IdentityKey,
member: IdentityKey,
},
#[error("Feature is not yet implemented")]
NotImplemented,
@@ -219,13 +204,28 @@ pub enum MixnetContractError {
#[error("attempted to reward mixnode out of order. Attempted to reward {attempted_to_reward} while last rewarded was {last_rewarded}.")]
RewardingOutOfOrder {
last_rewarded: MixId,
attempted_to_reward: MixId,
last_rewarded: NodeId,
attempted_to_reward: NodeId,
},
#[error("the epoch is currently not in the 'event reconciliation' state. (the state is {current_state})")]
EpochNotInEventReconciliationState { current_state: EpochState },
#[error(
"the epoch is currently not in the 'role assignment' state. (the state is {current_state})"
)]
EpochNotInRoleAssignmentState { current_state: EpochState },
#[error("unexpected role assignment. got: {got} while expected: {expected}")]
UnexpectedRoleAssignment { expected: Role, got: Role },
#[error("attempted to assign an invalid number of nodes for a role of {role}. got {assigned}, but the maximum allowed is {allowed}")]
IllegalRoleCount {
role: Role,
assigned: u32,
allowed: u32,
},
#[error("the epoch is currently not in the 'epoch advancement' state. (the state is {current_state})")]
EpochNotInAdvancementState { current_state: EpochState },
@@ -258,6 +258,17 @@ pub enum MixnetContractError {
provided: Uint128,
range: OperatingCostRange,
},
#[error(
"currently it's not possible to migrate nodes bonded with vesting tokens into a nym-node. please perform vesting->liquid migration first."
)]
VestingNodeMigration,
#[error("value {got} does not correspond to any known node role")]
UnknownRoleRepresentation { got: u8 },
#[error("the total work for this epoch seems to be bigger than 1.0!")]
TotalWorkAboveOne,
}
impl MixnetContractError {
@@ -1,11 +1,13 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::error::MixnetContractError;
use crate::gateway::GatewayConfigUpdate;
use crate::mixnode::{MixNodeConfigUpdate, MixNodeCostParams};
use crate::reward_params::{IntervalRewardParams, IntervalRewardingParamsUpdate};
use crate::mixnode::{MixNodeConfigUpdate, NodeCostParams};
use crate::nym_node::Role;
use crate::reward_params::{ActiveSetUpdate, IntervalRewardParams, IntervalRewardingParamsUpdate};
use crate::rewarding::RewardDistribution;
use crate::{BlockHeight, ContractStateParams, IdentityKeyRef, Interval, Layer, MixId};
use crate::{BlockHeight, ContractStateParams, EpochId, IdentityKeyRef, Interval, NodeId};
pub use contracts_common::events::*;
use cosmwasm_std::{Addr, Coin, Decimal, Event};
use std::fmt::Display;
@@ -14,6 +16,11 @@ pub const EVENT_VERSION_PREFIX: &str = "v2_";
pub enum MixnetEventType {
MixnodeBonding,
NymNodeBonding,
NymNodeUnbonding,
PendingNymNodeUnbonding,
GatewayMigration,
MixnodeMigration,
PendingPledgeIncrease,
PledgeIncrease,
PendingPledgeDecrease,
@@ -23,9 +30,9 @@ pub enum MixnetEventType {
PendingMixnodeUnbonding,
MixnodeUnbonding,
MixnodeConfigUpdate,
PendingMixnodeCostParamsUpdate,
MixnodeCostParamsUpdate,
MixnodeRewarding,
PendingCostParamsUpdate,
CostParamsUpdate,
NodeRewarding,
WithdrawDelegatorReward,
WithdrawOperatorReward,
PendingActiveSetUpdate,
@@ -41,6 +48,7 @@ pub enum MixnetEventType {
RewardingValidatorUpdate,
BeginEpochTransition,
AdvanceEpoch,
RoleAssignment,
ExecutePendingEpochEvents,
ExecutePendingIntervalEvents,
ReconcilePendingEvents,
@@ -59,6 +67,11 @@ impl Display for MixnetEventType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let event_name = match self {
MixnetEventType::MixnodeBonding => "mixnode_bonding",
MixnetEventType::NymNodeBonding => "nymnode_bonding",
MixnetEventType::NymNodeUnbonding => "nymnode_unbonding",
MixnetEventType::PendingNymNodeUnbonding => "pending_nymnode_unbonding",
MixnetEventType::GatewayMigration => "gateway_migration",
MixnetEventType::MixnodeMigration => "mixnode_migration",
MixnetEventType::PendingPledgeIncrease => "pending_pledge_increase",
MixnetEventType::PledgeIncrease => "pledge_increase",
MixnetEventType::PendingPledgeDecrease => "pending_pledge_decrease",
@@ -68,9 +81,9 @@ impl Display for MixnetEventType {
MixnetEventType::PendingMixnodeUnbonding => "pending_mixnode_unbonding",
MixnetEventType::MixnodeConfigUpdate => "mixnode_config_update",
MixnetEventType::MixnodeUnbonding => "mixnode_unbonding",
MixnetEventType::PendingMixnodeCostParamsUpdate => "pending_mixnode_cost_params_update",
MixnetEventType::MixnodeCostParamsUpdate => "mixnode_cost_params_update",
MixnetEventType::MixnodeRewarding => "mix_rewarding",
MixnetEventType::PendingCostParamsUpdate => "pending_cost_params_update",
MixnetEventType::CostParamsUpdate => "cost_params_update",
MixnetEventType::NodeRewarding => "node_rewarding",
MixnetEventType::WithdrawDelegatorReward => "withdraw_delegator_reward",
MixnetEventType::WithdrawOperatorReward => "withdraw_operator_reward",
MixnetEventType::PendingActiveSetUpdate => "pending_active_set_update",
@@ -87,6 +100,7 @@ impl Display for MixnetEventType {
MixnetEventType::RewardingValidatorUpdate => "rewarding_validator_address_update",
MixnetEventType::BeginEpochTransition => "beginning_epoch_transition",
MixnetEventType::AdvanceEpoch => "advance_epoch",
MixnetEventType::RoleAssignment => "role_assignment",
MixnetEventType::ExecutePendingEpochEvents => "execute_pending_epoch_events",
MixnetEventType::ExecutePendingIntervalEvents => "execute_pending_interval_events",
MixnetEventType::ReconcilePendingEvents => "reconcile_pending_events",
@@ -103,6 +117,7 @@ impl Display for MixnetEventType {
// attributes that are used in multiple places
pub const OWNER_KEY: &str = "owner";
pub const AMOUNT_KEY: &str = "amount";
pub const ERROR_MESSAGE_KEY: &str = "error_message";
// event-specific attributes
@@ -113,16 +128,14 @@ pub const UNIT_REWARD_KEY: &str = "unit_reward";
// bonding/unbonding
pub const MIX_ID_KEY: &str = "mix_id";
pub const NODE_ID_KEY: &str = "node_id";
pub const NODE_IDENTITY_KEY: &str = "identity";
pub const ASSIGNED_LAYER_KEY: &str = "assigned_layer";
// settings change
pub const OLD_MINIMUM_MIXNODE_PLEDGE_KEY: &str = "old_minimum_mixnode_pledge";
pub const OLD_MINIMUM_GATEWAY_PLEDGE_KEY: &str = "old_minimum_gateway_pledge";
pub const OLD_MINIMUM_PLEDGE_KEY: &str = "old_minimum_pledge";
pub const OLD_MINIMUM_DELEGATION_KEY: &str = "old_minimum_delegation";
pub const NEW_MINIMUM_MIXNODE_PLEDGE_KEY: &str = "new_minimum_mixnode_pledge";
pub const NEW_MINIMUM_GATEWAY_PLEDGE_KEY: &str = "new_minimum_gateway_pledge";
pub const NEW_MINIMUM_PLEDGE_KEY: &str = "new_minimum_pledge";
pub const NEW_MINIMUM_DELEGATION_KEY: &str = "new_minimum_delegation";
pub const OLD_REWARDING_VALIDATOR_ADDRESS_KEY: &str = "old_rewarding_validator_address";
@@ -144,14 +157,19 @@ pub const PRIOR_UNIT_REWARD_KEY: &str = "prior_unit_reward";
pub const NO_REWARD_REASON_KEY: &str = "no_reward_reason";
pub const BOND_NOT_FOUND_VALUE: &str = "bond_not_found";
pub const ZERO_PERFORMANCE_VALUE: &str = "zero_performance";
pub const ZERO_PERFORMANCE_OR_WORK_VALUE: &str = "zero_performance_or_work";
// rewarded set update
pub const ACTIVE_SET_SIZE_KEY: &str = "active_set_size";
pub const NUM_MIXNODES_KEY: &str = "num_mixnodes";
pub const NUM_ENTRIES_KEY: &str = "num_entry_gateways";
pub const NUM_EXITS_KEY: &str = "num_exit_gateways";
pub const CURRENT_EPOCH_KEY: &str = "current_epoch";
pub const NEW_CURRENT_EPOCH_KEY: &str = "new_current_epoch";
pub const ROLE_KEY: &str = "role";
pub const NODE_COUNT_KEY: &str = "node_count";
// interval
pub const EVENTS_EXECUTED_KEY: &str = "number_of_events_executed";
pub const EVENT_CREATION_HEIGHT_KEY: &str = "created_at";
@@ -163,7 +181,7 @@ pub fn new_delegation_event(
created_at: BlockHeight,
delegator: &Addr,
amount: &Coin,
mix_id: MixId,
mix_id: NodeId,
unit_reward: Decimal,
) -> Event {
Event::new(MixnetEventType::Delegation)
@@ -174,45 +192,57 @@ pub fn new_delegation_event(
.add_attribute(UNIT_REWARD_KEY, unit_reward.to_string())
}
pub fn new_delegation_on_unbonded_node_event(delegator: &Addr, mix_id: MixId) -> Event {
pub fn new_delegation_on_unbonded_node_event(delegator: &Addr, mix_id: NodeId) -> Event {
Event::new(MixnetEventType::Delegation)
.add_attribute(DELEGATOR_KEY, delegator)
.add_attribute(DELEGATION_TARGET_KEY, mix_id.to_string())
}
pub fn new_pending_delegation_event(delegator: &Addr, amount: &Coin, mix_id: MixId) -> Event {
pub fn new_pending_delegation_event(delegator: &Addr, amount: &Coin, mix_id: NodeId) -> Event {
Event::new(MixnetEventType::PendingDelegation)
.add_attribute(DELEGATOR_KEY, delegator)
.add_attribute(AMOUNT_KEY, amount.to_string())
.add_attribute(DELEGATION_TARGET_KEY, mix_id.to_string())
}
pub fn new_withdraw_operator_reward_event(owner: &Addr, amount: Coin, mix_id: MixId) -> Event {
pub fn new_withdraw_operator_reward_event(owner: &Addr, amount: Coin, mix_id: NodeId) -> Event {
Event::new(MixnetEventType::WithdrawOperatorReward)
.add_attribute(OWNER_KEY, owner.as_str())
.add_attribute(AMOUNT_KEY, amount.to_string())
.add_attribute(MIX_ID_KEY, mix_id.to_string())
}
pub fn new_withdraw_delegator_reward_event(delegator: &Addr, amount: Coin, mix_id: MixId) -> Event {
pub fn new_withdraw_delegator_reward_event(
delegator: &Addr,
amount: Coin,
mix_id: NodeId,
) -> Event {
Event::new(MixnetEventType::WithdrawDelegatorReward)
.add_attribute(DELEGATOR_KEY, delegator)
.add_attribute(AMOUNT_KEY, amount.to_string())
.add_attribute(DELEGATION_TARGET_KEY, mix_id.to_string())
}
pub fn new_active_set_update_event(created_at: BlockHeight, new_size: u32) -> Event {
pub fn new_active_set_update_failure(err: MixnetContractError) -> Event {
Event::new(MixnetEventType::ActiveSetUpdate).add_attribute(ERROR_MESSAGE_KEY, err.to_string())
}
pub fn new_active_set_update_event(created_at: BlockHeight, update: ActiveSetUpdate) -> Event {
Event::new(MixnetEventType::ActiveSetUpdate)
.add_attribute(EVENT_CREATION_HEIGHT_KEY, created_at.to_string())
.add_attribute(ACTIVE_SET_SIZE_KEY, new_size.to_string())
.add_attribute(NUM_MIXNODES_KEY, update.mixnodes.to_string())
.add_attribute(NUM_ENTRIES_KEY, update.entry_gateways.to_string())
.add_attribute(NUM_EXITS_KEY, update.exit_gateways.to_string())
}
pub fn new_pending_active_set_update_event(
new_size: u32,
update: ActiveSetUpdate,
approximate_time_remaining_secs: i64,
) -> Event {
Event::new(MixnetEventType::PendingActiveSetUpdate)
.add_attribute(ACTIVE_SET_SIZE_KEY, new_size.to_string())
.add_attribute(NUM_MIXNODES_KEY, update.mixnodes.to_string())
.add_attribute(NUM_ENTRIES_KEY, update.entry_gateways.to_string())
.add_attribute(NUM_EXITS_KEY, update.exit_gateways.to_string())
.add_attribute(
APPROXIMATE_TIME_LEFT_SECS_KEY,
approximate_time_remaining_secs.to_string(),
@@ -221,7 +251,6 @@ pub fn new_pending_active_set_update_event(
pub fn new_rewarding_params_update_event(
created_at: BlockHeight,
update: IntervalRewardingParamsUpdate,
updated: IntervalRewardParams,
) -> Event {
@@ -252,30 +281,19 @@ pub fn new_pending_rewarding_params_update_event(
)
}
pub fn new_undelegation_event(created_at: BlockHeight, delegator: &Addr, mix_id: MixId) -> Event {
pub fn new_undelegation_event(created_at: BlockHeight, delegator: &Addr, mix_id: NodeId) -> Event {
Event::new(MixnetEventType::Undelegation)
.add_attribute(EVENT_CREATION_HEIGHT_KEY, created_at.to_string())
.add_attribute(DELEGATOR_KEY, delegator)
.add_attribute(MIX_ID_KEY, mix_id.to_string())
}
pub fn new_pending_undelegation_event(delegator: &Addr, mix_id: MixId) -> Event {
pub fn new_pending_undelegation_event(delegator: &Addr, mix_id: NodeId) -> Event {
Event::new(MixnetEventType::PendingUndelegation)
.add_attribute(DELEGATOR_KEY, delegator)
.add_attribute(MIX_ID_KEY, mix_id.to_string())
}
pub fn new_gateway_bonding_event(
owner: &Addr,
amount: &Coin,
identity: IdentityKeyRef<'_>,
) -> Event {
Event::new(MixnetEventType::GatewayBonding)
.add_attribute(OWNER_KEY, owner)
.add_attribute(NODE_IDENTITY_KEY, identity)
.add_attribute(AMOUNT_KEY, amount.to_string())
}
pub fn new_gateway_unbonding_event(
owner: &Addr,
amount: &Coin,
@@ -287,49 +305,85 @@ pub fn new_gateway_unbonding_event(
.add_attribute(AMOUNT_KEY, amount.to_string())
}
pub fn new_mixnode_bonding_event(
pub fn new_nym_node_bonding_event(
owner: &Addr,
amount: &Coin,
identity: IdentityKeyRef<'_>,
mix_id: MixId,
assigned_layer: Layer,
node_id: NodeId,
) -> Event {
// coin implements Display trait and we use that implementation here
Event::new(MixnetEventType::MixnodeBonding)
.add_attribute(MIX_ID_KEY, mix_id.to_string())
Event::new(MixnetEventType::NymNodeBonding)
.add_attribute(NODE_ID_KEY, node_id.to_string())
.add_attribute(NODE_IDENTITY_KEY, identity)
.add_attribute(OWNER_KEY, owner)
.add_attribute(ASSIGNED_LAYER_KEY, assigned_layer)
.add_attribute(AMOUNT_KEY, amount.to_string())
}
pub fn new_pending_pledge_increase_event(mix_id: MixId, amount: &Coin) -> Event {
pub fn new_nym_node_unbonding_event(created_at: BlockHeight, node_id: NodeId) -> Event {
Event::new(MixnetEventType::NymNodeUnbonding)
.add_attribute(EVENT_CREATION_HEIGHT_KEY, created_at.to_string())
.add_attribute(NODE_ID_KEY, node_id.to_string())
}
pub fn new_pending_nym_node_unbonding_event(
owner: &Addr,
identity: IdentityKeyRef<'_>,
node_id: NodeId,
) -> Event {
Event::new(MixnetEventType::PendingNymNodeUnbonding)
.add_attribute(NODE_ID_KEY, node_id.to_string())
.add_attribute(NODE_IDENTITY_KEY, identity)
.add_attribute(OWNER_KEY, owner)
}
pub fn new_migrated_gateway_event(
owner: &Addr,
identity: IdentityKeyRef<'_>,
node_id: NodeId,
) -> Event {
Event::new(MixnetEventType::GatewayMigration)
.add_attribute(NODE_ID_KEY, node_id.to_string())
.add_attribute(NODE_IDENTITY_KEY, identity)
.add_attribute(OWNER_KEY, owner)
}
pub fn new_migrated_mixnode_event(
owner: &Addr,
identity: IdentityKeyRef<'_>,
node_id: NodeId,
) -> Event {
Event::new(MixnetEventType::MixnodeMigration)
.add_attribute(NODE_ID_KEY, node_id.to_string())
.add_attribute(NODE_IDENTITY_KEY, identity)
.add_attribute(OWNER_KEY, owner)
}
pub fn new_pending_pledge_increase_event(node_id: NodeId, amount: &Coin) -> Event {
Event::new(MixnetEventType::PendingPledgeIncrease)
.add_attribute(MIX_ID_KEY, mix_id.to_string())
.add_attribute(NODE_ID_KEY, node_id.to_string())
.add_attribute(AMOUNT_KEY, amount.to_string())
}
pub fn new_pledge_increase_event(created_at: BlockHeight, mix_id: MixId, amount: &Coin) -> Event {
pub fn new_pledge_increase_event(created_at: BlockHeight, node_id: NodeId, amount: &Coin) -> Event {
Event::new(MixnetEventType::PledgeIncrease)
.add_attribute(EVENT_CREATION_HEIGHT_KEY, created_at.to_string())
.add_attribute(MIX_ID_KEY, mix_id.to_string())
.add_attribute(NODE_ID_KEY, node_id.to_string())
.add_attribute(AMOUNT_KEY, amount.to_string())
}
pub fn new_pending_pledge_decrease_event(mix_id: MixId, amount: &Coin) -> Event {
pub fn new_pending_pledge_decrease_event(node_id: NodeId, amount: &Coin) -> Event {
Event::new(MixnetEventType::PendingPledgeDecrease)
.add_attribute(MIX_ID_KEY, mix_id.to_string())
.add_attribute(NODE_ID_KEY, node_id.to_string())
.add_attribute(AMOUNT_KEY, amount.to_string())
}
pub fn new_pledge_decrease_event(created_at: BlockHeight, mix_id: MixId, amount: &Coin) -> Event {
pub fn new_pledge_decrease_event(created_at: BlockHeight, node_id: NodeId, amount: &Coin) -> Event {
Event::new(MixnetEventType::PledgeDecrease)
.add_attribute(EVENT_CREATION_HEIGHT_KEY, created_at.to_string())
.add_attribute(MIX_ID_KEY, mix_id.to_string())
.add_attribute(NODE_ID_KEY, node_id.to_string())
.add_attribute(AMOUNT_KEY, amount.to_string())
}
pub fn new_mixnode_unbonding_event(created_at: BlockHeight, mix_id: MixId) -> Event {
pub fn new_mixnode_unbonding_event(created_at: BlockHeight, mix_id: NodeId) -> Event {
Event::new(MixnetEventType::MixnodeUnbonding)
.add_attribute(EVENT_CREATION_HEIGHT_KEY, created_at.to_string())
.add_attribute(MIX_ID_KEY, mix_id.to_string())
@@ -338,7 +392,7 @@ pub fn new_mixnode_unbonding_event(created_at: BlockHeight, mix_id: MixId) -> Ev
pub fn new_pending_mixnode_unbonding_event(
owner: &Addr,
identity: IdentityKeyRef<'_>,
mix_id: MixId,
mix_id: NodeId,
) -> Event {
Event::new(MixnetEventType::PendingMixnodeUnbonding)
.add_attribute(MIX_ID_KEY, mix_id.to_string())
@@ -347,7 +401,7 @@ pub fn new_pending_mixnode_unbonding_event(
}
pub fn new_mixnode_config_update_event(
mix_id: MixId,
mix_id: NodeId,
owner: &Addr,
update: &MixNodeConfigUpdate,
) -> Event {
@@ -363,23 +417,18 @@ pub fn new_gateway_config_update_event(owner: &Addr, update: &GatewayConfigUpdat
.add_attribute(UPDATED_GATEWAY_CONFIG_KEY, update.to_inline_json())
}
pub fn new_mixnode_pending_cost_params_update_event(
mix_id: MixId,
owner: &Addr,
new_costs: &MixNodeCostParams,
) -> Event {
Event::new(MixnetEventType::PendingMixnodeCostParamsUpdate)
.add_attribute(MIX_ID_KEY, mix_id.to_string())
.add_attribute(OWNER_KEY, owner)
pub fn new_pending_cost_params_update_event(mix_id: NodeId, new_costs: &NodeCostParams) -> Event {
Event::new(MixnetEventType::PendingCostParamsUpdate)
.add_attribute(NODE_ID_KEY, mix_id.to_string())
.add_attribute(UPDATED_MIXNODE_COST_PARAMS_KEY, new_costs.to_inline_json())
}
pub fn new_mixnode_cost_params_update_event(
pub fn new_cost_params_update_event(
created_at: BlockHeight,
mix_id: MixId,
new_costs: &MixNodeCostParams,
mix_id: NodeId,
new_costs: &NodeCostParams,
) -> Event {
Event::new(MixnetEventType::MixnodeCostParamsUpdate)
Event::new(MixnetEventType::CostParamsUpdate)
.add_attribute(EVENT_CREATION_HEIGHT_KEY, created_at.to_string())
.add_attribute(MIX_ID_KEY, mix_id.to_string())
.add_attribute(UPDATED_MIXNODE_COST_PARAMS_KEY, new_costs.to_inline_json())
@@ -397,37 +446,25 @@ pub fn new_settings_update_event(
) -> Event {
let mut event = Event::new(MixnetEventType::ContractSettingsUpdate);
if old_params.minimum_mixnode_pledge != new_params.minimum_mixnode_pledge {
if old_params.minimum_pledge != new_params.minimum_pledge {
event = event
.add_attribute(
OLD_MINIMUM_MIXNODE_PLEDGE_KEY,
old_params.minimum_mixnode_pledge.to_string(),
OLD_MINIMUM_PLEDGE_KEY,
old_params.minimum_pledge.to_string(),
)
.add_attribute(
NEW_MINIMUM_MIXNODE_PLEDGE_KEY,
new_params.minimum_mixnode_pledge.to_string(),
NEW_MINIMUM_PLEDGE_KEY,
new_params.minimum_pledge.to_string(),
)
}
if old_params.minimum_gateway_pledge != new_params.minimum_gateway_pledge {
event = event
.add_attribute(
OLD_MINIMUM_GATEWAY_PLEDGE_KEY,
old_params.minimum_gateway_pledge.to_string(),
)
.add_attribute(
NEW_MINIMUM_GATEWAY_PLEDGE_KEY,
new_params.minimum_gateway_pledge.to_string(),
)
}
if old_params.minimum_mixnode_delegation != new_params.minimum_mixnode_delegation {
if let Some(ref old) = old_params.minimum_mixnode_delegation {
if old_params.minimum_delegation != new_params.minimum_delegation {
if let Some(ref old) = old_params.minimum_delegation {
event = event.add_attribute(OLD_MINIMUM_DELEGATION_KEY, old.to_string())
} else {
event = event.add_attribute(OLD_MINIMUM_DELEGATION_KEY, "None")
}
if let Some(ref new) = new_params.minimum_mixnode_delegation {
if let Some(ref new) = new_params.minimum_delegation {
event = event.add_attribute(NEW_MINIMUM_DELEGATION_KEY, new.to_string())
} else {
event = event.add_attribute(NEW_MINIMUM_DELEGATION_KEY, "None")
@@ -437,41 +474,41 @@ pub fn new_settings_update_event(
event
}
pub fn new_not_found_mix_operator_rewarding_event(interval: Interval, mix_id: MixId) -> Event {
Event::new(MixnetEventType::MixnodeRewarding)
pub fn new_not_found_node_operator_rewarding_event(interval: Interval, node_id: NodeId) -> Event {
Event::new(MixnetEventType::NodeRewarding)
.add_attribute(
INTERVAL_KEY,
interval.current_epoch_absolute_id().to_string(),
)
.add_attribute(MIX_ID_KEY, mix_id.to_string())
.add_attribute(NODE_ID_KEY, node_id.to_string())
.add_attribute(NO_REWARD_REASON_KEY, BOND_NOT_FOUND_VALUE)
}
pub fn new_zero_uptime_mix_operator_rewarding_event(interval: Interval, mix_id: MixId) -> Event {
Event::new(MixnetEventType::MixnodeRewarding)
pub fn new_zero_uptime_mix_operator_rewarding_event(interval: Interval, node_id: NodeId) -> Event {
Event::new(MixnetEventType::NodeRewarding)
.add_attribute(
INTERVAL_KEY,
interval.current_epoch_absolute_id().to_string(),
)
.add_attribute(MIX_ID_KEY, mix_id.to_string())
.add_attribute(NO_REWARD_REASON_KEY, ZERO_PERFORMANCE_VALUE)
.add_attribute(NODE_ID_KEY, node_id.to_string())
.add_attribute(NO_REWARD_REASON_KEY, ZERO_PERFORMANCE_OR_WORK_VALUE)
}
pub fn new_mix_rewarding_event(
interval: Interval,
mix_id: MixId,
node_id: NodeId,
reward_distribution: RewardDistribution,
prior_delegates: Decimal,
prior_unit_reward: Decimal,
) -> Event {
Event::new(MixnetEventType::MixnodeRewarding)
Event::new(MixnetEventType::NodeRewarding)
.add_attribute(
INTERVAL_KEY,
interval.current_epoch_absolute_id().to_string(),
)
.add_attribute(PRIOR_DELEGATES_KEY, prior_delegates.to_string())
.add_attribute(PRIOR_UNIT_REWARD_KEY, prior_unit_reward.to_string())
.add_attribute(MIX_ID_KEY, mix_id.to_string())
.add_attribute(NODE_ID_KEY, node_id.to_string())
.add_attribute(
OPERATOR_REWARD_KEY,
reward_distribution.operator.to_string(),
@@ -489,13 +526,15 @@ pub fn new_epoch_transition_start_event(current_interval: Interval) -> Event {
)
}
pub fn new_advance_epoch_event(interval: Interval, rewarded_nodes: u32) -> Event {
pub fn new_assigned_role_event(role: Role, nodes: u32) -> Event {
Event::new(MixnetEventType::RoleAssignment)
.add_attribute(ROLE_KEY, role.to_string())
.add_attribute(NODE_COUNT_KEY, nodes.to_string())
}
pub fn new_advance_epoch_event(epoch_id: EpochId) -> Event {
Event::new(MixnetEventType::AdvanceEpoch)
.add_attribute(
NEW_CURRENT_EPOCH_KEY,
interval.current_epoch_absolute_id().to_string(),
)
.add_attribute(REWARDED_SET_NODES_KEY, rewarded_nodes.to_string())
.add_attribute(NEW_CURRENT_EPOCH_KEY, epoch_id.to_string())
}
pub fn new_pending_epoch_events_execution_event(executed: u32) -> Event {
@@ -1,189 +0,0 @@
// Copyright 2022-2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::{IdentityKey, IdentityKeyRef};
use cosmwasm_schema::cw_serde;
use schemars::JsonSchema;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::fmt::{Display, Formatter};
use std::str::FromStr;
/// A group of mixnodes associated with particular staking entity.
/// When defined all nodes belonging to the same family will be prioritised to be put onto the same layer.
#[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))]
#[cfg_attr(
feature = "generate-ts",
ts(export_to = "ts-packages/types/src/types/rust/NodeFamily.ts")
)]
#[cw_serde]
pub struct Family {
/// Owner of this family.
head: FamilyHead,
/// Optional proxy (i.e. vesting contract address) used when creating the family.
proxy: Option<String>,
/// Human readable label for this family.
label: String,
}
/// Head of particular family as identified by its identity key (i.e. public component of its ed25519 keypair stringified into base58).
#[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))]
#[cfg_attr(
feature = "generate-ts",
ts(export_to = "ts-packages/types/src/types/rust/NodeFamilyHead.ts")
)]
#[derive(Debug, Clone, Eq, PartialEq, JsonSchema)]
pub struct FamilyHead(IdentityKey);
impl Serialize for FamilyHead {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
self.0.serialize(serializer)
}
}
impl<'de> Deserialize<'de> for FamilyHead {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let inner = IdentityKey::deserialize(deserializer)?;
Ok(FamilyHead(inner))
}
}
impl FromStr for FamilyHead {
type Err = <IdentityKey as FromStr>::Err;
fn from_str(s: &str) -> Result<Self, Self::Err> {
// theoretically we should be verifying whether it's a valid base58 value
// (or even better, whether it's a valid ed25519 public key), but definition of
// `FamilyHead` might change later
Ok(FamilyHead(IdentityKey::from_str(s)?))
}
}
impl Display for FamilyHead {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
self.0.fmt(f)
}
}
impl FamilyHead {
pub fn new<S: Into<String>>(identity: S) -> Self {
FamilyHead(identity.into())
}
pub fn identity(&self) -> IdentityKeyRef<'_> {
&self.0
}
}
impl Family {
pub fn new(head: FamilyHead, label: String) -> Self {
Family {
head,
proxy: None,
label,
}
}
#[allow(dead_code)]
pub fn head(&self) -> &FamilyHead {
&self.head
}
pub fn head_identity(&self) -> IdentityKeyRef<'_> {
self.head.identity()
}
#[allow(dead_code)]
pub fn proxy(&self) -> Option<&String> {
self.proxy.as_ref()
}
pub fn label(&self) -> &str {
&self.label
}
}
/// Response containing paged list of all families registered in the contract.
#[cw_serde]
pub struct PagedFamiliesResponse {
/// The families registered in the contract.
pub families: Vec<Family>,
/// Field indicating paging information for the following queries if the caller wishes to get further entries.
pub start_next_after: Option<String>,
}
/// Response containing paged list of all family members (of ALL families) registered in the contract.
#[cw_serde]
pub struct PagedMembersResponse {
/// The members alongside their family heads.
pub members: Vec<(IdentityKey, FamilyHead)>,
/// Field indicating paging information for the following queries if the caller wishes to get further entries.
pub start_next_after: Option<String>,
}
/// Response containing family information.
#[cw_serde]
pub struct FamilyByHeadResponse {
/// The family head used for the query.
pub head: FamilyHead,
/// If applicable, the family associated with the provided head.
pub family: Option<Family>,
}
/// Response containing family information.
#[cw_serde]
pub struct FamilyByLabelResponse {
/// The family label used for the query.
pub label: String,
/// If applicable, the family associated with the provided label.
pub family: Option<Family>,
}
/// Response containing family members information.
#[cw_serde]
pub struct FamilyMembersByHeadResponse {
/// The family head used for the query.
pub head: FamilyHead,
/// All members belonging to the specified family.
pub members: Vec<IdentityKey>,
}
/// Response containing family members information.
#[cw_serde]
pub struct FamilyMembersByLabelResponse {
/// The family label used for the query.
pub label: String,
/// All members belonging to the specified family.
pub members: Vec<IdentityKey>,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn family_head_serde() {
let dummy = FamilyHead::new("foomp");
let ser_str = serde_json_wasm::to_string(&dummy).unwrap();
let de_str: FamilyHead = serde_json_wasm::from_str(&ser_str).unwrap();
assert_eq!(dummy, de_str);
let ser_bytes = serde_json_wasm::to_vec(&dummy).unwrap();
let de_bytes: FamilyHead = serde_json_wasm::from_slice(&ser_bytes).unwrap();
assert_eq!(dummy, de_bytes);
}
}
@@ -1,7 +1,7 @@
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::{IdentityKey, SphinxKey};
use crate::{IdentityKey, NodeId, SphinxKey};
use cosmwasm_schema::cw_serde;
use cosmwasm_std::{Addr, Coin};
use std::cmp::Ordering;
@@ -135,7 +135,10 @@ impl Display for GatewayBond {
#[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))]
#[cfg_attr(
feature = "generate-ts",
ts(export_to = "ts-packages/types/src/types/rust/GatewayConfigUpdate.ts")
ts(
export,
export_to = "ts-packages/types/src/types/rust/GatewayConfigUpdate.ts"
)
)]
#[cw_serde]
pub struct GatewayConfigUpdate {
@@ -200,6 +203,23 @@ pub struct GatewayBondResponse {
pub gateway: Option<GatewayBond>,
}
#[cw_serde]
pub struct PreassignedId {
/// The identity key (base58-encoded ed25519 public key) of the gateway.
pub identity: IdentityKey,
/// The id pre-assigned to this gateway
pub node_id: NodeId,
}
#[cw_serde]
pub struct PreassignedGatewayIdsResponse {
pub ids: Vec<PreassignedId>,
/// Field indicating paging information for the following queries if the caller wishes to get further entries.
pub start_next_after: Option<IdentityKey>,
}
#[cfg(test)]
mod tests {
use super::*;

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