Compare commits

..

27 Commits

Author SHA1 Message Date
fmtabbara e68a2c2ae3 create reuseable ActionMenu component 2022-07-21 11:31:03 +01:00
fmtabbara e945c94afc rebuild BondedNodeCard using existing shared components 2022-07-20 22:01:14 +01:00
fmtabbara 641b8179ba fix displayed denom 2022-07-20 12:22:36 +01:00
fmtabbara df4385ab71 update coin types in new bonding page 2022-07-18 11:35:59 +01:00
pierre 777166b93d feat(wallet-bonding): fetch mixnode status 2022-07-18 11:10:08 +01:00
pierre ccd889fc38 chore(wallet-bonding): add todo 2022-07-18 11:09:58 +01:00
pierre d9291df347 fix(wallet-bonding): bonding context mock 2022-07-18 11:09:33 +01:00
pierre 5fcce2de48 fix(wallet-bonding): bonding context mock 2022-07-18 11:09:13 +01:00
pierre abf9ccb823 refactor(wallet-bonding): switch to simpledialog component to keep modals consistency 2022-07-18 11:09:11 +01:00
pierre 352527a098 feat(wallet-bonding): unbond with gasFee and request 2022-07-18 11:08:45 +01:00
pierre 724888e790 feat(wallet-bonding): unbond with gasFee and request 2022-07-18 11:08:38 +01:00
pierre 4b552db19f refactor(wallet-bonding): bonding flow with new gasFee estimation 2022-07-18 11:08:38 +01:00
pierre 75aa2579a0 feat(wallet-bonding): node menu ui 2022-07-18 11:08:38 +01:00
pierre 2493abcdff various ui adjustments 2022-07-18 11:08:23 +01:00
pierre 508f8324f9 feat(wallet): use confirmation modal component 2022-07-18 11:08:14 +01:00
pierre 468d0f38e9 feat(wallet-bonding): bond more flow (done) 2022-07-18 11:07:07 +01:00
pierre 3382642d70 feat(wallet-bonding): node settings flow 2022-07-18 11:07:07 +01:00
pierre 8d3f1a3c38 feat(wallet-bonding): new dialog component 2022-07-18 11:07:07 +01:00
pierre c5e695f8b5 refactor(wallet-bonding): code structure 2022-07-18 11:07:07 +01:00
pierre 80cfe83f9d refactor(wallet-bonding): code structure 2022-07-18 11:06:58 +01:00
pierre 76a22035be feat(wallet-bonding): node settings wip 2022-07-18 11:06:51 +01:00
pierre 79bc2ab493 feat(wallet-bonding): add node table component 2022-07-18 11:06:39 +01:00
pierre 8c2c0f8033 fix(wallet-bonding): post merge 2022-07-18 11:06:39 +01:00
pierre 5deb0875e2 feat(wallet-bonding): bonding page, new bond form wip 2022-07-18 11:06:39 +01:00
pierre d1ee6faca8 feat(wallet-bonding): bonding page, new bond form wip 2022-07-18 11:06:24 +01:00
pierre 756bad977f feat(wallet-bonding): add context mock 2022-07-18 11:04:12 +01:00
Mark Sinclair b6448691ce feat(wallet-bonding): create context wip 2022-07-18 11:04:02 +01:00
404 changed files with 5860 additions and 15396 deletions
-36
View File
@@ -1,36 +0,0 @@
name: Daily security audit
on: workflow_dispatch
jobs:
security_audit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- uses: actions-rs/audit-check@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
notification:
if: ${{ failure() }}
needs: security_audit
runs-on: ubuntu-latest
steps:
- name: Check out repository code
uses: actions/checkout@v2
- name: Keybase - Node Install
run: npm install
working-directory: .github/workflows/support-files
- name: Keybase - Send Notification
env:
NYM_NOTIFICATION_KIND: nightly
NYM_PROJECT_NAME: "Nym daily audit"
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
GIT_COMMIT_MESSAGE: "${{ github.event.head_commit.message }}"
GIT_BRANCH: "${GITHUB_REF##*/}"
KEYBASE_NYMBOT_USERNAME: "${{ secrets.KEYBASE_NYMBOT_USERNAME }}"
KEYBASE_NYMBOT_PAPERKEY: "${{ secrets.KEYBASE_NYMBOT_PAPERKEY }}"
KEYBASE_NYMBOT_TEAM: "${{ secrets.KEYBASE_NYMBTECH_TEAM }}"
KEYBASE_NYM_CHANNEL: "test"
uses: docker://keybaseio/client:stable-node
with:
args: .github/workflows/support-files/notifications/entry_point.sh
-12
View File
@@ -1,7 +1,6 @@
name: CI for Network Explorer
on:
workflow_dispatch:
push:
paths:
- 'explorer/**'
@@ -76,14 +75,3 @@ jobs:
uses: docker://keybaseio/client:stable-node
with:
args: .github/workflows/support-files/notifications/entry_point.sh
- name: Deploy
if: github.event_name == 'workflow_dispatch'
uses: easingthemes/ssh-deploy@main
env:
SSH_PRIVATE_KEY: ${{ secrets.CD_PROD_NE_SSH_PRIVATE_KEY }}
ARGS: "-rltgoDzvO --delete"
SOURCE: "explorer/dist/"
REMOTE_HOST: ${{ secrets.CD_PROD_NE_REMOTE_HOST }}
REMOTE_USER: ${{ secrets.CD_PROD_NE_REMOTE_USER }}
TARGET: ${{ secrets.CD_PROD_NE_REMOTE_TARGET }}
EXCLUDE: "/dist/, /node_modules/"
@@ -166,8 +166,8 @@ jobs:
GIT_BRANCH: "${GITHUB_REF##*/}"
KEYBASE_NYMBOT_USERNAME: "${{ secrets.KEYBASE_NYMBOT_USERNAME }}"
KEYBASE_NYMBOT_PAPERKEY: "${{ secrets.KEYBASE_NYMBOT_PAPERKEY }}"
KEYBASE_NYMBOT_TEAM: "${{ secrets.KEYBASE_NYMTECH_TEAM }}"
KEYBASE_NYM_CHANNEL: "test"
KEYBASE_NYMBOT_TEAM: "${{ secrets.KEYBASE_NYMBOT_TEAM }}"
KEYBASE_NYM_CHANNEL: "ci-nightly"
IS_SUCCESS: "${{ env.WORKFLOW_CONCLUSION == 'success' }}"
uses: docker://keybaseio/client:stable-node
with:
-50
View File
@@ -1,50 +0,0 @@
name: Publish Nym CLI binaries
on:
workflow_dispatch:
release:
types: [created]
env:
NETWORK: mainnet
jobs:
publish-nym-cli:
strategy:
fail-fast: false
matrix:
platform: [ubuntu-latest, windows-latest, macos-latest]
runs-on: ${{ matrix.platform }}
steps:
- uses: actions/checkout@v3
- name: Check the release tag starts with `nym-cli-`
if: startsWith(github.ref, 'refs/tags/nym-cli-') == false && github.event_name != 'workflow_dispatch'
uses: actions/github-script@v3
with:
script: |
core.setFailed('Release tag did not start with nym-cli-...')
- name: Install Rust stable
uses: actions-rs/toolchain@v1
with:
toolchain: stable
- name: Build binary
run: make build-nym-cli
- name: Upload Artifact
uses: actions/upload-artifact@v3
with:
name: nym-cli-${{ matrix.platform }}
path: |
target/release/nym-cli*
retention-days: 30
- name: Upload to release based on tag name
uses: softprops/action-gh-release@v1
if: github.event_name == 'release'
with:
files: |
target/release/nym-cli
+1 -21
View File
@@ -1,7 +1,5 @@
name: Publish Nym binaries
on:
workflow_dispatch:
release:
types: [created]
@@ -20,7 +18,7 @@ jobs:
- uses: actions/checkout@v3
- name: Check the release tag starts with `nym-binaries-`
if: startsWith(github.ref, 'refs/tags/nym-binaries-') == false && github.event_name != 'workflow_dispatch'
if: startsWith(github.ref, 'refs/tags/nym-binaries-') == false
uses: actions/github-script@v3
with:
script: |
@@ -37,24 +35,8 @@ jobs:
command: build
args: --workspace --release
- name: Upload Artifact
uses: actions/upload-artifact@v3
with:
name: my-artifact
path: |
target/release/nym-client
target/release/nym-gateway
target/release/nym-mixnode
target/release/nym-socks5-client
target/release/nym-validator-api
target/release/nym-network-requester
target/release/nym-network-statistics
target/release/nym-cli
retention-days: 30
- name: Upload to release based on tag name
uses: softprops/action-gh-release@v1
if: github.event_name == 'release'
with:
files: |
target/release/nym-client
@@ -63,5 +45,3 @@ jobs:
target/release/nym-socks5-client
target/release/nym-validator-api
target/release/nym-network-requester
target/release/nym-network-statistics
target/release/nym-cli
+245 -41
View File
@@ -2,28 +2,16 @@
Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## Unreleased
### Added
- validator-client: added `query_contract_smart` and `query_contract_raw` on `NymdClient` ([#1558])
### Changed
- validator-client: made `fee` argument optional for `execute` and `execute_multiple` ([#1541])
- wasm-client: fixed build errors on MacOS and changed example JS code to use mainnet ([#1585])
[#1541]: https://github.com/nymtech/nym/pull/1541
[#1558]: https://github.com/nymtech/nym/pull/1558
[#1585]: https://github.com/nymtech/nym/pull/1585
## [nym-binaries-1.0.2](https://github.com/nymtech/nym/tree/nym-binaries-1.0.2)
## [Unreleased]
### Added
- socks5 client/websocket client: add `--force-register-gateway` flag, useful when rerunning init ([#1353])
- nym-connect: initial proof-of-concept of a UI around the socks5 client was added
- nym-connect: add ability to select network requester and gateway ([#1427])
- nym-connect: add ability to export gateway keys as JSON
- nym-connect: add auto updater
- all: added network compilation target to `--help` (or `--version`) commands ([#1256]).
- explorer-api: learned how to sum the delegations by owner in a new endpoint.
- explorer-api: add apy values to `mix_nodes` endpoint
@@ -35,14 +23,10 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
- validator-api: add Swagger to document the REST API ([#1249]).
- validator-api: Added new endpoints for coconut spending flow and communications with coconut & multisig contracts ([#1261])
- validator-api: add `uptime`, `estimated_operator_apy`, `estimated_delegators_apy` to `/mixnodes/detailed` endpoint ([#1393])
- validator-api: add node info cache storing simulated active set inclusion probabilities
- network-statistics: a new mixnet service that aggregates and exposes anonymized data about mixnet services ([#1328])
- mixnode: Added basic mixnode hardware reporting to the HTTP API ([#1308]).
- validator-api: endpoint, in coconut mode, for returning the validator-api cosmos address ([#1404]).
- validator-client: add `denom` argument and add simple test for querying an account balance
- gateway, validator-api: Checks for coconut credential double spending attempts, taking the coconut bandwidth contract as source of truth ([#1457])
- coconut-bandwidth-contract: Record the state of a coconut credential; create specific proposal for releasing funds ([#1457])
- inclusion-probability: add simulator for active set inclusion probability
### Fixed
@@ -53,12 +37,10 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
- native & socks5 clients: rerun init will now reuse previous gateway configuration instead of failing ([#1353])
- native & socks5 clients: deduplicate big chunks of init logic
- validator: fixed local docker-compose setup to work on Apple M1 ([#1329])
- explorer-api: listen out for SIGTERM and SIGQUIT too, making it play nicely as a system service ([#1482]).
- network-requester: fix filter for suffix-only domains ([#1487])
- validator-api: listen out for SIGTERM and SIGQUIT too, making it play nicely as a system service; cleaner shutdown, without panics ([#1496], [#1573]).
### Changed
- nym-connect: reuse config id instead of creating a new id on each connection
- validator-client: created internal `Coin` type that replaces coins from `cosmrs` and `cosmwasm` for API entrypoints [[#1295]]
- all: updated all `cosmwasm`-related dependencies to `1.0.0` and `cw-storage-plus` to `0.13.4` [[#1318]]
- all: updated `rocket` to `0.5.0-rc.2`.
@@ -67,13 +49,6 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
- gateway & mixnode: move detailed build info back to `--version` from `--help`.
- socks5 client/websocket client: upgrade to latest clap and switched to declarative commandline parsing.
- validator-api: fee payment for multisig operations comes from the gateway account instead of the validator APIs' accounts ([#1419])
- multisig-contract: Limit the proposal creating functionality to one address (coconut-bandwidth-contract address) ([#1457])
- All binaries and cosmwasm blobs are configured at runtime now; binaries are configured using environment variables or .env files and contracts keep the configuration parameters in storage ([#1463])
- gateway, network-statistics: include gateway id in the sent statistical data ([#1478])
- network explorer: tweak how active set probability is shown ([#1503])
- validator-api: rewarder set update fails without panicking on possible nymd queries ([#1520])
- network-requester, socks5 client (nym-connect): send and receive respectively a message error to be displayed about filter check failure ([#1576])
[#1249]: https://github.com/nymtech/nym/pull/1249
[#1256]: https://github.com/nymtech/nym/pull/1256
@@ -94,16 +69,76 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
[#1393]: https://github.com/nymtech/nym/pull/1393
[#1404]: https://github.com/nymtech/nym/pull/1404
[#1419]: https://github.com/nymtech/nym/pull/1419
[#1457]: https://github.com/nymtech/nym/pull/1457
[#1463]: https://github.com/nymtech/nym/pull/1463
[#1478]: https://github.com/nymtech/nym/pull/1478
[#1482]: https://github.com/nymtech/nym/pull/1482
[#1487]: https://github.com/nymtech/nym/pull/1487
[#1496]: https://github.com/nymtech/nym/pull/1496
[#1503]: https://github.com/nymtech/nym/pull/1503
[#1520]: https://github.com/nymtech/nym/pull/1520
[#1573]: https://github.com/nymtech/nym/pull/1573
[#1576]: https://github.com/nymtech/nym/pull/1576
[#1427]: https://github.com/nymtech/nym/pull/1427
## [nym-wallet-v1.0.7](https://github.com/nymtech/nym/tree/nym-wallet-v1.0.7) (2022-07-11)
- wallet: dark mode
- wallet: when simulating gas costs, an automatic adjustment is being used ([#1388]).
[#1388]: https://github.com/nymtech/nym/pull/1388
## [nym-contracts-v1.0.1](https://github.com/nymtech/nym/tree/nym-contracts-v1.0.1) (2022-06-22)
### Added
- mixnet-contract: Added ClaimOperatorReward and ClaimDelegatorReward messages ([#1292])
- mixnet-contract: Replace all naked `-` with `saturating_sub`.
- mixnet-contract: Added staking_supply field to ContractStateParams.
- mixnet-contract: Added a query to get MixnodeBond by identity key ([#1369]).
- mixnet-contract: Added a query to get GatewayBond by identity key ([#1369]).
- vesting-contract: Added ClaimOperatorReward and ClaimDelegatorReward messages ([#1292])
- vesting-contract: Added limit to the amount of tokens one can pledge ([#1331])
### Fixed
- mixnet-contract: `estimated_delegator_reward` calculation ([#1284])
- mixnet-contract: delegator and operator rewards use lambda and sigma instead of lambda_ticked and sigma_ticked ([#1284])
- mixnet-contract: removed `expect` in `query_delegator_reward` and queries containing invalid proxy address should now return a more human-readable error ([#1257])
- mixnet-contract: replaced integer division with fixed for performance calculations ([#1284])
- mixnet-contract: Under certain circumstances nodes could not be unbonded ([#1255](https://github.com/nymtech/nym/issues/1255)) ([#1258])
- mixnet-contract: Using correct staking supply when distributing rewards. ([#1373])
- vesting-contract: replaced `checked_sub` with `saturating_sub` to fix the underflow in `get_vesting_tokens` ([#1275])
[#1255]: https://github.com/nymtech/nym/pull/1255
[#1257]: https://github.com/nymtech/nym/pull/1257
[#1258]: https://github.com/nymtech/nym/pull/1258
[#1275]: https://github.com/nymtech/nym/pull/1275
[#1284]: https://github.com/nymtech/nym/pull/1284
[#1292]: https://github.com/nymtech/nym/pull/1292
[#1331]: https://github.com/nymtech/nym/pull/1331
[#1369]: https://github.com/nymtech/nym/pull/1369
[#1373]: https://github.com/nymtech/nym/pull/1373
## [nym-wallet-v1.0.6](https://github.com/nymtech/nym/tree/nym-wallet-v1.0.6) (2022-06-21)
- wallet: undelegating now uses either the mixnet or vesting contract, or both, depending on how delegations were made
- wallet: redeeming and compounding now uses both the mixnet and vesting contract
- wallet: the wallet backend learned how to archive wallet files
- wallet: add ENABLE_QA_MODE environment variable to enable QA mode on built wallet
## [nym-wallet-v1.0.5](https://github.com/nymtech/nym/tree/nym-wallet-v1.0.5) (2022-06-14)
- wallet: add simple CLI tool for decrypting and recovering the wallet file.
- wallet: added support for multiple accounts ([#1265])
- wallet: compound and claim reward endpoints for operators and delegators ([#1302])
- wallet: require password to switch accounts
- wallet: the wallet backend learned how to keep track of validator name, either hardcoded or by querying the status endpoint.
- wallet: new delegation and rewards UI
- wallet: show version in nav bar
- wallet: contract admin route put back
- wallet: staking_supply field to StateParams
- wallet: show transaction hash for redeeming or compounding rewards
[#1265]: https://github.com/nymtech/nym/pull/1265
[#1302]: https://github.com/nymtech/nym/pull/1302
## [nym-wallet-v1.0.4](https://github.com/nymtech/nym/tree/nym-wallet-v1.0.4) (2022-05-04)
### Changed
- all: the default behaviour of validator client is changed to use `broadcast_sync` and poll for transaction inclusion instead of using `broadcast_commit` to deal with timeouts ([#1246])
## [v1.0.1](https://github.com/nymtech/nym/tree/v1.0.1) (2022-05-04)
@@ -136,10 +171,77 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
[Full Changelog](https://github.com/nymtech/nym/compare/nym-wallet-v1.0.3...nym-binaries-1.0.0)
## [nym-wallet-v1.0.3](https://github.com/nymtech/nym/tree/nym-wallet-v1.0.3) (2022-04-25)
[Full Changelog](https://github.com/nymtech/nym/compare/nym-binaries-1.0.0-rc.2...nym-wallet-v1.0.3)
**Fixed bugs:**
- \[Issue\] Wallet 1.0.2 cannot send NYM tokens from a DelayedVestingAccount [\#1215](https://github.com/nymtech/nym/issues/1215)
- Main README not showing properly with GitHub dark mode [\#1211](https://github.com/nymtech/nym/issues/1211)
**Merged pull requests:**
- Bugfix - wallet undelegation for vesting accounts [\#1220](https://github.com/nymtech/nym/pull/1220) ([mmsinclair](https://github.com/mmsinclair))
- Bugfix/delegation reconcile [\#1219](https://github.com/nymtech/nym/pull/1219) ([jstuczyn](https://github.com/jstuczyn))
- Bugfix/query proxied pending delegations [\#1218](https://github.com/nymtech/nym/pull/1218) ([jstuczyn](https://github.com/jstuczyn))
- Using custom gas multiplier in the wallet [\#1217](https://github.com/nymtech/nym/pull/1217) ([jstuczyn](https://github.com/jstuczyn))
- Feature/vesting accounts support [\#1216](https://github.com/nymtech/nym/pull/1216) ([jstuczyn](https://github.com/jstuczyn))
- Release/1.0.0 rc.2 [\#1214](https://github.com/nymtech/nym/pull/1214) ([jstuczyn](https://github.com/jstuczyn))
- chore: fix dark mode rendering [\#1212](https://github.com/nymtech/nym/pull/1212) ([pwnfoo](https://github.com/pwnfoo))
- Feature/spend coconut [\#1210](https://github.com/nymtech/nym/pull/1210) ([neacsu](https://github.com/neacsu))
- Bugfix/unique sphinx key [\#1207](https://github.com/nymtech/nym/pull/1207) ([jstuczyn](https://github.com/jstuczyn))
- Add cache read and write timeouts [\#1206](https://github.com/nymtech/nym/pull/1206) ([durch](https://github.com/durch))
- Additional, more informative routes [\#1204](https://github.com/nymtech/nym/pull/1204) ([durch](https://github.com/durch))
- Feature/aggregated econ dynamics explorer endpoint [\#1203](https://github.com/nymtech/nym/pull/1203) ([jstuczyn](https://github.com/jstuczyn))
- Debugging validator [\#1198](https://github.com/nymtech/nym/pull/1198) ([durch](https://github.com/durch))
- wallet: expose additional validator configuration functionality to the frontend [\#1195](https://github.com/nymtech/nym/pull/1195) ([octol](https://github.com/octol))
- Update rewarding validator address [\#1193](https://github.com/nymtech/nym/pull/1193) ([durch](https://github.com/durch))
- Crypto part of the Groth's NIDKG [\#1182](https://github.com/nymtech/nym/pull/1182) ([jstuczyn](https://github.com/jstuczyn))
- fix unbond page [\#1180](https://github.com/nymtech/nym/pull/1180) ([tommyv1987](https://github.com/tommyv1987))
- Type safe bounds [\#1179](https://github.com/nymtech/nym/pull/1179) ([durch](https://github.com/durch))
- Fix delegation paging [\#1174](https://github.com/nymtech/nym/pull/1174) ([durch](https://github.com/durch))
- Update binaries to rc version [\#1172](https://github.com/nymtech/nym/pull/1172) ([tommyv1987](https://github.com/tommyv1987))
- Bump ansi-regex from 4.1.0 to 4.1.1 in /docker/typescript\_client/upload\_contract [\#1171](https://github.com/nymtech/nym/pull/1171) ([dependabot[bot]](https://github.com/apps/dependabot))
## [nym-binaries-1.0.0-rc.2](https://github.com/nymtech/nym/tree/nym-binaries-1.0.0-rc.2) (2022-04-15)
[Full Changelog](https://github.com/nymtech/nym/compare/nym-wallet-v1.0.2...nym-binaries-1.0.0-rc.2)
## [nym-wallet-v1.0.2](https://github.com/nymtech/nym/tree/nym-wallet-v1.0.2) (2022-04-05)
[Full Changelog](https://github.com/nymtech/nym/compare/nym-wallet-v1.0.1...nym-wallet-v1.0.2)
**Merged pull requests:**
- Wallet 1.0.2 visual tweaks [\#1197](https://github.com/nymtech/nym/pull/1197) ([mmsinclair](https://github.com/mmsinclair))
- Password for wallet with routes [\#1196](https://github.com/nymtech/nym/pull/1196) ([fmtabbara](https://github.com/fmtabbara))
- Add auto-updater to Nym Wallet [\#1194](https://github.com/nymtech/nym/pull/1194) ([mmsinclair](https://github.com/mmsinclair))
- Fix clippy warnings for beta toolchain [\#1191](https://github.com/nymtech/nym/pull/1191) ([octol](https://github.com/octol))
- wallet: expose validator urls to the frontend [\#1190](https://github.com/nymtech/nym/pull/1190) ([octol](https://github.com/octol))
- wallet: add test for decrypting stored wallet file [\#1189](https://github.com/nymtech/nym/pull/1189) ([octol](https://github.com/octol))
- Fix clippy warnings [\#1188](https://github.com/nymtech/nym/pull/1188) ([octol](https://github.com/octol))
- Password for wallet with routes [\#1187](https://github.com/nymtech/nym/pull/1187) ([mmsinclair](https://github.com/mmsinclair))
- wallet: add validate\_mnemonic [\#1186](https://github.com/nymtech/nym/pull/1186) ([octol](https://github.com/octol))
- wallet: support removing accounts from the wallet file [\#1185](https://github.com/nymtech/nym/pull/1185) ([octol](https://github.com/octol))
- Feature/adding discord [\#1184](https://github.com/nymtech/nym/pull/1184) ([gala1234](https://github.com/gala1234))
- wallet: config backend for validator selection [\#1183](https://github.com/nymtech/nym/pull/1183) ([octol](https://github.com/octol))
- Add storybook to wallet [\#1178](https://github.com/nymtech/nym/pull/1178) ([mmsinclair](https://github.com/mmsinclair))
- wallet: connection test nymd and api urls independently [\#1170](https://github.com/nymtech/nym/pull/1170) ([octol](https://github.com/octol))
- wallet: wire up account storage [\#1153](https://github.com/nymtech/nym/pull/1153) ([octol](https://github.com/octol))
- Feature/signature on deposit [\#1151](https://github.com/nymtech/nym/pull/1151) ([neacsu](https://github.com/neacsu))
## [nym-wallet-v1.0.1](https://github.com/nymtech/nym/tree/nym-wallet-v1.0.1) (2022-04-05)
[Full Changelog](https://github.com/nymtech/nym/compare/nym-binaries-1.0.0-rc.1...nym-wallet-v1.0.1)
**Closed issues:**
- Check enabling bbbc simultaneously with open access. Estimate what it would take to make this the default compilation target. [\#1175](https://github.com/nymtech/nym/issues/1175)
- Get coconut credential for deposited tokens [\#1138](https://github.com/nymtech/nym/issues/1138)
- Make payments lazy [\#1135](https://github.com/nymtech/nym/issues/1135)
- Uptime on node selection for sets [\#1049](https://github.com/nymtech/nym/issues/1049)
## [nym-binaries-1.0.0-rc.1](https://github.com/nymtech/nym/tree/nym-binaries-1.0.0-rc.1) (2022-03-28)
[Full Changelog](https://github.com/nymtech/nym/compare/nym-wallet-v1.0.0...nym-binaries-1.0.0-rc.1)
@@ -218,6 +320,108 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
- feature/pedersen-commitments [\#1048](https://github.com/nymtech/nym/pull/1048) ([danielementary](https://github.com/danielementary))
- Feature/reuse init owner [\#970](https://github.com/nymtech/nym/pull/970) ([neacsu](https://github.com/neacsu))
## [nym-wallet-v1.0.0](https://github.com/nymtech/nym/tree/nym-wallet-v1.0.0) (2022-02-03)
[Full Changelog](https://github.com/nymtech/nym/compare/v0.12.1...nym-wallet-v1.0.0)
**Implemented enhancements:**
- \[Feature Request\] Please enable registration without need for Telegram account [\#1016](https://github.com/nymtech/nym/issues/1016)
- Fast mixnode launch with a pre-built ISO + VM software [\#1001](https://github.com/nymtech/nym/issues/1001)
**Fixed bugs:**
- \[Issue\] [\#1000](https://github.com/nymtech/nym/issues/1000)
- \[Issue\] `nym-client` requires multiple attempts to run a server [\#869](https://github.com/nymtech/nym/issues/869)
- De-'float'-ing `Interval` \(`Display` impl + `serde`\) [\#1065](https://github.com/nymtech/nym/pull/1065) ([jstuczyn](https://github.com/jstuczyn))
- display client address on wallet creation [\#1058](https://github.com/nymtech/nym/pull/1058) ([fmtabbara](https://github.com/fmtabbara))
**Closed issues:**
- Rewarded set inclusion probability API endpoint [\#1037](https://github.com/nymtech/nym/issues/1037)
- Update cw-storage-plus to 0.11 [\#1032](https://github.com/nymtech/nym/issues/1032)
- Change `u128` fields in `RewardEstimationResponse` to `u64` [\#1029](https://github.com/nymtech/nym/issues/1029)
- Test out the mainnet Gravity Bridge [\#1006](https://github.com/nymtech/nym/issues/1006)
- Add vesting contract interface to nym-wallet [\#959](https://github.com/nymtech/nym/issues/959)
- Mixnode crash [\#486](https://github.com/nymtech/nym/issues/486)
**Merged pull requests:**
- create custom urls for mainnet [\#1095](https://github.com/nymtech/nym/pull/1095) ([fmtabbara](https://github.com/fmtabbara))
- Wallet signing on MacOS [\#1093](https://github.com/nymtech/nym/pull/1093) ([mmsinclair](https://github.com/mmsinclair))
- Fix rust 2018 idioms warnings [\#1092](https://github.com/nymtech/nym/pull/1092) ([octol](https://github.com/octol))
- Prevent contract overwriting [\#1090](https://github.com/nymtech/nym/pull/1090) ([durch](https://github.com/durch))
- Logout operation [\#1087](https://github.com/nymtech/nym/pull/1087) ([jstuczyn](https://github.com/jstuczyn))
- Update to rust edition 2021 everywhere [\#1086](https://github.com/nymtech/nym/pull/1086) ([octol](https://github.com/octol))
- Tag contract errors, and print out lines for easier QA [\#1084](https://github.com/nymtech/nym/pull/1084) ([durch](https://github.com/durch))
- Feature/flexible vesting + utility queries [\#1083](https://github.com/nymtech/nym/pull/1083) ([durch](https://github.com/durch))
- Bump @openzeppelin/contracts from 4.3.1 to 4.4.2 in /contracts/basic-bandwidth-generation [\#1082](https://github.com/nymtech/nym/pull/1082) ([dependabot[bot]](https://github.com/apps/dependabot))
- Bump nth-check from 2.0.0 to 2.0.1 in /clients/native/examples/js-examples/websocket [\#1081](https://github.com/nymtech/nym/pull/1081) ([dependabot[bot]](https://github.com/apps/dependabot))
- Bump url-parse from 1.5.1 to 1.5.4 in /clients/native/examples/js-examples/websocket [\#1080](https://github.com/nymtech/nym/pull/1080) ([dependabot[bot]](https://github.com/apps/dependabot))
- Bump follow-redirects from 1.14.1 to 1.14.7 in /clients/native/examples/js-examples/websocket [\#1079](https://github.com/nymtech/nym/pull/1079) ([dependabot[bot]](https://github.com/apps/dependabot))
- Bump nanoid from 3.1.23 to 3.2.0 in /clients/native/examples/js-examples/websocket [\#1078](https://github.com/nymtech/nym/pull/1078) ([dependabot[bot]](https://github.com/apps/dependabot))
- Setup basic test for mixnode stats reporting [\#1077](https://github.com/nymtech/nym/pull/1077) ([octol](https://github.com/octol))
- Make wallet\_address mandatory for mixnode init [\#1076](https://github.com/nymtech/nym/pull/1076) ([octol](https://github.com/octol))
- Tidy nym-mixnode module visibility [\#1075](https://github.com/nymtech/nym/pull/1075) ([octol](https://github.com/octol))
- Feature/wallet login with password [\#1074](https://github.com/nymtech/nym/pull/1074) ([fmtabbara](https://github.com/fmtabbara))
- Add trait to mock client dependency in DelayForwarder [\#1073](https://github.com/nymtech/nym/pull/1073) ([octol](https://github.com/octol))
- Bump rust-version to latest stable for nym-mixnode [\#1072](https://github.com/nymtech/nym/pull/1072) ([octol](https://github.com/octol))
- Fixes CI for our wasm build [\#1069](https://github.com/nymtech/nym/pull/1069) ([jstuczyn](https://github.com/jstuczyn))
- Add @octol as codeowner [\#1068](https://github.com/nymtech/nym/pull/1068) ([octol](https://github.com/octol))
- set-up inclusion probability [\#1067](https://github.com/nymtech/nym/pull/1067) ([fmtabbara](https://github.com/fmtabbara))
- Feature/wasm client [\#1066](https://github.com/nymtech/nym/pull/1066) ([neacsu](https://github.com/neacsu))
- Changed bech32\_prefix from punk to nymt [\#1064](https://github.com/nymtech/nym/pull/1064) ([jstuczyn](https://github.com/jstuczyn))
- Bump nanoid from 3.1.30 to 3.2.0 in /testnet-faucet [\#1063](https://github.com/nymtech/nym/pull/1063) ([dependabot[bot]](https://github.com/apps/dependabot))
- Bump nanoid from 3.1.30 to 3.2.0 in /nym-wallet [\#1062](https://github.com/nymtech/nym/pull/1062) ([dependabot[bot]](https://github.com/apps/dependabot))
- Rework vesting contract storage [\#1061](https://github.com/nymtech/nym/pull/1061) ([durch](https://github.com/durch))
- Mixnet Contract constants extraction [\#1060](https://github.com/nymtech/nym/pull/1060) ([jstuczyn](https://github.com/jstuczyn))
- fix: make explorer footer year dynamic [\#1059](https://github.com/nymtech/nym/pull/1059) ([martinyung](https://github.com/martinyung))
- Add mnemonic just on creation, to display it [\#1057](https://github.com/nymtech/nym/pull/1057) ([neacsu](https://github.com/neacsu))
- Network Explorer: updates to API and UI to show the active set [\#1056](https://github.com/nymtech/nym/pull/1056) ([mmsinclair](https://github.com/mmsinclair))
- Made contract addresses for query NymdClient construction optional [\#1055](https://github.com/nymtech/nym/pull/1055) ([jstuczyn](https://github.com/jstuczyn))
- Introduced RPC query for total token supply [\#1053](https://github.com/nymtech/nym/pull/1053) ([jstuczyn](https://github.com/jstuczyn))
- Feature/tokio console [\#1052](https://github.com/nymtech/nym/pull/1052) ([durch](https://github.com/durch))
- Implemented beta clippy lint recommendations [\#1051](https://github.com/nymtech/nym/pull/1051) ([jstuczyn](https://github.com/jstuczyn))
- add new function to update profit percentage [\#1050](https://github.com/nymtech/nym/pull/1050) ([fmtabbara](https://github.com/fmtabbara))
- Upgrade Clap and use declarative argument parsing for nym-mixnode [\#1047](https://github.com/nymtech/nym/pull/1047) ([octol](https://github.com/octol))
- Feature/additional bond validation [\#1046](https://github.com/nymtech/nym/pull/1046) ([fmtabbara](https://github.com/fmtabbara))
- Fix clippy on relevant lints [\#1044](https://github.com/nymtech/nym/pull/1044) ([neacsu](https://github.com/neacsu))
- Bump shelljs from 0.8.4 to 0.8.5 in /contracts/basic-bandwidth-generation [\#1043](https://github.com/nymtech/nym/pull/1043) ([dependabot[bot]](https://github.com/apps/dependabot))
- Endpoint for rewarded set inclusion probabilities [\#1042](https://github.com/nymtech/nym/pull/1042) ([durch](https://github.com/durch))
- Bump follow-redirects from 1.14.4 to 1.14.7 in /contracts/basic-bandwidth-generation [\#1041](https://github.com/nymtech/nym/pull/1041) ([dependabot[bot]](https://github.com/apps/dependabot))
- Bump follow-redirects from 1.14.5 to 1.14.7 in /testnet-faucet [\#1040](https://github.com/nymtech/nym/pull/1040) ([dependabot[bot]](https://github.com/apps/dependabot))
- Feature/node settings update [\#1036](https://github.com/nymtech/nym/pull/1036) ([fmtabbara](https://github.com/fmtabbara))
- Migrate to cw-storage-plus 0.11.1 [\#1035](https://github.com/nymtech/nym/pull/1035) ([durch](https://github.com/durch))
- Bump @openzeppelin/contracts from 4.4.1 to 4.4.2 in /contracts/basic-bandwidth-generation [\#1034](https://github.com/nymtech/nym/pull/1034) ([dependabot[bot]](https://github.com/apps/dependabot))
- Feature/configurable wallet [\#1033](https://github.com/nymtech/nym/pull/1033) ([neacsu](https://github.com/neacsu))
- Feature/downcast reward estimation [\#1031](https://github.com/nymtech/nym/pull/1031) ([durch](https://github.com/durch))
- Wallet UI updates [\#1028](https://github.com/nymtech/nym/pull/1028) ([fmtabbara](https://github.com/fmtabbara))
- Remove migration code [\#1027](https://github.com/nymtech/nym/pull/1027) ([neacsu](https://github.com/neacsu))
- Chore/stricter dependency requirements [\#1025](https://github.com/nymtech/nym/pull/1025) ([jstuczyn](https://github.com/jstuczyn))
- Feature/validator api client endpoints [\#1024](https://github.com/nymtech/nym/pull/1024) ([jstuczyn](https://github.com/jstuczyn))
- Updated cosmrs to 0.4.1 [\#1023](https://github.com/nymtech/nym/pull/1023) ([jstuczyn](https://github.com/jstuczyn))
- Feature/testnet deploy scripts [\#1022](https://github.com/nymtech/nym/pull/1022) ([mfahampshire](https://github.com/mfahampshire))
- Changed wallet's client to a full validator client [\#1021](https://github.com/nymtech/nym/pull/1021) ([jstuczyn](https://github.com/jstuczyn))
- Fix 404 link [\#1020](https://github.com/nymtech/nym/pull/1020) ([RiccardoMasutti](https://github.com/RiccardoMasutti))
- Feature/additional mixnode endpoints [\#1019](https://github.com/nymtech/nym/pull/1019) ([jstuczyn](https://github.com/jstuczyn))
- Introduced denom check when trying to withdraw vested coins [\#1018](https://github.com/nymtech/nym/pull/1018) ([jstuczyn](https://github.com/jstuczyn))
- Add network defaults for qa [\#1017](https://github.com/nymtech/nym/pull/1017) ([neacsu](https://github.com/neacsu))
- Feature/expanded events [\#1015](https://github.com/nymtech/nym/pull/1015) ([jstuczyn](https://github.com/jstuczyn))
- update frontend to use new profit update api [\#1014](https://github.com/nymtech/nym/pull/1014) ([fmtabbara](https://github.com/fmtabbara))
- Feature/node state endpoint [\#1013](https://github.com/nymtech/nym/pull/1013) ([jstuczyn](https://github.com/jstuczyn))
- Feature/hourly set updates [\#1012](https://github.com/nymtech/nym/pull/1012) ([durch](https://github.com/durch))
- Feature/remove unused profit margin [\#1011](https://github.com/nymtech/nym/pull/1011) ([neacsu](https://github.com/neacsu))
- Feature/explorer node status [\#1010](https://github.com/nymtech/nym/pull/1010) ([jstuczyn](https://github.com/jstuczyn))
- Use serial integer instead of random [\#1009](https://github.com/nymtech/nym/pull/1009) ([durch](https://github.com/durch))
- Feature/configure profit [\#1008](https://github.com/nymtech/nym/pull/1008) ([neacsu](https://github.com/neacsu))
- Feature/fix gateway sign [\#1004](https://github.com/nymtech/nym/pull/1004) ([neacsu](https://github.com/neacsu))
- Fix clippy [\#1003](https://github.com/nymtech/nym/pull/1003) ([neacsu](https://github.com/neacsu))
- Update wallet version [\#998](https://github.com/nymtech/nym/pull/998) ([tommyv1987](https://github.com/tommyv1987))
- Fix wallet build instructions [\#997](https://github.com/nymtech/nym/pull/997) ([tommyv1987](https://github.com/tommyv1987))
- Make the separation between testnet-mode and erc20 bandwidth mode clearer [\#994](https://github.com/nymtech/nym/pull/994) ([neacsu](https://github.com/neacsu))
- Bump @openzeppelin/contracts from 3.4.0 to 4.4.1 in /contracts/basic-bandwidth-generation [\#983](https://github.com/nymtech/nym/pull/983) ([dependabot[bot]](https://github.com/apps/dependabot))
- Feature/implicit runtime [\#973](https://github.com/nymtech/nym/pull/973) ([jstuczyn](https://github.com/jstuczyn))
- Differentiate staking and ownership [\#961](https://github.com/nymtech/nym/pull/961) ([durch](https://github.com/durch))
## [v0.12.1](https://github.com/nymtech/nym/tree/v0.12.1) (2021-12-23)
Generated
+50 -35
View File
@@ -644,7 +644,6 @@ name = "coconut-bandwidth-contract-common"
version = "0.1.0"
dependencies = [
"cosmwasm-std",
"multisig-contract-common",
"schemars",
"serde",
]
@@ -894,7 +893,6 @@ dependencies = [
"cfg-if 0.1.10",
"clap 3.2.8",
"coconut-interface",
"config",
"credential-storage",
"credentials",
"crypto",
@@ -929,6 +927,7 @@ dependencies = [
"coconut-interface",
"cosmrs",
"crypto",
"network-defaults",
"rand 0.7.3",
"thiserror",
"url",
@@ -1591,7 +1590,6 @@ name = "explorer-api"
version = "1.0.1"
dependencies = [
"chrono",
"clap 3.2.8",
"humantime-serde",
"isocountry",
"itertools",
@@ -1607,7 +1605,6 @@ dependencies = [
"schemars",
"serde",
"serde_json",
"task",
"thiserror",
"tokio",
"validator-client",
@@ -1904,6 +1901,10 @@ name = "futures-timer"
version = "3.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c"
dependencies = [
"gloo-timers",
"send_wrapper",
]
[[package]]
name = "futures-util"
@@ -2088,6 +2089,18 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
[[package]]
name = "gloo-timers"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d12a7f4e95cfe710f1d624fb1210b7d961a5fb05c4fd942f4feab06e61f590e"
dependencies = [
"futures-channel",
"futures-core",
"js-sys",
"wasm-bindgen",
]
[[package]]
name = "group"
version = "0.10.0"
@@ -2481,15 +2494,6 @@ dependencies = [
"syn",
]
[[package]]
name = "inclusion-probability"
version = "0.1.0"
dependencies = [
"log",
"rand 0.8.5",
"thiserror",
]
[[package]]
name = "indenter"
version = "0.3.3"
@@ -2737,9 +2741,9 @@ dependencies = [
[[package]]
name = "log"
version = "0.4.17"
version = "0.4.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
checksum = "6389c490849ff5bc16be905ae24bc913a9c8892e19b2341dbc175e14c341c2b8"
dependencies = [
"cfg-if 1.0.0",
]
@@ -2866,6 +2870,7 @@ dependencies = [
"cosmwasm-std",
"fixed",
"log",
"network-defaults",
"schemars",
"serde",
"serde_repr",
@@ -2962,7 +2967,6 @@ name = "network-defaults"
version = "0.1.0"
dependencies = [
"cfg-if 1.0.0",
"dotenv",
"hex-literal",
"once_cell",
"serde",
@@ -3050,7 +3054,7 @@ dependencies = [
[[package]]
name = "nym-client"
version = "1.0.2"
version = "1.0.1"
dependencies = [
"clap 3.2.8",
"client-core",
@@ -3060,6 +3064,7 @@ dependencies = [
"credentials",
"crypto",
"dirs",
"dotenv",
"futures",
"gateway-client",
"gateway-requests",
@@ -3084,7 +3089,7 @@ dependencies = [
[[package]]
name = "nym-gateway"
version = "1.0.2"
version = "1.0.1"
dependencies = [
"anyhow",
"async-trait",
@@ -3132,7 +3137,7 @@ dependencies = [
[[package]]
name = "nym-mixnode"
version = "1.0.2"
version = "1.0.1"
dependencies = [
"anyhow",
"bs58",
@@ -3172,7 +3177,7 @@ dependencies = [
[[package]]
name = "nym-network-requester"
version = "1.0.2"
version = "1.0.1"
dependencies = [
"async-trait",
"clap 2.34.0",
@@ -3200,7 +3205,7 @@ dependencies = [
[[package]]
name = "nym-network-statistics"
version = "1.0.2"
version = "0.1.0"
dependencies = [
"dirs",
"log",
@@ -3216,7 +3221,7 @@ dependencies = [
[[package]]
name = "nym-socks5-client"
version = "1.0.2"
version = "1.0.1"
dependencies = [
"clap 3.2.8",
"client-core",
@@ -3226,6 +3231,7 @@ dependencies = [
"credentials",
"crypto",
"dirs",
"dotenv",
"futures",
"gateway-client",
"gateway-requests",
@@ -3277,7 +3283,7 @@ dependencies = [
[[package]]
name = "nym-validator-api"
version = "1.0.2"
version = "1.0.1"
dependencies = [
"anyhow",
"async-trait",
@@ -3292,15 +3298,12 @@ dependencies = [
"credential-storage",
"credentials",
"crypto",
"cw-utils",
"cw3",
"dirs",
"dotenv",
"futures",
"gateway-client",
"getset",
"humantime-serde",
"inclusion-probability",
"log",
"mixnet-contract-common",
"multisig-contract-common",
@@ -3320,8 +3323,6 @@ dependencies = [
"serde",
"serde_json",
"sqlx",
"tap",
"task",
"thiserror",
"time 0.3.9",
"tokio",
@@ -4910,6 +4911,12 @@ dependencies = [
"pest",
]
[[package]]
name = "send_wrapper"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f638d531eccd6e23b980caf34876660d38e265409d8e99b397ab71eb3612fad0"
[[package]]
name = "serde"
version = "1.0.136"
@@ -4971,9 +4978,9 @@ dependencies = [
[[package]]
name = "serde_json"
version = "1.0.83"
version = "1.0.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38dd04e3c8279e75b31ef29dbdceebfe5ad89f4d0937213c53f7d49d01b3d5a7"
checksum = "8e8d9fa5c3b304765ce1fd9c4c8a3de2c8db365a5b91be52f186efc675681d95"
dependencies = [
"itoa 1.0.1",
"ryu",
@@ -5189,7 +5196,6 @@ version = "0.1.0"
dependencies = [
"nymsphinx-addressing",
"ordered-buffer",
"thiserror",
]
[[package]]
@@ -5381,6 +5387,7 @@ version = "1.0.1"
dependencies = [
"async-trait",
"log",
"network-defaults",
"reqwest",
"serde",
"serde_json",
@@ -5643,18 +5650,18 @@ checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb"
[[package]]
name = "thiserror"
version = "1.0.32"
version = "1.0.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f5f6586b7f764adc0231f4c79be7b920e766bb2f3e51b3661cdb263828f19994"
checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.32"
version = "1.0.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12bafc5b54507e0149cdf1b145a5d80ab80a90bcd9275df43d4fff68460f6c21"
checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b"
dependencies = [
"proc-macro2",
"quote",
@@ -6328,6 +6335,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
name = "vesting-contract"
version = "1.0.1"
dependencies = [
"config",
"cosmwasm-std",
"cw-storage-plus",
"mixnet-contract-common",
@@ -6396,6 +6404,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "632f73e236b219150ea279196e54e610f5dbafa5d61786303d4da54f84e47fce"
dependencies = [
"cfg-if 1.0.0",
"serde",
"serde_json",
"wasm-bindgen-macro",
]
@@ -6491,12 +6501,15 @@ dependencies = [
"ethereum-types",
"futures",
"futures-timer",
"getrandom 0.2.6",
"headers",
"hex",
"js-sys",
"jsonrpc-core",
"log",
"parking_lot 0.11.2",
"pin-project",
"rand 0.8.5",
"reqwest",
"rlp",
"secp256k1",
@@ -6508,6 +6521,8 @@ dependencies = [
"tokio-stream",
"tokio-util 0.6.9",
"url",
"wasm-bindgen",
"wasm-bindgen-futures",
"web3-async-native-tls",
]
+7 -9
View File
@@ -22,23 +22,22 @@ members = [
"clients/native",
"clients/native/websocket-requests",
"clients/socks5",
"common/bandwidth-claim-contract",
"common/client-libs/gateway-client",
"common/client-libs/mixnet-client",
"common/client-libs/validator-client",
"common/credential-storage",
"common/coconut-interface",
"common/config",
"common/credentials",
"common/crypto",
"common/crypto/dkg",
"common/execute",
"common/bandwidth-claim-contract",
"common/cosmwasm-smart-contracts/coconut-bandwidth-contract",
"common/cosmwasm-smart-contracts/contracts-common",
"common/cosmwasm-smart-contracts/mixnet-contract",
"common/cosmwasm-smart-contracts/multisig-contract",
"common/cosmwasm-smart-contracts/vesting-contract",
"common/credential-storage",
"common/credentials",
"common/crypto",
"common/crypto/dkg",
"common/execute",
"common/inclusion-probability",
"common/mixnode-common",
"common/network-defaults",
"common/nonexhaustive-delayqueue",
@@ -54,9 +53,9 @@ members = [
"common/nymsphinx/params",
"common/nymsphinx/types",
"common/pemstore",
"common/statistics",
"common/socks5/proxy-helpers",
"common/socks5/requests",
"common/statistics",
"common/task",
"common/topology",
"common/types",
@@ -77,7 +76,6 @@ default-members = [
"clients/socks5",
"gateway",
"service-providers/network-requester",
"service-providers/network-statistics",
"mixnode",
"validator-api",
"explorer-api",
+1 -1
View File
@@ -1,5 +1,5 @@
test: clippy-all cargo-test wasm fmt
test-all: test cargo-test-expensive
test: build clippy-all cargo-test wasm fmt
no-clippy: build cargo-test wasm fmt
happy: fmt clippy-happy test
clippy-all: clippy-all-main clippy-all-contracts clippy-all-wallet clippy-all-connect
@@ -133,6 +133,7 @@ where
let prepared_fragment = self
.message_preparer
.prepare_chunk_for_sending(chunk_clone, topology, &self.ack_key, &recipient)
.await
.unwrap();
real_messages.push(RealMessage::new(
@@ -83,6 +83,7 @@ where
let prepared_fragment = self
.message_preparer
.prepare_chunk_for_sending(chunk_clone, topology_ref, &self.ack_key, packet_recipient)
.await
.unwrap();
// if we have the ONLY strong reference to the ack data, it means it was removed from the
+2 -1
View File
@@ -1,6 +1,7 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use config::defaults::*;
use config::NymConfig;
use serde::{Deserialize, Serialize};
use std::marker::PhantomData;
@@ -365,7 +366,7 @@ impl<T: NymConfig> Default for Client<T> {
version: env!("CARGO_PKG_VERSION").to_string(),
id: "".to_string(),
disabled_credentials_mode: true,
validator_api_urls: vec![],
validator_api_urls: default_api_endpoints(),
private_identity_key_file: Default::default(),
public_identity_key_file: Default::default(),
private_encryption_key_file: Default::default(),
-1
View File
@@ -18,7 +18,6 @@ url = "2.2"
tokio = { version = "1.19.1", features = ["rt-multi-thread", "net", "signal", "macros"] } # async runtime
coconut-interface = { path = "../../common/coconut-interface" }
config = { path = "../../common/config" }
credentials = { path = "../../common/credentials" }
credential-storage = { path = "../../common/credential-storage" }
crypto = { path = "../../common/crypto", features = ["rand", "asymmetric", "symmetric", "aes", "hashing"] }
+8 -12
View File
@@ -2,8 +2,9 @@
// SPDX-License-Identifier: Apache-2.0
use crate::error::Result;
use crate::{MNEMONIC, NYMD_URL};
use bip39::Mnemonic;
use network_defaults::{NymNetworkDetails, VOUCHER_INFO};
use network_defaults::{DEFAULT_NETWORK, MIX_DENOM, VOUCHER_INFO};
use std::str::FromStr;
use url::Url;
use validator_client::nymd;
@@ -12,23 +13,18 @@ use validator_client::nymd::{Coin, Fee, NymdClient, SigningNymdClient};
pub(crate) struct Client {
nymd_client: NymdClient<SigningNymdClient>,
mix_denom_base: String,
}
impl Client {
pub fn new(nymd_url: &str, mnemonic: &str) -> Self {
let nymd_url = Url::from_str(nymd_url).unwrap();
let mnemonic = Mnemonic::from_str(mnemonic).unwrap();
let network_details = NymNetworkDetails::new_from_env();
let config = nymd::Config::try_from_nym_network_details(&network_details)
pub fn new() -> Self {
let nymd_url = Url::from_str(NYMD_URL).unwrap();
let mnemonic = Mnemonic::from_str(MNEMONIC).unwrap();
let config = nymd::Config::try_from_nym_network_details(&DEFAULT_NETWORK.details())
.expect("failed to construct valid validator client config with the provided network");
let nymd_client =
NymdClient::connect_with_mnemonic(config, nymd_url.as_ref(), mnemonic, None).unwrap();
Client {
nymd_client,
mix_denom_base: network_details.chain_details.mix_denom.base,
}
Client { nymd_client }
}
pub async fn deposit(
@@ -38,7 +34,7 @@ impl Client {
encryption_key: String,
fee: Option<Fee>,
) -> Result<String> {
let amount = Coin::new(amount as u128, self.mix_denom_base.clone());
let amount = Coin::new(amount as u128, MIX_DENOM.base.to_string());
Ok(self
.nymd_client
.deposit(
+4 -13
View File
@@ -6,6 +6,7 @@ use clap::{Args, Subcommand};
use pickledb::PickleDb;
use rand::rngs::OsRng;
use std::str::FromStr;
use url::Url;
use coconut_interface::{Attribute, Base58, BlindSignRequest, Bytable, Parameters};
use credential_storage::storage::Storage;
@@ -19,6 +20,7 @@ use validator_client::nymd::tx::Hash;
use crate::client::Client;
use crate::error::{CredentialClientError, Result};
use crate::state::{KeyPair, RequestData, State};
use crate::SIGNER_AUTHORITIES;
#[derive(Subcommand)]
pub(crate) enum Commands {
@@ -37,12 +39,6 @@ pub(crate) trait Execute {
#[derive(Args, Clone)]
pub(crate) struct Deposit {
/// The nymd URL that should be used
#[clap(long)]
nymd_url: String,
/// A mnemonic for the account that does the deposit
#[clap(long)]
mnemonic: String,
/// The amount that needs to be deposited
#[clap(long)]
amount: u64,
@@ -55,7 +51,7 @@ impl Execute for Deposit {
let signing_keypair = KeyPair::from(identity::KeyPair::new(&mut rng));
let encryption_keypair = KeyPair::from(encryption::KeyPair::new(&mut rng));
let client = Client::new(&self.nymd_url, &self.mnemonic);
let client = Client::new();
let tx_hash = client
.deposit(
self.amount,
@@ -100,10 +96,6 @@ pub(crate) struct GetCredential {
/// The hash of a successful deposit transaction
#[clap(long)]
tx_hash: String,
/// The URLs to the validator-api endpoints the are run as coconut signer authorities, separated
/// by comma (,)
#[clap(long)]
signer_authorities: String,
/// If we want to get the signature without attaching a blind sign request; it is expected that
/// there is already a signature stored on the signer
#[clap(long, parse(from_flag))]
@@ -116,8 +108,7 @@ impl Execute for GetCredential {
let mut state = db
.get::<State>(&self.tx_hash)
.ok_or(CredentialClientError::NoDeposit)?;
let urls = config::parse_validators(&self.signer_authorities);
let urls = SIGNER_AUTHORITIES.map(|addr| Url::from_str(addr).unwrap());
let params = Parameters::new(TOTAL_ATTRIBUTES).unwrap();
let bandwidth_credential_attributes = if self.__no_request {
+8 -13
View File
@@ -11,24 +11,20 @@ cfg_if::cfg_if! {
use commands::{Commands, Execute};
use error::Result;
use network_defaults::setup_env;
use clap::Parser;
use pickledb::{PickleDb, PickleDbDumpPolicy, SerializationMethod};
pub const MNEMONIC: &str = "jazz fatigue diagram account outer wrist slide cherry mother grid network pause wolf pig round answer mail junior better hair dismiss toward access end";
pub const NYMD_URL: &str = "http://127.0.0.1:26657";
pub const CONTRACT_ADDRESS: &str = "nymt1nc5tatafv6eyq7llkr2gv50ff9e22mnfp9pc5s";
pub const SIGNER_AUTHORITIES: [&str; 1] = [
"http://127.0.0.1:8080",
];
#[derive(Parser)]
#[clap(author = "Nymtech", version, about)]
struct Cli {
/// Path pointing to an env file that configures the client.
#[clap(long)]
pub(crate) config_env_file: Option<std::path::PathBuf>,
/// Path where the sqlite credental database will be located.
/// It should point to a $HOME/$CLIENT_ID/data/db.sqlite file of
/// the client that is supposed to use the credential.
#[clap(long)]
pub(crate) credential_db_path: std::path::PathBuf,
#[clap(subcommand)]
command: Commands,
}
@@ -36,9 +32,8 @@ cfg_if::cfg_if! {
#[tokio::main]
async fn main() -> Result<()> {
let args = Cli::parse();
setup_env(args.config_env_file.clone());
let shared_storage = credential_storage::initialise_storage(args.credential_db_path.clone()).await;
let shared_storage = credential_storage::initialise_storage(std::path::PathBuf::from("/tmp/credential.db")).await;
let mut db = match PickleDb::load(
"credential.db",
PickleDbDumpPolicy::AutoDump,
+2 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "nym-client"
version = "1.0.2"
version = "1.0.1"
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"]
description = "Implementation of the Nym Client"
edition = "2021"
@@ -22,6 +22,7 @@ url = "2.2"
clap = { version = "3.2.8", features = ["cargo", "derive"] }
dirs = "4.0"
dotenv = "0.15.0" # for obtaining environmental variables (only used for RUST_LOG for time being)
log = "0.4" # self explanatory
pretty_env_logger = "0.4" # for formatting log messages
rand = { version = "0.7.3", features = ["wasm-bindgen"] } # rng-related traits + some rng implementation to use
-4
View File
@@ -50,10 +50,6 @@ impl NymConfig for Config {
.join("clients")
}
fn try_default_root_directory() -> Option<PathBuf> {
dirs::home_dir().map(|path| path.join(".nym").join("clients"))
}
fn root_directory(&self) -> PathBuf {
self.base.get_nym_root_directory()
}
+3 -3
View File
@@ -199,9 +199,9 @@ impl NymClient {
Some(bandwidth_controller),
);
gateway_client
.set_disabled_credentials_mode(self.config.get_base().get_disabled_credentials_mode());
if self.config.get_base().get_disabled_credentials_mode() {
gateway_client.set_disabled_credentials_mode(true)
}
gateway_client
.authenticate_and_start()
.await
+5 -4
View File
@@ -46,9 +46,10 @@ pub(crate) struct Init {
fastmode: bool,
/// Set this client to work in a enabled credentials mode that would attempt to use gateway
/// with bandwidth credential requirement.
#[cfg(any(feature = "eth", feature = "coconut"))]
#[clap(long)]
/// with bandwidth credential requirement. If this value is set, --eth-endpoint and
/// --eth-private_key don't need to be set.
#[cfg(all(feature = "eth", not(feature = "coconut")))]
#[clap(long, conflicts_with_all = &["eth-endpoint", "eth-private-key"])]
enabled_credentials_mode: bool,
/// URL of an Ethereum full node that we want to use for getting bandwidth tokens from ERC20
@@ -78,7 +79,7 @@ impl From<Init> for OverrideConfig {
port: init_config.port,
fastmode: init_config.fastmode,
#[cfg(any(feature = "eth", feature = "coconut"))]
#[cfg(all(feature = "eth", not(feature = "coconut")))]
enabled_credentials_mode: init_config.enabled_credentials_mode,
#[cfg(all(feature = "eth", not(feature = "coconut")))]
+20 -17
View File
@@ -3,6 +3,8 @@
use crate::client::config::{Config, SocketType};
use clap::{Parser, Subcommand};
use network_defaults::DEFAULT_NETWORK;
use url::Url;
#[cfg(not(feature = "coconut"))]
pub(crate) const DEFAULT_ETH_ENDPOINT: &str =
@@ -26,6 +28,7 @@ fn long_version() -> String {
{:<20}{}
{:<20}{}
{:<20}{}
{:<20}{}
"#,
"Build Timestamp:",
env!("VERGEN_BUILD_TIMESTAMP"),
@@ -43,6 +46,8 @@ fn long_version() -> String {
env!("VERGEN_RUSTC_CHANNEL"),
"cargo Profile:",
env!("VERGEN_CARGO_PROFILE"),
"Network:",
DEFAULT_NETWORK
)
}
@@ -53,10 +58,6 @@ fn long_version_static() -> &'static str {
#[derive(Parser)]
#[clap(author = "Nymtech", version, long_version = long_version_static(), about)]
pub(crate) struct Cli {
/// Path pointing to an env file that configures the client.
#[clap(long)]
pub(crate) config_env_file: Option<std::path::PathBuf>,
#[clap(subcommand)]
command: Commands,
}
@@ -78,7 +79,7 @@ pub(crate) struct OverrideConfig {
port: Option<u16>,
fastmode: bool,
#[cfg(any(feature = "eth", feature = "coconut"))]
#[cfg(all(feature = "eth", not(feature = "coconut")))]
enabled_credentials_mode: bool,
#[cfg(all(feature = "eth", not(feature = "coconut")))]
@@ -96,17 +97,22 @@ pub(crate) async fn execute(args: &Cli) {
}
}
fn parse_validators(raw: &str) -> Vec<Url> {
raw.split(',')
.map(|raw_validator| {
raw_validator
.trim()
.parse()
.expect("one of the provided validator api urls is invalid")
})
.collect()
}
pub(crate) fn override_config(mut config: Config, args: OverrideConfig) -> Config {
if let Some(raw_validators) = args.validators {
config
.get_base_mut()
.set_custom_validator_apis(config::parse_validators(&raw_validators));
} else if std::env::var(network_defaults::var_names::CONFIGURED).is_ok() {
let raw_validators = std::env::var(network_defaults::var_names::API_VALIDATOR)
.expect("api validator not set");
config
.get_base_mut()
.set_custom_validator_apis(config::parse_validators(&raw_validators));
.set_custom_validator_apis(parse_validators(&raw_validators));
}
if args.disable_socket {
@@ -126,15 +132,12 @@ pub(crate) fn override_config(mut config: Config, args: OverrideConfig) -> Confi
.get_base_mut()
.with_eth_private_key(DEFAULT_ETH_PRIVATE_KEY.to_string());
}
#[cfg(any(feature = "eth", feature = "coconut"))]
#[cfg(all(feature = "eth", not(feature = "coconut")))]
{
if args.enabled_credentials_mode {
config.get_base_mut().with_disabled_credentials(false)
}
}
#[cfg(all(feature = "eth", not(feature = "coconut")))]
{
if let Some(eth_endpoint) = args.eth_endpoint {
config.get_base_mut().with_eth_endpoint(eth_endpoint);
}
+6 -5
View File
@@ -35,9 +35,10 @@ pub(crate) struct Run {
port: Option<u16>,
/// Set this client to work in a enabled credentials mode that would attempt to use gateway
/// with bandwidth credential requirement.
#[cfg(any(feature = "eth", feature = "coconut"))]
#[clap(long)]
/// with bandwidth credential requirement. If this value is set, --eth-endpoint and
/// --eth-private-key don't need to be set.
#[cfg(all(feature = "eth", not(feature = "coconut")))]
#[clap(long, conflicts_with_all = &["eth-endpoint", "eth-private-key"])]
enabled_credentials_mode: bool,
/// URL of an Ethereum full node that we want to use for getting bandwidth tokens from ERC20
@@ -61,7 +62,7 @@ impl From<Run> for OverrideConfig {
port: run_config.port,
fastmode: false,
#[cfg(any(feature = "eth", feature = "coconut"))]
#[cfg(all(feature = "eth", not(feature = "coconut")))]
enabled_credentials_mode: run_config.enabled_credentials_mode,
#[cfg(all(feature = "eth", not(feature = "coconut")))]
@@ -81,7 +82,7 @@ fn version_check(cfg: &Config) -> bool {
if binary_version == config_version {
true
} else {
warn!("The native-client binary has different version than what is specified in config file! {} and {}", binary_version, config_version);
warn!("The mixnode binary has different version than what is specified in config file! {} and {}", binary_version, config_version);
if is_minor_version_compatible(binary_version, config_version) {
info!("but they are still semver compatible. However, consider running the `upgrade` command");
true
+10 -1
View File
@@ -3,7 +3,7 @@
use crate::client::config::{Config, MISSING_VALUE};
use config::NymConfig;
use config::{defaults::default_api_endpoints, NymConfig};
use version_checker::Version;
use clap::Args;
@@ -105,6 +105,15 @@ fn minor_0_12_upgrade(
print_start_upgrade(&config_version, &to_version);
println!(
"Setting validator API endpoints to {:?}",
default_api_endpoints()
);
config
.get_base_mut()
.set_custom_validator_apis(default_api_endpoints());
config
.get_base_mut()
.set_custom_version(to_version.to_string().as_ref());
+1 -2
View File
@@ -2,7 +2,6 @@
// SPDX-License-Identifier: Apache-2.0
use clap::{crate_version, Parser};
use network_defaults::setup_env;
pub mod client;
pub mod commands;
@@ -10,11 +9,11 @@ pub mod websocket;
#[tokio::main]
async fn main() {
dotenv::dotenv().ok();
setup_logging();
println!("{}", banner());
let args = commands::Cli::parse();
setup_env(args.config_env_file.clone());
commands::execute(&args).await;
}
+2 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "nym-socks5-client"
version = "1.0.2"
version = "1.0.1"
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
description = "A SOCKS5 localhost proxy that converts incoming messages to Sphinx and sends them to a Nym address"
edition = "2021"
@@ -13,6 +13,7 @@ path = "src/lib.rs"
[dependencies]
clap = { version = "3.2.8", features = ["cargo", "derive"] }
dirs = "4.0"
dotenv = "0.15.0"
futures = "0.3"
log = "0.4"
pin-project = "1.0"
-4
View File
@@ -33,10 +33,6 @@ impl NymConfig for Config {
.join("socks5-clients")
}
fn try_default_root_directory() -> Option<PathBuf> {
dirs::home_dir().map(|path| path.join(".nym").join("socks5-clients"))
}
fn root_directory(&self) -> PathBuf {
self.base.get_nym_root_directory()
}
+3 -3
View File
@@ -198,9 +198,9 @@ impl NymClient {
Some(bandwidth_controller),
);
gateway_client
.set_disabled_credentials_mode(self.config.get_base().get_disabled_credentials_mode());
if self.config.get_base().get_disabled_credentials_mode() {
gateway_client.set_disabled_credentials_mode(true)
}
gateway_client
.authenticate_and_start()
.await
+5 -4
View File
@@ -46,9 +46,10 @@ pub(crate) struct Init {
fastmode: bool,
/// Set this client to work in a enabled credentials mode that would attempt to use gateway
/// with bandwidth credential requirement.
#[cfg(any(feature = "eth", feature = "coconut"))]
#[clap(long)]
/// with bandwidth credential requirement. If this value is set, --eth-endpoint and
/// --eth-private_key don't need to be set.
#[cfg(all(feature = "eth", not(feature = "coconut")))]
#[clap(long, conflicts_with_all = &["eth-endpoint", "eth-private-key"])]
enabled_credentials_mode: bool,
/// URL of an Ethereum full node that we want to use for getting bandwidth tokens from ERC20
@@ -77,7 +78,7 @@ impl From<Init> for OverrideConfig {
port: init_config.port,
fastmode: init_config.fastmode,
#[cfg(any(feature = "eth", feature = "coconut"))]
#[cfg(all(feature = "eth", not(feature = "coconut")))]
enabled_credentials_mode: init_config.enabled_credentials_mode,
#[cfg(all(feature = "eth", not(feature = "coconut")))]
+18 -14
View File
@@ -3,7 +3,8 @@
use crate::client::config::Config;
use clap::{Parser, Subcommand};
use config::parse_validators;
use network_defaults::DEFAULT_NETWORK;
use url::Url;
pub mod init;
pub(crate) mod run;
@@ -27,6 +28,7 @@ fn long_version() -> String {
{:<20}{}
{:<20}{}
{:<20}{}
{:<20}{}
"#,
"Build Timestamp:",
env!("VERGEN_BUILD_TIMESTAMP"),
@@ -44,6 +46,8 @@ fn long_version() -> String {
env!("VERGEN_RUSTC_CHANNEL"),
"cargo Profile:",
env!("VERGEN_CARGO_PROFILE"),
"Network:",
DEFAULT_NETWORK
)
}
@@ -54,10 +58,6 @@ fn long_version_static() -> &'static str {
#[derive(Parser)]
#[clap(author = "Nymtech", version, long_version = long_version_static(), about)]
pub(crate) struct Cli {
/// Path pointing to an env file that configures the client.
#[clap(long)]
pub(crate) config_env_file: Option<std::path::PathBuf>,
#[clap(subcommand)]
command: Commands,
}
@@ -78,7 +78,7 @@ pub(crate) struct OverrideConfig {
port: Option<u16>,
fastmode: bool,
#[cfg(any(feature = "eth", feature = "coconut"))]
#[cfg(all(feature = "eth", not(feature = "coconut")))]
enabled_credentials_mode: bool,
#[cfg(all(feature = "eth", not(feature = "coconut")))]
@@ -96,15 +96,22 @@ pub(crate) async fn execute(args: &Cli) {
}
}
fn parse_validators(raw: &str) -> Vec<Url> {
raw.split(',')
.map(|raw_validator| {
raw_validator
.trim()
.parse()
.expect("one of the provided validator api urls is invalid")
})
.collect()
}
pub(crate) fn override_config(mut config: Config, args: OverrideConfig) -> Config {
if let Some(raw_validators) = args.validators {
config
.get_base_mut()
.set_custom_validator_apis(parse_validators(&raw_validators));
} else if let Ok(raw_validators) = std::env::var(network_defaults::var_names::API_VALIDATOR) {
config
.get_base_mut()
.set_custom_validator_apis(parse_validators(&raw_validators));
}
if let Some(port) = args.port {
@@ -121,14 +128,11 @@ pub(crate) fn override_config(mut config: Config, args: OverrideConfig) -> Confi
.with_eth_private_key(DEFAULT_ETH_PRIVATE_KEY.to_string());
}
#[cfg(any(feature = "eth", feature = "coconut"))]
#[cfg(all(feature = "eth", not(feature = "coconut")))]
{
if args.enabled_credentials_mode {
config.get_base_mut().with_disabled_credentials(false)
}
}
#[cfg(all(feature = "eth", not(feature = "coconut")))]
{
if let Some(eth_endpoint) = args.eth_endpoint {
config.get_base_mut().with_eth_endpoint(eth_endpoint);
}
+5 -4
View File
@@ -39,9 +39,10 @@ pub(crate) struct Run {
port: Option<u16>,
/// Set this client to work in a enabled credentials mode that would attempt to use gateway
/// with bandwidth credential requirement.
#[cfg(any(feature = "eth", feature = "coconut"))]
#[clap(long)]
/// with bandwidth credential requirement. If this value is set, --eth-endpoint and
/// --eth-private-key don't need to be set.
#[cfg(all(feature = "eth", not(feature = "coconut")))]
#[clap(long, conflicts_with_all = &["eth-endpoint", "eth-private-key"])]
enabled_credentials_mode: bool,
/// URL of an Ethereum full node that we want to use for getting bandwidth tokens from ERC20
@@ -64,7 +65,7 @@ impl From<Run> for OverrideConfig {
port: run_config.port,
fastmode: false,
#[cfg(any(feature = "eth", feature = "coconut"))]
#[cfg(all(feature = "eth", not(feature = "coconut")))]
enabled_credentials_mode: run_config.enabled_credentials_mode,
#[cfg(all(feature = "eth", not(feature = "coconut")))]
+10 -1
View File
@@ -3,7 +3,7 @@
use crate::client::config::{Config, MISSING_VALUE};
use config::NymConfig;
use config::{defaults::default_api_endpoints, NymConfig};
use version_checker::Version;
use clap::Args;
@@ -104,6 +104,15 @@ fn minor_0_12_upgrade(
print_start_upgrade(&config_version, &to_version);
println!(
"Setting validator API endpoints to {:?}",
default_api_endpoints()
);
config
.get_base_mut()
.set_custom_validator_apis(default_api_endpoints());
config
.get_base_mut()
.set_custom_version(to_version.to_string().as_ref());
+5
View File
@@ -2,4 +2,9 @@
// SPDX-License-Identifier: Apache-2.0
pub mod client;
// This is only used as we reach into the init functions in nym-connect. We need to refactor the
// init functions so that nym-connect can just call the same init function as the regular socks5
// client.
#[allow(unused)]
pub mod commands;
pub mod socks;
+1 -2
View File
@@ -2,7 +2,6 @@
// SPDX-License-Identifier: Apache-2.0
use clap::{crate_version, Parser};
use network_defaults::setup_env;
pub mod client;
mod commands;
@@ -10,11 +9,11 @@ pub mod socks;
#[tokio::main]
async fn main() {
dotenv::dotenv().ok();
setup_logging();
println!("{}", banner());
let args = commands::Cli::parse();
setup_env(args.config_env_file.clone());
commands::execute(&args).await;
}
+3 -14
View File
@@ -5,7 +5,7 @@ use futures::StreamExt;
use log::*;
use nymsphinx::receiver::ReconstructedMessage;
use proxy_helpers::connection_controller::{ControllerCommand, ControllerSender};
use socks5_requests::Message;
use socks5_requests::Response;
pub(crate) struct MixnetResponseListener {
buffer_requester: ReceivedBufferRequestSender,
@@ -44,23 +44,12 @@ impl MixnetResponseListener {
warn!("this message had a surb - we didn't do anything with it");
}
let response = match Message::try_from_bytes(&raw_message) {
let response = match Response::try_from_bytes(&raw_message) {
Err(err) => {
warn!("failed to parse received response - {:?}", err);
return;
}
Ok(Message::Request(_)) => {
warn!("unexpected request");
return;
}
Ok(Message::Response(data)) => data,
Ok(Message::NetworkRequesterResponse(r)) => {
error!(
"Network requester failed on connection id {} with error: {}",
r.connection_id, r.network_requester_error
);
return;
}
Ok(data) => data,
};
self.controller_sender
+1 -1
View File
@@ -32,7 +32,7 @@ credentials = { path = "../../common/credentials", optional = true }
crypto = { path = "../../common/crypto" }
nymsphinx = { path = "../../common/nymsphinx" }
topology = { path = "../../common/topology" }
gateway-client = { path = "../../common/client-libs/gateway-client", default-features = false, features = ["wasm", "coconut"] }
gateway-client = { path = "../../common/client-libs/gateway-client", default-features = false, features = ["wasm"] }
validator-client = { path = "../../common/client-libs/validator-client", default-features = false }
wasm-utils = { path = "../../common/wasm-utils" }
+1 -1
View File
@@ -25,7 +25,7 @@ async function main() {
set_panic_hook();
// validator server we will use to get topology from
const validator = "https://validator.nymtech.net/api"; //"http://localhost:8081";
const validator = "https://sandbox-validator.nymtech.net/api"; //"http://localhost:8081";
client = new NymClient(validator);
+4 -1
View File
@@ -132,7 +132,9 @@ impl NymClient {
bandwidth_controller,
);
gateway_client.set_disabled_credentials_mode(disabled_credentials_mode);
if disabled_credentials_mode {
gateway_client.set_disabled_credentials_mode(true)
}
gateway_client
.authenticate_and_start()
@@ -197,6 +199,7 @@ impl NymClient {
// don't bother with acks etc. for time being
let prepared_fragment = message_preparer
.prepare_chunk_for_sending(message_chunk, topology, &self.ack_key, &recipient)
.await
.unwrap();
console_warn!("packet is going to have round trip time of {:?}, but we're not going to do anything for acks anyway ", prepared_fragment.total_delay);
+4 -4
View File
@@ -15,8 +15,8 @@ log = "0.4"
thiserror = "1.0"
url = "2.2"
rand = { version = "0.7.3", features = ["wasm-bindgen"] }
secp256k1 = { version = "0.20.3", optional = true }
web3 = { version = "0.17.0", default-features = false, optional = true }
secp256k1 = "0.20.3"
web3 = { version = "0.17.0", default-features = false }
async-trait = { version = "0.1.51" }
# internal
@@ -73,5 +73,5 @@ features = ["js"]
[features]
coconut = ["gateway-requests/coconut", "coconut-interface", "validator-client", "credentials/coconut"]
wasm = []
default = ["web3/default", "secp256k1"]
wasm = ["web3/wasm", "web3/http", "web3/signing"]
default = ["web3/default"]
@@ -23,7 +23,7 @@ use {
},
};
#[cfg(all(not(target_arch = "wasm32"), not(feature = "coconut")))]
#[cfg(not(feature = "coconut"))]
use {
credentials::token::bandwidth::TokenCredential,
crypto::asymmetric::identity,
@@ -45,7 +45,7 @@ use {
},
};
#[cfg(all(not(target_arch = "wasm32"), not(feature = "coconut")))]
#[cfg(not(feature = "coconut"))]
pub fn eth_contract(web3: Web3<Http>) -> Contract<Http> {
Contract::from_json(
web3.eth(),
@@ -58,7 +58,7 @@ pub fn eth_contract(web3: Web3<Http>) -> Contract<Http> {
.expect("Invalid json abi")
}
#[cfg(all(not(target_arch = "wasm32"), not(feature = "coconut")))]
#[cfg(not(feature = "coconut"))]
pub fn eth_erc20_contract(web3: Web3<Http>) -> Contract<Http> {
Contract::from_json(
web3.eth(),
@@ -76,11 +76,11 @@ pub struct BandwidthController<St: Storage> {
storage: St,
#[cfg(feature = "coconut")]
validator_endpoints: Vec<url::Url>,
#[cfg(all(not(target_arch = "wasm32"), not(feature = "coconut")))]
#[cfg(not(feature = "coconut"))]
contract: Contract<Http>,
#[cfg(all(not(target_arch = "wasm32"), not(feature = "coconut")))]
#[cfg(not(feature = "coconut"))]
erc20_contract: Contract<Http>,
#[cfg(all(not(target_arch = "wasm32"), not(feature = "coconut")))]
#[cfg(not(feature = "coconut"))]
eth_private_key: SecretKey,
}
@@ -96,7 +96,7 @@ where
}
}
#[cfg(all(not(target_arch = "wasm32"), not(feature = "coconut")))]
#[cfg(not(feature = "coconut"))]
pub fn new(
storage: St,
eth_endpoint: String,
@@ -120,7 +120,7 @@ where
})
}
#[cfg(all(not(target_arch = "wasm32"), not(feature = "coconut")))]
#[cfg(not(feature = "coconut"))]
async fn backup_keypair(&self, keypair: &identity::KeyPair) -> Result<(), GatewayClientError> {
self.storage
.insert_erc20_credential(
@@ -132,7 +132,7 @@ where
Ok(())
}
#[cfg(all(not(target_arch = "wasm32"), not(feature = "coconut")))]
#[cfg(not(feature = "coconut"))]
async fn restore_keypair(&self) -> Result<identity::KeyPair, GatewayClientError> {
let data = self.storage.get_next_erc20_credential().await?;
let public_key = identity::PublicKey::from_base58_string(data.public_key).unwrap();
@@ -141,7 +141,7 @@ where
Ok(identity::KeyPair::from_keys(private_key, public_key))
}
#[cfg(all(not(target_arch = "wasm32"), not(feature = "coconut")))]
#[cfg(not(feature = "coconut"))]
async fn mark_keypair_as_spent(
&self,
keypair: &identity::KeyPair,
@@ -180,7 +180,7 @@ where
)?)
}
#[cfg(all(not(target_arch = "wasm32"), not(feature = "coconut")))]
#[cfg(not(feature = "coconut"))]
pub async fn prepare_token_credential(
&self,
gateway_identity: identity::PublicKey,
@@ -219,7 +219,7 @@ where
))
}
#[cfg(all(not(target_arch = "wasm32"), not(feature = "coconut")))]
#[cfg(not(feature = "coconut"))]
pub async fn buy_token_credential(
&self,
verification_key: identity::PublicKey,
@@ -348,7 +348,7 @@ where
}
}
#[cfg(all(not(target_arch = "wasm32"), not(feature = "coconut")))]
#[cfg(not(feature = "coconut"))]
#[cfg(test)]
mod tests {
use network_defaults::ETH_EVENT_NAME;
@@ -162,10 +162,12 @@ impl PartiallyDelegated {
.expect("stream sender was somehow dropped without sending anything!");
if let Some(res) = receive_res {
let _res = res?;
panic!(
"This should have NEVER happened - returned a stream before receiving notification"
)
if let Err(err) = res {
// the receiver got an error. most likely a network one.
return Err(err);
} else {
panic!("This should have NEVER happened - returned a stream before receiving notification")
}
}
// this call failing is incredibly unlikely, but not impossible.
@@ -5,7 +5,8 @@ use crate::{validator_api, ValidatorClientError};
use mixnet_contract_common::{GatewayBond, IdentityKeyRef, MixNodeBond};
use url::Url;
use validator_api_requests::coconut::{
BlindSignRequestBody, BlindedSignatureResponse, CosmosAddressResponse, VerificationKeyResponse,
BlindSignRequestBody, BlindedSignatureResponse, CosmosAddressResponse,
ProposeReleaseFundsRequestBody, ProposeReleaseFundsResponse, VerificationKeyResponse,
VerifyCredentialBody, VerifyCredentialResponse,
};
use validator_api_requests::models::{
@@ -28,7 +29,7 @@ use mixnet_contract_common::{
RewardedSetUpdateDetails,
};
#[cfg(feature = "nymd-client")]
use network_defaults::NymNetworkDetails;
use network_defaults::{all::Network, NymNetworkDetails};
#[cfg(feature = "nymd-client")]
use std::collections::{HashMap, HashSet};
@@ -113,6 +114,9 @@ impl Config {
#[cfg(feature = "nymd-client")]
pub struct Client<C> {
// compatibility : (
pub network: Network,
// TODO: we really shouldn't be storing a mnemonic here, but removing it would be
// non-trivial amount of work and it's out of scope of the current branch
mnemonic: Option<bip39::Mnemonic>,
@@ -131,6 +135,9 @@ pub struct Client<C> {
impl Client<SigningNymdClient> {
pub fn new_signing(
config: Config,
// we need to provide network argument due to compatibility with other components (wallet...)
// that rely on its existence...
network: Network,
mnemonic: bip39::Mnemonic,
) -> Result<Client<SigningNymdClient>, ValidatorClientError> {
let validator_api_client = validator_api::Client::new(config.api_url.clone());
@@ -142,6 +149,7 @@ impl Client<SigningNymdClient> {
)?;
Ok(Client {
network,
mnemonic: Some(mnemonic),
mixnode_page_limit: config.mixnode_page_limit,
gateway_page_limit: config.gateway_page_limit,
@@ -169,12 +177,18 @@ impl Client<SigningNymdClient> {
#[cfg(feature = "nymd-client")]
impl Client<QueryNymdClient> {
pub fn new_query(config: Config) -> Result<Client<QueryNymdClient>, ValidatorClientError> {
pub fn new_query(
config: Config,
// we need to provide network argument due to compatibility with other components (wallet...)
// that rely on its existence...
network: Network,
) -> Result<Client<QueryNymdClient>, ValidatorClientError> {
let validator_api_client = validator_api::Client::new(config.api_url.clone());
let nymd_client =
NymdClient::connect(config.nymd_config.clone(), config.nymd_url.as_str())?;
Ok(Client {
network,
mnemonic: None,
mixnode_page_limit: config.mixnode_page_limit,
gateway_page_limit: config.gateway_page_limit,
@@ -733,4 +747,14 @@ impl ApiClient {
.verify_bandwidth_credential(request_body)
.await?)
}
pub async fn propose_release_funds(
&self,
request_body: &ProposeReleaseFundsRequestBody,
) -> Result<ProposeReleaseFundsResponse, ValidatorClientError> {
Ok(self
.validator_api
.propose_release_funds(request_body)
.await?)
}
}
@@ -24,7 +24,7 @@ use mixnet_contract_common::{
PagedMixDelegationsResponse, PagedMixnodeResponse, PagedRewardedSetResponse, QueryMsg,
RewardedSetUpdateDetails,
};
use serde::{Deserialize, Serialize};
use serde::Serialize;
use std::convert::TryInto;
use std::time::SystemTime;
use vesting_contract_common::ExecuteMsg as VestingExecuteMsg;
@@ -282,30 +282,6 @@ impl<C> NymdClient<C> {
self.simulated_gas_multiplier = multiplier;
}
pub async fn query_contract_smart<M, T>(
&self,
contract: &AccountId,
query_msg: &M,
) -> Result<T, NymdError>
where
C: CosmWasmClient + Sync,
M: ?Sized + Serialize + Sync,
for<'a> T: Deserialize<'a>,
{
self.client.query_contract_smart(contract, query_msg).await
}
pub async fn query_contract_raw(
&self,
contract: &AccountId,
query_data: Vec<u8>,
) -> Result<Vec<u8>, NymdError>
where
C: CosmWasmClient + Sync,
{
self.client.query_contract_raw(contract, query_data).await
}
pub fn wrap_contract_execute_message<M>(
&self,
contract_address: &AccountId,
@@ -917,7 +893,7 @@ impl<C> NymdClient<C> {
&self,
contract_address: &AccountId,
msg: &M,
fee: Option<Fee>,
fee: Fee,
memo: impl Into<String> + Send + 'static,
funds: Vec<Coin>,
) -> Result<ExecuteResult, NymdError>
@@ -925,7 +901,6 @@ impl<C> NymdClient<C> {
C: SigningCosmWasmClient + Sync,
M: ?Sized + Serialize + Sync,
{
let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier)));
self.client
.execute(self.address(), contract_address, msg, fee, memo, funds)
.await
@@ -935,7 +910,7 @@ impl<C> NymdClient<C> {
&self,
contract_address: &AccountId,
msgs: I,
fee: Option<Fee>,
fee: Fee,
memo: impl Into<String> + Send + 'static,
) -> Result<ExecuteResult, NymdError>
where
@@ -943,7 +918,6 @@ impl<C> NymdClient<C> {
I: IntoIterator<Item = (M, Vec<Coin>)> + Send,
M: Serialize,
{
let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier)));
self.client
.execute_multiple(self.address(), contract_address, msgs, fee, memo)
.await
@@ -1032,29 +1006,6 @@ impl<C> NymdClient<C> {
.await
}
#[execute("mixnet")]
fn _compound_reward(
&self,
operator: Option<String>,
delegator: Option<String>,
mix_identity: Option<IdentityKey>,
proxy: Option<String>,
fee: Option<Fee>,
) -> (ExecuteMsg, Option<Fee>)
where
C: SigningCosmWasmClient + Sync,
{
(
ExecuteMsg::CompoundReward {
operator,
delegator,
mix_identity,
proxy,
},
fee,
)
}
#[execute("mixnet")]
fn _compound_operator_reward(&self, fee: Option<Fee>) -> (ExecuteMsg, Option<Fee>)
where
@@ -1,33 +0,0 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::nymd::error::NymdError;
use crate::nymd::{CosmWasmClient, NymdClient};
use coconut_bandwidth_contract_common::msg::QueryMsg;
use coconut_bandwidth_contract_common::spend_credential::SpendCredentialResponse;
use async_trait::async_trait;
#[async_trait]
pub trait CoconutBandwidthQueryClient {
async fn get_spent_credential(
&self,
blinded_serial_number: String,
) -> Result<SpendCredentialResponse, NymdError>;
}
#[async_trait]
impl<C: CosmWasmClient + Sync + Send> CoconutBandwidthQueryClient for NymdClient<C> {
async fn get_spent_credential(
&self,
blinded_serial_number: String,
) -> Result<SpendCredentialResponse, NymdError> {
let request = QueryMsg::GetSpentCredential {
blinded_serial_number,
};
self.client
.query_contract_smart(self.coconut_bandwidth_contract_address(), &request)
.await
}
}
@@ -5,7 +5,6 @@ pub use crate::nymd::cosmwasm_client::signing_client::SigningCosmWasmClient;
use crate::nymd::cosmwasm_client::types::ExecuteResult;
use crate::nymd::error::NymdError;
use crate::nymd::{Coin, Fee, NymdClient};
use coconut_bandwidth_contract_common::spend_credential::SpendCredentialData;
use coconut_bandwidth_contract_common::{deposit::DepositData, msg::ExecuteMsg};
use async_trait::async_trait;
@@ -20,13 +19,6 @@ pub trait CoconutBandwidthSigningClient {
encryption_key: String,
fee: Option<Fee>,
) -> Result<ExecuteResult, NymdError>;
async fn spend_credential(
&self,
funds: Coin,
blinded_serial_number: String,
gateway_cosmos_address: String,
fee: Option<Fee>,
) -> Result<ExecuteResult, NymdError>;
}
#[async_trait]
@@ -54,30 +46,4 @@ impl<C: SigningCosmWasmClient + Sync + Send> CoconutBandwidthSigningClient for N
)
.await
}
async fn spend_credential(
&self,
funds: Coin,
blinded_serial_number: String,
gateway_cosmos_address: String,
fee: Option<Fee>,
) -> Result<ExecuteResult, NymdError> {
let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier)));
let req = ExecuteMsg::SpendCredential {
data: SpendCredentialData::new(
funds.into(),
blinded_serial_number,
gateway_cosmos_address,
),
};
self.client
.execute(
self.address(),
self.coconut_bandwidth_contract_address(),
&req,
fee,
"CoconutBandwidth::SpendCredential",
vec![],
)
.await
}
}
@@ -1,16 +1,14 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
mod coconut_bandwidth_query_client;
mod coconut_bandwidth_signing_client;
mod multisig_query_client;
mod multisig_signing_client;
mod vesting_query_client;
mod vesting_signing_client;
pub use coconut_bandwidth_query_client::CoconutBandwidthQueryClient;
pub use coconut_bandwidth_signing_client::CoconutBandwidthSigningClient;
pub use multisig_query_client::MultisigQueryClient;
pub use multisig_query_client::QueryClient;
pub use multisig_signing_client::MultisigSigningClient;
pub use vesting_query_client::VestingQueryClient;
pub use vesting_signing_client::VestingSigningClient;
@@ -9,12 +9,12 @@ use multisig_contract_common::msg::{ProposalResponse, QueryMsg};
use async_trait::async_trait;
#[async_trait]
pub trait MultisigQueryClient {
pub trait QueryClient {
async fn get_proposal(&self, proposal_id: u64) -> Result<ProposalResponse, NymdError>;
}
#[async_trait]
impl<C: CosmWasmClient + Sync + Send> MultisigQueryClient for NymdClient<C> {
impl<C: CosmWasmClient + Sync + Send> QueryClient for NymdClient<C> {
async fn get_proposal(&self, proposal_id: u64) -> Result<ProposalResponse, NymdError> {
let request = QueryMsg::Proposal { proposal_id };
self.client
@@ -12,6 +12,7 @@ use multisig_contract_common::msg::ExecuteMsg;
use async_trait::async_trait;
use cosmwasm_std::{to_binary, Coin, CosmosMsg, WasmMsg};
use cw3::Vote;
use network_defaults::DEFAULT_NETWORK;
#[async_trait]
pub trait MultisigSigningClient {
@@ -48,10 +49,7 @@ impl<C: SigningCosmWasmClient + Sync + Send> MultisigSigningClient for NymdClien
) -> Result<ExecuteResult, NymdError> {
let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier)));
let release_funds_req = CoconutBandwidthExecuteMsg::ReleaseFunds {
funds: Coin::new(
voucher_value,
self.config.chain_details.mix_denom.base.clone(),
),
funds: Coin::new(voucher_value, DEFAULT_NETWORK.mix_denom().base),
};
let release_funds_msg = CosmosMsg::Wasm(WasmMsg::Execute {
contract_addr: self.coconut_bandwidth_contract_address().to_string(),
@@ -7,11 +7,9 @@ use crate::nymd::error::NymdError;
use crate::nymd::NymdClient;
use async_trait::async_trait;
use cosmwasm_std::{Coin as CosmWasmCoin, Timestamp};
use mixnet_contract_common::IdentityKey;
use vesting_contract::vesting::Account;
use vesting_contract_common::{
messages::QueryMsg as VestingQueryMsg, AllDelegationsResponse, DelegationTimesResponse,
OriginalVestingResponse, Period, PledgeData, VestingDelegation,
messages::QueryMsg as VestingQueryMsg, OriginalVestingResponse, Period, PledgeData,
};
#[async_trait]
@@ -72,37 +70,6 @@ pub trait VestingQueryClient {
&self,
vesting_account_address: &str,
) -> Result<Period, NymdError>;
async fn get_delegation_timestamps(
&self,
address: &str,
mix_identity: String,
) -> Result<DelegationTimesResponse, NymdError>;
async fn get_all_vesting_delegations_paged(
&self,
start_after: Option<(u32, IdentityKey, u64)>,
limit: Option<u32>,
) -> Result<AllDelegationsResponse, NymdError>;
async fn get_all_vesting_delegations(&self) -> Result<Vec<VestingDelegation>, NymdError> {
let mut delegations = Vec::new();
let mut start_after = None;
loop {
let mut paged_response = self
.get_all_vesting_delegations_paged(start_after.take(), None)
.await?;
delegations.append(&mut paged_response.delegations);
if let Some(start_after_res) = paged_response.start_next_after {
start_after = Some(start_after_res)
} else {
break;
}
}
Ok(delegations)
}
}
#[async_trait]
@@ -265,29 +232,4 @@ impl<C: CosmWasmClient + Sync + Send> VestingQueryClient for NymdClient<C> {
.query_contract_smart(self.vesting_contract_address(), &request)
.await
}
async fn get_delegation_timestamps(
&self,
address: &str,
mix_identity: String,
) -> Result<DelegationTimesResponse, NymdError> {
let request = VestingQueryMsg::GetDelegationTimes {
address: address.to_string(),
mix_identity,
};
self.client
.query_contract_smart(self.vesting_contract_address(), &request)
.await
}
async fn get_all_vesting_delegations_paged(
&self,
start_after: Option<(u32, IdentityKey, u64)>,
limit: Option<u32>,
) -> Result<AllDelegationsResponse, NymdError> {
let request = VestingQueryMsg::GetAllDelegations { start_after, limit };
self.client
.query_contract_smart(self.vesting_contract_address(), &request)
.await
}
}
@@ -207,20 +207,35 @@ mod tests {
"acquire rebel spot skin gun such erupt pull swear must define ill chief turtle today flower chunk truth battle claw rigid detail gym feel",
"step income throw wheat mobile ship wave drink pool sudden upset jaguar bar globe rifle spice frost bless glimpse size regular carry aspect ball"
];
let prefix = MAINNET.bech32_prefix();
let addrs = vec![
"n1jw6mp7d5xqc7w6xm79lha27glmd0vdt3l9artf",
"n1h5hgn94nsq4kh99rjj794hr5h5q6yfm2lr52es",
"n17n9flp6jflljg6fp05dsy07wcprf2uuu8g40rf",
let prefixes = vec![
MAINNET.bech32_prefix(),
SANDBOX.bech32_prefix(),
QA.bech32_prefix(),
];
for (idx, mnemonic) in mnemonics.iter().enumerate() {
let wallet =
DirectSecp256k1HdWallet::from_mnemonic(&prefix, mnemonic.parse().unwrap()).unwrap();
assert_eq!(
wallet.try_derive_accounts().unwrap()[0].address,
addrs[idx].parse().unwrap()
)
for prefix in prefixes {
let addrs = match prefix.as_ref() {
"nymt" => vec![
"nymt1jw6mp7d5xqc7w6xm79lha27glmd0vdt339me94",
"nymt1h5hgn94nsq4kh99rjj794hr5h5q6yfm23rjshv",
"nymt17n9flp6jflljg6fp05dsy07wcprf2uuufgn4d4",
],
"n" => vec![
"n1jw6mp7d5xqc7w6xm79lha27glmd0vdt3l9artf",
"n1h5hgn94nsq4kh99rjj794hr5h5q6yfm2lr52es",
"n17n9flp6jflljg6fp05dsy07wcprf2uuu8g40rf",
],
_ => panic!("Test needs to be updated with new bech32 prefix"),
};
for (idx, mnemonic) in mnemonics.iter().enumerate() {
let wallet =
DirectSecp256k1HdWallet::from_mnemonic(&prefix, mnemonic.parse().unwrap())
.unwrap();
assert_eq!(
wallet.try_derive_accounts().unwrap()[0].address,
addrs[idx].parse().unwrap()
)
}
}
}
}
@@ -8,7 +8,8 @@ use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use url::Url;
use validator_api_requests::coconut::{
BlindSignRequestBody, BlindedSignatureResponse, CosmosAddressResponse, VerificationKeyResponse,
BlindSignRequestBody, BlindedSignatureResponse, CosmosAddressResponse,
ProposeReleaseFundsRequestBody, ProposeReleaseFundsResponse, VerificationKeyResponse,
VerifyCredentialBody, VerifyCredentialResponse,
};
use validator_api_requests::models::{
@@ -404,6 +405,23 @@ impl Client {
)
.await
}
pub async fn propose_release_funds(
&self,
request_body: &ProposeReleaseFundsRequestBody,
) -> Result<ProposeReleaseFundsResponse, ValidatorAPIError> {
self.post_validator_api(
&[
routes::API_VERSION,
routes::COCONUT_ROUTES,
routes::BANDWIDTH,
routes::COCONUT_PROPOSE_RELEASE_FUNDS,
],
NO_PARAMS,
request_body,
)
.await
}
}
// utility function that should solve the double slash problem in validator API forever.
@@ -19,6 +19,7 @@ pub const COCONUT_PARTIAL_BANDWIDTH_CREDENTIAL: &str = "partial-bandwidth-creden
pub const COCONUT_VERIFICATION_KEY: &str = "verification-key";
pub const COCONUT_COSMOS_ADDRESS: &str = "cosmos-address";
pub const COCONUT_VERIFY_BANDWIDTH_CREDENTIAL: &str = "verify-bandwidth-credential";
pub const COCONUT_PROPOSE_RELEASE_FUNDS: &str = "propose-release-funds";
pub const STATUS_ROUTES: &str = "status";
pub const MIXNODE: &str = "mixnode";
-35
View File
@@ -41,30 +41,6 @@ pub trait NymConfig: Default + Serialize + DeserializeOwned {
Self::default_config_directory(id).join(Self::config_file_name())
}
// We provide a second set of functions that tries to not panic.
fn try_default_root_directory() -> Option<PathBuf>;
fn try_default_config_directory(id: Option<&str>) -> Option<PathBuf> {
if let Some(id) = id {
Self::try_default_root_directory().map(|d| d.join(id).join("config"))
} else {
Self::try_default_root_directory().map(|d| d.join("config"))
}
}
fn try_default_data_directory(id: Option<&str>) -> Option<PathBuf> {
if let Some(id) = id {
Self::try_default_root_directory().map(|d| d.join(id).join("data"))
} else {
Self::try_default_root_directory().map(|d| d.join("data"))
}
}
fn try_default_config_file_path(id: Option<&str>) -> Option<PathBuf> {
Self::try_default_config_directory(id).map(|d| d.join(Self::config_file_name()))
}
fn root_directory(&self) -> PathBuf;
fn config_directory(&self) -> PathBuf;
fn data_directory(&self) -> PathBuf;
@@ -112,14 +88,3 @@ pub trait NymConfig: Default + Serialize + DeserializeOwned {
.map_err(|toml_err| io::Error::new(io::ErrorKind::Other, toml_err))
}
}
pub fn parse_validators(raw: &str) -> Vec<url::Url> {
raw.split(',')
.map(|raw_validator| {
raw_validator
.trim()
.parse()
.expect("one of the provided validator api urls is invalid")
})
.collect()
}
@@ -9,4 +9,3 @@ edition = "2021"
cosmwasm-std = "1.0.0"
schemars = "0.8"
serde = { version = "1.0.103", default-features = false, features = ["derive"] }
multisig-contract-common = { path = "../multisig-contract" }
@@ -1,4 +1,3 @@
pub mod deposit;
pub mod events;
pub mod msg;
pub mod spend_credential;
@@ -5,34 +5,24 @@ use cosmwasm_std::Coin;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use crate::{deposit::DepositData, spend_credential::SpendCredentialData};
use crate::deposit::DepositData;
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
pub struct InstantiateMsg {
pub multisig_addr: String,
pub pool_addr: String,
pub mix_denom: String,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum ExecuteMsg {
DepositFunds { data: DepositData },
SpendCredential { data: SpendCredentialData },
ReleaseFunds { funds: Coin },
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum QueryMsg {
GetSpentCredential {
blinded_serial_number: String,
},
GetAllSpentCredentials {
limit: Option<u32>,
start_after: Option<String>,
},
}
pub enum QueryMsg {}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
#[serde(rename_all = "snake_case")]
@@ -1,148 +0,0 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use cosmwasm_std::{from_binary, to_binary, Addr, Coin, CosmosMsg, StdResult, WasmMsg};
use multisig_contract_common::msg::ExecuteMsg as MultisigExecuteMsg;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use crate::msg::ExecuteMsg;
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
pub struct SpendCredentialData {
funds: Coin,
blinded_serial_number: String,
gateway_cosmos_address: String,
}
impl SpendCredentialData {
pub fn new(funds: Coin, blinded_serial_number: String, gateway_cosmos_address: String) -> Self {
SpendCredentialData {
funds,
blinded_serial_number,
gateway_cosmos_address,
}
}
pub fn funds(&self) -> &Coin {
&self.funds
}
pub fn blinded_serial_number(&self) -> &str {
&self.blinded_serial_number
}
pub fn gateway_cosmos_address(&self) -> &str {
&self.gateway_cosmos_address
}
}
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Eq, Serialize, JsonSchema)]
pub enum SpendCredentialStatus {
InProgress,
Spent,
}
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, JsonSchema)]
pub struct SpendCredential {
funds: Coin,
blinded_serial_number: String,
gateway_cosmos_address: Addr,
status: SpendCredentialStatus,
}
impl SpendCredential {
pub fn new(funds: Coin, blinded_serial_number: String, gateway_cosmos_address: Addr) -> Self {
SpendCredential {
funds,
blinded_serial_number,
gateway_cosmos_address,
status: SpendCredentialStatus::InProgress,
}
}
pub fn blinded_serial_number(&self) -> &str {
&self.blinded_serial_number
}
pub fn status(&self) -> SpendCredentialStatus {
self.status
}
pub fn mark_as_spent(&mut self) {
self.status = SpendCredentialStatus::Spent;
}
}
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, JsonSchema)]
pub struct PagedSpendCredentialResponse {
pub spend_credentials: Vec<SpendCredential>,
pub per_page: usize,
pub start_next_after: Option<String>,
}
impl PagedSpendCredentialResponse {
pub fn new(
spend_credentials: Vec<SpendCredential>,
per_page: usize,
start_next_after: Option<String>,
) -> Self {
PagedSpendCredentialResponse {
spend_credentials,
per_page,
start_next_after,
}
}
}
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, JsonSchema)]
pub struct SpendCredentialResponse {
pub spend_credential: Option<SpendCredential>,
}
impl SpendCredentialResponse {
pub fn new(spend_credential: Option<SpendCredential>) -> Self {
SpendCredentialResponse { spend_credential }
}
}
pub fn to_cosmos_msg(
funds: Coin,
blinded_serial_number: String,
coconut_bandwidth_addr: String,
multisig_addr: String,
) -> StdResult<CosmosMsg> {
let release_funds_req = ExecuteMsg::ReleaseFunds { funds };
let release_funds_msg = CosmosMsg::Wasm(WasmMsg::Execute {
contract_addr: coconut_bandwidth_addr,
msg: to_binary(&release_funds_req)?,
funds: vec![],
});
let req = MultisigExecuteMsg::Propose {
title: String::from("Release funds, as ordered by Coconut Bandwidth Contract"),
description: blinded_serial_number,
msgs: vec![release_funds_msg],
latest: None,
};
let msg = CosmosMsg::Wasm(WasmMsg::Execute {
contract_addr: multisig_addr,
msg: to_binary(&req)?,
funds: vec![],
});
Ok(msg)
}
pub fn funds_from_cosmos_msgs(msgs: Vec<CosmosMsg>) -> Option<Coin> {
if let Some(CosmosMsg::Wasm(WasmMsg::Execute {
contract_addr: _,
msg,
funds: _,
})) = msgs.get(0)
{
if let Ok(ExecuteMsg::ReleaseFunds { funds }) = from_binary::<ExecuteMsg>(msg) {
return Some(funds);
}
}
None
}
@@ -14,6 +14,7 @@ serde = { version = "1.0", features = ["derive"] }
serde_repr = "0.1"
schemars = "0.8"
thiserror = "1.0"
network-defaults = { path = "../../network-defaults" }
fixed = { version = "1.1", features = ["serde"] }
az = "1.1"
log = "0.4.14"
@@ -10,7 +10,6 @@ use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
pub struct InstantiateMsg {
pub rewarding_validator_address: String,
pub mixnet_denom: String,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
@@ -33,12 +32,6 @@ pub enum ExecuteMsg {
CompoundDelegatorReward {
mix_identity: IdentityKey,
},
CompoundReward {
operator: Option<String>,
delegator: Option<String>,
mix_identity: Option<IdentityKey>,
proxy: Option<String>,
},
BondMixnode {
mix_node: MixNode,
owner_signature: String,
@@ -122,7 +115,6 @@ pub enum ExecuteMsg {
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum QueryMsg {
GetBlacklistedNodes {},
GetCurrentOperatorCost {},
GetRewardingValidatorAddress {},
GetAllDelegationKeys {},
@@ -215,29 +207,4 @@ pub enum QueryMsg {
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub struct MigrateMsg {
pub mixnet_denom: String,
pub nodes_to_remove: Option<Vec<NodeToRemove>>,
}
impl MigrateMsg {
pub fn nodes_to_remove(&self) -> Vec<NodeToRemove> {
self.nodes_to_remove.clone().unwrap_or_default()
}
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
pub struct NodeToRemove {
owner: String,
proxy: Option<String>,
}
impl NodeToRemove {
pub fn owner(&self) -> &str {
&self.owner
}
pub fn proxy(&self) -> Option<&String> {
self.proxy.as_ref()
}
}
pub struct MigrateMsg {}
@@ -14,7 +14,6 @@ use cw_utils::{Duration, Expiration, Threshold};
pub struct InstantiateMsg {
// this is the group contract that contains the member list
pub group_addr: String,
pub coconut_bandwidth_contract_address: String,
pub threshold: Threshold,
pub max_voting_period: Duration,
}
@@ -78,8 +77,3 @@ pub enum QueryMsg {
limit: Option<u32>,
},
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub struct MigrateMsg {
pub coconut_bandwidth_address: String,
}
@@ -1,17 +1,17 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use cosmwasm_std::{Addr, Coin, Timestamp, Uint128};
use config::defaults::MIX_DENOM;
use cosmwasm_std::{Coin, Timestamp};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
pub use messages::{ExecuteMsg, InitMsg, MigrateMsg, QueryMsg};
use mixnet_contract_common::IdentityKey;
pub mod events;
pub mod messages;
pub fn one_ucoin(denom: String) -> Coin {
Coin::new(1, denom)
pub fn one_ucoin() -> Coin {
Coin::new(1, MIX_DENOM.base)
}
#[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))]
@@ -74,35 +74,3 @@ impl OriginalVestingResponse {
}
}
}
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Clone, JsonSchema)]
pub struct VestingDelegation {
pub account_id: u32,
pub mix_identity: IdentityKey,
pub block_timestamp: u64,
pub amount: Uint128,
}
impl VestingDelegation {
pub fn storage_key(&self) -> (u32, IdentityKey, u64) {
(
self.account_id,
self.mix_identity.clone(),
self.block_timestamp,
)
}
}
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Clone, JsonSchema)]
pub struct DelegationTimesResponse {
pub owner: Addr,
pub account_id: u32,
pub mix_identity: IdentityKey,
pub delegation_timestamps: Vec<u64>,
}
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Clone, JsonSchema)]
pub struct AllDelegationsResponse {
pub delegations: Vec<VestingDelegation>,
pub start_next_after: Option<(u32, IdentityKey, u64)>,
}
@@ -7,14 +7,11 @@ use serde::{Deserialize, Serialize};
#[serde(rename_all = "snake_case")]
pub struct InitMsg {
pub mixnet_contract_address: String,
pub mix_denom: String,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub struct MigrateMsg {
pub mix_denom: String,
}
pub struct MigrateMsg {}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema, Default)]
pub struct VestingSpecification {
@@ -170,12 +167,4 @@ pub enum QueryMsg {
address: String,
},
GetLockedPledgeCap {},
GetDelegationTimes {
address: String,
mix_identity: IdentityKey,
},
GetAllDelegations {
start_after: Option<(u32, IdentityKey, u64)>,
limit: Option<u32>,
},
}
+1
View File
@@ -14,6 +14,7 @@ url = "2.2"
# I guess temporarily until we get serde support in coconut up and running
coconut-interface = { path = "../coconut-interface" }
crypto = { path = "../crypto", features = ["rand", "asymmetric", "symmetric", "hashing"] }
network-defaults = { path = "../network-defaults" }
validator-api-requests = { path = "../../validator-api/validator-api-requests" }
validator-client = { path = "../client-libs/validator-client" }
+7 -11
View File
@@ -1,3 +1,4 @@
use config::defaults::DEFAULT_NETWORK;
use subtle_encoding::bech32;
#[derive(Debug, Clone, PartialEq, Eq)]
@@ -14,15 +15,16 @@ pub fn try_bech32_decode(address: &str) -> Result<String, Bech32Error> {
}
}
pub fn validate_bech32_prefix(bech32_prefix: &str, address: &str) -> Result<(), Bech32Error> {
pub fn validate_bech32_prefix(address: &str) -> Result<(), Bech32Error> {
let prefix = try_bech32_decode(address)?;
if prefix == bech32_prefix {
if prefix == DEFAULT_NETWORK.bech32_prefix() {
Ok(())
} else {
Err(Bech32Error::WrongPrefix(format!(
"your bech32 address prefix should be {}, not {}",
bech32_prefix, prefix
DEFAULT_NETWORK.bech32_prefix(),
prefix
)))
}
}
@@ -31,8 +33,6 @@ pub fn validate_bech32_prefix(bech32_prefix: &str, address: &str) -> Result<(),
mod tests {
use super::*;
const TEST_BECH32_PREFIX: &str = "n";
mod decoding_bech32_addresses {
use super::*;
@@ -71,12 +71,9 @@ mod tests {
assert_eq!(
Err(Bech32Error::WrongPrefix(format!(
"your bech32 address prefix should be {}, not punk",
TEST_BECH32_PREFIX
DEFAULT_NETWORK.bech32_prefix()
))),
validate_bech32_prefix(
TEST_BECH32_PREFIX,
"punk1h3w4nj7kny5dfyjw2le4vm74z03v9vd4dstpu0"
)
validate_bech32_prefix("punk1h3w4nj7kny5dfyjw2le4vm74z03v9vd4dstpu0")
)
}
@@ -85,7 +82,6 @@ mod tests {
assert_eq!(
Ok(()),
validate_bech32_prefix(
TEST_BECH32_PREFIX,
"n14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9sjyvg3g"
)
)
-11
View File
@@ -1,11 +0,0 @@
[package]
name = "inclusion-probability"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
log = "0.4.17"
rand = "0.8.5"
thiserror = "1.0.32"
-11
View File
@@ -1,11 +0,0 @@
#[derive(thiserror::Error, Debug)]
pub enum Error {
#[error("The list of cumulative stake was unexpectedly empty")]
EmptyListCumulStake,
#[error("Sample point was unexpectedly out of bounds")]
SamplePointOutOfBounds,
#[error("Norm computation failed on different size arrays")]
NormDifferenceSizeArrays,
#[error("Computed probabilities are fewer than input number of nodes")]
ResultsShorterThanInput,
}
-426
View File
@@ -1,426 +0,0 @@
//! Active set inclusion probability simulator
use std::time::{Duration, Instant};
use error::Error;
use rand::Rng;
mod error;
const TOLERANCE_L2_NORM: f64 = 1e-4;
const TOLERANCE_MAX_NORM: f64 = 1e-4;
pub struct SelectionProbability {
pub active_set_probability: Vec<f64>,
pub reserve_set_probability: Vec<f64>,
pub samples: u64,
pub time: Duration,
pub delta_l2: f64,
pub delta_max: f64,
}
pub fn simulate_selection_probability_mixnodes<R>(
list_stake_for_mixnodes: &[u128],
active_set_size: usize,
reserve_set_size: usize,
max_samples: u64,
max_time: Duration,
rng: &mut R,
) -> Result<SelectionProbability, Error>
where
R: Rng + ?Sized,
{
log::trace!("Simulating mixnode active set selection probability");
// In case the active set size is larger than the number of bonded mixnodes, they all have 100%
// chance we don't have to go through with the simulation
if list_stake_for_mixnodes.len() <= active_set_size {
return Ok(SelectionProbability {
active_set_probability: vec![1.0; list_stake_for_mixnodes.len()],
reserve_set_probability: vec![0.0; list_stake_for_mixnodes.len()],
samples: 0,
time: Duration::ZERO,
delta_l2: 0.0,
delta_max: 0.0,
});
}
// Total number of existing (registered) nodes
let num_mixnodes = list_stake_for_mixnodes.len();
// Cumulative stake ordered by node index
let list_cumul = cumul_sum(list_stake_for_mixnodes);
// The computed probabilities
let mut active_set_probability = vec![0.0; num_mixnodes];
let mut reserve_set_probability = vec![0.0; num_mixnodes];
// Number sufficiently large to have a good approximation of selection probability
let mut samples = 0;
let mut delta_l2;
let mut delta_max;
// Make sure we bound the time we allow it to run
let start_time = Instant::now();
loop {
samples += 1;
let mut sample_active_mixnodes = Vec::new();
let mut sample_reserve_mixnodes = Vec::new();
let mut list_cumul_temp = list_cumul.clone();
let active_set_probability_previous = active_set_probability.clone();
// Select the active nodes for the epoch (hour)
while sample_active_mixnodes.len() < active_set_size
&& sample_active_mixnodes.len() < list_cumul_temp.len()
{
let candidate = sample_candidate(&list_cumul_temp, rng)?;
if !sample_active_mixnodes.contains(&candidate) {
sample_active_mixnodes.push(candidate);
remove_mixnode_from_cumul_stake(candidate, &mut list_cumul_temp);
}
}
// Select the reserve nodes for the epoch (hour)
while sample_reserve_mixnodes.len() < reserve_set_size
&& sample_reserve_mixnodes.len() + sample_active_mixnodes.len() < list_cumul_temp.len()
{
let candidate = sample_candidate(&list_cumul_temp, rng)?;
if !sample_reserve_mixnodes.contains(&candidate)
&& !sample_active_mixnodes.contains(&candidate)
{
sample_reserve_mixnodes.push(candidate);
remove_mixnode_from_cumul_stake(candidate, &mut list_cumul_temp);
}
}
// Sum up nodes being in active or reserve set
for active_mixnodes in sample_active_mixnodes {
active_set_probability[active_mixnodes] += 1.0;
}
for reserve_mixnodes in sample_reserve_mixnodes {
reserve_set_probability[reserve_mixnodes] += 1.0;
}
// Convergence critera only on active set.
// We devide by samples to get the average, that is not really part of the delta
// computation.
delta_l2 =
l2_diff(&active_set_probability, &active_set_probability_previous)? / (samples as f64);
delta_max =
max_diff(&active_set_probability, &active_set_probability_previous)? / (samples as f64);
if samples > 10 && delta_l2 < TOLERANCE_L2_NORM && delta_max < TOLERANCE_MAX_NORM
|| samples >= max_samples
{
break;
}
// Stop if we run out of time
if start_time.elapsed() > max_time {
log::debug!("Simulation ran out of time, stopping");
break;
}
}
// Divide occurrences with the number of samples once we're done to get the probabilities.
active_set_probability
.iter_mut()
.for_each(|x| *x /= samples as f64);
reserve_set_probability
.iter_mut()
.for_each(|x| *x /= samples as f64);
// Some sanity checks of the output
if active_set_probability.len() != num_mixnodes || reserve_set_probability.len() != num_mixnodes
{
return Err(Error::ResultsShorterThanInput);
}
Ok(SelectionProbability {
active_set_probability,
reserve_set_probability,
samples,
time: start_time.elapsed(),
delta_l2,
delta_max,
})
}
// Compute the cumulative sum
fn cumul_sum<'a>(list: impl IntoIterator<Item = &'a u128>) -> Vec<u128> {
let mut list_cumul = Vec::new();
let mut cumul = 0;
for entry in list {
cumul += entry;
list_cumul.push(cumul);
}
list_cumul
}
fn sample_candidate<R>(list_cumul: &[u128], rng: &mut R) -> Result<usize, Error>
where
R: Rng + ?Sized,
{
use rand::distributions::{Distribution, Uniform};
let uniform = Uniform::from(0..*list_cumul.last().ok_or(Error::EmptyListCumulStake)?);
let r = uniform.sample(rng);
let candidate = list_cumul
.iter()
.enumerate()
.find(|(_, x)| *x >= &r)
.ok_or(Error::SamplePointOutOfBounds)?
.0;
Ok(candidate)
}
// Update list of cumulative stake to reflect eliminating the picked node
fn remove_mixnode_from_cumul_stake(candidate: usize, list_cumul_stake: &mut [u128]) {
let prob_candidate = if candidate == 0 {
list_cumul_stake[0]
} else {
list_cumul_stake[candidate] - list_cumul_stake[candidate - 1]
};
for cumul in list_cumul_stake.iter_mut().skip(candidate) {
*cumul -= prob_candidate;
}
}
// Compute the difference in l2-norm
fn l2_diff(v1: &[f64], v2: &[f64]) -> Result<f64, Error> {
if v1.len() != v2.len() {
return Err(Error::NormDifferenceSizeArrays);
}
Ok(v1
.iter()
.zip(v2)
.map(|(&i1, &i2)| (i1 - i2).powi(2))
.sum::<f64>()
.sqrt())
}
// Compute the difference in max-norm
fn max_diff(v1: &[f64], v2: &[f64]) -> Result<f64, Error> {
if v1.len() != v2.len() {
return Err(Error::NormDifferenceSizeArrays);
}
Ok(v1
.iter()
.zip(v2)
.map(|(x, y)| (x - y).abs())
.fold(f64::NEG_INFINITY, f64::max))
}
#[cfg(test)]
mod tests {
use rand::{rngs::StdRng, SeedableRng};
use super::*;
fn test_rng() -> StdRng {
StdRng::seed_from_u64(42)
}
#[test]
fn compute_cumul_sum() {
let v = cumul_sum(&vec![1, 2, 3]);
assert_eq!(v, &[1, 3, 6]);
}
#[test]
fn remove_mixnode_from_cumul() {
let mut cumul_stake = vec![1, 2, 3, 4, 5, 6];
remove_mixnode_from_cumul_stake(3, &mut cumul_stake);
assert_eq!(cumul_stake, &[1, 2, 3, 3, 4, 5]);
}
#[test]
fn max_norm() {
let v1 = vec![1.0, 2.0, 3.0];
let v2 = vec![2.0, 4.0, -6.0];
assert!((max_diff(&v1, &v2).unwrap() - 9.0).abs() < f64::EPSILON);
}
#[test]
fn ls_norm() {
let v1 = vec![1.0, 2.0, 3.0];
let v2 = vec![2.0, 3.0, -2.0];
assert!((l2_diff(&v1, &v2).unwrap() - 5.196_152_422_706_632).abs() < 1e2 * f64::EPSILON);
}
// Replicate the results from the Python simulation code in https://github.com/nymtech/team-core/issues/114
#[test]
fn replicate_python_simulation() {
let active_set_size = 4;
let standby_set_size = 1;
// this has to contain the total stake per node
let list_mix = vec![
100, 100, 3000, 500_000, 100, 10, 10, 10, 10, 10, 30000, 500, 200, 52345,
];
let max_samples = 100_000;
let max_time = Duration::from_secs(10);
let mut rng = test_rng();
let SelectionProbability {
active_set_probability,
reserve_set_probability,
samples,
time,
delta_l2,
delta_max,
} = simulate_selection_probability_mixnodes(
&list_mix,
active_set_size,
standby_set_size,
max_samples,
max_time,
&mut rng,
)
.unwrap();
// Check that any possible test failure wasn't because we ran it on 1970s hardware, and the
// sampling aborted prematurely due to hitting `max_time`.
assert!(time < max_time);
// These values comes from running the python simulator for a very long time
let expected_active_set_probability = vec![
0.025_070_8,
0.025_073_2,
0.744_117,
0.999_999,
0.025_000_2,
0.002_524_4,
0.002_527_8,
0.002_528_6,
0.002_569_6,
0.002_513_6,
0.994,
0.125_482_8,
0.050_279_8,
0.998_313_2,
];
// The same check is used in the convergence criterion, and hence should be reflected in
// `delta_max` too.
assert!(
max_diff(&active_set_probability, &expected_active_set_probability).unwrap() < 1e-2
);
let expected_reserve_set_probability = vec![
0.076_392_4,
0.076_499,
0.204_893_6,
1e-06,
0.076_278_8,
0.007_720_6,
0.007_673,
0.007_700_2,
0.007_669_4,
0.007_731_2,
0.005_789_4,
0.368_465_6,
0.151_537_2,
0.001_648_6,
];
assert!(
max_diff(&reserve_set_probability, &expected_reserve_set_probability).unwrap() < 1e-2
);
// We converge around 20_000, add another 500 for some slack due to random values
assert_eq!(samples, 20_001);
assert!(delta_l2 < TOLERANCE_L2_NORM);
assert!(delta_max < TOLERANCE_MAX_NORM);
}
#[test]
fn fewer_nodes_than_active_set_size() {
let active_set_size = 10;
let standby_set_size = 3;
let list_mix = vec![100, 100, 3000];
let max_samples = 100_000;
let max_time = Duration::from_secs(10);
let mut rng = test_rng();
let SelectionProbability {
active_set_probability,
reserve_set_probability,
samples,
time: _,
delta_l2,
delta_max,
} = simulate_selection_probability_mixnodes(
&list_mix,
active_set_size,
standby_set_size,
max_samples,
max_time,
&mut rng,
)
.unwrap();
// These values comes from running the python simulator for a very long time
let expected_active_set_probability = vec![1.0, 1.0, 1.0];
let expected_reserve_set_probability = vec![0.0, 0.0, 0.0];
assert!(
max_diff(&active_set_probability, &expected_active_set_probability).unwrap()
< 1e1 * f64::EPSILON
);
assert!(
max_diff(&reserve_set_probability, &expected_reserve_set_probability).unwrap()
< 1e1 * f64::EPSILON
);
// We converge around 20_000, add another 500 for some slack due to random values
assert_eq!(samples, 0);
assert!(delta_l2 < f64::EPSILON);
assert!(delta_max < f64::EPSILON);
}
#[test]
fn fewer_nodes_than_reward_set_size() {
let active_set_size = 4;
let standby_set_size = 3;
let list_mix = vec![100, 100, 3000, 342, 3_498_234];
let max_samples = 100_000_000;
let max_time = Duration::from_secs(10);
let mut rng = test_rng();
let SelectionProbability {
active_set_probability,
reserve_set_probability,
samples,
time: _,
delta_l2,
delta_max,
} = simulate_selection_probability_mixnodes(
&list_mix,
active_set_size,
standby_set_size,
max_samples,
max_time,
&mut rng,
)
.unwrap();
// These values comes from running the python simulator for a very long time
let expected_active_set_probability = vec![0.546, 0.538, 0.999, 0.915, 1.0];
let expected_reserve_set_probability = vec![0.453, 0.461, 0.0005, 0.084, 0.0];
assert!(
max_diff(&active_set_probability, &expected_active_set_probability).unwrap() < 1e-2,
);
assert!(
max_diff(&reserve_set_probability, &expected_reserve_set_probability).unwrap() < 1e-2,
);
// We converge around 20_000, add another 500 for some slack due to random values
assert_eq!(samples, 20_001);
assert!(delta_l2 < TOLERANCE_L2_NORM);
assert!(delta_max < TOLERANCE_MAX_NORM);
}
}
-1
View File
@@ -8,7 +8,6 @@ edition = "2021"
[dependencies]
cfg-if = "1.0.0"
dotenv = "0.15.0"
hex-literal = "0.3.3"
once_cell = "1.7.2"
serde = {version = "1.0", features = ["derive"]}
+11
View File
@@ -0,0 +1,11 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
fn main() {
match option_env!("NETWORK") {
None | Some("mainnet") => println!("cargo:rustc-cfg=network=\"mainnet\"",),
Some("sandbox") => println!("cargo:rustc-cfg=network=\"sandbox\"",),
Some("qa") => println!("cargo:rustc-cfg=network=\"qa\""),
_ => panic!("No such network"),
}
}
+61 -63
View File
@@ -3,7 +3,6 @@
use once_cell::sync::Lazy;
use serde::{Deserialize, Serialize};
use std::{env::var, path::PathBuf};
use url::Url;
pub mod all;
@@ -11,10 +10,36 @@ pub mod eth_contract;
pub mod mainnet;
pub mod qa;
pub mod sandbox;
pub mod var_names;
pub const ETH_CONTRACT_ADDRESS: [u8; 20] = mainnet::_ETH_CONTRACT_ADDRESS;
pub const ETH_ERC20_CONTRACT_ADDRESS: [u8; 20] = mainnet::_ETH_ERC20_CONTRACT_ADDRESS;
// The set of defaults that are decided at compile time. Ideally we want to reduce these to a
// minimum.
// Keep DENOM around mostly for use in contracts. (TODO: consider moving it there, or renaming?)
cfg_if::cfg_if! {
if #[cfg(network = "mainnet")] {
pub const DEFAULT_NETWORK: all::Network = all::Network::MAINNET;
pub const MIX_DENOM: DenomDetails = mainnet::MIX_DENOM;
pub const STAKE_DENOM: DenomDetails = mainnet::STAKE_DENOM;
pub const ETH_CONTRACT_ADDRESS: [u8; 20] = mainnet::_ETH_CONTRACT_ADDRESS;
pub const ETH_ERC20_CONTRACT_ADDRESS: [u8; 20] = mainnet::_ETH_ERC20_CONTRACT_ADDRESS;
} else if #[cfg(network = "qa")] {
pub const DEFAULT_NETWORK: all::Network = all::Network::QA;
pub const MIX_DENOM: DenomDetails = qa::MIX_DENOM;
pub const STAKE_DENOM: DenomDetails = qa::STAKE_DENOM;
pub const ETH_CONTRACT_ADDRESS: [u8; 20] = qa::_ETH_CONTRACT_ADDRESS;
pub const ETH_ERC20_CONTRACT_ADDRESS: [u8; 20] = qa::_ETH_ERC20_CONTRACT_ADDRESS;
} else if #[cfg(network = "sandbox")] {
pub const DEFAULT_NETWORK: all::Network = all::Network::SANDBOX;
pub const MIX_DENOM: DenomDetails = sandbox::MIX_DENOM;
pub const STAKE_DENOM: DenomDetails = sandbox::STAKE_DENOM;
pub const ETH_CONTRACT_ADDRESS: [u8; 20] = sandbox::_ETH_CONTRACT_ADDRESS;
pub const ETH_ERC20_CONTRACT_ADDRESS: [u8; 20] = sandbox::_ETH_ERC20_CONTRACT_ADDRESS;
}
}
#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub struct ChainDetails {
@@ -57,56 +82,23 @@ impl NymNetworkDetails {
NymNetworkDetails::default()
}
pub fn new_from_env() -> Self {
NymNetworkDetails::new()
.with_bech32_account_prefix(
var(var_names::BECH32_PREFIX).expect("bech32 prefix not set"),
)
.with_mix_denom(DenomDetailsOwned {
base: var(var_names::MIX_DENOM).expect("mix denomination base not set"),
display: var(var_names::MIX_DENOM_DISPLAY)
.expect("mix denomination display not set"),
display_exponent: var(var_names::DENOMS_EXPONENT)
.expect("denomination exponent not set")
.parse()
.expect("denomination exponent is not u32"),
})
.with_stake_denom(DenomDetailsOwned {
base: var(var_names::STAKE_DENOM).expect("stake denomination base not set"),
display: var(var_names::STAKE_DENOM_DISPLAY)
.expect("stake denomination display not set"),
display_exponent: var(var_names::DENOMS_EXPONENT)
.expect("denomination exponent not set")
.parse()
.expect("denomination exponent is not u32"),
})
.with_validator_endpoint(ValidatorDetails::new(
var(var_names::NYMD_VALIDATOR).expect("nymd validator not set"),
Some(var(var_names::API_VALIDATOR).expect("api validator not set")),
))
.with_mixnet_contract(Some(
var(var_names::MIXNET_CONTRACT_ADDRESS).expect("mixnet contract not set"),
))
.with_vesting_contract(Some(
var(var_names::VESTING_CONTRACT_ADDRESS).expect("vesting contract not set"),
))
.with_bandwidth_claim_contract(Some(
var(var_names::BANDWIDTH_CLAIM_CONTRACT_ADDRESS)
.expect("bandwidth claim contract not set"),
))
.with_coconut_bandwidth_contract(Some(
var(var_names::COCONUT_BANDWIDTH_CONTRACT_ADDRESS)
.expect("coconut bandwidth contract not set"),
))
.with_multisig_contract(Some(
var(var_names::MULTISIG_CONTRACT_ADDRESS).expect("multisig contract not set"),
))
pub fn new_qa() -> Self {
(&*QA_DEFAULTS).into()
}
pub fn new_sandbox() -> Self {
(&*SANDBOX_DEFAULTS).into()
}
pub fn new_mainnet() -> Self {
(&*MAINNET_DEFAULTS).into()
}
pub fn current_default() -> Self {
// backwards compatibility reasons
DEFAULT_NETWORK.details()
}
pub fn with_bech32_account_prefix<S: Into<String>>(mut self, prefix: S) -> Self {
self.chain_details.bech32_account_prefix = prefix.into();
self
@@ -341,21 +333,27 @@ impl ValidatorDetails {
}
}
pub fn setup_env(config_env_file: Option<PathBuf>) {
match std::env::var(var_names::CONFIGURED) {
// if the configuration is not already set in the env vars
Err(std::env::VarError::NotPresent) => {
if let Some(config_env_file) = config_env_file {
dotenv::from_path(config_env_file)
.expect("Invalid path to environment configuration file");
} else {
// if nothing is set, the use mainnet defaults
crate::mainnet::export_to_env();
}
}
Err(_) => crate::mainnet::export_to_env(),
_ => {}
}
pub fn default_statistics_service_url() -> Url {
DEFAULT_NETWORK
.statistics_service_url()
.parse()
.expect("the provided statistics service url is invalid!")
}
pub fn default_nymd_endpoints() -> Vec<Url> {
DEFAULT_NETWORK
.validators()
.iter()
.map(ValidatorDetails::nymd_url)
.collect()
}
pub fn default_api_endpoints() -> Vec<Url> {
DEFAULT_NETWORK
.validators()
.iter()
.filter_map(ValidatorDetails::api_url)
.collect()
}
// Name of the event triggered by the eth contract. If the event name is changed,
+5 -45
View File
@@ -1,7 +1,6 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::var_names;
use crate::{DenomDetails, ValidatorDetails};
pub(crate) const BECH32_PREFIX: &str = "n";
@@ -24,49 +23,10 @@ pub(crate) const _ETH_ERC20_CONTRACT_ADDRESS: [u8; 20] =
hex_literal::hex!("0000000000000000000000000000000000000000");
pub(crate) const REWARDING_VALIDATOR_ADDRESS: &str = "n10yyd98e2tuwu0f7ypz9dy3hhjw7v772q6287gy";
pub(crate) const STATISTICS_SERVICE_DOMAIN_ADDRESS: &str = "https://mainnet-stats.nymte.ch:8090/";
pub const NYMD_VALIDATOR: &str = "https://rpc.nyx.nodes.guru/";
pub const API_VALIDATOR: &str = "https://validator.nymtech.net/api/";
pub(crate) const STATISTICS_SERVICE_DOMAIN_ADDRESS: &str = "http://127.0.0.1:8090";
pub(crate) fn validators() -> Vec<ValidatorDetails> {
vec![ValidatorDetails::new(NYMD_VALIDATOR, Some(API_VALIDATOR))]
}
pub fn export_to_env() {
std::env::set_var(var_names::CONFIGURED, "true");
std::env::set_var(var_names::BECH32_PREFIX, BECH32_PREFIX);
std::env::set_var(var_names::MIX_DENOM, MIX_DENOM.base);
std::env::set_var(var_names::MIX_DENOM_DISPLAY, MIX_DENOM.display);
std::env::set_var(var_names::STAKE_DENOM, STAKE_DENOM.base);
std::env::set_var(var_names::STAKE_DENOM_DISPLAY, STAKE_DENOM.display);
std::env::set_var(
var_names::DENOMS_EXPONENT,
STAKE_DENOM.display_exponent.to_string(),
);
std::env::set_var(var_names::MIXNET_CONTRACT_ADDRESS, MIXNET_CONTRACT_ADDRESS);
std::env::set_var(
var_names::VESTING_CONTRACT_ADDRESS,
VESTING_CONTRACT_ADDRESS,
);
std::env::set_var(
var_names::BANDWIDTH_CLAIM_CONTRACT_ADDRESS,
BANDWIDTH_CLAIM_CONTRACT_ADDRESS,
);
std::env::set_var(
var_names::COCONUT_BANDWIDTH_CONTRACT_ADDRESS,
COCONUT_BANDWIDTH_CONTRACT_ADDRESS,
);
std::env::set_var(
var_names::MULTISIG_CONTRACT_ADDRESS,
MULTISIG_CONTRACT_ADDRESS,
);
std::env::set_var(
var_names::REWARDING_VALIDATOR_ADDRESS,
REWARDING_VALIDATOR_ADDRESS,
);
std::env::set_var(
var_names::STATISTICS_SERVICE_DOMAIN_ADDRESS,
STATISTICS_SERVICE_DOMAIN_ADDRESS,
);
std::env::set_var(var_names::NYMD_VALIDATOR, NYMD_VALIDATOR);
std::env::set_var(var_names::API_VALIDATOR, API_VALIDATOR);
vec![ValidatorDetails::new(
"https://rpc.nyx.nodes.guru/",
Some("https://validator.nymtech.net/api/"),
)]
}
-21
View File
@@ -1,21 +0,0 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
// Environment variable that, if set, shows the environment is currently configured
pub const CONFIGURED: &str = "CONFIGURED";
pub const BECH32_PREFIX: &str = "BECH32_PREFIX";
pub const MIX_DENOM: &str = "MIX_DENOM";
pub const MIX_DENOM_DISPLAY: &str = "MIX_DENOM_DISPLAY";
pub const STAKE_DENOM: &str = "STAKE_DENOM";
pub const STAKE_DENOM_DISPLAY: &str = "STAKE_DENOM_DISPLAY";
pub const DENOMS_EXPONENT: &str = "DENOMS_EXPONENT";
pub const MIXNET_CONTRACT_ADDRESS: &str = "MIXNET_CONTRACT_ADDRESS";
pub const VESTING_CONTRACT_ADDRESS: &str = "VESTING_CONTRACT_ADDRESS";
pub const BANDWIDTH_CLAIM_CONTRACT_ADDRESS: &str = "BANDWIDTH_CLAIM_CONTRACT_ADDRESS";
pub const COCONUT_BANDWIDTH_CONTRACT_ADDRESS: &str = "COCONUT_BANDWIDTH_CONTRACT_ADDRESS";
pub const MULTISIG_CONTRACT_ADDRESS: &str = "MULTISIG_CONTRACT_ADDRESS";
pub const REWARDING_VALIDATOR_ADDRESS: &str = "REWARDING_VALIDATOR_ADDRESS";
pub const STATISTICS_SERVICE_DOMAIN_ADDRESS: &str = "STATISTICS_SERVICE_DOMAIN_ADDRESS";
pub const NYMD_VALIDATOR: &str = "NYMD_VALIDATOR";
pub const API_VALIDATOR: &str = "API_VALIDATOR";
+1 -1
View File
@@ -42,7 +42,7 @@ pub enum CoconutError {
)]
DeserializationMinLength { min: usize, actual: usize },
#[error("Tried to deserialize {object} with bytes of invalid length. Expected {actual} < {object} or {modulus_target} % {modulus} == 0")]
#[error("Tried to deserialize {object} with bytes of invalid length. Expected {actual} < {} or {modulus_target} % {modulus} == 0")]
DeserializationInvalidLength {
actual: usize,
target: usize,
+2 -1
View File
@@ -34,7 +34,8 @@ mod error;
mod impls;
mod proofs;
mod scheme;
pub mod tests;
#[cfg(test)]
mod tests;
mod traits;
mod utils;
+63 -3
View File
@@ -1,13 +1,23 @@
use crate::{
aggregate_verification_keys, setup, tests::helpers::theta_from_keys_and_attributes, ttp_keygen,
verify_credential, CoconutError, VerificationKey,
aggregate_signature_shares, aggregate_verification_keys, blind_sign, prepare_blind_sign,
prove_bandwidth_credential, setup, ttp_keygen, verify_credential, CoconutError, Signature,
SignatureShare, VerificationKey,
};
use itertools::izip;
#[test]
fn main() -> Result<(), CoconutError> {
let params = setup(5)?;
let public_attributes = params.n_random_scalars(2);
let serial_number = params.random_scalar();
let binding_number = params.random_scalar();
let private_attributes = vec![serial_number, binding_number];
// generate commitment
let (commitments_openings, blind_sign_request) =
prepare_blind_sign(&params, &private_attributes, &public_attributes)?;
// generate_keys
let coconut_keypairs = ttp_keygen(&params, 2, 3)?;
@@ -20,8 +30,58 @@ fn main() -> Result<(), CoconutError> {
// aggregate verification keys
let verification_key = aggregate_verification_keys(&verification_keys, Some(&[1, 2, 3]))?;
// generate blinded signatures
let mut blinded_signatures = Vec::new();
for keypair in coconut_keypairs {
let blinded_signature = blind_sign(
&params,
&keypair.secret_key(),
&blind_sign_request,
&public_attributes,
)?;
blinded_signatures.push(blinded_signature)
}
// Unblind
let unblinded_signatures: Vec<Signature> =
izip!(blinded_signatures.iter(), verification_keys.iter())
.map(|(s, vk)| {
s.unblind(
&params,
vk,
&private_attributes,
&public_attributes,
&blind_sign_request.get_commitment_hash(),
&commitments_openings,
)
.unwrap()
})
.collect();
// Aggregate signatures
let signature_shares: Vec<SignatureShare> = unblinded_signatures
.iter()
.enumerate()
.map(|(idx, signature)| SignatureShare::new(*signature, (idx + 1) as u64))
.collect();
let mut attributes = Vec::with_capacity(private_attributes.len() + public_attributes.len());
attributes.extend_from_slice(&private_attributes);
attributes.extend_from_slice(&public_attributes);
// Randomize credentials and generate any cryptographic material to verify them
let signature =
aggregate_signature_shares(&params, &verification_key, &attributes, &signature_shares)?;
// Generate cryptographic material to verify them
let theta = theta_from_keys_and_attributes(&params, &coconut_keypairs, &public_attributes)?;
let theta = prove_bandwidth_credential(
&params,
&verification_key,
&signature,
serial_number,
binding_number,
)?;
// Verify credentials
assert!(verify_credential(
-87
View File
@@ -1,87 +0,0 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::*;
use itertools::izip;
pub fn theta_from_keys_and_attributes(
params: &Parameters,
coconut_keypairs: &Vec<KeyPair>,
public_attributes: &Vec<PublicAttribute>,
) -> Result<Theta, CoconutError> {
let serial_number = params.random_scalar();
let binding_number = params.random_scalar();
let private_attributes = vec![serial_number, binding_number];
// generate commitment
let (commitments_openings, blind_sign_request) =
prepare_blind_sign(params, &private_attributes, public_attributes)?;
let verification_keys: Vec<VerificationKey> = coconut_keypairs
.iter()
.map(|keypair| keypair.verification_key())
.collect();
// aggregate verification keys
let indices: Vec<u64> = coconut_keypairs
.iter()
.enumerate()
.map(|(idx, _)| (idx + 1) as u64)
.collect();
let verification_key = aggregate_verification_keys(&verification_keys, Some(&indices))?;
// generate blinded signatures
let mut blinded_signatures = Vec::new();
for keypair in coconut_keypairs {
let blinded_signature = blind_sign(
params,
&keypair.secret_key(),
&blind_sign_request,
public_attributes,
)?;
blinded_signatures.push(blinded_signature)
}
// Unblind
let unblinded_signatures: Vec<Signature> =
izip!(blinded_signatures.iter(), verification_keys.iter())
.map(|(s, vk)| {
s.unblind(
params,
vk,
&private_attributes,
public_attributes,
&blind_sign_request.get_commitment_hash(),
&commitments_openings,
)
.unwrap()
})
.collect();
// Aggregate signatures
let signature_shares: Vec<SignatureShare> = unblinded_signatures
.iter()
.enumerate()
.map(|(idx, signature)| SignatureShare::new(*signature, (idx + 1) as u64))
.collect();
let mut attributes = Vec::with_capacity(private_attributes.len() + public_attributes.len());
attributes.extend_from_slice(&private_attributes);
attributes.extend_from_slice(public_attributes);
// Randomize credentials and generate any cryptographic material to verify them
let signature =
aggregate_signature_shares(params, &verification_key, &attributes, &signature_shares)?;
// Generate cryptographic material to verify them
let theta = prove_bandwidth_credential(
params,
&verification_key,
&signature,
serial_number,
binding_number,
)?;
Ok(theta)
}
-2
View File
@@ -1,3 +1 @@
#[cfg(test)]
mod e2e;
pub mod helpers;
+6 -4
View File
@@ -213,7 +213,7 @@ where
/// - compute vk_b = g^x || v_b
/// - compute sphinx_plaintext = SURB_ACK || g^x || v_b
/// - compute sphinx_packet = Sphinx(recipient, sphinx_plaintext)
pub fn prepare_chunk_for_sending(
pub async fn prepare_chunk_for_sending(
&mut self,
fragment: Fragment,
topology: &NymTopology,
@@ -222,7 +222,8 @@ where
) -> Result<PreparedFragment, NymTopologyError> {
// create an ack
let (ack_delay, surb_ack_bytes) = self
.generate_surb_ack(fragment.fragment_identifier(), topology, ack_key)?
.generate_surb_ack(fragment.fragment_identifier(), topology, ack_key)
.await?
.prepare_for_sending();
// TODO:
@@ -293,7 +294,7 @@ where
}
/// Construct an acknowledgement SURB for the given [`FragmentIdentifier`]
fn generate_surb_ack(
async fn generate_surb_ack(
&mut self,
fragment_id: FragmentIdentifier,
topology: &NymTopology,
@@ -356,7 +357,8 @@ where
// gateways could not distinguish reply packets from normal messages due to lack of said acks
// note: the ack delay is irrelevant since we do not know the delay of actual surb
let (_, surb_ack_bytes) = self
.generate_surb_ack(reply_id, topology, ack_key)?
.generate_surb_ack(reply_id, topology, ack_key)
.await?
.prepare_for_sending();
let zero_pad_len = self.packet_size.plaintext_size()
-1
View File
@@ -9,4 +9,3 @@ edition = "2021"
[dependencies]
nymsphinx-addressing = { path = "../../../common/nymsphinx/addressing" }
ordered-buffer = {path = "../ordered-buffer"}
thiserror = "1"
-5
View File
@@ -1,12 +1,7 @@
// Copyright 2020-2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
pub mod msg;
pub mod network_requester_response;
pub mod request;
pub mod response;
pub use msg::*;
pub use network_requester_response::*;
pub use request::*;
pub use response::*;
+13 -26
View File
@@ -1,40 +1,36 @@
// Copyright 2020-2022 - Nym Technologies SA <contact@nymtech.net>
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use thiserror::Error;
use crate::network_requester_response::{Error as NrError, NetworkRequesterResponse};
use crate::request::{Request, RequestError};
use crate::response::{Response, ResponseError};
#[derive(Debug, Error)]
#[derive(Debug)]
pub enum MessageError {
#[error("{0}")]
Request(RequestError),
#[error("{0:?}")]
Response(ResponseError),
#[error("{0}")]
NetworkRequesterResponseError(NrError),
#[error("no data")]
NoData,
#[error("unknown message type received")]
UnknownMessageType,
}
impl std::fmt::Display for MessageError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
MessageError::Request(r) => write!(f, "{}", r),
MessageError::Response(r) => write!(f, "{:?}", r),
MessageError::NoData => write!(f, "no data provided"),
MessageError::UnknownMessageType => write!(f, "unknown message type received"),
}
}
}
pub enum Message {
Request(Request),
Response(Response),
NetworkRequesterResponse(NetworkRequesterResponse),
}
impl Message {
const REQUEST_FLAG: u8 = 0;
const RESPONSE_FLAG: u8 = 1;
const NR_RESPONSE_FLAG: u8 = 2;
pub fn conn_id(&self) -> u64 {
match self {
@@ -43,7 +39,6 @@ impl Message {
Request::Send(conn_id, _, _) => *conn_id,
},
Message::Response(resp) => resp.connection_id,
Message::NetworkRequesterResponse(resp) => resp.connection_id,
}
}
@@ -54,7 +49,6 @@ impl Message {
Request::Send(_, data, _) => data.len(),
},
Message::Response(resp) => resp.data.len(),
Message::NetworkRequesterResponse(_) => 0,
}
}
@@ -71,10 +65,6 @@ impl Message {
Response::try_from_bytes(&b[1..])
.map(Message::Response)
.map_err(MessageError::Response)
} else if b[0] == Self::NR_RESPONSE_FLAG {
NetworkRequesterResponse::try_from_bytes(&b[1..])
.map(Message::NetworkRequesterResponse)
.map_err(MessageError::NetworkRequesterResponseError)
} else {
Err(MessageError::UnknownMessageType)
}
@@ -88,9 +78,6 @@ impl Message {
Self::Response(r) => std::iter::once(Self::RESPONSE_FLAG)
.chain(r.into_bytes().iter().cloned())
.collect(),
Self::NetworkRequesterResponse(r) => std::iter::once(Self::NR_RESPONSE_FLAG)
.chain(r.into_bytes().iter().cloned())
.collect(),
}
}
}
@@ -1,112 +0,0 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::ConnectionId;
#[derive(Debug)]
pub struct NetworkRequesterResponse {
pub connection_id: ConnectionId,
pub network_requester_error: String,
}
#[derive(Debug, thiserror::Error, PartialEq, Eq)]
pub enum Error {
#[error("no data provided")]
NoData,
#[error("not enough bytes to recover the connection id")]
ConnectionIdTooShort,
#[error("message is not utf8 encoded")]
MalformedErrorMessage(#[from] std::string::FromUtf8Error),
}
impl NetworkRequesterResponse {
pub fn new(connection_id: ConnectionId, network_requester_error: String) -> Self {
NetworkRequesterResponse {
connection_id,
network_requester_error,
}
}
pub fn try_from_bytes(b: &[u8]) -> Result<NetworkRequesterResponse, Error> {
if b.is_empty() {
return Err(Error::NoData);
}
if b.len() < 8 {
return Err(Error::ConnectionIdTooShort);
}
let mut connection_id_bytes = b.to_vec();
let network_requester_error_bytes = connection_id_bytes.split_off(8);
let connection_id = u64::from_be_bytes([
connection_id_bytes[0],
connection_id_bytes[1],
connection_id_bytes[2],
connection_id_bytes[3],
connection_id_bytes[4],
connection_id_bytes[5],
connection_id_bytes[6],
connection_id_bytes[7],
]);
let network_requester_error = String::from_utf8(network_requester_error_bytes)?;
Ok(NetworkRequesterResponse {
connection_id,
network_requester_error,
})
}
pub fn into_bytes(self) -> Vec<u8> {
self.connection_id
.to_be_bytes()
.iter()
.cloned()
.chain(self.network_requester_error.into_bytes().into_iter())
.collect()
}
}
#[cfg(test)]
mod network_requester_response_serde_tests {
use super::*;
#[test]
fn simple_serde() {
let conn_id = 42;
let network_requester_error = String::from("This is a test msg");
let response = NetworkRequesterResponse::new(conn_id, network_requester_error.clone());
let bytes = response.into_bytes();
let deserialized_response = NetworkRequesterResponse::try_from_bytes(&bytes).unwrap();
assert_eq!(conn_id, deserialized_response.connection_id);
assert_eq!(
network_requester_error,
deserialized_response.network_requester_error
);
}
#[test]
fn deserialization_errors() {
let err = NetworkRequesterResponse::try_from_bytes(&[]).err().unwrap();
assert_eq!(err, Error::NoData);
let bytes: [u8; 5] = [1, 2, 3, 4, 5];
let err = NetworkRequesterResponse::try_from_bytes(&bytes)
.err()
.unwrap();
assert_eq!(err, Error::ConnectionIdTooShort);
let bytes: Vec<u8> = 42u64
.to_be_bytes()
.into_iter()
.chain([0, 159, 146, 150].into_iter())
.collect();
let err = NetworkRequesterResponse::try_from_bytes(&bytes)
.err()
.unwrap();
assert!(matches!(err, Error::MalformedErrorMessage(_)));
}
}
+24 -18
View File
@@ -1,9 +1,6 @@
// Copyright 2020-2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use nymsphinx_addressing::clients::{Recipient, RecipientFormattingError};
use std::convert::TryFrom;
use thiserror::Error;
use std::fmt::{self};
pub type ConnectionId = u64;
pub type RemoteAddress = String;
@@ -15,30 +12,39 @@ pub enum RequestFlag {
Send = 1,
}
#[derive(Debug, Error)]
#[derive(Debug)]
pub enum RequestError {
#[error("not enough bytes to recover the length of the address")]
AddressLengthTooShort,
#[error("not enough bytes to recover the address")]
AddressTooShort,
#[error("not enough bytes to recover the connection id")]
ConnectionIdTooShort,
#[error("no data provided")]
NoData,
#[error("request of unknown type")]
UnknownRequestFlag,
#[error("too short return address")]
ReturnAddressTooShort,
#[error("malformed return address - {0}")]
MalformedReturnAddress(RecipientFormattingError),
}
impl fmt::Display for RequestError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> fmt::Result {
match self {
RequestError::AddressLengthTooShort => {
write!(f, "not enough bytes to recover the length of the address")
}
RequestError::AddressTooShort => write!(f, "not enough bytes to recover the address"),
RequestError::ConnectionIdTooShort => {
write!(f, "not enough bytes to recover the connection id")
}
RequestError::NoData => write!(f, "no data provided"),
RequestError::UnknownRequestFlag => write!(f, "request of unknown type"),
RequestError::ReturnAddressTooShort => write!(f, "too short return address"),
RequestError::MalformedReturnAddress(recipient_err) => {
write!(f, "malformed return address - {}", recipient_err)
}
}
}
}
impl std::error::Error for RequestError {}
impl RequestError {
pub fn is_malformed_return(&self) -> bool {
matches!(self, RequestError::MalformedReturnAddress(_))
+1 -8
View File
@@ -1,15 +1,8 @@
// Copyright 2020-2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use thiserror::Error;
use crate::ConnectionId;
#[derive(Debug, Error, PartialEq, Eq)]
#[derive(Debug, PartialEq, Eq)]
pub enum ResponseError {
#[error("not enough bytes to recover the connection id")]
ConnectionIdTooShort,
#[error("no data provided")]
NoData,
}
/// A remote network response retrieved by the Socks5 service provider. This
+2
View File
@@ -17,3 +17,5 @@ serde_json = "1"
sqlx = { version = "0.5", features = ["runtime-tokio-rustls", "chrono"]}
thiserror = "1"
tokio = { version = "1.19.1", features = [ "time" ] }
network-defaults = { path = "../network-defaults" }
+2 -6
View File
@@ -34,16 +34,12 @@ pub enum StatsData {
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct StatsGatewayData {
pub gateway_id: String,
pub inbox_count: u32,
}
impl StatsGatewayData {
pub fn new(gateway_id: String, inbox_count: u32) -> Self {
StatsGatewayData {
gateway_id,
inbox_count,
}
pub fn new(inbox_count: u32) -> Self {
StatsGatewayData { inbox_count }
}
}
+2 -11
View File
@@ -5,14 +5,13 @@ use std::time::Duration;
use tokio::sync::watch::{self, error::SendError};
const DEFAULT_SHUTDOWN_TIMER_SECS: u64 = 5;
const SHUTDOWN_TIMER_SECS: u64 = 5;
/// Used to notify other tasks to gracefully shutdown
#[derive(Debug)]
pub struct ShutdownNotifier {
notify_tx: watch::Sender<()>,
notify_rx: Option<watch::Receiver<()>>,
shutdown_timer_secs: u64,
}
impl Default for ShutdownNotifier {
@@ -21,19 +20,11 @@ impl Default for ShutdownNotifier {
Self {
notify_tx,
notify_rx: Some(notify_rx),
shutdown_timer_secs: DEFAULT_SHUTDOWN_TIMER_SECS,
}
}
}
impl ShutdownNotifier {
pub fn new(shutdown_timer_secs: u64) -> Self {
Self {
shutdown_timer_secs,
..Default::default()
}
}
pub fn subscribe(&self) -> ShutdownListener {
ShutdownListener::new(
self.notify_rx
@@ -59,7 +50,7 @@ impl ShutdownNotifier {
_ = tokio::signal::ctrl_c() => {
log::info!("Forcing shutdown");
}
_ = tokio::time::sleep(Duration::from_secs(self.shutdown_timer_secs)) => {
_ = tokio::time::sleep(Duration::from_secs(SHUTDOWN_TIMER_SECS)) => {
log::info!("Timout reached, forcing shutdown");
},
}
+1 -1
View File
@@ -507,7 +507,7 @@ mod test {
for (expected, raw_display) in values {
let coin = DecCoin {
denom: Network::MAINNET.mix_denom().display,
denom: Network::MAINNET.mix_denom().display.into(),
amount: raw_display.parse().unwrap(),
};
let base = reg.attempt_convert_to_base_coin(coin).unwrap();
-51
View File
@@ -1,51 +0,0 @@
## Unreleased
### Added
- vesting-contract: added queries for delegation timestamps and paged query for all vesting delegations in the contract ([#1569])
### Changed
- mixnet-contract: compounding delegator rewards now happens instantaneously as opposed to having to wait for the current epoch to finish ([#1571])
### Fixed
- vesting-contract: the contract now correctly stores delegations with their timestamp as opposed to using block height ([#1544])
- mixnet-contract: compounding delegator rewards is now possible even if the associated mixnode had already unbonded ([#1571])
[#1544]: https://github.com/nymtech/nym/pull/1544
[#1569]: https://github.com/nymtech/nym/pull/1569
[#1569]: https://github.com/nymtech/nym/pull/1571
## [nym-contracts-v1.0.1](https://github.com/nymtech/nym/tree/nym-contracts-v1.0.1) (2022-06-22)
### Added
- mixnet-contract: Added ClaimOperatorReward and ClaimDelegatorReward messages ([#1292])
- mixnet-contract: Replace all naked `-` with `saturating_sub`.
- mixnet-contract: Added staking_supply field to ContractStateParams.
- mixnet-contract: Added a query to get MixnodeBond by identity key ([#1369]).
- mixnet-contract: Added a query to get GatewayBond by identity key ([#1369]).
- vesting-contract: Added ClaimOperatorReward and ClaimDelegatorReward messages ([#1292])
- vesting-contract: Added limit to the amount of tokens one can pledge ([#1331])
### Fixed
- mixnet-contract: `estimated_delegator_reward` calculation ([#1284])
- mixnet-contract: delegator and operator rewards use lambda and sigma instead of lambda_ticked and sigma_ticked ([#1284])
- mixnet-contract: removed `expect` in `query_delegator_reward` and queries containing invalid proxy address should now return a more human-readable error ([#1257])
- mixnet-contract: replaced integer division with fixed for performance calculations ([#1284])
- mixnet-contract: Under certain circumstances nodes could not be unbonded ([#1255](https://github.com/nymtech/nym/issues/1255)) ([#1258])
- mixnet-contract: Using correct staking supply when distributing rewards. ([#1373])
- vesting-contract: replaced `checked_sub` with `saturating_sub` to fix the underflow in `get_vesting_tokens` ([#1275])
[#1255]: https://github.com/nymtech/nym/pull/1255
[#1257]: https://github.com/nymtech/nym/pull/1257
[#1258]: https://github.com/nymtech/nym/pull/1258
[#1275]: https://github.com/nymtech/nym/pull/1275
[#1284]: https://github.com/nymtech/nym/pull/1284
[#1292]: https://github.com/nymtech/nym/pull/1292
[#1331]: https://github.com/nymtech/nym/pull/1331
[#1369]: https://github.com/nymtech/nym/pull/1369
[#1373]: https://github.com/nymtech/nym/pull/1373
+9 -34
View File
@@ -50,6 +50,7 @@ name = "bandwidth-claim"
version = "1.0.0"
dependencies = [
"bandwidth-claim-contract",
"config",
"cosmwasm-std",
"cosmwasm-storage",
"schemars",
@@ -220,11 +221,12 @@ version = "0.1.0"
dependencies = [
"bandwidth-claim-contract",
"coconut-bandwidth-contract-common",
"config",
"cosmwasm-std",
"cosmwasm-storage",
"cw-controllers",
"cw-multi-test",
"cw-storage-plus",
"multisig-contract-common",
"schemars",
"serde",
"thiserror",
@@ -235,32 +237,10 @@ name = "coconut-bandwidth-contract-common"
version = "0.1.0"
dependencies = [
"cosmwasm-std",
"multisig-contract-common",
"schemars",
"serde",
]
[[package]]
name = "coconut-test"
version = "0.1.0"
dependencies = [
"bandwidth-claim-contract",
"coconut-bandwidth",
"coconut-bandwidth-contract-common",
"cosmwasm-std",
"cosmwasm-storage",
"cw-controllers",
"cw-multi-test",
"cw-storage-plus",
"cw-utils",
"cw3-flex-multisig",
"cw4-group",
"multisig-contract-common",
"schemars",
"serde",
"thiserror",
]
[[package]]
name = "config"
version = "0.1.0"
@@ -612,12 +592,6 @@ dependencies = [
"generic-array 0.14.5",
]
[[package]]
name = "dotenv"
version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f"
[[package]]
name = "dyn-clone"
version = "1.0.4"
@@ -1082,6 +1056,7 @@ dependencies = [
"cosmwasm-std",
"fixed",
"log",
"network-defaults",
"schemars",
"serde",
"serde_repr",
@@ -1107,7 +1082,6 @@ name = "network-defaults"
version = "0.1.0"
dependencies = [
"cfg-if",
"dotenv",
"hex-literal",
"once_cell",
"serde",
@@ -1392,18 +1366,18 @@ dependencies = [
[[package]]
name = "regex"
version = "1.6.0"
version = "1.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b"
checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461"
dependencies = [
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.6.27"
version = "0.6.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244"
checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
[[package]]
name = "rfc6979"
@@ -1854,6 +1828,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
name = "vesting-contract"
version = "1.0.1"
dependencies = [
"config",
"cosmwasm-std",
"cw-storage-plus",
"mixnet-contract-common",
+1 -1
View File
@@ -1,5 +1,5 @@
[workspace]
members = ["bandwidth-claim", "coconut-bandwidth", "mixnet", "vesting", "multisig/cw3-flex-multisig", "multisig/cw4-group", "coconut-test"]
members = ["bandwidth-claim", "coconut-bandwidth", "mixnet", "vesting", "multisig/cw3-flex-multisig", "multisig/cw4-group"]
[profile.release]
opt-level = 3
+2
View File
@@ -9,6 +9,8 @@ edition = "2021"
crate-type = ["cdylib", "rlib"]
[dev-dependencies]
config = { path = "../../common/config"}
[dependencies]
bandwidth-claim-contract = { path = "../../common/bandwidth-claim-contract" }
+3 -4
View File
@@ -62,11 +62,10 @@ pub fn migrate(_deps: DepsMut<'_>, _env: Env, _msg: MigrateMsg) -> Result<Respon
pub mod tests {
use super::*;
use bandwidth_claim_contract::payment::PagedPaymentResponse;
use config::defaults::MIX_DENOM;
use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info};
use cosmwasm_std::{coins, from_binary};
const TEST_MIX_DENOM: &str = "unym";
#[test]
fn initialize_contract() {
let mut deps = mock_dependencies();
@@ -92,11 +91,11 @@ pub mod tests {
// Contract balance should match what we initialized it as
assert_eq!(
coins(0, TEST_MIX_DENOM),
coins(0, MIX_DENOM.base),
vec![deps
.as_ref()
.querier
.query_balance(env.contract.address, TEST_MIX_DENOM)
.query_balance(env.contract.address, MIX_DENOM.base)
.unwrap()]
);
}
+4 -1
View File
@@ -11,7 +11,7 @@ crate-type = ["cdylib", "rlib"]
[dependencies]
bandwidth-claim-contract = { path = "../../common/bandwidth-claim-contract" }
coconut-bandwidth-contract-common = { path = "../../common/cosmwasm-smart-contracts/coconut-bandwidth-contract" }
multisig-contract-common = { path = "../../common/cosmwasm-smart-contracts/multisig-contract" }
config = { path = "../../common/config"}
cosmwasm-std = "1.0.0"
cosmwasm-storage = "1.0.0"
@@ -21,3 +21,6 @@ cw-controllers = "0.13.4"
schemars = "0.8"
serde = { version = "1.0.103", default-features = false, features = ["derive"] }
thiserror = "1.0.23"
[dev-dependencies]
cw-multi-test = { version = "0.13.2" }
+77 -23
View File
@@ -1,14 +1,11 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use cosmwasm_std::{
entry_point, to_binary, Binary, Deps, DepsMut, Env, MessageInfo, Response, StdResult,
};
use cosmwasm_std::{entry_point, Binary, Deps, DepsMut, Env, MessageInfo, Response, StdResult};
use coconut_bandwidth_contract_common::msg::{ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg};
use crate::error::ContractError;
use crate::queries::{query_all_spent_credentials_paged, query_spent_credential};
use crate::state::{Config, ADMIN, CONFIG};
use crate::transactions;
@@ -25,14 +22,12 @@ pub fn instantiate(
) -> Result<Response, ContractError> {
let multisig_addr = deps.api.addr_validate(&msg.multisig_addr)?;
let pool_addr = deps.api.addr_validate(&msg.pool_addr)?;
let mix_denom = msg.mix_denom;
ADMIN.set(deps.branch(), Some(multisig_addr.clone()))?;
let cfg = Config {
multisig_addr,
pool_addr,
mix_denom,
};
CONFIG.save(deps.storage, &cfg)?;
@@ -49,23 +44,13 @@ pub fn execute(
) -> Result<Response, ContractError> {
match msg {
ExecuteMsg::DepositFunds { data } => transactions::deposit_funds(deps, env, info, data),
ExecuteMsg::SpendCredential { data } => {
transactions::spend_credential(deps, env, info, data)
}
ExecuteMsg::ReleaseFunds { funds } => transactions::release_funds(deps, env, info, funds),
}
}
#[entry_point]
pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult<Binary> {
match msg {
QueryMsg::GetAllSpentCredentials { limit, start_after } => to_binary(
&query_all_spent_credentials_paged(deps, start_after, limit)?,
),
QueryMsg::GetSpentCredential {
blinded_serial_number,
} => to_binary(&query_spent_credential(deps, blinded_serial_number)?),
}
pub fn query(_deps: Deps, _env: Env, _msg: QueryMsg) -> StdResult<Binary> {
unimplemented!();
}
#[entry_point]
@@ -76,10 +61,12 @@ pub fn migrate(_deps: DepsMut<'_>, _env: Env, _msg: MigrateMsg) -> Result<Respon
#[cfg(test)]
mod tests {
use super::*;
use crate::support::tests::fixtures::TEST_MIX_DENOM;
use crate::support::tests::helpers::*;
use cosmwasm_std::coins;
use coconut_bandwidth_contract_common::deposit::DepositData;
use config::defaults::MIX_DENOM;
use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info};
use cosmwasm_std::{coins, Addr};
use cw_multi_test::Executor;
#[test]
fn initialize_contract() {
@@ -88,7 +75,6 @@ mod tests {
let msg = InstantiateMsg {
multisig_addr: String::from(MULTISIG_CONTRACT),
pool_addr: String::from(POOL_CONTRACT),
mix_denom: TEST_MIX_DENOM.to_string(),
};
let info = mock_info("creator", &[]);
@@ -97,12 +83,80 @@ mod tests {
// Contract balance should be 0
assert_eq!(
coins(0, TEST_MIX_DENOM),
coins(0, MIX_DENOM.base),
vec![deps
.as_ref()
.querier
.query_balance(env.contract.address, TEST_MIX_DENOM)
.query_balance(env.contract.address, MIX_DENOM.base)
.unwrap()]
);
}
#[test]
fn deposit_and_release() {
let init_funds = coins(10, MIX_DENOM.base);
let deposit_funds = coins(1, MIX_DENOM.base);
let release_funds = coins(2, MIX_DENOM.base);
let mut app = mock_app(&init_funds);
let multisig_addr = String::from(MULTISIG_CONTRACT);
let pool_addr = String::from(POOL_CONTRACT);
let code_id = app.store_code(contract_bandwidth());
let msg = InstantiateMsg {
multisig_addr: multisig_addr.clone(),
pool_addr: pool_addr.clone(),
};
let contract_addr = app
.instantiate_contract(
code_id,
Addr::unchecked(OWNER),
&msg,
&[],
"bandwidth",
None,
)
.unwrap();
let msg = ExecuteMsg::DepositFunds {
data: DepositData::new(
String::from("info"),
String::from("id"),
String::from("enc"),
),
};
app.execute_contract(
Addr::unchecked(OWNER),
contract_addr.clone(),
&msg,
&deposit_funds,
)
.unwrap();
// try to release more then it's in the contract
let msg = ExecuteMsg::ReleaseFunds {
funds: release_funds[0].clone(),
};
let err = app
.execute_contract(
Addr::unchecked(multisig_addr.clone()),
contract_addr.clone(),
&msg,
&[],
)
.unwrap_err();
assert_eq!(ContractError::NotEnoughFunds, err.downcast().unwrap());
let msg = ExecuteMsg::ReleaseFunds {
funds: deposit_funds[0].clone(),
};
app.execute_contract(
Addr::unchecked(multisig_addr),
contract_addr.clone(),
&msg,
&[],
)
.unwrap();
let pool_bal = app.wrap().query_balance(pool_addr, MIX_DENOM.base).unwrap();
assert_eq!(pool_bal, deposit_funds[0]);
}
}
+4 -5
View File
@@ -5,6 +5,8 @@ use cosmwasm_std::StdError;
use cw_controllers::AdminError;
use thiserror::Error;
use config::defaults::MIX_DENOM;
/// Custom errors for contract failure conditions.
///
/// Add any other custom errors you like here.
@@ -20,15 +22,12 @@ pub enum ContractError {
#[error("No coin was sent for voucher")]
NoCoin,
#[error("Wrong coin denomination, you must send {mix_denom}")]
WrongDenom { mix_denom: String },
#[error("Wrong coin denomination, you must send {}", MIX_DENOM.base)]
WrongDenom,
#[error("There aren't enough funds in the contract")]
NotEnoughFunds,
#[error("Credential already spent or in process of spending")]
DuplicateBlindedSerialNumber,
#[error("{0}")]
Admin(#[from] AdminError),
}
+1 -3
View File
@@ -2,9 +2,7 @@
// SPDX-License-Identifier: Apache-2.0
pub mod contract;
pub mod error;
mod queries;
mod error;
mod state;
mod storage;
mod support;
mod transactions;
-178
View File
@@ -1,178 +0,0 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use coconut_bandwidth_contract_common::spend_credential::{
PagedSpendCredentialResponse, SpendCredential, SpendCredentialResponse,
};
use cosmwasm_std::{Deps, Order, StdResult};
use cw_storage_plus::Bound;
use crate::storage::{self, SPEND_CREDENTIAL_PAGE_DEFAULT_LIMIT, SPEND_CREDENTIAL_PAGE_MAX_LIMIT};
pub(crate) fn query_all_spent_credentials_paged(
deps: Deps<'_>,
start_after: Option<String>,
limit: Option<u32>,
) -> StdResult<PagedSpendCredentialResponse> {
let limit = limit
.unwrap_or(SPEND_CREDENTIAL_PAGE_DEFAULT_LIMIT)
.min(SPEND_CREDENTIAL_PAGE_MAX_LIMIT) as usize;
let start = start_after.as_deref().map(Bound::exclusive);
let nodes = storage::spent_credentials()
.range(deps.storage, start, None, Order::Ascending)
.take(limit)
.map(|res| res.map(|item| item.1))
.collect::<StdResult<Vec<SpendCredential>>>()?;
let start_next_after = nodes
.last()
.map(|spend_credential| spend_credential.blinded_serial_number().to_string());
Ok(PagedSpendCredentialResponse::new(
nodes,
limit,
start_next_after,
))
}
pub(crate) fn query_spent_credential(
deps: Deps<'_>,
blinded_serial_number: String,
) -> StdResult<SpendCredentialResponse> {
let spend_credential =
storage::spent_credentials().may_load(deps.storage, &blinded_serial_number)?;
Ok(SpendCredentialResponse::new(spend_credential))
}
#[cfg(test)]
pub(crate) mod tests {
use super::*;
use crate::support::tests::fixtures::spend_credential_data_fixture;
use crate::support::tests::helpers::init_contract;
use crate::transactions::spend_credential;
use cosmwasm_std::testing::{mock_env, mock_info};
#[test]
fn spent_credentials_empty_on_init() {
let deps = init_contract();
let response =
query_all_spent_credentials_paged(deps.as_ref(), None, Option::from(2)).unwrap();
assert_eq!(0, response.spend_credentials.len());
}
#[test]
fn spent_credentials_paged_retrieval_obeys_limits() {
let mut deps = init_contract();
let env = mock_env();
let info = mock_info("requester", &[]);
let limit = 2;
for n in 0..1000 {
let data = spend_credential_data_fixture(&format!("blinded_serial_number{}", n));
spend_credential(deps.as_mut(), env.clone(), info.clone(), data).unwrap();
}
let page1 =
query_all_spent_credentials_paged(deps.as_ref(), None, Option::from(limit)).unwrap();
assert_eq!(limit, page1.spend_credentials.len() as u32);
}
#[test]
fn spent_credentials_paged_retrieval_has_default_limit() {
let mut deps = init_contract();
let env = mock_env();
let info = mock_info("requester", &[]);
for n in 0..1000 {
let data = spend_credential_data_fixture(&format!("blinded_serial_number{}", n));
spend_credential(deps.as_mut(), env.clone(), info.clone(), data).unwrap();
}
// query without explicitly setting a limit
let page1 = query_all_spent_credentials_paged(deps.as_ref(), None, None).unwrap();
assert_eq!(
SPEND_CREDENTIAL_PAGE_DEFAULT_LIMIT,
page1.spend_credentials.len() as u32
);
}
#[test]
fn spent_credentials_paged_retrieval_has_max_limit() {
let mut deps = init_contract();
let env = mock_env();
let info = mock_info("requester", &[]);
for n in 0..1000 {
let data = spend_credential_data_fixture(&format!("blinded_serial_number{}", n));
spend_credential(deps.as_mut(), env.clone(), info.clone(), data).unwrap();
}
// query with a crazily high limit in an attempt to use too many resources
let crazy_limit = 1000 * SPEND_CREDENTIAL_PAGE_MAX_LIMIT;
let page1 =
query_all_spent_credentials_paged(deps.as_ref(), None, Option::from(crazy_limit))
.unwrap();
// we default to a decent sized upper bound instead
let expected_limit = SPEND_CREDENTIAL_PAGE_MAX_LIMIT;
assert_eq!(expected_limit, page1.spend_credentials.len() as u32);
}
#[test]
fn spent_credentials_pagination_works() {
let mut deps = init_contract();
let env = mock_env();
let info = mock_info("requester", &[]);
let data = spend_credential_data_fixture("blinded_serial_number1");
spend_credential(deps.as_mut(), env.clone(), info.clone(), data).unwrap();
let per_page = 2;
let page1 =
query_all_spent_credentials_paged(deps.as_ref(), None, Option::from(per_page)).unwrap();
// page should have 1 result on it
assert_eq!(1, page1.spend_credentials.len());
// save another
let data = spend_credential_data_fixture("blinded_serial_number2");
spend_credential(deps.as_mut(), env.clone(), info.clone(), data).unwrap();
// page1 should have 2 results on it
let page1 =
query_all_spent_credentials_paged(deps.as_ref(), None, Option::from(per_page)).unwrap();
assert_eq!(2, page1.spend_credentials.len());
let data = spend_credential_data_fixture("blinded_serial_number3");
spend_credential(deps.as_mut(), env.clone(), info.clone(), data).unwrap();
// page1 still has 2 results
let page1 =
query_all_spent_credentials_paged(deps.as_ref(), None, Option::from(per_page)).unwrap();
assert_eq!(2, page1.spend_credentials.len());
// retrieving the next page should start after the last key on this page
let start_after = page1.start_next_after.unwrap();
let page2 = query_all_spent_credentials_paged(
deps.as_ref(),
Option::from(start_after.clone()),
Option::from(per_page),
)
.unwrap();
assert_eq!(1, page2.spend_credentials.len());
let data = spend_credential_data_fixture("blinded_serial_number4");
spend_credential(deps.as_mut(), env, info, data).unwrap();
let page2 = query_all_spent_credentials_paged(
deps.as_ref(),
Option::from(start_after),
Option::from(per_page),
)
.unwrap();
// now we have 2 pages, with 2 results on the second page
assert_eq!(2, page2.spend_credentials.len());
}
}
-1
View File
@@ -13,7 +13,6 @@ pub const ADMIN: Admin = Admin::new("admin");
pub struct Config {
pub multisig_addr: Addr,
pub pool_addr: Addr,
pub mix_denom: String,
}
pub const CONFIG: Item<Config> = Item::new("config");
-106
View File
@@ -1,106 +0,0 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use coconut_bandwidth_contract_common::spend_credential::SpendCredential;
use cw_storage_plus::{Index, IndexList, IndexedMap, UniqueIndex};
// storage prefixes
const SPEND_CREDENTIAL_PK_NAMESPACE: &str = "sc";
const SPEND_CREDENTIAL_BLINDED_SERIAL_NO_IDX_NAMESPACE: &str = "scn";
// paged retrieval limits for all queries and transactions
pub(crate) const SPEND_CREDENTIAL_PAGE_MAX_LIMIT: u32 = 75;
pub(crate) const SPEND_CREDENTIAL_PAGE_DEFAULT_LIMIT: u32 = 50;
pub(crate) struct SpendCredentialIndex<'a> {
pub(crate) blinded_serial_number: UniqueIndex<'a, String, SpendCredential>,
}
// IndexList is just boilerplate code for fetching a struct's indexes
// note that from my understanding this will be converted into a macro at some point in the future
impl<'a> IndexList<SpendCredential> for SpendCredentialIndex<'a> {
fn get_indexes(&'_ self) -> Box<dyn Iterator<Item = &'_ dyn Index<SpendCredential>> + '_> {
let v: Vec<&dyn Index<SpendCredential>> = vec![&self.blinded_serial_number];
Box::new(v.into_iter())
}
}
// gateways() is the storage access function.
pub(crate) fn spent_credentials<'a>(
) -> IndexedMap<'a, &'a str, SpendCredential, SpendCredentialIndex<'a>> {
let indexes = SpendCredentialIndex {
blinded_serial_number: UniqueIndex::new(
|d| d.blinded_serial_number().to_string(),
SPEND_CREDENTIAL_BLINDED_SERIAL_NO_IDX_NAMESPACE,
),
};
IndexedMap::new(SPEND_CREDENTIAL_PK_NAMESPACE, indexes)
}
// currently not used outside tests
#[cfg(test)]
mod tests {
use super::super::storage;
use crate::storage::SpendCredential;
use crate::support::tests::fixtures;
use crate::support::tests::fixtures::TEST_MIX_DENOM;
use coconut_bandwidth_contract_common::spend_credential::SpendCredentialStatus;
use cosmwasm_std::testing::MockStorage;
use cosmwasm_std::Addr;
use cosmwasm_std::Coin;
#[test]
fn spend_credential_single_read_retrieval() {
let mut storage = MockStorage::new();
let blind_serial_number1 = "number1";
let blind_serial_number2 = "number2";
let spend1 = fixtures::spend_credential_fixture(blind_serial_number1);
let spend2 = fixtures::spend_credential_fixture(blind_serial_number2);
storage::spent_credentials()
.save(&mut storage, blind_serial_number1, &spend1)
.unwrap();
storage::spent_credentials()
.save(&mut storage, blind_serial_number2, &spend2)
.unwrap();
let res1 = storage::spent_credentials()
.load(&storage, blind_serial_number1)
.unwrap();
let res2 = storage::spent_credentials()
.load(&storage, blind_serial_number2)
.unwrap();
assert_eq!(spend1, res1);
assert_eq!(spend2, res2);
}
#[test]
fn mark_as_spent_credential() {
let mut mock_storage = MockStorage::new();
let funds = Coin::new(100, TEST_MIX_DENOM);
let blind_serial_number = "blind_serial_number";
let gateway_cosmos_address: Addr = Addr::unchecked("gateway_cosmos_address");
let res = storage::spent_credentials()
.may_load(&mock_storage, blind_serial_number)
.unwrap();
assert!(res.is_none());
let mut spend_credential = SpendCredential::new(
funds.clone(),
blind_serial_number.to_string(),
gateway_cosmos_address.clone(),
);
spend_credential.mark_as_spent();
storage::spent_credentials()
.save(&mut mock_storage, blind_serial_number, &spend_credential)
.unwrap();
let ret = storage::spent_credentials()
.load(&mock_storage, blind_serial_number)
.unwrap();
assert_eq!(ret, spend_credential);
assert_eq!(ret.status(), SpendCredentialStatus::Spent);
}
}
@@ -1,5 +1,3 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
#[cfg(test)]
pub mod tests;

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