Compare commits

..

18 Commits

Author SHA1 Message Date
Jędrzej Stuczyński f4492b4b13 Manual merge of #810 2021-10-11 10:55:03 +01:00
Jędrzej Stuczyński 5585a83e3e Unused import 2021-10-11 10:46:28 +01:00
Jędrzej Stuczyński 308af24881 Using default rocket build (that uses Rocket.toml) 2021-10-04 10:54:09 +01:00
Jędrzej Stuczyński 50d7fc73cb Loosened some argument restrictions for the sake of easier deployments 2021-09-30 15:13:08 +01:00
Jędrzej Stuczyński 01043d7940 Removed invalid field from validator-api config field 2021-09-30 15:00:45 +01:00
Jędrzej Stuczyński 2d1961b8be Removed use of coconut in validator-api and gateway 2021-09-28 10:55:14 +01:00
Jędrzej Stuczyński e891c68158 Created getters for AccountData (#787) 2021-09-27 12:16:16 +02:00
Jędrzej Stuczyński b1fb032f43 Removed SQLx offline mode artifact (#790) 2021-09-27 12:06:13 +02:00
Jędrzej Stuczyński 23ea82952e Bugfix/validator api windows build (#791)
* Use https://github.com/nymtech/nym/pull/784/commits/3eceb349c695372cbb7a3bee9aa5e090da7c9c4d trick to make build.rs work with windows

* Re-enabled validator-api windows CI build
2021-09-27 12:05:53 +02:00
Drazen Urch 9a65e44166 Add Tauri wallet
--
Squashed commit of the following:

commit 3f4f9073b7
Author: Drazen Urch <durch@users.noreply.guthub.com>
Date:   Mon Sep 27 11:38:12 2021 +0200

    Delete .lock for merge

commit bf502f6338
Author: Drazen Urch <durch@users.noreply.guthub.com>
Date:   Mon Sep 27 11:36:51 2021 +0200

    Squashed commit of the following:

    commit 020cad897d
    Author: Jędrzej Stuczyński <jedrzej.stuczynski@gmail.com>
    Date:   Fri Sep 24 15:49:21 2021 +0100

        Feature/rust rewarding (#750)

        * Calculating gas fees

        * Ability to set custom fees

        * Added extra test

        * Removed commented code

        * Moved all msg types to common contract crate

        * Temporarily disabling get_tx method

        * Finishing up nymd client API

        * Comment fix

        * Remaining fee values

        * Some cleanup

        * Removed needless borrow

        * Fixed imports in contract tests

        * Moved error types around

        * New ValidatorClient

        * Experiment with new type of defaults

        * Removed dead module

        * Dealt with unwrap

        * Migrated mixnode to use new validator client

        * Migrated gateway to use new validator client

        * Mixnode and gateway adjustments

        * More exported defaults

        * Clients using new validator client

        * Fixed mixnode upgrade

        * Moved default values to a new crate

        * Changed behaviour of validator client features

        * Migrated basic functions of validator api

        * Updated config + fixed startup

        * Fixed wasm client build

        * Integration with the explorer api

        * Removed tokio dev dependency

        * Needless borrow

        * Fixex wasm client build

        * Fixed tauri client build

        * Needless borrows

        * New tables for rewarding

        * Updated cosmos-sdk version

        * Removed reward-specific node status routes

        * New rewarding-specific config entries

        * Additional network defaults

        * Initial periodic rewards from validator api

        * Replaced print with log

        * Filtering nodes with uptime > 0

        * Additional failure logging statements

        * Fixed operation ordering

        * Adjusted next rewarding epoch determination

        * Modified rewarding behaviour to keep track of rewarding in progress

        * Improved error message on config load failure

        * Additional log statement

        * Adjusted rewarding gas limit calculation

        * Made naming slightly more consistent

        * Fixed incorrect parentheses placement

        * Fixed fee calculation

        * Cargo fmt

        * Removed failed merge artifacts

        * Introduced comment for any future reward modification

        * typos

        * Helper functions for the future

        * Making @mfahampshire 's life easier

        * Redesigned epoch + rewarding skipped epochs (if possible)

        * Removed old merge artifacts

        * Naming consistency

        * Constraining arguments

        * Removed unnecessary if branch

        * Ignore monitor check for current epoch

        * Additional checks for current epoch data

        * Monitor threshold check

        * cargo fmt

        * Fixed post-merge issues in transactions.rs

    commit 5dfaff6296
    Author: Drazen Urch <drazen@urch.eu>
    Date:   Tue Sep 21 10:59:17 2021 +0200

        Update hmac and blake3 (#673)

        * Update hmac and blake3

        * Remain paranoid for `0.*` crates

        * Most paranoid versions :)

        * Updated aes and using published version of blake3

        Co-authored-by: Jędrzej Stuczyński <jedrzej.stuczynski@gmail.com>

    commit 5b03982043
    Author: Jędrzej Stuczyński <jedrzej.stuczynski@gmail.com>
    Date:   Mon Sep 20 10:40:03 2021 +0100

        Replaced unwrap_or_else with unwrap_or_default (#780)

    commit 8f6856d6fb
    Author: Drazen Urch <drazen@urch.eu>
    Date:   Mon Sep 20 11:15:06 2021 +0200

        Make fee helpers public (#777)

        Co-authored-by: Drazen Urch <durch@users.noreply.guthub.com>

commit 80664b911f
Merge: f66ea059 46149012
Author: Fouad <fmtabbara@hotmail.co.uk>
Date:   Thu Sep 23 20:59:27 2021 +0100

    Merge pull request #783 from nymtech/tauri-wallet-frontend

    tauri wallet front-end

commit 46149012bd
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Thu Sep 23 17:42:34 2021 +0100

    PR updates

commit de601c319a
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Thu Sep 23 17:06:47 2021 +0100

    PR updates

commit 7318de23f2
Author: max <mfahampshire@gmail.com>
Date:   Wed Sep 22 18:07:29 2021 +0200

    added info on nym-wallet (tauri) in readme

commit 56e07753ea
Author: max <mfahampshire@gmail.com>
Date:   Wed Sep 22 14:44:22 2021 +0200

    added minimal readme for wallet

commit 21b008fae9
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Mon Sep 13 13:30:05 2021 +0100

    use wrapper functions for send and delegate

    form updates

    update working

    finish bonding and unbonding setup

    funds allocation check when bonding/sending/delegating

    update title

commit 27a202cbe8
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Fri Sep 17 11:32:41 2021 +0100

    integrate admin functions

    updates

    integrate admin form update function

commit 085538582b
Author: Drazen Urch <durch@users.noreply.guthub.com>
Date:   Fri Sep 17 10:43:26 2021 +0200

    Admin functions, reorganize code

commit f66ea05929
Author: Drazen Urch <durch@users.noreply.guthub.com>
Date:   Fri Sep 17 10:43:26 2021 +0200

    Admin functions, reorganize code

commit 052c7188ec
Merge: f6c316ee 976dd7aa
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Fri Sep 17 09:38:19 2021 +0100

    merge develop

commit f6c316eea9
Author: Drazen Urch <durch@users.noreply.guthub.com>
Date:   Thu Sep 16 18:02:15 2021 +0200

    fix typo

commit f33defc645
Author: Drazen Urch <durch@users.noreply.guthub.com>
Date:   Thu Sep 16 17:36:24 2021 +0200

    Squashed commit of the following:

    commit 976dd7aae2
    Author: Drazen Urch <drazen@urch.eu>
    Date:   Wed Sep 15 17:28:49 2021 +0200

        Add block_height method to Delegation (#778)

        Co-authored-by: Drazen Urch <durch@users.noreply.guthub.com>

    commit 0d21f4e937
    Merge: e84af4f6 1403449a
    Author: Fouad <fmtabbara@hotmail.co.uk>
    Date:   Wed Sep 15 12:41:29 2021 +0100

        Merge pull request #776 from nymtech/update/re-enable-bonding

        re-enable bonding

    commit 1403449ad5
    Author: fmtabbara <fmtabbara@hotmail.co.uk>
    Date:   Tue Sep 14 16:00:21 2021 +0100

        enable bonding

    commit e84af4f601
    Author: Drazen Urch <drazen@urch.eu>
    Date:   Tue Sep 14 15:15:26 2021 +0200

        Migrate legacy delegation data (#771)

        * Skip ReadOnlyBucket deserialization errors

        * empty migration

        * clippy

        * cargo schema

        * Drop invalid delegation data

        * Dont drop old data

        * Add todo

        * Unify on type param

        * gateways are different

        * cargo fmt

        Co-authored-by: Drazen Urch <durch@users.noreply.guthub.com>

    commit 26b032c15c
    Merge: e1ddaff0 cba36253
    Author: Mark Sinclair <mmsinclair@gmail.com>
    Date:   Tue Sep 14 10:09:14 2021 +0100

        Merge pull request #774 from nymtech/feature/explorer-api-delegations

        Explorer-api: add API resource to show the delegations for each mix node

    commit cba3625394
    Author: Mark Sinclair <mmsinclair@gmail.com>
    Date:   Mon Sep 13 10:33:41 2021 +0100

        explorer-api: add API resource to show the delegations for each mix node

    commit e1ddaff04d
    Merge: 0b9c03ca 66ab5de4
    Author: Fouad <fmtabbara@hotmail.co.uk>
    Date:   Fri Sep 10 17:17:14 2021 +0100

        Merge pull request #772 from nymtech/update/disable-bonding

        add app alert

    commit 66ab5de442
    Author: fmtabbara <fmtabbara@hotmail.co.uk>
    Date:   Fri Sep 10 16:16:58 2021 +0100

        add app alert

    commit 0b9c03ca90
    Author: Dave Hrycyszyn <futurechimp@users.noreply.github.com>
    Date:   Fri Sep 10 11:23:21 2021 +0300

        Adding deps for building the Tauri wallet under Ubuntu (#770)

    commit c9dce0c1da
    Author: Bogdan-Ștefan Neacşu <bogdan@nymtech.net>
    Date:   Thu Sep 9 11:21:45 2021 +0200

        Feature/consumable bandwidth (#766)

        * Set actual value for bandwidth

        Also put it as a public attribute, such that it can be actively used
        by the credential consumer

        * Switch from sending Attribute structs to sending the actual attribute bytes over the wire

        * Add atomic bandwidth value to gateway

        * Consume bandwidth based on the mix packet size

        * Use Bandwidth struct for specific functionality

        * Move bandwidth code outside the dependency path of wasm client

        * Use u64 instead of AtomicU64, as the handling is not parallel

    commit e00e77db15
    Author: Bogdan-Ștefan Neacşu <bogdan@nymtech.net>
    Date:   Wed Sep 8 15:07:24 2021 +0200

        Feature/bond blockstamp (#760)

        * Add block_height to MixNode/GatewayBond

        * Reward based on blockstamp of bonded node or of delegation

        * Add specific tests

        * Add migration code

        * Apply doc nit

    commit 1074449f91
    Merge: 08276e6e 9a3d824a
    Author: Fouad <fmtabbara@hotmail.co.uk>
    Date:   Tue Sep 7 23:45:10 2021 +0100

        Merge pull request #767 from nymtech/update/remove-app-alert

        remove alert

    commit 08276e6e42
    Author: Bogdan-Ștefan Neacşu <bogdan@nymtech.net>
    Date:   Tue Sep 7 16:33:30 2021 +0200

        Remove migration code (#759)

    commit 9a3d824a4a
    Author: fmtabbara <fmtabbara@hotmail.co.uk>
    Date:   Mon Sep 6 20:39:24 2021 +0100

        remove alert

    commit 2789ee8f18
    Author: Bogdan-Ștefan Neacşu <bogdan@nymtech.net>
    Date:   Fri Sep 3 15:30:45 2021 +0300

        Update coconut-rs and use hash_to_scalar from there (#765)

        Failed tests are due to some nightly issue, not related to this PR

    commit a7ba643c35
    Merge: 28be53ee c42f3c68
    Author: Fouad <fmtabbara@hotmail.co.uk>
    Date:   Fri Sep 3 09:14:50 2021 +0100

        Merge pull request #762 from nymtech/feature/app-alert

        add app alert banner

    commit 28be53eefb
    Author: Bogdan-Ștefan Neacşu <bogdan@nymtech.net>
    Date:   Thu Sep 2 18:26:40 2021 +0300

        Add block_height in the Delegation structure as well (#757)

    commit 219c45a352
    Author: Jędrzej Stuczyński <jedrzej.stuczynski@gmail.com>
    Date:   Thu Sep 2 15:48:29 2021 +0100

        Updated cosmos-sdk (#761)

        * Updated cosmos-sdk

        * Re-exposing more things

    commit 1a3b83752e
    Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
    Date:   Thu Sep 2 15:45:56 2021 +0100

        Bump next from 11.1.0 to 11.1.1 in /wallet-web (#758)

        Bumps [next](https://github.com/vercel/next.js) from 11.1.0 to 11.1.1.
        - [Release notes](https://github.com/vercel/next.js/releases)
        - [Changelog](https://github.com/vercel/next.js/blob/canary/release.js)
        - [Commits](https://github.com/vercel/next.js/compare/v11.1.0...v11.1.1)

        ---
        updated-dependencies:
        - dependency-name: next
          dependency-type: direct:production
        ...

        Signed-off-by: dependabot[bot] <support@github.com>

        Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

    commit c42f3c6844
    Author: fmtabbara <fmtabbara@hotmail.co.uk>
    Date:   Thu Sep 2 12:29:47 2021 +0100

        add app alert banner

    commit a5d3ba3900
    Merge: 92e13a5d cdf0d443
    Author: Mark Sinclair <mmsinclair@gmail.com>
    Date:   Tue Aug 31 15:59:11 2021 +0100

        Merge pull request #755 from nymtech/bugfix/explorer-api-ping

        Explorer API: port test now split out address resolution and add units tests

    commit cdf0d44341
    Author: Mark Sinclair <mmsinclair@gmail.com>
    Date:   Tue Aug 31 14:37:28 2021 +0100

        explorer-api: turned down logging from `error` to `warn`

    commit 92f976a45d
    Author: Mark Sinclair <mmsinclair@gmail.com>
    Date:   Fri Aug 27 11:34:21 2021 +0100

        explorer-api: sanitize hostname before running checks to avoid leading or trailing spaces that are known to exist in the current test net

    commit 2bc858cde3
    Author: Mark Sinclair <mmsinclair@gmail.com>
    Date:   Fri Aug 27 09:32:26 2021 +0100

        explorer-api: port test: split out address resolution and add units tests

    commit 92e13a5d00
    Author: Bogdan-Ștefan Neacşu <bogdan@nymtech.net>
    Date:   Tue Aug 31 14:51:15 2021 +0300

        Feature/add blockstamp (#756)

        * Add RawDelegationData

        * Fix current tests for the new stored data

        * Added migration commit. Will be reverted after doing the migration

        * New tests for block height

        * Use current blockstamp instead of 24h old one

        * Put _alot_ of migration stuff in the migrate function scope

    commit 122f5d9f2e
    Author: Bogdan-Ștefan Neacşu <bogdan@nymtech.net>
    Date:   Mon Aug 30 10:27:20 2021 +0300

        Feature/cred after handshake (#745)

        * Call perform_initial_authentication instead of register in clients

        * Refactor the register/authenticate functions a bit

        * Introduce Bandwidth request type

        * Add encryption layer to cred

        * Remove cred pass and check from handshake

        * Replaced unreachable!  with error

        * Changed decrypt_tagged signature to not take mutable ownership of data

        * Put handle_bandwidth work inside a function

        * Add check before unwrap

        * Remove unnecessary async

        * Decouple bandwidth credential from authentication

        * Use new_error for ServerResponse:Error

        * Send a fresh IV each time the BandwidthCredential request is sent

        * Remove unwrap of bincode::serialize

        * Add comment regarding Bandwidth response

        * Remove _mut from naming

        * Leave Debug trait alone, as the initial error doesn't reproduce anymore

        * Pass iv as Vec<u8> instead of base58 string

        * Renamed AuthenticationIV to IV, as it is now used for more the just authentication

        * Did some IV refactorization

    commit 982ee0266c
    Author: Bogdan-Ștefan Neacşu <bogdan@nymtech.net>
    Date:   Fri Aug 27 16:02:34 2021 +0300

        Feature/get own delegations (#748)

        * Introduce reverse delegation bucket

        * Add client command

        * Fix clippy error

        * Added tests in queries

        * Add tests in transactions

        * Migration code. Will be reverted after it's called on testnet

        * Replace unwrap with expect

        * Move some test code in the right file...

        ... to remove unnecessary auxiliary function.

        * Reduce the scope to migration auxiliary functions

        * Rename everything from [node]reverse to reverse[node]

        * Fix fmt

    commit 5f42a9bd05
    Author: Jędrzej Stuczyński <jedrzej.stuczynski@gmail.com>
    Date:   Fri Aug 27 13:52:18 2021 +0100

        NetworkMonitorBuilder - starting the monitor after rocket has launched (#754)

        * NetworkMonitorBuilder - starting the monitor after rocket has launched

        * Removed unused import

    commit 1811df9ddb
    Author: Jędrzej Stuczyński <jedrzej.stuczynski@gmail.com>
    Date:   Fri Aug 27 13:52:10 2021 +0100

        Enabled validators api argument (#753)

    commit 6bdfe7f895
    Author: Jędrzej Stuczyński <jedrzej.stuczynski@gmail.com>
    Date:   Thu Aug 26 11:21:01 2021 +0100

        Correctly bounding nominator of uptime calculation (#752)

    commit c6b286a1db
    Author: Jędrzej Stuczyński <jedrzej.stuczynski@gmail.com>
    Date:   Wed Aug 25 14:50:57 2021 +0100

        Fixed argument parsing for ipv6 'good' topology (#751)

    commit b3568a26f5
    Author: Bogdan-Ștefan Neacşu <bogdan@nymtech.net>
    Date:   Tue Aug 24 11:25:05 2021 +0300

        Revert "Migration commit, will be reverted after the testnet contract is updated" (#749)

        This reverts commit 38d868bcce.

    commit 15ae0f521e
    Author: Jędrzej Stuczyński <jedrzej.stuczynski@gmail.com>
    Date:   Mon Aug 23 10:26:51 2021 +0100

        Feature/more reliable uptime calculation (#747)

        * New database table holding monitor run info

        * SQL interface for new table

        * Updated uptime calculation to instead rely on number of monitor test runs

    commit 2923d4b872
    Author: Bogdan-Ștefan Neacşu <bogdan@nymtech.net>
    Date:   Thu Aug 19 22:03:07 2021 +0300

        Update template toml key (#746)

commit 424230c3bb
Author: Drazen Urch <durch@users.noreply.guthub.com>
Date:   Thu Sep 16 17:33:20 2021 +0200

    Squashed commit of the following:

    commit cddd9e8e4c
    Merge: 40fbdff0 976dd7aa
    Author: Drazen Urch <durch@users.noreply.guthub.com>
    Date:   Thu Sep 16 17:27:27 2021 +0200

        Merge branch 'develop' into tauri-wallet

    commit 976dd7aae2
    Author: Drazen Urch <drazen@urch.eu>
    Date:   Wed Sep 15 17:28:49 2021 +0200

        Add block_height method to Delegation (#778)

        Co-authored-by: Drazen Urch <durch@users.noreply.guthub.com>

    commit 0d21f4e937
    Merge: e84af4f6 1403449a
    Author: Fouad <fmtabbara@hotmail.co.uk>
    Date:   Wed Sep 15 12:41:29 2021 +0100

        Merge pull request #776 from nymtech/update/re-enable-bonding

        re-enable bonding

    commit 1403449ad5
    Author: fmtabbara <fmtabbara@hotmail.co.uk>
    Date:   Tue Sep 14 16:00:21 2021 +0100

        enable bonding

    commit e84af4f601
    Author: Drazen Urch <drazen@urch.eu>
    Date:   Tue Sep 14 15:15:26 2021 +0200

        Migrate legacy delegation data (#771)

        * Skip ReadOnlyBucket deserialization errors

        * empty migration

        * clippy

        * cargo schema

        * Drop invalid delegation data

        * Dont drop old data

        * Add todo

        * Unify on type param

        * gateways are different

        * cargo fmt

        Co-authored-by: Drazen Urch <durch@users.noreply.guthub.com>

    commit 26b032c15c
    Merge: e1ddaff0 cba36253
    Author: Mark Sinclair <mmsinclair@gmail.com>
    Date:   Tue Sep 14 10:09:14 2021 +0100

        Merge pull request #774 from nymtech/feature/explorer-api-delegations

        Explorer-api: add API resource to show the delegations for each mix node

    commit cba3625394
    Author: Mark Sinclair <mmsinclair@gmail.com>
    Date:   Mon Sep 13 10:33:41 2021 +0100

        explorer-api: add API resource to show the delegations for each mix node

    commit e1ddaff04d
    Merge: 0b9c03ca 66ab5de4
    Author: Fouad <fmtabbara@hotmail.co.uk>
    Date:   Fri Sep 10 17:17:14 2021 +0100

        Merge pull request #772 from nymtech/update/disable-bonding

        add app alert

    commit 66ab5de442
    Author: fmtabbara <fmtabbara@hotmail.co.uk>
    Date:   Fri Sep 10 16:16:58 2021 +0100

        add app alert

    commit 0b9c03ca90
    Author: Dave Hrycyszyn <futurechimp@users.noreply.github.com>
    Date:   Fri Sep 10 11:23:21 2021 +0300

        Adding deps for building the Tauri wallet under Ubuntu (#770)

    commit c9dce0c1da
    Author: Bogdan-Ștefan Neacşu <bogdan@nymtech.net>
    Date:   Thu Sep 9 11:21:45 2021 +0200

        Feature/consumable bandwidth (#766)

        * Set actual value for bandwidth

        Also put it as a public attribute, such that it can be actively used
        by the credential consumer

        * Switch from sending Attribute structs to sending the actual attribute bytes over the wire

        * Add atomic bandwidth value to gateway

        * Consume bandwidth based on the mix packet size

        * Use Bandwidth struct for specific functionality

        * Move bandwidth code outside the dependency path of wasm client

        * Use u64 instead of AtomicU64, as the handling is not parallel

    commit e00e77db15
    Author: Bogdan-Ștefan Neacşu <bogdan@nymtech.net>
    Date:   Wed Sep 8 15:07:24 2021 +0200

        Feature/bond blockstamp (#760)

        * Add block_height to MixNode/GatewayBond

        * Reward based on blockstamp of bonded node or of delegation

        * Add specific tests

        * Add migration code

        * Apply doc nit

    commit 1074449f91
    Merge: 08276e6e 9a3d824a
    Author: Fouad <fmtabbara@hotmail.co.uk>
    Date:   Tue Sep 7 23:45:10 2021 +0100

        Merge pull request #767 from nymtech/update/remove-app-alert

        remove alert

    commit 08276e6e42
    Author: Bogdan-Ștefan Neacşu <bogdan@nymtech.net>
    Date:   Tue Sep 7 16:33:30 2021 +0200

        Remove migration code (#759)

    commit 9a3d824a4a
    Author: fmtabbara <fmtabbara@hotmail.co.uk>
    Date:   Mon Sep 6 20:39:24 2021 +0100

        remove alert

    commit 2789ee8f18
    Author: Bogdan-Ștefan Neacşu <bogdan@nymtech.net>
    Date:   Fri Sep 3 15:30:45 2021 +0300

        Update coconut-rs and use hash_to_scalar from there (#765)

        Failed tests are due to some nightly issue, not related to this PR

    commit a7ba643c35
    Merge: 28be53ee c42f3c68
    Author: Fouad <fmtabbara@hotmail.co.uk>
    Date:   Fri Sep 3 09:14:50 2021 +0100

        Merge pull request #762 from nymtech/feature/app-alert

        add app alert banner

    commit 28be53eefb
    Author: Bogdan-Ștefan Neacşu <bogdan@nymtech.net>
    Date:   Thu Sep 2 18:26:40 2021 +0300

        Add block_height in the Delegation structure as well (#757)

    commit 219c45a352
    Author: Jędrzej Stuczyński <jedrzej.stuczynski@gmail.com>
    Date:   Thu Sep 2 15:48:29 2021 +0100

        Updated cosmos-sdk (#761)

        * Updated cosmos-sdk

        * Re-exposing more things

    commit 1a3b83752e
    Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
    Date:   Thu Sep 2 15:45:56 2021 +0100

        Bump next from 11.1.0 to 11.1.1 in /wallet-web (#758)

        Bumps [next](https://github.com/vercel/next.js) from 11.1.0 to 11.1.1.
        - [Release notes](https://github.com/vercel/next.js/releases)
        - [Changelog](https://github.com/vercel/next.js/blob/canary/release.js)
        - [Commits](https://github.com/vercel/next.js/compare/v11.1.0...v11.1.1)

        ---
        updated-dependencies:
        - dependency-name: next
          dependency-type: direct:production
        ...

        Signed-off-by: dependabot[bot] <support@github.com>

        Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

    commit c42f3c6844
    Author: fmtabbara <fmtabbara@hotmail.co.uk>
    Date:   Thu Sep 2 12:29:47 2021 +0100

        add app alert banner

    commit a5d3ba3900
    Merge: 92e13a5d cdf0d443
    Author: Mark Sinclair <mmsinclair@gmail.com>
    Date:   Tue Aug 31 15:59:11 2021 +0100

        Merge pull request #755 from nymtech/bugfix/explorer-api-ping

        Explorer API: port test now split out address resolution and add units tests

    commit cdf0d44341
    Author: Mark Sinclair <mmsinclair@gmail.com>
    Date:   Tue Aug 31 14:37:28 2021 +0100

        explorer-api: turned down logging from `error` to `warn`

    commit 92f976a45d
    Author: Mark Sinclair <mmsinclair@gmail.com>
    Date:   Fri Aug 27 11:34:21 2021 +0100

        explorer-api: sanitize hostname before running checks to avoid leading or trailing spaces that are known to exist in the current test net

    commit 2bc858cde3
    Author: Mark Sinclair <mmsinclair@gmail.com>
    Date:   Fri Aug 27 09:32:26 2021 +0100

        explorer-api: port test: split out address resolution and add units tests

    commit 92e13a5d00
    Author: Bogdan-Ștefan Neacşu <bogdan@nymtech.net>
    Date:   Tue Aug 31 14:51:15 2021 +0300

        Feature/add blockstamp (#756)

        * Add RawDelegationData

        * Fix current tests for the new stored data

        * Added migration commit. Will be reverted after doing the migration

        * New tests for block height

        * Use current blockstamp instead of 24h old one

        * Put _alot_ of migration stuff in the migrate function scope

    commit 122f5d9f2e
    Author: Bogdan-Ștefan Neacşu <bogdan@nymtech.net>
    Date:   Mon Aug 30 10:27:20 2021 +0300

        Feature/cred after handshake (#745)

        * Call perform_initial_authentication instead of register in clients

        * Refactor the register/authenticate functions a bit

        * Introduce Bandwidth request type

        * Add encryption layer to cred

        * Remove cred pass and check from handshake

        * Replaced unreachable!  with error

        * Changed decrypt_tagged signature to not take mutable ownership of data

        * Put handle_bandwidth work inside a function

        * Add check before unwrap

        * Remove unnecessary async

        * Decouple bandwidth credential from authentication

        * Use new_error for ServerResponse:Error

        * Send a fresh IV each time the BandwidthCredential request is sent

        * Remove unwrap of bincode::serialize

        * Add comment regarding Bandwidth response

        * Remove _mut from naming

        * Leave Debug trait alone, as the initial error doesn't reproduce anymore

        * Pass iv as Vec<u8> instead of base58 string

        * Renamed AuthenticationIV to IV, as it is now used for more the just authentication

        * Did some IV refactorization

    commit 982ee0266c
    Author: Bogdan-Ștefan Neacşu <bogdan@nymtech.net>
    Date:   Fri Aug 27 16:02:34 2021 +0300

        Feature/get own delegations (#748)

        * Introduce reverse delegation bucket

        * Add client command

        * Fix clippy error

        * Added tests in queries

        * Add tests in transactions

        * Migration code. Will be reverted after it's called on testnet

        * Replace unwrap with expect

        * Move some test code in the right file...

        ... to remove unnecessary auxiliary function.

        * Reduce the scope to migration auxiliary functions

        * Rename everything from [node]reverse to reverse[node]

        * Fix fmt

    commit 5f42a9bd05
    Author: Jędrzej Stuczyński <jedrzej.stuczynski@gmail.com>
    Date:   Fri Aug 27 13:52:18 2021 +0100

        NetworkMonitorBuilder - starting the monitor after rocket has launched (#754)

        * NetworkMonitorBuilder - starting the monitor after rocket has launched

        * Removed unused import

    commit 1811df9ddb
    Author: Jędrzej Stuczyński <jedrzej.stuczynski@gmail.com>
    Date:   Fri Aug 27 13:52:10 2021 +0100

        Enabled validators api argument (#753)

    commit 6bdfe7f895
    Author: Jędrzej Stuczyński <jedrzej.stuczynski@gmail.com>
    Date:   Thu Aug 26 11:21:01 2021 +0100

        Correctly bounding nominator of uptime calculation (#752)

    commit c6b286a1db
    Author: Jędrzej Stuczyński <jedrzej.stuczynski@gmail.com>
    Date:   Wed Aug 25 14:50:57 2021 +0100

        Fixed argument parsing for ipv6 'good' topology (#751)

    commit b3568a26f5
    Author: Bogdan-Ștefan Neacşu <bogdan@nymtech.net>
    Date:   Tue Aug 24 11:25:05 2021 +0300

        Revert "Migration commit, will be reverted after the testnet contract is updated" (#749)

        This reverts commit 38d868bcce.

    commit 15ae0f521e
    Author: Jędrzej Stuczyński <jedrzej.stuczynski@gmail.com>
    Date:   Mon Aug 23 10:26:51 2021 +0100

        Feature/more reliable uptime calculation (#747)

        * New database table holding monitor run info

        * SQL interface for new table

        * Updated uptime calculation to instead rely on number of monitor test runs

    commit 2923d4b872
    Author: Bogdan-Ștefan Neacşu <bogdan@nymtech.net>
    Date:   Thu Aug 19 22:03:07 2021 +0300

        Update template toml key (#746)

commit cddd9e8e4c
Merge: 40fbdff0 976dd7aa
Author: Drazen Urch <durch@users.noreply.guthub.com>
Date:   Thu Sep 16 17:27:27 2021 +0200

    Merge branch 'develop' into tauri-wallet

commit 63bc42cd5f
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Thu Sep 16 10:01:53 2021 +0100

    update title

commit 9dc8ba7b77
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Wed Sep 15 21:39:18 2021 +0100

    funds allocation check when bonding/sending/delegating

commit e130131f16
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Wed Sep 15 20:37:24 2021 +0100

    finish bonding and unbonding setup

commit 64a5b4b593
Merge: 9934b9bc 40fbdff0
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Tue Sep 14 12:08:38 2021 +0100

    Merge branch 'tauri-wallet' into tauri-wallet-frontend
    rust updates

commit 40fbdff05a
Author: Drazen Urch <durch@users.noreply.guthub.com>
Date:   Tue Sep 14 10:29:31 2021 +0200

    Coin and denom tests

commit 9934b9bc8a
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Mon Sep 13 15:20:56 2021 +0100

    update working

commit 6954b383a7
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Mon Sep 13 14:26:21 2021 +0100

    form updates

commit 4b5276e816
Merge: 56a95274 0278bd2c
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Mon Sep 13 13:32:24 2021 +0100

    Merge branch 'tauri-wallet' into tauri-wallet-frontend
    rust updates

commit 0278bd2c26
Author: Drazen Urch <durch@users.noreply.guthub.com>
Date:   Mon Sep 13 14:31:33 2021 +0200

    Fix coin to cosmwasm coin

commit 56a9527497
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Mon Sep 13 13:30:05 2021 +0100

    use wrapper functions for send and delegate

commit a601c28a20
Author: Drazen Urch <durch@users.noreply.guthub.com>
Date:   Mon Sep 13 13:07:57 2021 +0200

    Return useful info from bond/unbond

commit 005dd7513b
Merge: 3ebdc558 aaf5d186
Author: Drazen Urch <durch@users.noreply.guthub.com>
Date:   Mon Sep 13 12:58:01 2021 +0200

    Merge branch 'tauri-wallet-frontend' into tauri-wallet

commit 3ebdc55847
Author: Drazen Urch <durch@users.noreply.guthub.com>
Date:   Mon Sep 13 12:50:26 2021 +0200

    extract Coin and Denom

commit aaf5d18692
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Mon Sep 13 11:19:28 2021 +0100

    update admin component

commit bcbec1f3e6
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Sun Sep 12 21:49:39 2021 +0100

    admin form style updates

commit c95005265d
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Sun Sep 12 01:26:57 2021 +0100

    button updates

commit b299c9e4b5
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Sun Sep 12 01:03:21 2021 +0100

    add qrcode to receive page

commit bacbd3dfce
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Sun Sep 12 00:40:53 2021 +0100

    fix bug

commit 55561fe1f7
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Sun Sep 12 00:26:15 2021 +0100

    add admin page

commit 0d01500b87
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Sat Sep 11 00:35:14 2021 +0100

    remove login deets

commit 74e34567b4
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Sat Sep 11 00:32:54 2021 +0100

    form updates

commit b77025bfd5
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Sat Sep 11 00:10:03 2021 +0100

    form updates

commit 4d831efcd6
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Fri Sep 10 22:33:00 2021 +0100

    more fees work

commit d227d20385
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Fri Sep 10 17:31:04 2021 +0100

    add gas fees to bond form

commit fb2d3bae3c
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Fri Sep 10 14:17:24 2021 +0100

    use new getFee api

commit 967d74eb19
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Fri Sep 10 11:15:52 2021 +0100

    add nvmrc file

commit 228df278d9
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Fri Sep 10 11:13:18 2021 +0100

    update tsconfig

commit 37da23ab1c
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Fri Sep 10 09:56:04 2021 +0100

    set up global error handling

commit 0c9cf7b5d9
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Fri Sep 10 09:16:45 2021 +0100

    finish create account

commit 262149078c
Merge: 08fd1c1b 3bcbb901
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Thu Sep 9 19:21:38 2021 +0100

    rust updates

commit 08fd1c1b47
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Thu Sep 9 19:00:30 2021 +0100

    make getBalance global

commit 3bcbb90127
Author: Drazen Urch <durch@users.noreply.guthub.com>
Date:   Thu Sep 9 17:47:11 2021 +0200

    fix docs

commit 8156ed0029
Author: Drazen Urch <durch@users.noreply.guthub.com>
Date:   Thu Sep 9 17:43:56 2021 +0200

    get_fee, create_new_account

commit 265f7a7c2e
Author: Drazen Urch <durch@users.noreply.guthub.com>
Date:   Thu Sep 9 13:21:27 2021 +0200

    Dedicated workspace, random_mnemonic, gas_limits

commit 5de8c9d1ed
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Thu Sep 9 11:35:49 2021 +0100

    style updates

commit 7658eec9b9
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Thu Sep 9 09:16:38 2021 +0100

    create account page

commit 99c49581df
Merge: 7a8ad138 926689da
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Wed Sep 8 20:49:27 2021 +0100

    Merge branch 'tauri-wallet' into tauri-wallet-frontend
    rust updates

commit 926689da1d
Merge: 714171f4 b40be179
Author: Drazen Urch <durch@users.noreply.guthub.com>
Date:   Wed Sep 8 11:54:49 2021 +0200

    Merge branch 'tauri-wallet' of https://github.com/nymtech/nym into tauri-wallet

commit 714171f4e5
Author: Drazen Urch <durch@users.noreply.guthub.com>
Date:   Wed Sep 8 11:54:36 2021 +0200

    redundant into

commit 7a8ad1387d
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Wed Sep 8 10:30:51 2021 +0100

    add eslint file

commit bd72426280
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Tue Sep 7 23:44:02 2021 +0100

    start adding gas fees

commit 48d0f31d7e
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Tue Sep 7 23:13:54 2021 +0100

    send updates

commit 4522c18a55
Merge: b9389f12 b40be179
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Tue Sep 7 21:53:38 2021 +0100

    Merge branch 'tauri-wallet' into tauri-wallet-frontend
    rust updates

commit b9389f1235
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Tue Sep 7 21:53:05 2021 +0100

    send updates

commit b40be179ae
Author: durch <durch@users.noreply.github.com>
Date:   Tue Sep 7 12:37:24 2021 +0000

    [ci skip] Generate TS types

commit 32ef9e019e
Author: Drazen Urch <durch@users.noreply.guthub.com>
Date:   Tue Sep 7 14:26:48 2021 +0200

    More verbose send response

commit 45a56a7088
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Mon Sep 6 20:27:15 2021 +0100

    update logo

commit d50afd6113
Author: Drazen Urch <durch@users.noreply.guthub.com>
Date:   Mon Sep 6 20:00:47 2021 +0200

    Add coconut creds

commit 3205b1e0e6
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Mon Sep 6 16:42:56 2021 +0100

    start work on send form

commit 53ea8486f8
Author: Drazen Urch <durch@users.noreply.guthub.com>
Date:   Mon Sep 6 17:36:46 2021 +0200

    get_gas_price, get_gas_limits

commit 43ababf8d4
Author: Drazen Urch <durch@users.noreply.guthub.com>
Date:   Mon Sep 6 17:31:08 2021 +0200

    Rework client errors

commit 5461574023
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Mon Sep 6 13:23:20 2021 +0100

    small refactors

commit 01d2df7bb7
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Mon Sep 6 11:12:39 2021 +0100

    set up form validation for undelegation

commit 7cff72757b
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Sun Sep 5 00:07:46 2021 +0100

    set up delgate request

commit 5bcbf45d16
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Sat Sep 4 22:52:02 2021 +0100

    onerror onsuccess added to bond form

commit 4295d75e0f
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Fri Sep 3 16:53:32 2021 +0100

    format bonding data pre request

commit 018666a614
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Fri Sep 3 16:37:51 2021 +0100

    layout updates

commit 15048524a7
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Fri Sep 3 16:25:15 2021 +0100

    layout updates

commit 2b792945cc
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Fri Sep 3 15:07:38 2021 +0100

    update type roots

commit b6193270a6
Merge: 0b4a8fe6 29973379
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Fri Sep 3 15:02:56 2021 +0100

    Merge branch 'tauri-wallet' into tauri-wallet-frontend
    rust updates

commit 0b4a8fe657
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Fri Sep 3 15:02:09 2021 +0100

    update type roots

commit 2997337948
Author: Drazen Urch <durch@users.noreply.guthub.com>
Date:   Fri Sep 3 15:29:20 2021 +0200

    printable balance should be major

commit e1bea43ff4
Author: Drazen Urch <drazen@urch.eu>
Date:   Fri Sep 3 15:22:48 2021 +0200

    Autogenerate types (#763)

    * Generate TS types on push

    * run shell

    * fix typo

    * pango

    * libpango-dev

    * hopefully all deps are in now :)

    Co-authored-by: Drazen Urch <durch@users.noreply.guthub.com>

commit 27ef28da8d
Merge: 42bf139e 87a0b05d
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Fri Sep 3 12:13:28 2021 +0100

    Merge branch 'tauri-wallet' into tauri-wallet-frontend
    rust updates

commit 42bf139ebb
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Fri Sep 3 12:12:52 2021 +0100

    update args collection function

commit 352862e4d0
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Fri Sep 3 11:42:31 2021 +0100

    delegation form validation

commit 9f9ab010d8
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Fri Sep 3 11:39:17 2021 +0100

    integrate rust generated types

commit 87a0b05d1a
Author: Drazen Urch <drazen@urch.eu>
Date:   Fri Sep 3 07:43:29 2021 +0200

    Send

commit dbf82da9b6
Author: Drazen Urch <drazen@urch.eu>
Date:   Fri Sep 3 07:36:02 2021 +0200

    Delegation docs

commit 01a4305883
Author: Drazen Urch <drazen@urch.eu>
Date:   Fri Sep 3 07:33:11 2021 +0200

    Delegation

commit 704b3241ee
Author: Drazen Urch <drazen@urch.eu>
Date:   Fri Sep 3 06:58:57 2021 +0200

    Gateway bonding

commit 4513edae46
Merge: 5d3f1b86 f020b211
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Thu Sep 2 21:38:19 2021 +0100

    rust updates

commit f020b21106
Author: Drazen Urch <durch@users.noreply.guthub.com>
Date:   Thu Sep 2 21:08:19 2021 +0200

    node unbond

commit 2587906473
Author: Drazen Urch <durch@users.noreply.guthub.com>
Date:   Thu Sep 2 20:57:10 2021 +0200

    TS exports, rework internals

commit 5d3f1b86e8
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Thu Sep 2 17:29:03 2021 +0100

    delegate form validation

commit 5a17e48581
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Thu Sep 2 16:11:54 2021 +0100

    finish bond form validation

commit 41356f2181
Merge: bd7d7887 63107c2b
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Thu Sep 2 10:10:55 2021 +0100

    Merge branch 'tauri-wallet' into tauri-wallet-frontend
    merge rust updates

commit bd7d788741
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Thu Sep 2 10:10:18 2021 +0100

    more validation work

commit 63107c2bca
Author: Drazen Urch <drazen@urch.eu>
Date:   Thu Sep 2 10:27:49 2021 +0200

    WIP node bonding

commit f043639ad2
Merge: 1d2a1b26 6fb15fff
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Wed Sep 1 19:48:22 2021 +0100

    Merge branch 'tauri-wallet' into tauri-wallet-frontend
    merge rust update

commit 1d2a1b2635
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Wed Sep 1 19:47:41 2021 +0100

    start form validation

commit 6fb15fff8b
Author: Drazen Urch <durch@users.noreply.guthub.com>
Date:   Wed Sep 1 16:33:29 2021 +0200

    printable_balance

commit c69d7fa46f
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Wed Sep 1 15:12:50 2021 +0100

    remove unused imports

commit c2ee02a2cf
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Wed Sep 1 15:12:25 2021 +0100

    use printable balance

commit 6f5f0c00b5
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Wed Sep 1 15:11:24 2021 +0100

    use printable balance

commit 12707c5f1e
Merge: 2aa7fa04 0daf89ee
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Wed Sep 1 14:59:27 2021 +0100

    merge rust updates

commit 0daf89eeb4
Author: Drazen Urch <drazen@urch.eu>
Date:   Wed Sep 1 15:14:50 2021 +0200

    Utility native <> printable functions

commit 2aa7fa0426
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Wed Sep 1 13:41:42 2021 +0100

    move balance function call to global state

commit f5aa6e2db2
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Wed Sep 1 09:39:22 2021 +0100

    style updates

commit ee5d1c3419
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Tue Aug 31 20:57:21 2021 +0100

    fix nav styling

commit e68c261162
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Tue Aug 31 20:48:30 2021 +0100

    fix ts error

commit c7fe4cd24e
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Tue Aug 31 15:28:46 2021 +0100

    update imports

commit 1c690fc3d0
Merge: d8e6a5fb f56edb82
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Tue Aug 31 15:24:35 2021 +0100

    Merge branch 'tauri-wallet' into tauri-wallet-frontend
    merge rust updates

commit f56edb825a
Author: Drazen Urch <durch@users.noreply.guthub.com>
Date:   Tue Aug 31 15:22:10 2021 +0200

    Fix client address

commit d8e6a5fb2e
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Tue Aug 31 12:55:13 2021 +0100

    make typescript happy

commit b95893bb02
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Tue Aug 31 11:20:12 2021 +0100

    update balance page

commit 6bdff701b4
Merge: ccdb5911 eff38c84
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Tue Aug 31 11:05:51 2021 +0100

    merge backend updates

commit ccdb5911c6
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Tue Aug 31 09:35:24 2021 +0100

    update routing and use new sign in function

commit eff38c8466
Author: Drazen Urch <durch@users.noreply.guthub.com>
Date:   Tue Aug 31 07:38:25 2021 +0200

    some cleanup, get blockchain stuff working

commit 5f4fabc0b8
Author: Drazen Urch <durch@users.noreply.guthub.com>
Date:   Fri Aug 27 15:17:15 2021 +0200

    Add internal documentation scaffolding

commit e2dd1cc9ae
Merge: c7e622f2 42f75028
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Wed Aug 25 14:51:29 2021 +0100

    Merge branch 'tauri-wallet' into tauri-wallet-frontend
    connect with mnemonic update

commit 42f75028bc
Author: Drazen Urch <durch@users.noreply.guthub.com>
Date:   Wed Aug 25 15:44:08 2021 +0200

    Resolve state deadlock

commit c7e622f284
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Wed Aug 25 14:06:37 2021 +0100

    begin sign in rust integration

commit 248da351c6
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Wed Aug 25 14:05:00 2021 +0100

    use color palette object

commit fe1c8a3b08
Merge: 84af9233 1bc17abb
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Wed Aug 25 10:36:11 2021 +0100

    Merge branch 'tauri-wallet' into tauri-wallet-frontend
    merge rust api updates

commit 84af923389
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Wed Aug 25 10:35:42 2021 +0100

    update receive to use state value

commit 1bc17abbaa
Author: Drazen Urch <drazen@urch.eu>
Date:   Wed Aug 25 11:18:16 2021 +0200

    Add connect_with_mnemonic and get_balance tauri functions

commit b8c2735520
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Tue Aug 24 16:12:08 2021 +0100

    cargo lock update

commit 67fd4367ef
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Tue Aug 24 16:08:55 2021 +0100

    global theme update

commit 4540d2c447
Merge: ce757697 4ad25114
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Tue Aug 24 12:56:59 2021 +0100

    Merge branch 'feature/tauri-wallet-ui' into tauri-wallet
    merge with rust updates

commit 4ad25114c3
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Tue Aug 24 12:46:34 2021 +0100

    update nav cards

commit 3ce7888c07
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Tue Aug 24 11:59:10 2021 +0100

    address and balance cards

commit ce75769703
Author: Drazen Urch <drazen@urch.eu>
Date:   Tue Aug 24 12:54:49 2021 +0200

    Bootstrap nymd client with config

commit 66210658cb
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Tue Aug 24 10:35:54 2021 +0100

    add favicon

commit 728da763b3
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Mon Aug 23 22:54:30 2021 +0100

    fix padding issue

commit 3da08ee33c
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Mon Aug 23 22:49:39 2021 +0100

    style updates

commit 55977185fd
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Mon Aug 23 22:04:26 2021 +0100

    add unbond and undelegte pages

commit 1c8c0a47bc
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Mon Aug 23 21:34:14 2021 +0100

    receive page adjust margin

commit c161b2fe71
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Mon Aug 23 21:32:29 2021 +0100

    send wizard updates

commit eb91c1180d
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Mon Aug 23 17:23:25 2021 +0100

    update balance page

commit 13e357637b
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Mon Aug 23 17:18:07 2021 +0100

    style updates

commit 54c4bdb7d2
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Mon Aug 23 17:12:40 2021 +0100

    send wizard update

commit 9b5f50913f
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Mon Aug 23 14:56:52 2021 +0100

    add send wizard

commit 7cfa35b542
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Mon Aug 23 11:18:13 2021 +0100

    style updates

commit 581a6b0a6f
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Mon Aug 23 10:38:56 2021 +0100

    update nav bar

commit 85f23eb3d1
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Mon Aug 23 10:38:42 2021 +0100

    create delegation page

commit 17100fa7da
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Mon Aug 23 10:38:17 2021 +0100

    create node type selector component

commit 24af0c94bf
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Fri Aug 20 22:26:14 2021 +0100

    add bond form

commit 8ec9e3121f
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Fri Aug 20 17:35:59 2021 +0100

    side bar updates

commit 498dbb8ba3
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Fri Aug 20 12:24:04 2021 +0100

    add balance page

commit 7345bd8148
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Fri Aug 20 11:51:27 2021 +0100

    update navigation style

commit b405d2e4af
Author: fmtabbara <fmtabbara@hotmail.co.uk>
Date:   Fri Aug 20 09:03:21 2021 +0100

    set up tauri app with React frontend
2021-09-27 12:03:54 +02:00
Jędrzej Stuczyński 020cad897d Feature/rust rewarding (#750)
* Calculating gas fees

* Ability to set custom fees

* Added extra test

* Removed commented code

* Moved all msg types to common contract crate

* Temporarily disabling get_tx method

* Finishing up nymd client API

* Comment fix

* Remaining fee values

* Some cleanup

* Removed needless borrow

* Fixed imports in contract tests

* Moved error types around

* New ValidatorClient

* Experiment with new type of defaults

* Removed dead module

* Dealt with unwrap

* Migrated mixnode to use new validator client

* Migrated gateway to use new validator client

* Mixnode and gateway adjustments

* More exported defaults

* Clients using new validator client

* Fixed mixnode upgrade

* Moved default values to a new crate

* Changed behaviour of validator client features

* Migrated basic functions of validator api

* Updated config + fixed startup

* Fixed wasm client build

* Integration with the explorer api

* Removed tokio dev dependency

* Needless borrow

* Fixex wasm client build

* Fixed tauri client build

* Needless borrows

* New tables for rewarding

* Updated cosmos-sdk version

* Removed reward-specific node status routes

* New rewarding-specific config entries

* Additional network defaults

* Initial periodic rewards from validator api

* Replaced print with log

* Filtering nodes with uptime > 0

* Additional failure logging statements

* Fixed operation ordering

* Adjusted next rewarding epoch determination

* Modified rewarding behaviour to keep track of rewarding in progress

* Improved error message on config load failure

* Additional log statement

* Adjusted rewarding gas limit calculation

* Made naming slightly more consistent

* Fixed incorrect parentheses placement

* Fixed fee calculation

* Cargo fmt

* Removed failed merge artifacts

* Introduced comment for any future reward modification

* typos

* Helper functions for the future

* Making @mfahampshire 's life easier

* Redesigned epoch + rewarding skipped epochs (if possible)

* Removed old merge artifacts

* Naming consistency

* Constraining arguments

* Removed unnecessary if branch

* Ignore monitor check for current epoch

* Additional checks for current epoch data

* Monitor threshold check

* cargo fmt

* Fixed post-merge issues in transactions.rs
2021-09-24 15:49:21 +01:00
Drazen Urch 5dfaff6296 Update hmac and blake3 (#673)
* Update hmac and blake3

* Remain paranoid for `0.*` crates

* Most paranoid versions :)

* Updated aes and using published version of blake3

Co-authored-by: Jędrzej Stuczyński <jedrzej.stuczynski@gmail.com>
2021-09-21 09:59:17 +01:00
Jędrzej Stuczyński 5b03982043 Replaced unwrap_or_else with unwrap_or_default (#780) 2021-09-20 10:40:03 +01:00
Drazen Urch 8f6856d6fb Make fee helpers public (#777)
Co-authored-by: Drazen Urch <durch@users.noreply.guthub.com>
2021-09-20 10:15:06 +01:00
Drazen Urch 976dd7aae2 Add block_height method to Delegation (#778)
Co-authored-by: Drazen Urch <durch@users.noreply.guthub.com>
2021-09-15 17:28:49 +02:00
Fouad 0d21f4e937 Merge pull request #776 from nymtech/update/re-enable-bonding
re-enable bonding
2021-09-15 12:41:29 +01:00
fmtabbara 1403449ad5 enable bonding 2021-09-14 16:00:21 +01:00
Drazen Urch e84af4f601 Migrate legacy delegation data (#771)
* Skip ReadOnlyBucket deserialization errors

* empty migration

* clippy

* cargo schema

* Drop invalid delegation data

* Dont drop old data

* Add todo

* Unify on type param

* gateways are different

* cargo fmt

Co-authored-by: Drazen Urch <durch@users.noreply.guthub.com>
2021-09-14 14:15:26 +01:00
200 changed files with 22928 additions and 2511 deletions
+2 -24
View File
@@ -3,7 +3,7 @@ name: Continuous integration
on: [push, pull_request]
jobs:
ci:
build:
runs-on: ${{ matrix.os }}
continue-on-error: ${{ matrix.rust == 'nightly' || matrix.rust == 'beta' }}
strategy:
@@ -25,28 +25,13 @@ jobs:
override: true
components: rustfmt, clippy
# Exclude validator API on Windows
- uses: actions-rs/cargo@v1
if: ${{ matrix.os == 'windows-latest' }}
with:
command: build
args: --all --exclude nym-validator-api
- uses: actions-rs/cargo@v1
if: ${{ matrix.os != 'windows-latest' }}
with:
command: build
args: --all
# Exclude validator API on Windows
- uses: actions-rs/cargo@v1
if: ${{ matrix.os == 'windows-latest' }}
with:
command: test
args: --all --exclude nym-validator-api
- uses: actions-rs/cargo@v1
if: ${{ matrix.os != 'windows-latest' }}
with:
command: test
args: --all
@@ -56,15 +41,8 @@ jobs:
command: fmt
args: --all -- --check
# Exclude validator API on Windows
- uses: actions-rs/cargo@v1
if: ${{ matrix.rust != 'nightly' && matrix.os == 'windows-latest' }}
with:
command: clippy
args: --all --exclude nym-validator-api -- -D warnings
- uses: actions-rs/cargo@v1
if: ${{ matrix.rust != 'nightly' && matrix.os != 'windows-latest' }}
if: ${{ matrix.rust != 'nightly' }}
with:
command: clippy
args: -- -D warnings
+1 -1
View File
@@ -3,7 +3,7 @@ name: Mixnet Contract
on: [push, pull_request]
jobs:
ci:
mixnet-contract:
# since it's going to be compiled into wasm, there's absolutely
# no point in running CI on different OS-es
runs-on: ubuntu-latest
+22
View File
@@ -0,0 +1,22 @@
name: Generate TS types
on: push
jobs:
tauri-wallet-types:
runs-on: ubuntu-latest
steps:
- name: Prepare
run: sudo apt-get update && sudo apt-get install -y libpango1.0-dev libatk1.0-dev libgdk-pixbuf2.0-dev libsoup2.4-dev librust-gdk-dev libwebkit2gtk-4.0-dev
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
with:
toolchain: stable
- name: Generate TS
run: cd tauri-wallet/src-tauri && cargo test
- uses: EndBug/add-and-commit@v7.2.1 # https://github.com/marketplace/actions/add-commit
with:
add: '["tauri-wallet"]'
message: '[ci skip] Generate TS types'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+1 -1
View File
@@ -3,7 +3,7 @@ name: Wasm Client
on: [push, pull_request]
jobs:
ci:
wasm:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
Generated
+947 -627
View File
File diff suppressed because it is too large Load Diff
+1
View File
@@ -15,6 +15,7 @@ The platform is composed of multiple Rust crates. Top-level executable binary cr
* nym-gateway - acts sort of like a mailbox for mixnet messages, removing the need for directly delivery to potentially offline or firewalled devices.
* nym-network-monitor - sends packets through the full system to check that they are working as expected, and stores node uptime histories as the basis of a rewards system ("mixmining" or "proof-of-mixing").
* nym-explorer - a (projected) block explorer and (existing) mixnet viewer.
* nym-wallet (currently in development)- a desktop wallet implemented using the [Tauri](https://tauri.studio/en/docs/about/intro) framework.
[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg?style=for-the-badge)](https://opensource.org/licenses/Apache-2.0)
[![Build Status](https://img.shields.io/github/workflow/status/nymtech/nym/Continuous%20integration/develop?style=for-the-badge&logo=github-actions)](https://github.com/nymtech/nym/actions?query=branch%3Adevelop)
@@ -18,7 +18,7 @@ pub enum ReplyKeyStorageError {
/// Permanent storage for keys in all sent [`ReplySURB`]
///
/// Each sent out [`ReplySURB`] has a new key associated with it that is going to be used for
/// payload encryption. In order to decrypt whatever reply we receive, we need to know which
/// payload encryption. In order to -decrypt whatever reply we receive, we need to know which
/// key to use for that purpose. We do it based on received `H(t)` which has to be included
/// with each reply.
/// Moreover, there is no restriction when the [`ReplySURB`] might get used so we need to
-2
View File
@@ -31,8 +31,6 @@ tokio-tungstenite = "0.14" # websocket
## internal
client-core = { path = "../client-core" }
coconut-interface = { path = "../../common/coconut-interface" }
credentials = { path = "../../common/credentials" }
config = { path = "../../common/config" }
crypto = { path = "../../common/crypto" }
gateway-client = { path = "../../common/client-libs/gateway-client" }
-30
View File
@@ -22,9 +22,6 @@ use client_core::client::topology_control::{
TopologyAccessor, TopologyRefresher, TopologyRefresherConfig,
};
use client_core::config::persistence::key_pathfinder::ClientKeyPathfinder;
use coconut_interface::Credential;
use credentials::bandwidth::prepare_for_spending;
use credentials::obtain_aggregate_verification_key;
use crypto::asymmetric::identity;
use futures::channel::mpsc;
use gateway_client::{
@@ -166,30 +163,6 @@ impl NymClient {
.start(self.runtime.handle())
}
async fn prepare_credential(&self) -> Credential {
let verification_key = obtain_aggregate_verification_key(
&self.config.get_base().get_validator_api_endpoints(),
)
.await
.expect("could not obtain aggregate verification key of validators");
let bandwidth_credential = credentials::bandwidth::obtain_signature(
&self.key_manager.identity_keypair().public_key().to_bytes(),
&self.config.get_base().get_validator_api_endpoints(),
)
.await
.expect("could not obtain bandwidth credential");
// the above would presumably be loaded from a file
// the below would only be executed once we know where we want to spend it (i.e. which gateway and stuff)
prepare_for_spending(
&self.key_manager.identity_keypair().public_key().to_bytes(),
&bandwidth_credential,
&verification_key,
)
.expect("could not prepare out bandwidth credential for spending")
}
fn start_gateway_client(
&mut self,
mixnet_message_sender: MixnetMessageSender,
@@ -208,8 +181,6 @@ impl NymClient {
.expect("provided gateway id is invalid!");
self.runtime.block_on(async {
let coconut_credential = self.prepare_credential().await;
let mut gateway_client = GatewayClient::new(
gateway_address,
self.key_manager.identity_keypair(),
@@ -218,7 +189,6 @@ impl NymClient {
mixnet_message_sender,
ack_sender,
self.config.get_base().get_gateway_response_timeout(),
coconut_credential,
);
gateway_client
+2 -29
View File
@@ -6,10 +6,7 @@ use crate::commands::override_config;
use clap::{App, Arg, ArgMatches};
use client_core::client::key_manager::KeyManager;
use client_core::config::persistence::key_pathfinder::ClientKeyPathfinder;
use coconut_interface::Credential;
use config::NymConfig;
use credentials::bandwidth::prepare_for_spending;
use credentials::obtain_aggregate_verification_key;
use crypto::asymmetric::{encryption, identity};
use gateway_client::GatewayClient;
use gateway_requests::registration::handshake::SharedKeys;
@@ -60,34 +57,15 @@ pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
)
}
// this behaviour should definitely be changed, we shouldn't
// need to get bandwidth credential for registration
async fn prepare_temporary_credential(validators: &[Url], raw_identity: &[u8]) -> Credential {
let verification_key = obtain_aggregate_verification_key(validators)
.await
.expect("could not obtain aggregate verification key of validators");
let bandwidth_credential = credentials::bandwidth::obtain_signature(raw_identity, validators)
.await
.expect("could not obtain bandwidth credential");
prepare_for_spending(raw_identity, &bandwidth_credential, &verification_key)
.expect("could not prepare out bandwidth credential for spending")
}
async fn register_with_gateway(
gateway: &gateway::Node,
our_identity: Arc<identity::KeyPair>,
validator_urls: Vec<Url>,
) -> Arc<SharedKeys> {
let timeout = Duration::from_millis(1500);
let coconut_credential =
prepare_temporary_credential(&validator_urls, &our_identity.public_key().to_bytes()).await;
let mut gateway_client = GatewayClient::new_init(
gateway.clients_address(),
gateway.identity_key,
our_identity.clone(),
coconut_credential,
timeout,
);
gateway_client
@@ -210,13 +188,8 @@ pub fn execute(matches: &ArgMatches) {
config
.get_base_mut()
.with_gateway_id(gate_details.identity_key.to_base58_string());
let validator_urls = config.get_base().get_validator_api_endpoints();
let shared_keys = register_with_gateway(
&gate_details,
key_manager.identity_keypair(),
validator_urls,
)
.await;
let shared_keys =
register_with_gateway(&gate_details, key_manager.identity_keypair()).await;
(shared_keys, gate_details.clients_address())
};
-2
View File
@@ -24,8 +24,6 @@ url = "2.2"
# internal
client-core = { path = "../client-core" }
coconut-interface = { path = "../../common/coconut-interface" }
credentials = { path = "../../common/credentials" }
config = { path = "../../common/config" }
crypto = { path = "../../common/crypto" }
gateway-client = { path = "../../common/client-libs/gateway-client" }
-30
View File
@@ -23,9 +23,6 @@ use client_core::client::topology_control::{
TopologyAccessor, TopologyRefresher, TopologyRefresherConfig,
};
use client_core::config::persistence::key_pathfinder::ClientKeyPathfinder;
use coconut_interface::Credential;
use credentials::bandwidth::prepare_for_spending;
use credentials::obtain_aggregate_verification_key;
use crypto::asymmetric::identity;
use futures::channel::mpsc;
use gateway_client::{
@@ -154,30 +151,6 @@ impl NymClient {
.start(self.runtime.handle())
}
async fn prepare_credential(&self) -> Credential {
let verification_key = obtain_aggregate_verification_key(
&self.config.get_base().get_validator_api_endpoints(),
)
.await
.expect("could not obtain aggregate verification key of validators");
let bandwidth_credential = credentials::bandwidth::obtain_signature(
&self.key_manager.identity_keypair().public_key().to_bytes(),
&self.config.get_base().get_validator_api_endpoints(),
)
.await
.expect("could not obtain bandwidth credential");
// the above would presumably be loaded from a file
// the below would only be executed once we know where we want to spend it (i.e. which gateway and stuff)
prepare_for_spending(
&self.key_manager.identity_keypair().public_key().to_bytes(),
&bandwidth_credential,
&verification_key,
)
.expect("could not prepare out bandwidth credential for spending")
}
fn start_gateway_client(
&mut self,
mixnet_message_sender: MixnetMessageSender,
@@ -196,8 +169,6 @@ impl NymClient {
.expect("provided gateway id is invalid!");
self.runtime.block_on(async {
let coconut_credential = self.prepare_credential().await;
let mut gateway_client = GatewayClient::new(
gateway_address,
self.key_manager.identity_keypair(),
@@ -206,7 +177,6 @@ impl NymClient {
mixnet_message_sender,
ack_sender,
self.config.get_base().get_gateway_response_timeout(),
coconut_credential,
);
gateway_client
+2 -29
View File
@@ -6,10 +6,7 @@ use crate::commands::override_config;
use clap::{App, Arg, ArgMatches};
use client_core::client::key_manager::KeyManager;
use client_core::config::persistence::key_pathfinder::ClientKeyPathfinder;
use coconut_interface::Credential;
use config::NymConfig;
use credentials::bandwidth::prepare_for_spending;
use credentials::obtain_aggregate_verification_key;
use crypto::asymmetric::{encryption, identity};
use gateway_client::GatewayClient;
use gateway_requests::registration::handshake::SharedKeys;
@@ -60,34 +57,15 @@ pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
)
}
// this behaviour should definitely be changed, we shouldn't
// need to get bandwidth credential for registration
async fn prepare_temporary_credential(validators: &[Url], raw_identity: &[u8]) -> Credential {
let verification_key = obtain_aggregate_verification_key(validators)
.await
.expect("could not obtain aggregate verification key of validators");
let bandwidth_credential = credentials::bandwidth::obtain_signature(raw_identity, validators)
.await
.expect("could not obtain bandwidth credential");
prepare_for_spending(raw_identity, &bandwidth_credential, &verification_key)
.expect("could not prepare out bandwidth credential for spending")
}
async fn register_with_gateway(
gateway: &gateway::Node,
our_identity: Arc<identity::KeyPair>,
validator_urls: Vec<Url>,
) -> Arc<SharedKeys> {
let timeout = Duration::from_millis(1500);
let coconut_credential =
prepare_temporary_credential(&validator_urls, &our_identity.public_key().to_bytes()).await;
let mut gateway_client = GatewayClient::new_init(
gateway.clients_address(),
gateway.identity_key,
our_identity.clone(),
coconut_credential,
timeout,
);
gateway_client
@@ -211,13 +189,8 @@ pub fn execute(matches: &ArgMatches) {
config
.get_base_mut()
.with_gateway_id(gate_details.identity_key.to_base58_string());
let validator_urls = config.get_base().get_validator_api_endpoints();
let shared_keys = register_with_gateway(
&gate_details,
key_manager.identity_keypair(),
validator_urls,
)
.await;
let shared_keys =
register_with_gateway(&gate_details, key_manager.identity_keypair()).await;
(shared_keys, gate_details.clients_address())
};
@@ -8,7 +8,6 @@ pub use crate::packet_router::{
AcknowledgementReceiver, AcknowledgementSender, MixnetMessageReceiver, MixnetMessageSender,
};
use crate::socket_state::{PartiallyDelegated, SocketState};
use coconut_interface::Credential;
use crypto::asymmetric::identity;
use futures::{FutureExt, SinkExt, StreamExt};
use gateway_requests::authentication::encrypted_address::EncryptedAddressBytes;
@@ -36,8 +35,6 @@ const DEFAULT_RECONNECTION_BACKOFF: Duration = Duration::from_secs(5);
pub struct GatewayClient {
authenticated: bool,
// TODO: This should be replaced by an actual bandwidth value, with 0 meaning no bandwidth
has_bandwidth: bool,
gateway_address: String,
gateway_identity: identity::PublicKey,
local_identity: Arc<identity::KeyPair>,
@@ -54,7 +51,6 @@ pub struct GatewayClient {
reconnection_attempts: usize,
/// Delay between each subsequent reconnection attempt.
reconnection_backoff: Duration,
coconut_credential: Credential,
}
impl GatewayClient {
@@ -68,11 +64,9 @@ impl GatewayClient {
mixnet_message_sender: MixnetMessageSender,
ack_sender: AcknowledgementSender,
response_timeout_duration: Duration,
coconut_credential: Credential,
) -> Self {
GatewayClient {
authenticated: false,
has_bandwidth: false,
gateway_address,
gateway_identity,
local_identity,
@@ -83,7 +77,6 @@ impl GatewayClient {
should_reconnect_on_failure: true,
reconnection_attempts: DEFAULT_RECONNECTION_ATTEMPTS,
reconnection_backoff: DEFAULT_RECONNECTION_BACKOFF,
coconut_credential,
}
}
@@ -104,7 +97,6 @@ impl GatewayClient {
gateway_address: String,
gateway_identity: identity::PublicKey,
local_identity: Arc<identity::KeyPair>,
coconut_credential: Credential,
response_timeout_duration: Duration,
) -> Self {
use futures::channel::mpsc;
@@ -117,7 +109,6 @@ impl GatewayClient {
GatewayClient {
authenticated: false,
has_bandwidth: false,
gateway_address,
gateway_identity,
local_identity,
@@ -128,7 +119,6 @@ impl GatewayClient {
should_reconnect_on_failure: false,
reconnection_attempts: DEFAULT_RECONNECTION_ATTEMPTS,
reconnection_backoff: DEFAULT_RECONNECTION_BACKOFF,
coconut_credential,
}
}
@@ -456,32 +446,6 @@ impl GatewayClient {
}
}
pub async fn claim_bandwidth(&mut self) -> Result<(), GatewayClientError> {
if !self.authenticated {
return Err(GatewayClientError::NotAuthenticated);
}
if self.shared_key.is_none() {
return Err(GatewayClientError::NoSharedKeyAvailable);
}
let mut rng = OsRng;
let iv = IV::new_random(&mut rng);
let msg = ClientControlRequest::new_enc_bandwidth_credential(
&self.coconut_credential,
self.shared_key.as_ref().unwrap(),
iv,
)
.ok_or(GatewayClientError::SerializeCredential)?
.into();
self.has_bandwidth = match self.send_websocket_message(msg).await? {
ServerResponse::Bandwidth { status } => Ok(status),
ServerResponse::Error { message } => Err(GatewayClientError::GatewayError(message)),
_ => Err(GatewayClientError::UnexpectedResponse),
}?;
Ok(())
}
pub async fn batch_send_mix_packets(
&mut self,
packets: Vec<MixPacket>,
@@ -489,9 +453,6 @@ impl GatewayClient {
if !self.authenticated {
return Err(GatewayClientError::NotAuthenticated);
}
if !self.has_bandwidth {
return Err(GatewayClientError::NotEnoughBandwidth);
}
if !self.connection.is_established() {
return Err(GatewayClientError::ConnectionNotEstablished);
}
@@ -550,9 +511,6 @@ impl GatewayClient {
if !self.authenticated {
return Err(GatewayClientError::NotAuthenticated);
}
if !self.has_bandwidth {
return Err(GatewayClientError::NotEnoughBandwidth);
}
if !self.connection.is_established() {
return Err(GatewayClientError::ConnectionNotEstablished);
}
@@ -598,9 +556,6 @@ impl GatewayClient {
if !self.authenticated {
return Err(GatewayClientError::NotAuthenticated);
}
if !self.has_bandwidth {
return Err(GatewayClientError::NotEnoughBandwidth);
}
if self.connection.is_partially_delegated() {
return Ok(());
}
@@ -633,7 +588,6 @@ impl GatewayClient {
self.establish_connection().await?;
}
let shared_key = self.perform_initial_authentication().await?;
self.claim_bandwidth().await?;
// this call is NON-blocking
self.start_listening_for_mixnet_messages()?;
@@ -31,6 +31,7 @@ flate2 = { version = "1.0.20", optional = true }
sha2 = { version = "0.9.5", optional = true }
itertools = { version = "0.10", optional = true }
cosmwasm-std = { git = "https://github.com/jstuczyn/cosmwasm", branch="0.14.1-updatedk256", optional = true }
ts-rs = "3.0"
[features]
nymd-client = ["async-trait", "bip39", "config", "cosmrs", "prost", "flate2", "sha2", "itertools", "cosmwasm-std"]
@@ -158,6 +158,10 @@ impl<C> Client<C> {
self.mixnet_contract_address = Some(mixnet_contract_address)
}
pub fn get_mixnet_contract_address(&self) -> Option<cosmrs::AccountId> {
self.mixnet_contract_address.clone()
}
pub async fn get_cached_mixnodes(&self) -> Result<Vec<MixNodeBond>, ValidatorClientError> {
Ok(self.validator_api.get_mixnodes().await?)
}
@@ -15,6 +15,7 @@ use cosmrs::rpc::{Error as TendermintRpcError, HttpClient, HttpClientUrl, Simple
use cosmrs::staking::{MsgDelegate, MsgUndelegate};
use cosmrs::tx::{Fee, Msg, MsgType, SignDoc, SignerInfo};
use cosmrs::{cosmwasm, rpc, tx, AccountId, Coin};
use log::debug;
use serde::Serialize;
use sha2::Digest;
use sha2::Sha256;
@@ -256,6 +257,48 @@ pub trait SigningCosmWasmClient: CosmWasmClient {
})
}
async fn execute_multiple<I, M>(
&self,
sender_address: &AccountId,
contract_address: &AccountId,
msgs: I,
fee: Fee,
memo: impl Into<String> + Send + 'static,
) -> Result<ExecuteResult, NymdError>
where
I: IntoIterator<Item = (M, Vec<Coin>)> + Send,
M: Serialize,
{
let messages = msgs
.into_iter()
.map(|(msg, funds)| {
cosmwasm::MsgExecuteContract {
sender: sender_address.clone(),
contract: contract_address.clone(),
msg: serde_json::to_vec(&msg)?,
funds,
}
.to_msg()
.map_err(|_| NymdError::SerializationError("MsgExecuteContract".to_owned()))
})
.collect::<Result<_, _>>()?;
let tx_res = self
.sign_and_broadcast_commit(sender_address, messages, fee, memo)
.await?
.check_response()?;
debug!(
"gas wanted: {:?}, gas used: {:?}",
tx_res.deliver_tx.gas_wanted, tx_res.deliver_tx.gas_used
);
Ok(ExecuteResult {
logs: parse_raw_logs(tx_res.deliver_tx.log)?,
transaction_hash: tx_res.hash,
})
}
async fn send_tokens(
&self,
sender_address: &AccountId,
@@ -442,6 +485,7 @@ pub trait SigningCosmWasmClient: CosmWasmClient {
}
}
#[derive(Debug)]
pub struct Client {
rpc_client: HttpClient,
signer: DirectSecp256k1HdWallet,
@@ -3,10 +3,12 @@
use crate::nymd::cosmwasm_client::types::ContractCodeId;
use cosmrs::tendermint::block;
use cosmrs::{bip32, rpc, tx, AccountId};
use cosmrs::{bip32, tx, AccountId};
use std::io;
use thiserror::Error;
pub use cosmrs::rpc::error::{Code, Error as TendermintRpcError};
#[derive(Debug, Error)]
pub enum NymdError {
#[error("No contract address is available to perform the call")]
@@ -31,7 +33,7 @@ pub enum NymdError {
InvalidTxHash(String),
#[error("There was an issue with a tendermint RPC request - {0}")]
TendermintError(#[from] rpc::Error),
TendermintError(#[from] TendermintRpcError),
#[error("There was an issue when attempting to serialize data")]
SerializationError(String),
@@ -98,3 +100,48 @@ pub enum NymdError {
#[error("The provided gas price is malformed")]
MalformedGasPrice,
}
impl NymdError {
pub fn is_tendermint_timeout(&self) -> bool {
match &self {
NymdError::TendermintError(tm_err) => {
if tm_err.code() == Code::InternalError {
// 0.34 (and earlier) versions of tendermint seemed to be using phrase "timed out waiting ..."
// (https://github.com/tendermint/tendermint/blob/v0.34.13/rpc/core/mempool.go#L124)
// while 0.35+ has "timeout waiting for ..."
// https://github.com/tendermint/tendermint/blob/v0.35.0-rc3/internal/rpc/core/mempool.go#L99
// note that as of the time of writing this comment (08.10.2021), the most recent version
// of cosmos-sdk (v0.44.1) uses tendermint 0.34.13
if let Some(data) = tm_err.data() {
data.contains("timed out") || data.contains("timeout")
} else {
false
}
} else {
false
}
}
_ => false,
}
}
pub fn is_tendermint_duplicate(&self) -> bool {
match &self {
NymdError::TendermintError(tm_err) => {
if tm_err.code() == Code::InternalError {
// this particular error message seems to be unchanged between 0.34 and newer versions
// https://github.com/tendermint/tendermint/blob/v0.34.13/mempool/errors.go#L10
// https://github.com/tendermint/tendermint/blob/v0.35.0-rc3/types/mempool.go#L10
if let Some(data) = tm_err.data() {
data.contains("tx already exists in cache")
} else {
false
}
} else {
false
}
}
_ => false,
}
}
}
@@ -4,9 +4,11 @@
use crate::nymd::GasPrice;
use cosmrs::tx::{Fee, Gas};
use cosmrs::Coin;
use cosmwasm_std::Uint128;
use serde::{Deserialize, Serialize};
use std::fmt;
use ts_rs::TS;
#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Serialize, Deserialize, TS)]
pub enum Operation {
Upload,
Init,
@@ -28,18 +30,33 @@ pub enum Operation {
}
pub(crate) fn calculate_fee(gas_price: &GasPrice, gas_limit: Gas) -> Coin {
let limit_uint128 = Uint128::from(gas_limit.value());
let amount = gas_price.amount * limit_uint128;
assert!(amount.u128() <= u64::MAX as u128);
Coin {
denom: gas_price.denom.clone(),
amount: (amount.u128() as u64).into(),
gas_price * gas_limit
}
impl fmt::Display for Operation {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
Operation::Upload => f.write_str("Upload"),
Operation::Init => f.write_str("Init"),
Operation::Migrate => f.write_str("Migrate"),
Operation::ChangeAdmin => f.write_str("ChangeAdmin"),
Operation::Send => f.write_str("Send"),
Operation::BondMixnode => f.write_str("BondMixnode"),
Operation::UnbondMixnode => f.write_str("UnbondMixnode"),
Operation::DelegateToMixnode => f.write_str("DelegateToMixnode"),
Operation::UndelegateFromMixnode => f.write_str("UndelegateFromMixnode"),
Operation::BondGateway => f.write_str("BondGateway"),
Operation::UnbondGateway => f.write_str("UnbondGateway"),
Operation::DelegateToGateway => f.write_str("DelegateToGateway"),
Operation::UndelegateFromGateway => f.write_str("UndelegateFromGateway"),
Operation::UpdateStateParams => f.write_str("UpdateStateParams"),
}
}
}
impl Operation {
// TODO: some value tweaking
pub(crate) fn default_gas_limit(&self) -> Gas {
pub fn default_gas_limit(&self) -> Gas {
match self {
Operation::Upload => 2_500_000u64.into(),
Operation::Init => 500_000u64.into(),
@@ -61,16 +78,20 @@ impl Operation {
}
}
pub(crate) fn determine_fee(&self, gas_price: &GasPrice, gas_limit: Option<Gas>) -> Fee {
pub(crate) fn determine_custom_fee(gas_price: &GasPrice, gas_limit: Gas) -> Fee {
// we need to know 2 of the following 3 parameters (the third one is being implicit) in order to construct Fee:
// (source: https://docs.cosmos.network/v0.42/basics/gas-fees.html)
// - gas price
// - gas limit
// - fees
let gas_limit = gas_limit.unwrap_or_else(|| self.default_gas_limit());
let fee = calculate_fee(gas_price, gas_limit);
Fee::from_amount_and_gas(fee, gas_limit)
}
pub(crate) fn determine_fee(&self, gas_price: &GasPrice, gas_limit: Option<Gas>) -> Fee {
let gas_limit = gas_limit.unwrap_or_else(|| self.default_gas_limit());
Self::determine_custom_fee(gas_price, gas_limit)
}
}
#[cfg(test)]
@@ -3,8 +3,10 @@
use crate::nymd::error::NymdError;
use config::defaults;
use cosmrs::Denom;
use cosmwasm_std::Decimal;
use cosmrs::tx::Gas;
use cosmrs::{Coin, Denom};
use cosmwasm_std::{Decimal, Fraction, Uint128};
use std::ops::Mul;
use std::str::FromStr;
/// A gas price, i.e. the price of a single unit of gas. This is typically a fraction of
@@ -18,6 +20,36 @@ pub struct GasPrice {
pub denom: Denom,
}
impl<'a> Mul<Gas> for &'a GasPrice {
type Output = Coin;
fn mul(self, gas_limit: Gas) -> Self::Output {
let limit_uint128 = Uint128::from(gas_limit.value());
let mut amount = self.amount * limit_uint128;
let gas_price_numerator = self.amount.numerator();
let gas_price_denominator = self.amount.denominator();
// gas price is a fraction of the smallest fee token unit, so we must ensure that
// for any multiplication, we have rounded up
//
// I don't really like the this solution as it has a theoretical chance of
// overflowing (internally cosmwasm uses U256 to avoid that)
// however, realistically that is impossible to happen as the resultant value
// would have to be way higher than our token limit of 10^15 (1 billion of tokens * 1 million for denomination)
// and max value of u128 is approximately 10^38
if limit_uint128.u128() * gas_price_numerator > amount.u128() * gas_price_denominator {
amount += Uint128::new(1);
}
assert!(amount.u128() <= u64::MAX as u128);
Coin {
denom: self.denom.clone(),
amount: (amount.u128() as u64).into(),
}
}
}
impl FromStr for GasPrice {
type Err = NymdError;
@@ -78,4 +110,15 @@ mod tests {
assert!("0.025 upunk".parse::<GasPrice>().is_err());
assert!("0.025UPUNK".parse::<GasPrice>().is_err());
}
#[test]
fn gas_limit_multiplication() {
// real world example that caused an issue when the result was rounded down
let gas_price: GasPrice = "0.025upunk".parse().unwrap();
let gas_limit: Gas = 157500u64.into();
let fee = &gas_price * gas_limit;
// the failing behaviour was result value of 3937
assert_eq!(fee.amount, 3938u64.into());
}
}
@@ -4,14 +4,13 @@
use crate::nymd::cosmwasm_client::signing_client;
use crate::nymd::cosmwasm_client::types::{
ChangeAdminResult, ContractCodeId, ExecuteResult, InstantiateOptions, InstantiateResult,
MigrateResult, UploadMeta, UploadResult,
MigrateResult, SequenceResponse, UploadMeta, UploadResult,
};
use crate::nymd::error::NymdError;
use crate::nymd::fee_helpers::Operation;
use crate::nymd::wallet::DirectSecp256k1HdWallet;
use cosmrs::rpc::endpoint::broadcast;
use cosmrs::rpc::{Error as TendermintRpcError, HttpClientUrl};
use cosmrs::tx::{Fee, Gas};
use cosmwasm_std::Coin;
use mixnet_contract::{
@@ -29,16 +28,20 @@ pub use crate::nymd::cosmwasm_client::client::CosmWasmClient;
pub use crate::nymd::cosmwasm_client::signing_client::SigningCosmWasmClient;
pub use crate::nymd::gas_price::GasPrice;
pub use cosmrs::rpc::HttpClient as QueryNymdClient;
use cosmrs::tendermint::block::Height;
pub use cosmrs::tendermint::Time as TendermintTime;
pub use cosmrs::tx::{Fee, Gas};
pub use cosmrs::Coin as CosmosCoin;
pub use cosmrs::{AccountId, Denom};
pub use signing_client::Client as SigningNymdClient;
pub mod cosmwasm_client;
pub mod error;
pub(crate) mod fee_helpers;
pub mod fee_helpers;
pub mod gas_price;
pub mod wallet;
#[derive(Debug)]
pub struct NymdClient<C> {
client: C,
contract_address: Option<AccountId>,
@@ -124,6 +127,14 @@ impl<C> NymdClient<C> {
self.custom_gas_limits.insert(operation, limit);
}
pub fn get_gas_price(&self) -> GasPrice {
self.gas_price.clone()
}
pub fn get_custom_gas_limits(&self) -> HashMap<Operation, Gas> {
self.custom_gas_limits.clone()
}
pub fn contract_address(&self) -> Result<&AccountId, NymdError> {
self.contract_address
.as_ref()
@@ -145,11 +156,36 @@ impl<C> NymdClient<C> {
&self.client_address.as_ref().unwrap()[0]
}
fn get_fee(&self, operation: Operation) -> Fee {
pub async fn account_sequence(&self) -> Result<SequenceResponse, NymdError>
where
C: SigningCosmWasmClient + Sync,
{
self.client.get_sequence(self.address()).await
}
pub fn get_fee(&self, operation: Operation) -> Fee {
let gas_limit = self.custom_gas_limits.get(&operation).cloned();
operation.determine_fee(&self.gas_price, gas_limit)
}
pub async fn get_current_block_height(&self) -> Result<Height, NymdError>
where
C: CosmWasmClient + Sync,
{
self.client.get_height().await
}
pub fn calculate_custom_fee(&self, gas_limit: impl Into<Gas>) -> Fee {
Operation::determine_custom_fee(&self.gas_price, gas_limit.into())
}
pub async fn get_current_block_timestamp(&self) -> Result<TendermintTime, NymdError>
where
C: CosmWasmClient + Sync,
{
Ok(self.client.get_block(None).await?.block.header.time)
}
pub async fn get_balance(&self, address: &AccountId) -> Result<Option<CosmosCoin>, NymdError>
where
C: CosmWasmClient + Sync,
@@ -391,6 +427,23 @@ impl<C> NymdClient<C> {
.await
}
pub async fn execute_multiple<I, M>(
&self,
contract_address: &AccountId,
msgs: I,
fee: Fee,
memo: impl Into<String> + Send + 'static,
) -> Result<ExecuteResult, NymdError>
where
C: SigningCosmWasmClient + Sync,
I: IntoIterator<Item = (M, Vec<CosmosCoin>)> + Send,
M: Serialize,
{
self.client
.execute_multiple(self.address(), contract_address, msgs, fee, memo)
.await
}
pub async fn upload(
&self,
wasm_code: Vec<u8>,
@@ -517,15 +570,17 @@ impl<C> NymdClient<C> {
/// Delegates specified amount of stake to particular mixnode.
pub async fn delegate_to_mixnode(
&self,
mix_identity: IdentityKey,
amount: Coin,
mix_identity: &str,
amount: &Coin,
) -> Result<ExecuteResult, NymdError>
where
C: SigningCosmWasmClient + Sync,
{
let fee = self.get_fee(Operation::DelegateToMixnode);
let req = ExecuteMsg::DelegateToMixnode { mix_identity };
let req = ExecuteMsg::DelegateToMixnode {
mix_identity: mix_identity.to_string(),
};
self.client
.execute(
self.address(),
@@ -533,7 +588,7 @@ impl<C> NymdClient<C> {
&req,
fee,
"Delegating to mixnode from rust!",
vec![cosmwasm_coin_to_cosmos_coin(amount)],
vec![cosmwasm_coin_ptr_to_cosmos_coin(amount)],
)
.await
}
@@ -541,14 +596,16 @@ impl<C> NymdClient<C> {
/// Removes stake delegation from a particular mixnode.
pub async fn remove_mixnode_delegation(
&self,
mix_identity: IdentityKey,
mix_identity: &str,
) -> Result<ExecuteResult, NymdError>
where
C: SigningCosmWasmClient + Sync,
{
let fee = self.get_fee(Operation::UndelegateFromMixnode);
let req = ExecuteMsg::UndelegateFromMixnode { mix_identity };
let req = ExecuteMsg::UndelegateFromMixnode {
mix_identity: mix_identity.to_string(),
};
self.client
.execute(
self.address(),
@@ -608,15 +665,17 @@ impl<C> NymdClient<C> {
/// Delegates specified amount of stake to particular gateway.
pub async fn delegate_to_gateway(
&self,
gateway_identity: IdentityKey,
amount: Coin,
gateway_identity: &str,
amount: &Coin,
) -> Result<ExecuteResult, NymdError>
where
C: SigningCosmWasmClient + Sync,
{
let fee = self.get_fee(Operation::DelegateToGateway);
let req = ExecuteMsg::DelegateToGateway { gateway_identity };
let req = ExecuteMsg::DelegateToGateway {
gateway_identity: gateway_identity.to_string(),
};
self.client
.execute(
self.address(),
@@ -624,7 +683,7 @@ impl<C> NymdClient<C> {
&req,
fee,
"Delegating to gateway from rust!",
vec![cosmwasm_coin_to_cosmos_coin(amount)],
vec![cosmwasm_coin_ptr_to_cosmos_coin(amount)],
)
.await
}
@@ -632,14 +691,16 @@ impl<C> NymdClient<C> {
/// Removes stake delegation from a particular gateway.
pub async fn remove_gateway_delegation(
&self,
gateway_identity: IdentityKey,
gateway_identity: &str,
) -> Result<ExecuteResult, NymdError>
where
C: SigningCosmWasmClient + Sync,
{
let fee = self.get_fee(Operation::UndelegateFromGateway);
let req = ExecuteMsg::UndelegateFromGateway { gateway_identity };
let req = ExecuteMsg::UndelegateFromGateway {
gateway_identity: gateway_identity.to_string(),
};
self.client
.execute(
self.address(),
@@ -682,3 +743,11 @@ fn cosmwasm_coin_to_cosmos_coin(coin: Coin) -> CosmosCoin {
amount: (coin.amount.u128() as u64).into(),
}
}
fn cosmwasm_coin_ptr_to_cosmos_coin(coin: &Coin) -> CosmosCoin {
CosmosCoin {
denom: coin.denom.parse().unwrap(),
// this might be a bit iffy, cosmwasm coin stores value as u128, while cosmos does it as u64
amount: (coin.amount.u128() as u64).into(),
}
}
@@ -10,6 +10,7 @@ use cosmrs::tx::SignDoc;
use cosmrs::{tx, AccountId};
/// Derivation information required to derive a keypair and an address from a mnemonic.
#[derive(Debug)]
struct Secp256k1Derivation {
hd_path: DerivationPath,
prefix: String,
@@ -23,8 +24,23 @@ pub struct AccountData {
pub(crate) private_key: SigningKey,
}
impl AccountData {
pub fn address(&self) -> &AccountId {
&self.address
}
pub fn public_key(&self) -> PublicKey {
self.public_key
}
pub fn private_key(&self) -> &SigningKey {
&self.private_key
}
}
type Secp256k1Keypair = (SigningKey, PublicKey);
#[derive(Debug)]
pub struct DirectSecp256k1HdWallet {
/// Base secret
secret: bip39::Mnemonic,
+7 -8
View File
@@ -7,15 +7,14 @@ edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
aes-ctr = "0.6.0"
bs58 = "0.4"
blake3 = "0.3"
#blake3 = { version = "0.3", features = ["traits-preview"]}
digest = "0.9"
aes = { version = "0.7.4", features = ["ctr"] }
bs58 = "0.4.0"
blake3 = { version = "1.0.0", features = ["traits-preview"] }
digest = "0.9.0"
generic-array = "0.14"
hkdf = "0.10"
hmac = "0.8"
cipher = "0.2"
hkdf = "0.11.0"
hmac = "0.11.0"
cipher = "0.3.0"
x25519-dalek = "1.1"
ed25519-dalek = "1.0"
log = "0.4"
+2 -2
View File
@@ -18,7 +18,7 @@ where
D::OutputSize: ArrayLength<u8>,
{
let mut hmac =
Hmac::<D>::new_varkey(key).expect("HMAC should be able to take key of any size!");
Hmac::<D>::new_from_slice(key).expect("HMAC should be able to take key of any size!");
hmac.update(data);
hmac.finalize()
}
@@ -31,7 +31,7 @@ where
D::OutputSize: ArrayLength<u8>,
{
let mut hmac =
Hmac::<D>::new_varkey(key).expect("HMAC should be able to take key of any size!");
Hmac::<D>::new_from_slice(key).expect("HMAC should be able to take key of any size!");
hmac.update(data);
// note, under the hood ct_eq is called
hmac.verify(tag).is_ok()
+1 -1
View File
@@ -13,7 +13,7 @@ pub use generic_array;
// with the below my idea was to try to introduce having a single place of importing all hashing, encryption,
// etc. algorithms and import them elsewhere as needed via common/crypto
pub use aes_ctr;
pub use aes;
pub use blake3;
// TODO: this function uses all three modules: asymmetric crypto, symmetric crypto and derives key...,
+7 -7
View File
@@ -3,7 +3,7 @@
use crate::asymmetric::encryption;
use crate::hkdf;
use cipher::stream::{Key, NewStreamCipher, SyncStreamCipher};
use cipher::{CipherKey, NewCipher, StreamCipher};
use digest::{BlockInput, FixedOutput, Reset, Update};
use generic_array::{typenum::Unsigned, ArrayLength};
use rand::{CryptoRng, RngCore};
@@ -13,9 +13,9 @@ use rand::{CryptoRng, RngCore};
pub fn new_ephemeral_shared_key<C, D, R>(
rng: &mut R,
remote_key: &encryption::PublicKey,
) -> (encryption::KeyPair, Key<C>)
) -> (encryption::KeyPair, CipherKey<C>)
where
C: SyncStreamCipher + NewStreamCipher,
C: StreamCipher + NewCipher,
D: Update + BlockInput + FixedOutput + Reset + Default + Clone,
D::BlockSize: ArrayLength<u8>,
D::OutputSize: ArrayLength<u8>,
@@ -31,7 +31,7 @@ where
.expect("somehow too long okm was provided");
let derived_shared_key =
Key::<C>::from_exact_iter(okm).expect("okm was expanded to incorrect length!");
CipherKey::<C>::from_exact_iter(okm).expect("okm was expanded to incorrect length!");
(ephemeral_keypair, derived_shared_key)
}
@@ -40,9 +40,9 @@ where
pub fn recompute_shared_key<C, D>(
remote_key: &encryption::PublicKey,
local_key: &encryption::PrivateKey,
) -> Key<C>
) -> CipherKey<C>
where
C: SyncStreamCipher + NewStreamCipher,
C: StreamCipher + NewCipher,
D: Update + BlockInput + FixedOutput + Reset + Default + Clone,
D::BlockSize: ArrayLength<u8>,
D::OutputSize: ArrayLength<u8>,
@@ -53,5 +53,5 @@ where
let okm = hkdf::extract_then_expand::<D>(None, &dh_result, None, C::KeySize::to_usize())
.expect("somehow too long okm was provided");
Key::<C>::from_exact_iter(okm).expect("okm was expanded to incorrect length!")
CipherKey::<C>::from_exact_iter(okm).expect("okm was expanded to incorrect length!")
}
+23 -18
View File
@@ -1,13 +1,14 @@
// Copyright 2020 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use cipher::stream::{Nonce, StreamCipher, SyncStreamCipher};
use cipher::{Nonce, StreamCipher};
use generic_array::{typenum::Unsigned, GenericArray};
use rand::{CryptoRng, RngCore};
// re-export this for ease of use
pub use cipher::stream::{Key, NewStreamCipher};
pub use cipher::{CipherKey, NewCipher};
// SECURITY:
// TODO: note that this is not the most secure approach here
// we are not using nonces properly but instead "kinda" thinking of them as IVs.
// Nonce require, as the name suggest, being only seen once. Ever.
@@ -20,9 +21,9 @@ pub use cipher::stream::{Key, NewStreamCipher};
#[allow(clippy::upper_case_acronyms)]
pub type IV<C> = Nonce<C>;
pub fn generate_key<C, R>(rng: &mut R) -> Key<C>
pub fn generate_key<C, R>(rng: &mut R) -> CipherKey<C>
where
C: NewStreamCipher,
C: NewCipher,
R: RngCore + CryptoRng,
{
let mut key = GenericArray::default();
@@ -32,7 +33,7 @@ where
pub fn random_iv<C, R>(rng: &mut R) -> IV<C>
where
C: NewStreamCipher,
C: NewCipher,
R: RngCore + CryptoRng,
{
let mut iv = GenericArray::default();
@@ -42,14 +43,14 @@ where
pub fn zero_iv<C>() -> IV<C>
where
C: NewStreamCipher,
C: NewCipher,
{
GenericArray::default()
}
pub fn iv_from_slice<C>(b: &[u8]) -> &IV<C>
where
C: NewStreamCipher,
C: NewCipher,
{
if b.len() != C::NonceSize::to_usize() {
// `from_slice` would have caused a panic about this issue anyway.
@@ -66,38 +67,42 @@ where
// TODO: there's really no way to use more parts of the keystream if it was required at some point.
// However, do we really expect to ever need it?
pub fn encrypt<C>(key: &Key<C>, iv: &IV<C>, data: &[u8]) -> Vec<u8>
#[inline]
pub fn encrypt<C>(key: &CipherKey<C>, iv: &IV<C>, data: &[u8]) -> Vec<u8>
where
C: SyncStreamCipher + NewStreamCipher,
C: StreamCipher + NewCipher,
{
let mut ciphertext = data.to_vec();
encrypt_in_place::<C>(key, iv, &mut ciphertext);
ciphertext
}
pub fn encrypt_in_place<C>(key: &Key<C>, iv: &IV<C>, data: &mut [u8])
#[inline]
pub fn encrypt_in_place<C>(key: &CipherKey<C>, iv: &IV<C>, data: &mut [u8])
where
C: SyncStreamCipher + NewStreamCipher,
C: StreamCipher + NewCipher,
{
let mut cipher = C::new(key, iv);
cipher.encrypt(data)
cipher.apply_keystream(data)
}
pub fn decrypt<C>(key: &Key<C>, iv: &IV<C>, ciphertext: &[u8]) -> Vec<u8>
#[inline]
pub fn decrypt<C>(key: &CipherKey<C>, iv: &IV<C>, ciphertext: &[u8]) -> Vec<u8>
where
C: SyncStreamCipher + NewStreamCipher,
C: StreamCipher + NewCipher,
{
let mut data = ciphertext.to_vec();
decrypt_in_place::<C>(key, iv, &mut data);
data
}
pub fn decrypt_in_place<C>(key: &Key<C>, iv: &IV<C>, data: &mut [u8])
#[inline]
pub fn decrypt_in_place<C>(key: &CipherKey<C>, iv: &IV<C>, data: &mut [u8])
where
C: SyncStreamCipher + NewStreamCipher,
C: StreamCipher + NewCipher,
{
let mut cipher = C::new(key, iv);
cipher.decrypt(data)
cipher.apply_keystream(data)
}
#[cfg(test)]
@@ -108,7 +113,7 @@ mod tests {
#[cfg(test)]
mod aes_ctr128 {
use super::*;
use aes_ctr::Aes128Ctr;
use aes::Aes128Ctr;
#[test]
fn zero_iv_is_actually_zero() {
+1
View File
@@ -14,3 +14,4 @@ cosmwasm-std = { git = "https://github.com/jstuczyn/cosmwasm", branch="0.14.1-up
serde = { version = "1.0", features = ["derive"] }
serde_repr = "0.1"
schemars = "0.8"
ts-rs = "3.0"
+4
View File
@@ -45,6 +45,10 @@ impl Delegation {
pub fn owner(&self) -> Addr {
self.owner.clone()
}
pub fn block_height(&self) -> u64 {
self.block_height
}
}
impl Display for Delegation {
+2 -1
View File
@@ -6,10 +6,11 @@ use cosmwasm_std::{coin, Addr, Coin};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use std::fmt::Display;
use ts_rs::TS;
use crate::current_block_height;
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, JsonSchema)]
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, JsonSchema, TS)]
pub struct Gateway {
pub host: String,
pub mix_port: u16,
+2 -1
View File
@@ -7,10 +7,11 @@ use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use serde_repr::{Deserialize_repr, Serialize_repr};
use std::fmt::Display;
use ts_rs::TS;
use crate::current_block_height;
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, JsonSchema)]
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, JsonSchema, TS)]
pub struct MixNode {
pub host: String,
pub mix_port: u16,
+2
View File
@@ -7,4 +7,6 @@ edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
serde = {version = "1.0", features = ["derive"]}
url = "2.2"
time = { version = "0.3", features = ["macros"] }
+30 -16
View File
@@ -1,19 +1,26 @@
// Copyright 2020 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use serde::{Deserialize, Serialize};
use std::time::Duration;
use time::OffsetDateTime;
use url::Url;
pub struct ValidatorDetails<'a> {
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct ValidatorDetails {
// it is assumed those values are always valid since they're being provided in our defaults file
pub nymd_url: &'a str,
pub nymd_url: String,
// Right now api_url is optional as we are not running the api reliably on all validators
// however, later on it should be a mandatory field
pub api_url: Option<&'a str>,
pub api_url: Option<String>,
}
impl<'a> ValidatorDetails<'a> {
pub const fn new(nymd_url: &'a str, api_url: Option<&'a str>) -> Self {
ValidatorDetails { nymd_url, api_url }
impl ValidatorDetails {
pub fn new(nymd_url: &str, api_url: Option<&str>) -> Self {
let api_url = api_url.map(|api_url_str| api_url_str.to_string());
ValidatorDetails {
nymd_url: nymd_url.to_string(),
api_url,
}
}
pub fn nymd_url(&self) -> Url {
@@ -24,27 +31,30 @@ impl<'a> ValidatorDetails<'a> {
pub fn api_url(&self) -> Option<Url> {
self.api_url
.as_ref()
.map(|url| url.parse().expect("the provided api url is invalid!"))
}
}
pub const DEFAULT_VALIDATORS: &[ValidatorDetails] = &[
ValidatorDetails::new(
"https://testnet-milhon-validator1.nymtech.net",
Some("https://testnet-milhon-validator1.nymtech.net/api"),
),
ValidatorDetails::new("https://testnet-milhon-validator2.nymtech.net", None),
];
pub fn default_validators() -> Vec<ValidatorDetails> {
vec![
ValidatorDetails::new(
"https://testnet-milhon-validator1.nymtech.net",
Some("https://testnet-milhon-validator1.nymtech.net/api"),
),
ValidatorDetails::new("https://testnet-milhon-validator2.nymtech.net", None),
]
}
pub fn default_nymd_endpoints() -> Vec<Url> {
DEFAULT_VALIDATORS
default_validators()
.iter()
.map(|validator| validator.nymd_url())
.collect()
}
pub fn default_api_endpoints() -> Vec<Url> {
DEFAULT_VALIDATORS
default_validators()
.iter()
.filter_map(|validator| validator.api_url())
.collect()
@@ -80,3 +90,7 @@ pub const DEFAULT_SOCKS5_LISTENING_PORT: u16 = 1080;
pub const DEFAULT_VALIDATOR_API_PORT: u16 = 8080;
pub const VALIDATOR_API_VERSION: &str = "v1";
// REWARDING
pub const DEFAULT_FIRST_EPOCH_START: OffsetDateTime = time::macros::datetime!(2021-08-23 12:00 UTC);
pub const DEFAULT_EPOCH_LENGTH: Duration = Duration::from_secs(24 * 60 * 60); // 24h
@@ -3,7 +3,7 @@
use crate::AckKey;
use crypto::generic_array::typenum::Unsigned;
use crypto::symmetric::stream_cipher::{self, encrypt, iv_from_slice, random_iv, NewStreamCipher};
use crypto::symmetric::stream_cipher::{self, encrypt, iv_from_slice, random_iv, NewCipher};
use nymsphinx_params::{
packet_sizes::PacketSize, AckEncryptionAlgorithm, SerializedFragmentIdentifier, FRAG_ID_LEN,
};
@@ -33,7 +33,7 @@ pub fn recover_identifier(
return None;
}
let iv_size = <AckEncryptionAlgorithm as NewStreamCipher>::NonceSize::to_usize();
let iv_size = <AckEncryptionAlgorithm as NewCipher>::NonceSize::to_usize();
let iv = iv_from_slice::<AckEncryptionAlgorithm>(&iv_id_ciphertext[..iv_size]);
let id = stream_cipher::decrypt::<AckEncryptionAlgorithm>(
+4 -4
View File
@@ -2,13 +2,13 @@
// SPDX-License-Identifier: Apache-2.0
use crypto::generic_array::{typenum::Unsigned, GenericArray};
use crypto::symmetric::stream_cipher::{generate_key, Key, NewStreamCipher};
use crypto::symmetric::stream_cipher::{generate_key, CipherKey, NewCipher};
use nymsphinx_params::AckEncryptionAlgorithm;
use pemstore::traits::PemStorableKey;
use rand::{CryptoRng, RngCore};
use std::fmt::{self, Display, Formatter};
pub struct AckKey(Key<AckEncryptionAlgorithm>);
pub struct AckKey(CipherKey<AckEncryptionAlgorithm>);
#[derive(Debug)]
pub enum AckKeyConversionError {
@@ -33,7 +33,7 @@ impl AckKey {
}
pub fn try_from_bytes(bytes: &[u8]) -> Result<Self, AckKeyConversionError> {
if bytes.len() != <AckEncryptionAlgorithm as NewStreamCipher>::KeySize::to_usize() {
if bytes.len() != <AckEncryptionAlgorithm as NewCipher>::KeySize::to_usize() {
return Err(AckKeyConversionError::BytesOfInvalidLengthError);
}
@@ -48,7 +48,7 @@ impl AckKey {
self.0.as_ref()
}
pub fn inner(&self) -> &Key<AckEncryptionAlgorithm> {
pub fn inner(&self) -> &CipherKey<AckEncryptionAlgorithm> {
&self.0
}
}
@@ -5,7 +5,7 @@ pub use crypto::generic_array::typenum::Unsigned;
use crypto::{
crypto_hash,
generic_array::GenericArray,
symmetric::stream_cipher::{generate_key, Key, NewStreamCipher},
symmetric::stream_cipher::{generate_key, CipherKey, NewCipher},
Digest,
};
use nymsphinx_params::{ReplySurbEncryptionAlgorithm, ReplySurbKeyDigestAlgorithm};
@@ -15,10 +15,10 @@ use std::fmt::{self, Display, Formatter};
pub type EncryptionKeyDigest =
GenericArray<u8, <ReplySurbKeyDigestAlgorithm as Digest>::OutputSize>;
pub type SurbEncryptionKeySize = <ReplySurbEncryptionAlgorithm as NewStreamCipher>::KeySize;
pub type SurbEncryptionKeySize = <ReplySurbEncryptionAlgorithm as NewCipher>::KeySize;
#[derive(Clone, Debug)]
pub struct SurbEncryptionKey(Key<ReplySurbEncryptionAlgorithm>);
pub struct SurbEncryptionKey(CipherKey<ReplySurbEncryptionAlgorithm>);
#[derive(Debug)]
pub enum SurbEncryptionKeyError {
@@ -64,7 +64,7 @@ impl SurbEncryptionKey {
self.0.as_ref()
}
pub fn inner(&self) -> &Key<ReplySurbEncryptionAlgorithm> {
pub fn inner(&self) -> &CipherKey<ReplySurbEncryptionAlgorithm> {
&self.0
}
}
@@ -196,7 +196,7 @@ impl ReplySurb {
message: &[u8],
packet_size: Option<PacketSize>,
) -> Result<(SphinxPacket, NymNodeRoutingAddress), ReplySurbError> {
let packet_size = packet_size.unwrap_or_else(Default::default);
let packet_size = packet_size.unwrap_or_default();
if message.len() != packet_size.plaintext_size() {
return Err(ReplySurbError::UnpaddedMessageError);
+1 -1
View File
@@ -1,7 +1,7 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crypto::aes_ctr::Aes128Ctr;
use crypto::aes::Aes128Ctr;
use crypto::blake3;
// Re-export for ease of use
+618 -11
View File
@@ -2,6 +2,45 @@
# It is not intended for manual editing.
version = 3
[[package]]
name = "Inflector"
version = "0.11.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3"
dependencies = [
"lazy_static",
"regex",
]
[[package]]
name = "aho-corasick"
version = "0.7.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
dependencies = [
"memchr",
]
[[package]]
name = "ast_node"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f93f52ce8fac3d0e6720a92b0576d737c01b1b5db4dd786e962e5925f00bf755"
dependencies = [
"darling",
"pmutil",
"proc-macro2",
"quote",
"swc_macros_common",
"syn",
]
[[package]]
name = "autocfg"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
[[package]]
name = "base64"
version = "0.13.0"
@@ -38,6 +77,12 @@ dependencies = [
"byte-tools",
]
[[package]]
name = "bumpalo"
version = "3.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9df67f7bf9ef8498769f994239c45613ef0c5899415fb58e9add412d2c1a538"
[[package]]
name = "byte-tools"
version = "0.3.1"
@@ -50,6 +95,12 @@ version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
[[package]]
name = "cfg-if"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
[[package]]
name = "cfg-if"
version = "1.0.0"
@@ -178,6 +229,41 @@ dependencies = [
"zeroize",
]
[[package]]
name = "darling"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d706e75d87e35569db781a9b5e2416cff1236a47ed380831f959382ccd5f858"
dependencies = [
"darling_core",
"darling_macro",
]
[[package]]
name = "darling_core"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0c960ae2da4de88a91b2d920c2a7233b400bc33cb28453a2987822d8392519b"
dependencies = [
"fnv",
"ident_case",
"proc-macro2",
"quote",
"strsim",
"syn",
]
[[package]]
name = "darling_macro"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b5a2f4ac4969822c62224815d069952656cadc7084fdca9751e6d959189b72"
dependencies = [
"darling_core",
"quote",
"syn",
]
[[package]]
name = "der"
version = "0.4.0"
@@ -205,6 +291,45 @@ dependencies = [
"generic-array 0.14.4",
]
[[package]]
name = "dprint-core"
version = "0.35.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93bd44f40b1881477837edc7112695d4b174f058c36c1cbc4c50f8d0482e2ac8"
dependencies = [
"bumpalo",
"fnv",
"serde",
]
[[package]]
name = "dprint-plugin-typescript"
version = "0.43.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67ba0077bd2ab9235848e793fbbfb563e6a04b4c8e4149827802a84063c15805"
dependencies = [
"dprint-core",
"dprint-swc-ecma-ast-view",
"fnv",
"serde",
"swc_common",
"swc_ecmascript",
]
[[package]]
name = "dprint-swc-ecma-ast-view"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ecf692a2ee5c5f699ed0e95f21686cf6367f3a591e5d8e7bd3041bbf184651f9"
dependencies = [
"bumpalo",
"fnv",
"num-bigint",
"swc_atoms",
"swc_common",
"swc_ecmascript",
]
[[package]]
name = "dyn-clone"
version = "1.0.4"
@@ -237,6 +362,12 @@ dependencies = [
"thiserror",
]
[[package]]
name = "either"
version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
[[package]]
name = "elliptic-curve"
version = "0.10.4"
@@ -253,6 +384,18 @@ dependencies = [
"zeroize",
]
[[package]]
name = "enum_kind"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78b940da354ae81ef0926c5eaa428207b8f4f091d3956c891dfbd124162bed99"
dependencies = [
"pmutil",
"proc-macro2",
"swc_macros_common",
"syn",
]
[[package]]
name = "fake-simd"
version = "0.1.2"
@@ -269,6 +412,12 @@ dependencies = [
"subtle",
]
[[package]]
name = "fnv"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]]
name = "form_urlencoded"
version = "1.0.1"
@@ -279,6 +428,27 @@ dependencies = [
"percent-encoding",
]
[[package]]
name = "from_variant"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0951635027ca477be98f8774abd6f0345233439d63f307e47101acb40c7cc63d"
dependencies = [
"pmutil",
"proc-macro2",
"swc_macros_common",
"syn",
]
[[package]]
name = "fxhash"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c"
dependencies = [
"byteorder",
]
[[package]]
name = "generic-array"
version = "0.12.4"
@@ -304,7 +474,7 @@ version = "0.1.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce"
dependencies = [
"cfg-if",
"cfg-if 1.0.0",
"libc",
"wasi 0.9.0+wasi-snapshot-preview1",
]
@@ -315,7 +485,7 @@ version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753"
dependencies = [
"cfg-if",
"cfg-if 1.0.0",
"libc",
"wasi 0.10.2+wasi-snapshot-preview1",
]
@@ -377,6 +547,12 @@ dependencies = [
"serde",
]
[[package]]
name = "ident_case"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
[[package]]
name = "idna"
version = "0.2.3"
@@ -388,6 +564,19 @@ dependencies = [
"unicode-normalization",
]
[[package]]
name = "is-macro"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a322dd16d960e322c3d92f541b4c1a4f0a2e81e1fdeee430d8cecc8b72e8015f"
dependencies = [
"Inflector",
"pmutil",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "itoa"
version = "0.4.7"
@@ -400,17 +589,23 @@ version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "008b0281ca8032567c9711cd48631781c15228301860a39b32deb28d63125e46"
dependencies = [
"cfg-if",
"cfg-if 1.0.0",
"ecdsa",
"elliptic-curve",
"sha2",
]
[[package]]
name = "libc"
version = "0.2.95"
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "789da6d93f1b866ffe175afc5322a4d76c038605a1c3319bb57b06967ca98a36"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1fa8cddc8fbbee11227ef194b5317ed014b8acbf15139bd716a18ad3fe99ec5"
[[package]]
name = "log"
@@ -418,7 +613,7 @@ version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
dependencies = [
"cfg-if",
"cfg-if 1.0.0",
]
[[package]]
@@ -433,6 +628,12 @@ version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
[[package]]
name = "memchr"
version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
[[package]]
name = "mixnet-contract"
version = "0.1.0"
@@ -441,6 +642,7 @@ dependencies = [
"schemars",
"serde",
"serde_repr",
"ts-rs",
]
[[package]]
@@ -461,9 +663,54 @@ dependencies = [
name = "network-defaults"
version = "0.1.0"
dependencies = [
"serde",
"time",
"url",
]
[[package]]
name = "new_debug_unreachable"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54"
[[package]]
name = "num-bigint"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304"
dependencies = [
"autocfg",
"num-integer",
"num-traits",
"serde",
]
[[package]]
name = "num-integer"
version = "0.1.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db"
dependencies = [
"autocfg",
"num-traits",
]
[[package]]
name = "num-traits"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
dependencies = [
"autocfg",
]
[[package]]
name = "once_cell"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56"
[[package]]
name = "opaque-debug"
version = "0.2.3"
@@ -476,6 +723,15 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
[[package]]
name = "owning_ref"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ff55baddef9e4ad00f88b6c743a2a8062d4c6ade126c2a528644b8e444d52ce"
dependencies = [
"stable_deref_trait",
]
[[package]]
name = "percent-encoding"
version = "2.1.0"
@@ -525,6 +781,25 @@ dependencies = [
"sha-1",
]
[[package]]
name = "phf_generator"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17367f0cc86f2d25802b2c26ee58a7b23faeccf78a396094c13dced0d0182526"
dependencies = [
"phf_shared",
"rand",
]
[[package]]
name = "phf_shared"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c00cf8b9eafe68dde5e9eaa2cef8ee84a9336a47d566ec55ca16589633b65af7"
dependencies = [
"siphasher",
]
[[package]]
name = "pkcs8"
version = "0.7.5"
@@ -535,6 +810,29 @@ dependencies = [
"spki",
]
[[package]]
name = "pmutil"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3894e5d549cccbe44afecf72922f277f603cd4bb0219c8342631ef18fffbe004"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "ppv-lite86"
version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857"
[[package]]
name = "precomputed-hash"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
[[package]]
name = "proc-macro2"
version = "1.0.24"
@@ -559,6 +857,30 @@ dependencies = [
"proc-macro2",
]
[[package]]
name = "rand"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
dependencies = [
"getrandom 0.1.16",
"libc",
"rand_chacha",
"rand_core 0.5.1",
"rand_hc",
"rand_pcg",
]
[[package]]
name = "rand_chacha"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
dependencies = [
"ppv-lite86",
"rand_core 0.5.1",
]
[[package]]
name = "rand_core"
version = "0.5.1"
@@ -577,6 +899,41 @@ dependencies = [
"getrandom 0.2.3",
]
[[package]]
name = "rand_hc"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
dependencies = [
"rand_core 0.5.1",
]
[[package]]
name = "rand_pcg"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429"
dependencies = [
"rand_core 0.5.1",
]
[[package]]
name = "regex"
version = "1.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.6.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
[[package]]
name = "ryu"
version = "1.0.5"
@@ -607,6 +964,12 @@ dependencies = [
"syn",
]
[[package]]
name = "scoped-tls"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2"
[[package]]
name = "serde"
version = "1.0.122"
@@ -688,7 +1051,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b362ae5752fd2137731f9fa25fd4d9058af34666ca1966fb969119cc35719f12"
dependencies = [
"block-buffer 0.9.0",
"cfg-if",
"cfg-if 1.0.0",
"cpufeatures",
"digest 0.9.0",
"opaque-debug 0.3.0",
@@ -704,6 +1067,18 @@ dependencies = [
"rand_core 0.6.3",
]
[[package]]
name = "siphasher"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "533494a8f9b724d33625ab53c6c4800f7cc445895924a8ef649222dcb76e938b"
[[package]]
name = "smallvec"
version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e"
[[package]]
name = "spki"
version = "0.4.0"
@@ -713,12 +1088,62 @@ dependencies = [
"der",
]
[[package]]
name = "stable_deref_trait"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
[[package]]
name = "static_assertions"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
name = "string_cache"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ddb1139b5353f96e429e1a5e19fbaf663bddedaa06d1dbd49f82e352601209a"
dependencies = [
"lazy_static",
"new_debug_unreachable",
"phf_shared",
"precomputed-hash",
"serde",
]
[[package]]
name = "string_cache_codegen"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f24c8e5e19d22a726626f1a5e16fe15b132dcf21d10177fa5a45ce7962996b97"
dependencies = [
"phf_generator",
"phf_shared",
"proc-macro2",
"quote",
]
[[package]]
name = "string_enum"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f584cc881e9e5f1fd6bf827b0444aa94c30d8fe6378cf241071b5f5700b2871f"
dependencies = [
"pmutil",
"proc-macro2",
"quote",
"swc_macros_common",
"syn",
]
[[package]]
name = "strsim"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c"
[[package]]
name = "subtle"
version = "2.4.0"
@@ -726,10 +1151,148 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e81da0851ada1f3e9d4312c704aa4f8806f0f9d69faaf8df2f3464b4a9437c2"
[[package]]
name = "syn"
version = "1.0.60"
name = "swc_atoms"
version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c700597eca8a5a762beb35753ef6b94df201c81cca676604f547495a0d7f0081"
checksum = "837a3ef86c2817228e733b6f173c821fd76f9eb21a0bc9001a826be48b00b4e7"
dependencies = [
"string_cache",
"string_cache_codegen",
]
[[package]]
name = "swc_common"
version = "0.10.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c93df65683ec1a001e15ce1de438c7c2c226c0c2462d1cb93fa1bd2a7664170b"
dependencies = [
"ast_node",
"cfg-if 0.1.10",
"either",
"from_variant",
"fxhash",
"log",
"num-bigint",
"once_cell",
"owning_ref",
"scoped-tls",
"serde",
"string_cache",
"swc_eq_ignore_macros",
"swc_visit",
"unicode-width",
]
[[package]]
name = "swc_ecma_ast"
version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "83eb6a73820660a5af3c24ae1d436e84e4d4c13822021140011361e678df247b"
dependencies = [
"is-macro",
"num-bigint",
"serde",
"string_enum",
"swc_atoms",
"swc_common",
]
[[package]]
name = "swc_ecma_parser"
version = "0.52.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c03250697857164f16fa98f8e1726f566652d13e52ea3f0c3ecea9deb63ee327"
dependencies = [
"either",
"enum_kind",
"fxhash",
"log",
"num-bigint",
"serde",
"smallvec",
"swc_atoms",
"swc_common",
"swc_ecma_ast",
"swc_ecma_visit",
"unicode-xid",
]
[[package]]
name = "swc_ecma_visit"
version = "0.28.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd3d60b9dc97ae4f181d4d60f43142d8ac9669953db410bcedefb29a14627e19"
dependencies = [
"num-bigint",
"swc_atoms",
"swc_common",
"swc_ecma_ast",
"swc_visit",
]
[[package]]
name = "swc_ecmascript"
version = "0.29.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ffb53afe008c15d4dc4957e80148c4b457659f93e4d4e8736eaeae352e48ec8"
dependencies = [
"swc_ecma_ast",
"swc_ecma_parser",
]
[[package]]
name = "swc_eq_ignore_macros"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c8f200a2eaed938e7c1a685faaa66e6d42fa9e17da5f62572d3cbc335898f5e"
dependencies = [
"pmutil",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "swc_macros_common"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08ed2e930f5a1a4071fe62c90fd3a296f6030e5d94bfe13993244423caf59a78"
dependencies = [
"pmutil",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "swc_visit"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a423caa0b4585118164dbad8f1ad52b592a9a9370b25decc4d84c6b4309132c0"
dependencies = [
"either",
"swc_visit_macros",
]
[[package]]
name = "swc_visit_macros"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3b2825fee79f10d0166e8e650e79c7a862fb991db275743083f07555d7641f0"
dependencies = [
"Inflector",
"pmutil",
"proc-macro2",
"quote",
"swc_macros_common",
"syn",
]
[[package]]
name = "syn"
version = "1.0.65"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3a1d708c221c5a612956ef9f75b37e454e88d1f7b899fbd3a18d4252012d663"
dependencies = [
"proc-macro2",
"quote",
@@ -756,6 +1319,22 @@ dependencies = [
"syn",
]
[[package]]
name = "time"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a776787d9c5d455bec3db044586ccdd8a9c74d5da5dc319fb80f3db08808fe6"
dependencies = [
"libc",
"time-macros",
]
[[package]]
name = "time-macros"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04a153416002296880a3b51329a0e3df31c779c53ec827993e865ce427982843"
[[package]]
name = "tinyvec"
version = "1.3.1"
@@ -780,6 +1359,28 @@ dependencies = [
"serde",
]
[[package]]
name = "ts-rs"
version = "3.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "369e48de67506679b3a576b0faf666fa9f9acf2fd00b4c61e28bdb6c8e08ec06"
dependencies = [
"dprint-plugin-typescript",
"ts-rs-macros",
]
[[package]]
name = "ts-rs-macros"
version = "3.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f269e8fd28e26b4cdbd01f81f345aaf666131511e54a735a76a614b5062d0a5a"
dependencies = [
"Inflector",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "typenum"
version = "1.13.0"
@@ -822,6 +1423,12 @@ dependencies = [
"tinyvec",
]
[[package]]
name = "unicode-width"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
[[package]]
name = "unicode-xid"
version = "0.2.1"
+349
View File
@@ -0,0 +1,349 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "ExecuteMsg",
"anyOf": [
{
"type": "object",
"required": [
"bond_mixnode"
],
"properties": {
"bond_mixnode": {
"type": "object",
"required": [
"mix_node"
],
"properties": {
"mix_node": {
"$ref": "#/definitions/MixNode"
}
}
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"unbond_mixnode"
],
"properties": {
"unbond_mixnode": {
"type": "object"
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"bond_gateway"
],
"properties": {
"bond_gateway": {
"type": "object",
"required": [
"gateway"
],
"properties": {
"gateway": {
"$ref": "#/definitions/Gateway"
}
}
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"unbond_gateway"
],
"properties": {
"unbond_gateway": {
"type": "object"
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"update_state_params"
],
"properties": {
"update_state_params": {
"$ref": "#/definitions/StateParams"
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"delegate_to_mixnode"
],
"properties": {
"delegate_to_mixnode": {
"type": "object",
"required": [
"mix_identity"
],
"properties": {
"mix_identity": {
"type": "string"
}
}
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"undelegate_from_mixnode"
],
"properties": {
"undelegate_from_mixnode": {
"type": "object",
"required": [
"mix_identity"
],
"properties": {
"mix_identity": {
"type": "string"
}
}
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"delegate_to_gateway"
],
"properties": {
"delegate_to_gateway": {
"type": "object",
"required": [
"gateway_identity"
],
"properties": {
"gateway_identity": {
"type": "string"
}
}
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"undelegate_from_gateway"
],
"properties": {
"undelegate_from_gateway": {
"type": "object",
"required": [
"gateway_identity"
],
"properties": {
"gateway_identity": {
"type": "string"
}
}
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"reward_mixnode"
],
"properties": {
"reward_mixnode": {
"type": "object",
"required": [
"identity",
"uptime"
],
"properties": {
"identity": {
"type": "string"
},
"uptime": {
"type": "integer",
"format": "uint32",
"minimum": 0.0
}
}
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"reward_gateway"
],
"properties": {
"reward_gateway": {
"type": "object",
"required": [
"identity",
"uptime"
],
"properties": {
"identity": {
"type": "string"
},
"uptime": {
"type": "integer",
"format": "uint32",
"minimum": 0.0
}
}
}
},
"additionalProperties": false
}
],
"definitions": {
"Decimal": {
"description": "A fixed-point decimal value with 18 fractional digits, i.e. Decimal(1_000_000_000_000_000_000) == 1.0\n\nThe greatest possible value that can be represented is 340282366920938463463.374607431768211455 (which is (2^128 - 1) / 10^18)",
"type": "string"
},
"Gateway": {
"type": "object",
"required": [
"clients_port",
"host",
"identity_key",
"location",
"mix_port",
"sphinx_key",
"version"
],
"properties": {
"clients_port": {
"type": "integer",
"format": "uint16",
"minimum": 0.0
},
"host": {
"type": "string"
},
"identity_key": {
"description": "Base58 encoded ed25519 EdDSA public key of the gateway used to derive shared keys with clients",
"type": "string"
},
"location": {
"type": "string"
},
"mix_port": {
"type": "integer",
"format": "uint16",
"minimum": 0.0
},
"sphinx_key": {
"type": "string"
},
"version": {
"type": "string"
}
}
},
"MixNode": {
"type": "object",
"required": [
"host",
"http_api_port",
"identity_key",
"mix_port",
"sphinx_key",
"verloc_port",
"version"
],
"properties": {
"host": {
"type": "string"
},
"http_api_port": {
"type": "integer",
"format": "uint16",
"minimum": 0.0
},
"identity_key": {
"description": "Base58 encoded ed25519 EdDSA public key.",
"type": "string"
},
"mix_port": {
"type": "integer",
"format": "uint16",
"minimum": 0.0
},
"sphinx_key": {
"type": "string"
},
"verloc_port": {
"type": "integer",
"format": "uint16",
"minimum": 0.0
},
"version": {
"type": "string"
}
}
},
"StateParams": {
"type": "object",
"required": [
"epoch_length",
"gateway_bond_reward_rate",
"gateway_delegation_reward_rate",
"minimum_gateway_bond",
"minimum_mixnode_bond",
"mixnode_active_set_size",
"mixnode_bond_reward_rate",
"mixnode_delegation_reward_rate"
],
"properties": {
"epoch_length": {
"type": "integer",
"format": "uint32",
"minimum": 0.0
},
"gateway_bond_reward_rate": {
"$ref": "#/definitions/Decimal"
},
"gateway_delegation_reward_rate": {
"$ref": "#/definitions/Decimal"
},
"minimum_gateway_bond": {
"$ref": "#/definitions/Uint128"
},
"minimum_mixnode_bond": {
"$ref": "#/definitions/Uint128"
},
"mixnode_active_set_size": {
"type": "integer",
"format": "uint32",
"minimum": 0.0
},
"mixnode_bond_reward_rate": {
"$ref": "#/definitions/Decimal"
},
"mixnode_delegation_reward_rate": {
"$ref": "#/definitions/Decimal"
}
}
},
"Uint128": {
"description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```",
"type": "string"
}
}
}
-134
View File
@@ -1,134 +0,0 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "HandleMsg",
"anyOf": [
{
"type": "object",
"required": [
"register_mixnode"
],
"properties": {
"register_mixnode": {
"type": "object",
"required": [
"mix_node"
],
"properties": {
"mix_node": {
"$ref": "#/definitions/MixNode"
}
}
}
}
},
{
"type": "object",
"required": [
"un_register_mixnode"
],
"properties": {
"un_register_mixnode": {
"type": "object"
}
}
},
{
"type": "object",
"required": [
"bond_gateway"
],
"properties": {
"bond_gateway": {
"type": "object",
"required": [
"gateway"
],
"properties": {
"gateway": {
"$ref": "#/definitions/Gateway"
}
}
}
}
},
{
"type": "object",
"required": [
"unbond_gateway"
],
"properties": {
"unbond_gateway": {
"type": "object"
}
}
}
],
"definitions": {
"Gateway": {
"type": "object",
"required": [
"clients_host",
"identity_key",
"location",
"mix_host",
"sphinx_key",
"version"
],
"properties": {
"clients_host": {
"type": "string"
},
"identity_key": {
"description": "Base58 encoded ed25519 EdDSA public key of the gateway used to derive shared keys with clients",
"type": "string"
},
"location": {
"type": "string"
},
"mix_host": {
"type": "string"
},
"sphinx_key": {
"type": "string"
},
"version": {
"type": "string"
}
}
},
"MixNode": {
"type": "object",
"required": [
"host",
"identity_key",
"layer",
"location",
"sphinx_key",
"version"
],
"properties": {
"host": {
"type": "string"
},
"identity_key": {
"description": "Base58 encoded ed25519 EdDSA public key.",
"type": "string"
},
"layer": {
"type": "integer",
"format": "uint64",
"minimum": 0.0
},
"location": {
"type": "string"
},
"sphinx_key": {
"type": "string"
},
"version": {
"type": "string"
}
}
}
}
}
@@ -1,5 +1,5 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "InitMsg",
"title": "InstantiateMsg",
"type": "object"
}
+47 -17
View File
@@ -3,25 +3,40 @@
"title": "MixNodeBond",
"type": "object",
"required": [
"amount",
"bond_amount",
"layer",
"mix_node",
"owner"
"owner",
"total_delegation"
],
"properties": {
"amount": {
"type": "array",
"items": {
"$ref": "#/definitions/Coin"
}
"block_height": {
"default": 0,
"type": "integer",
"format": "uint64",
"minimum": 0.0
},
"bond_amount": {
"$ref": "#/definitions/Coin"
},
"layer": {
"$ref": "#/definitions/Layer"
},
"mix_node": {
"$ref": "#/definitions/MixNode"
},
"owner": {
"$ref": "#/definitions/HumanAddr"
"$ref": "#/definitions/Addr"
},
"total_delegation": {
"$ref": "#/definitions/Coin"
}
},
"definitions": {
"Addr": {
"description": "A human readable address.\n\nIn Cosmos, this is typically bech32 encoded. But for multi-chain smart contracts no assumptions should be made other than being UTF-8 encoded and of reasonable length.\n\nThis type represents a validated address. It can be created in the following ways 1. Use `Addr::unchecked(input)` 2. Use `let checked: Addr = deps.api.addr_validate(input)?` 3. Use `let checked: Addr = deps.api.addr_humanize(canonical_addr)?` 4. Deserialize from JSON. This must only be done from JSON that was validated before such as a contract's state. `Addr` must not be used in messages sent by the user because this would result in unvalidated instances.\n\nThis type is immutable. If you really need to mutate it (Really? Are you sure?), create a mutable copy using `let mut mutable = Addr::to_string()` and operate on that `String` instance.",
"type": "string"
},
"Coin": {
"type": "object",
"required": [
@@ -37,44 +52,59 @@
}
}
},
"HumanAddr": {
"type": "string"
"Layer": {
"type": "string",
"enum": [
"Gateway",
"One",
"Two",
"Three"
]
},
"MixNode": {
"type": "object",
"required": [
"host",
"http_api_port",
"identity_key",
"layer",
"location",
"mix_port",
"sphinx_key",
"verloc_port",
"version"
],
"properties": {
"host": {
"type": "string"
},
"http_api_port": {
"type": "integer",
"format": "uint16",
"minimum": 0.0
},
"identity_key": {
"description": "Base58 encoded ed25519 EdDSA public key.",
"type": "string"
},
"layer": {
"mix_port": {
"type": "integer",
"format": "uint64",
"format": "uint16",
"minimum": 0.0
},
"location": {
"type": "string"
},
"sphinx_key": {
"type": "string"
},
"verloc_port": {
"type": "integer",
"format": "uint16",
"minimum": 0.0
},
"version": {
"type": "string"
}
}
},
"Uint128": {
"description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```",
"type": "string"
}
}
+262 -11
View File
@@ -20,18 +20,15 @@
"minimum": 0.0
},
"start_after": {
"anyOf": [
{
"$ref": "#/definitions/HumanAddr"
},
{
"type": "null"
}
"type": [
"string",
"null"
]
}
}
}
}
},
"additionalProperties": false
},
{
"type": "object",
@@ -50,10 +47,96 @@
"format": "uint32",
"minimum": 0.0
},
"start_after": {
"type": [
"string",
"null"
]
}
}
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"owns_mixnode"
],
"properties": {
"owns_mixnode": {
"type": "object",
"required": [
"address"
],
"properties": {
"address": {
"$ref": "#/definitions/Addr"
}
}
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"owns_gateway"
],
"properties": {
"owns_gateway": {
"type": "object",
"required": [
"address"
],
"properties": {
"address": {
"$ref": "#/definitions/Addr"
}
}
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"state_params"
],
"properties": {
"state_params": {
"type": "object"
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"get_mix_delegations"
],
"properties": {
"get_mix_delegations": {
"type": "object",
"required": [
"mix_identity"
],
"properties": {
"limit": {
"type": [
"integer",
"null"
],
"format": "uint32",
"minimum": 0.0
},
"mix_identity": {
"type": "string"
},
"start_after": {
"anyOf": [
{
"$ref": "#/definitions/HumanAddr"
"$ref": "#/definitions/Addr"
},
{
"type": "null"
@@ -62,11 +145,179 @@
}
}
}
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"get_reverse_mix_delegations"
],
"properties": {
"get_reverse_mix_delegations": {
"type": "object",
"required": [
"delegation_owner"
],
"properties": {
"delegation_owner": {
"$ref": "#/definitions/Addr"
},
"limit": {
"type": [
"integer",
"null"
],
"format": "uint32",
"minimum": 0.0
},
"start_after": {
"type": [
"string",
"null"
]
}
}
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"get_mix_delegation"
],
"properties": {
"get_mix_delegation": {
"type": "object",
"required": [
"address",
"mix_identity"
],
"properties": {
"address": {
"$ref": "#/definitions/Addr"
},
"mix_identity": {
"type": "string"
}
}
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"get_gateway_delegations"
],
"properties": {
"get_gateway_delegations": {
"type": "object",
"required": [
"gateway_identity"
],
"properties": {
"gateway_identity": {
"type": "string"
},
"limit": {
"type": [
"integer",
"null"
],
"format": "uint32",
"minimum": 0.0
},
"start_after": {
"anyOf": [
{
"$ref": "#/definitions/Addr"
},
{
"type": "null"
}
]
}
}
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"get_reverse_gateway_delegations"
],
"properties": {
"get_reverse_gateway_delegations": {
"type": "object",
"required": [
"delegation_owner"
],
"properties": {
"delegation_owner": {
"$ref": "#/definitions/Addr"
},
"limit": {
"type": [
"integer",
"null"
],
"format": "uint32",
"minimum": 0.0
},
"start_after": {
"type": [
"string",
"null"
]
}
}
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"get_gateway_delegation"
],
"properties": {
"get_gateway_delegation": {
"type": "object",
"required": [
"address",
"gateway_identity"
],
"properties": {
"address": {
"$ref": "#/definitions/Addr"
},
"gateway_identity": {
"type": "string"
}
}
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"layer_distribution"
],
"properties": {
"layer_distribution": {
"type": "object"
}
},
"additionalProperties": false
}
],
"definitions": {
"HumanAddr": {
"Addr": {
"description": "A human readable address.\n\nIn Cosmos, this is typically bech32 encoded. But for multi-chain smart contracts no assumptions should be made other than being UTF-8 encoded and of reasonable length.\n\nThis type represents a validated address. It can be created in the following ways 1. Use `Addr::unchecked(input)` 2. Use `let checked: Addr = deps.api.addr_validate(input)?` 3. Use `let checked: Addr = deps.api.addr_humanize(canonical_addr)?` 4. Deserialize from JSON. This must only be done from JSON that was validated before such as a contract's state. `Addr` must not be used in messages sent by the user because this would result in unvalidated instances.\n\nThis type is immutable. If you really need to mutate it (Really? Are you sure?), create a mutable copy using `let mut mutable = Addr::to_string()` and operate on that `String` instance.",
"type": "string"
}
}
+79 -3
View File
@@ -3,15 +3,91 @@
"title": "State",
"type": "object",
"required": [
"owner"
"gateway_epoch_bond_reward",
"gateway_epoch_delegation_reward",
"mixnode_epoch_bond_reward",
"mixnode_epoch_delegation_reward",
"network_monitor_address",
"owner",
"params"
],
"properties": {
"gateway_epoch_bond_reward": {
"$ref": "#/definitions/Decimal"
},
"gateway_epoch_delegation_reward": {
"$ref": "#/definitions/Decimal"
},
"mixnode_epoch_bond_reward": {
"$ref": "#/definitions/Decimal"
},
"mixnode_epoch_delegation_reward": {
"$ref": "#/definitions/Decimal"
},
"network_monitor_address": {
"$ref": "#/definitions/Addr"
},
"owner": {
"$ref": "#/definitions/HumanAddr"
"$ref": "#/definitions/Addr"
},
"params": {
"$ref": "#/definitions/StateParams"
}
},
"definitions": {
"HumanAddr": {
"Addr": {
"description": "A human readable address.\n\nIn Cosmos, this is typically bech32 encoded. But for multi-chain smart contracts no assumptions should be made other than being UTF-8 encoded and of reasonable length.\n\nThis type represents a validated address. It can be created in the following ways 1. Use `Addr::unchecked(input)` 2. Use `let checked: Addr = deps.api.addr_validate(input)?` 3. Use `let checked: Addr = deps.api.addr_humanize(canonical_addr)?` 4. Deserialize from JSON. This must only be done from JSON that was validated before such as a contract's state. `Addr` must not be used in messages sent by the user because this would result in unvalidated instances.\n\nThis type is immutable. If you really need to mutate it (Really? Are you sure?), create a mutable copy using `let mut mutable = Addr::to_string()` and operate on that `String` instance.",
"type": "string"
},
"Decimal": {
"description": "A fixed-point decimal value with 18 fractional digits, i.e. Decimal(1_000_000_000_000_000_000) == 1.0\n\nThe greatest possible value that can be represented is 340282366920938463463.374607431768211455 (which is (2^128 - 1) / 10^18)",
"type": "string"
},
"StateParams": {
"type": "object",
"required": [
"epoch_length",
"gateway_bond_reward_rate",
"gateway_delegation_reward_rate",
"minimum_gateway_bond",
"minimum_mixnode_bond",
"mixnode_active_set_size",
"mixnode_bond_reward_rate",
"mixnode_delegation_reward_rate"
],
"properties": {
"epoch_length": {
"type": "integer",
"format": "uint32",
"minimum": 0.0
},
"gateway_bond_reward_rate": {
"$ref": "#/definitions/Decimal"
},
"gateway_delegation_reward_rate": {
"$ref": "#/definitions/Decimal"
},
"minimum_gateway_bond": {
"$ref": "#/definitions/Uint128"
},
"minimum_mixnode_bond": {
"$ref": "#/definitions/Uint128"
},
"mixnode_active_set_size": {
"type": "integer",
"format": "uint32",
"minimum": 0.0
},
"mixnode_bond_reward_rate": {
"$ref": "#/definitions/Decimal"
},
"mixnode_delegation_reward_rate": {
"$ref": "#/definitions/Decimal"
}
}
},
"Uint128": {
"description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```",
"type": "string"
}
}
+51 -12
View File
@@ -10,7 +10,9 @@ use cosmwasm_std::{
entry_point, to_binary, Addr, Decimal, Deps, DepsMut, Env, MessageInfo, QueryResponse,
Response, Uint128,
};
use mixnet_contract::{ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg, StateParams};
use mixnet_contract::{
ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg, RawDelegationData, StateParams,
};
pub const INITIAL_DEFAULT_EPOCH_LENGTH: u32 = 2;
@@ -205,31 +207,68 @@ pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> Result<QueryResponse, Cont
}
#[entry_point]
pub fn migrate(deps: DepsMut, env: Env, _msg: MigrateMsg) -> Result<Response, ContractError> {
use crate::storage::{gateways, gateways_read, mixnodes, mixnodes_read};
pub fn migrate(mut deps: DepsMut, _env: Env, _msg: MigrateMsg) -> Result<Response, ContractError> {
use crate::storage::{
gateway_delegations, gateway_delegations_read, gateway_delegations_read_old, gateways_read,
mix_delegations, mix_delegations_read, mix_delegations_read_old, mixnodes_read,
};
use crate::transactions::delegations;
use cosmwasm_std::{Order, StdResult};
use mixnet_contract::CURRENT_BLOCK_HEIGHT;
use mixnet_contract::{GatewayBond, MixNodeBond};
use std::sync::atomic::Ordering;
CURRENT_BLOCK_HEIGHT.store(env.block.height, Ordering::Relaxed);
// Read existing delegations data, drop invalid values, and rewrite delegations data with valid data only
fn overwrite_mixnode_delegations_data(
identity: &str,
deps: &mut DepsMut,
) -> Result<(), ContractError> {
let delegations_bucket = mix_delegations_read(deps.storage, identity);
let old_delegations_bucket = mix_delegations_read_old(deps.storage, identity);
let mut delegations_vec = delegations(delegations_bucket)?;
let old_delegations = delegations::<Uint128>(old_delegations_bucket)?;
for delegation in old_delegations {
delegations_vec.push((delegation.0, RawDelegationData::new(delegation.1, 1)))
}
let bonds = mixnodes_read(deps.storage)
for (key, delegation) in delegations_vec {
mix_delegations(deps.storage, identity).save(&key, &delegation)?;
}
Ok(())
}
fn overwrite_gateway_delegations_data(
identity: &str,
deps: &mut DepsMut,
) -> Result<(), ContractError> {
let delegations_bucket = gateway_delegations_read(deps.storage, identity);
let old_delegations_bucket = gateway_delegations_read_old(deps.storage, identity);
let mut delegations_vec = delegations(delegations_bucket)?;
let old_delegations = delegations::<Uint128>(old_delegations_bucket)?;
for delegation in old_delegations {
delegations_vec.push((delegation.0, RawDelegationData::new(delegation.1, 1)))
}
for (key, delegation) in delegations_vec {
gateway_delegations(deps.storage, identity).save(&key, &delegation)?;
}
Ok(())
}
let mixnet_bonds = mixnodes_read(deps.storage)
.range(None, None, Order::Ascending)
.map(|res| res.map(|item| item.1))
.collect::<StdResult<Vec<MixNodeBond>>>()?;
for bond in bonds {
mixnodes(deps.storage).save(bond.identity().as_bytes(), &bond)?;
for bond in mixnet_bonds {
overwrite_mixnode_delegations_data(bond.identity(), &mut deps)?;
}
let bonds = gateways_read(deps.storage)
let gateway_bonds = gateways_read(deps.storage)
.range(None, None, Order::Ascending)
.map(|res| res.map(|item| item.1))
.collect::<StdResult<Vec<GatewayBond>>>()?;
for bond in bonds {
gateways(deps.storage).save(bond.identity().as_bytes(), &bond)?;
for bond in gateway_bonds {
overwrite_gateway_delegations_data(bond.identity(), &mut deps)?;
}
Ok(Default::default())
+20
View File
@@ -36,6 +36,8 @@ const PREFIX_REVERSE_GATEWAY_DELEGATION: &[u8] = b"dg";
// Contract-level stuff
// TODO Unify bucket and mixnode storage functions
pub fn config(storage: &mut dyn Storage) -> Singleton<State> {
singleton(storage, CONFIG_KEY)
}
@@ -316,6 +318,14 @@ pub fn mix_delegations_read<'a>(
ReadonlyBucket::multilevel(storage, &[PREFIX_MIX_DELEGATION, mix_identity.as_bytes()])
}
// https://github.com/nymtech/nym/blob/122f5d9f2e5c1ced96e3b9ba0c74ef8b7dbde2c7/contracts/mixnet/src/storage.rs
pub fn mix_delegations_read_old<'a>(
storage: &'a dyn Storage,
mix_identity: IdentityKeyRef,
) -> ReadonlyBucket<'a, Uint128> {
ReadonlyBucket::multilevel(storage, &[PREFIX_MIX_DELEGATION, mix_identity.as_bytes()])
}
pub fn reverse_mix_delegations<'a>(storage: &'a mut dyn Storage, owner: &Addr) -> Bucket<'a, ()> {
Bucket::multilevel(storage, &[PREFIX_REVERSE_MIX_DELEGATION, owner.as_bytes()])
}
@@ -347,6 +357,16 @@ pub fn gateway_delegations_read<'a>(
)
}
pub fn gateway_delegations_read_old<'a>(
storage: &'a dyn Storage,
gateway_identity: IdentityKeyRef,
) -> ReadonlyBucket<'a, Uint128> {
ReadonlyBucket::multilevel(
storage,
&[PREFIX_GATEWAY_DELEGATION, gateway_identity.as_bytes()],
)
}
pub fn reverse_gateway_delegations<'a>(
storage: &'a mut dyn Storage,
owner: &Addr,
+49 -19
View File
@@ -14,6 +14,8 @@ use cosmwasm_storage::ReadonlyBucket;
use mixnet_contract::{
Gateway, GatewayBond, IdentityKey, Layer, MixNode, MixNodeBond, RawDelegationData, StateParams,
};
use serde::de::DeserializeOwned;
use serde::Serialize;
const OLD_DELEGATIONS_CHUNK_SIZE: usize = 500;
pub(crate) const MINIMUM_BLOCK_AGE_FOR_REWARDING: u64 = 17280;
@@ -25,12 +27,15 @@ pub(crate) const MINIMUM_BLOCK_AGE_FOR_REWARDING: u64 = 17280;
// 3. The node unbonds
// 4. Some of the addresses that delegated in the past have not removed the delegation yet
// 5. The node rebonds with the same identity
fn find_old_delegations(delegations_bucket: ReadonlyBucket<RawDelegationData>) -> StdResult<Coin> {
pub fn delegations<T: DeserializeOwned + Serialize>(
delegations_bucket: ReadonlyBucket<T>,
) -> StdResult<Vec<(Vec<u8>, T)>> {
// I think it's incredibly unlikely to ever read more than that
// but in case we do, we should guard ourselves against possible
// out of memory errors (wasm contracts can only allocate at most 2MB
// of RAM, so we don't want to box the entire iterator)
let mut total_delegation = Coin::new(0, DENOM);
let mut delegations = Vec::new();
// let mut total_delegation = Coin::new(0, DENOM);
let mut start = None;
loop {
let iterator = delegations_bucket
@@ -39,16 +44,23 @@ fn find_old_delegations(delegations_bucket: ReadonlyBucket<RawDelegationData>) -
let mut iterated = 0;
for delegation in iterator {
for result_tuple in iterator {
iterated += 1;
if iterated == OLD_DELEGATIONS_CHUNK_SIZE + 1 {
// we reached start of next chunk, don't process it, mark it for the next iteration of the loop
start = Some(delegation?.0);
continue;
match result_tuple {
Ok((position, delegation)) => {
// We might skip some values due to deserializatio errors
if iterated > OLD_DELEGATIONS_CHUNK_SIZE {
// we reached start of next chunk, don't process it, mark it for the next iteration of the loop
start = Some(position);
continue;
}
delegations.push((position, delegation))
}
Err(_e) => {
// Skip errors
continue;
}
}
let value = delegation?.1.amount;
total_delegation.amount += value;
}
if iterated <= OLD_DELEGATIONS_CHUNK_SIZE {
@@ -57,7 +69,17 @@ fn find_old_delegations(delegations_bucket: ReadonlyBucket<RawDelegationData>) -
}
}
Ok(total_delegation)
Ok(delegations)
}
fn total_delegations(delegations_bucket: ReadonlyBucket<RawDelegationData>) -> StdResult<Coin> {
match delegations(delegations_bucket) {
Ok(delegations) => Ok(Coin::new(
delegations.iter().fold(0, |acc, x| acc + x.1.amount.u128()),
"upunk",
)),
Err(e) => Err(e),
}
}
fn validate_mixnode_bond(bond: &[Coin], minimum_bond: Uint128) -> Result<(), ContractError> {
@@ -138,7 +160,7 @@ pub(crate) fn try_add_mixnode(
// this might potentially require more gas if a significant number of delegations was there
let delegations_bucket = mix_delegations_read(deps.storage, &bond.mix_node.identity_key);
let existing_delegation = find_old_delegations(delegations_bucket)?;
let existing_delegation = total_delegations(delegations_bucket)?;
bond.total_delegation = existing_delegation;
let identity = bond.identity();
@@ -270,7 +292,7 @@ pub(crate) fn try_add_gateway(
// this might potentially require more gas if a significant number of delegations was there
let delegations_bucket = gateway_delegations_read(deps.storage, &bond.gateway.identity_key);
let existing_delegation = find_old_delegations(delegations_bucket)?;
let existing_delegation = total_delegations(delegations_bucket)?;
bond.total_delegation = existing_delegation;
let identity = bond.identity();
@@ -403,6 +425,10 @@ pub(crate) fn try_update_state_params(
Ok(Response::default())
}
// Note: if any changes are made to this function or anything it is calling down the stack,
// for example delegation reward distribution, the gas limits must be retested and both
// validator-api/src/rewarding/mod.rs::{MIXNODE_REWARD_OP_BASE_GAS_LIMIT, PER_MIXNODE_DELEGATION_GAS_INCREASE}
// must be updated appropriately.
pub(crate) fn try_reward_mixnode(
deps: DepsMut,
env: Env,
@@ -474,6 +500,10 @@ pub(crate) fn try_reward_mixnode(
})
}
// Note: if any changes are made to this function or anything it is calling down the stack,
// for example delegation reward distribution, the gas limits must be retested and both
// validator-api/src/rewarding/mod.rs::{GATEWAY_REWARD_OP_BASE_GAS_LIMIT, PER_GATEWAY_DELEGATION_GAS_INCREASE}
// must be updated appropriately.
pub(crate) fn try_reward_gateway(
deps: DepsMut,
env: Env,
@@ -502,7 +532,7 @@ pub(crate) fn try_reward_gateway(
}
// check if the bond even exists
let mut current_bond = match gateways(deps.storage).load(gateway_identity.as_bytes()) {
let mut current_bond = match gateways_read(deps.storage).load(gateway_identity.as_bytes()) {
Ok(bond) => bond,
Err(_) => {
return Ok(Response {
@@ -3928,7 +3958,7 @@ pub mod tests {
let node_identity: IdentityKey = "nodeidentity".into();
let read_bucket = mix_delegations_read(&deps.storage, &node_identity);
let old_delegations = find_old_delegations(read_bucket).unwrap();
let old_delegations = total_delegations(read_bucket).unwrap();
assert_eq!(Coin::new(0, DENOM), old_delegations);
}
@@ -3945,14 +3975,14 @@ pub mod tests {
OLD_DELEGATIONS_CHUNK_SIZE * 3 + 1,
];
for total_delegations in num_delegations {
for delegations in num_delegations {
let mut deps = helpers::init_contract();
let node_identity: IdentityKey = "nodeidentity".into();
// delegate some stake
let mut write_bucket = mix_delegations(&mut deps.storage, &node_identity);
for i in 1..=total_delegations {
for i in 1..=delegations {
let delegator = Addr::unchecked(format!("delegator{}", i));
let delegation = raw_delegation_fixture(i as u128);
write_bucket
@@ -3961,9 +3991,9 @@ pub mod tests {
}
let read_bucket = mix_delegations_read(&deps.storage, &node_identity);
let old_delegations = find_old_delegations(read_bucket).unwrap();
let old_delegations = total_delegations(read_bucket).unwrap();
let total_delegation = (1..=total_delegations as u128).into_iter().sum();
let total_delegation = (1..=delegations as u128).into_iter().sum();
assert_eq!(Coin::new(total_delegation, DENOM), old_delegations);
}
}
-1
View File
@@ -20,7 +20,6 @@ okapi = { version = "0.6.0-alpha-1", features = ["derive_json_schema"] }
rocket_okapi = "0.7.0-alpha-1"
log = "0.4.0"
pretty_env_logger = "0.4.0"
handlebars = "4.1.3"
mixnet-contract = { path = "../common/mixnet-contract" }
network-defaults = { path = "../common/network-defaults" }
+11 -15
View File
@@ -4,7 +4,6 @@ use reqwest::Error as ReqwestError;
use crate::country_statistics::country_nodes_distribution::CountryNodesDistribution;
use crate::mix_nodes::{GeoLocation, Location};
use crate::state::ExplorerApiStateContext;
use std::env;
pub mod country_nodes_distribution;
pub mod http;
@@ -19,21 +18,18 @@ impl CountryStatistics {
}
pub(crate) fn start(mut self) {
if env::var("DEV_MODE").is_err() {
info!("Spawning task runner...");
tokio::spawn(async move {
let mut interval_timer =
tokio::time::interval(std::time::Duration::from_secs(60 * 60));
loop {
// wait for the next interval tick
interval_timer.tick().await;
info!("Spawning task runner...");
tokio::spawn(async move {
let mut interval_timer = tokio::time::interval(std::time::Duration::from_secs(60 * 60));
loop {
// wait for the next interval tick
interval_timer.tick().await;
info!("Running task...");
self.calculate_nodes_per_country().await;
info!("Done");
}
});
}
info!("Running task...");
self.calculate_nodes_per_country().await;
info!("Done");
}
});
}
/// Retrieves the current list of mixnodes from the validators and calculates how many nodes are in each country
-4
View File
@@ -7,7 +7,6 @@ use rocket_okapi::swagger_ui::make_swagger_ui;
use crate::country_statistics::http::country_statistics_make_default_routes;
use crate::http::swagger::get_docs;
use crate::mix_node::http::mix_node_make_default_routes;
use crate::mix_node::templates::Templates;
use crate::ping::http::ping_make_default_routes;
use crate::state::ExplorerApiStateContext;
@@ -30,8 +29,6 @@ pub(crate) fn start(state: ExplorerApiStateContext) {
.to_cors()
.unwrap();
let templates = Templates::new();
let config = rocket::config::Config::release_default();
rocket::build()
.configure(config)
@@ -41,7 +38,6 @@ pub(crate) fn start(state: ExplorerApiStateContext) {
.mount("/swagger", make_swagger_ui(&get_docs()))
.register("/", catchers![not_found])
.manage(state)
.manage(templates)
.attach(cors)
.launch()
.await
+3 -40
View File
@@ -1,5 +1,4 @@
use reqwest::Error as ReqwestError;
use rocket::response::content::Html;
use rocket::serde::json::Json;
use rocket::{Route, State};
use serde::Serialize;
@@ -7,12 +6,11 @@ use serde::Serialize;
use mixnet_contract::{Addr, Coin, Layer, MixNode};
use crate::mix_node::models::{NodeDescription, NodeStats};
use crate::mix_node::templates::{PreviewTemplateData, Templates};
use crate::mix_nodes::{get_mixnode_delegations, Location};
use crate::state::ExplorerApiStateContext;
pub fn mix_node_make_default_routes() -> Vec<Route> {
routes_with_openapi![get_delegations, get_description, get_stats, list, preview]
routes_with_openapi![get_delegations, get_description, get_stats, list]
}
#[derive(Clone, Debug, Serialize, JsonSchema)]
@@ -53,34 +51,6 @@ pub(crate) async fn list(
)
}
#[openapi(tag = "mix_node")]
#[get("/<pubkey>/preview")]
pub(crate) async fn preview(
pubkey: &str,
templates: &State<Templates>,
state: &State<ExplorerApiStateContext>,
) -> Html<String> {
match get_mixnode_description(pubkey, state).await {
Some(node_description) => {
// use handlebars to render an HTML output for an OpenGraph / Twitter preview - this is
// used in social media apps / messenger apps that show previews for links
match templates.render_preview(PreviewTemplateData {
title: node_description.name,
description: node_description.description,
url: format!(
"https://testnet-milhon-explorer.nymtech.net/nym/mixnodes/{}",
pubkey
),
image_url: String::from("https://media2.giphy.com/media/pwyW4XDmtqjG8/200.gif?cid=dda24d50ae15e44c38783edc824618df68645c6af2592b28&amp;rid=200.gif&amp;ct=g"),
}) {
Ok(r) => Html(r),
Err(_e) => Html(String::from("Oh no, something went wrong!")),
}
}
None => Html(String::from("Sorry, mix node not found")),
}
}
#[openapi(tag = "mix_node")]
#[get("/<pubkey>/delegations")]
pub(crate) async fn get_delegations(pubkey: &str) -> Json<Vec<mixnet_contract::Delegation>> {
@@ -93,13 +63,6 @@ pub(crate) async fn get_description(
pubkey: &str,
state: &State<ExplorerApiStateContext>,
) -> Option<Json<NodeDescription>> {
get_mixnode_description(pubkey, state).await.map(Json)
}
async fn get_mixnode_description(
pubkey: &str,
state: &State<ExplorerApiStateContext>,
) -> Option<NodeDescription> {
match state
.inner
.mix_node_cache
@@ -109,7 +72,7 @@ async fn get_mixnode_description(
{
Some(cache_value) => {
trace!("Returning cached value for {}", pubkey);
Some(cache_value)
Some(Json(cache_value))
}
None => {
trace!("No valid cache value for {}", pubkey);
@@ -128,7 +91,7 @@ async fn get_mixnode_description(
.mix_node_cache
.set_description(pubkey, response.clone())
.await;
Some(response)
Some(Json(response))
}
Err(e) => {
error!(
-1
View File
@@ -1,4 +1,3 @@
mod cache;
pub(crate) mod http;
pub(crate) mod models;
pub(crate) mod templates;
-73
View File
@@ -1,73 +0,0 @@
use handlebars::{Handlebars, RenderError};
use serde::Serialize;
#[derive(Clone)]
pub(crate) struct Templates {
handlebars: Handlebars<'static>,
}
impl Templates {
pub(crate) fn new() -> Self {
let mut handlebars = Handlebars::new();
assert!(handlebars
.register_template_string("preview", PREVIEW_TEMPLATE)
.is_ok());
Templates { handlebars }
}
pub(crate) fn render_preview(&self, data: PreviewTemplateData) -> Result<String, RenderError> {
self.handlebars.render("preview", &data)
}
}
#[derive(Clone, Debug, Serialize, JsonSchema)]
pub(crate) struct PreviewTemplateData {
pub(crate) title: String,
pub(crate) description: String,
pub(crate) url: String,
pub(crate) image_url: String,
}
const PREVIEW_TEMPLATE: &str = r#"<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>{{ title }}</title>
<meta name="description" content="{{ description }}">
<meta property="og:type" content="article">
<meta property="og:url" content="{{ url }}">
<meta property="og:title" content="{{ title }}">
<meta property="og:description" content="{{ description }}">
<meta property="og:image" content="{{ image_url }}">
<meta name="twitter:card" value="summary_large_image">
<meta name="twitter:title" value="{{ title }}">
<meta name="twitter:description" value="{{ description }}">
<meta name="twitter:image" value="{{ image_url }}">
<meta name="twitter:site" value="@nymtech">
<meta http-equiv="refresh" content="0;url={{url}}" />
<style>
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
}
.meme {
padding-top: 20px;
}
.meme > img {
max-width: 200px;
max-height: 200px;
}
</style>
</head>
<body>
<h1>{{title}}</h1>
<div>{{description}}<div>
</body>
</html>"#;
-2
View File
@@ -28,8 +28,6 @@ tokio-tungstenite = "0.14"
url = { version = "2.2", features = [ "serde" ] }
# internal
coconut-interface = { path = "../common/coconut-interface" }
credentials = { path = "../common/credentials" }
config = { path = "../common/config" }
crypto = { path = "../common/crypto" }
gateway-requests = { path = "gateway-requests" }
+2 -2
View File
@@ -2,11 +2,11 @@
// SPDX-License-Identifier: Apache-2.0
use crypto::generic_array::{typenum::Unsigned, GenericArray};
use crypto::symmetric::stream_cipher::{random_iv, NewStreamCipher, IV as CryptoIV};
use crypto::symmetric::stream_cipher::{random_iv, NewCipher, IV as CryptoIV};
use nymsphinx::params::GatewayEncryptionAlgorithm;
use rand::{CryptoRng, RngCore};
type NonceSize = <GatewayEncryptionAlgorithm as NewStreamCipher>::NonceSize;
type NonceSize = <GatewayEncryptionAlgorithm as NewCipher>::NonceSize;
// I think 'IV' looks better than 'Iv', feel free to change that.
#[allow(clippy::upper_case_acronyms)]
@@ -7,7 +7,7 @@ use crypto::generic_array::{
GenericArray,
};
use crypto::hmac::{compute_keyed_hmac, recompute_keyed_hmac_and_verify_tag};
use crypto::symmetric::stream_cipher::{self, Key, NewStreamCipher, IV};
use crypto::symmetric::stream_cipher::{self, CipherKey, NewCipher, IV};
use nymsphinx::params::{GatewayEncryptionAlgorithm, GatewayIntegrityHmacAlgorithm};
use pemstore::traits::PemStorableKey;
use std::fmt::{self, Display, Formatter};
@@ -17,14 +17,14 @@ pub type SharedKeySize = Sum<EncryptionKeySize, MacKeySize>;
// we're using 16 byte long key in sphinx, so let's use the same one here
type MacKeySize = U16;
type EncryptionKeySize = <GatewayEncryptionAlgorithm as NewStreamCipher>::KeySize;
type EncryptionKeySize = <GatewayEncryptionAlgorithm as NewCipher>::KeySize;
/// Shared key used when computing MAC for messages exchanged between client and its gateway.
pub type MacKey = GenericArray<u8, MacKeySize>;
#[derive(Clone, Debug)]
pub struct SharedKeys {
encryption_key: Key<GatewayEncryptionAlgorithm>,
encryption_key: CipherKey<GatewayEncryptionAlgorithm>,
mac_key: MacKey,
}
@@ -138,7 +138,7 @@ impl SharedKeys {
Ok(message_bytes_mut.to_vec())
}
pub fn encryption_key(&self) -> &Key<GatewayEncryptionAlgorithm> {
pub fn encryption_key(&self) -> &CipherKey<GatewayEncryptionAlgorithm> {
&self.encryption_key
}
-33
View File
@@ -5,7 +5,6 @@ use crate::authentication::encrypted_address::EncryptedAddressBytes;
use crate::iv::IV;
use crate::registration::handshake::SharedKeys;
use crate::GatewayMacSize;
use coconut_interface::Credential;
use crypto::generic_array::typenum::Unsigned;
use crypto::hmac::recompute_keyed_hmac_and_verify_tag;
use crypto::symmetric::stream_cipher;
@@ -113,10 +112,6 @@ pub enum ClientControlRequest {
},
#[serde(alias = "handshakePayload")]
RegisterHandshakeInitRequest { data: Vec<u8> },
BandwidthCredential {
enc_credential: Vec<u8>,
iv: Vec<u8>,
},
}
impl ClientControlRequest {
@@ -131,34 +126,6 @@ impl ClientControlRequest {
iv: iv.to_base58_string(),
}
}
pub fn new_enc_bandwidth_credential(
credential: &Credential,
shared_key: &SharedKeys,
iv: IV,
) -> Option<Self> {
match bincode::serialize(credential) {
Ok(serialized_credential) => {
let enc_credential =
shared_key.encrypt_and_tag(&serialized_credential, Some(iv.inner()));
Some(ClientControlRequest::BandwidthCredential {
enc_credential,
iv: iv.to_bytes(),
})
}
_ => None,
}
}
pub fn try_from_enc_bandwidth_credential(
enc_credential: Vec<u8>,
shared_key: &SharedKeys,
iv: IV,
) -> Result<Credential, GatewayRequestsError> {
let credential = shared_key.decrypt_tagged(&enc_credential, Some(iv.inner()))?;
bincode::deserialize(&credential).map_err(|_| GatewayRequestsError::MalformedEncryption)
}
}
impl From<ClientControlRequest> for Message {
@@ -1,85 +0,0 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use std::collections::HashMap;
use std::convert::TryFrom;
use std::sync::Arc;
use tokio::sync::RwLock;
use coconut_interface::Credential;
use credentials::error::Error;
use nymsphinx::DestinationAddressBytes;
const BANDWIDTH_INDEX: usize = 0;
pub type BandwidthDatabase = Arc<RwLock<HashMap<DestinationAddressBytes, u64>>>;
pub fn empty_bandwidth_database() -> BandwidthDatabase {
Arc::new(RwLock::new(HashMap::new()))
}
pub struct Bandwidth {
value: u64,
}
impl Bandwidth {
pub fn value(&self) -> u64 {
self.value
}
pub async fn consume_bandwidth(
bandwidths: &BandwidthDatabase,
remote_address: &DestinationAddressBytes,
consumed: u64,
) -> Result<(), Error> {
if let Some(bandwidth) = bandwidths.write().await.get_mut(remote_address) {
if let Some(res) = bandwidth.checked_sub(consumed) {
*bandwidth = res;
Ok(())
} else {
Err(Error::BandwidthOverflow(String::from(
"Allocate more bandwidth for consumption",
)))
}
} else {
Err(Error::MissingBandwidth)
}
}
pub async fn increase_bandwidth(
bandwidths: &BandwidthDatabase,
remote_address: &DestinationAddressBytes,
increase: u64,
) -> Result<(), Error> {
let mut db = bandwidths.write().await;
if let Some(bandwidth) = db.get_mut(remote_address) {
if let Some(new_bandwidth) = bandwidth.checked_add(increase) {
*bandwidth = new_bandwidth;
} else {
return Err(Error::BandwidthOverflow(String::from(
"Use some of the already allocated bandwidth",
)));
}
} else {
db.insert(*remote_address, increase);
}
Ok(())
}
}
impl TryFrom<Credential> for Bandwidth {
type Error = Error;
fn try_from(credential: Credential) -> Result<Self, Self::Error> {
match credential.public_attributes().get(BANDWIDTH_INDEX) {
None => Err(Error::NotEnoughPublicAttributes),
Some(attr) => match <[u8; 8]>::try_from(attr.as_slice()) {
Ok(bandwidth_bytes) => {
let value = u64::from_be_bytes(bandwidth_bytes);
Ok(Self { value })
}
Err(_) => Err(Error::InvalidBandwidthSize),
},
}
}
}
-1
View File
@@ -1,6 +1,5 @@
// Copyright 2020 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
mod bandwidth;
pub(crate) mod clients_handler;
pub(crate) mod websocket;
@@ -1,14 +1,12 @@
// Copyright 2020 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::node::client_handling::bandwidth::{Bandwidth, BandwidthDatabase};
use crate::node::client_handling::clients_handler::{
ClientsHandlerRequest, ClientsHandlerRequestSender, ClientsHandlerResponse,
};
use crate::node::client_handling::websocket::message_receiver::{
MixMessageReceiver, MixMessageSender,
};
use coconut_interface::VerificationKey;
use crypto::asymmetric::identity;
use futures::{
channel::{mpsc, oneshot},
@@ -25,7 +23,6 @@ use mixnet_client::forwarder::MixForwardingSender;
use nymsphinx::DestinationAddressBytes;
use rand::{CryptoRng, Rng};
use std::convert::TryFrom;
use std::mem;
use std::sync::Arc;
use tokio::io::{AsyncRead, AsyncWrite};
use tokio_tungstenite::{
@@ -58,10 +55,8 @@ pub(crate) struct Handle<R, S> {
clients_handler_sender: ClientsHandlerRequestSender,
outbound_mix_sender: MixForwardingSender,
socket_connection: SocketStream<S>,
local_identity: Arc<identity::KeyPair>,
aggregated_verification_key: VerificationKey,
bandwidths: BandwidthDatabase,
local_identity: Arc<identity::KeyPair>,
}
impl<R, S> Handle<R, S>
@@ -76,8 +71,6 @@ where
clients_handler_sender: ClientsHandlerRequestSender,
outbound_mix_sender: MixForwardingSender,
local_identity: Arc<identity::KeyPair>,
aggregated_verification_key: VerificationKey,
bandwidths: BandwidthDatabase,
) -> Self {
Handle {
rng,
@@ -87,8 +80,6 @@ where
outbound_mix_sender,
socket_connection: SocketStream::RawTcp(conn),
local_identity,
aggregated_verification_key,
bandwidths,
}
}
@@ -209,19 +200,8 @@ where
Ok(request) => match request {
// currently only a single type exists
BinaryRequest::ForwardSphinx(mix_packet) => {
let consumed_bandwidth = mem::size_of_val(&mix_packet) as u64;
if let Err(e) = Bandwidth::consume_bandwidth(
&self.bandwidths,
&self.remote_address.unwrap(),
consumed_bandwidth,
)
.await
{
ServerResponse::new_error(format!("{:?}", e))
} else {
self.outbound_mix_sender.unbounded_send(mix_packet).unwrap();
ServerResponse::Send { status: true }
}
self.outbound_mix_sender.unbounded_send(mix_packet).unwrap();
ServerResponse::Send { status: true }
}
},
}
@@ -357,68 +337,12 @@ where
}
}
async fn handle_bandwidth(&mut self, enc_credential: Vec<u8>, iv: Vec<u8>) -> ServerResponse {
if self.shared_key.is_none() {
return ServerResponse::new_error("No shared key has been exchanged with the gateway");
}
if self.remote_address.is_none() {
return ServerResponse::new_error("No remote address has been set");
}
let iv = match IV::try_from_bytes(&iv) {
Ok(iv) => iv,
Err(e) => {
trace!("failed to parse received IV {:?}", e);
return ServerResponse::new_error("malformed iv");
}
};
let credential = match ClientControlRequest::try_from_enc_bandwidth_credential(
enc_credential,
self.shared_key.as_ref().unwrap(),
iv,
) {
Ok(c) => c,
Err(e) => {
return ServerResponse::new_error(e.to_string());
}
};
if credential.verify(&self.aggregated_verification_key) {
match Bandwidth::try_from(credential) {
Ok(bandwidth) => {
if let Err(e) = Bandwidth::increase_bandwidth(
&self.bandwidths,
&self.remote_address.unwrap(),
bandwidth.value(),
)
.await
{
return ServerResponse::Error {
message: format!("{:?}", e),
};
}
ServerResponse::Bandwidth { status: true }
}
Err(e) => ServerResponse::Error {
message: format!("{:?}", e),
},
}
} else {
ServerResponse::Bandwidth { status: false }
}
}
// currently there are no valid control messages you can send after authentication
async fn handle_text(&mut self, _: String) -> Message {
trace!("Handling text message (presumably control message)");
// currently the bandwidth credential request is the only one we can receive after
// authentication
async fn handle_text(&mut self, raw_request: String) -> Message {
if let Ok(request) = ClientControlRequest::try_from(raw_request) {
match request {
ClientControlRequest::BandwidthCredential { enc_credential, iv } => {
self.handle_bandwidth(enc_credential, iv).await.into()
}
_ => ServerResponse::new_error("invalid request").into(),
}
} else {
ServerResponse::new_error("malformed request").into()
}
error!("Currently there are no text messages besides 'Authenticate' and 'Register' and they were already dealt with!");
ServerResponse::new_error("invalid request").into()
}
async fn handle_request(&mut self, raw_request: Message) -> Option<Message> {
@@ -455,7 +379,6 @@ where
ClientControlRequest::RegisterHandshakeInitRequest { data } => {
self.handle_register(data, mix_sender).await
}
_ => ServerResponse::new_error("invalid request"),
}
} else {
// TODO: is this a malformed request or rather a network error and
@@ -1,10 +1,8 @@
// Copyright 2020 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::node::client_handling::bandwidth::empty_bandwidth_database;
use crate::node::client_handling::clients_handler::ClientsHandlerRequestSender;
use crate::node::client_handling::websocket::connection_handler::Handle;
use coconut_interface::VerificationKey;
use crypto::asymmetric::identity;
use log::*;
use mixnet_client::forwarder::MixForwardingSender;
@@ -17,19 +15,13 @@ use tokio::task::JoinHandle;
pub(crate) struct Listener {
address: SocketAddr,
local_identity: Arc<identity::KeyPair>,
aggregated_verification_key: VerificationKey,
}
impl Listener {
pub(crate) fn new(
address: SocketAddr,
local_identity: Arc<identity::KeyPair>,
aggregated_verification_key: VerificationKey,
) -> Self {
pub(crate) fn new(address: SocketAddr, local_identity: Arc<identity::KeyPair>) -> Self {
Listener {
address,
local_identity,
aggregated_verification_key,
}
}
@@ -47,8 +39,6 @@ impl Listener {
}
};
let bandwidths = empty_bandwidth_database();
loop {
match tcp_listener.accept().await {
Ok((socket, remote_addr)) => {
@@ -61,8 +51,6 @@ impl Listener {
clients_handler_sender.clone(),
outbound_mix_sender.clone(),
Arc::clone(&self.local_identity),
self.aggregated_verification_key.clone(),
Arc::clone(&bandwidths),
);
tokio::spawn(async move { handle.start_handling().await });
}
+3 -12
View File
@@ -6,8 +6,6 @@ use crate::node::client_handling::clients_handler::{ClientsHandler, ClientsHandl
use crate::node::client_handling::websocket;
use crate::node::mixnet_handling::receiver::connection_handler::ConnectionHandler;
use crate::node::storage::{inboxes, ClientLedger};
use coconut_interface::VerificationKey;
use credentials::obtain_aggregate_verification_key;
use crypto::asymmetric::{encryption, identity};
use log::*;
use mixnet_client::forwarder::{MixForwardingSender, PacketForwarder};
@@ -85,7 +83,6 @@ impl Gateway {
&self,
forwarding_channel: MixForwardingSender,
clients_handler_sender: ClientsHandlerRequestSender,
verification_key: VerificationKey,
) {
info!("Starting client [web]socket listener...");
@@ -94,12 +91,8 @@ impl Gateway {
self.config.get_clients_port(),
);
websocket::Listener::new(
listening_address,
Arc::clone(&self.identity),
verification_key,
)
.start(clients_handler_sender, forwarding_channel);
websocket::Listener::new(listening_address, Arc::clone(&self.identity))
.start(clients_handler_sender, forwarding_channel);
}
fn start_packet_forwarder(&self) -> MixForwardingSender {
@@ -183,13 +176,11 @@ impl Gateway {
}
}
let validators_verification_key = obtain_aggregate_verification_key(&self.config.get_validator_api_endpoints()).await.expect("failed to contact validators to obtain their verification keys");
let mix_forwarding_channel = self.start_packet_forwarder();
let clients_handler_sender = self.start_clients_handler();
self.start_mix_socket_listener(clients_handler_sender.clone(), mix_forwarding_channel.clone());
self.start_client_websocket_listener(mix_forwarding_channel, clients_handler_sender, validators_verification_key);
self.start_client_websocket_listener(mix_forwarding_channel, clients_handler_sender);
info!("Finished nym gateway startup procedure - it should now be able to receive mix and client traffic!");
+15
View File
@@ -0,0 +1,15 @@
{
"presets": [
[
"@babel/preset-env",
{
"targets": {
"esmodules": true
}
}
],
"@babel/preset-react",
"@babel/preset-typescript"
],
"plugins": ["@babel/plugin-transform-async-to-generator"]
}
+109
View File
@@ -0,0 +1,109 @@
{
"env": {
"browser": true,
"es6": true,
"node": true,
"jest": true
},
"parserOptions": {
"ecmaFeatures": {
"jsx": true
},
"ecmaVersion": 2019,
"sourceType": "module"
},
"globals": {
"Atomics": "readonly",
"SharedArrayBuffer": "readonly"
},
"plugins": ["react", "react-hooks", "jsx-a11y", "prettier", "jest"],
"extends": [
"plugin:react/recommended",
"airbnb",
"prettier",
"plugin:jest/recommended",
"plugin:jest/style"
],
"rules": {
"jest/prefer-strict-equal": "error",
"jest/prefer-to-have-length": "warn",
"prettier/prettier": "error",
"import/prefer-default-export": "off",
"react/prop-types": "off",
"react/jsx-filename-extension": "off",
"react/jsx-props-no-spreading": "off",
"import/no-extraneous-dependencies": [
"error",
{
"devDependencies": [
"**/*.test.[jt]s",
"**/*.spec.[jt]s",
"**/*.test.[jt]sx",
"**/*.spec.[jt]sx"
]
}
],
"import/extensions": [
"error",
"ignorePackages",
{
"ts": "never",
"tsx": "never",
"js": "never",
"jsx": "never"
}
]
},
"overrides": [
{
"files": "**/*.+(ts|tsx)",
"parser": "@typescript-eslint/parser",
"parserOptions": {
"project": "./tsconfig.json"
},
"plugins": ["@typescript-eslint/eslint-plugin"],
"extends": [
"plugin:@typescript-eslint/eslint-recommended",
"plugin:@typescript-eslint/recommended",
"prettier"
],
"rules": {
"@typescript-eslint/explicit-function-return-type": "off",
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-var-requires": "off",
"no-use-before-define": [0],
"@typescript-eslint/no-use-before-define": [1],
"import/no-unresolved": 0,
"import/no-extraneous-dependencies": [
"error",
{
"devDependencies": [
"**/*.test.ts",
"**/*.spec.ts",
"**/*.test.tsx",
"**/*.spec.tsx"
]
}
],
"quotes": "off",
"@typescript-eslint/quotes": [
2,
"single",
{
"avoidEscape": true
}
],
"@typescript-eslint/no-unused-vars": [2, { "argsIgnorePattern": "^_" }]
}
}
],
"settings": {
"import/resolver": {
"root-import": {
"rootPathPrefix": "@",
"rootPathSuffix": "src",
"extensions": [".js", ".ts", ".tsx", ".jsx", ".mdx"]
}
}
}
}
+1
View File
@@ -0,0 +1 @@
14
+5213
View File
File diff suppressed because it is too large Load Diff
+2
View File
@@ -0,0 +1,2 @@
[workspace]
members = ["src-tauri"]
+19
View File
@@ -0,0 +1,19 @@
<!--
Copyright 2020 - Nym Technologies SA <contact@nymtech.net>
SPDX-License-Identifier: Apache-2.0
-->
# Nym Tauri Wallet
A Rust and Tauri desktop wallet implementation.
## Installation prerequisites
* `Yarn`
* `NodeJS >= v16.8.0`
* `Rust & cargo >= v1.51`
## Installation & usage
* `yarn install`
* `yarn dev`
View File
+52
View File
@@ -0,0 +1,52 @@
{
"name": "tauri-app",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"scripts": {
"webpack:dev": "yarn webpack serve",
"tauri:dev": "yarn tauri dev",
"dev": "yarn run webpack:dev & yarn run tauri:dev "
},
"dependencies": {
"@babel/preset-typescript": "^7.15.0",
"@hookform/resolvers": "^2.8.0",
"@material-ui/core": "^4.12.3",
"@material-ui/icons": "^4.11.2",
"@material-ui/lab": "^4.0.0-alpha.60",
"@material-ui/styles": "^4.11.4",
"@types/react-dom": "^17.0.9",
"bs58": "^4.0.1",
"clsx": "^1.1.1",
"qrcode.react": "^1.0.1",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-error-boundary": "^3.1.3",
"react-hook-form": "^7.14.2",
"react-router-dom": "^5.2.0",
"semver": "^6.3.0",
"yup": "^0.32.9"
},
"devDependencies": {
"@babel/core": "^7.15.0",
"@babel/plugin-transform-async-to-generator": "^7.14.5",
"@babel/preset-env": "^7.15.0",
"@babel/preset-react": "^7.14.5",
"@tauri-apps/api": "^1.0.0-beta.6",
"@tauri-apps/cli": "^1.0.0-beta.9",
"@types/bs58": "^4.0.1",
"@types/qrcode.react": "^1.0.2",
"@types/react-router-dom": "^5.1.8",
"@types/semver": "^7.3.8",
"babel-loader": "^8.2.2",
"css-loader": "^6.2.0",
"favicons-webpack-plugin": "^5.0.2",
"file-loader": "^6.2.0",
"html-webpack-plugin": "^5.3.2",
"style-loader": "^3.2.1",
"url-loader": "^4.1.1",
"webpack": "^5.50.0",
"webpack-cli": "^4.8.0",
"webpack-dev-server": "^4.1.0"
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

+9
View File
@@ -0,0 +1,9 @@
<!DOCTYPE html>
<html>
<head>
<title>Nym Wallet</title>
</head>
<body>
<div id="root"></div>
</body>
</html>
+4
View File
@@ -0,0 +1,4 @@
# Generated by Cargo
# will have compiled files and executables
/target/
WixTools
+44
View File
@@ -0,0 +1,44 @@
[package]
name = "nym_wallet"
version = "0.1.0"
description = "Nym Native Wallet"
authors = ["you"]
license = ""
repository = ""
default-run = "nym_wallet"
edition = "2018"
build = "src/build.rs"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[build-dependencies]
tauri-build = { version = "1.0.0-beta.4" }
[dependencies]
serde_json = "1.0"
serde = { version = "1.0", features = ["derive"] }
tauri = { version = "1.0.0-beta.8", features = [] }
tokio = { version = "1.10", features = ["sync"] }
dirs = "3.0"
# url = "2.2"
bip39 = "1.0"
thiserror = "1.0"
tendermint-rpc = "0.21.0"
ts-rs = "3.0"
url = "2.0"
rand = "0.6.5"
cosmrs = { version = "0.1", features = ["rpc", "bip32", "cosmwasm"] }
cosmwasm-std = { git = "https://github.com/jstuczyn/cosmwasm", branch = "0.14.1-updatedk256" }
validator-client = { path = "../../common/client-libs/validator-client", features = [
"nymd-client",
] }
mixnet-contract = { path = "../../common/mixnet-contract" }
config = { path = "../../common/config" }
coconut-interface = { path = "../../common/coconut-interface" }
credentials = { path = "../../common/credentials" }
[features]
default = ["custom-protocol"]
custom-protocol = ["tauri/custom-protocol"]
Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 974 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 903 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

+13
View File
@@ -0,0 +1,13 @@
max_width = 100
hard_tabs = false
tab_spaces = 2
newline_style = "Auto"
use_small_heuristics = "Default"
reorder_imports = true
reorder_modules = true
remove_nested_parens = true
edition = "2018"
merge_derives = true
use_try_shorthand = false
use_field_init_shorthand = false
force_explicit_abi = true
+3
View File
@@ -0,0 +1,3 @@
fn main() {
tauri_build::build()
}
+349
View File
@@ -0,0 +1,349 @@
// This should be moved out of the wallet, and used as a primary coin type throughout the codebase
use ::config::defaults::DENOM;
use cosmrs::Decimal;
use cosmrs::Denom as CosmosDenom;
use cosmwasm_std::Coin as CosmWasmCoin;
use cosmwasm_std::Uint128;
use serde::{Deserialize, Serialize};
use std::convert::TryFrom;
use std::fmt;
use std::ops::{Add, Sub};
use std::str::FromStr;
use ts_rs::TS;
use validator_client::nymd::{CosmosCoin, GasPrice};
use crate::format_err;
#[derive(TS, Serialize, Deserialize, Clone, PartialEq, Debug)]
pub enum Denom {
Major,
Minor,
}
const MINOR_IN_MAJOR: f64 = 1_000_000.;
impl fmt::Display for Denom {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
Denom::Major => f.write_str(&DENOM[1..]),
Denom::Minor => f.write_str(DENOM),
}
}
}
impl FromStr for Denom {
type Err = String;
fn from_str(s: &str) -> Result<Denom, String> {
let s = s.to_lowercase();
if s == DENOM.to_lowercase() || s == "minor" {
Ok(Denom::Minor)
} else if s == DENOM[1..].to_lowercase() || s == "major" {
Ok(Denom::Major)
} else {
Err(format_err!(format!(
"{} is not a valid denomination string",
s
)))
}
}
}
#[derive(TS, Serialize, Deserialize, Clone, PartialEq, Debug)]
pub struct Coin {
amount: String,
denom: Denom,
}
// TODO convert to TryFrom
impl From<GasPrice> for Coin {
fn from(g: GasPrice) -> Coin {
Coin {
amount: g.amount.to_string(),
denom: Denom::from_str(&g.denom.to_string()).unwrap(),
}
}
}
impl fmt::Display for Coin {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(&format!("{} {}", self.amount, self.denom))
}
}
// Allows adding minor and major denominations, output will have the LHS denom.
impl Add for Coin {
type Output = Self;
fn add(self, rhs: Self) -> Self {
let denom = self.denom.clone();
let lhs = self.to_minor();
let rhs = rhs.to_minor();
let lhs_amount = lhs.amount.parse::<u64>().unwrap();
let rhs_amount = rhs.amount.parse::<u64>().unwrap();
let amount = lhs_amount + rhs_amount;
let coin = Coin {
amount: amount.to_string(),
denom: Denom::Minor,
};
match denom {
Denom::Major => coin.to_major(),
Denom::Minor => coin,
}
}
}
// Allows adding minor and major denominations, output will have the LHS denom.
impl Sub for Coin {
type Output = Self;
fn sub(self, rhs: Self) -> Self {
let denom = self.denom.clone();
let lhs = self.to_minor();
let rhs = rhs.to_minor();
let lhs_amount = lhs.amount.parse::<i64>().unwrap();
let rhs_amount = rhs.amount.parse::<i64>().unwrap();
let amount = lhs_amount - rhs_amount;
let coin = Coin {
amount: amount.to_string(),
denom: Denom::Minor,
};
match denom {
Denom::Major => coin.to_major(),
Denom::Minor => coin,
}
}
}
impl Coin {
pub fn major<T: ToString>(amount: T) -> Coin {
Coin {
amount: amount.to_string(),
denom: Denom::Major,
}
}
pub fn minor<T: ToString>(amount: T) -> Coin {
Coin {
amount: amount.to_string(),
denom: Denom::Minor,
}
}
pub fn new<T: ToString>(amount: T, denom: &Denom) -> Coin {
Coin {
amount: amount.to_string(),
denom: denom.clone(),
}
}
pub fn to_major(&self) -> Coin {
match self.denom {
Denom::Major => self.clone(),
Denom::Minor => Coin {
amount: (self.amount.parse::<f64>().unwrap() / MINOR_IN_MAJOR).to_string(),
denom: Denom::Major,
},
}
}
pub fn to_minor(&self) -> Coin {
match self.denom {
Denom::Minor => self.clone(),
Denom::Major => Coin {
amount: (self.amount.parse::<f64>().unwrap() * MINOR_IN_MAJOR).to_string(),
denom: Denom::Minor,
},
}
}
pub fn amount(&self) -> String {
self.amount.clone()
}
pub fn denom(&self) -> Denom {
self.denom.clone()
}
}
impl TryFrom<Coin> for CosmWasmCoin {
type Error = String;
fn try_from(coin: Coin) -> Result<CosmWasmCoin, String> {
Ok(CosmWasmCoin::new(
Uint128::try_from(coin.amount.as_str()).unwrap().u128(),
coin.denom.to_string(),
))
}
}
impl TryFrom<Coin> for CosmosCoin {
type Error = String;
fn try_from(coin: Coin) -> Result<CosmosCoin, String> {
match Decimal::from_str(&coin.amount) {
Ok(d) => Ok(CosmosCoin {
amount: d,
denom: CosmosDenom::from_str(&coin.denom.to_string()).unwrap(),
}),
Err(e) => Err(format_err!(e)),
}
}
}
impl From<CosmosCoin> for Coin {
fn from(c: CosmosCoin) -> Coin {
Coin {
amount: c.amount.to_string(),
denom: Denom::from_str(&c.denom.to_string()).unwrap(),
}
}
}
impl From<CosmWasmCoin> for Coin {
fn from(c: CosmWasmCoin) -> Coin {
Coin {
amount: c.amount.to_string(),
denom: Denom::from_str(&c.denom).unwrap(),
}
}
}
#[cfg(test)]
mod test {
use crate::coin::{Coin, Denom};
use cosmrs::Coin as CosmosCoin;
use cosmrs::Decimal;
use cosmrs::Denom as CosmosDenom;
use cosmwasm_std::Coin as CosmWasmCoin;
use serde_json::json;
use std::convert::{TryFrom, TryInto};
use std::str::FromStr;
#[test]
fn json_to_coin() {
let minor = json!({
"amount": "1",
"denom": "Minor"
});
let major = json!({
"amount": "1",
"denom": "Major"
});
let test_minor_coin = Coin::minor("1");
let test_major_coin = Coin::major("1");
let minor_coin = serde_json::from_value::<Coin>(minor).unwrap();
let major_coin = serde_json::from_value::<Coin>(major).unwrap();
assert_eq!(minor_coin, test_minor_coin);
assert_eq!(major_coin, test_major_coin);
}
#[test]
fn denom_conversions() {
let minor = Coin::minor("1");
let major = minor.to_major();
assert_eq!(major, Coin::major("0.000001"));
let minor = major.to_minor();
assert_eq!(minor, Coin::minor("1"));
}
fn amounts() -> Vec<&'static str> {
vec![
"1",
"10",
"100",
"1000",
"10000",
"100000",
"10000000",
"100000000",
"1000000000",
"10000000000",
"100000000000",
"1000000000000",
"10000000000000",
"100000000000000",
"1000000000000000",
"10000000000000000",
"100000000000000000",
"1000000000000000000",
]
}
#[test]
fn coin_to_cosmoswasm() {
for amount in amounts() {
let coin: Coin = Coin::minor(amount).into();
let cosmoswasm_coin: CosmWasmCoin = coin.try_into().unwrap();
assert_eq!(
cosmoswasm_coin,
CosmWasmCoin::new(amount.parse::<u128>().unwrap(), Denom::Minor.to_string())
);
assert_eq!(
Coin::try_from(cosmoswasm_coin).unwrap(),
Coin::minor(amount)
);
let coin: Coin = Coin::major(amount).into();
let cosmoswasm_coin: CosmWasmCoin = coin.try_into().unwrap();
assert_eq!(
cosmoswasm_coin,
CosmWasmCoin::new(amount.parse::<u128>().unwrap(), Denom::Major.to_string())
);
assert_eq!(
Coin::try_from(cosmoswasm_coin).unwrap(),
Coin::major(amount)
);
}
}
#[test]
fn coin_to_cosmos() {
for amount in amounts() {
let coin: Coin = Coin::minor(amount).into();
let cosmos_coin: CosmosCoin = coin.try_into().unwrap();
assert_eq!(
cosmos_coin,
CosmosCoin {
amount: Decimal::from_str(amount).unwrap(),
denom: CosmosDenom::from_str(&Denom::Minor.to_string()).unwrap()
}
);
assert_eq!(Coin::try_from(cosmos_coin).unwrap(), Coin::minor(amount));
let coin: Coin = Coin::major(amount).into();
let cosmos_coin: CosmosCoin = coin.try_into().unwrap();
assert_eq!(
cosmos_coin,
CosmosCoin {
amount: Decimal::from_str(amount).unwrap(),
denom: CosmosDenom::from_str(&Denom::Major.to_string()).unwrap()
}
);
assert_eq!(Coin::try_from(cosmos_coin).unwrap(), Coin::major(amount));
}
}
#[test]
fn test_add() {
assert_eq!(Coin::minor("1") + Coin::minor("1"), Coin::minor("2"));
assert_eq!(Coin::major("1") + Coin::major("1"), Coin::major("2"));
assert_eq!(Coin::minor("1") + Coin::major("1"), Coin::minor("1000001"));
assert_eq!(Coin::major("1") + Coin::minor("1"), Coin::major("1.000001"));
}
#[test]
fn test_sub() {
assert_eq!(Coin::minor("1") - Coin::minor("1"), Coin::minor("0"));
assert_eq!(Coin::major("1") - Coin::major("1"), Coin::major("0"));
assert_eq!(Coin::minor("1") - Coin::major("1"), Coin::minor("-999999"));
assert_eq!(Coin::major("1") - Coin::minor("1"), Coin::major("0.999999"));
}
}
+90
View File
@@ -0,0 +1,90 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use config::defaults::{default_validators, ValidatorDetails, DEFAULT_MIXNET_CONTRACT_ADDRESS};
use config::NymConfig;
use serde::{Deserialize, Serialize};
use std::path::PathBuf;
use std::str::FromStr;
use tendermint_rpc::Url;
mod template;
use template::config_template;
use crate::error::BackendError;
#[derive(Debug, Default, Deserialize, Serialize, Clone)]
#[serde(deny_unknown_fields)]
pub struct Config {
base: Base,
}
#[derive(Debug, Deserialize, Serialize, Clone)]
#[serde(deny_unknown_fields)]
pub struct Base {
validators: Vec<ValidatorDetails>,
/// Address of the validator contract managing the network
mixnet_contract_address: String,
/// Mnemonic (currently of the network monitor) used for rewarding
mnemonic: String,
}
impl Default for Base {
fn default() -> Self {
Base {
validators: default_validators(),
mixnet_contract_address: DEFAULT_MIXNET_CONTRACT_ADDRESS.to_string(),
mnemonic: String::default(),
}
}
}
impl NymConfig for Config {
fn template() -> &'static str {
config_template()
}
fn default_root_directory() -> PathBuf {
dirs::home_dir()
.expect("Failed to evaluate $HOME value")
.join(".nym")
.join("wallet")
}
fn root_directory(&self) -> PathBuf {
Self::default_root_directory()
}
fn config_directory(&self) -> PathBuf {
self.root_directory().join("config")
}
fn data_directory(&self) -> PathBuf {
self.root_directory().join("data")
}
}
impl Config {
pub fn get_nymd_validator_url(&self) -> Result<Url, BackendError> {
// TODO make this a random choice
if let Some(validator_details) = self.base.validators.first() {
match tendermint_rpc::Url::from_str(&validator_details.nymd_url().to_string()) {
Ok(url) => Ok(url),
Err(e) => Err(e.into()),
}
} else {
panic!("No validators found in config")
}
}
pub fn get_mixnet_contract_address(&self) -> String {
self.base.mixnet_contract_address.clone()
}
// pub fn get_mnemonic(&self) -> String {
// self.base.mnemonic.clone()
// }
}
@@ -0,0 +1,17 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
pub(crate) fn config_template() -> &'static str {
r#"
# This is a TOML config file.
# For more information, see https://github.com/toml-lang/toml
##### main base tauri-wallet config options #####
[base]
# Validator server to which the API will be getting information about the network.
validator_url = '{{ base.validator_url }}'
"#
}
+21
View File
@@ -0,0 +1,21 @@
use thiserror::Error;
use validator_client::nymd::error::NymdError;
#[derive(Error, Debug)]
pub enum BackendError {
#[error("Error parsing bip39 mnemonic")]
Bip39Error {
#[from]
source: bip39::Error,
},
#[error("Error parsing into tendermint Url")]
TendermintError {
#[from]
source: tendermint_rpc::Error,
},
#[error("Error getting balances")]
NymdError {
#[from]
source: NymdError,
},
}
+78
View File
@@ -0,0 +1,78 @@
#![cfg_attr(
all(not(debug_assertions), target_os = "windows"),
windows_subsystem = "windows"
)]
use mixnet_contract::{Gateway, MixNode};
use std::sync::Arc;
use tokio::sync::RwLock;
use ts_rs::export;
use validator_client::nymd::fee_helpers::Operation;
mod coin;
mod config;
mod error;
mod operations;
mod state;
mod utils;
use crate::operations::account::*;
use crate::operations::admin::*;
use crate::operations::bond::*;
use crate::operations::delegate::*;
use crate::operations::send::*;
use crate::utils::*;
use crate::state::State;
#[cfg(test)]
use crate::coin::{Coin, Denom};
#[macro_export]
macro_rules! format_err {
($e:expr) => {
format!("line {}: {}", line!(), $e)
};
}
fn main() {
tauri::Builder::default()
.manage(Arc::new(RwLock::new(State::default())))
.invoke_handler(tauri::generate_handler![
connect_with_mnemonic,
get_balance,
minor_to_major,
major_to_minor,
owns_gateway,
owns_mixnode,
bond_mixnode,
unbond_mixnode,
bond_gateway,
unbond_gateway,
delegate_to_mixnode,
undelegate_from_mixnode,
delegate_to_gateway,
undelegate_from_gateway,
send,
create_new_account,
get_fee,
get_state_params,
update_state_params
])
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
export! {
MixNode => "../src/types/rust/mixnode.ts",
Coin => "../src/types/rust/coin.ts",
Balance => "../src/types/rust/balance.ts",
Gateway => "../src/types/rust/gateway.ts",
TauriTxResult => "../src/types/rust/tauritxresult.ts",
TransactionDetails => "../src/types/rust/transactiondetails.ts",
Operation => "../src/types/rust/operation.ts",
Denom => "../src/types/rust/denom.ts",
DelegationResult => "../src/types/rust/delegationresult.ts",
Account => "../src/types/rust/account.ts",
TauriStateParams => "../src/types/rust/stateparams.ts"
}
@@ -0,0 +1,113 @@
use crate::coin::{Coin, Denom};
use crate::config::Config;
use crate::error::BackendError;
use crate::format_err;
use crate::state::State;
use bip39::{Language, Mnemonic};
use serde::{Deserialize, Serialize};
use std::str::FromStr;
use std::sync::Arc;
use tokio::sync::RwLock;
use ts_rs::TS;
use validator_client::nymd::{AccountId, NymdClient, SigningNymdClient};
#[derive(TS, Serialize, Deserialize)]
pub struct Account {
contract_address: String,
client_address: String,
denom: Denom,
mnemonmic: Option<String>,
}
#[derive(TS, Serialize, Deserialize)]
pub struct Balance {
coin: Coin,
printable_balance: String,
}
#[tauri::command]
pub async fn connect_with_mnemonic(
mnemonic: String,
state: tauri::State<'_, Arc<RwLock<State>>>,
) -> Result<Account, String> {
let mnemonic = match Mnemonic::from_str(&mnemonic) {
Ok(mnemonic) => mnemonic,
Err(e) => return Err(BackendError::from(e).to_string()),
};
let client;
{
let r_state = state.read().await;
client = _connect_with_mnemonic(mnemonic, &r_state.config());
}
let contract_address = match client.contract_address() {
Ok(address) => address.to_string(),
Err(e) => return Err(format_err!(e)),
};
let client_address = client.address().to_string();
let denom = match client.denom() {
Ok(denom) => denom,
Err(e) => return Err(format_err!(e)),
};
let account = Account {
contract_address,
client_address,
denom: Denom::from_str(&denom.to_string())?,
mnemonmic: None,
};
let mut w_state = state.write().await;
w_state.set_client(client);
Ok(account)
}
#[tauri::command]
pub async fn get_balance(state: tauri::State<'_, Arc<RwLock<State>>>) -> Result<Balance, String> {
let r_state = state.read().await;
let client = r_state.client()?;
match client.get_balance(client.address()).await {
Ok(Some(coin)) => {
let coin = Coin::new(
&coin.amount.to_string(),
&Denom::from_str(&coin.denom.to_string())?,
);
Ok(Balance {
coin: coin.clone(),
printable_balance: coin.to_major().to_string(),
})
}
Ok(None) => Err(format!(
"No balance available for address {}",
client.address()
)),
Err(e) => Err(BackendError::from(e).to_string()),
}
}
#[tauri::command]
pub async fn create_new_account(
state: tauri::State<'_, Arc<RwLock<State>>>,
) -> Result<Account, String> {
let mnemonic = random_mnemonic();
let mut client = connect_with_mnemonic(mnemonic.to_string(), state).await?;
client.mnemonmic = Some(mnemonic.to_string());
Ok(client)
}
fn random_mnemonic() -> Mnemonic {
let mut rng = rand::thread_rng();
Mnemonic::generate_in_with(&mut rng, Language::English, 24).unwrap()
}
fn _connect_with_mnemonic(mnemonic: Mnemonic, config: &Config) -> NymdClient<SigningNymdClient> {
match NymdClient::connect_with_mnemonic(
config.get_nymd_validator_url().unwrap(),
Some(AccountId::from_str(&config.get_mixnet_contract_address()).unwrap()),
mnemonic,
) {
Ok(client) => client,
Err(e) => panic!("{}", e),
}
}
@@ -0,0 +1,84 @@
use crate::format_err;
use crate::state::State;
use cosmwasm_std::Decimal;
use cosmwasm_std::Uint128;
use mixnet_contract::StateParams;
use serde::{Deserialize, Serialize};
use std::convert::{TryFrom, TryInto};
use std::str::FromStr;
use std::sync::Arc;
use tokio::sync::RwLock;
use ts_rs::TS;
#[derive(Serialize, Deserialize, TS)]
pub struct TauriStateParams {
epoch_length: u32,
minimum_mixnode_bond: String,
minimum_gateway_bond: String,
mixnode_bond_reward_rate: String,
gateway_bond_reward_rate: String,
mixnode_delegation_reward_rate: String,
gateway_delegation_reward_rate: String,
mixnode_active_set_size: u32,
}
impl From<StateParams> for TauriStateParams {
fn from(p: StateParams) -> TauriStateParams {
TauriStateParams {
epoch_length: p.epoch_length,
minimum_mixnode_bond: p.minimum_mixnode_bond.to_string(),
minimum_gateway_bond: p.minimum_gateway_bond.to_string(),
mixnode_bond_reward_rate: p.mixnode_bond_reward_rate.to_string(),
gateway_bond_reward_rate: p.gateway_bond_reward_rate.to_string(),
mixnode_delegation_reward_rate: p.mixnode_delegation_reward_rate.to_string(),
gateway_delegation_reward_rate: p.gateway_delegation_reward_rate.to_string(),
mixnode_active_set_size: p.mixnode_active_set_size,
}
}
}
impl TryFrom<TauriStateParams> for StateParams {
type Error = Box<dyn std::error::Error>;
fn try_from(p: TauriStateParams) -> Result<StateParams, Self::Error> {
Ok(StateParams {
epoch_length: p.epoch_length,
minimum_mixnode_bond: Uint128::try_from(p.minimum_mixnode_bond.as_str())?,
minimum_gateway_bond: Uint128::try_from(p.minimum_gateway_bond.as_str())?,
mixnode_bond_reward_rate: Decimal::from_str(p.mixnode_bond_reward_rate.as_str())?,
gateway_bond_reward_rate: Decimal::from_str(p.gateway_bond_reward_rate.as_str())?,
mixnode_delegation_reward_rate: Decimal::from_str(p.mixnode_delegation_reward_rate.as_str())?,
gateway_delegation_reward_rate: Decimal::from_str(p.gateway_delegation_reward_rate.as_str())?,
mixnode_active_set_size: p.mixnode_active_set_size,
})
}
}
#[tauri::command]
pub async fn get_state_params(
state: tauri::State<'_, Arc<RwLock<State>>>,
) -> Result<TauriStateParams, String> {
let r_state = state.read().await;
let client = r_state.client()?;
match client.get_state_params().await {
Ok(params) => Ok(params.into()),
Err(e) => Err(format_err!(e)),
}
}
#[tauri::command]
pub async fn update_state_params(
params: TauriStateParams,
state: tauri::State<'_, Arc<RwLock<State>>>,
) -> Result<TauriStateParams, String> {
let r_state = state.read().await;
let client = r_state.client()?;
let state_params: StateParams = match params.try_into() {
Ok(state_params) => state_params,
Err(e) => return Err(format_err!(e)),
};
match client.update_state_params(state_params.clone()).await {
Ok(_) => Ok(state_params.into()),
Err(e) => Err(format_err!(e)),
}
}

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