Compare commits

..

51 Commits

Author SHA1 Message Date
aniampio 5f758f47ba Add extended packet sizes 2023-02-15 09:17:30 +00:00
aniampio e0274bb394 Increase sampling time 2023-02-14 21:15:33 +00:00
aniampio 607d4dc743 Change benchmark name 2023-02-14 21:13:13 +00:00
aniampio 25f7b7a083 Add benchmarks 2023-02-14 17:44:19 +00:00
Jon Häggblad fd1fb7ca7b rust-sdk: fix clippy in example (#3020) 2023-02-13 15:22:39 +01:00
Jon Häggblad 6252b66724 ci: keep the 3 nightly builds in sync (#3018) 2023-02-13 15:00:24 +01:00
Jon Häggblad b770cab3f0 nym-wallet: update Cargo.lock to fix security advisories (#3015) 2023-02-13 13:36:39 +01:00
Pierre Dommerc e69552b19d fix(nc-android): disable landscape mode (#3012)
* fix(nc-android): disable landscape mode

* feat(nc-android): UI sizing
2023-02-10 17:43:51 +01:00
pierre e3cc43487a fix(nc-andoird): apk build 2023-02-10 16:13:17 +01:00
pierre 41be555aa6 ci(nc-android): fix build 2023-02-10 13:44:51 +01:00
pierre bdc0bcbd56 ci(nc-android): fix gradle build 2023-02-10 12:29:35 +01:00
Jon Häggblad 0baa8b2c92 rust-sdk: improve send api (#3011)
* nym-sdk: remove unneeded function

* rust-sdk: rework send api a bit

* rust-sdk: add send_wait without impl

* fix doc test failures

* more doctest fixes
2023-02-10 11:07:48 +01:00
pierre 2ab969b2c6 ci(nc-android): debug workflow, use precompiled tauri cli 2023-02-09 22:47:28 +01:00
pierre 9f2e7e16e5 ci(nc-android): fix workflow apk build 2023-02-09 18:53:50 +01:00
pierre 1c99446bcc ci(nc-android): fix workflow for nc android apk upload 2023-02-09 18:21:55 +01:00
Pierre Dommerc 90d9c9ec41 feat(nc-android): add nym icon launchers (#3007) 2023-02-09 17:17:00 +01:00
Jon Häggblad 2e38c5e38e nym-sdk: remove a few unwraps related to creating reply surb storage (#3006) 2023-02-09 16:55:01 +01:00
Bogdan-Ștefan Neacşu dbb7a27441 Feature/stabilize credential deposit (#3002) 2023-02-09 16:55:18 +02:00
Jon Häggblad 89c05387f8 rust-sdk: add two more examples (#3003) 2023-02-09 15:43:12 +01:00
Jon Häggblad 7952277c4b rust-sdk: restructure API to builder pattern (#3000) 2023-02-09 14:58:42 +01:00
Pierre Dommerc c5866db137 feat(nc-android): sync with nc desktop (new design) (#2971)
* feat(nc-android): fit the design to mobile

* refactor(nc-android): resync with nc desktop

* fix(nc-android): tauri version

* refactor(nc-android): resync with nc desktop (rust)

* chore(nc-android): format code

* chore(nc-android): bump version
2023-02-09 14:26:19 +01:00
Dave Hrycyszyn 37187c79cc Merge branch 'master' into develop 2023-02-08 16:54:27 +00:00
Dave Hrycyszyn 24839770ff Fixing Cargo.lock to include updated version of nym-api 2023-02-08 16:54:09 +00:00
Dave Hrycyszyn 0238499e33 Changelog bump to trigger nym-connect build 2023-02-08 16:48:17 +00:00
Dave Hrycyszyn 3363230c4c Building the SDK package and only selected examples 2023-02-08 16:48:17 +00:00
pierre 1f8b373780 fix(nym-connect): lint errors 2023-02-08 16:48:17 +00:00
Dave Hrycyszyn 7ac3ec3598 Merge branch 'release/v1.1.9' 2023-02-08 16:21:57 +00:00
Dave Hrycyszyn 77ae71eba4 Changelog bump to trigger nym-connect build 2023-02-08 16:15:33 +00:00
Dave Hrycyszyn d4b836277e Merge branch 'release/v1.1.9' 2023-02-08 16:04:49 +00:00
Dave Hrycyszyn b92ee84874 Building the SDK package and only selected examples 2023-02-08 15:56:30 +00:00
pierre 2eb0ce381a fix(nym-connect): lint errors 2023-02-08 16:36:00 +01:00
Jon Häggblad 037cd54573 Merge branch 'release/v1.1.9' into develop 2023-02-08 13:45:37 +01:00
Jon Häggblad 9f42f0152b Merge branch 'release/v1.1.9' 2023-02-08 13:27:32 +01:00
Dave Hrycyszyn 5217edcca3 Changelog tweaks 2023-02-08 13:14:12 +01:00
joeiacono2021 e306effdac Merge branch 'release/v1.1.9' of https://github.com/nymtech/nym into release/v1.1.9 2023-02-08 13:14:12 +01:00
joeiacono2021 dc2b1c6d2a changelog changes for release 1.1.9 2023-02-08 13:14:12 +01:00
Jon Häggblad 4232801e80 changelog: add note about fix for unexpected shutdown 2023-02-08 13:14:12 +01:00
Fouad 96df3ad4ce Feature/nym connect health status frontend (#2969)
* filter services on rust side by gateway performance

* format rust code

* create events hook

* use events hook

* remove unused component

remove unused component

update prop names in svg

* display errors in connected screen when needed

update failed health check message
2023-02-08 13:14:12 +01:00
Fouad d614a2b81b link owner field to ng explorer (#2970)
* link owner field to ng explorer
2023-02-08 13:14:12 +01:00
Fouad d27245e184 filter services on rust side by gateway performance (#2966)
* filter services on rust side by gateway performance

* update changelog for NC
2023-02-08 13:14:12 +01:00
Mark Sinclair 5dbfcadfdb GitHub Actions: fix up build-and-upload-binaries-ci.yml 2023-02-08 13:14:12 +01:00
Jędrzej Stuczyński 035dada0e0 introduced '/circulating-supply/total-supply-value' and '/circulating-supply/circulating-supply-value' endpoints (#2965) 2023-02-08 13:14:12 +01:00
Mark Sinclair 1d867156e3 Update build-and-upload-binaries-ci.yml 2023-02-08 13:14:12 +01:00
Mark Sinclair ed9be47ec4 Update build-and-upload-binaries-ci.yml 2023-02-08 13:14:12 +01:00
Mark Sinclair 3aa2e6c54d Update build-and-upload-binaries-ci.yml 2023-02-08 13:14:12 +01:00
Mark Sinclair eb96fc72b9 GitHub Actions: add action to build and upload binaries to CI server 2023-02-08 13:14:12 +01:00
Jon Häggblad 59cec6f03c Don't drop in mixnet connection handlers (#2963) 2023-02-08 13:14:12 +01:00
Fouad c0a0d89a90 NymConnect - Add button animations (#2950)
* add button animations

* pulse and disable button on connecting/disconnecting status

* update button component story

* disabled hover on connecting/disconnecting

* add transition delay

fix up overflow
2023-02-08 13:14:12 +01:00
Bogdan-Ștefan Neacşu 3099f2ead3 Hide coconut runtime flags (#2990) 2023-02-08 13:00:17 +01:00
farbanas 9881a94757 bumped nym-api version 2023-02-03 15:12:18 +01:00
Jędrzej Stuczyński 76b07d487b introduced '/circulating-supply/total-supply-value' and '/circulating-supply/circulating-supply-value' endpoints (#2965) 2023-02-03 13:37:55 +00:00
167 changed files with 11511 additions and 2587 deletions
@@ -34,7 +34,7 @@ on:
- 'tools/ts-rs-cli/**'
env:
NETWORK: mainnet
NETWORK: mainnet
jobs:
publish-nym:
@@ -46,7 +46,7 @@ jobs:
runs-on: ${{ matrix.platform }}
steps:
- uses: actions/checkout@v3
- name: Prepare build output directory
shell: bash
env:
@@ -110,4 +110,3 @@ jobs:
REMOTE_USER: ${{ secrets.CI_WWW_REMOTE_USER }}
TARGET: ${{ secrets.CI_WWW_REMOTE_TARGET }}/builds/
EXCLUDE: "/dist/, /node_modules/"
+31 -24
View File
@@ -9,11 +9,11 @@ on:
jobs:
build:
name: Build APK
runs-on: ubuntu-latest
runs-on: custom-runner-linux
env:
ANDROID_HOME: ${{ github.workspace }}/android-sdk
NDK_VERSION: 25.1.8937393
NDK_HOME: ${{ env.ANDROID_HOME }}/ndk/${{ env.NDK_VERSION }}
NDK_HOME: ${{ github.workspace }}/android-sdk/ndk/25.1.8937393
SDK_PLATFORM_VERSION: android-33
SDK_BUILDTOOLS_VERSION: 33.0.1
@@ -25,6 +25,7 @@ jobs:
sudo apt-get -y install \
libwebkit2gtk-4.0-dev \
build-essential \
unzip \
curl \
wget \
libssl-dev \
@@ -33,6 +34,9 @@ jobs:
libayatana-appindicator3-dev \
librsvg2-dev
- name: Checkout
uses: actions/checkout@v3
- name: Install Java
uses: actions/setup-java@v3
with:
@@ -80,9 +84,6 @@ jobs:
npm i -g yarn
yarn --version
- name: Checkout
uses: actions/checkout@v3
- name: Build frontend code
run: |
yarn install --frozen-lockfile
@@ -92,36 +93,42 @@ jobs:
- name: Build APK
working-directory: nym-connect-android
env:
ANDROID_SDK_ROOT: ${{ env.ANDROID_HOME }}
WRY_ANDROID_PACKAGE: net.nymtech.nym_connect_android
WRY_ANDROID_LIBRARY: nym_connect_android
# TODO build with release profile (--release), it will requires
# to sign the APK. For now build with debug profile to avoid that
run: cargo tauri android build --debug --apk
run: cargo tauri android build --debug --apk --split-per-abi -t aarch64
# TODO add the version number to APK name
- name: Rename APK artifact
run: |
mv nym-connect-android/src-tauri/gen/android/nym_connect_android/app/build/outputs/apk/universal/debug/app-universal-debug.apk \
nym-connect-debug.apk
mkdir apk/
mv nym-connect-android/src-tauri/gen/android/nym_connect_android/app/build/outputs/apk/arm64/debug/app-arm64-debug.apk \
apk/nym-connect-arm64-debug.apk
mv nym-connect-android/src-tauri/gen/android/nym_connect_android/app/build/outputs/apk/x86_64/debug/app-x86_64-debug.apk \
apk/nym-connect-x86_64-debug.apk
- name: Upload APK artifact
uses: actions/upload-artifact@v3
with:
name: nc-apk-debug
path: nym-connect-debug.apk
path: |
apk/nym-connect-arm64-debug.apk
apk/nym-connect-x86_64-debug.apk
publish:
name: Publish APK
needs: build
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Download binary artifact
uses: actions/download-artifact@v3
with:
name: nc-apk-debug
path: apk
# TODO add a step to upload the APK somewhere
# - name: Publish
# uses: ???
# publish:
# name: Publish APK
# needs: build
# runs-on: ubuntu-latest
# steps:
# - name: Checkout
# uses: actions/checkout@v3
# - name: Download binary artifact
# uses: actions/download-artifact@v3
# with:
# name: nc-apk-debug
# path: apk
# # TODO add a step to upload the APK somewhere
# - name: Publish
# uses: ???
+3 -3
View File
@@ -10,7 +10,7 @@ jobs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
steps:
# creates the matrix strategy from nightly_build_matrix_includes.json
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- id: set-matrix
uses: JoshuaTheMiller/conditional-build-matrix@main
with:
@@ -29,7 +29,7 @@ jobs:
if: matrix.os == 'ubuntu-20.04'
- name: Check out repository code
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: Install rust toolchain
uses: actions-rs/toolchain@v1
@@ -147,7 +147,7 @@ jobs:
- name: Collect jobs status
uses: technote-space/workflow-conclusion-action@v2
- name: Check out repository code
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: install npm
uses: actions/setup-node@v3
if: env.WORKFLOW_CONCLUSION == 'failure'
+21 -9
View File
@@ -54,6 +54,12 @@ jobs:
override: true
components: rustfmt, clippy
- name: Check formatting
uses: actions-rs/cargo@v1
with:
command: fmt
args: --all -- --check
- name: Build all binaries
uses: actions-rs/cargo@v1
with:
@@ -66,6 +72,18 @@ jobs:
with:
command: clean
- name: Build all examples
uses: actions-rs/cargo@v1
with:
command: build
args: --workspace --examples
- name: Reclaim some disk space (because Windows is being annoying)
uses: actions-rs/cargo@v1
if: ${{ matrix.os == 'windows-latest' }}
with:
command: clean
- name: Run all tests
uses: actions-rs/cargo@v1
with:
@@ -74,7 +92,7 @@ jobs:
- name: Reclaim some disk space (because Windows is being annoying)
uses: actions-rs/cargo@v1
if: ${{ matrix.os == 'windows-latest' }}
if: ${{ matrix.os == 'windows-latest' || matrix.os == 'ubuntu-20.04' }}
with:
command: clean
@@ -83,13 +101,7 @@ jobs:
uses: actions-rs/cargo@v1
with:
command: test
args: --workspace --all-features -- --ignored
- name: Check formatting
uses: actions-rs/cargo@v1
with:
command: fmt
args: --all -- --check
args: --workspace -- --ignored
- name: Reclaim some disk space (because Windows is being annoying)
uses: actions-rs/cargo@v1
@@ -102,7 +114,7 @@ jobs:
continue-on-error: true
with:
token: ${{ secrets.GITHUB_TOKEN }}
args: --all-features
args: --workspace
- name: Run clippy
uses: actions-rs/cargo@v1
+21 -9
View File
@@ -54,6 +54,12 @@ jobs:
override: true
components: rustfmt, clippy
- name: Check formatting
uses: actions-rs/cargo@v1
with:
command: fmt
args: --all -- --check
- name: Build all binaries
uses: actions-rs/cargo@v1
with:
@@ -66,6 +72,18 @@ jobs:
with:
command: clean
- name: Build all examples
uses: actions-rs/cargo@v1
with:
command: build
args: --workspace --examples
- name: Reclaim some disk space (because Windows is being annoying)
uses: actions-rs/cargo@v1
if: ${{ matrix.os == 'windows-latest' }}
with:
command: clean
- name: Run all tests
uses: actions-rs/cargo@v1
with:
@@ -74,7 +92,7 @@ jobs:
- name: Reclaim some disk space (because Windows is being annoying)
uses: actions-rs/cargo@v1
if: ${{ matrix.os == 'windows-latest' }}
if: ${{ matrix.os == 'windows-latest' || matrix.os == 'ubuntu-20.04' }}
with:
command: clean
@@ -83,13 +101,7 @@ jobs:
uses: actions-rs/cargo@v1
with:
command: test
args: --workspace --all-features -- --ignored
- name: Check formatting
uses: actions-rs/cargo@v1
with:
command: fmt
args: --all -- --check
args: --workspace -- --ignored
- name: Reclaim some disk space (because Windows is being annoying)
uses: actions-rs/cargo@v1
@@ -102,7 +114,7 @@ jobs:
continue-on-error: true
with:
token: ${{ secrets.GITHUB_TOKEN }}
args: --all-features
args: --workspace
- name: Run clippy
uses: actions-rs/cargo@v1
+18 -4
View File
@@ -6,14 +6,28 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
### Added
- remove coconut feature and unify builds ([#2890])
- native-client: is now capable of listening for requests on sockets different than `127.0.0.1` ([#2939]). This can be specified via `--host` flag during `init` or `run`. Alternatively a custom `host` can be set in `config.toml` file under `socket` section.
- dkg resharing mode ([#2936])
[#2890]: https://github.com/nymtech/nym/pull/2890
[#2939]: https://github.com/nymtech/nym/pull/2939
[#2936]: https://github.com/nymtech/nym/pull/2936
# [v1.1.9] (2023-02-07)
### Added
- Separate `nym-api` endpoints with values of "total-supply" and "circulating-supply" in `nym` ([#2964])
- Add `host` option to client init ([#2912])
- Remove Coconut feature flag ([#2793])
- Don't drop in mixnet connection handler ([#2963])
### Changed
- native-client: is now capable of listening for requests on sockets different than `127.0.0.1` ([#2939]). This can be specified via `--host` flag during `init` or `run`. Alternatively a custom `host` can be set in `config.toml` file under `socket` section.
- mixnode, gateway: fix unexpected shutdown on corrupted connection ([#2963])
[#2939]: https://github.com/nymtech/nym/pull/2939
[#2963]: https://github.com/nymtech/nym/pull/2963
# [v1.1.8] (2023-01-31)
### Added
Generated
+152 -142
View File
@@ -99,9 +99,9 @@ checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299"
[[package]]
name = "anyhow"
version = "1.0.68"
version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2cb2f989d18dd141ab8ae82f64d1a8cdd37e0840f73a406896cf5e99502fab61"
checksum = "224afbd727c3d6e4b90103ece64b8d1b67fbb1973b1046c2281eed3f3803f800"
[[package]]
name = "arrayref"
@@ -138,9 +138,9 @@ dependencies = [
[[package]]
name = "async-trait"
version = "0.1.63"
version = "0.1.64"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eff18d764974428cf3a9328e23fc5c986f5fbed46e6cd4cdf42544df5d297ec1"
checksum = "1cd7fce9ba8c3c042128ce72d8b2ddbf3a05747efb67ea0313c635e10bda47a2"
dependencies = [
"proc-macro2",
"quote",
@@ -290,15 +290,6 @@ version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "383d29d513d8764dcdc42ea295d979eb99c3c9f00607b3692cf68a431f7dca72"
[[package]]
name = "bincode"
version = "1.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad"
dependencies = [
"serde",
]
[[package]]
name = "bip32"
version = "0.3.0"
@@ -459,7 +450,7 @@ name = "build-information"
version = "0.1.0"
dependencies = [
"serde",
"vergen 7.5.0",
"vergen 7.5.1",
]
[[package]]
@@ -482,9 +473,9 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
[[package]]
name = "bytes"
version = "1.3.0"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c"
checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be"
[[package]]
name = "cast"
@@ -494,9 +485,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
[[package]]
name = "cc"
version = "1.0.78"
version = "1.0.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a20104e2335ce8a659d6dd92a51a767a0c062599c73b343fd152cb401e828c3d"
checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"
dependencies = [
"jobserver",
]
@@ -629,9 +620,9 @@ dependencies = [
[[package]]
name = "clap"
version = "4.1.3"
version = "4.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8d93d855ce6a0aa87b8473ef9169482f40abaa2e9e0993024c35c902cbd5920"
checksum = "f13b9c79b5d1dd500d20ef541215a6423c75829ef43117e1b4d17fd8af0b5d76"
dependencies = [
"bitflags",
"clap_derive",
@@ -648,7 +639,7 @@ version = "4.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d6540eedc41f8a5a76cf3d8d458057dcdf817be4158a55b5f861f7a5483de75"
dependencies = [
"clap 4.1.3",
"clap 4.1.4",
]
[[package]]
@@ -657,7 +648,7 @@ version = "4.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf0c76d8fcf782a1102ccfcd10ca8246e7fdd609c1cd6deddbb96cb638e9bb5c"
dependencies = [
"clap 4.1.3",
"clap 4.1.4",
"clap_complete",
]
@@ -667,7 +658,7 @@ version = "4.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "684a277d672e91966334af371f1a7b5833f9aa00b07c84e92fbce95e00208ce8"
dependencies = [
"heck 0.4.0",
"heck 0.4.1",
"proc-macro-error",
"proc-macro2",
"quote",
@@ -818,7 +809,7 @@ dependencies = [
name = "completions"
version = "0.1.0"
dependencies = [
"clap 4.1.3",
"clap 4.1.4",
"clap_complete",
"clap_complete_fig",
]
@@ -978,9 +969,9 @@ dependencies = [
[[package]]
name = "cosmwasm-derive"
version = "1.1.9"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6fca30d51f7e5fbfa6440d8b10d7df0231bdf77e97fd3fe5d0cb79cc4822e50c"
checksum = "d5abeeb891e6d0098402e4d3d042f90451db52651d2fe14b170e69a1dd3e4115"
dependencies = [
"syn",
]
@@ -1022,9 +1013,9 @@ dependencies = [
[[package]]
name = "crc"
version = "3.0.0"
version = "3.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53757d12b596c16c78b83458d732a5d1a17ab3f53f2f7412f6fb57cc8a140ab3"
checksum = "86ec7a15cbe22e59248fc7eadb1907dab5ba09372595da4d73dd805ed4417dfe"
dependencies = [
"crc-catalog 2.2.0",
]
@@ -1055,13 +1046,15 @@ name = "credential"
version = "0.1.0"
dependencies = [
"bip39",
"clap 4.1.3",
"clap 4.1.4",
"coconut-interface",
"completions",
"config",
"credential-storage",
"credentials",
"crypto",
"log",
"logging",
"network-defaults",
"pemstore",
"rand 0.7.3",
@@ -1471,9 +1464,9 @@ dependencies = [
[[package]]
name = "cxx"
version = "1.0.87"
version = "1.0.89"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b61a7545f753a88bcbe0a70de1fcc0221e10bfc752f576754fa91e663db1622e"
checksum = "bc831ee6a32dd495436e317595e639a587aa9907bef96fe6e6abc290ab6204e9"
dependencies = [
"cc",
"cxxbridge-flags",
@@ -1483,9 +1476,9 @@ dependencies = [
[[package]]
name = "cxx-build"
version = "1.0.87"
version = "1.0.89"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f464457d494b5ed6905c63b0c4704842aba319084a0a3561cdc1359536b53200"
checksum = "94331d54f1b1a8895cd81049f7eaaaef9d05a7dcb4d1fd08bf3ff0806246789d"
dependencies = [
"cc",
"codespan-reporting",
@@ -1498,15 +1491,15 @@ dependencies = [
[[package]]
name = "cxxbridge-flags"
version = "1.0.87"
version = "1.0.89"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43c7119ce3a3701ed81aca8410b9acf6fc399d2629d057b87e2efa4e63a3aaea"
checksum = "48dcd35ba14ca9b40d6e4b4b39961f23d835dbb8eed74565ded361d93e1feb8a"
[[package]]
name = "cxxbridge-macro"
version = "1.0.87"
version = "1.0.89"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "65e07508b90551e610910fa648a1878991d367064997a596135b86df30daf07e"
checksum = "81bbeb29798b407ccd82a3324ade1a7286e0d29851475990b612670f6f5124d2"
dependencies = [
"proc-macro2",
"quote",
@@ -1568,7 +1561,7 @@ dependencies = [
"hashbrown 0.12.3",
"lock_api",
"once_cell",
"parking_lot_core 0.9.6",
"parking_lot_core 0.9.7",
]
[[package]]
@@ -1762,9 +1755,9 @@ dependencies = [
[[package]]
name = "either"
version = "1.8.0"
version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797"
checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91"
[[package]]
name = "elliptic-curve"
@@ -1786,9 +1779,9 @@ dependencies = [
[[package]]
name = "encoding_rs"
version = "0.8.31"
version = "0.8.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9852635589dc9f9ea1b6fe9f05b50ef208c85c834a562f0c6abb1c475736ec2b"
checksum = "071a31f4ee85403370b58aca746f01041ede6f0da2730960ad001edc2b71b394"
dependencies = [
"cfg-if",
]
@@ -1895,7 +1888,7 @@ name = "explorer-api"
version = "1.1.8"
dependencies = [
"chrono",
"clap 4.1.3",
"clap 4.1.4",
"contracts-common",
"dotenv",
"humantime-serde",
@@ -2006,7 +1999,7 @@ dependencies = [
"futures-core",
"futures-sink",
"pin-project",
"spin 0.9.4",
"spin 0.9.5",
]
[[package]]
@@ -2059,9 +2052,9 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c"
[[package]]
name = "futures"
version = "0.3.25"
version = "0.3.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38390104763dc37a5145a53c29c63c1290b5d316d6086ec32c293f6736051bb0"
checksum = "13e2792b0ff0340399d58445b88fd9770e3489eff258a4cbc1523418f12abf84"
dependencies = [
"futures-channel",
"futures-core",
@@ -2074,9 +2067,9 @@ dependencies = [
[[package]]
name = "futures-channel"
version = "0.3.25"
version = "0.3.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52ba265a92256105f45b719605a571ffe2d1f0fea3807304b522c1d778f79eed"
checksum = "2e5317663a9089767a1ec00a487df42e0ca174b61b4483213ac24448e4664df5"
dependencies = [
"futures-core",
"futures-sink",
@@ -2084,15 +2077,15 @@ dependencies = [
[[package]]
name = "futures-core"
version = "0.3.25"
version = "0.3.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04909a7a7e4633ae6c4a9ab280aeb86da1236243a77b694a49eacd659a4bd3ac"
checksum = "ec90ff4d0fe1f57d600049061dc6bb68ed03c7d2fbd697274c41805dcb3f8608"
[[package]]
name = "futures-executor"
version = "0.3.25"
version = "0.3.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7acc85df6714c176ab5edf386123fafe217be88c0840ec11f199441134a074e2"
checksum = "e8de0a35a6ab97ec8869e32a2473f4b1324459e14c29275d14b10cb1fd19b50e"
dependencies = [
"futures-core",
"futures-task",
@@ -2112,15 +2105,15 @@ dependencies = [
[[package]]
name = "futures-io"
version = "0.3.25"
version = "0.3.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00f5fb52a06bdcadeb54e8d3671f8888a39697dcb0b81b23b55174030427f4eb"
checksum = "bfb8371b6fb2aeb2d280374607aeabfc99d95c72edfe51692e42d3d7f0d08531"
[[package]]
name = "futures-macro"
version = "0.3.25"
version = "0.3.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bdfb8ce053d86b91919aad980c220b1fb8401a9394410e1c289ed7e66b61835d"
checksum = "95a73af87da33b5acf53acfebdc339fe592ecf5357ac7c0a7734ab9d8c876a70"
dependencies = [
"proc-macro2",
"quote",
@@ -2129,21 +2122,21 @@ dependencies = [
[[package]]
name = "futures-sink"
version = "0.3.25"
version = "0.3.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39c15cf1a4aa79df40f1bb462fb39676d0ad9e366c2a33b590d7c66f4f81fcf9"
checksum = "f310820bb3e8cfd46c80db4d7fb8353e15dfff853a127158425f31e0be6c8364"
[[package]]
name = "futures-task"
version = "0.3.25"
version = "0.3.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2ffb393ac5d9a6eaa9d3fdf37ae2776656b706e200c8e16b1bdb227f5198e6ea"
checksum = "dcf79a1bf610b10f42aea489289c5a2c478a786509693b80cd39c44ccd936366"
[[package]]
name = "futures-util"
version = "0.3.25"
version = "0.3.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "197676987abd2f9cadff84926f410af1c183608d36641465df73ae8211dc65d6"
checksum = "9c1d6de3acfef38d2be4b1f543f553131788603495be83da675e180c8d6b7bd1"
dependencies = [
"futures-channel",
"futures-core",
@@ -2295,19 +2288,6 @@ dependencies = [
"polyval",
]
[[package]]
name = "git2"
version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2994bee4a3a6a51eb90c218523be382fd7ea09b16380b9312e9dbe955ff7c7d1"
dependencies = [
"bitflags",
"libc",
"libgit2-sys",
"log",
"url",
]
[[package]]
name = "git2"
version = "0.16.1"
@@ -2496,9 +2476,9 @@ dependencies = [
[[package]]
name = "heck"
version = "0.4.0"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9"
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
dependencies = [
"unicode-segmentation",
]
@@ -2521,6 +2501,12 @@ dependencies = [
"libc",
]
[[package]]
name = "hermit-abi"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286"
[[package]]
name = "hex"
version = "0.4.3"
@@ -2650,9 +2636,9 @@ dependencies = [
[[package]]
name = "hyper"
version = "0.14.23"
version = "0.14.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "034711faac9d2166cb1baf1a2fb0b60b1f277f8492fd72176c17f3515e1abd3c"
checksum = "5e011372fa0b68db8350aa7a248930ecc7839bf46d8485577d69f117a75f164c"
dependencies = [
"bytes",
"futures-channel",
@@ -2839,12 +2825,12 @@ dependencies = [
[[package]]
name = "io-lifetimes"
version = "1.0.4"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e7d6c6f8c91b4b9ed43484ad1a938e393caf35960fce7f82a040497207bd8e9e"
checksum = "1abeb7a0dd0f8181267ff8adc397075586500b81b28a73e8a0208b00fc170fb3"
dependencies = [
"libc",
"windows-sys",
"windows-sys 0.45.0",
]
[[package]]
@@ -2873,14 +2859,14 @@ dependencies = [
[[package]]
name = "is-terminal"
version = "0.4.2"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28dfb6c8100ccc63462345b67d1bbc3679177c75ee4bf59bf29c8b1d110b8189"
checksum = "22e18b0a45d56fe973d6db23972bf5bc46f988a4a2385deac9cc29572f09daef"
dependencies = [
"hermit-abi 0.2.6",
"hermit-abi 0.3.1",
"io-lifetimes",
"rustix",
"windows-sys",
"windows-sys 0.45.0",
]
[[package]]
@@ -3215,7 +3201,7 @@ dependencies = [
"libc",
"log",
"wasi 0.11.0+wasi-snapshot-preview1",
"windows-sys",
"windows-sys 0.42.0",
]
[[package]]
@@ -3298,7 +3284,7 @@ dependencies = [
"log",
"memchr",
"mime",
"spin 0.9.4",
"spin 0.9.5",
"tokio",
"tokio-util",
"version_check",
@@ -3439,7 +3425,7 @@ dependencies = [
[[package]]
name = "nym-api"
version = "1.1.8"
version = "1.1.9"
dependencies = [
"anyhow",
"async-trait",
@@ -3447,7 +3433,7 @@ dependencies = [
"bs58",
"build-information",
"cfg-if",
"clap 4.1.3",
"clap 4.1.4",
"coconut-bandwidth-contract-common",
"coconut-dkg-common",
"coconut-interface",
@@ -3543,7 +3529,7 @@ dependencies = [
"base64 0.13.1",
"bip39",
"bs58",
"clap 4.1.3",
"clap 4.1.4",
"clap_complete",
"clap_complete_fig",
"dotenv",
@@ -3567,7 +3553,7 @@ dependencies = [
"bip39",
"bs58",
"cfg-if",
"clap 4.1.3",
"clap 4.1.4",
"coconut-bandwidth-contract-common",
"coconut-dkg-common",
"comfy-table",
@@ -3598,7 +3584,7 @@ name = "nym-client"
version = "1.1.8"
dependencies = [
"build-information",
"clap 4.1.3",
"clap 4.1.4",
"client-connections",
"client-core",
"coconut-interface",
@@ -3643,7 +3629,7 @@ dependencies = [
"bip39",
"bs58",
"build-information",
"clap 4.1.3",
"clap 4.1.4",
"coconut-interface",
"colored",
"completions",
@@ -3693,7 +3679,7 @@ dependencies = [
"atty",
"bs58",
"build-information",
"clap 4.1.3",
"clap 4.1.4",
"colored",
"completions",
"config",
@@ -3736,7 +3722,7 @@ version = "1.1.8"
dependencies = [
"async-trait",
"build-information",
"clap 4.1.3",
"clap 4.1.4",
"client-connections",
"completions",
"dirs",
@@ -3826,7 +3812,7 @@ name = "nym-socks5-client"
version = "1.1.8"
dependencies = [
"build-information",
"clap 4.1.3",
"clap 4.1.4",
"client-connections",
"client-core",
"coconut-interface",
@@ -3915,7 +3901,6 @@ dependencies = [
name = "nymcoconut"
version = "0.5.0"
dependencies = [
"bincode",
"bls12_381 0.6.0",
"bs58",
"criterion 0.3.6",
@@ -3939,6 +3924,7 @@ dependencies = [
name = "nymsphinx"
version = "0.1.0"
dependencies = [
"criterion 0.3.6",
"crypto",
"mixnet-contract-common",
"nymsphinx-acknowledgements",
@@ -4199,7 +4185,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
dependencies = [
"lock_api",
"parking_lot_core 0.9.6",
"parking_lot_core 0.9.7",
]
[[package]]
@@ -4218,15 +4204,15 @@ dependencies = [
[[package]]
name = "parking_lot_core"
version = "0.9.6"
version = "0.9.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba1ef8814b5c993410bb3adfad7a5ed269563e4a2f90c41f5d85be7fb47133bf"
checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521"
dependencies = [
"cfg-if",
"libc",
"redox_syscall",
"smallvec 1.10.0",
"windows-sys",
"windows-sys 0.45.0",
]
[[package]]
@@ -4320,9 +4306,9 @@ checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e"
[[package]]
name = "pest"
version = "2.5.3"
version = "2.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4257b4a04d91f7e9e6290be5d3da4804dd5784fafde3a497d73eb2b4a158c30a"
checksum = "028accff104c4e513bad663bbcd2ad7cfd5304144404c31ed0a77ac103d00660"
dependencies = [
"thiserror",
"ucd-trie",
@@ -4330,9 +4316,9 @@ dependencies = [
[[package]]
name = "pest_derive"
version = "2.5.3"
version = "2.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "241cda393b0cdd65e62e07e12454f1f25d57017dcc514b1514cd3c4645e3a0a6"
checksum = "2ac3922aac69a40733080f53c1ce7f91dcf57e1a5f6c52f421fadec7fbdc4b69"
dependencies = [
"pest",
"pest_generator",
@@ -4340,9 +4326,9 @@ dependencies = [
[[package]]
name = "pest_generator"
version = "2.5.3"
version = "2.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46b53634d8c8196302953c74d5352f33d0c512a9499bd2ce468fc9f4128fa27c"
checksum = "d06646e185566b5961b4058dd107e0a7f56e77c3f484549fb119867773c0f202"
dependencies = [
"pest",
"pest_meta",
@@ -4353,9 +4339,9 @@ dependencies = [
[[package]]
name = "pest_meta"
version = "2.5.3"
version = "2.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ef4f1332a8d4678b41966bb4cc1d0676880e84183a1ecc3f4b69f03e99c7a51"
checksum = "e6f60b2ba541577e2a0c307c8f39d1439108120eb7903adeb6497fa880c59616"
dependencies = [
"once_cell",
"pest",
@@ -4504,9 +4490,9 @@ dependencies = [
[[package]]
name = "proc-macro2"
version = "1.0.50"
version = "1.0.51"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ef7d57beacfaf2d8aee5937dab7b7f28de3cb8b1828479bb5de2a7106f2bae2"
checksum = "5d727cae5b39d21da60fa540906919ad737832fe0b1c165da3a34d6548c849d6"
dependencies = [
"unicode-ident",
]
@@ -5178,16 +5164,16 @@ dependencies = [
[[package]]
name = "rustix"
version = "0.36.7"
version = "0.36.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4fdebc4b395b7fbb9ab11e462e20ed9051e7b16e42d24042c776eca0ac81b03"
checksum = "f43abb88211988493c1abb44a70efa56ff0ce98f233b7b276146f1f3f7ba9644"
dependencies = [
"bitflags",
"errno",
"io-lifetimes",
"libc",
"linux-raw-sys",
"windows-sys",
"windows-sys 0.45.0",
]
[[package]]
@@ -5263,7 +5249,7 @@ version = "0.1.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "713cfb06c7059f3588fb8044c0fad1d09e3c01d225e25b9220dbfdcf16dbb1b3"
dependencies = [
"windows-sys",
"windows-sys 0.42.0",
]
[[package]]
@@ -5344,9 +5330,9 @@ dependencies = [
[[package]]
name = "security-framework"
version = "2.8.0"
version = "2.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "645926f31b250a2dca3c232496c2d898d91036e45ca0e97e0e2390c54e11be36"
checksum = "a332be01508d814fed64bf28f798a146d73792121129962fdf335bb3c49a4254"
dependencies = [
"bitflags",
"core-foundation",
@@ -5424,9 +5410,9 @@ dependencies = [
[[package]]
name = "serde_bytes"
version = "0.11.8"
version = "0.11.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "718dc5fff5b36f99093fc49b280cfc96ce6fc824317783bff5a1fed0c7a64819"
checksum = "416bda436f9aab92e02c8e10d49a15ddd339cea90b6e340fe51ed97abb548294"
dependencies = [
"serde",
]
@@ -5465,9 +5451,9 @@ dependencies = [
[[package]]
name = "serde_json"
version = "1.0.91"
version = "1.0.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "877c235533714907a8c2464236f5c4b2a17262ef1bd71f38f35ea592c8da6883"
checksum = "cad406b69c91885b5107daf2c29572f6c8cdb3c66826821e286c533490c0bc76"
dependencies = [
"itoa 1.0.5",
"ryu",
@@ -5673,7 +5659,7 @@ version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "475b3bbe5245c26f2d8a6f62d67c1f30eb9fffeccee721c45d162c3ebbdf81b2"
dependencies = [
"heck 0.4.0",
"heck 0.4.1",
"proc-macro2",
"quote",
"syn",
@@ -5731,9 +5717,9 @@ checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
[[package]]
name = "spin"
version = "0.9.4"
version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f6002a767bff9e83f8eeecf883ecb8011875a21ae8da43bffb817a57e78cc09"
checksum = "7dccf47db1b41fa1573ed27ccf5e08e3ca771cb994f776668c5ebda893b248fc"
dependencies = [
"lock_api",
]
@@ -5848,7 +5834,7 @@ dependencies = [
"byteorder",
"bytes",
"chrono",
"crc 3.0.0",
"crc 3.0.1",
"crossbeam-queue",
"dotenvy",
"either",
@@ -5891,7 +5877,7 @@ checksum = "bc0fba2b0cae21fc00fe6046f8baa4c7fcb49e379f0f592b04696607f69ed2e1"
dependencies = [
"dotenv",
"either",
"heck 0.4.0",
"heck 0.4.1",
"once_cell",
"proc-macro2",
"quote",
@@ -5910,7 +5896,7 @@ checksum = "b850fa514dc11f2ee85be9d055c512aa866746adfacd1cb42d867d68e6a5b0d9"
dependencies = [
"dotenvy",
"either",
"heck 0.4.0",
"heck 0.4.1",
"once_cell",
"proc-macro2",
"quote",
@@ -6031,7 +6017,7 @@ version = "0.24.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59"
dependencies = [
"heck 0.4.0",
"heck 0.4.1",
"proc-macro2",
"quote",
"rustversion",
@@ -6072,9 +6058,9 @@ dependencies = [
[[package]]
name = "sync_wrapper"
version = "0.1.1"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "20518fe4a4c9acf048008599e464deb21beeae3d3578418951a189c235a7a9a8"
checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160"
[[package]]
name = "synstructure"
@@ -6335,9 +6321,9 @@ dependencies = [
[[package]]
name = "tokio"
version = "1.24.2"
version = "1.25.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "597a12a59981d9e3c38d216785b0c37399f6e415e8d0712047620f189371b0bb"
checksum = "c8e00990ebabbe4c14c08aca901caed183ecd5c09562a12c824bb53d3c3fd3af"
dependencies = [
"autocfg 1.1.0",
"bytes",
@@ -6351,7 +6337,7 @@ dependencies = [
"socket2",
"tokio-macros",
"tracing",
"windows-sys",
"windows-sys 0.42.0",
]
[[package]]
@@ -6377,9 +6363,9 @@ dependencies = [
[[package]]
name = "tokio-native-tls"
version = "0.3.0"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7d995660bd2b7f8c1568414c1126076c13fbb725c40112dc0120b78eb9b717b"
checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2"
dependencies = [
"native-tls",
"tokio",
@@ -6820,9 +6806,9 @@ dependencies = [
[[package]]
name = "unicode-segmentation"
version = "1.10.0"
version = "1.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fdbf052a0783de01e944a6ce7a8cb939e295b1e7be835a1112c3b9a7f047a5a"
checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36"
[[package]]
name = "unicode-width"
@@ -6945,7 +6931,7 @@ dependencies = [
"chrono",
"enum-iterator 0.8.1",
"getset",
"git2 0.16.1",
"git2",
"rustc_version 0.4.0",
"rustversion",
"thiserror",
@@ -6953,15 +6939,15 @@ dependencies = [
[[package]]
name = "vergen"
version = "7.5.0"
version = "7.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "571b69f690c855821462709b6f41d42ceccc316fbd17b60bd06d06928cfe6a99"
checksum = "f21b881cd6636ece9735721cf03c1fe1e774fe258683d084bb2812ab67435749"
dependencies = [
"anyhow",
"cfg-if",
"enum-iterator 1.2.0",
"getset",
"git2 0.15.0",
"git2",
"rustc_version 0.4.0",
"rustversion",
"thiserror",
@@ -7255,6 +7241,30 @@ dependencies = [
"windows_x86_64_msvc 0.42.1",
]
[[package]]
name = "windows-sys"
version = "0.45.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc 0.42.1",
"windows_i686_gnu 0.42.1",
"windows_i686_msvc 0.42.1",
"windows_x86_64_gnu 0.42.1",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc 0.42.1",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.42.1"
+4 -1
View File
@@ -107,8 +107,11 @@ edition = "2021"
[workspace.dependencies]
async-trait = "0.1.63"
lazy_static = "1.4.0"
log = "0.4"
thiserror = "1.0.38"
serde = "1.0.152"
serde_json = "1.0.91"
tap = "1.0.1"
thiserror = "1.0.38"
tokio = "1.24.1"
url = "2.2"
@@ -51,11 +51,22 @@ pub mod non_wasm_helpers;
pub mod helpers;
#[derive(Clone)]
pub struct ClientInput {
pub connection_command_sender: ConnectionCommandSender,
pub input_sender: InputMessageSender,
}
impl ClientInput {
pub async fn send(
&self,
message: InputMessage,
) -> Result<(), tokio::sync::mpsc::error::SendError<InputMessage>> {
self.input_sender.send(message).await
}
}
#[derive(Clone)]
pub struct ClientOutput {
pub received_buffer_request_sender: ReceivedBufferRequestSender,
}
@@ -303,6 +314,7 @@ where
let shared_key = if self.key_manager.is_gateway_key_set() {
Some(self.key_manager.gateway_shared_key())
} else {
log::info!("Gateway key not set! Will proceed anyway.");
None
};
@@ -77,4 +77,12 @@ impl InputMessage {
lane,
}
}
pub fn lane(&self) -> &TransmissionLane {
match self {
InputMessage::Regular { lane, .. }
| InputMessage::Anonymous { lane, .. }
| InputMessage::Reply { lane, .. } => lane,
}
}
}
@@ -5,6 +5,8 @@ use crate::client::replies::reply_storage::backend::Empty;
use crate::client::replies::reply_storage::{CombinedReplyStorage, ReplyStorageBackend};
use async_trait::async_trait;
use std::path::PathBuf;
// well, right now we don't have the browser storage : (
// so we keep everything in memory
#[derive(Debug)]
@@ -27,6 +29,18 @@ impl Backend {
impl ReplyStorageBackend for Backend {
type StorageError = <Empty as ReplyStorageBackend>::StorageError;
async fn new(
debug_config: &crate::config::DebugConfig,
_db_path: Option<PathBuf>,
) -> Result<Self, Self::StorageError> {
Ok(Backend {
empty: Empty {
min_surb_threshold: debug_config.minimum_reply_surb_storage_threshold,
max_surb_threshold: debug_config.maximum_reply_surb_storage_threshold,
},
})
}
async fn flush_surb_storage(
&mut self,
storage: &CombinedReplyStorage,
@@ -56,4 +56,9 @@ pub enum StorageError {
details: String,
// err: Option<Box<dyn std::error::Error>>
},
#[error("failed to create storage")]
FailedToCreateStorage {
source: Box<dyn std::error::Error + Send + Sync>,
},
}
@@ -1,6 +1,7 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::client::base_client::non_wasm_helpers;
use crate::client::replies::reply_storage::backend::fs_backend::manager::StorageManager;
use crate::client::replies::reply_storage::backend::fs_backend::models::{
ReplySurbStorageMetadata, StoredReplyKey, StoredReplySurb, StoredSenderTag, StoredSurbSender,
@@ -367,6 +368,20 @@ impl Backend {
impl ReplyStorageBackend for Backend {
type StorageError = error::StorageError;
async fn new(
debug_config: &crate::config::DebugConfig,
db_path: Option<PathBuf>,
) -> Result<Self, Self::StorageError> {
non_wasm_helpers::setup_fs_reply_surb_backend(db_path, debug_config)
.await
.map_err(|err| {
log::error!("Failed to create storage: {err}");
Self::StorageError::FailedToCreateStorage {
source: Box::new(err),
}
})
}
fn is_active(&self) -> bool {
self.manager.is_active()
}
@@ -3,7 +3,7 @@
use crate::client::replies::reply_storage::CombinedReplyStorage;
use async_trait::async_trait;
use std::error::Error;
use std::{error::Error, path::PathBuf};
use thiserror::Error;
#[cfg(target_arch = "wasm32")]
@@ -30,6 +30,16 @@ pub struct Empty {
impl ReplyStorageBackend for Empty {
type StorageError = UndefinedError;
async fn new(
debug_config: &crate::config::DebugConfig,
_db_path: Option<PathBuf>,
) -> Result<Self, Self::StorageError> {
Ok(Self {
min_surb_threshold: debug_config.minimum_reply_surb_storage_threshold,
max_surb_threshold: debug_config.maximum_reply_surb_storage_threshold,
})
}
async fn flush_surb_storage(
&mut self,
_storage: &CombinedReplyStorage,
@@ -63,6 +73,11 @@ impl ReplyStorageBackend for Empty {
pub trait ReplyStorageBackend: Sized {
type StorageError: Error + 'static;
async fn new(
debug_config: &crate::config::DebugConfig,
db_path: Option<PathBuf>,
) -> Result<Self, Self::StorageError>;
fn is_active(&self) -> bool {
true
}
+2
View File
@@ -8,6 +8,7 @@ edition = "2021"
[dependencies]
bip39 = "1.0.1"
clap = { version = "4.0", features = ["cargo", "derive"] }
log = "0.4"
rand = "0.7.3"
serde = { version = "1.0", features = ["derive"] }
thiserror = "1.0"
@@ -20,6 +21,7 @@ completions = { path = "../../common/completions" }
credentials = { path = "../../common/credentials" }
credential-storage = { path = "../../common/credential-storage" }
crypto = { path = "../../common/crypto", features = ["rand", "asymmetric", "symmetric", "aes", "hashing"] }
logging = { path = "../../common/logging"}
network-defaults = { path = "../../common/network-defaults" }
pemstore = { path = "../../common/pemstore" }
validator-client = { path = "../../common/client-libs/validator-client", features = ["nyxd-client"] }
+75 -32
View File
@@ -1,8 +1,9 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use clap::{Args, Subcommand};
use clap::{ArgGroup, Args, Subcommand};
use completions::ArgShell;
use log::*;
use rand::rngs::OsRng;
use std::str::FromStr;
@@ -12,18 +13,20 @@ use credential_storage::PersistentStorage;
use credentials::coconut::bandwidth::{BandwidthVoucher, TOTAL_ATTRIBUTES};
use credentials::coconut::utils::obtain_aggregate_signature;
use crypto::asymmetric::{encryption, identity};
use network_defaults::{NymNetworkDetails, VOUCHER_INFO};
use network_defaults::VOUCHER_INFO;
use validator_client::nyxd::traits::DkgQueryClient;
use validator_client::nyxd::tx::Hash;
use validator_client::{CoconutApiClient, Config};
use validator_client::nyxd::CosmWasmClient;
use validator_client::CoconutApiClient;
use crate::client::Client;
use crate::error::{CredentialClientError, Result};
use crate::recovery_storage::RecoveryStorage;
use crate::state::{KeyPair, State};
#[derive(Subcommand)]
pub(crate) enum Command {
/// Run the binary
/// Run the binary to obtain a credential
Run(Run),
/// Generate shell completions
@@ -34,6 +37,11 @@ pub(crate) enum Command {
}
#[derive(Args)]
#[clap(group(
ArgGroup::new("recov")
.required(true)
.args(&["amount", "recovery_mode"]),
))]
pub(crate) struct Run {
/// Home directory of the client that is supposed to use the credential.
#[clap(long)]
@@ -47,15 +55,25 @@ pub(crate) struct Run {
#[clap(long)]
pub(crate) mnemonic: String,
/// The amount of utokens the credential will hold
#[clap(long)]
/// The amount of utokens the credential will hold. If recovery mode is enabled, this value
/// is not needed
#[clap(long, default_value = "0")]
pub(crate) amount: u64,
/// Path to a directory used to store recovery files for unconsumed deposits
#[clap(long)]
pub(crate) recovery_dir: std::path::PathBuf,
/// Recovery mode, when enabled, tries to recover any deposit data dumped in recovery_dir
#[clap(long)]
pub(crate) recovery_mode: bool,
}
pub(crate) async fn deposit(nyxd_url: &str, mnemonic: &str, amount: u64) -> Result<State> {
let mut rng = OsRng;
let signing_keypair = KeyPair::from(identity::KeyPair::new(&mut rng));
let encryption_keypair = KeyPair::from(encryption::KeyPair::new(&mut rng));
let params = Parameters::new(TOTAL_ATTRIBUTES).unwrap();
let client = Client::new(nyxd_url, mnemonic);
let tx_hash = client
@@ -67,20 +85,25 @@ pub(crate) async fn deposit(nyxd_url: &str, mnemonic: &str, amount: u64) -> Resu
)
.await?;
let state = State {
amount,
tx_hash,
signing_keypair,
encryption_keypair,
};
let voucher = BandwidthVoucher::new(
&params,
amount.to_string(),
VOUCHER_INFO.to_string(),
Hash::from_str(&tx_hash).map_err(|_| CredentialClientError::InvalidTxHash)?,
identity::PrivateKey::from_base58_string(&signing_keypair.private_key)?,
encryption::PrivateKey::from_base58_string(&encryption_keypair.private_key)?,
);
let state = State { voucher, params };
Ok(state)
}
pub(crate) async fn get_credential(state: &State, shared_storage: PersistentStorage) -> Result<()> {
let network_details = NymNetworkDetails::new_from_env();
let config = Config::try_from_nym_network_details(&network_details)?;
let client = validator_client::Client::new_query(config)?;
pub(crate) async fn get_credential<C: Clone + CosmWasmClient + Send + Sync>(
state: &State,
client: validator_client::Client<C>,
shared_storage: PersistentStorage,
) -> Result<()> {
let epoch_id = client.nyxd.get_current_epoch().await?.epoch_id;
let threshold = client
.nyxd
@@ -89,30 +112,20 @@ pub(crate) async fn get_credential(state: &State, shared_storage: PersistentStor
.ok_or(CredentialClientError::NoThreshold)?;
let coconut_api_clients = CoconutApiClient::all_coconut_api_clients(&client, epoch_id).await?;
let params = Parameters::new(TOTAL_ATTRIBUTES).unwrap();
let bandwidth_credential_attributes = BandwidthVoucher::new(
&params,
state.amount.to_string(),
VOUCHER_INFO.to_string(),
Hash::from_str(&state.tx_hash).map_err(|_| CredentialClientError::InvalidTxHash)?,
identity::PrivateKey::from_base58_string(&state.signing_keypair.private_key)?,
encryption::PrivateKey::from_base58_string(&state.encryption_keypair.private_key)?,
);
let signature = obtain_aggregate_signature(
&params,
&bandwidth_credential_attributes,
&state.params,
&state.voucher,
&coconut_api_clients,
threshold,
)
.await?;
println!("Signature: {:?}", signature.to_bs58());
info!("Signature: {:?}", signature.to_bs58());
shared_storage
.insert_coconut_credential(
state.amount.to_string(),
state.voucher.get_voucher_value(),
VOUCHER_INFO.to_string(),
bandwidth_credential_attributes.get_private_attributes()[0].to_bs58(),
bandwidth_credential_attributes.get_private_attributes()[1].to_bs58(),
state.voucher.get_private_attributes()[0].to_bs58(),
state.voucher.get_private_attributes()[1].to_bs58(),
signature.to_bs58(),
epoch_id.to_string(),
)
@@ -120,3 +133,33 @@ pub(crate) async fn get_credential(state: &State, shared_storage: PersistentStor
Ok(())
}
pub(crate) async fn recover_credentials<C: Clone + CosmWasmClient + Send + Sync>(
client: validator_client::Client<C>,
recovery_storage: &RecoveryStorage,
shared_storage: PersistentStorage,
) -> Result<()> {
for voucher in recovery_storage.unconsumed_vouchers()? {
let state = State {
voucher,
params: Parameters::new(TOTAL_ATTRIBUTES).unwrap(),
};
if let Err(e) = get_credential(&state, client.clone(), shared_storage.clone()).await {
error!(
"Could not recover deposit {} due to {:?}, try again later",
state.voucher.tx_hash(),
e
)
} else {
info!(
"Converted deposit {} to a credential, removing recovery data for it",
state.voucher.tx_hash()
);
if let Err(e) = recovery_storage.remove_voucher(state.voucher.tx_hash().to_string()) {
warn!("Could not remove recovery data - {:?}", e);
}
}
}
Ok(())
}
+7
View File
@@ -1,6 +1,7 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use std::time::SystemTimeError;
use thiserror::Error;
use credential_storage::error::StorageError;
@@ -14,6 +15,9 @@ pub type Result<T> = std::result::Result<T, CredentialClientError>;
#[derive(Error, Debug)]
pub enum CredentialClientError {
#[error("IO error: {0}")]
IOError(#[from] std::io::Error),
#[error("Nyxd error: {0}")]
Nyxd(#[from] NyxdError),
@@ -35,6 +39,9 @@ pub enum CredentialClientError {
#[error("Could not use shared storage")]
SharedStorageError(#[from] StorageError),
#[error("Could not get system time")]
SysTimeError(#[from] SystemTimeError),
#[error("Threshold not set yet")]
NoThreshold,
}
+65 -3
View File
@@ -4,15 +4,25 @@
mod client;
mod commands;
mod error;
mod recovery_storage;
mod state;
use commands::*;
use completions::fig_generate;
use config::{DATA_DIR, DB_FILE_NAME};
use error::Result;
use network_defaults::setup_env;
use log::*;
use network_defaults::{setup_env, NymNetworkDetails};
use std::process::exit;
use std::time::{Duration, SystemTime};
use clap::{CommandFactory, Parser};
use logging::setup_logging;
use validator_client::nyxd::traits::DkgQueryClient;
use validator_client::nyxd::CosmWasmClient;
use validator_client::Config;
const SAFETY_BUFFER_SECS: u64 = 60; // 1 minute
#[derive(Parser)]
#[clap(author = "Nymtech", version, about)]
@@ -25,9 +35,36 @@ struct Cli {
pub(crate) command: Command,
}
async fn block_until_coconut_is_available<C: Clone + CosmWasmClient + Send + Sync>(
client: &validator_client::Client<C>,
) -> Result<()> {
loop {
let epoch = client.nyxd.get_current_epoch().await?;
let current_timestamp_secs = SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH)?
.as_secs();
if epoch.state.is_final() {
if current_timestamp_secs + SAFETY_BUFFER_SECS >= epoch.finish_timestamp.seconds() {
info!("In the next {} minute(s), a transition will take place in the coconut system. Deposits should be halted in this time for safety reasons.", SAFETY_BUFFER_SECS / 60);
exit(0);
}
break;
} else {
// Use 20 additional seconds to avoid the exact moment of going into the final epoch state
let secs_until_final = epoch.final_timestamp_secs() + 20 - current_timestamp_secs;
info!("Approximately {} seconds until coconut is available. Sleeping until then. You can safely kill the process at any moment.", secs_until_final);
std::thread::sleep(Duration::from_secs(secs_until_final));
}
}
Ok(())
}
#[tokio::main]
async fn main() -> Result<()> {
let args = Cli::parse();
setup_logging();
setup_env(args.config_env_file.as_ref());
let bin_name = "nym-credential-client";
@@ -35,9 +72,34 @@ async fn main() -> Result<()> {
Command::Run(r) => {
let db_path = r.client_home_directory.join(DATA_DIR).join(DB_FILE_NAME);
let shared_storage = credential_storage::initialise_storage(db_path).await;
let recovery_storage = recovery_storage::RecoveryStorage::new(r.recovery_dir)?;
let state = deposit(&r.nyxd_url, &r.mnemonic, r.amount).await?;
get_credential(&state, shared_storage).await?;
let network_details = NymNetworkDetails::new_from_env();
let config = Config::try_from_nym_network_details(&network_details)?;
let client = validator_client::Client::new_query(config)?;
block_until_coconut_is_available(&client).await?;
info!("Starting depositing funds, don't kill the process");
if !r.recovery_mode {
let state = deposit(&r.nyxd_url, &r.mnemonic, r.amount).await?;
if get_credential(&state, client, shared_storage)
.await
.is_err()
{
warn!("Failed to obtain credential. Dumping recovery data.",);
match recovery_storage.insert_voucher(&state.voucher) {
Ok(file_path) => {
warn!("Dumped recovery data to {:?}. Try using recovery mode to convert it to a credential", file_path);
}
Err(e) => {
error!("Could not dump recovery data to file system due to {:?}, the deposit will be lost!", e)
}
}
}
} else {
recover_credentials(client, &recovery_storage, shared_storage).await?;
}
}
Command::Completions(c) => c.generate(&mut crate::Cli::command(), bin_name),
Command::GenerateFigSpec => fig_generate(&mut crate::Cli::command(), bin_name),
@@ -0,0 +1,56 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use credentials::coconut::bandwidth::BandwidthVoucher;
use std::fs::{create_dir_all, read_dir, File};
use std::io::{Read, Write};
use std::path::PathBuf;
pub struct RecoveryStorage {
recovery_dir: PathBuf,
}
impl RecoveryStorage {
pub fn new(recovery_dir: PathBuf) -> std::io::Result<Self> {
create_dir_all(&recovery_dir)?;
Ok(Self { recovery_dir })
}
pub fn unconsumed_vouchers(&self) -> std::io::Result<impl Iterator<Item = BandwidthVoucher>> {
Ok(read_dir(&self.recovery_dir)?
.filter_map(|entry| entry.ok())
.filter_map(|entry| {
let path = entry.path();
if path.is_file() {
Some(path)
} else {
None
}
})
.filter_map(|path| File::open(path).ok())
.filter_map(|mut f| {
let mut buff = Vec::new();
if f.read_to_end(&mut buff).is_ok() {
Some(buff)
} else {
None
}
})
.filter_map(|buff| BandwidthVoucher::try_from_bytes(&buff).ok()))
}
pub fn insert_voucher(&self, voucher: &BandwidthVoucher) -> std::io::Result<PathBuf> {
let file_name = voucher.tx_hash().to_string();
let file_path = self.recovery_dir.join(file_name);
let mut file = File::create(&file_path)?;
let buff = voucher.to_bytes();
file.write_all(&buff)?;
Ok(file_path)
}
pub fn remove_voucher(&self, file_name: String) -> std::io::Result<()> {
let file_path = self.recovery_dir.join(file_name);
std::fs::remove_file(file_path)
}
}
+4 -7
View File
@@ -1,11 +1,11 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use serde::{Deserialize, Serialize};
use coconut_interface::Parameters;
use credentials::coconut::bandwidth::BandwidthVoucher;
use crypto::asymmetric::{encryption, identity};
#[derive(Clone, Debug, Deserialize, Serialize)]
pub(crate) struct KeyPair {
pub public_key: String,
pub private_key: String,
@@ -29,10 +29,7 @@ impl From<encryption::KeyPair> for KeyPair {
}
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub(crate) struct State {
pub amount: u64,
pub tx_hash: String,
pub signing_keypair: KeyPair,
pub encryption_keypair: KeyPair,
pub voucher: BandwidthVoucher,
pub params: Parameters,
}
+2 -2
View File
@@ -31,7 +31,7 @@ pub(crate) struct Init {
force_register_gateway: bool,
/// Comma separated list of rest endpoints of the nyxd validators
#[clap(long, alias = "nymd_validators", value_delimiter = ',')]
#[clap(long, alias = "nymd_validators", value_delimiter = ',', hide = true)]
nyxd_urls: Option<Vec<url::Url>>,
/// Comma separated list of rest endpoints of the API validators
@@ -62,7 +62,7 @@ pub(crate) struct Init {
/// Set this client to work in a enabled credentials mode that would attempt to use gateway
/// with bandwidth credential requirement.
#[clap(long)]
#[clap(long, hide = true)]
enabled_credentials_mode: Option<bool>,
/// Save a summary of the initialization to a json file
+2 -2
View File
@@ -23,7 +23,7 @@ pub(crate) struct Run {
id: String,
/// Comma separated list of rest endpoints of the nyxd validators
#[clap(long, alias = "nymd_validators", value_delimiter = ',')]
#[clap(long, alias = "nymd_validators", value_delimiter = ',', hide = true)]
nyxd_urls: Option<Vec<url::Url>>,
/// Comma separated list of rest endpoints of the API validators
@@ -59,7 +59,7 @@ pub(crate) struct Run {
/// Set this client to work in a enabled credentials mode that would attempt to use gateway
/// with bandwidth credential requirement.
#[clap(long)]
#[clap(long, hide = true)]
enabled_credentials_mode: Option<bool>,
}
+2
View File
@@ -18,6 +18,7 @@ use client_core::client::key_manager::KeyManager;
use client_core::config::persistence::key_pathfinder::ClientKeyPathfinder;
use futures::channel::mpsc;
use futures::StreamExt;
#[cfg(not(feature = "mobile"))]
use gateway_client::bandwidth::BandwidthController;
use log::*;
use nymsphinx::addressing::clients::Recipient;
@@ -69,6 +70,7 @@ impl NymClient {
}
}
#[cfg(not(feature = "mobile"))]
async fn create_bandwidth_controller(config: &Config) -> BandwidthController<QueryNyxdClient> {
let details = network_defaults::NymNetworkDetails::new_from_env();
let mut client_config = validator_client::Config::try_from_nym_network_details(&details)
+2 -2
View File
@@ -43,7 +43,7 @@ pub(crate) struct Init {
force_register_gateway: bool,
/// Comma separated list of rest endpoints of the nyxd validators
#[clap(long, alias = "nymd_validators", value_delimiter = ',')]
#[clap(long, alias = "nymd_validators", value_delimiter = ',', hide = true)]
nyxd_urls: Option<Vec<url::Url>>,
/// Comma separated list of rest endpoints of the API validators
@@ -66,7 +66,7 @@ pub(crate) struct Init {
/// Set this client to work in a enabled credentials mode that would attempt to use gateway
/// with bandwidth credential requirement.
#[clap(long)]
#[clap(long, hide = true)]
enabled_credentials_mode: Option<bool>,
/// Save a summary of the initialization to a json file
+2 -2
View File
@@ -43,7 +43,7 @@ pub(crate) struct Run {
gateway: Option<identity::PublicKey>,
/// Comma separated list of rest endpoints of the nyxd validators
#[clap(long, alias = "nymd_validators", value_delimiter = ',')]
#[clap(long, alias = "nymd_validators", value_delimiter = ',', hide = true)]
nyxd_urls: Option<Vec<url::Url>>,
/// Comma separated list of rest endpoints of the Nym APIs
@@ -65,7 +65,7 @@ pub(crate) struct Run {
/// Set this client to work in a enabled credentials mode that would attempt to use gateway
/// with bandwidth credential requirement.
#[clap(long)]
#[clap(long, hide = true)]
enabled_credentials_mode: Option<bool>,
}
@@ -441,6 +441,7 @@ where
}
debug_assert!(self.connection.is_available());
log::trace!("Registering gateway");
// it's fine to instantiate it here as it's only used once (during authentication or registration)
// and putting it into the GatewayClient struct would be a hassle
@@ -934,16 +934,6 @@ impl NymApiClient {
Ok(self.nym_api_client.blind_sign(request_body).await?)
}
pub async fn partial_bandwidth_credential(
&self,
request_body: &str,
) -> Result<BlindedSignatureResponse, ValidatorClientError> {
Ok(self
.nym_api_client
.partial_bandwidth_credential(request_body)
.await?)
}
pub async fn verify_bandwidth_credential(
&self,
request_body: &VerifyCredentialBody,
@@ -449,23 +449,6 @@ impl Client {
.await
}
pub async fn partial_bandwidth_credential(
&self,
request_body: &str,
) -> Result<BlindedSignatureResponse, NymAPIError> {
self.post_nym_api(
&[
routes::API_VERSION,
routes::COCONUT_ROUTES,
routes::BANDWIDTH,
routes::COCONUT_PARTIAL_BANDWIDTH_CREDENTIAL,
],
NO_PARAMS,
request_body,
)
.await
}
pub async fn verify_bandwidth_credential(
&self,
request_body: &VerifyCredentialBody,
@@ -14,7 +14,6 @@ pub const COCONUT_ROUTES: &str = "coconut";
pub const BANDWIDTH: &str = "bandwidth";
pub const COCONUT_BLIND_SIGN: &str = "blind-sign";
pub const COCONUT_PARTIAL_BANDWIDTH_CREDENTIAL: &str = "partial-bandwidth-credential";
pub const COCONUT_VERIFY_BANDWIDTH_CREDENTIAL: &str = "verify-bandwidth-credential";
pub const STATUS_ROUTES: &str = "status";
@@ -114,6 +114,33 @@ impl Epoch {
finish_timestamp: current_timestamp.plus_seconds(duration),
}
}
pub fn final_timestamp_secs(&self) -> u64 {
let mut finish = self.finish_timestamp.seconds();
let time_configuration = self.time_configuration;
let mut curr_epoch_state = self.state;
while let Some(state) = curr_epoch_state.next() {
curr_epoch_state = state;
let adding = match curr_epoch_state {
EpochState::PublicKeySubmission { .. } => {
time_configuration.public_key_submission_time_secs
}
EpochState::DealingExchange { .. } => time_configuration.dealing_exchange_time_secs,
EpochState::VerificationKeySubmission { .. } => {
time_configuration.verification_key_submission_time_secs
}
EpochState::VerificationKeyValidation { .. } => {
time_configuration.verification_key_validation_time_secs
}
EpochState::VerificationKeyFinalization { .. } => {
time_configuration.verification_key_finalization_time_secs
}
EpochState::InProgress { .. } => 0,
};
finish += adding;
}
finish
}
}
// currently (it is still extremely likely to change, we might be able to get rid of verification key-related complaints),
@@ -195,4 +222,8 @@ impl EpochState {
states
}
pub fn is_final(&self) -> bool {
*self == EpochState::InProgress
}
}
+172 -38
View File
@@ -42,41 +42,9 @@ pub struct BandwidthVoucher {
encryption_key: encryption::PrivateKey,
pedersen_commitments_openings: Vec<Attribute>,
blind_sign_request: BlindSignRequest,
use_request: bool,
}
impl BandwidthVoucher {
pub fn new_with_blind_sign_req(
private_attributes: [PrivateAttribute; PRIVATE_ATTRIBUTES as usize],
public_attributes_plain: [&str; PUBLIC_ATTRIBUTES as usize],
tx_hash: Hash,
signing_key: identity::PrivateKey,
encryption_key: encryption::PrivateKey,
pedersen_commitments_openings: Vec<Attribute>,
blind_sign_request: BlindSignRequest,
) -> Self {
let voucher_value = public_attributes_plain[0];
let voucher_info = public_attributes_plain[1];
let voucher_value_plain = voucher_value.to_string();
let voucher_info_plain = voucher_info.to_string();
let voucher_value = hash_to_scalar(voucher_value.as_bytes());
let voucher_info = hash_to_scalar(voucher_info.as_bytes());
BandwidthVoucher {
serial_number: private_attributes[0],
binding_number: private_attributes[1],
voucher_value,
voucher_value_plain,
voucher_info,
voucher_info_plain,
tx_hash,
signing_key,
encryption_key,
pedersen_commitments_openings,
blind_sign_request,
use_request: false,
}
}
pub fn new(
params: &Parameters,
voucher_value: String,
@@ -109,10 +77,135 @@ impl BandwidthVoucher {
encryption_key,
pedersen_commitments_openings,
blind_sign_request,
use_request: true,
}
}
pub fn to_bytes(&self) -> Vec<u8> {
let serial_number_b = self.serial_number.to_bytes();
let binding_number_b = self.binding_number.to_bytes();
let voucher_value_plain_b = self.voucher_value_plain.as_bytes();
let voucher_info_plain_b = self.voucher_info_plain.as_bytes();
let tx_hash_b = self.tx_hash.as_bytes();
let signing_key_b = self.signing_key.to_bytes();
let encryption_key_b = self.encryption_key.to_bytes();
let blind_sign_request_b = self.blind_sign_request.to_bytes();
let mut ret = Vec::new();
ret.extend_from_slice(&serial_number_b);
ret.extend_from_slice(&binding_number_b);
ret.extend_from_slice(tx_hash_b);
ret.extend_from_slice(&signing_key_b);
ret.extend_from_slice(&encryption_key_b);
ret.extend_from_slice(&(voucher_value_plain_b.len() as u64).to_be_bytes());
ret.extend_from_slice(&(voucher_info_plain_b.len() as u64).to_be_bytes());
ret.extend_from_slice(&(blind_sign_request_b.len() as u64).to_be_bytes());
ret.extend_from_slice(&(self.pedersen_commitments_openings.len() as u64).to_be_bytes());
ret.extend_from_slice(voucher_value_plain_b);
ret.extend_from_slice(voucher_info_plain_b);
ret.extend_from_slice(&blind_sign_request_b);
for commitment in self.pedersen_commitments_openings.iter() {
ret.extend_from_slice(&commitment.to_bytes());
}
ret
}
pub fn try_from_bytes(bytes: &[u8]) -> Result<Self, Error> {
if bytes.len() < 32 * 5 + 4 * 8 {
return Err(Error::BandwidthVoucherDeserializationError(format!(
"Less then {} bytes needed",
32 * 5 + 4 * 8
)));
}
let mut buff = [0u8; 32];
let mut small_buff = [0u8; 8];
let scalar_err =
|| Error::BandwidthVoucherDeserializationError(String::from("Invalid Scalar"));
buff.copy_from_slice(&bytes[..32]);
let serial_number = Option::<PrivateAttribute>::from(PrivateAttribute::from_bytes(&buff))
.ok_or_else(scalar_err)?;
buff.copy_from_slice(&bytes[32..2 * 32]);
let binding_number = Option::<PrivateAttribute>::from(PrivateAttribute::from_bytes(&buff))
.ok_or_else(scalar_err)?;
buff.copy_from_slice(&bytes[2 * 32..3 * 32]);
let tx_hash = Hash::new(buff);
buff.copy_from_slice(&bytes[3 * 32..4 * 32]);
let signing_key = identity::PrivateKey::from_bytes(&buff).map_err(|_| {
Error::BandwidthVoucherDeserializationError(String::from("Invalid key"))
})?;
buff.copy_from_slice(&bytes[4 * 32..5 * 32]);
let encryption_key = encryption::PrivateKey::from_bytes(&buff).map_err(|_| {
Error::BandwidthVoucherDeserializationError(String::from("Invalid key"))
})?;
small_buff.copy_from_slice(&bytes[5 * 32..5 * 32 + 8]);
let voucher_value_plain_no = u64::from_be_bytes(small_buff) as usize;
small_buff.copy_from_slice(&bytes[5 * 32 + 8..5 * 32 + 2 * 8]);
let voucher_info_plain_no = u64::from_be_bytes(small_buff) as usize;
small_buff.copy_from_slice(&bytes[5 * 32 + 2 * 8..5 * 32 + 3 * 8]);
let blind_sign_request_no = u64::from_be_bytes(small_buff) as usize;
small_buff.copy_from_slice(&bytes[5 * 32 + 3 * 8..5 * 32 + 4 * 8]);
let pedersen_commitments_openings_no = u64::from_be_bytes(small_buff) as usize;
let total_length = 32 * 5
+ 4 * 8
+ voucher_value_plain_no
+ voucher_info_plain_no
+ blind_sign_request_no
+ pedersen_commitments_openings_no * 32;
if bytes.len() != total_length {
return Err(Error::BandwidthVoucherDeserializationError(format!(
"Expected {total_length} bytes",
)));
}
let utf_err = |_| {
Err(Error::BandwidthVoucherDeserializationError(String::from(
"Invalid UTF8 string",
)))
};
let mut var_length_pointer = 5 * 32 + 4 * 8;
let voucher_value_plain = String::from_utf8(
bytes[var_length_pointer..var_length_pointer + voucher_value_plain_no].to_vec(),
)
.or_else(utf_err)?;
let voucher_value = hash_to_scalar(&voucher_value_plain);
var_length_pointer += voucher_value_plain_no;
let voucher_info_plain = String::from_utf8(
bytes[var_length_pointer..var_length_pointer + voucher_info_plain_no].to_vec(),
)
.or_else(utf_err)?;
let voucher_info = hash_to_scalar(&voucher_info_plain);
var_length_pointer += voucher_info_plain_no;
let blind_sign_request = BlindSignRequest::from_bytes(
&bytes[var_length_pointer..var_length_pointer + blind_sign_request_no],
)?;
var_length_pointer += blind_sign_request_no;
let mut pedersen_commitments_openings = Vec::new();
for _ in 0..pedersen_commitments_openings_no {
buff.copy_from_slice(&bytes[var_length_pointer..var_length_pointer + 32]);
let commitment =
Option::<Attribute>::from(Attribute::from_bytes(&buff)).ok_or_else(scalar_err)?;
var_length_pointer += 32;
pedersen_commitments_openings.push(commitment);
}
Ok(Self {
serial_number,
binding_number,
voucher_value,
voucher_value_plain,
voucher_info,
voucher_info_plain,
tx_hash,
signing_key,
encryption_key,
pedersen_commitments_openings,
blind_sign_request,
})
}
/// Check if the plain values correspond to the PublicAttributes
pub fn verify_against_plain(values: &[PublicAttribute], plain_values: &[String]) -> bool {
values.len() == 2
@@ -141,8 +234,8 @@ impl BandwidthVoucher {
&self.blind_sign_request
}
pub fn use_request(&self) -> bool {
self.use_request
pub fn get_voucher_value(&self) -> String {
self.voucher_value_plain.clone()
}
pub fn get_public_attributes_plain(&self) -> Vec<String> {
@@ -189,13 +282,13 @@ pub fn prepare_for_spending(
#[cfg(test)]
mod test {
use super::*;
use coconut_interface::Base58;
use rand::rngs::OsRng;
#[test]
fn voucher_consistency() {
fn voucher_fixture() -> BandwidthVoucher {
let params = Parameters::new(4).unwrap();
let mut rng = OsRng;
let voucher = BandwidthVoucher::new(
BandwidthVoucher::new(
&params,
"1234".to_string(),
"voucher info".to_string(),
@@ -210,7 +303,48 @@ mod test {
&encryption::KeyPair::new(&mut rng).private_key().to_bytes(),
)
.unwrap(),
)
}
#[test]
fn serde_voucher() {
let voucher = voucher_fixture();
let bytes = voucher.to_bytes();
let deserialized_voucher = BandwidthVoucher::try_from_bytes(&bytes).unwrap();
assert_eq!(voucher.serial_number, deserialized_voucher.serial_number);
assert_eq!(voucher.binding_number, deserialized_voucher.binding_number);
assert_eq!(voucher.voucher_value, deserialized_voucher.voucher_value);
assert_eq!(
voucher.voucher_value_plain,
deserialized_voucher.voucher_value_plain
);
assert_eq!(voucher.voucher_info, deserialized_voucher.voucher_info);
assert_eq!(
voucher.voucher_info_plain,
deserialized_voucher.voucher_info_plain
);
assert_eq!(voucher.tx_hash, deserialized_voucher.tx_hash);
assert_eq!(
voucher.signing_key.to_string(),
deserialized_voucher.signing_key.to_string()
);
assert_eq!(
voucher.encryption_key.to_string(),
deserialized_voucher.encryption_key.to_string()
);
assert_eq!(
voucher.pedersen_commitments_openings,
deserialized_voucher.pedersen_commitments_openings
);
assert_eq!(
voucher.blind_sign_request.to_bs58(),
deserialized_voucher.blind_sign_request.to_bs58()
);
}
#[test]
fn voucher_consistency() {
let voucher = voucher_fixture();
assert!(!BandwidthVoucher::verify_against_plain(
&[],
&voucher.get_public_attributes_plain()
+13 -24
View File
@@ -45,21 +45,15 @@ async fn obtain_partial_credential(
let private_attributes = attributes.get_private_attributes();
let blind_sign_request = attributes.blind_sign_request();
let response = if attributes.use_request() {
let blind_sign_request_body = BlindSignRequestBody::new(
blind_sign_request,
attributes.tx_hash().to_string(),
attributes.sign(blind_sign_request).to_base58_string(),
&public_attributes,
public_attributes_plain,
(public_attributes.len() + private_attributes.len()) as u32,
);
client.blind_sign(&blind_sign_request_body).await?
} else {
client
.partial_bandwidth_credential(&attributes.tx_hash().to_string())
.await?
};
let blind_sign_request_body = BlindSignRequestBody::new(
blind_sign_request,
attributes.tx_hash().to_string(),
attributes.sign(blind_sign_request).to_base58_string(),
&public_attributes,
public_attributes_plain,
(public_attributes.len() + private_attributes.len()) as u32,
);
let response = client.blind_sign(&blind_sign_request_body).await?;
let encrypted_signature = response.encrypted_signature;
let remote_key = PublicKey::from_bytes(&response.remote_key)?;
@@ -109,6 +103,8 @@ pub async fn obtain_aggregate_signature(
.iter()
.map(|api_client| api_client.node_id)
.collect();
let verification_key =
aggregate_verification_keys(&validators_partial_vks, Some(indices.as_ref()))?;
for coconut_api_client in coconut_api_clients.iter() {
if let Ok(signature) = obtain_partial_credential(
@@ -131,15 +127,8 @@ pub async fn obtain_aggregate_signature(
attributes.extend_from_slice(&private_attributes);
attributes.extend_from_slice(&public_attributes);
let verification_key =
aggregate_verification_keys(&validators_partial_vks, Some(indices.as_ref()))?;
Ok(aggregate_signature_shares(
params,
&verification_key,
&attributes,
&shares,
)?)
aggregate_signature_shares(params, &verification_key, &attributes, &shares)
.map_err(Error::SignatureAggregationError)
}
// TODO: better type flow
+10 -1
View File
@@ -9,6 +9,9 @@ use thiserror::Error;
#[derive(Debug, Error)]
pub enum Error {
#[error("IO error")]
IOError(#[from] std::io::Error),
#[error("The detailed description is yet to be determined")]
BandwidthCredentialError,
@@ -30,6 +33,12 @@ pub enum Error {
#[error("Could not parse the key - {0}")]
ParsePublicKey(#[from] KeyRecoveryError),
#[error("Could not gather enough signature shares")]
#[error("Could not gather enough signature shares. Try again using the recovery command")]
NotEnoughShares,
#[error("Could not aggregate signature shares - {0}. Try again using the recovery command")]
SignatureAggregationError(CoconutError),
#[error("Could not deserialize bandwidth voucher - {0}")]
BandwidthVoucherDeserializationError(String),
}
-3
View File
@@ -33,9 +33,6 @@ criterion = { version="0.3", features=["html_reports"] }
doc-comment = "0.3"
rand_chacha = "0.3"
[dev-dependencies.bincode]
version = "1"
[[bench]]
name = "benchmarks"
harness = false
+5
View File
@@ -27,6 +27,11 @@ topology = { path = "../topology" }
[dev-dependencies]
mixnet-contract-common = { path = "../cosmwasm-smart-contracts/mixnet-contract" }
criterion = "0.3"
[[bench]]
name = "benchmarks"
harness = false
# do not include this when compiling into wasm as it somehow when combined together with reqwest, it will require
# net2 via tokio-util -> tokio -> mio -> net2
+269
View File
@@ -0,0 +1,269 @@
use std::borrow::Borrow;
use std::collections::HashMap;
use std::sync::Arc;
use std::time::Duration;
use criterion::{black_box, Criterion, criterion_group, criterion_main};
use crypto::asymmetric::{encryption, identity};
use crypto::asymmetric::encryption::{KeyPair, PrivateKey};
use crypto::asymmetric::identity::PublicKey;
use mixnet_contract_common::Layer;
use nymsphinx::{delays, Node, NODE_ADDRESS_LENGTH, NodeAddressBytes, NymsphinxPayloadBuilder, PAYLOAD_OVERHEAD_SIZE, SphinxPacket};
use nymsphinx::acknowledgements::AckKey;
use nymsphinx::acknowledgements::surb_ack::SurbAck;
use nymsphinx::addressing::clients::Recipient;
use nymsphinx::builder::SphinxPacketBuilder;
use nymsphinx::chunking::fragment::{Fragment, FragmentHeader, FragmentIdentifier};
use nymsphinx::cover::generate_loop_cover_packet;
use nymsphinx::crypto::keygen;
use nymsphinx::params::packet_sizes::PacketSize::{ExtendedPacket16, ExtendedPacket32, ExtendedPacket8, RegularPacket};
use nymsphinx::params::PacketSize;
use topology::{gateway, mix, MixLayer, NymTopology};
const REGULAR_PACKET_SIZE: usize = PAYLOAD_OVERHEAD_SIZE + 2 * 1024;
const EXTENDED_PACKET_SIZE_8: usize = PAYLOAD_OVERHEAD_SIZE + 8 * 1024;
const EXTENDED_PACKET_SIZE_16: usize = PAYLOAD_OVERHEAD_SIZE + 16 * 1024;
const EXTENDED_PACKET_SIZE_32: usize = PAYLOAD_OVERHEAD_SIZE + 32 * 1024;
struct BenchCase {
packet_size: PacketSize,
}
fn feature_topology(sender_gateway_id: PublicKey, recipient_gateway_id: PublicKey) -> (NymTopology, KeyPair) {
let mut rng = rand::thread_rng();
let gateway1 = gateway::Node {
owner: "N/A".to_string(),
stake: 1000,
location: "N/A".to_string(),
host: "1.1.1.1".parse().unwrap(),
mix_host: "1.1.1.1:1789".parse().unwrap(),
clients_port: 8888,
identity_key: sender_gateway_id,
sphinx_key: encryption::PublicKey::from_base58_string(
"C7cown6dYCLZpLiMFC1PaBmhvLvmJmLDJGeRTbPD45bX",
)
.unwrap(),
version: "0.x.0".to_string(),
};
let gateway2 = gateway::Node {
identity_key: recipient_gateway_id,
..gateway1.clone()
};
let node1_enc_keys = KeyPair::new(&mut rng);
let node1 = mix::Node {
mix_id: 42,
owner: "N/A".to_string(),
host: "3.3.3.3".parse().unwrap(),
mix_host: "3.3.3.3:1789".parse().unwrap(),
identity_key: identity::PublicKey::from_base58_string(
"3ebjp1Fb9hdcS1AR6AZihgeJiMHkB5jjJUsvqNnfQwU7",
)
.unwrap(),
sphinx_key: *node1_enc_keys.public_key(),
layer: Layer::One,
version: "0.x.0".to_string(),
};
let node2 = mix::Node {
owner: "Alice".to_string(),
..node1.clone()
};
let node3 = mix::Node {
owner: "Bob".to_string(),
..node1.clone()
};
let mut mixes: HashMap<MixLayer, Vec<mix::Node>> = HashMap::new();
mixes.insert(1, vec![node1]);
mixes.insert(2, vec![node2]);
mixes.insert(3, vec![node3]);
let topology = NymTopology::new(mixes, vec![gateway1, gateway2]);
(topology, node1_enc_keys)
}
fn make_packet_copy(packet: &SphinxPacket) -> SphinxPacket {
SphinxPacket::from_bytes(&packet.to_bytes()).unwrap()
}
fn bench_loop_packet_create(c: &mut Criterion) {
let mut group = c.benchmark_group("benchmark-sphinx");
// group.sample_size(200);
group.measurement_time(Duration::from_secs(500));
let mut rng = rand::thread_rng();
let case = BenchCase {
packet_size: RegularPacket,
};
// create sender
let sender_client_id_pair = identity::KeyPair::new(&mut rng);
let sender_client_enc_pair = encryption::KeyPair::new(&mut rng);
let sender_gateway_id_pair = identity::KeyPair::new(&mut rng);
let packet_sender = Recipient::new(
*sender_client_id_pair.public_key(),
*sender_client_enc_pair.public_key(),
*sender_gateway_id_pair.public_key(),
);
// build topology
let (topology, node_keypair) = feature_topology(*sender_gateway_id_pair.public_key(), *sender_gateway_id_pair.public_key());
// generate the encryption key for the ack
let ack_key = AckKey::new(&mut rng);
group.bench_function(
&format!(
"[Sphinx] create_loop_cover_packet_with_payload_size_{}",
case.packet_size.payload_size(),
),
|b| {
b.iter(|| {
generate_loop_cover_packet(
&mut rng,
&topology,
&ack_key,
&packet_sender,
Duration::from_millis(50),
Duration::from_millis(50),
case.packet_size)
})
},
);
// let's create the packet to later benchmark the processing
let packet = generate_loop_cover_packet(
&mut rng,
&topology,
&ack_key,
&packet_sender,
Duration::from_millis(50),
Duration::from_millis(50),
case.packet_size).unwrap();
group.bench_function(
&format!(
"[Sphinx] process_loop_cover_packet_with_payload_size_{}",
case.packet_size.payload_size(),
),
|b| {
b.iter(|| {
make_packet_copy(&packet.sphinx_packet).process(&node_keypair.private_key().into())
})
},
);
// let new_packet = packet.sphinx_packet.process(&node_keypair.private_key().into());
}
fn bench_new_no_surb(c: &mut Criterion) {
let mut group = c.benchmark_group("benchmark-sphinx");
// group.sample_size(200);
group.measurement_time(Duration::from_secs(500));
let mut rng = rand::thread_rng();
let case = BenchCase {
packet_size: ExtendedPacket8,
};
// create sender
let sender_client_id_pair = identity::KeyPair::new(&mut rng);
let sender_client_enc_pair = encryption::KeyPair::new(&mut rng);
let sender_gateway_id_pair = identity::KeyPair::new(&mut rng);
let packet_sender = Recipient::new(
*sender_client_id_pair.public_key(),
*sender_client_enc_pair.public_key(),
*sender_gateway_id_pair.public_key(),
);
// create recipient
let recipient_client_id_pair = identity::KeyPair::new(&mut rng);
let recipient_client_enc_pair = encryption::KeyPair::new(&mut rng);
let recipient_gateway_id_pair = identity::KeyPair::new(&mut rng);
let packet_recipient = Recipient::new(
*recipient_client_id_pair.public_key(),
*recipient_client_enc_pair.public_key(),
*recipient_gateway_id_pair.public_key(),
);
// build topology
let (topology, node_keypair) = feature_topology(*sender_gateway_id_pair.public_key(), *recipient_gateway_id_pair.public_key());
// generate pseudorandom route for the packet
let route = topology.random_route_to_gateway(
&mut rng,
3,
packet_recipient.gateway(),
).unwrap();
// generate some payload
let mlen = 40;
let mut msg = vec![0u8; mlen];
let fragment = Fragment {
header: FragmentHeader::try_new(
12345,
u8::max_value(),
u8::max_value(),
None,
Some(1234),
)
.unwrap(),
payload: msg,
};
let ack_key = AckKey::new(&mut rng);
let surb_ack = SurbAck::construct(
&mut rng,
&packet_sender,
&ack_key,
fragment.fragment_identifier().to_bytes(),
Duration::from_millis(50),
&topology,
).unwrap();
let packet_payload = NymsphinxPayloadBuilder::new(fragment, surb_ack)
.build_regular(&mut rng, packet_recipient.encryption_key());
let delays = delays::generate_from_average_duration(route.len(), Duration::from_millis(50));
let destination = packet_recipient.as_sphinx_destination();
group.bench_function(
&format!(
"[Sphinx] create_packet_no_reply_surbs_with_payload_size_{}",
case.packet_size.payload_size(),
),
|b| {
b.iter(|| {
SphinxPacketBuilder::new()
.with_payload_size(case.packet_size.payload_size())
.build_packet(packet_payload.clone(), &route, &destination, &delays)
})
},
);
// let's create the packet to later benchmark the processing
let sphinx_packet = SphinxPacketBuilder::new()
.with_payload_size(case.packet_size.payload_size())
.build_packet(packet_payload.clone(), &route, &destination, &delays)
.unwrap();
group.bench_function(
&format!(
"[Sphinx] process_packet_with_payload_size_{}",
case.packet_size.payload_size(),
),
|b| {
b.iter(|| {
make_packet_copy(&sphinx_packet).process(&node_keypair.private_key().into())
})
},
);
}
criterion_group!(sphinx, bench_loop_packet_create, bench_new_no_surb);
criterion_main!(sphinx);
+39 -35
View File
@@ -1,11 +1,13 @@
// Copyright 2021-2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::ChunkingError;
use nymsphinx_params::{SerializedFragmentIdentifier, FRAG_ID_LEN};
use std::convert::TryInto;
use std::fmt::{self, Debug, Formatter};
use nymsphinx_params::{FRAG_ID_LEN, SerializedFragmentIdentifier};
use crate::ChunkingError;
// Personal reflection: In hindsight I've spent too much time on relatively too little
// gain here, as even though I might have saved couple of bytes per packet, the gain
// is negligible in the context of having to include SURB-ACKs and reply-SURBs in the packets.
@@ -110,8 +112,8 @@ impl FragmentIdentifier {
/// header used to reconstruct the message after being received.
#[derive(PartialEq, Clone)]
pub struct Fragment {
header: FragmentHeader,
payload: Vec<u8>,
pub header: FragmentHeader,
pub payload: Vec<u8>,
}
// manual implementation to hide detailed payload that we don't care about
@@ -290,7 +292,7 @@ impl Fragment {
/// and for the longest messages, without upper bound, there is usually also only 7 bytes
/// of overhead apart from first and last fragments in each set that instead have 10 bytes of overhead.
#[derive(PartialEq, Clone, Debug)]
pub(crate) struct FragmentHeader {
pub struct FragmentHeader {
/// ID associated with `FragmentSet` to which this particular `Fragment` belongs.
/// Its value is restricted to (0, i32::max_value()].
/// Note that it *excludes* 0, but *includes* i32::max_value().
@@ -319,7 +321,7 @@ impl FragmentHeader {
/// Tries to create a new `FragmentHeader` using provided metadata. Bunch of logical
/// checks are performed to see if the data is not self-contradictory,
/// for example if current_fragment > total_fragments.
fn try_new(
pub fn try_new(
id: i32,
total_fragments: u8,
current_fragment: u8,
@@ -460,9 +462,11 @@ impl FragmentHeader {
#[cfg(test)]
mod fragment_tests {
use super::*;
use rand::{RngCore, thread_rng};
use nymsphinx_params::packet_sizes::PacketSize;
use rand::{thread_rng, RngCore};
use super::*;
fn max_plaintext_size() -> usize {
PacketSize::default().plaintext_size() - PacketSize::AckPacket.size()
@@ -585,7 +589,7 @@ mod fragment_tests {
None,
Some(1234),
)
.unwrap(),
.unwrap(),
payload: msg,
};
let packet_bytes = fragment.clone().into_bytes();
@@ -602,7 +606,7 @@ mod fragment_tests {
None,
Some(1234),
)
.unwrap(),
.unwrap(),
payload: msg,
};
let packet_bytes = fragment.clone().into_bytes();
@@ -644,7 +648,7 @@ mod fragment_tests {
None,
max_plaintext_size(),
)
.is_ok());
.is_ok());
assert!(Fragment::try_new(
&non_full_payload,
id,
@@ -654,7 +658,7 @@ mod fragment_tests {
None,
max_plaintext_size(),
)
.is_ok());
.is_ok());
assert!(Fragment::try_new(
&non_full_payload2,
@@ -665,7 +669,7 @@ mod fragment_tests {
None,
max_plaintext_size(),
)
.is_ok());
.is_ok());
assert!(Fragment::try_new(
&non_full_payload2,
id,
@@ -675,7 +679,7 @@ mod fragment_tests {
None,
max_plaintext_size(),
)
.is_ok());
.is_ok());
}
#[test]
@@ -697,7 +701,7 @@ mod fragment_tests {
None,
max_plaintext_size(),
)
.is_err());
.is_err());
assert!(Fragment::try_new(
&non_full_payload,
id,
@@ -707,7 +711,7 @@ mod fragment_tests {
None,
max_plaintext_size(),
)
.is_err());
.is_err());
assert!(Fragment::try_new(
&too_much_payload,
@@ -718,7 +722,7 @@ mod fragment_tests {
None,
max_plaintext_size(),
)
.is_err());
.is_err());
assert!(Fragment::try_new(
&too_much_payload,
id,
@@ -728,7 +732,7 @@ mod fragment_tests {
None,
max_plaintext_size(),
)
.is_err());
.is_err());
assert!(Fragment::try_new(
&too_much_payload,
id,
@@ -738,7 +742,7 @@ mod fragment_tests {
None,
max_plaintext_size(),
)
.is_err());
.is_err());
assert!(Fragment::try_new(
&non_full_payload2,
@@ -749,7 +753,7 @@ mod fragment_tests {
None,
max_plaintext_size(),
)
.is_err());
.is_err());
assert!(Fragment::try_new(
&non_full_payload2,
id,
@@ -759,7 +763,7 @@ mod fragment_tests {
None,
max_plaintext_size(),
)
.is_err());
.is_err());
}
#[test]
@@ -780,7 +784,7 @@ mod fragment_tests {
None,
max_plaintext_size(),
)
.is_ok());
.is_ok());
assert!(Fragment::try_new(
&full_payload,
id,
@@ -790,7 +794,7 @@ mod fragment_tests {
None,
max_plaintext_size(),
)
.is_ok());
.is_ok());
assert!(Fragment::try_new(
&non_full_payload,
id,
@@ -800,7 +804,7 @@ mod fragment_tests {
None,
max_plaintext_size(),
)
.is_ok());
.is_ok());
assert!(Fragment::try_new(
&non_full_payload2,
id,
@@ -810,7 +814,7 @@ mod fragment_tests {
None,
max_plaintext_size(),
)
.is_ok());
.is_ok());
assert!(Fragment::try_new(
&full_payload,
@@ -821,7 +825,7 @@ mod fragment_tests {
Some(link_id),
max_plaintext_size(),
)
.is_ok());
.is_ok());
}
#[test]
@@ -842,7 +846,7 @@ mod fragment_tests {
None,
max_plaintext_size(),
)
.is_err());
.is_err());
assert!(Fragment::try_new(
&non_full_payload2,
id,
@@ -852,7 +856,7 @@ mod fragment_tests {
None,
max_plaintext_size(),
)
.is_err());
.is_err());
assert!(Fragment::try_new(
&too_much_payload,
id,
@@ -862,7 +866,7 @@ mod fragment_tests {
None,
max_plaintext_size(),
)
.is_err());
.is_err());
assert!(Fragment::try_new(
&too_much_payload,
id,
@@ -872,7 +876,7 @@ mod fragment_tests {
None,
max_plaintext_size(),
)
.is_err());
.is_err());
assert!(Fragment::try_new(
&non_full_payload,
@@ -883,7 +887,7 @@ mod fragment_tests {
Some(link_id),
max_plaintext_size(),
)
.is_err());
.is_err());
assert!(Fragment::try_new(
&non_full_payload2,
id,
@@ -893,7 +897,7 @@ mod fragment_tests {
Some(link_id),
max_plaintext_size(),
)
.is_err());
.is_err());
assert!(Fragment::try_new(
&too_much_payload,
@@ -904,7 +908,7 @@ mod fragment_tests {
Some(link_id),
max_plaintext_size(),
)
.is_err());
.is_err());
}
}
@@ -1008,7 +1012,7 @@ mod fragment_header {
None,
Some(0),
)
.is_err());
.is_err());
}
#[test]
@@ -1066,7 +1070,7 @@ mod fragment_header {
None,
Some(1234),
)
.is_ok());
.is_ok());
assert!(FragmentHeader::try_new(12345, 10, 2, Some(1234), None).is_err());
}
+4 -3
View File
@@ -1,11 +1,12 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use std::convert::TryFrom;
use std::fmt::{self, Debug, Display, Formatter};
use nymsphinx_addressing::nodes::{NymNodeRoutingAddress, NymNodeRoutingAddressError};
use nymsphinx_params::{PacketMode, PacketSize};
use nymsphinx_types::SphinxPacket;
use std::convert::TryFrom;
use std::fmt::{self, Debug, Display, Formatter};
#[derive(Debug)]
pub enum MixPacketFormattingError {
@@ -46,7 +47,7 @@ impl From<NymNodeRoutingAddressError> for MixPacketFormattingError {
pub struct MixPacket {
next_hop: NymNodeRoutingAddress,
sphinx_packet: SphinxPacket,
pub sphinx_packet: SphinxPacket,
packet_mode: PacketMode,
}
+8 -6
View File
@@ -1,6 +1,8 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use rand::{CryptoRng, RngCore};
use crypto::aes::cipher::{KeyIvInit, StreamCipher};
use crypto::asymmetric::encryption;
use crypto::shared_key::new_ephemeral_shared_key;
@@ -12,7 +14,6 @@ use nymsphinx_chunking::fragment::Fragment;
use nymsphinx_params::{
PacketEncryptionAlgorithm, PacketHkdfAlgorithm, ReplySurbEncryptionAlgorithm,
};
use rand::{CryptoRng, RngCore};
pub struct NymsphinxPayloadBuilder {
fragment: Fragment,
@@ -27,10 +28,10 @@ impl NymsphinxPayloadBuilder {
fn build<C>(
self,
packet_encryption_key: &CipherKey<C>,
variant_data: impl IntoIterator<Item = u8>,
variant_data: impl IntoIterator<Item=u8>,
) -> NymsphinxPayload
where
C: StreamCipher + KeyIvInit,
where
C: StreamCipher + KeyIvInit,
{
let (_, surb_ack_bytes) = self.surb_ack.prepare_for_sending();
@@ -68,8 +69,8 @@ impl NymsphinxPayloadBuilder {
rng: &mut R,
recipient_encryption_key: &encryption::PublicKey,
) -> NymsphinxPayload
where
R: RngCore + CryptoRng,
where
R: RngCore + CryptoRng,
{
// create keys for 'payload' encryption
let (ephemeral_keypair, shared_key) = new_ephemeral_shared_key::<
@@ -88,6 +89,7 @@ impl NymsphinxPayloadBuilder {
// the actual byte data that will be put into the sphinx packet paylaod.
// no more transformations are going to happen to it
// TODO: use that fact for some better compile time assertions
#[derive(Clone)]
pub struct NymsphinxPayload(Vec<u8>);
impl AsRef<[u8]> for NymsphinxPayload {
+10
View File
@@ -1,5 +1,15 @@
## UNRELEASED
- nothing yet
## [nym-explorer-v1.0.5](https://github.com/nymtech/nym/tree/nym-explorer-v1.0.5) (2023-02-07)
- NE - link `Owner` field on the node detail page to the account details on NG explorer ([#2923])
- NE - Upgrade Sandbox and make below changes: ([#2332])
[#2923]: https://github.com/nymtech/nym/issues/2923
[#2332]: https://github.com/nymtech/nym/issues/2332
## [nym-explorer-v1.0.4](https://github.com/nymtech/nym/tree/nym-explorer-v1.0.4) (2023-01-31)
- Add routing score on gateway list ([#2913])
+11 -1
View File
@@ -1,5 +1,5 @@
import * as React from 'react';
import { Paper, Table, TableBody, TableCell, TableContainer, TableHead, TableRow } from '@mui/material';
import { Link, Paper, Table, TableBody, TableCell, TableContainer, TableHead, TableRow } from '@mui/material';
import { useTheme } from '@mui/material/styles';
import { Tooltip } from '@nymproject/react/tooltip/Tooltip';
import { CopyToClipboard } from '@nymproject/react/clipboard/CopyToClipboard';
@@ -37,9 +37,19 @@ function formatCellValues(val: string | number, field: string) {
</Box>
);
}
if (field === 'bond') {
return unymToNym(val, 6);
}
if (field === 'owner') {
return (
<Link underline="none" color="inherit" target="_blank" href={`https://mixnet.explorers.guru/account/${val}`}>
{val}
</Link>
);
}
return val;
}
+3 -2
View File
@@ -55,7 +55,8 @@ pub struct Init {
long,
alias = "validators",
alias = "nymd_validators",
value_delimiter = ','
value_delimiter = ',',
hide = true
)]
// the alias here is included for backwards compatibility (1.1.4 and before)
nyxd_urls: Option<Vec<url::Url>>,
@@ -66,7 +67,7 @@ pub struct Init {
/// Set this gateway to work only with coconut credentials; that would disallow clients to
/// bypass bandwidth credential requirement
#[clap(long)]
#[clap(long, hide = true)]
only_coconut_credentials: Option<bool>,
/// Enable/disable gateway anonymized statistics that get sent to a statistics aggregator server
+3 -2
View File
@@ -53,7 +53,8 @@ pub struct Run {
long,
alias = "validators",
alias = "nymd_validators",
value_delimiter = ','
value_delimiter = ',',
hide = true
)]
// the alias here is included for backwards compatibility (1.1.4 and before)
nyxd_urls: Option<Vec<url::Url>>,
@@ -64,7 +65,7 @@ pub struct Run {
/// Set this gateway to work only with coconut credentials; that would disallow clients to
/// bypass bandwidth credential requirement
#[clap(long)]
#[clap(long, hide = true)]
only_coconut_credentials: Option<bool>,
/// Enable/disable gateway anonymized statistics that get sent to a statistics aggregator server
@@ -181,6 +181,7 @@ impl<St: Storage> ConnectionHandler<St> {
mut shutdown: TaskClient,
) {
debug!("Starting connection handler for {:?}", remote);
shutdown.mark_as_success();
let mut framed_conn = Framed::new(conn, SphinxCodec);
while !shutdown.is_shutdown() {
tokio::select! {
+3 -2
View File
@@ -4,7 +4,8 @@
"nym-wallet",
"nym-connect",
"nym-connect-android",
"sdk/typescript/**"
"sdk/typescript/examples/docs",
"sdk/typescript/packages/**"
],
"version": "0.0.0"
}
}
@@ -77,6 +77,7 @@ impl ConnectionHandler {
mut shutdown: TaskClient,
) {
debug!("Starting connection handler for {:?}", remote);
shutdown.mark_as_success();
let mut framed_conn = Framed::new(conn, SphinxCodec);
while !shutdown.is_shutdown() {
tokio::select! {
+1 -1
View File
@@ -3,7 +3,7 @@
[package]
name = "nym-api"
version = "1.1.8"
version = "1.1.9"
authors = [
"Dave Hrycyszyn <futurechimp@users.noreply.github.com>",
"Jędrzej Stuczyński <andrew@nymtech.net>",
+5 -1
View File
@@ -15,7 +15,11 @@ pub(crate) mod routes;
/// Merges the routes with http information and returns it to Rocket for serving
pub(crate) fn circulating_supply_routes(settings: &OpenApiSettings) -> (Vec<Route>, OpenApi) {
openapi_get_routes_spec![settings: routes::get_circulating_supply]
openapi_get_routes_spec![
settings: routes::get_full_circulating_supply,
routes::get_total_supply,
routes::get_circulating_supply
]
}
/// Spawn the circulating supply cache refresher.
+59 -4
View File
@@ -1,15 +1,30 @@
use rocket::http::Status;
use rocket::serde::json::Json;
use rocket::State;
// Copyright 2022-2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::circulating_supply_api::cache::CirculatingSupplyCache;
use crate::node_status_api::models::ErrorResponse;
use nym_api_requests::models::CirculatingSupplyResponse;
use rocket::http::Status;
use rocket::serde::json::Json;
use rocket::State;
use rocket_okapi::openapi;
use validator_client::nyxd::Coin;
// TODO: this is not the best place to put it, it should be more centralised,
// but for a quick fix, that's good enough for now...
// (for proper solution we should be managing `NymNetworkDetails` via rocket and grabbing display exponent
// value from the mix denom here.
const UNYM_RATIO: f64 = 1000000.;
fn unym_coin_to_float_unym(coin: Coin) -> f64 {
// our total supply can't exceed 1B so an overflow here is impossible
// (if it happened, then we SHOULD crash)
coin.amount as f64 / UNYM_RATIO
}
#[openapi(tag = "circulating-supply")]
#[get("/circulating-supply")]
pub(crate) async fn get_circulating_supply(
pub(crate) async fn get_full_circulating_supply(
cache: &State<CirculatingSupplyCache>,
) -> Result<Json<CirculatingSupplyResponse>, ErrorResponse> {
match cache.get_circulating_supply().await {
@@ -20,3 +35,43 @@ pub(crate) async fn get_circulating_supply(
)),
}
}
#[openapi(tag = "circulating-supply")]
#[get("/circulating-supply/total-supply-value")]
pub(crate) async fn get_total_supply(
cache: &State<CirculatingSupplyCache>,
) -> Result<Json<f64>, ErrorResponse> {
let full_circulating_supply = match cache.get_circulating_supply().await {
Some(res) => res,
None => {
return Err(ErrorResponse::new(
"unavailable",
Status::InternalServerError,
))
}
};
Ok(Json(unym_coin_to_float_unym(
full_circulating_supply.total_supply.into(),
)))
}
#[openapi(tag = "circulating-supply")]
#[get("/circulating-supply/circulating-supply-value")]
pub(crate) async fn get_circulating_supply(
cache: &State<CirculatingSupplyCache>,
) -> Result<Json<f64>, ErrorResponse> {
let full_circulating_supply = match cache.get_circulating_supply().await {
Some(res) => res,
None => {
return Err(ErrorResponse::new(
"unavailable",
Status::InternalServerError,
))
}
};
Ok(Json(unym_coin_to_float_unym(
full_circulating_supply.circulating_supply.into(),
)))
}
-3
View File
@@ -70,9 +70,6 @@ pub enum CoconutError {
)]
DifferentPublicAttributes(String, String),
#[error("No signature found")]
NoSignature,
#[error("Error in coconut interface - {0}")]
CoconutInterfaceError(#[from] coconut_interface::error::CoconutInterfaceError),
+1 -17
View File
@@ -182,11 +182,7 @@ impl InternalSignRequest {
rocket.manage(state).mount(
// this format! is so ugly...
format!("/{}/{}/{}", NYM_API_VERSION, COCONUT_ROUTES, BANDWIDTH),
routes![
post_blind_sign,
post_partial_bandwidth_credential,
verify_bandwidth_credential
],
routes![post_blind_sign, verify_bandwidth_credential],
)
})
}
@@ -242,18 +238,6 @@ pub async fn post_blind_sign(
Ok(Json(response))
}
#[post("/partial-bandwidth-credential", data = "<tx_hash>")]
pub async fn post_partial_bandwidth_credential(
tx_hash: Json<String>,
state: &RocketState<State>,
) -> Result<Json<BlindedSignatureResponse>> {
let v = state
.signed_before(&tx_hash)
.await?
.ok_or(CoconutError::NoSignature)?;
Ok(Json(v))
}
#[post("/verify-bandwidth-credential", data = "<verify_credential_body>")]
pub async fn verify_bandwidth_credential(
verify_credential_body: Json<VerifyCredentialBody>,
+1 -72
View File
@@ -27,8 +27,7 @@ use nymcoconut::{
prepare_blind_sign, ttp_keygen, Base58, BlindSignRequest, BlindedSignature, Parameters,
};
use validator_client::nym_api::routes::{
API_VERSION, BANDWIDTH, COCONUT_BLIND_SIGN, COCONUT_PARTIAL_BANDWIDTH_CREDENTIAL,
COCONUT_ROUTES, COCONUT_VERIFY_BANDWIDTH_CREDENTIAL,
API_VERSION, BANDWIDTH, COCONUT_BLIND_SIGN, COCONUT_ROUTES, COCONUT_VERIFY_BANDWIDTH_CREDENTIAL,
};
use validator_client::nyxd::Coin;
use validator_client::nyxd::{tx::Hash, AccountId, DeliverTx, Event, Fee, Tag, TxResponse};
@@ -827,76 +826,6 @@ async fn blind_sign_correct() {
assert!(blinded_signature_response.is_ok());
}
#[tokio::test]
async fn signature_test() {
let tx_hash = String::from("7C41AF8266D91DE55E1C8F4712E6A952A165ED3D8C27C7B00428CBD0DE00A52B");
let params = Parameters::new(4).unwrap();
let key_pair = ttp_keygen(&params, 1, 1).unwrap().remove(0);
let mut db_dir = std::env::temp_dir();
db_dir.push(&key_pair.verification_key().to_bs58()[..8]);
let storage = NymApiStorage::init(db_dir).await.unwrap();
let nyxd_client =
DummyClient::new(AccountId::from_str(TEST_REWARDING_VALIDATOR_ADDRESS).unwrap());
let comm_channel = DummyCommunicationChannel::new(key_pair.verification_key());
let staged_key_pair = crate::coconut::KeyPair::new();
staged_key_pair.set(Some(key_pair)).await;
let rocket = rocket::build().attach(InternalSignRequest::stage(
nyxd_client,
TEST_COIN_DENOM.to_string(),
staged_key_pair,
comm_channel,
storage.clone(),
));
let client = Client::tracked(rocket)
.await
.expect("valid rocket instance");
let response = client
.post(format!(
"/{}/{}/{}/{}",
API_VERSION, COCONUT_ROUTES, BANDWIDTH, COCONUT_PARTIAL_BANDWIDTH_CREDENTIAL
))
.json(&tx_hash)
.dispatch()
.await;
assert_eq!(response.status(), Status::BadRequest);
assert_eq!(
response.into_string().await.unwrap(),
CoconutError::NoSignature.to_string()
);
let encrypted_signature = vec![1, 2, 3, 4];
let remote_key = [42; 32];
let expected_response = BlindedSignatureResponse::new(encrypted_signature, remote_key);
storage
.insert_blinded_signature_response(&tx_hash, &expected_response.to_base58_string())
.await
.unwrap();
let response = client
.post(format!(
"/{}/{}/{}/{}",
API_VERSION, COCONUT_ROUTES, BANDWIDTH, COCONUT_PARTIAL_BANDWIDTH_CREDENTIAL
))
.json(&tx_hash)
.dispatch()
.await;
assert_eq!(response.status(), Status::Ok);
// This is a more direct way, but there's a bug which makes it hang https://github.com/SergioBenitez/Rocket/issues/1893
// let blinded_signature_response = response
// .into_json::<BlindedSignatureResponse>()
// .await
// .unwrap();
let blinded_signature_response =
serde_json::from_str::<BlindedSignatureResponse>(&response.into_string().await.unwrap())
.unwrap();
assert_eq!(
blinded_signature_response.to_bytes(),
expected_response.to_bytes()
);
}
#[tokio::test]
async fn verification_of_bandwidth_credential() {
// Setup variables
+7 -2
View File
@@ -93,11 +93,16 @@ pub(crate) struct CliArgs {
pub(crate) enabled_credentials_mode: Option<bool>,
/// Announced address where coconut clients will connect.
#[clap(long)]
#[clap(long, hide = true)]
pub(crate) announce_address: Option<url::Url>,
/// Flag to indicate whether coconut signer authority is enabled on this API
#[clap(long, requires = "mnemonic", requires = "announce_address")]
#[clap(
long,
requires = "mnemonic",
requires = "announce_address",
hide = true
)]
pub(crate) enable_coconut: Option<bool>,
}
+3 -2
View File
@@ -8,6 +8,7 @@
"webpack:dev": "yarn webpack serve --config webpack.dev.js",
"webpack:dev:onlyThis": "yarn webpack serve --config webpack.dev.js",
"webpack:prod": "yarn webpack --progress --config webpack.prod.js",
"tauri": "tauri",
"tauri:dev": "WRY_ANDROID_PACKAGE=net.nymtech.nym_connect_android WRY_ANDROID_LIBRARY=nym_connect_android cargo tauri android dev",
"tauri:build": "WRY_ANDROID_PACKAGE=net.nymtech.nym_connect_android WRY_ANDROID_LIBRARY=nym_connect_android cargo tauri android build",
"dev": "run-p webpack:dev:onlyThis tauri:dev",
@@ -43,7 +44,7 @@
"react-error-boundary": "^3.1.3",
"react-hook-form": "^7.14.2",
"react-markdown": "^8.0.4",
"react-router-dom": "^5.2.0",
"react-router-dom": "^6.7.0",
"semver": "^6.3.0",
"yup": "^0.32.9"
},
@@ -58,7 +59,7 @@
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.4",
"@storybook/react": "^6.5.15",
"@svgr/webpack": "^6.1.1",
"@tauri-apps/cli": "^2.0.0-alpha.1",
"@tauri-apps/cli": "^2.0.0-alpha.2",
"@testing-library/jest-dom": "^5.14.1",
"@testing-library/react": "^12.0.0",
"@types/jest": "^27.0.1",
File diff suppressed because it is too large Load Diff
+7 -4
View File
@@ -1,6 +1,6 @@
[package]
name = "nym-connect-android"
version = "1.1.7"
version = "1.1.9"
description = "nym-connect for Android"
authors = ["Nym Technologies SA"]
license = ""
@@ -16,8 +16,8 @@ rust-version = "1.58"
crate-type = ["staticlib", "cdylib", "rlib"]
[build-dependencies]
# tauri-build = { version = "2.0.0-alpha.0", features = [] }
tauri-build = { git = "https://github.com/tauri-apps/tauri", branch = "next", features = [] }
tauri-build = { version = "2.0.0-alpha.1", features = [] }
# tauri-build = { git = "https://github.com/tauri-apps/tauri", branch = "next", features = [] }
[dependencies]
anyhow = "1.0"
@@ -38,7 +38,8 @@ serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
serde_repr = "0.1"
tap = "1.0.1"
tauri = { git = "https://github.com/tauri-apps/tauri", branch = "next", features = ["clipboard-write-text", "native-tls-vendored", "notification-all", "shell-open", "system-tray", "window-close", "window-minimize", "window-start-dragging"] }
# tauri = { git = "https://github.com/tauri-apps/tauri", branch = "next", features = ["clipboard-write-text", "native-tls-vendored", "notification-all", "shell-open", "system-tray", "window-close", "window-minimize", "window-start-dragging"] }
tauri = { version = "2.0.0-alpha.3", features = ["clipboard-write-text", "native-tls-vendored", "notification-all", "shell-open", "system-tray", "window-close", "window-minimize", "window-start-dragging"] }
tendermint-rpc = "0.23.0"
thiserror = "1.0"
tokio = { version = "1.24.1", features = ["sync", "time"] }
@@ -46,6 +47,8 @@ url = "2.2"
yaml-rust = "0.4"
client-core = { path = "../../clients/client-core" }
nym-api-requests = { path = "../../nym-api/nym-api-requests" }
contracts-common = { path = "../../common/cosmwasm-smart-contracts/contracts-common"}
config-common = { path = "../../common/config", package = "config" }
crypto = { path = "../../common/crypto" }
logging = { path = "../../common/logging"}
@@ -5,6 +5,7 @@
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/Theme.nym_connect_android"
android:screenOrientation="portrait"
android:usesCleartextTraffic="${usesCleartextTraffic}">
<activity
android:name=".MainActivity"
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_background"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
</adaptive-icon>
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_background"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
</adaptive-icon>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.9 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.8 KiB

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.8 KiB

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 18 KiB

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="grey_900">#212121</color>
<color name="grey_900">#1d2125</color>
<color name="grey_800">#424242</color>
<color name="green_500">#4caf50</color>
<color name="green_900">#1b5e20</color>
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="ic_launcher_background">#1D2125</color>
</resources>
@@ -14,8 +14,10 @@ open class BuildTask : DefaultTask() {
@InputDirectory
@PathSensitive(PathSensitivity.RELATIVE)
var rootDirRel: File? = null
@Input
var target: String? = null
@Input
var release: Boolean? = null
@@ -25,11 +27,15 @@ open class BuildTask : DefaultTask() {
val target = target ?: throw GradleException("target cannot be null")
val release = release ?: throw GradleException("release cannot be null")
val home = (System.getenv("HOME") ?: "")
val cargo_home = (System.getenv("CARGO_HOME") ?: "$home/.cargo")
println("gradle Rust plugin: CARGO_HOME $cargo_home")
val cargoHome = (System.getenv("CARGO_HOME") ?: "$home/.cargo")
val tauriCli = "$cargoHome/bin/cargo-tauri"
if (!File(tauriCli).isFile()) {
throw GradleException("$tauriCli no shuch file")
}
println("gradle Rust plugin, using tauri cli executable: $tauriCli")
project.exec {
workingDir(File(project.projectDir, rootDirRel.path))
executable("""$cargo_home/bin/cargo-tauri""")
executable(tauriCli)
args(listOf("tauri", "android", "android-studio-script"))
if (project.logger.isEnabled(LogLevel.DEBUG)) {
args("-vv")
+1 -1
View File
@@ -1,3 +1,3 @@
fn main() {
tauri_build::build()
tauri_build::build();
}
+2 -2
View File
@@ -51,9 +51,9 @@ pub enum BackendError {
InitializationPanic,
#[error("could not get config id before gateway is set")]
CouldNotGetIdWithoutGateway,
#[error("could initialize without gateway set")]
#[error("could not initialize without gateway set")]
CouldNotInitWithoutGateway,
#[error("could initialize without service provider set")]
#[error("could not initialize without service provider set")]
CouldNotInitWithoutServiceProvider,
#[error("could not get file name")]
CouldNotGetFilename,
+5 -1
View File
@@ -66,14 +66,18 @@ impl AppBuilder {
.invoke_handler(tauri::generate_handler![
crate::config::get_config_file_location,
crate::config::get_config_id,
crate::operations::connection::status::get_connection_status,
crate::operations::connection::connect::get_gateway,
crate::operations::connection::connect::get_service_provider,
crate::operations::connection::connect::set_gateway,
crate::operations::connection::connect::set_service_provider,
crate::operations::connection::connect::start_connecting,
crate::operations::connection::disconnect::start_disconnecting,
crate::operations::connection::status::get_connection_health_check_status,
crate::operations::connection::status::get_connection_status,
crate::operations::connection::status::get_gateway_connection_status,
crate::operations::connection::status::start_connection_health_check_task,
crate::operations::directory::get_services,
crate::operations::directory::get_gateways_detailed,
crate::operations::export::export_keys,
])
.setup(move |app| {
@@ -1,21 +1,35 @@
use itertools::Itertools;
use crate::error::Result;
use crate::models::{DirectoryService, HarbourMasterService, PagedResult};
use crate::models::{
DirectoryService, DirectoryServiceProvider, HarbourMasterService, PagedResult,
};
use contracts_common::types::Percent;
use nym_api_requests::models::GatewayBondAnnotated;
static SERVICE_PROVIDER_WELLKNOWN_URL: &str =
"https://nymtech.net/.wellknown/connect/service-providers.json";
static HARBOUR_MASTER_URL: &str = "https://harbourmaster.nymtech.net/v1/services/?size=100";
static GATEWAYS_DETAILED_URL: &str =
"https://validator.nymtech.net/api/v1/status/gateways/detailed";
#[tauri::command]
pub async fn get_services() -> Result<Vec<DirectoryService>> {
pub async fn get_services() -> Result<Vec<DirectoryServiceProvider>> {
log::trace!("Fetching services");
let res = reqwest::get(SERVICE_PROVIDER_WELLKNOWN_URL)
let services_res = reqwest::get(SERVICE_PROVIDER_WELLKNOWN_URL)
.await?
.json::<Vec<DirectoryService>>()
.await?;
log::trace!("Received: {:#?}", res);
log::trace!("Received: {:#?}", services_res);
log::trace!("Fetching gateways");
let gateway_res = reqwest::get(GATEWAYS_DETAILED_URL)
.await?
.json::<Vec<GatewayBondAnnotated>>()
.await?;
log::trace!("Received: {:#?}", gateway_res);
// TODO: get paged
log::trace!("Fetching active services");
@@ -27,7 +41,7 @@ pub async fn get_services() -> Result<Vec<DirectoryService>> {
let mut filtered: Vec<DirectoryService> = vec![];
for service in &res {
for service in &services_res {
let items: _ = service
.items
.clone()
@@ -47,5 +61,32 @@ pub async fn get_services() -> Result<Vec<DirectoryService>> {
})
}
Ok(filtered)
let perf_threshold = Percent::from_percentage_value(90).unwrap();
// Use only services that are active AND have a performance of >= 90%
let services_with_good_performance: Vec<DirectoryServiceProvider> = filtered
.iter_mut()
.fold(vec![], |mut acc, sp| {
acc.append(&mut sp.items);
acc
})
.into_iter()
.filter(|sp| {
gateway_res.iter().any(|gateway| {
gateway.gateway_bond.gateway.identity_key == sp.gateway
&& gateway.performance >= perf_threshold
})
})
.collect();
Ok(services_with_good_performance)
}
#[tauri::command]
pub async fn get_gateways_detailed() -> Result<Vec<GatewayBondAnnotated>> {
let res = reqwest::get(GATEWAYS_DETAILED_URL)
.await?
.json::<Vec<GatewayBondAnnotated>>()
.await?;
Ok(res)
}
@@ -174,17 +174,6 @@ impl State {
) -> Result<(task::StatusReceiver, ExitStatusReceiver)> {
self.set_state(ConnectionStatusKind::Connecting, window);
// Setup configuration by writing to file
//if let Err(err) = self.init_config().await {
// log::error!("Failed to initialize: {err}");
// // Wait a little to give the user some rudimentary feedback that the click actually
// // registered.
// tokio::time::sleep(Duration::from_secs(1)).await;
// self.set_state(ConnectionStatusKind::Disconnected, window);
// return Err(err);
//}
let res = self.init_config().await;
match &res {
Ok(_) => {}
@@ -1,7 +1,7 @@
{
"package": {
"productName": "nym-connect-android",
"version": "1.1.7"
"version": "1.1.9"
},
"build": {
"distDir": "../dist",
-94
View File
@@ -1,94 +0,0 @@
import React, { useEffect } from 'react';
import { DateTime } from 'luxon';
import { forage } from '@tauri-apps/tauri-forage';
import { ConnectionStatusKind } from './types';
import { useClientContext } from './context/main';
import { DefaultLayout } from './layouts/DefaultLayout';
import { ConnectedLayout } from './layouts/ConnectedLayout';
import { HelpGuideLayout } from './layouts/HelpGuideLayout';
import { useTauriEvents } from './utils';
export const App: FCWithChildren = () => {
const context = useClientContext();
const [busy, setBusy] = React.useState<boolean>();
const [showInfoModal, setShowInfoModal] = React.useState(false);
useTauriEvents('help://clear-storage', (_event) => {
console.log('About to clear local storage...');
// clear local storage
try {
forage.clear()();
console.log('Local storage cleared');
} catch (e) {
console.error('Failed to clear local storage', e);
}
});
const handleConnectClick = React.useCallback(async () => {
const currentStatus = context.connectionStatus;
if (currentStatus === ConnectionStatusKind.connected || currentStatus === ConnectionStatusKind.disconnected) {
setBusy(true);
// eslint-disable-next-line default-case
switch (currentStatus) {
case ConnectionStatusKind.disconnected:
await context.startConnecting();
context.setConnectedSince(DateTime.now());
break;
case ConnectionStatusKind.connected:
await context.startDisconnecting();
context.setConnectedSince(undefined);
break;
}
setBusy(false);
}
}, [context.connectionStatus]);
useEffect(() => {
if (context.connectionStatus === ConnectionStatusKind.connected) setShowInfoModal(true);
}, [context.connectionStatus]);
if (context.showHelp) return <HelpGuideLayout />;
if (
context.connectionStatus === ConnectionStatusKind.disconnected ||
context.connectionStatus === ConnectionStatusKind.connecting
) {
return (
<DefaultLayout
error={context.error}
clearError={context.clearError}
status={context.connectionStatus}
busy={busy}
onConnectClick={handleConnectClick}
services={context.services}
/>
);
}
return (
<ConnectedLayout
showInfoModal={showInfoModal}
handleCloseInfoModal={() => setShowInfoModal(false)}
status={context.connectionStatus}
busy={busy}
onConnectClick={handleConnectClick}
ipAddress="127.0.0.1"
port={1080}
gatewayPerformance={context.gatewayPerformance}
connectedSince={context.connectedSince}
serviceProvider={context.serviceProvider}
stats={[
{
label: 'in:',
totalBytes: 1024,
rateBytesPerSecond: 1024 * 1024 * 1024 + 10,
},
{
label: 'out:',
totalBytes: 1024 * 1024 * 1024 * 1024 * 20,
rateBytesPerSecond: 1024 * 1024 + 10,
},
]}
/>
);
};
Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 18 KiB

@@ -6,8 +6,8 @@ export const AppVersion = () => {
const { appVersion } = useClientContext();
return (
<Box sx={{ display: 'grid', width: '100%', justifyContent: 'center' }}>
<Box fontSize="small" sx={{ mb: 4, color: 'grey.600' }}>
<Box sx={{ display: 'flex', width: '100%', justifyContent: 'center' }}>
<Box fontSize="small" sx={{ color: 'grey.600' }}>
Version {appVersion}
</Box>
</Box>
@@ -1,20 +1,21 @@
import React from 'react';
import { Box } from '@mui/material';
import { useLocation } from 'react-router-dom';
import { CustomTitleBar } from './CustomTitleBar';
import { AppVersion } from './AppVersion';
export const AppWindowFrame: FCWithChildren = ({ children }) => (
<Box
sx={{
display: 'grid',
borderRadius: '12px',
gridTemplateRows: '40px 1fr 30px',
height: '100vh',
overflowY: 'hidden',
}}
>
<CustomTitleBar />
<Box style={{ padding: '16px' }}>{children}</Box>
<AppVersion />
</Box>
);
export const AppWindowFrame: FCWithChildren = ({ children }) => {
const location = useLocation();
return (
<Box
sx={{
display: 'grid',
gridTemplateRows: '40px 1fr',
height: '100vh',
}}
>
<CustomTitleBar path={location.pathname} />
<Box style={{ padding: '16px' }}>{children}</Box>
</Box>
);
};
@@ -10,13 +10,13 @@ const getStatusFillColor = (status: ConnectionStatusKind, hover: boolean, isErro
}
switch (status) {
case ConnectionStatusKind.disconnected:
case 'disconnected':
if (hover) {
return '#FFFF33';
}
return '#FFE600';
case ConnectionStatusKind.connecting:
case ConnectionStatusKind.disconnecting:
case 'connecting':
case 'disconnecting':
return '#FFE600';
default:
// connected
@@ -29,11 +29,11 @@ const getStatusFillColor = (status: ConnectionStatusKind, hover: boolean, isErro
const getStatusText = (status: ConnectionStatusKind, hover: boolean): string => {
switch (status) {
case ConnectionStatusKind.disconnected:
case 'disconnected':
return 'Connect';
case ConnectionStatusKind.connecting:
case 'connecting':
return 'Connecting';
case ConnectionStatusKind.disconnecting:
case 'disconnecting':
return 'Connected';
default:
// connected
@@ -89,7 +89,7 @@ export const ConnectionButton: FCWithChildren<{
<circle cx="131" cy="131" r="64" stroke={statusFillColor} strokeWidth="2" />
</g>
<circle cx="131" cy="131" r="73.5" stroke={statusFillColor} strokeOpacity="0.5" />
{status === ConnectionStatusKind.connected && hover ? (
{status === 'connected' && hover ? (
<path
d="M120.217 119.833C120.217 117.838 121.838 116.217 123.833 116.217H128.5V114H123.833C120.613 114 118 116.613 118 119.833C118 123.053 120.613 125.667 123.833 125.667H128.5V123.45H123.833C121.838 123.45 120.217 121.828 120.217 119.833ZM127 121H136.333V118.667H127V121ZM139.5 114H134.833V116.217H139.505C141.5 116.217 143.117 117.838 143.117 119.833C143.117 121.828 141.495 123.45 139.5 123.45H134.833V125.667H139.5C142.72 125.667 145.333 123.053 145.333 119.833C145.333 116.613 142.72 114 139.5 114Z"
fill="white"
@@ -1,34 +1,67 @@
import React from 'react';
import { Box, CircularProgress, Tooltip, Typography } from '@mui/material';
import { DateTime } from 'luxon';
import { ErrorOutline, InfoOutlined } from '@mui/icons-material';
import { ConnectionStatusKind, GatewayPerformance } from '../types';
import { ServiceProvider } from '../types/directory';
import { ServiceProviderInfo } from './ServiceProviderInfo';
import { GatwayWarningInfo, ServiceProviderInfo } from './TooltipInfo';
const FONT_SIZE = '10px';
const FONT_SIZE = '14px';
const FONT_WEIGHT = '600';
const FONT_STYLE = 'normal';
const ConnectionStatusContent: FCWithChildren<{
status: ConnectionStatusKind;
}> = ({ status }) => {
serviceProvider?: ServiceProvider;
gatewayError: boolean;
}> = ({ status, serviceProvider, gatewayError }) => {
if (gatewayError) {
return (
<Tooltip title={serviceProvider ? <GatwayWarningInfo /> : undefined}>
<Box
display="flex"
alignItems="center"
gap={0.5}
justifyContent="center"
sx={{ cursor: 'pointer' }}
color="warning.main"
>
<ErrorOutline sx={{ fontSize: 14 }} />
<Typography fontWeight={FONT_WEIGHT} fontStyle={FONT_STYLE} fontSize={FONT_SIZE} textAlign="center">
Gateway has issues
</Typography>
</Box>
</Tooltip>
);
}
switch (status) {
case ConnectionStatusKind.connected:
case 'connected':
return (
<Typography fontWeight={FONT_WEIGHT} fontStyle={FONT_STYLE} fontSize="14px">
Connected to
<Tooltip title={serviceProvider ? <ServiceProviderInfo serviceProvider={serviceProvider} /> : undefined}>
<Box display="flex" alignItems="center" gap={0.5} justifyContent="center" sx={{ cursor: 'pointer' }}>
<InfoOutlined sx={{ fontSize: 14 }} />
<Typography fontWeight={FONT_WEIGHT} fontStyle={FONT_STYLE} fontSize={FONT_SIZE} textAlign="center">
Connected to Nym Mixnet
</Typography>
</Box>
</Tooltip>
);
case 'disconnected':
return (
<Typography fontWeight={FONT_WEIGHT} fontStyle={FONT_STYLE} textAlign="center" fontSize={FONT_SIZE}>
Connect to the mixnet
</Typography>
);
case ConnectionStatusKind.disconnecting:
case 'disconnecting':
return (
<Box display="flex" alignItems="center" justifyContent="center">
<CircularProgress size={FONT_SIZE} color="inherit" />
<Typography fontWeight={FONT_WEIGHT} fontStyle={FONT_STYLE} ml={1}>
<Typography fontWeight={FONT_WEIGHT} fontStyle={FONT_STYLE}>
Disconnecting...
</Typography>
</Box>
);
case ConnectionStatusKind.connecting:
case 'connecting':
return (
<Box display="flex" alignItems="center" justifyContent="center">
<CircularProgress size={FONT_SIZE} color="inherit" />
@@ -37,20 +70,7 @@ const ConnectionStatusContent: FCWithChildren<{
</Typography>
</Box>
);
case ConnectionStatusKind.disconnected:
return (
<Typography
fontWeight={FONT_WEIGHT}
fontStyle={FONT_STYLE}
ml={1}
textTransform="uppercase"
textAlign="center"
fontSize={FONT_SIZE}
sx={{ wordSpacing: 3, letterSpacing: 2 }}
>
You are not protected
</Typography>
);
default:
return null;
}
@@ -62,29 +82,15 @@ export const ConnectionStatus: FCWithChildren<{
connectedSince?: DateTime;
serviceProvider?: ServiceProvider;
}> = ({ status, serviceProvider, gatewayPerformance }) => {
const color =
status === ConnectionStatusKind.connected || status === ConnectionStatusKind.disconnecting
? '#21D072'
: 'warning.main';
const color = status === 'connected' || status === 'disconnecting' ? '#21D072' : 'white';
return (
<>
<Box color={color} fontSize={FONT_SIZE} sx={{ mb: 1 }}>
{status === ConnectionStatusKind.connected && gatewayPerformance !== 'Good' ? (
<Typography fontWeight={FONT_WEIGHT} fontStyle={FONT_STYLE} textAlign="left" color="primary">
Gateway has issues
</Typography>
) : (
<ConnectionStatusContent status={status} />
)}
</Box>
{serviceProvider ? (
<Tooltip title={<ServiceProviderInfo serviceProvider={serviceProvider} />}>
<Box sx={{ cursor: 'pointer' }}>
{serviceProvider && <Typography>{serviceProvider.description}</Typography>}
</Box>
</Tooltip>
) : null}
</>
<Box color={color} sx={{ mb: 2 }}>
<ConnectionStatusContent
status={status}
serviceProvider={serviceProvider}
gatewayError={gatewayPerformance !== 'Good'}
/>
</Box>
);
};
@@ -1,8 +1,8 @@
import React from 'react';
import { ArrowBack, HelpOutline } from '@mui/icons-material';
import { Box, IconButton } from '@mui/material';
import { ArrowBack, Menu } from '@mui/icons-material';
import { Box, IconButton, Typography } from '@mui/material';
import { NymWordmark } from '@nymproject/react/logo/NymWordmark';
import { useClientContext } from 'src/context/main';
import { useNavigate } from 'react-router-dom';
const customTitleBarStyles = {
titlebar: {
@@ -19,25 +19,36 @@ const customTitleBarStyles = {
const CustomButton = ({ Icon, onClick }: { Icon: React.JSXElementConstructor<any>; onClick: () => void }) => (
<IconButton size="small" onClick={onClick} sx={{ padding: 0 }}>
<Icon style={{ fontSize: 16 }} />
<Icon style={{ fontSize: 24 }} />
</IconButton>
);
export const CustomTitleBar = () => {
const { showHelp, handleShowHelp } = useClientContext();
return (
<Box data-tauri-drag-region style={customTitleBarStyles.titlebar}>
{/* set width to keep logo centered */}
<Box sx={{ width: '40px' }}>
<CustomButton
Icon={!showHelp ? HelpOutline : ArrowBack}
onClick={() => {
handleShowHelp();
}}
/>
</Box>
<NymWordmark width={36} />
</Box>
);
const MenuIcon = () => {
const navigate = useNavigate();
return <CustomButton Icon={Menu} onClick={() => navigate('/menu')} />;
};
const ArrowBackIcon = () => {
const navigate = useNavigate();
return <CustomButton Icon={ArrowBack} onClick={() => navigate(-1)} />;
};
const getTitleIcon = (path: string) => {
if (path !== '/') {
const title = path.split('/').slice(-1);
return (
<Typography textTransform="capitalize" fontWeight={700}>
{title}
</Typography>
);
}
return <NymWordmark width={36} />;
};
export const CustomTitleBar = ({ path = '/' }: { path?: string }) => (
<Box data-tauri-drag-region style={customTitleBarStyles.titlebar}>
{/* set width to keep logo centered */}
<Box sx={{ width: '40px' }}>{path === '/' ? <MenuIcon /> : <ArrowBackIcon />}</Box>
{getTitleIcon(path)}
</Box>
);
@@ -0,0 +1,13 @@
import React from 'react';
import { Box, Typography } from '@mui/material';
export const ExperimentalWarning = () => (
<Box sx={{ color: 'grey.600' }}>
<Typography fontSize="12px" textAlign="center">
This is experimental software.
</Typography>
<Typography fontSize="12px" textAlign="center">
Do not rely on it for strong anonymity (yet).
</Typography>
</Box>
);
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

@@ -6,24 +6,26 @@ import { StepIndicator } from './HelpPageStepIndicator';
export const HelpPage = ({
step,
totalSteps,
description,
img,
onNext,
onPrev,
}: {
step: number;
totalSteps: number;
description: string;
img: any;
onNext?: () => void;
onPrev?: () => void;
}) => (
<Stack justifyContent="space-between" sx={{ height: '100%' }}>
<Stack gap={3}>
<Stack gap={2} alignItems="center">
<StepIndicator step={step} />
<Typography variant="body2" color="white" fontWeight="bold">
How to connect guide {step}/4
How to connect guide {step}/{totalSteps}
</Typography>
<Typography variant="body2" sx={{ color: 'grey.400' }}>
<Typography variant="body2" sx={{ color: 'grey.400' }} textAlign="left">
{description}
</Typography>
<HelpImage img={img} imageDescription="select a provider" />
@@ -5,14 +5,14 @@ import React from 'react';
export const HelpPageActions = ({ onNext, onPrev }: { onNext?: () => void; onPrev?: () => void }) => (
<Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
{onPrev ? (
<Button onClick={onPrev} color="inherit" startIcon={<ArrowBack color="inherit" style={{ fontSize: 16 }} />}>
<Button onClick={onPrev} color="inherit" startIcon={<ArrowBack color="inherit" style={{ fontSize: 22 }} />}>
Back
</Button>
) : (
<div />
)}
{onNext && (
<Button onClick={onNext} endIcon={<ArrowForward style={{ fontSize: 16 }} />}>
<Button onClick={onNext} endIcon={<ArrowForward style={{ fontSize: 22 }} />}>
Next
</Button>
)}
@@ -1,5 +1,5 @@
import React from 'react';
export const HelpImage = ({ img, imageDescription }: { img: any; imageDescription: string }) => (
<img src={img} alt={imageDescription} />
export const HelpImage = ({ img, imageDescription }: { img: string; imageDescription: string }) => (
<img src={img} alt={imageDescription} width="100%" />
);
@@ -1,15 +1,14 @@
import { Box } from '@mui/material';
import React from 'react';
import { Box, Stack } from '@mui/material';
const Step = ({ highlight }: { highlight: boolean }) => (
<Box sx={{ width: '48px', height: '1px', bgcolor: highlight ? 'nym.highlight' : 'grey.600' }} />
<Box sx={{ width: '65px', height: '3px', bgcolor: highlight ? 'nym.highlight' : 'grey.600' }} />
);
export const StepIndicator = ({ step }: { step: number }) => (
<Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-evenly' }}>
<Stack direction="row" alignItems="center" justifyContent="space-between" width="240px">
<Step highlight />
<Step highlight={step >= 2} />
<Step highlight={step >= 3} />
<Step highlight={step >= 4} />
</Box>
</Stack>
);

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