Compare commits

..

58 Commits

Author SHA1 Message Date
Mark Sinclair 33c162f3b4 Make traits public to allow PCC to use formatting traits 2021-11-16 16:01:30 +00:00
Mark Sinclair 2809c23722 Adjust public visibility so that structs and methods can be used from PCC WASM package 2021-11-16 10:52:07 +00:00
aniampio 66830d0a8d Merge branch 'feature/covidcredentials' of https://github.com/nymtech/nym into feature/covidcredentials 2021-11-12 11:04:33 +00:00
aniampio 802449d8af Add function to turn theta into bytes and from bytes 2021-11-12 11:04:19 +00:00
aniampio 5dd4245d4c [ci skip] Generate TS types 2021-11-08 17:01:40 +00:00
aniampio c49498a669 Run cargo fmt 2021-11-08 14:53:35 +00:00
aniampio 7d123b9fce Add functions for proving and verification of a covid credential + e2e test showing how it should work 2021-11-08 14:52:33 +00:00
aniampio 3c76b8386a Run cargo fmt 2021-11-04 14:15:56 +00:00
aniampio bdb021994e Resolve double imports after merge 2021-11-04 14:15:35 +00:00
AniaPiotrowska f732d83479 Merge branch 'develop' into feature/vouchers 2021-11-04 14:08:50 +00:00
aniampio 221d042a21 Fix merge conflict 2021-11-04 13:05:16 +00:00
aniampio 4dea20e15b Merge commits 2021-11-04 12:52:10 +00:00
aniampio 6ae54b2f89 Remove old comment 2021-11-04 12:47:37 +00:00
AniaPiotrowska fe2386eab2 Update common/nymcoconut/src/proofs/mod.rs
Co-authored-by: Jędrzej Stuczyński <jedrzej.stuczynski@gmail.com>
2021-11-04 12:37:56 +00:00
aniampio 2a551610ae Remove empty file 2021-11-04 12:35:51 +00:00
aniampio b00fa15b55 Change passing verification key as inpput to functions to actually computing it when it is needed 2021-11-04 12:30:43 +00:00
AniaPiotrowska 4d904257a9 Update common/credentials/src/bandwidth.rs
Co-authored-by: Jędrzej Stuczyński <jedrzej.stuczynski@gmail.com>
2021-11-04 10:55:14 +00:00
aniampio f3a192a023 Merge branch 'feature/vouchers' of https://github.com/nymtech/nym into feature/vouchers 2021-11-03 20:44:23 +00:00
aniampio c67c114af6 Fix for a failed clippy test 2021-11-03 20:41:26 +00:00
AniaPiotrowska 87c8b512b0 Update common/credentials/src/bandwidth.rs
Co-authored-by: Jędrzej Stuczyński <jedrzej.stuczynski@gmail.com>
2021-11-03 20:32:24 +00:00
AniaPiotrowska 36d8502fed Update clients/socks5/src/commands/init.rs
Co-authored-by: Jędrzej Stuczyński <jedrzej.stuczynski@gmail.com>
2021-11-03 20:31:40 +00:00
aniampio ec2bf0beaf Fix incorrect error message 2021-11-03 19:34:39 +00:00
aniampio 36b20d4e6e Add get attribute function instead of making it public 2021-11-03 19:30:27 +00:00
aniampio 9554cebb2b Fix the error in wasm client 2021-11-03 16:52:33 +00:00
aniampio b9c4922e1a Merge branch 'feature/vouchers' of https://github.com/nymtech/nym into feature/vouchers 2021-11-03 16:16:28 +00:00
aniampio 65ef3f02e7 Run cargo fmt 2021-11-03 16:14:13 +00:00
aniampio a75ca9f114 Rename function to indicate that it returns the number of attributes 2021-11-03 16:09:46 +00:00
aniampio aa2410c99b Remove commented code 2021-11-03 16:04:22 +00:00
aniampio c1df8eef62 Replace numeric value with a constant 2021-11-03 15:59:10 +00:00
aniampio f5726a07f3 Add docs for the bandwidth voucher struct 2021-11-03 15:51:57 +00:00
aniampio 639fb802a4 Add spacing between errors 2021-11-03 15:43:42 +00:00
aniampio 9b945acba3 Remove commented code 2021-11-03 15:41:14 +00:00
aniampio 70a28d3767 Change expect to unwrap 2021-11-03 15:38:32 +00:00
Jędrzej Stuczyński 533f6c5b24 cargo fmt 2021-11-03 09:05:10 +00:00
aniampio fba653fcfd Fix dead code warning 2021-10-28 16:36:42 +02:00
aniampio 22c0669f5d Run cargo fmt 2021-10-28 16:09:50 +02:00
aniampio edfd9531af Fix warnings from clippy 2021-10-28 16:09:24 +02:00
aniampio bbd35feb81 Run cargo fmt 2021-10-25 10:43:45 +02:00
aniampio bd26bc192e Update flag #[cfg(feature = coconut)] 2021-10-25 10:41:29 +02:00
aniampio 39af6abec7 Run cargo fmt 2021-10-25 09:59:05 +02:00
aniampio d1563c079e Fix the fields in tauri-client 2021-10-25 09:53:40 +02:00
aniampio 8250dca8be Fix warnings from clippy 2021-10-22 17:59:53 +02:00
aniampio 5bf0a14c20 Rename prove_credential to prove_bandwidth_credential 2021-10-22 17:29:27 +02:00
aniampio 6a3d10bab7 Run cargo fmt 2021-10-22 17:16:19 +02:00
aniampio 842b58751a Rename input variable to be more informative 2021-10-22 17:15:47 +02:00
aniampio 544355bbfd Rename input variable to be more informative 2021-10-22 17:13:48 +02:00
aniampio bd64a29932 Fix unused imports 2021-10-22 16:50:07 +02:00
aniampio ed2cf1ced6 Fix breaking test and remove doctest from nymcoconut 2021-10-22 16:11:17 +02:00
aniampio 890b0bb677 Update nymcoconut/src/scheme/mod file 2021-10-22 15:37:15 +02:00
aniampio 09efb62fa1 Add features flag for coconut 2021-10-22 15:18:06 +02:00
AniaPiotrowska 4e80c57076 Merge branch 'develop' into feature/vouchers 2021-10-20 17:18:22 +01:00
aniampio 8c2361757e Merge branch 'feature/vouchers' of https://github.com/nymtech/nym into feature/vouchers 2021-10-20 17:05:21 +01:00
aniampio 0eaad032f6 Run cargo fmt 2021-10-20 17:05:00 +01:00
aniampio 371467cede [ci skip] Generate TS types 2021-10-20 15:45:26 +00:00
aniampio 9110a8eefd Add proper creation of bandwidth attributes 2021-10-20 16:35:13 +01:00
aniampio 2e8a0e9a72 Add missing blinded serial number value and update accordingly the code 2021-10-20 16:06:30 +01:00
aniampio b068dde7c7 Introduce specific field for the bandwidth voucher. Values need to be updated, tmp put what was already used 2021-10-18 18:56:20 +01:00
aniampio d93918e99b Move the Coconut library 2021-10-18 16:32:38 +01:00
1390 changed files with 135827 additions and 183085 deletions
+3 -3
View File
@@ -15,8 +15,8 @@
* @futurechimp @mmsinclair * @futurechimp @mmsinclair
# Rust rules: # Rust rules:
*.rs @durch @futurechimp @jstuczyn @neacsu @octol *.rs @durch @futurechimp @jstuczyn @neacsu
Cargo.* @durch @futurechimp @jstuczyn @neacsu @octol Cargo.* @durch @futurechimp @jstuczyn @neacsu
# JS rules: # JS rules:
*.js @mmsinclair @fmtabbara @Aid19801 *.js @mmsinclair @fmtabbara @Aid19801
@@ -36,5 +36,5 @@ Cargo.* @durch @futurechimp @jstuczyn @neacsu @octol
# Explorer and wallet should probably get looked by the product team # Explorer and wallet should probably get looked by the product team
/explorer/ @nymtech/product /explorer/ @nymtech/product
/nym-wallet/ @nymtech/product /tauri-wallet/ @nymtech/product
/wallet-web/ @nymtech/product /wallet-web/ @nymtech/product
-63
View File
@@ -1,63 +0,0 @@
name: CI for ts-packages
on:
push:
paths:
- 'ts-packages/**'
jobs:
build:
runs-on: custom-runner-linux
steps:
- uses: actions/checkout@v2
- name: Install rsync
run: sudo apt-get install rsync
- uses: rlespinasse/github-slug-action@v3.x
- uses: actions/setup-node@v2
with:
node-version: '16'
- name: Setup yarn
run: npm install -g yarn
- name: Build
run: yarn && yarn build && yarn build:ci
- name: Deploy branch to CI www (storybook)
continue-on-error: true
uses: easingthemes/ssh-deploy@main
env:
SSH_PRIVATE_KEY: ${{ secrets.CI_WWW_SSH_PRIVATE_KEY }}
ARGS: "-rltgoDzvO --delete"
SOURCE: "ts-packages/dist/storybook/"
REMOTE_HOST: ${{ secrets.CI_WWW_REMOTE_HOST }}
REMOTE_USER: ${{ secrets.CI_WWW_REMOTE_USER }}
TARGET: ${{ secrets.CI_WWW_REMOTE_TARGET }}/ts-${{ env.GITHUB_REF_SLUG }}
EXCLUDE: "/dist/, /node_modules/"
- name: Deploy branch to CI www (example)
continue-on-error: true
uses: easingthemes/ssh-deploy@main
env:
SSH_PRIVATE_KEY: ${{ secrets.CI_WWW_SSH_PRIVATE_KEY }}
ARGS: "-rltgoDzvO --delete"
SOURCE: "ts-packages/dist/example/"
REMOTE_HOST: ${{ secrets.CI_WWW_REMOTE_HOST }}
REMOTE_USER: ${{ secrets.CI_WWW_REMOTE_USER }}
TARGET: ${{ secrets.CI_WWW_REMOTE_TARGET }}/ts-${{ env.GITHUB_REF_SLUG }}-example
EXCLUDE: "/dist/, /node_modules/"
- name: Keybase - Node Install
run: npm install
working-directory: .github/workflows/support-files
- name: Keybase - Send Notification
env:
NYM_NOTIFICATION_KIND: ts-packages
NYM_PROJECT_NAME: "ts-packages"
NYM_CI_WWW_BASE: "${{ secrets.NYM_CI_WWW_BASE }}"
NYM_CI_WWW_LOCATION: "ts-${{ env.GITHUB_REF_SLUG }}"
GIT_COMMIT_MESSAGE: "${{ github.event.head_commit.message }}"
GIT_BRANCH: "${GITHUB_REF##*/}"
KEYBASE_NYMBOT_USERNAME: "${{ secrets.KEYBASE_NYMBOT_USERNAME }}"
KEYBASE_NYMBOT_PAPERKEY: "${{ secrets.KEYBASE_NYMBOT_PAPERKEY }}"
KEYBASE_NYMBOT_TEAM: "${{ secrets.KEYBASE_NYMBOT_TEAM }}"
KEYBASE_NYM_CHANNEL: "ci-ts-packages"
IS_SUCCESS: "${{ job.status == 'success' }}"
uses: docker://keybaseio/client:stable-node
with:
args: .github/workflows/support-files/notifications/entry_point.sh
+86 -28
View File
@@ -1,22 +1,20 @@
name: Continuous integration name: Continuous integration
on: on: [push, pull_request]
push:
paths-ignore:
- 'explorer/**'
pull_request:
paths-ignore:
- 'explorer/**'
jobs: jobs:
build: build:
runs-on: [ self-hosted, custom-linux-exoscale ] runs-on: ${{ matrix.os }}
# Enable sccache via environment variable continue-on-error: ${{ matrix.rust == 'nightly' || matrix.rust == 'beta' || matrix.os == 'windows-latest' }}
env: strategy:
RUSTC_WRAPPER: /home/ubuntu/.cargo/bin/sccache matrix:
rust: [stable, beta, nightly]
os: [ubuntu-latest, macos-latest, windows-latest]
steps: steps:
- name: Install Dependencies (Linux) - name: Install Dependencies (Linux)
run: sudo apt-get update && sudo apt-get -y install libwebkit2gtk-4.0-dev build-essential curl wget libssl-dev libgtk-3-dev squashfs-tools run: sudo apt-get update && sudo apt-get install libwebkit2gtk-4.0-dev build-essential curl wget libssl-dev libgtk-3-dev squashfs-tools
if: matrix.os == 'ubuntu-latest'
- name: Check out repository code - name: Check out repository code
uses: actions/checkout@v2 uses: actions/checkout@v2
@@ -25,7 +23,7 @@ jobs:
uses: actions-rs/toolchain@v1 uses: actions-rs/toolchain@v1
with: with:
profile: minimal profile: minimal
toolchain: stable toolchain: ${{ matrix.rust }}
override: true override: true
components: rustfmt, clippy components: rustfmt, clippy
@@ -33,13 +31,13 @@ jobs:
uses: actions-rs/cargo@v1 uses: actions-rs/cargo@v1
with: with:
command: build command: build
args: --workspace args: --all
- name: Run all tests - name: Run all tests
uses: actions-rs/cargo@v1 uses: actions-rs/cargo@v1
with: with:
command: test command: test
args: --workspace --all-features args: --all
- name: Check formatting - name: Check formatting
uses: actions-rs/cargo@v1 uses: actions-rs/cargo@v1
@@ -47,32 +45,92 @@ jobs:
command: fmt command: fmt
args: --all -- --check args: --all -- --check
- uses: actions-rs/clippy-check@v1
name: Clippy checks
with:
token: ${{ secrets.GITHUB_TOKEN }}
args: --all-features
- name: Run clippy - name: Run clippy
uses: actions-rs/cargo@v1 uses: actions-rs/cargo@v1
if: ${{ matrix.rust != 'nightly' }}
with: with:
command: clippy command: clippy
args: --workspace -- -D warnings args: -- -D warnings
- name: Build all binaries with coconut enabled # COCONUT stuff
- name: Reclaim some disk space (because Windows is being annoying)
uses: actions-rs/cargo@v1
if: ${{ matrix.os == 'windows-latest' }}
with:
command: clean
# BUILD
- name: Build gateway with coconut feature
uses: actions-rs/cargo@v1 uses: actions-rs/cargo@v1
with: with:
command: build command: build
args: --workspace --features=coconut args: --bin nym-gateway --features=coconut
- name: Run all tests with coconut enabled - name: Build native client with coconut feature
uses: actions-rs/cargo@v1
with:
command: build
args: --bin nym-client --features=coconut
- name: Build socks5 client with coconut feature
uses: actions-rs/cargo@v1
with:
command: build
args: --bin nym-socks5-client --features=coconut
- name: Build validator-api with coconut feature
uses: actions-rs/cargo@v1
with:
command: build
args: --bin nym-validator-api --features=coconut
# TEST
- name: Test gateway with coconut feature
uses: actions-rs/cargo@v1 uses: actions-rs/cargo@v1
with: with:
command: test command: test
args: --workspace --features=coconut args: --bin nym-gateway --features=coconut
- name: Run clippy with coconut enabled - name: Test native client with coconut feature
uses: actions-rs/cargo@v1
with:
command: test
args: --bin nym-client --features=coconut
- name: Test socks5 client with coconut feature
uses: actions-rs/cargo@v1
with:
command: test
args: --bin nym-socks5-client --features=coconut
- name: Test validator-api with coconut feature
uses: actions-rs/cargo@v1
with:
command: test
args: --bin nym-validator-api --features=coconut
# CLIPPY
- name: Run clippy on gateway with coconut feature
uses: actions-rs/cargo@v1 uses: actions-rs/cargo@v1
with: with:
command: clippy command: clippy
args: --features=coconut -- -D warnings args: --bin nym-gateway --features=coconut -- -D warnings
- name: Run clippy on native client with coconut feature
uses: actions-rs/cargo@v1
with:
command: clippy
args: --bin nym-client --features=coconut -- -D warnings
- name: Run clippy on socks5 client with coconut feature
uses: actions-rs/cargo@v1
with:
command: clippy
args: --bin nym-socks5-client --features=coconut -- -D warnings
- name: Run clippy on validator-api with coconut feature
uses: actions-rs/cargo@v1
with:
command: clippy
args: --bin nym-validator-api --features=coconut -- -D warnings
@@ -1,19 +0,0 @@
[
{
"os":"ubuntu-latest",
"rust":"stable",
"runOnEvent":"always"
},
{
"os":"windows-latest",
"rust":"stable",
"runOnEvent":"pull_request"
},
{
"os":"macos-latest",
"rust":"stable",
"runOnEvent":"pull_request"
}
]
+14
View File
@@ -0,0 +1,14 @@
name: Clippy check
on: push
jobs:
clippy_check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- run: rustup component add clippy
- uses: actions-rs/clippy-check@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
args: --all-features
@@ -1,14 +0,0 @@
[
{
"rust":"stable",
"runOnEvent":"always"
},
{
"rust":"beta",
"runOnEvent":"pull_request"
},
{
"rust":"nightly",
"runOnEvent":"pull_request"
}
]
-64
View File
@@ -1,64 +0,0 @@
name: Contracts
on:
push:
paths-ignore:
- 'explorer/**'
pull_request:
paths-ignore:
- 'explorer/**'
jobs:
matrix_prep:
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
steps:
# creates the matrix strategy from build_matrix_includes.json
- uses: actions/checkout@v2
- id: set-matrix
uses: JoshuaTheMiller/conditional-build-matrix@main
with:
inputFile: '.github/workflows/contract_matrix_includes.json'
filter: '[?runOnEvent==`${{ github.event_name }}` || runOnEvent==`always`]'
contracts:
# since it's going to be compiled into wasm, there's absolutely
# no point in running CI on different OS-es
runs-on: ubuntu-latest
continue-on-error: ${{ matrix.rust == 'nightly' }}
needs: matrix_prep
strategy:
matrix: ${{fromJson(needs.matrix_prep.outputs.matrix)}}
steps:
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: ${{ matrix.rust }}
target: wasm32-unknown-unknown
override: true
components: rustfmt, clippy
- uses: actions-rs/cargo@v1
env:
RUSTFLAGS: '-C link-arg=-s'
with:
command: build
args: --manifest-path contracts/Cargo.toml --workspace --target wasm32-unknown-unknown
- uses: actions-rs/cargo@v1
with:
command: test
args: --manifest-path contracts/Cargo.toml
- uses: actions-rs/cargo@v1
with:
command: fmt
args: --manifest-path contracts/Cargo.toml --all -- --check
- uses: actions-rs/cargo@v1
if: ${{ matrix.rust != 'nightly' }}
with:
command: clippy
args: --manifest-path contracts/Cargo.toml --workspace -- -D warnings
+44
View File
@@ -0,0 +1,44 @@
name: Mixnet Contract
on: [push, pull_request]
jobs:
mixnet-contract:
# since it's going to be compiled into wasm, there's absolutely
# no point in running CI on different OS-es
runs-on: ubuntu-latest
continue-on-error: ${{ matrix.rust == 'nightly' }}
strategy:
matrix:
rust: [ stable, beta, nightly ]
steps:
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: ${{ matrix.rust }}
target: wasm32-unknown-unknown
override: true
components: rustfmt, clippy
- uses: actions-rs/cargo@v1
with:
command: build
args: --manifest-path contracts/mixnet/Cargo.toml --target wasm32-unknown-unknown
- uses: actions-rs/cargo@v1
with:
command: test
args: --manifest-path contracts/mixnet/Cargo.toml
- uses: actions-rs/cargo@v1
with:
command: fmt
args: --manifest-path contracts/mixnet/Cargo.toml -- --check
- uses: actions-rs/cargo@v1
if: ${{ matrix.rust != 'nightly' }}
with:
command: clippy
args: --manifest-path contracts/mixnet/Cargo.toml -- -D warnings
@@ -1,24 +0,0 @@
name: Linting for Network Explorer (eslint/prettier)
on:
pull_request:
paths:
- 'explorer/**'
defaults:
run:
working-directory: explorer
jobs:
build:
runs-on: custom-runner-linux
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: '16'
- name: Setup yarn
run: npm install -g yarn
- name: Run ESLint
# GitHub should automatically annotate the PR
run: yarn && yarn lint
+9 -16
View File
@@ -11,7 +11,7 @@ defaults:
jobs: jobs:
build: build:
runs-on: custom-runner-linux runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- name: Install rsync - name: Install rsync
@@ -19,17 +19,12 @@ jobs:
- uses: rlespinasse/github-slug-action@v3.x - uses: rlespinasse/github-slug-action@v3.x
- uses: actions/setup-node@v2 - uses: actions/setup-node@v2
with: with:
node-version: '16' node-version: '14'
- name: Setup yarn - run: npm install
run: npm install -g yarn
continue-on-error: true continue-on-error: true
- name: Build shared packages - run: npm run test
run: cd .. && yarn && yarn build continue-on-error: true
- name: Set environment from the example - run: npm run build
run: cp .env.prod .env
# - run: yarn test
# continue-on-error: true
- run: yarn && yarn build
continue-on-error: true continue-on-error: true
- name: Deploy branch to CI www - name: Deploy branch to CI www
continue-on-error: true continue-on-error: true
@@ -40,17 +35,15 @@ jobs:
SOURCE: "explorer/dist/" SOURCE: "explorer/dist/"
REMOTE_HOST: ${{ secrets.CI_WWW_REMOTE_HOST }} REMOTE_HOST: ${{ secrets.CI_WWW_REMOTE_HOST }}
REMOTE_USER: ${{ secrets.CI_WWW_REMOTE_USER }} REMOTE_USER: ${{ secrets.CI_WWW_REMOTE_USER }}
TARGET: ${{ secrets.CI_WWW_REMOTE_TARGET }}/network-explorer-${{ env.GITHUB_REF_SLUG }} TARGET: ${{ secrets.CI_WWW_REMOTE_TARGET }}/${{ env.GITHUB_REF_SLUG }}
EXCLUDE: "/dist/, /node_modules/" EXCLUDE: "/dist/, /node_modules/"
- name: Keybase - Node Install - name: Keybase - Node Install
run: npm install run: npm install
working-directory: .github/workflows/support-files working-directory: .github/workflows/support-files/messages
- name: Keybase - Send Notification - name: Keybase - Send Notification
env: env:
NYM_NOTIFICATION_KIND: network-explorer
NYM_PROJECT_NAME: "Network Explorer" NYM_PROJECT_NAME: "Network Explorer"
NYM_CI_WWW_BASE: "${{ secrets.NYM_CI_WWW_BASE }}" NYM_CI_WWW_BASE: "${{ secrets.NYM_CI_WWW_BASE }}"
NYM_CI_WWW_LOCATION: "network-explorer-${{ env.GITHUB_REF_SLUG }}"
GIT_COMMIT_MESSAGE: "${{ github.event.head_commit.message }}" GIT_COMMIT_MESSAGE: "${{ github.event.head_commit.message }}"
GIT_BRANCH: "${GITHUB_REF##*/}" GIT_BRANCH: "${GITHUB_REF##*/}"
KEYBASE_NYMBOT_USERNAME: "${{ secrets.KEYBASE_NYMBOT_USERNAME }}" KEYBASE_NYMBOT_USERNAME: "${{ secrets.KEYBASE_NYMBOT_USERNAME }}"
@@ -60,4 +53,4 @@ jobs:
IS_SUCCESS: "${{ job.status == 'success' }}" IS_SUCCESS: "${{ job.status == 'success' }}"
uses: docker://keybaseio/client:stable-node uses: docker://keybaseio/client:stable-node
with: with:
args: .github/workflows/support-files/notifications/entry_point.sh args: .github/workflows/support-files/messages/entry_point_notifications.sh
-125
View File
@@ -1,125 +0,0 @@
name: Nightly builds
on:
schedule:
- cron: '14 4 * * *'
jobs:
matrix_prep:
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
steps:
# creates the matrix strategy from nightly_build_matrix_includes.json
- uses: actions/checkout@v2
- id: set-matrix
uses: JoshuaTheMiller/conditional-build-matrix@main
with:
inputFile: '.github/workflows/nightly_build_matrix_includes.json'
filter: '[?runOnEvent==`${{ github.event_name }}` || runOnEvent==`always`]'
build:
needs: matrix_prep
strategy:
matrix: ${{fromJson(needs.matrix_prep.outputs.matrix)}}
runs-on: ${{ matrix.os }}
continue-on-error: ${{ matrix.rust == 'nightly' || matrix.rust == 'beta' || matrix.rust == 'stable' }}
steps:
- name: Install Dependencies (Linux)
run: sudo apt-get update && sudo apt-get install libwebkit2gtk-4.0-dev build-essential curl wget libssl-dev libgtk-3-dev squashfs-tools
if: matrix.os == 'ubuntu-latest'
- name: Check out repository code
uses: actions/checkout@v2
- name: Install rust toolchain
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: ${{ matrix.rust }}
override: true
components: rustfmt, clippy
- name: Build all binaries
uses: actions-rs/cargo@v1
with:
command: build
args: --workspace
- name: Run all tests
uses: actions-rs/cargo@v1
with:
command: test
args: --workspace
- name: Check formatting
uses: actions-rs/cargo@v1
with:
command: fmt
args: --all -- --check
- name: Reclaim some disk space (because Windows is being annoying)
uses: actions-rs/cargo@v1
if: ${{ matrix.os == 'windows-latest' }}
with:
command: clean
- uses: actions-rs/clippy-check@v1
name: Clippy checks
with:
token: ${{ secrets.GITHUB_TOKEN }}
args: --all-features
- name: Run clippy
uses: actions-rs/cargo@v1
if: ${{ matrix.rust != 'nightly' }}
with:
command: clippy
args: --workspace --all-targets -- -D warnings
# COCONUT stuff
- name: Build all binaries with coconut enabled
uses: actions-rs/cargo@v1
with:
command: build
args: --workspace --features=coconut
- name: Run all tests with coconut enabled
uses: actions-rs/cargo@v1
with:
command: test
args: --workspace --features=coconut
- name: Run clippy with coconut enabled
uses: actions-rs/cargo@v1
if: ${{ matrix.rust != 'nightly' }}
with:
command: clippy
args: --workspace --all-targets --features=coconut -- -D warnings
notification:
needs: build
runs-on: ubuntu-latest
steps:
- name: Collect jobs status
uses: technote-space/workflow-conclusion-action@v2
- name: Check out repository code
uses: actions/checkout@v2
- name: Keybase - Node Install
if: env.WORKFLOW_CONCLUSION == 'failure'
run: npm install
working-directory: .github/workflows/support-files
- name: Keybase - Send Notification
if: env.WORKFLOW_CONCLUSION == 'failure'
env:
NYM_NOTIFICATION_KIND: nightly
NYM_PROJECT_NAME: "Nym nightly build"
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
GIT_COMMIT_MESSAGE: "${{ github.event.head_commit.message }}"
GIT_BRANCH: "${GITHUB_REF##*/}"
KEYBASE_NYMBOT_USERNAME: "${{ secrets.KEYBASE_NYMBOT_USERNAME }}"
KEYBASE_NYMBOT_PAPERKEY: "${{ secrets.KEYBASE_NYMBOT_PAPERKEY }}"
KEYBASE_NYMBOT_TEAM: "${{ secrets.KEYBASE_NYMBOT_TEAM }}"
KEYBASE_NYM_CHANNEL: "ci-nightly"
IS_SUCCESS: "${{ env.WORKFLOW_CONCLUSION == 'success' }}"
uses: docker://keybaseio/client:stable-node
with:
args: .github/workflows/support-files/notifications/entry_point.sh
@@ -1,50 +0,0 @@
[
{
"os":"ubuntu-latest",
"rust":"stable",
"runOnEvent":"schedule"
},
{
"os":"windows-latest",
"rust":"stable",
"runOnEvent":"schedule"
},
{
"os":"macos-latest",
"rust":"stable",
"runOnEvent":"schedule"
},
{
"os":"ubuntu-latest",
"rust":"beta",
"runOnEvent":"schedule"
},
{
"os":"windows-latest",
"rust":"beta",
"runOnEvent":"schedule"
},
{
"os":"macos-latest",
"rust":"beta",
"runOnEvent":"schedule"
},
{
"os":"ubuntu-latest",
"rust":"nightly",
"runOnEvent":"schedule"
},
{
"os":"windows-latest",
"rust":"nightly",
"runOnEvent":"schedule"
},
{
"os":"macos-latest",
"rust":"nightly",
"runOnEvent":"schedule"
}
]
-43
View File
@@ -1,43 +0,0 @@
name: Publish Nym binaries
on:
release:
types: [created]
jobs:
publish-nym:
strategy:
fail-fast: false
matrix:
platform: [ubuntu-latest]
runs-on: ${{ matrix.platform }}
steps:
- uses: actions/checkout@v3
- name: Check the release tag starts with `nym-binaries-`
if: startsWith(github.ref, 'refs/tags/nym-binaries-') == false
uses: actions/github-script@v3
with:
script: |
core.setFailed('Release tag did not start with nym-binaries-...')
- name: Install Rust stable
uses: actions-rs/toolchain@v1
with:
toolchain: stable
- name: Build all binaries
uses: actions-rs/cargo@v1
with:
command: build
args: --workspace --release
- name: Upload to release based on tag name
uses: softprops/action-gh-release@v1
with:
files: |
target/release/nym-client
target/release/nym-gateway
target/release/nym-mixnode
target/release/nym-socks5-client
target/release/nym-validator-api
@@ -1,77 +0,0 @@
name: Publish Nym Wallet (MacOS)
on:
release:
types: [created]
defaults:
run:
working-directory: nym-wallet
jobs:
publish-tauri:
strategy:
fail-fast: false
matrix:
platform: [macos-latest]
runs-on: ${{ matrix.platform }}
steps:
- uses: actions/checkout@v2
- name: Check the release tag starts with `nym-wallet-`
if: startsWith(github.ref, 'refs/tags/nym-wallet-') == false
uses: actions/github-script@v3
with:
script: |
core.setFailed('Release tag did not start with nym-wallet-...')
- name: Node v16
uses: actions/setup-node@v1
with:
node-version: 16.x
- name: Install Rust stable
uses: actions-rs/toolchain@v1
with:
toolchain: stable
- name: Install the Apple developer certificate for code signing
env:
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
run: |
# create variables
CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12
KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db
# import certificate and provisioning profile from secrets
echo -n "$APPLE_CERTIFICATE" | base64 --decode --output $CERTIFICATE_PATH
# create temporary keychain
security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
security set-keychain-settings -lut 21600 $KEYCHAIN_PATH
security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
# import certificate to keychain
security import $CERTIFICATE_PATH -P "$APPLE_CERTIFICATE_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
security list-keychain -d user -s $KEYCHAIN_PATH
- name: Install app dependencies and build it
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
ENABLE_CODE_SIGNING: ${{ secrets.APPLE_CERTIFICATE }}
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_IDENTITY_ID }}
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
run: yarn && yarn build
- name: Upload to release based on tag name
uses: softprops/action-gh-release@v1
with:
files: nym-wallet/target/release/bundle/dmg/*.dmg
- name: Clean up keychain
if: ${{ always() }}
run: |
security delete-keychain $RUNNER_TEMP/app-signing.keychain-db
@@ -1,46 +0,0 @@
name: Publish Nym Wallet (Ubuntu)
on:
release:
types: [created]
defaults:
run:
working-directory: nym-wallet
jobs:
publish-tauri:
strategy:
fail-fast: false
matrix:
platform: [ubuntu-latest]
runs-on: ${{ matrix.platform }}
steps:
- uses: actions/checkout@v2
- name: Tauri dependencies
run: >
sudo apt-get update &&
sudo apt-get install -y webkit2gtk-4.0
- name: Check the release tag starts with `nym-wallet-`
if: startsWith(github.ref, 'refs/tags/nym-wallet-') == false
uses: actions/github-script@v3
with:
script: |
core.setFailed('Release tag did not start with nym-wallet-...')
- name: Node v16
uses: actions/setup-node@v1
with:
node-version: 16.x
- name: Install Rust stable
uses: actions-rs/toolchain@v1
with:
toolchain: stable
- name: Install app dependencies and build it
run: yarn && yarn build
- name: Upload to release based on tag name
uses: softprops/action-gh-release@v1
with:
files: nym-wallet/target/release/bundle/appimage/*.AppImage
@@ -1,71 +0,0 @@
name: Publish Nym Wallet (Windows 10)
on:
release:
types: [created]
defaults:
run:
working-directory: nym-wallet
jobs:
publish-tauri:
strategy:
fail-fast: false
matrix:
platform: [windows10]
runs-on: ${{ matrix.platform }}
steps:
- name: Clean up first
continue-on-error: true
working-directory: .
run: |
cd ..
del /s /q /A:H nym
rmdir /s /q nym
- uses: actions/checkout@v3
- name: Check the release tag starts with `nym-wallet-`
if: startsWith(github.ref, 'refs/tags/nym-wallet-') == false
uses: actions/github-script@v3
with:
script: |
core.setFailed('Release tag did not start with nym-wallet-...')
- name: Import signing certificate
env:
WINDOWS_CERTIFICATE: ${{ secrets.WINDOWS_CERTIFICATE }}
WINDOWS_CERTIFICATE_PASSWORD: ${{ secrets.WINDOWS_CERTIFICATE_PASSWORD }}
run: |
New-Item -ItemType directory -Path certificate
Set-Content -Path certificate/tempCert.txt -Value $env:WINDOWS_CERTIFICATE
certutil -decode certificate/tempCert.txt certificate/certificate.pfx
Remove-Item -path certificate -include tempCert.txt
Import-PfxCertificate -FilePath certificate/certificate.pfx -CertStoreLocation Cert:\CurrentUser\My -Password (ConvertTo-SecureString -String $env:WINDOWS_CERTIFICATE_PASSWORD -Force -AsPlainText)
- name: Node v16
uses: actions/setup-node@v1
with:
node-version: 16.x
- name: Install Rust stable
uses: actions-rs/toolchain@v1
with:
toolchain: stable
- name: Install app dependencies
run: yarn
- name: Build and sign it
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
ENABLE_CODE_SIGNING: ${{ secrets.WINDOWS_CERTIFICATE }}
WINDOWS_CERTIFICATE: ${{ secrets.WINDOWS_CERTIFICATE }}
WINDOWS_CERTIFICATE_PASSWORD: ${{ secrets.WINDOWS_CERTIFICATE_PASSWORD }}
run: yarn build
- name: Upload to release based on tag name
uses: softprops/action-gh-release@v1
with:
files: nym-wallet/target/release/bundle/msi/*.msi
+19 -19
View File
@@ -1,18 +1,18 @@
name: Webdriverio tests for nym wallet name: Webdriverio tests for nym wallet
on: on:
push: push:
paths: paths:
- "nym-wallet/**" - 'tauri-wallet/**'
defaults: defaults:
run: run:
working-directory: nym-wallet working-directory: tauri-wallet
jobs: jobs:
test: test:
name: wallet tests name: wallet tests
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
@@ -30,8 +30,8 @@ jobs:
- name: Install minimal stable - name: Install minimal stable
uses: actions-rs/toolchain@v1 uses: actions-rs/toolchain@v1
with: with:
profile: minimal profile: minimal
toolchain: stable toolchain: stable
- name: Node v16 - name: Node v16
uses: actions/setup-node@v1 uses: actions/setup-node@v1
@@ -39,32 +39,32 @@ jobs:
node-version: 16.x node-version: 16.x
- name: Install yarn for building application - name: Install yarn for building application
run: yarn install run: yarn install
- name: Build application - name: Build application
run: yarn run webpack:build & yarn run tauri:build run: yarn run webpack:build & yarn run tauri:build
- name: Check binary exists - name: Check binary exists
run: | run: |
cd target/release/ cd target/release/
(test -f nym-wallet && echo nym binary exists) || echo wallet does not exist (test -f nym-wallet && echo nym binary exists) || echo wallet does not exist
- name: Install dependencies - name: Install dependencies
run: yarn install run: yarn install
working-directory: nym-wallet/webdriver working-directory: tauri-wallet/webdriver
- name: Remove existing user datafile - name: Remove existing user datafile
uses: JesseTG/rm@v1.0.2 uses: JesseTG/rm@v1.0.2
with: with:
path: nym-wallet/webdriver/common/data/user-data.json path: tauri-wallet/webdriver/common/data/user-data.json
- name: Create user data json file - name: Create user data json file
id: create-json id: create-json
uses: jsdaniell/create-json@1.1.2 uses: jsdaniell/create-json@1.1.2
with: with:
name: "user-data.json" name: "user-data.json"
json: ${{ secrets.WALLET_USERDATA }} json: ${{ secrets.WALLET_USERDATA }}
dir: "nym-wallet/webdriver/common/data/" dir: 'tauri-wallet/webdriver/common/data/'
- name: Install tauri-driver - name: Install tauri-driver
uses: actions-rs/cargo@v1 uses: actions-rs/cargo@v1
@@ -73,5 +73,5 @@ jobs:
args: tauri-driver args: tauri-driver
- name: Launch tests - name: Launch tests
run: xvfb-run yarn test:runall run: xvfb-run yarn test:newuser
working-directory: nym-wallet/webdriver working-directory: tauri-wallet/webdriver
@@ -1,35 +0,0 @@
KEYBASE_NYM_CHANNEL=
KEYBASE_NYMBOT_USERNAME=
KEYBASE_NYMBOT_PAPERKEY=
NYM_NOTIFICATION_KIND=nightly
NYM_PROJECT_NAME=Nightly Build
#----------------------------------------------------------------
# Custom GitHub Actions mock env vars
IS_SUCCESS=true
#----------------------------------------------------------------
# GitHub Actions context mock env vars
GITHUB_SHA=abcdef
GITHUB_RUN_ID=123456
GITHUB_REPOSITORY=nymtech/nym
GITHUB_SERVER_URL=https://github.com
GIT_BRANCH_NAME=feature/testing-support-files
GIT_BRANCH=feature/testing-support-files
GIT_COMMIT_MESSAGE=This is the commit message
GITHUB_ACTOR=octocat
# add a Personal Access Token (PAT) generated from GitHub here for use in testing
GITHUB_TOKEN=
#----------------------------------------------------------------
# Network Explorer
NYM_CI_WWW_LOCATION=some-branch
NYM_CI_WWW_BASE=example.com
#----------------------------------------------------------------
# Nightly builds
WORKFLOW_CONCLUSION=success
SHOW_DEBUG=true
@@ -1,5 +0,0 @@
node_modules
.idea
# don't commit the lock file to avoid cross-platform issues
package-lock.json
-1
View File
@@ -1 +0,0 @@
16
-58
View File
@@ -1,58 +0,0 @@
# GitHub Actions Support Files
This is a collection of scripts and files to support GitHub Actions.
## Sending Notifications
These scripts send CI notifications to Keybase by creating messages from templates and env vars passed from GitHub Actions.
### Adding notifications to a GitHub Action
```
jobs:
build:
...
- name: Notifications - Node Install
run: npm install
working-directory: .github/workflows/support-files/notifications
- name: Notifications - Send
env:
NYM_NOTIFICATION_KIND: "my-component"
GIT_BRANCH: "${GITHUB_REF##*/}"
KEYBASE_NYMBOT_USERNAME: "${{ secrets.KEYBASE_NYMBOT_USERNAME }}"
KEYBASE_NYMBOT_PAPERKEY: "${{ secrets.KEYBASE_NYMBOT_PAPERKEY }}"
KEYBASE_NYMBOT_TEAM: "${{ secrets.KEYBASE_NYMBOT_TEAM }}"
KEYBASE_NYM_CHANNEL: "ci-network-explorer"
IS_SUCCESS: "${{ job.status == 'success' }}"
uses: docker://keybaseio/client:stable-node
with:
args: .github/workflows/support-files/notifications/entry_point.sh
```
Notifications are run by adding the snippet above to a GitHub Action, and:
1. Installing node packages needed at run time
2. Set the env vars as required:
- `NYM_NOTIFICATION_KIND` matches the directory in `.github/workflows/support-files/${NYM_NOTIFICATION_KIND}` to provide the templates and extra scripting in `index.js`
- Keybase credentials, channel and other env vars for the status of the build and repo
3. Replacing the default entry point shell script on the `keybaseio/client:stable-node` docker image to run `.github/workflows/support-files/notifications/entry_point.sh`
### Running locally
You will need:
- Node 16 LTS
- npm
Copy `.github/workflows/support-files/.env.example` to `.github/workflows/support-files/.env` and valid Keybase credentials.
Then run `npm install` to get dependencies.
Start development mode for the notification type you want either by passing the value as an env var called `NYM_NOTIFICATION_KIND` or set the `.env` file values correctly.
```bash
cd .github/workflows/support-files
npm install
cp .env.example .env
vi .env
npm run dev
```
-1
View File
@@ -1 +0,0 @@
require('./notifications/send_message');
@@ -0,0 +1,2 @@
node_modules
.idea
@@ -4,14 +4,11 @@
"version": "1.0.0", "version": "1.0.0",
"private": true, "private": true,
"scripts": { "scripts": {
"dev": "node dev.js", "format": "prettier --write send_message.js"
"format": "prettier --write **/*.js"
}, },
"dependencies": { "dependencies": {
"dotenv": "^16.0.0",
"handlebars": "^4.7.7", "handlebars": "^4.7.7",
"keybase-bot": "^3.6.1", "keybase-bot": "^3.6.1"
"octokit": "^1.7.1"
}, },
"devDependencies": { "devDependencies": {
"prettier": "2.3.2" "prettier": "2.3.2"
@@ -0,0 +1,69 @@
const Bot = require('keybase-bot');
const Handlebars = require('handlebars');
const fs = require('fs');
async function main() {
const data = { env: process.env };
// const data = { ...PASTE TEST DATA HERE ... }; // -- DEV: uncomment to set test data
// validation of environment
if(!(process.env.NYM_PROJECT_NAME || data.env.NYM_PROJECT_NAME)) {
throw new Error('Please set env var NYM_PROJECT_NAME with the project name for displaying in notification messages');
}
const keybaseChannel = process.env.KEYBASE_NYM_CHANNEL || data.env.KEYBASE_NYM_CHANNEL;
if(!keybaseChannel) {
throw new Error('Please set env var KEYBASE_NYM_CHANNEL with the channel name for the notification message');
}
// extract the git branch name
const GIT_BRANCH_NAME = (process.env.GITHUB_REF || data.env.GITHUB_REF).split('/').slice(2).join('/');
data.env.GIT_BRANCH_NAME = GIT_BRANCH_NAME;
const source = fs
.readFileSync(process.env.IS_SUCCESS === 'true' ? 'success' : 'failure')
.toString();
const template = Handlebars.compile(source);
const result = template(data);
// -- DEV: uncomment to show what is available in the handlebars template / show the result
// console.dir({ data }, { depth: null });
// console.log(result);
const bot = new Bot();
try {
const username = process.env.KEYBASE_NYMBOT_USERNAME;
const paperkey = process.env.KEYBASE_NYMBOT_PAPERKEY;
if(!username) {
throw new Error('Username is not defined. Please set env var KEYBASE_NYMBOT_USERNAME');
}
if(!paperkey) {
throw new Error('Paperkey is not defined. Please set env var KEYBASE_NYMBOT_PAPERKEY');
}
console.log(`Initialising keybase with user "${username}" and key: "${'*'.repeat(paperkey.length)}"...`);
await bot.init(username, paperkey, { verbose: false });
const channel = {
name: 'nymtech_bot',
membersType: 'team',
topicName: keybaseChannel,
topic_type: 'CHAT',
};
const message = {
body: result,
};
console.log(`Sending to ${channel.name}#${channel.topicName}...`);
await bot.chat.send(channel, message);
console.log('Message sent!');
} catch (error) {
console.error(error);
process.exitCode = -1;
} finally {
await bot.deinit();
}
}
main();
@@ -1,11 +1,11 @@
🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩 🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩
> :rocket: {{ env.NYM_PROJECT_NAME }} ➡️➡️➡️➡️➡️ **View output:** https://{{ env.NYM_CI_WWW_LOCATION }}.{{ env.NYM_CI_WWW_BASE }}/ > :rocket: {{ env.NYM_PROJECT_NAME }} ➡️➡️➡️➡️➡️ **View output:** https://{{ env.GITHUB_REF_SLUG }}.{{ env.NYM_CI_WWW_BASE }}/
> ✅ **SUCCESS** > ✅ **SUCCESS**
> `branch` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/tree/{{ env.GIT_BRANCH_NAME }} > `branch` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/tree/{{ env.GIT_BRANCH_NAME }}
> `commit` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/commit/{{ env.GITHUB_SHA }} > `commit` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/commit/{{ env.GITHUB_SHA }}
> `build ` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/actions/runs/{{ env.GITHUB_RUN_ID }} > `build ` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/actions/runs/{{ env.GITHUB_RUN_ID }}
Commit message by `{{ env.GITHUB_ACTOR }}` at {{ timestamp }}: Commit message:
``` ```
{{ env.GIT_COMMIT_MESSAGE }} {{ env.GIT_COMMIT_MESSAGE }}
``` ```
@@ -1,29 +0,0 @@
const Handlebars = require('handlebars');
const fs = require('fs');
const path = require('path');
async function addToContextAndValidate(context) {
if (!context.env.NYM_CI_WWW_LOCATION) {
throw new Error('Please ensure the env var NYM_CI_WWW_LOCATION is set');
}
if (!context.env.NYM_CI_WWW_BASE) {
throw new Error('Please ensure the env var NYM_CI_WWW_BASE is set');
}
}
async function getMessageBody(context) {
const source = fs
.readFileSync(
context.env.IS_SUCCESS === 'true'
? path.resolve(__dirname, 'templates', 'success')
: path.resolve(__dirname, 'templates', 'failure'),
)
.toString();
const template = Handlebars.compile(source);
return template(context);
}
module.exports = {
addToContextAndValidate,
getMessageBody,
};
@@ -1,162 +0,0 @@
const Handlebars = require('handlebars');
const fs = require('fs');
const path = require('path');
const { Octokit, App } = require('octokit');
async function addToContextAndValidate(context) {
if (!context.env.WORKFLOW_CONCLUSION) {
throw new Error('Please ensure the env var WORKFLOW_CONCLUSION is set');
}
if (!context.env.GITHUB_TOKEN) {
throw new Error('Please ensure the env var GITHUB_TOKEN is set');
}
if (!context.env.GITHUB_RUN_ID) {
throw new Error('Please ensure the env var GITHUB_RUN_ID is set');
}
if (!context.env.GITHUB_REPOSITORY) {
throw new Error('Please ensure the env var GITHUB_REPOSITORY is set');
}
}
async function getMessageBody(context) {
const source = fs
.readFileSync(
context.env.WORKFLOW_CONCLUSION === 'success'
? path.resolve(__dirname, 'templates', 'success')
: path.resolve(__dirname, 'templates', 'failure'),
)
.toString();
const template = Handlebars.compile(source);
// get job details from GitHub API
const octokit = new Octokit({ auth: context.env.GITHUB_TOKEN });
const [owner, repo] = context.env.GITHUB_REPOSITORY.split('/');
const {
data: { jobs },
} = await octokit.rest.actions.listJobsForWorkflowRun({
run_id: context.env.GITHUB_RUN_ID,
owner,
repo,
});
// uncomment this to see what is available for each job
if(process.env.SHOW_DEBUG) {
console.dir(jobs, { depth: null });
}
/*
a sample of the response is:
{
total_count: 10,
jobs: [
{
id: 5182940024,
run_id: 1840752095,
run_url: 'https://api.github.com/repos/nymtech/nym/actions/runs/1840752095',
run_attempt: 1,
node_id: 'CR_kwDODdjOis8AAAABNO1jeA',
head_sha: 'aa00eb70d57751bfa556bd3602df87c7473367fc',
url: 'https://api.github.com/repos/nymtech/nym/actions/jobs/5182940024',
html_url: 'https://github.com/nymtech/nym/runs/5182940024?check_suite_focus=true',
status: 'completed',
conclusion: 'success',
started_at: '2022-02-14T11:28:34Z',
completed_at: '2022-02-14T11:28:38Z',
name: 'matrix_prep',
steps: [
{
name: 'Set up job',
status: 'completed',
conclusion: 'success',
number: 1,
started_at: '2022-02-14T13:28:34.000+02:00',
completed_at: '2022-02-14T13:28:36.000+02:00'
},
{
name: 'Run actions/checkout@v2',
status: 'completed',
conclusion: 'success',
number: 2,
started_at: '2022-02-14T13:28:36.000+02:00',
completed_at: '2022-02-14T13:28:37.000+02:00'
},
...
],
check_run_url: 'https://api.github.com/repos/nymtech/nym/check-runs/5182940024',
labels: [ 'ubuntu-latest' ],
runner_id: 1,
runner_name: 'Hosted Agent',
runner_group_id: 2,
runner_group_name: 'GitHub Actions'
},
{
id: 5182943473,
run_id: 1840752095,
run_url: 'https://api.github.com/repos/nymtech/nym/actions/runs/1840752095',
run_attempt: 1,
node_id: 'CR_kwDODdjOis8AAAABNO1w8Q',
head_sha: 'aa00eb70d57751bfa556bd3602df87c7473367fc',
url: 'https://api.github.com/repos/nymtech/nym/actions/jobs/5182943473',
html_url: 'https://github.com/nymtech/nym/runs/5182943473?check_suite_focus=true',
status: 'completed',
conclusion: 'failure',
started_at: '2022-02-14T11:29:04Z',
completed_at: '2022-02-14T11:55:45Z',
name: 'build (macos-latest, stable, schedule)',
steps: [
{
name: 'Set up job',
status: 'completed',
conclusion: 'success',
number: 1,
started_at: '2022-02-14T13:29:04.000+02:00',
completed_at: '2022-02-14T13:29:26.000+02:00'
},
{
name: 'Install Dependencies (Linux)',
status: 'completed',
conclusion: 'skipped',
number: 2,
started_at: '2022-02-14T13:29:26.000+02:00',
completed_at: '2022-02-14T13:29:26.000+02:00'
},
{
name: 'Keybase - Send Notification',
status: 'completed',
conclusion: 'failure',
number: 15,
started_at: '2022-02-14T13:55:44.000+02:00',
completed_at: '2022-02-14T13:55:44.000+02:00'
},
],
check_run_url: 'https://api.github.com/repos/nymtech/nym/check-runs/5182943473',
labels: [ 'macos-latest' ],
runner_id: 4,
runner_name: 'GitHub Actions 4',
runner_group_id: 2,
runner_group_name: 'GitHub Actions'
},
...
]
}
*/
const jobResults = jobs
.map((job) => {
const icon = job.conclusion === 'success' ? '🟩' : '🟥';
// each job is converted into formatted markdown text
return `${icon} ${job.conclusion}: ${job.name} - ${job.html_url}`;
})
// and join with newlines for display in the template
.join('\n');
return template({ ...context, jobResults });
}
module.exports = {
addToContextAndValidate,
getMessageBody,
};
@@ -1,9 +0,0 @@
🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥
> :rocket: {{ env.NYM_PROJECT_NAME }}
> 🔴 **FAILURE** :cry:
> `when` {{ timestamp }}
> `branch` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/tree/{{ env.GIT_BRANCH_NAME }}
> `commit` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/commit/{{ env.GITHUB_SHA }}
> `build ` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/actions/runs/{{ env.GITHUB_RUN_ID }}
{{ jobResults }}
@@ -1,9 +0,0 @@
🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩
> :rocket: {{ env.NYM_PROJECT_NAME }}
> ✅ **SUCCESS**
> `when` {{ timestamp }}
> `branch` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/tree/{{ env.GIT_BRANCH_NAME }}
> `commit` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/commit/{{ env.GITHUB_SHA }}
> `build ` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/actions/runs/{{ env.GITHUB_RUN_ID }}
{{ jobResults }}
@@ -1,153 +0,0 @@
require('dotenv').config();
const Bot = require('keybase-bot');
let context = {
kinds: ['ts-packages', 'network-explorer', 'nightly'],
};
/**
* Validate that all required env and context vars are available
*/
function validateContext() {
if (!context.env.NYM_NOTIFICATION_KIND) {
throw new Error(
'Please set env var NYM_NOTIFICATION_KIND with the project kind that matches a directory in ".github/workflows/support-files"',
);
}
if (!context.kinds.includes(context.env.NYM_NOTIFICATION_KIND)) {
throw new Error(`Env var NYM_NOTIFICATION_KIND is not in ${context.kinds}`);
}
if (!context.env.NYM_PROJECT_NAME) {
throw new Error(
'Please set env var NYM_PROJECT_NAME with the project name for displaying in notification messages',
);
}
if (!context.env.KEYBASE_NYM_CHANNEL) {
throw new Error(
'Please set env var KEYBASE_NYM_CHANNEL with the channel name for the notification message',
);
}
if (!context.env.KEYBASE_NYMBOT_USERNAME) {
throw new Error(
'Username is not defined. Please set env var KEYBASE_NYMBOT_USERNAME',
);
}
if (!context.env.KEYBASE_NYMBOT_PAPERKEY) {
throw new Error(
'Paperkey is not defined. Please set env var KEYBASE_NYMBOT_PAPERKEY',
);
}
}
/**
* Creates a context that will be available in the templates for rendering notifications
*/
function createTemplateContext() {
const options = { dateStyle: 'full', timeStyle: 'long' };
context.timestamp = new Date().toLocaleString(undefined, options);
// add environment to template context and validate
context.env = process.env;
try {
validateContext();
} catch (e) {
if(process.env.SHOW_DEBUG) {
// recursively print the context for easy debugging and rethrow the error
console.dir({ context }, { depth: null });
}
throw e;
}
context.kind = context.env.NYM_NOTIFICATION_KIND;
context.keybase = {
channel: context.env.KEYBASE_NYM_CHANNEL,
username: context.env.KEYBASE_NYMBOT_USERNAME,
paperkey: context.env.KEYBASE_NYMBOT_PAPERKEY,
};
if (!context.env.GIT_BRANCH_NAME) {
context.env.GIT_BRANCH_NAME = context.env.GITHUB_REF.split('/')
.slice(2)
.join('/');
}
context.status = process.env.IS_SUCCESS === 'true' ? 'success' : 'failure';
}
async function sendKeybaseMessage(messageBody) {
const bot = new Bot();
try {
console.log(
`Initialising keybase with user "${
context.keybase.username
}" and key: "${'*'.repeat(context.keybase.paperkey.length)}"...`,
);
await bot.init(context.keybase.username, context.keybase.paperkey, {
verbose: false,
});
const channel = {
name: 'nymtech_bot',
membersType: 'team',
topicName: context.keybase.channel,
topic_type: 'CHAT',
};
const message = {
body: messageBody,
};
console.log(`Sending to ${channel.name}#${channel.topicName}...`);
await bot.chat.send(channel, message);
console.log('Message sent!');
} catch (error) {
console.error(error);
process.exitCode = -1;
} finally {
await bot.deinit();
}
}
/**
* Uses the `kind` set in the context to process the context and generate a notification message
* @returns {Promise<string>} A string notification message body
*/
async function processKindScript() {
const script = require(`../${context.kind}`);
if (!script.addToContextAndValidate) {
throw new Error(
`"./${context.kind}/index.js" does not export a method called "async addToContextAndValidate(context)"`,
);
}
if (!script.getMessageBody) {
throw new Error(
`"./${context.kind}/index.js" does not export a method called "async getMessageBody(context)"`,
);
}
// call the script to modify and validate the context
await script.addToContextAndValidate(context);
// let the script create a message body and return the result as a string for sending
return await script.getMessageBody(context);
}
/**
* The main function, as async so that await syntax is available
*/
async function main() {
createTemplateContext();
console.log(`Sending notification for kind "${context.kind}"...`);
const messageBody = await processKindScript();
if(process.env.SHOW_DEBUG) {
console.log('-----------------------------------------');
console.log(messageBody);
console.log('-----------------------------------------');
}
await sendKeybaseMessage(messageBody);
}
// call main function and let NodeJS handle the promise
main();
@@ -1,29 +0,0 @@
const Handlebars = require('handlebars');
const fs = require('fs');
const path = require('path');
async function addToContextAndValidate(context) {
if (!context.env.NYM_CI_WWW_LOCATION) {
throw new Error('Please ensure the env var NYM_CI_WWW_LOCATION is set');
}
if (!context.env.NYM_CI_WWW_BASE) {
throw new Error('Please ensure the env var NYM_CI_WWW_BASE is set');
}
}
async function getMessageBody(context) {
const source = fs
.readFileSync(
context.env.IS_SUCCESS === 'true'
? path.resolve(__dirname, 'templates', 'success')
: path.resolve(__dirname, 'templates', 'failure'),
)
.toString();
const template = Handlebars.compile(source);
return template(context);
}
module.exports = {
addToContextAndValidate,
getMessageBody,
};
@@ -1,11 +0,0 @@
🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥
> :rocket: {{ env.NYM_PROJECT_NAME }}
> 🔴 **FAILURE** :cry:
> `branch` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/tree/{{ env.GIT_BRANCH_NAME }}
> `commit` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/commit/{{ env.GITHUB_SHA }}
> `build ` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/actions/runs/{{ env.GITHUB_RUN_ID }}
Commit message:
```
{{ env.GIT_COMMIT_MESSAGE }}
```
@@ -1,16 +0,0 @@
🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩
> :rocket: {{ env.NYM_PROJECT_NAME }}
> ✅ **SUCCESS**
> ➡️➡️➡️➡️➡️ **View output:**
> `storybook`: https://{{ env.NYM_CI_WWW_LOCATION }}.{{ env.NYM_CI_WWW_BASE }}
> `example`: https://{{ env.NYM_CI_WWW_LOCATION }}-example.{{ env.NYM_CI_WWW_BASE }}
> `branch` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/tree/{{ env.GIT_BRANCH_NAME }}
> `commit` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/commit/{{ env.GITHUB_SHA }}
> `build ` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/actions/runs/{{ env.GITHUB_RUN_ID }}
Commit message by `{{ env.GITHUB_ACTOR }}` at {{ timestamp }}:
```
{{ env.GIT_COMMIT_MESSAGE }}
```
+22
View File
@@ -0,0 +1,22 @@
name: Generate TS types
on: push
jobs:
tauri-wallet-types:
runs-on: ubuntu-latest
steps:
- name: Prepare
run: sudo apt-get update && sudo apt-get install -y libpango1.0-dev libatk1.0-dev libgdk-pixbuf2.0-dev libsoup2.4-dev librust-gdk-dev libwebkit2gtk-4.0-dev
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
with:
toolchain: stable
- name: Generate TS
run: cd tauri-wallet/src-tauri && cargo test
- uses: EndBug/add-and-commit@v7.2.1 # https://github.com/marketplace/actions/add-commit
with:
add: '["tauri-wallet"]'
message: '[ci skip] Generate TS types'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+11 -12
View File
@@ -1,9 +1,6 @@
name: Wasm Client name: Wasm Client
on: on: [push, pull_request]
pull_request:
paths-ignore:
- 'explorer/**'
jobs: jobs:
wasm: wasm:
@@ -29,17 +26,19 @@ jobs:
command: build command: build
args: --manifest-path clients/webassembly/Cargo.toml --target wasm32-unknown-unknown --features=coconut args: --manifest-path clients/webassembly/Cargo.toml --target wasm32-unknown-unknown --features=coconut
- uses: actions-rs/cargo@v1 # for some reason this does not seem to work correctly, leave it for later, building is good enough for now
with: # - uses: actions-rs/cargo@v1
command: test # with:
args: --manifest-path clients/webassembly/Cargo.toml # command: test
# args: --manifest-path clients/webassembly/Cargo.toml --target wasm32-unknown-unknown
- uses: actions-rs/cargo@v1 - uses: actions-rs/cargo@v1
with: with:
command: fmt command: fmt
args: --manifest-path clients/webassembly/Cargo.toml -- --check args: --manifest-path clients/webassembly/Cargo.toml -- --check
- uses: actions-rs/cargo@v1 # for some reason this does not seem to work correctly, leave it for later, building is good enough for now
with: # - uses: actions-rs/cargo@v1
command: clippy # with:
args: --manifest-path clients/webassembly/Cargo.toml --target wasm32-unknown-unknown -- -D warnings # command: clippy
# args: --manifest-path clients/webassembly/Cargo.toml --target wasm32-unknown-unknown -- -D warnings
-3
View File
@@ -1,3 +0,0 @@
unreleased=true
future-release=v0.12.0
since-tag=v0.11.0
+1 -9
View File
@@ -11,6 +11,7 @@ target
/.vscode/settings.json /.vscode/settings.json
validator/.vscode validator/.vscode
sample-configs/validator-config.toml sample-configs/validator-config.toml
.vscode
scripts/deploy_qa.sh scripts/deploy_qa.sh
scripts/run_gate.sh scripts/run_gate.sh
scripts/run_mix.sh scripts/run_mix.sh
@@ -24,17 +25,8 @@ v6-topology.json
/explorer/downloads/topology.json /explorer/downloads/topology.json
/explorer/public/downloads/mixmining.json /explorer/public/downloads/mixmining.json
/explorer/public/downloads/topology.json /explorer/public/downloads/topology.json
/nym-wallet/dist/*
/clients/validator/examples/nym-driver-example/current-contract.txt /clients/validator/examples/nym-driver-example/current-contract.txt
validator-api/v4.json validator-api/v4.json
validator-api/v6.json validator-api/v6.json
**/node_modules **/node_modules
validator-api/keypair validator-api/keypair
contracts/mixnet/code_id
contracts/mixnet/Justfile
contracts/mixnet/Makefile
validator-config
*.patch
validator-api-config.toml
dist
storybook-static
-1
View File
@@ -1 +0,0 @@
2.7.5
-6
View File
@@ -1,6 +0,0 @@
{
"mainnet":[{
"nymd_url":"https://rpc.nyx.nodes.guru/",
"api_url":"https://api.nyx.nodes.guru/"
}]
}
+879 -228
View File
File diff suppressed because it is too large Load Diff
Generated
+2501 -1621
View File
File diff suppressed because it is too large Load Diff
+5 -9
View File
@@ -11,13 +11,13 @@ panic = "abort"
[workspace] [workspace]
resolver = "2"
members = [ members = [
"clients/client-core", "clients/client-core",
"clients/native", "clients/native",
"clients/native/websocket-requests", "clients/native/websocket-requests",
"clients/socks5", "clients/socks5",
# "clients/tauri-client/src-tauri", "clients/tauri-client/src-tauri",
"clients/webassembly",
"common/client-libs/gateway-client", "common/client-libs/gateway-client",
"common/client-libs/mixnet-client", "common/client-libs/mixnet-client",
"common/client-libs/validator-client", "common/client-libs/validator-client",
@@ -25,10 +25,7 @@ members = [
"common/config", "common/config",
"common/credentials", "common/credentials",
"common/crypto", "common/crypto",
"common/bandwidth-claim-contract", "common/mixnet-contract",
"common/cosmwasm-smart-contracts/contracts-common",
"common/cosmwasm-smart-contracts/mixnet-contract",
"common/cosmwasm-smart-contracts/vesting-contract",
"common/mixnode-common", "common/mixnode-common",
"common/network-defaults", "common/network-defaults",
"common/nonexhaustive-delayqueue", "common/nonexhaustive-delayqueue",
@@ -54,17 +51,16 @@ members = [
"mixnode", "mixnode",
"service-providers/network-requester", "service-providers/network-requester",
"validator-api", "validator-api",
"validator-api/validator-api-requests",
] ]
default-members = [ default-members = [
"clients/native", "clients/native",
"clients/socks5", "clients/socks5",
# "clients/webassembly",
"gateway", "gateway",
"service-providers/network-requester", "service-providers/network-requester",
"mixnode", "mixnode",
"validator-api", "validator-api",
"explorer-api",
] ]
exclude = ["explorer", "contracts", "tokenomics-py", "clients/webassembly"] exclude = ["explorer", "contracts"]
-56
View File
@@ -1,56 +0,0 @@
test: build clippy-all cargo-test wasm fmt
no-clippy: build cargo-test wasm fmt
happy: fmt clippy-happy test
clippy-all: clippy-all-main clippy-all-contracts clippy-all-wallet
clippy-happy: clippy-happy-main clippy-happy-contracts clippy-happy-wallet
cargo-test: test-main test-contracts test-wallet
build: build-contracts build-wallet build-main
fmt: fmt-main fmt-contracts fmt-wallet
clippy-happy-main:
cargo clippy
clippy-happy-contracts:
cargo clippy --manifest-path contracts/Cargo.toml --target wasm32-unknown-unknown
clippy-happy-wallet:
cargo clippy --manifest-path nym-wallet/Cargo.toml
clippy-all-main:
cargo clippy --workspace --all-features -- -D warnings
clippy-all-contracts:
cargo clippy --workspace --manifest-path contracts/Cargo.toml --all-features --target wasm32-unknown-unknown -- -D warnings
clippy-all-wallet:
cargo clippy --workspace --manifest-path nym-wallet/Cargo.toml --all-features -- -D warnings
test-main:
cargo test --all-features --workspace
test-contracts:
cargo test --manifest-path contracts/Cargo.toml --all-features
test-wallet:
cargo test --manifest-path nym-wallet/Cargo.toml --all-features
build-main:
cargo build --workspace
build-contracts:
cargo build --manifest-path contracts/Cargo.toml --workspace
build-wallet:
cargo build --manifest-path nym-wallet/Cargo.toml --workspace
fmt-main:
cargo fmt --all
fmt-contracts:
cargo fmt --manifest-path contracts/Cargo.toml --all
fmt-wallet:
cargo fmt --manifest-path nym-wallet/Cargo.toml --all
wasm:
RUSTFLAGS='-C link-arg=-s' cargo build --manifest-path contracts/Cargo.toml --release --target wasm32-unknown-unknown
+4 -44
View File
@@ -5,6 +5,8 @@ SPDX-License-Identifier: Apache-2.0
## The Nym Privacy Platform ## The Nym Privacy Platform
This repository contains the Nym mixnet.
The platform is composed of multiple Rust crates. Top-level executable binary crates include: The platform is composed of multiple Rust crates. Top-level executable binary crates include:
* nym-mixnode - shuffles [Sphinx](https://github.com/nymtech/sphinx) packets together to provide privacy against network-level attackers. * nym-mixnode - shuffles [Sphinx](https://github.com/nymtech/sphinx) packets together to provide privacy against network-level attackers.
@@ -13,7 +15,7 @@ The platform is composed of multiple Rust crates. Top-level executable binary cr
* nym-gateway - acts sort of like a mailbox for mixnet messages, removing the need for directly delivery to potentially offline or firewalled devices. * nym-gateway - acts sort of like a mailbox for mixnet messages, removing the need for directly delivery to potentially offline or firewalled devices.
* nym-network-monitor - sends packets through the full system to check that they are working as expected, and stores node uptime histories as the basis of a rewards system ("mixmining" or "proof-of-mixing"). * nym-network-monitor - sends packets through the full system to check that they are working as expected, and stores node uptime histories as the basis of a rewards system ("mixmining" or "proof-of-mixing").
* nym-explorer - a (projected) block explorer and (existing) mixnet viewer. * nym-explorer - a (projected) block explorer and (existing) mixnet viewer.
* nym-wallet - a desktop wallet implemented using the [Tauri](https://tauri.studio/en/docs/about/intro) framework. * nym-wallet (currently in development)- a desktop wallet implemented using the [Tauri](https://tauri.studio/en/docs/about/intro) framework.
[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg?style=for-the-badge)](https://opensource.org/licenses/Apache-2.0) [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg?style=for-the-badge)](https://opensource.org/licenses/Apache-2.0)
[![Build Status](https://img.shields.io/github/workflow/status/nymtech/nym/Continuous%20integration/develop?style=for-the-badge&logo=github-actions)](https://github.com/nymtech/nym/actions?query=branch%3Adevelop) [![Build Status](https://img.shields.io/github/workflow/status/nymtech/nym/Continuous%20integration/develop?style=for-the-badge&logo=github-actions)](https://github.com/nymtech/nym/actions?query=branch%3Adevelop)
@@ -21,58 +23,16 @@ The platform is composed of multiple Rust crates. Top-level executable binary cr
### Building ### Building
Platform build instructions are available on [our docs site](https://nymtech.net/docs/stable/run-nym-nodes/build-nym). Platform build instructions are available on [our docs site](https://nymtech.net/docs/0.11.0/overview/index/).
Wallet build instructions are also available on [our docs site](https://nymtech.net/docs/stable/nym-apps/wallet#for-developers).
### Developing ### Developing
There's a `.env.sample-dev` file provided which you can rename to `.env` if you want convenient logging, backtrace, or other environment variables pre-set. The `.env` file is ignored so you don't need to worry about checking it in. There's a `.env.sample-dev` file provided which you can rename to `.env` if you want convenient logging, backtrace, or other environment variables pre-set. The `.env` file is ignored so you don't need to worry about checking it in.
For Typescript components, please see [ts-packages](./ts-packages).
### Developer chat ### Developer chat
You can chat to us in [Keybase](https://keybase.io). Download their chat app, then click **Teams -> Join a team**. Type **nymtech.friends** into the team name and hit **continue**. For general chat, hang out in the **#general** channel. Our development takes places in the **#dev** channel. Node operators should be in the **#node-operators** channel. You can chat to us in [Keybase](https://keybase.io). Download their chat app, then click **Teams -> Join a team**. Type **nymtech.friends** into the team name and hit **continue**. For general chat, hang out in the **#general** channel. Our development takes places in the **#dev** channel. Node operators should be in the **#node-operators** channel.
### Rewards
Node, node operator and delegator rewards are determined according to the principles laid out in the section 6 of [Nym Whitepaper](https://nymtech.net/nym-whitepaper.pdf). Below is a TLDR of the variables and formulas involved in calculating the epoch rewards. Initial reward pool is set to 250 million Nym, making the circulating supply 750 million Nym.
|Symbol|Definition|
|---|---|
|<img src="https://render.githubusercontent.com/render/math?math=R">|global share of rewards available, starts at 2% of the reward pool.
|<img src="https://render.githubusercontent.com/render/math?math=R_{i}">|node reward for mixnode `i`.
|<img src="https://render.githubusercontent.com/render/math?math=\sigma_{i}">|ratio of total node stake (node bond + all delegations) to the token circulating supply.
|<img src="https://render.githubusercontent.com/render/math?math=\lambda_{i}">|ratio of stake operator has pledged to their node to the token circulating supply.
|<img src="https://render.githubusercontent.com/render/math?math=\omega_{i}">|fraction of total effort undertaken by node `i`, set to `1/k`.
|<img src="https://render.githubusercontent.com/render/math?math=k">|number of nodes stakeholders are incentivised to create, set by the validators, a matter of governance. Currently determined by the `reward set` size, and set to 720 in testnet Sandbox.
|<img src="https://render.githubusercontent.com/render/math?math=\alpha">|Sybil attack resistance parameter - the higher this parameter is set the stronger the reduction in competitivness gets for a Sybil attacker.
|<img src="https://render.githubusercontent.com/render/math?math=PM_{i}">|declared profit margin of operator `i`, defaults to 10% in.
|<img src="https://render.githubusercontent.com/render/math?math=PF_{i}">|uptime of node `i`, scaled to 0 - 1, for the rewarding epoch
|<img src="https://render.githubusercontent.com/render/math?math=PP_{i}">|cost of operating node `i` for the duration of the rewarding eopoch, set to 40 NYMT.
Node reward for node `i` is determined as:
<img src="https://render.githubusercontent.com/render/math?math=R_{i}=PF_{i} \cdot R \cdot (\sigma^'_{i} \cdot \omega_{i} \cdot k %2b \alpha \cdot \lambda^'_{i} \cdot \sigma^'_{i} \cdot k)/(1 %2b \alpha)">
where:
<img src="https://render.githubusercontent.com/render/math?math=\sigma^'_{i} = min\{\sigma_{i}, 1/k\}">
and
<img src="https://render.githubusercontent.com/render/math?math=\lambda^'_{i} = min\{\lambda_{i}, 1/k\}">
Operator of node `i` is credited with the following amount:
<img src="https://render.githubusercontent.com/render/math?math=min\{PP_{i},R_{i})\} %2b max\{0, (PM_{i} %2b (1 - PM_{i}) \cdot \lambda_{i}/\delta_{i}) \cdot (R_{i} - PP_{i})\}">
Delegate with stake `s` recieves:
<img src="https://render.githubusercontent.com/render/math?math=max\{0, (1-PM_{i}) \cdot (s^'/\sigma_{i}) \cdot (R_{i} - PP_{i})\}">
where `s'` is stake `s` scaled over total token circulating supply.
### Licensing and copyright information ### Licensing and copyright information
This program is available as open source under the terms of the Apache 2.0 license. However, some elements are being licensed under CC0-1.0 and MIT. For accurate information, please check individual files. This program is available as open source under the terms of the Apache 2.0 license. However, some elements are being licensed under CC0-1.0 and MIT. For accurate information, please check individual files.
-12
View File
@@ -1,12 +0,0 @@
# Shared assets
This directory contains asset files shared by many projects in this repo.
You will find:
- favicons
- logos
- shared fonts
- shared icon SVGs
See [ts-packages/react-webpack-with-theme-example](../ts-packages/react-webpack-with-theme-example) for examples of usage.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 545 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.1 KiB

-10
View File
@@ -1,10 +0,0 @@
<svg width="64" height="64" viewBox="0 0 80 80" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M40 78.5C61.263 78.5 78.5 61.263 78.5 40C78.5 18.737 61.263 1.5 40 1.5C18.737 1.5 1.5 18.737 1.5 40C1.5 61.263 18.737 78.5 40 78.5Z" fill="#070B15" stroke="url(#paint0_linear_0_1)" stroke-width="3"/>
<path d="M31.4894 27.56L41.8623 56H48.5106H56V24H48.5106V52.4L38.1777 24H31.4894H24V56H31.4894V27.56Z" fill="white"/>
<defs>
<linearGradient id="paint0_linear_0_1" x1="0.839161" y1="80" x2="80" y2="80" gradientUnits="userSpaceOnUse">
<stop offset="0.09375" stop-color="#FB6E4E"/>
<stop offset="1" stop-color="#F51473"/>
</linearGradient>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 672 B

Binary file not shown.
-6
View File
@@ -1,6 +0,0 @@
@font-face {
font-family: 'Open Sans';
src: url('./OpenSans-VariableFont_wdth,wght.ttf') format('truetype-variations'),
url('./OpenSans-Italic-VariableFont_wdth,wght.ttf') format('truetype-variations');
font-weight: 100 1000;
}
-10
View File
@@ -1,10 +0,0 @@
<svg width="64" height="64" viewBox="0 0 80 80" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M40 78.5C61.263 78.5 78.5 61.263 78.5 40C78.5 18.737 61.263 1.5 40 1.5C18.737 1.5 1.5 18.737 1.5 40C1.5 61.263 18.737 78.5 40 78.5Z" fill="#070B15" stroke="url(#paint0_linear_0_1)" stroke-width="3"/>
<path d="M31.4894 27.56L41.8623 56H48.5106H56V24H48.5106V52.4L38.1777 24H31.4894H24V56H31.4894V27.56Z" fill="white"/>
<defs>
<linearGradient id="paint0_linear_0_1" x1="0.839161" y1="80" x2="80" y2="80" gradientUnits="userSpaceOnUse">
<stop offset="0.09375" stop-color="#FB6E4E"/>
<stop offset="1" stop-color="#F51473"/>
</linearGradient>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 714 B

-13
View File
@@ -1,13 +0,0 @@
<svg width="300" height="300" viewBox="0 0 296 296" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M148 296C229.738 296 296 229.738 296 148C296 66.2619 229.738 0 148 0C66.2619 0 0 66.2619 0 148C0 229.738 66.2619 296 148 296Z" fill="url(#paint0_linear_113_1244)"/>
<path d="M148 285.875C224.147 285.875 285.875 224.146 285.875 148C285.875 71.8536 224.147 10.1248 148 10.1248C71.8538 10.1248 10.125 71.8536 10.125 148C10.125 224.146 71.8538 285.875 148 285.875Z" fill="#121725"/>
<path d="M88.8829 120.143H88.7169V120.281V168.637L68.3289 120.226L68.3012 120.143H68.1905H56.6272H43.653H43.5146V120.281V175.719V175.857H43.653H56.6272H56.7655V175.719V127.28L77.2365 175.774L77.2642 175.857H77.3748H88.8829H101.829H101.968V175.719V120.281V120.143H101.829H88.8829Z" fill="white"/>
<path d="M252.347 120.143H227.616H227.477L227.45 120.253L214.78 168.858L202.082 120.253L202.054 120.143H201.944H177.157H176.991V120.281V175.719V175.857H177.157H190.104H190.242V175.719V127.667L202.774 175.747L202.801 175.857H202.94H226.564H226.675L226.703 175.747L239.234 127.667V175.719V175.857H239.373H252.347H252.485V175.719V120.281V120.143H252.347Z" fill="white"/>
<path d="M155.663 120.143H155.58L155.552 120.198L139.812 147.557L123.988 120.198L123.96 120.143H123.877H108.911H108.635L108.773 120.364L133.145 162.579V175.719V175.857H133.283H146.257H146.396V175.719V162.579L170.767 120.364L170.905 120.143H170.629H155.663Z" fill="white"/>
<defs>
<linearGradient id="paint0_linear_113_1244" x1="0" y1="148" x2="296" y2="148" gradientUnits="userSpaceOnUse">
<stop offset="0.09375" stop-color="#FB6E4E"/>
<stop offset="1" stop-color="#FC1D60"/>
</linearGradient>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 1.7 KiB

-5
View File
@@ -1,5 +0,0 @@
<svg width="210" height="56" viewBox="0 0 210 56" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M45.8829 0.142822H45.7169V0.28114V48.637L25.3289 0.225818L25.3012 0.142822H25.1905H13.6272H0.652966H0.514648V0.28114V55.7189V55.8572H0.652966H13.6272H13.7655V55.7189V7.28002L34.2365 55.7742L34.2642 55.8572H34.3748H45.8829H58.8294H58.9677V55.7189V0.28114V0.142822H58.8294H45.8829Z"/>
<path d="M209.347 0.142822H184.616H184.477L184.45 0.253483L171.78 48.8583L159.082 0.253483L159.054 0.142822H158.944H134.157H133.991V0.28114V55.7189V55.8572H134.157H147.104H147.242V55.7189V7.66731L159.774 55.7466L159.801 55.8572H159.94H183.564H183.675L183.703 55.7466L196.234 7.66731V55.7189V55.8572H196.373H209.347H209.485V55.7189V0.28114V0.142822H209.347Z"/>
<path d="M112.663 0.142822H112.58L112.552 0.198153L96.8116 27.5574L80.988 0.198153L80.9604 0.142822H80.8774H65.9114H65.6348L65.7731 0.364136L90.1447 42.5787V55.7189V55.8572H90.283H103.257H103.396V55.7189V42.5787L127.767 0.364136L127.905 0.142822H127.629H112.663Z"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.0 KiB

-5
View File
@@ -1,5 +0,0 @@
<svg width="200" height="200" viewBox="0 0 200 200" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M170.7 29.3001C131.7 -9.7999 68.3001 -9.7999 29.3001 29.3001C-9.7999 68.4001 -9.7999 131.7 29.3001 170.7C68.4001 209.8 131.7 209.8 170.7 170.7C209.8 131.7 209.8 68.3001 170.7 29.3001ZM162.1 162.1C127.8 196.4 72.1001 196.4 37.8001 162.1C3.5001 127.8 3.5001 72.1001 37.8001 37.8001C72.1001 3.5001 127.8 3.5001 162.1 37.8001C196.5 72.2001 196.5 127.8 162.1 162.1Z" fill="white"/>
<path d="M162.1 37.9C127.8 3.60005 72.1002 3.60005 37.8002 37.9C3.50019 72.2 3.50019 127.9 37.8002 162.2C72.1002 196.5 127.8 196.5 162.1 162.2C196.5 127.8 196.5 72.2 162.1 37.9ZM63.0002 170.7C56.8002 167.4 51.1002 163.2 46.1002 158.4V41.7C51.3002 36.7 57.2002 32.5 63.6002 29.1L137 140.9V29.3C143.2 32.6 148.9 36.8 153.9 41.6V158.3C148.7 163.3 142.8 167.5 136.4 170.9L63.0002 59.1V170.7Z" fill="#070B15"/>
<path d="M154 158.3V41.7C148.9 36.9 143.2 32.7 137.1 29.4V140.9L63.5 29C57.1 32.4 51.2 36.6 46 41.6V158.3C51.1 163.1 56.8 167.3 62.9 170.6V59.1L136.5 171C142.9 167.6 148.8 163.3 154 158.3Z" fill="white"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

-5
View File
@@ -1,5 +0,0 @@
<svg width="200" height="200" viewBox="0 0 200 200" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M170.7 29.3001C131.7 -9.7999 68.3001 -9.7999 29.3001 29.3001C-9.7999 68.4001 -9.7999 131.7 29.3001 170.7C68.4001 209.8 131.7 209.8 170.7 170.7C209.8 131.7 209.8 68.3001 170.7 29.3001ZM162.1 162.1C127.8 196.4 72.1001 196.4 37.8001 162.1C3.5001 127.8 3.5001 72.1001 37.8001 37.8001C72.1001 3.5001 127.8 3.5001 162.1 37.8001C196.5 72.2001 196.5 127.8 162.1 162.1Z" fill="#141521"/>
<path d="M162.1 37.9C127.8 3.60005 72.1002 3.60005 37.8002 37.9C3.50019 72.2 3.50019 127.9 37.8002 162.2C72.1002 196.5 127.8 196.5 162.1 162.2C196.5 127.8 196.5 72.2 162.1 37.9ZM63.0002 170.7C56.8002 167.4 51.1002 163.2 46.1002 158.4V41.7C51.3002 36.7 57.2002 32.5 63.6002 29.1L137 140.9V29.3C143.2 32.6 148.9 36.8 153.9 41.6V158.3C148.7 163.3 142.8 167.5 136.4 170.9L63.0002 59.1V170.7Z" fill="white"/>
<path d="M154 158.3V41.7C148.9 36.9 143.2 32.7 137.1 29.4V140.9L63.5 29C57.1 32.4 51.2 36.6 46 41.6V158.3C51.1 163.1 56.8 167.3 62.9 170.6V59.1L136.5 171C142.9 167.6 148.8 163.3 154 158.3Z" fill="#141521"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

+2 -5
View File
@@ -1,8 +1,8 @@
[package] [package]
name = "client-core" name = "client-core"
version = "1.0.0-rc.1" version = "0.11.0"
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"] authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
edition = "2021" edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
@@ -30,6 +30,3 @@ validator-client = { path = "../../common/client-libs/validator-client" }
[dev-dependencies] [dev-dependencies]
tempfile = "3.1.0" tempfile = "3.1.0"
[features]
coconut = []
@@ -13,6 +13,7 @@ use nymsphinx::utils::sample_poisson_duration;
use rand::{rngs::OsRng, CryptoRng, Rng}; use rand::{rngs::OsRng, CryptoRng, Rng};
use std::pin::Pin; use std::pin::Pin;
use std::sync::Arc; use std::sync::Arc;
use tokio::runtime::Handle;
use tokio::task::JoinHandle; use tokio::task::JoinHandle;
use tokio::time; use tokio::time;
@@ -164,8 +165,8 @@ impl LoopCoverTrafficStream<OsRng> {
} }
} }
pub fn start(mut self) -> JoinHandle<()> { pub fn start(mut self, handle: &Handle) -> JoinHandle<()> {
tokio::spawn(async move { handle.spawn(async move {
self.run().await; self.run().await;
}) })
} }
@@ -79,9 +79,9 @@ impl KeyManager {
))?; ))?;
let gateway_shared_key: SharedKeys = let gateway_shared_key: SharedKeys =
pemstore::load_key(client_pathfinder.gateway_shared_key())?; pemstore::load_key(&client_pathfinder.gateway_shared_key().to_owned())?;
let ack_key: AckKey = pemstore::load_key(client_pathfinder.ack_key())?; let ack_key: AckKey = pemstore::load_key(&client_pathfinder.ack_key().to_owned())?;
// TODO: ack key is never stored so it is generated now. But perhaps it should be stored // TODO: ack key is never stored so it is generated now. But perhaps it should be stored
// after all for consistency sake? // after all for consistency sake?
@@ -6,6 +6,7 @@ use futures::StreamExt;
use gateway_client::GatewayClient; use gateway_client::GatewayClient;
use log::*; use log::*;
use nymsphinx::forwarding::packet::MixPacket; use nymsphinx::forwarding::packet::MixPacket;
use tokio::runtime::Handle;
use tokio::task::JoinHandle; use tokio::task::JoinHandle;
pub type BatchMixMessageSender = mpsc::UnboundedSender<Vec<MixPacket>>; pub type BatchMixMessageSender = mpsc::UnboundedSender<Vec<MixPacket>>;
@@ -71,8 +72,8 @@ impl MixTrafficController {
} }
} }
pub fn start(mut self) -> JoinHandle<()> { pub fn start(mut self, handle: &Handle) -> JoinHandle<()> {
tokio::spawn(async move { handle.spawn(async move {
self.run().await; self.run().await;
}) })
} }
@@ -22,6 +22,7 @@ use nymsphinx::addressing::clients::Recipient;
use rand::{rngs::OsRng, CryptoRng, Rng}; use rand::{rngs::OsRng, CryptoRng, Rng};
use std::sync::Arc; use std::sync::Arc;
use std::time::Duration; use std::time::Duration;
use tokio::runtime::Handle;
use tokio::task::JoinHandle; use tokio::task::JoinHandle;
mod acknowledgement_control; mod acknowledgement_control;
@@ -169,8 +170,10 @@ impl RealMessagesController<OsRng> {
self.ack_control = Some(ack_control_fut.await.unwrap()); self.ack_control = Some(ack_control_fut.await.unwrap());
} }
pub fn start(mut self) -> JoinHandle<Self> { // &Handle is only passed for consistency sake with other client modules, but I think
tokio::spawn(async move { // when we get to refactoring, we should apply gateway approach and make it implicit
pub fn start(mut self, handle: &Handle) -> JoinHandle<Self> {
handle.spawn(async move {
self.run().await; self.run().await;
self self
}) })
@@ -15,6 +15,7 @@ use nymsphinx::params::{ReplySurbEncryptionAlgorithm, ReplySurbKeyDigestAlgorith
use nymsphinx::receiver::{MessageReceiver, MessageRecoveryError, ReconstructedMessage}; use nymsphinx::receiver::{MessageReceiver, MessageRecoveryError, ReconstructedMessage};
use std::collections::HashSet; use std::collections::HashSet;
use std::sync::Arc; use std::sync::Arc;
use tokio::runtime::Handle;
use tokio::task::JoinHandle; use tokio::task::JoinHandle;
// Buffer Requests to say "hey, send any reconstructed messages to this channel" // Buffer Requests to say "hey, send any reconstructed messages to this channel"
@@ -290,8 +291,8 @@ impl RequestReceiver {
} }
} }
fn start(mut self) -> JoinHandle<()> { fn start(mut self, handle: &Handle) -> JoinHandle<()> {
tokio::spawn(async move { handle.spawn(async move {
while let Some(request) = self.query_receiver.next().await { while let Some(request) = self.query_receiver.next().await {
match request { match request {
ReceivedBufferMessage::ReceiverAnnounce(sender) => { ReceivedBufferMessage::ReceiverAnnounce(sender) => {
@@ -321,8 +322,8 @@ impl FragmentedMessageReceiver {
mixnet_packet_receiver, mixnet_packet_receiver,
} }
} }
fn start(mut self) -> JoinHandle<()> { fn start(mut self, handle: &Handle) -> JoinHandle<()> {
tokio::spawn(async move { handle.spawn(async move {
while let Some(new_messages) = self.mixnet_packet_receiver.next().await { while let Some(new_messages) = self.mixnet_packet_receiver.next().await {
self.received_buffer.handle_new_received(new_messages).await; self.received_buffer.handle_new_received(new_messages).await;
} }
@@ -354,9 +355,9 @@ impl ReceivedMessagesBufferController {
} }
} }
pub fn start(self) { pub fn start(self, handle: &Handle) {
// TODO: should we do anything with JoinHandle(s) returned by start methods? // TODO: should we do anything with JoinHandle(s) returned by start methods?
self.fragmented_message_receiver.start(); self.fragmented_message_receiver.start(handle);
self.request_receiver.start(); self.request_receiver.start(handle);
} }
} }
@@ -1,10 +1,10 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net> // Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
use crypto::generic_array::typenum::Unsigned;
use log::*; use log::*;
use nymsphinx::anonymous_replies::{ use nymsphinx::anonymous_replies::{
encryption_key::EncryptionKeyDigest, SurbEncryptionKey, SurbEncryptionKeySize, encryption_key::EncryptionKeyDigest, encryption_key::Unsigned, SurbEncryptionKey,
SurbEncryptionKeySize,
}; };
use std::path::Path; use std::path::Path;
@@ -43,7 +43,7 @@ impl ReplyKeyStorage {
// if this fails it means we have some database corruption and we // if this fails it means we have some database corruption and we
// absolutely can't continue // absolutely can't continue
if key_bytes_ref.len() != SurbEncryptionKeySize::USIZE { if key_bytes_ref.len() != SurbEncryptionKeySize::to_usize() {
error!("REPLY KEY STORAGE DATA CORRUPTION - ENCRYPTION KEY HAS INVALID LENGTH"); error!("REPLY KEY STORAGE DATA CORRUPTION - ENCRYPTION KEY HAS INVALID LENGTH");
panic!("REPLY KEY STORAGE DATA CORRUPTION - ENCRYPTION KEY HAS INVALID LENGTH"); panic!("REPLY KEY STORAGE DATA CORRUPTION - ENCRYPTION KEY HAS INVALID LENGTH");
} }
@@ -59,7 +59,7 @@ impl ReplyKeyStorage {
) -> Result<(), ReplyKeyStorageError> { ) -> Result<(), ReplyKeyStorageError> {
let digest = encryption_key.compute_digest(); let digest = encryption_key.compute_digest();
let insertion_result = match self.db.insert(digest, encryption_key.to_bytes()) { let insertion_result = match self.db.insert(digest.to_vec(), encryption_key.to_bytes()) {
Err(e) => Err(ReplyKeyStorageError::DbWriteError(e)), Err(e) => Err(ReplyKeyStorageError::DbWriteError(e)),
Ok(existing_key) => { Ok(existing_key) => {
if existing_key.is_some() { if existing_key.is_some() {
@@ -79,7 +79,7 @@ impl ReplyKeyStorage {
&self, &self,
key_digest: EncryptionKeyDigest, key_digest: EncryptionKeyDigest,
) -> Result<Option<SurbEncryptionKey>, ReplyKeyStorageError> { ) -> Result<Option<SurbEncryptionKey>, ReplyKeyStorageError> {
let removal_result = match self.db.remove(key_digest) { let removal_result = match self.db.remove(&key_digest.to_vec()) {
Err(e) => Err(ReplyKeyStorageError::DbReadError(e)), Err(e) => Err(ReplyKeyStorageError::DbReadError(e)),
Ok(existing_key) => { Ok(existing_key) => {
Ok(existing_key.map(|existing_key| self.read_encryption_key(existing_key))) Ok(existing_key.map(|existing_key| self.read_encryption_key(existing_key)))
@@ -10,6 +10,7 @@ use std::ops::Deref;
use std::sync::Arc; use std::sync::Arc;
use std::time; use std::time;
use std::time::Duration; use std::time::Duration;
use tokio::runtime::Handle;
use tokio::sync::{RwLock, RwLockReadGuard}; use tokio::sync::{RwLock, RwLockReadGuard};
use tokio::task::JoinHandle; use tokio::task::JoinHandle;
use topology::{nym_topology_from_bonds, NymTopology}; use topology::{nym_topology_from_bonds, NymTopology};
@@ -303,8 +304,8 @@ impl TopologyRefresher {
self.topology_accessor.is_routable().await self.topology_accessor.is_routable().await
} }
pub fn start(mut self) -> JoinHandle<()> { pub fn start(mut self, handle: &Handle) -> JoinHandle<()> {
tokio::spawn(async move { handle.spawn(async move {
loop { loop {
tokio::time::sleep(self.refresh_rate).await; tokio::time::sleep(self.refresh_rate).await;
self.refresh().await; self.refresh().await;
+13 -107
View File
@@ -22,10 +22,7 @@ const DEFAULT_MESSAGE_STREAM_AVERAGE_DELAY: Duration = Duration::from_millis(20)
const DEFAULT_AVERAGE_PACKET_DELAY: Duration = Duration::from_millis(50); const DEFAULT_AVERAGE_PACKET_DELAY: Duration = Duration::from_millis(50);
const DEFAULT_TOPOLOGY_REFRESH_RATE: Duration = Duration::from_secs(5 * 60); // every 5min const DEFAULT_TOPOLOGY_REFRESH_RATE: Duration = Duration::from_secs(5 * 60); // every 5min
const DEFAULT_TOPOLOGY_RESOLUTION_TIMEOUT: Duration = Duration::from_millis(5_000); const DEFAULT_TOPOLOGY_RESOLUTION_TIMEOUT: Duration = Duration::from_millis(5_000);
// Set this to a high value for now, so that we don't risk sporadic timeouts that might cause const DEFAULT_GATEWAY_RESPONSE_TIMEOUT: Duration = Duration::from_millis(1_500);
// bought bandwidth tokens to not have time to be spent; Once we remove the gateway from the
// bandwidth bridging protocol, we can come back to a smaller timeout value
const DEFAULT_GATEWAY_RESPONSE_TIMEOUT: Duration = Duration::from_secs(5 * 60);
pub fn missing_string_value() -> String { pub fn missing_string_value() -> String {
MISSING_VALUE.to_string() MISSING_VALUE.to_string()
@@ -103,44 +100,15 @@ impl<T: NymConfig> Config<T> {
self::Client::<T>::default_reply_encryption_key_store_path(&id); self::Client::<T>::default_reply_encryption_key_store_path(&id);
} }
#[cfg(not(feature = "coconut"))]
if self
.client
.backup_bandwidth_token_keys_dir
.as_os_str()
.is_empty()
{
self.client.backup_bandwidth_token_keys_dir =
self::Client::<T>::default_backup_bandwidth_token_keys_dir(&id);
}
self.client.id = id; self.client.id = id;
} }
pub fn with_testnet_mode(&mut self, testnet_mode: bool) {
self.client.testnet_mode = testnet_mode;
}
pub fn with_gateway_endpoint<S: Into<String>>(&mut self, id: S, owner: S, listener: S) {
self.client.gateway_endpoint = GatewayEndpoint {
gateway_id: id.into(),
gateway_owner: owner.into(),
gateway_listener: listener.into(),
};
}
pub fn with_gateway_id<S: Into<String>>(&mut self, id: S) { pub fn with_gateway_id<S: Into<String>>(&mut self, id: S) {
self.client.gateway_endpoint.gateway_id = id.into(); self.client.gateway_id = id.into();
} }
#[cfg(not(feature = "coconut"))] pub fn with_gateway_listener<S: Into<String>>(&mut self, gateway_listener: S) {
pub fn with_eth_private_key<S: Into<String>>(&mut self, eth_private_key: S) { self.client.gateway_listener = gateway_listener.into();
self.client.eth_private_key = eth_private_key.into();
}
#[cfg(not(feature = "coconut"))]
pub fn with_eth_endpoint<S: Into<String>>(&mut self, eth_endpoint: S) {
self.client.eth_endpoint = eth_endpoint.into();
} }
pub fn set_custom_validator_apis(&mut self, validator_api_urls: Vec<Url>) { pub fn set_custom_validator_apis(&mut self, validator_api_urls: Vec<Url>) {
@@ -161,10 +129,6 @@ impl<T: NymConfig> Config<T> {
self.client.id.clone() self.client.id.clone()
} }
pub fn get_testnet_mode(&self) -> bool {
self.client.testnet_mode
}
pub fn get_nym_root_directory(&self) -> PathBuf { pub fn get_nym_root_directory(&self) -> PathBuf {
self.client.nym_root_directory.clone() self.client.nym_root_directory.clone()
} }
@@ -202,30 +166,11 @@ impl<T: NymConfig> Config<T> {
} }
pub fn get_gateway_id(&self) -> String { pub fn get_gateway_id(&self) -> String {
self.client.gateway_endpoint.gateway_id.clone() self.client.gateway_id.clone()
}
pub fn get_gateway_owner(&self) -> String {
self.client.gateway_endpoint.gateway_owner.clone()
} }
pub fn get_gateway_listener(&self) -> String { pub fn get_gateway_listener(&self) -> String {
self.client.gateway_endpoint.gateway_listener.clone() self.client.gateway_listener.clone()
}
#[cfg(not(feature = "coconut"))]
pub fn get_backup_bandwidth_token_keys_dir(&self) -> PathBuf {
self.client.backup_bandwidth_token_keys_dir.clone()
}
#[cfg(not(feature = "coconut"))]
pub fn get_eth_endpoint(&self) -> String {
self.client.eth_endpoint.clone()
}
#[cfg(not(feature = "coconut"))]
pub fn get_eth_private_key(&self) -> String {
self.client.eth_private_key.clone()
} }
// Debug getters // Debug getters
@@ -280,19 +225,6 @@ impl<T: NymConfig> Default for Config<T> {
} }
} }
#[derive(Debug, Default, Deserialize, PartialEq, Serialize)]
struct GatewayEndpoint {
/// gateway_id specifies ID of the gateway to which the client should send messages.
/// If initially omitted, a random gateway will be chosen from the available topology.
gateway_id: String,
/// Address of the gateway owner to which the client should send messages.
gateway_owner: String,
/// Address of the gateway listener to which all client requests should be sent.
gateway_listener: String,
}
#[derive(Debug, Deserialize, PartialEq, Serialize)] #[derive(Debug, Deserialize, PartialEq, Serialize)]
pub struct Client<T> { pub struct Client<T> {
/// Version of the client for which this configuration was created. /// Version of the client for which this configuration was created.
@@ -302,11 +234,6 @@ pub struct Client<T> {
/// ID specifies the human readable ID of this particular client. /// ID specifies the human readable ID of this particular client.
id: String, id: String,
/// Indicates whether this client is running in a testnet mode, thus attempting
/// to claim bandwidth without presenting bandwidth credentials.
#[serde(default)]
testnet_mode: bool,
/// Addresses to APIs running on validator from which the client gets the view of the network. /// Addresses to APIs running on validator from which the client gets the view of the network.
validator_api_urls: Vec<Url>, validator_api_urls: Vec<Url>,
@@ -334,22 +261,12 @@ pub struct Client<T> {
/// sent but not received back. /// sent but not received back.
reply_encryption_key_store_path: PathBuf, reply_encryption_key_store_path: PathBuf,
/// Information regarding how the client should send data to gateway. /// gateway_id specifies ID of the gateway to which the client should send messages.
gateway_endpoint: GatewayEndpoint, /// If initially omitted, a random gateway will be chosen from the available topology.
gateway_id: String,
/// Path to directory containing public/private keys used for bandwidth token purchase. /// Address of the gateway listener to which all client requests should be sent.
/// Those are saved in case of emergency, to be able to reclaim bandwidth tokens. gateway_listener: String,
/// The public key is the name of the file, while the private key is the content.
#[cfg(not(feature = "coconut"))]
backup_bandwidth_token_keys_dir: PathBuf,
/// Ethereum private key.
#[cfg(not(feature = "coconut"))]
eth_private_key: String,
/// Address to an Ethereum full node.
#[cfg(not(feature = "coconut"))]
eth_endpoint: String,
/// nym_home_directory specifies absolute path to the home nym Clients directory. /// nym_home_directory specifies absolute path to the home nym Clients directory.
/// It is expected to use default value and hence .toml file should not redefine this field. /// It is expected to use default value and hence .toml file should not redefine this field.
@@ -365,7 +282,6 @@ impl<T: NymConfig> Default for Client<T> {
Client { Client {
version: env!("CARGO_PKG_VERSION").to_string(), version: env!("CARGO_PKG_VERSION").to_string(),
id: "".to_string(), id: "".to_string(),
testnet_mode: false,
validator_api_urls: default_api_endpoints(), validator_api_urls: default_api_endpoints(),
private_identity_key_file: Default::default(), private_identity_key_file: Default::default(),
public_identity_key_file: Default::default(), public_identity_key_file: Default::default(),
@@ -374,13 +290,8 @@ impl<T: NymConfig> Default for Client<T> {
gateway_shared_key_file: Default::default(), gateway_shared_key_file: Default::default(),
ack_key_file: Default::default(), ack_key_file: Default::default(),
reply_encryption_key_store_path: Default::default(), reply_encryption_key_store_path: Default::default(),
gateway_endpoint: Default::default(), gateway_id: "".to_string(),
#[cfg(not(feature = "coconut"))] gateway_listener: "".to_string(),
backup_bandwidth_token_keys_dir: Default::default(),
#[cfg(not(feature = "coconut"))]
eth_private_key: "".to_string(),
#[cfg(not(feature = "coconut"))]
eth_endpoint: "".to_string(),
nym_root_directory: T::default_root_directory(), nym_root_directory: T::default_root_directory(),
super_struct: Default::default(), super_struct: Default::default(),
} }
@@ -415,11 +326,6 @@ impl<T: NymConfig> Client<T> {
fn default_reply_encryption_key_store_path(id: &str) -> PathBuf { fn default_reply_encryption_key_store_path(id: &str) -> PathBuf {
T::default_data_directory(Some(id)).join("reply_key_store") T::default_data_directory(Some(id)).join("reply_key_store")
} }
#[cfg(not(feature = "coconut"))]
fn default_backup_bandwidth_token_keys_dir(id: &str) -> PathBuf {
T::default_data_directory(Some(id)).join("backup_bandwidth_token_keys")
}
} }
#[derive(Debug, Default, Deserialize, PartialEq, Serialize)] #[derive(Debug, Default, Deserialize, PartialEq, Serialize)]
+3 -8
View File
@@ -1,8 +1,8 @@
[package] [package]
name = "nym-client" name = "nym-client"
version = "1.0.0-rc.1" version = "0.11.0"
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"] authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"]
edition = "2021" edition = "2018"
rust-version = "1.56" rust-version = "1.56"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
@@ -24,7 +24,7 @@ dirs = "3.0" # for determining default store directories in config
dotenv = "0.15.0" # for obtaining environmental variables (only used for RUST_LOG for time being) dotenv = "0.15.0" # for obtaining environmental variables (only used for RUST_LOG for time being)
log = "0.4" # self explanatory log = "0.4" # self explanatory
pretty_env_logger = "0.4" # for formatting log messages pretty_env_logger = "0.4" # for formatting log messages
rand = { version = "0.7.3", features = ["wasm-bindgen"] } # rng-related traits + some rng implementation to use rand = {version = "0.7.3", features = ["wasm-bindgen"]} # rng-related traits + some rng implementation to use
serde = { version = "1.0.104", features = ["derive"] } # for config serialization/deserialization serde = { version = "1.0.104", features = ["derive"] } # for config serialization/deserialization
sled = "0.34" # for storage of replySURB decryption keys sled = "0.34" # for storage of replySURB decryption keys
tokio = { version = "1.4", features = ["rt-multi-thread", "net", "signal"] } # async runtime tokio = { version = "1.4", features = ["rt-multi-thread", "net", "signal"] } # async runtime
@@ -44,14 +44,9 @@ topology = { path = "../../common/topology" }
websocket-requests = { path = "websocket-requests" } websocket-requests = { path = "websocket-requests" }
validator-client = { path = "../../common/client-libs/validator-client" } validator-client = { path = "../../common/client-libs/validator-client" }
version-checker = { path = "../../common/version-checker" } version-checker = { path = "../../common/version-checker" }
network-defaults = { path = "../../common/network-defaults" }
[features] [features]
coconut = ["coconut-interface", "credentials", "gateway-requests/coconut", "gateway-client/coconut"] coconut = ["coconut-interface", "credentials", "gateway-requests/coconut", "gateway-client/coconut"]
eth = []
[dev-dependencies] [dev-dependencies]
serde_json = "1.0" # for the "textsend" example serde_json = "1.0" # for the "textsend" example
[build-dependencies]
vergen = { version = "5", default-features = false, features = ["build", "git", "rustc", "cargo"] }
-8
View File
@@ -1,8 +0,0 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use vergen::{vergen, Config};
fn main() {
vergen(Config::default()).expect("failed to extract build metadata")
}
@@ -3,5 +3,6 @@ module github.com/nymtech/nym/clients/native/examples/go
go 1.14 go 1.14
require ( require (
github.com/btcsuite/btcutil v1.0.2 // indirect
github.com/gorilla/websocket v1.4.2 github.com/gorilla/websocket v1.4.2
) )
File diff suppressed because it is too large Load Diff
@@ -18,12 +18,14 @@
"author": "Dave Hrycyszyn", "author": "Dave Hrycyszyn",
"license": "Apache-2.0", "license": "Apache-2.0",
"devDependencies": { "devDependencies": {
"clean-webpack-plugin": "^4.0.0", "autoprefixer": "^10.2.6",
"webpack": "^5.70.0", "clean-webpack-plugin": "^3.0.0",
"webpack-cli": "^4.9.2", "webpack": "^4.42.1",
"webpack-dev-server": "^4.7.4" "webpack-cli": "^3.3.11",
"webpack-dev-server": "^3.11.0"
}, },
"dependencies": { "dependencies": {
"html-webpack-plugin": "^5.5.0" "core-js": "^3.6.5",
"html-webpack-plugin": "^4.2.0"
} }
} }
@@ -1,9 +1,9 @@
const autoprefixer = require('autoprefixer');
const path = require('path'); const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin'); const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin'); const { CleanWebpackPlugin } = require('clean-webpack-plugin');
module.exports = { module.exports = {
mode: 'production',
entry: './src/index.js', entry: './src/index.js',
output: { output: {
filename: 'bundle.js', filename: 'bundle.js',
@@ -18,7 +18,7 @@ module.exports = {
}) })
], ],
devServer: { devServer: {
static: path.join(__dirname, 'dist'), contentBase: path.join(__dirname, 'dist'),
compress: true, compress: true,
port: 8888 port: 8888
} }
@@ -35,7 +35,7 @@ async fn send_file_with_reply() {
let (mut ws_stream, _) = connect_async(uri).await.unwrap(); let (mut ws_stream, _) = connect_async(uri).await.unwrap();
let recipient = get_self_address(&mut ws_stream).await; let recipient = get_self_address(&mut ws_stream).await;
println!("our full address is: {}", recipient); println!("our full address is: {}", recipient.to_string());
let read_data = std::fs::read("examples/dummy_file").unwrap(); let read_data = std::fs::read("examples/dummy_file").unwrap();
@@ -83,7 +83,7 @@ async fn send_file_without_reply() {
let (mut ws_stream, _) = connect_async(uri).await.unwrap(); let (mut ws_stream, _) = connect_async(uri).await.unwrap();
let recipient = get_self_address(&mut ws_stream).await; let recipient = get_self_address(&mut ws_stream).await;
println!("our full address is: {}", recipient); println!("our full address is: {}", recipient.to_string());
let read_data = std::fs::read("examples/dummy_file").unwrap(); let read_data = std::fs::read("examples/dummy_file").unwrap();
@@ -36,7 +36,7 @@ async fn send_text_with_reply() {
let (mut ws_stream, _) = connect_async(uri).await.unwrap(); let (mut ws_stream, _) = connect_async(uri).await.unwrap();
let recipient = get_self_address(&mut ws_stream).await; let recipient = get_self_address(&mut ws_stream).await;
println!("our full address is: {}", recipient); println!("our full address is: {}", recipient.to_string());
let send_request = json!({ let send_request = json!({
"type" : "send", "type" : "send",
@@ -76,7 +76,7 @@ async fn send_text_without_reply() {
let (mut ws_stream, _) = connect_async(uri).await.unwrap(); let (mut ws_stream, _) = connect_async(uri).await.unwrap();
let recipient = get_self_address(&mut ws_stream).await; let recipient = get_self_address(&mut ws_stream).await;
println!("our full address is: {}", recipient); println!("our full address is: {}", recipient.to_string());
let send_request = json!({ let send_request = json!({
"type" : "send", "type" : "send",
+7 -27
View File
@@ -5,7 +5,7 @@ pub(crate) fn config_template() -> &'static str {
// While using normal toml marshalling would have been way simpler with less overhead, // While using normal toml marshalling would have been way simpler with less overhead,
// I think it's useful to have comments attached to the saved config file to explain behaviour of // I think it's useful to have comments attached to the saved config file to explain behaviour of
// particular fields. // particular fields.
// Note: any changes to the template must be reflected in the appropriate structs. // Note: any changes to the template must be reflected in the appropriate structs in verloc.
r#" r#"
# This is a TOML config file. # This is a TOML config file.
# For more information, see https://github.com/toml-lang/toml # For more information, see https://github.com/toml-lang/toml
@@ -19,10 +19,6 @@ version = '{{ client.version }}'
# Human readable ID of this particular client. # Human readable ID of this particular client.
id = '{{ client.id }}' id = '{{ client.id }}'
# Indicates whether this client is running in a testnet mode, thus attempting
# to claim bandwidth without presenting bandwidth credentials.
testnet_mode = {{ client.testnet_mode }}
# Addresses to APIs running on validator from which the client gets the view of the network. # Addresses to APIs running on validator from which the client gets the view of the network.
validator_api_urls = [ validator_api_urls = [
{{#each client.validator_api_urls }} {{#each client.validator_api_urls }}
@@ -46,19 +42,14 @@ public_encryption_key_file = '{{ client.public_encryption_key_file }}'
# sent but not received back. # sent but not received back.
reply_encryption_key_store_path = '{{ client.reply_encryption_key_store_path }}' reply_encryption_key_store_path = '{{ client.reply_encryption_key_store_path }}'
# Path to directory containing public/private keys used for bandwidth token purchase.
# Those are saved in case of emergency, to be able to reclaim bandwidth tokens.
# The public key is the name of the file, while the private key is the content.
backup_bandwidth_token_keys_dir = '{{ client.backup_bandwidth_token_keys_dir }}'
# Ethereum private key.
eth_private_key = '{{ client.eth_private_key }}'
# Addess to an Ethereum full node.
eth_endpoint = '{{ client.eth_endpoint }}'
##### additional client config options ##### ##### additional client config options #####
# ID of the gateway from which the client should be fetching messages.
gateway_id = '{{ client.gateway_id }}'
# Address of the gateway listener to which all client requests should be sent.
gateway_listener = '{{ client.gateway_listener }}'
# A gateway specific, optional, base58 stringified shared key used for # A gateway specific, optional, base58 stringified shared key used for
# communication with particular gateway. # communication with particular gateway.
gateway_shared_key_file = '{{ client.gateway_shared_key_file }}' gateway_shared_key_file = '{{ client.gateway_shared_key_file }}'
@@ -72,17 +63,6 @@ ack_key_file = '{{ client.ack_key_file }}'
# Absolute path to the home Nym Clients directory. # Absolute path to the home Nym Clients directory.
nym_root_directory = '{{ client.nym_root_directory }}' nym_root_directory = '{{ client.nym_root_directory }}'
[client.gateway_endpoint]
# ID of the gateway from which the client should be fetching messages.
gateway_id = '{{ client.gateway_endpoint.gateway_id }}'
# Address of the gateway owner to which the client should send messages.
gateway_owner = '{{ client.gateway_endpoint.gateway_owner }}'
# Address of the gateway listener to which all client requests should be sent.
gateway_listener = '{{ client.gateway_endpoint.gateway_listener }}'
##### socket config options ##### ##### socket config options #####
+101 -57
View File
@@ -1,6 +1,10 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net> // Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
use futures::channel::mpsc;
use log::*;
use tokio::runtime::Runtime;
use client_core::client::cover_traffic_stream::LoopCoverTrafficStream; use client_core::client::cover_traffic_stream::LoopCoverTrafficStream;
use client_core::client::inbound_messages::{ use client_core::client::inbound_messages::{
InputMessage, InputMessageReceiver, InputMessageSender, InputMessage, InputMessageReceiver, InputMessageSender,
@@ -20,14 +24,19 @@ use client_core::client::topology_control::{
TopologyAccessor, TopologyRefresher, TopologyRefresherConfig, TopologyAccessor, TopologyRefresher, TopologyRefresherConfig,
}; };
use client_core::config::persistence::key_pathfinder::ClientKeyPathfinder; use client_core::config::persistence::key_pathfinder::ClientKeyPathfinder;
#[cfg(feature = "coconut")]
use coconut_interface::{hash_to_scalar, Credential, Parameters};
#[cfg(feature = "coconut")]
use credentials::bandwidth::{
prepare_for_spending, BandwidthVoucherAttributes, BANDWIDTH_VALUE, TOTAL_ATTRIBUTES,
};
#[cfg(feature = "coconut")]
use credentials::obtain_aggregate_verification_key;
use crypto::asymmetric::identity; use crypto::asymmetric::identity;
use futures::channel::mpsc;
use gateway_client::bandwidth::BandwidthController;
use gateway_client::{ use gateway_client::{
AcknowledgementReceiver, AcknowledgementSender, GatewayClient, MixnetMessageReceiver, AcknowledgementReceiver, AcknowledgementSender, GatewayClient, MixnetMessageReceiver,
MixnetMessageSender, MixnetMessageSender,
}; };
use log::*;
use nymsphinx::addressing::clients::Recipient; use nymsphinx::addressing::clients::Recipient;
use nymsphinx::addressing::nodes::NodeIdentity; use nymsphinx::addressing::nodes::NodeIdentity;
use nymsphinx::anonymous_replies::ReplySurb; use nymsphinx::anonymous_replies::ReplySurb;
@@ -43,6 +52,11 @@ pub struct NymClient {
/// key filepaths, etc. /// key filepaths, etc.
config: Config, config: Config,
/// Tokio runtime used for futures execution.
// TODO: JS: Personally I think I prefer the implicit way of using it that we've done with the
// gateway.
runtime: Runtime,
/// KeyManager object containing smart pointers to all relevant keys used by the client. /// KeyManager object containing smart pointers to all relevant keys used by the client.
key_manager: KeyManager, key_manager: KeyManager,
@@ -62,6 +76,7 @@ impl NymClient {
let key_manager = KeyManager::load_keys(&pathfinder).expect("failed to load stored keys"); let key_manager = KeyManager::load_keys(&pathfinder).expect("failed to load stored keys");
NymClient { NymClient {
runtime: Runtime::new().unwrap(),
config, config,
key_manager, key_manager,
input_tx: None, input_tx: None,
@@ -87,6 +102,9 @@ impl NymClient {
mix_tx: BatchMixMessageSender, mix_tx: BatchMixMessageSender,
) { ) {
info!("Starting loop cover traffic stream..."); info!("Starting loop cover traffic stream...");
// we need to explicitly enter runtime due to "next_delay: time::delay_for(Default::default())"
// set in the constructor which HAS TO be called within context of a tokio runtime
let _guard = self.runtime.enter();
LoopCoverTrafficStream::new( LoopCoverTrafficStream::new(
self.key_manager.ack_key(), self.key_manager.ack_key(),
@@ -99,7 +117,7 @@ impl NymClient {
self.as_mix_recipient(), self.as_mix_recipient(),
topology_accessor, topology_accessor,
) )
.start(); .start(self.runtime.handle());
} }
fn start_real_traffic_controller( fn start_real_traffic_controller(
@@ -121,6 +139,10 @@ impl NymClient {
); );
info!("Starting real traffic stream..."); info!("Starting real traffic stream...");
// we need to explicitly enter runtime due to "next_delay: time::delay_for(Default::default())"
// set in the constructor [of OutQueueControl] which HAS TO be called within context of a tokio runtime
// When refactoring this restriction should definitely be removed.
let _guard = self.runtime.enter();
RealMessagesController::new( RealMessagesController::new(
controller_config, controller_config,
@@ -130,7 +152,7 @@ impl NymClient {
topology_accessor, topology_accessor,
reply_key_storage, reply_key_storage,
) )
.start(); .start(self.runtime.handle());
} }
// buffer controlling all messages fetched from provider // buffer controlling all messages fetched from provider
@@ -148,10 +170,45 @@ impl NymClient {
mixnet_receiver, mixnet_receiver,
reply_key_storage, reply_key_storage,
) )
.start() .start(self.runtime.handle())
} }
async fn start_gateway_client( #[cfg(feature = "coconut")]
async fn prepare_coconut_credential(&self) -> Credential {
let verification_key = obtain_aggregate_verification_key(
&self.config.get_base().get_validator_api_endpoints(),
)
.await
.expect("could not obtain aggregate verification key of validators");
let params = Parameters::new(TOTAL_ATTRIBUTES).unwrap();
let bandwidth_credential_attributes = BandwidthVoucherAttributes {
serial_number: params.random_scalar(),
binding_number: params.random_scalar(),
voucher_value: hash_to_scalar(BANDWIDTH_VALUE.to_be_bytes()),
voucher_info: hash_to_scalar(String::from("BandwidthVoucher").as_bytes()),
};
let bandwidth_credential = credentials::bandwidth::obtain_signature(
&params,
&bandwidth_credential_attributes,
&self.config.get_base().get_validator_api_endpoints(),
)
.await
.expect("could not obtain bandwidth credential");
// the above would presumably be loaded from a file
// the below would only be executed once we know where we want to spend it (i.e. which gateway and stuff)
prepare_for_spending(
&self.key_manager.identity_keypair().public_key().to_bytes(),
&bandwidth_credential,
&bandwidth_credential_attributes,
&verification_key,
)
.expect("could not prepare out bandwidth credential for spending")
}
fn start_gateway_client(
&mut self, &mut self,
mixnet_message_sender: MixnetMessageSender, mixnet_message_sender: MixnetMessageSender,
ack_sender: AcknowledgementSender, ack_sender: AcknowledgementSender,
@@ -160,10 +217,6 @@ impl NymClient {
if gateway_id.is_empty() { if gateway_id.is_empty() {
panic!("The identity of the gateway is unknown - did you run `nym-client` init?") panic!("The identity of the gateway is unknown - did you run `nym-client` init?")
} }
let gateway_owner = self.config.get_base().get_gateway_owner();
if gateway_owner.is_empty() {
panic!("The owner of the gateway is unknown - did you run `nym-client` init?")
}
let gateway_address = self.config.get_base().get_gateway_listener(); let gateway_address = self.config.get_base().get_gateway_listener();
if gateway_address.is_empty() { if gateway_address.is_empty() {
panic!("The address of the gateway is unknown - did you run `nym-client` init?") panic!("The address of the gateway is unknown - did you run `nym-client` init?")
@@ -172,45 +225,35 @@ impl NymClient {
let gateway_identity = identity::PublicKey::from_base58_string(gateway_id) let gateway_identity = identity::PublicKey::from_base58_string(gateway_id)
.expect("provided gateway id is invalid!"); .expect("provided gateway id is invalid!");
#[cfg(feature = "coconut")] self.runtime.block_on(async {
let bandwidth_controller = BandwidthController::new( #[cfg(feature = "coconut")]
self.config.get_base().get_validator_api_endpoints(), let coconut_credential = self.prepare_coconut_credential().await;
*self.key_manager.identity_keypair().public_key(),
);
#[cfg(not(feature = "coconut"))]
let bandwidth_controller = BandwidthController::new(
self.config.get_base().get_eth_endpoint(),
self.config.get_base().get_eth_private_key(),
self.config.get_base().get_backup_bandwidth_token_keys_dir(),
)
.expect("Could not create bandwidth controller");
let mut gateway_client = GatewayClient::new( let mut gateway_client = GatewayClient::new(
gateway_address, gateway_address,
self.key_manager.identity_keypair(), self.key_manager.identity_keypair(),
gateway_identity, gateway_identity,
gateway_owner, Some(self.key_manager.gateway_shared_key()),
Some(self.key_manager.gateway_shared_key()), mixnet_message_sender,
mixnet_message_sender, ack_sender,
ack_sender, self.config.get_base().get_gateway_response_timeout(),
self.config.get_base().get_gateway_response_timeout(), );
Some(bandwidth_controller),
);
if self.config.get_base().get_testnet_mode() { gateway_client
gateway_client.set_testnet_mode(true) .authenticate_and_start(
} #[cfg(feature = "coconut")]
gateway_client Some(coconut_credential),
.authenticate_and_start() )
.await .await
.expect("could not authenticate and start up the gateway connection"); .expect("could not authenticate and start up the gateway connection");
gateway_client gateway_client
})
} }
// future responsible for periodically polling directory server and updating // future responsible for periodically polling directory server and updating
// the current global view of topology // the current global view of topology
async fn start_topology_refresher(&mut self, topology_accessor: TopologyAccessor) { fn start_topology_refresher(&mut self, topology_accessor: TopologyAccessor) {
let topology_refresher_config = TopologyRefresherConfig::new( let topology_refresher_config = TopologyRefresherConfig::new(
self.config.get_base().get_validator_api_endpoints(), self.config.get_base().get_validator_api_endpoints(),
self.config.get_base().get_topology_refresh_rate(), self.config.get_base().get_topology_refresh_rate(),
@@ -221,10 +264,13 @@ impl NymClient {
// before returning, block entire runtime to refresh the current network view so that any // before returning, block entire runtime to refresh the current network view so that any
// components depending on topology would see a non-empty view // components depending on topology would see a non-empty view
info!("Obtaining initial network topology"); info!("Obtaining initial network topology");
topology_refresher.refresh().await; self.runtime.block_on(topology_refresher.refresh());
// TODO: a slightly more graceful termination here // TODO: a slightly more graceful termination here
if !topology_refresher.is_topology_routable().await { if !self
.runtime
.block_on(topology_refresher.is_topology_routable())
{
panic!( panic!(
"The current network topology seem to be insufficient to route any packets through\ "The current network topology seem to be insufficient to route any packets through\
- check if enough nodes and a gateway are online" - check if enough nodes and a gateway are online"
@@ -232,7 +278,7 @@ impl NymClient {
} }
info!("Starting topology refresher..."); info!("Starting topology refresher...");
topology_refresher.start(); topology_refresher.start(self.runtime.handle());
} }
// controller for sending sphinx packets to mixnet (either real traffic or cover traffic) // controller for sending sphinx packets to mixnet (either real traffic or cover traffic)
@@ -245,7 +291,7 @@ impl NymClient {
gateway_client: GatewayClient, gateway_client: GatewayClient,
) { ) {
info!("Starting mix traffic controller..."); info!("Starting mix traffic controller...");
MixTrafficController::new(mix_rx, gateway_client).start(); MixTrafficController::new(mix_rx, gateway_client).start(self.runtime.handle());
} }
fn start_websocket_listener( fn start_websocket_listener(
@@ -258,7 +304,8 @@ impl NymClient {
let websocket_handler = let websocket_handler =
websocket::Handler::new(msg_input, buffer_requester, self.as_mix_recipient()); websocket::Handler::new(msg_input, buffer_requester, self.as_mix_recipient());
websocket::Listener::new(self.config.get_listening_port()).start(websocket_handler); websocket::Listener::new(self.config.get_listening_port())
.start(self.runtime.handle(), websocket_handler);
} }
/// EXPERIMENTAL DIRECT RUST API /// EXPERIMENTAL DIRECT RUST API
@@ -305,9 +352,9 @@ impl NymClient {
} }
/// blocking version of `start` method. Will run forever (or until SIGINT is sent) /// blocking version of `start` method. Will run forever (or until SIGINT is sent)
pub async fn run_forever(&mut self) { pub fn run_forever(&mut self) {
self.start().await; self.start();
if let Err(e) = tokio::signal::ctrl_c().await { if let Err(e) = self.runtime.block_on(tokio::signal::ctrl_c()) {
error!( error!(
"There was an error while capturing SIGINT - {:?}. We will terminate regardless", "There was an error while capturing SIGINT - {:?}. We will terminate regardless",
e e
@@ -319,7 +366,7 @@ impl NymClient {
); );
} }
pub async fn start(&mut self) { pub fn start(&mut self) {
info!("Starting nym client"); info!("Starting nym client");
// channels for inter-component communication // channels for inter-component communication
// TODO: make the channels be internally created by the relevant components // TODO: make the channels be internally created by the relevant components
@@ -351,17 +398,14 @@ impl NymClient {
// the components are started in very specific order. Unless you know what you are doing, // the components are started in very specific order. Unless you know what you are doing,
// do not change that. // do not change that.
self.start_topology_refresher(shared_topology_accessor.clone()) self.start_topology_refresher(shared_topology_accessor.clone());
.await;
self.start_received_messages_buffer_controller( self.start_received_messages_buffer_controller(
received_buffer_request_receiver, received_buffer_request_receiver,
mixnet_messages_receiver, mixnet_messages_receiver,
reply_key_storage.clone(), reply_key_storage.clone(),
); );
let gateway_client = self let gateway_client = self.start_gateway_client(mixnet_messages_sender, ack_sender);
.start_gateway_client(mixnet_messages_sender, ack_sender)
.await;
self.start_mix_traffic_controller(sphinx_message_receiver, gateway_client); self.start_mix_traffic_controller(sphinx_message_receiver, gateway_client);
self.start_real_traffic_controller( self.start_real_traffic_controller(
+40 -61
View File
@@ -1,45 +1,39 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net> // Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
use std::convert::TryInto;
use std::sync::Arc;
use std::time::Duration;
use clap::{App, Arg, ArgMatches}; use clap::{App, Arg, ArgMatches};
use rand::rngs::OsRng;
use rand::seq::SliceRandom;
use rand::thread_rng;
use url::Url;
use client_core::client::key_manager::KeyManager; use client_core::client::key_manager::KeyManager;
use client_core::config::persistence::key_pathfinder::ClientKeyPathfinder; use client_core::config::persistence::key_pathfinder::ClientKeyPathfinder;
#[cfg(feature = "coconut")] #[cfg(feature = "coconut")]
use coconut_interface::{hash_to_scalar, Credential, Parameters}; use coconut_interface::{hash_to_scalar, Credential, Parameters};
use config::NymConfig; use config::NymConfig;
#[cfg(feature = "coconut")] #[cfg(feature = "coconut")]
use credentials::coconut::bandwidth::{ use credentials::bandwidth::{
obtain_signature, prepare_for_spending, BandwidthVoucherAttributes, TOTAL_ATTRIBUTES, prepare_for_spending, BandwidthVoucherAttributes, BANDWIDTH_VALUE, TOTAL_ATTRIBUTES,
}; };
#[cfg(feature = "coconut")] #[cfg(feature = "coconut")]
use credentials::obtain_aggregate_verification_key; use credentials::obtain_aggregate_verification_key;
use crypto::asymmetric::{encryption, identity}; use crypto::asymmetric::{encryption, identity};
use gateway_client::GatewayClient; use gateway_client::GatewayClient;
use gateway_requests::registration::handshake::SharedKeys; use gateway_requests::registration::handshake::SharedKeys;
#[cfg(feature = "coconut")]
use network_defaults::BANDWIDTH_VALUE;
use nymsphinx::addressing::clients::Recipient; use nymsphinx::addressing::clients::Recipient;
use nymsphinx::addressing::nodes::NodeIdentity; use nymsphinx::addressing::nodes::NodeIdentity;
use rand::rngs::OsRng;
use rand::seq::SliceRandom;
use rand::thread_rng;
use std::convert::TryInto;
use std::sync::Arc;
use std::time::Duration;
use topology::{filter::VersionFilterable, gateway}; use topology::{filter::VersionFilterable, gateway};
use url::Url;
use crate::client::config::Config; use crate::client::config::Config;
use crate::commands::override_config; use crate::commands::override_config;
#[cfg(feature = "eth")]
#[cfg(not(feature = "coconut"))]
use crate::commands::{
DEFAULT_ETH_ENDPOINT, DEFAULT_ETH_PRIVATE_KEY, ETH_ENDPOINT_ARG_NAME, ETH_PRIVATE_KEY_ARG_NAME,
TESTNET_MODE_ARG_NAME,
};
pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> { pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
let app = App::new("init") App::new("init")
.about("Initialise a Nym client. Do this first!") .about("Initialise a Nym client. Do this first!")
.arg(Arg::with_name("id") .arg(Arg::with_name("id")
.long("id") .long("id")
@@ -71,31 +65,7 @@ pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
.long("fastmode") .long("fastmode")
.hidden(true) // this will prevent this flag from being displayed in `--help` .hidden(true) // this will prevent this flag from being displayed in `--help`
.help("Mostly debug-related option to increase default traffic rate so that you would not need to modify config post init") .help("Mostly debug-related option to increase default traffic rate so that you would not need to modify config post init")
);
#[cfg(feature = "eth")]
#[cfg(not(feature = "coconut"))]
let app = app
.arg(
Arg::with_name(TESTNET_MODE_ARG_NAME)
.long(TESTNET_MODE_ARG_NAME)
.help("Set this client to work in a testnet mode that would attempt to use gateway without bandwidth credential requirement. If this value is set, --eth_endpoint and --eth_private_key don't need to be set.")
.conflicts_with_all(&[ETH_ENDPOINT_ARG_NAME, ETH_PRIVATE_KEY_ARG_NAME])
) )
.arg(Arg::with_name(ETH_ENDPOINT_ARG_NAME)
.long(ETH_ENDPOINT_ARG_NAME)
.help("URL of an Ethereum full node that we want to use for getting bandwidth tokens from ERC20 tokens. If you don't want to set this value, use --testnet-mode instead")
.takes_value(true)
.default_value_if(TESTNET_MODE_ARG_NAME, None, DEFAULT_ETH_ENDPOINT)
.required(true))
.arg(Arg::with_name(ETH_PRIVATE_KEY_ARG_NAME)
.long(ETH_PRIVATE_KEY_ARG_NAME)
.help("Ethereum private key used for obtaining bandwidth tokens from ERC20 tokens. If you don't want to set this value, use --testnet-mode instead")
.takes_value(true)
.default_value_if(TESTNET_MODE_ARG_NAME, None, DEFAULT_ETH_PRIVATE_KEY)
.required(true)
);
app
} }
// this behaviour should definitely be changed, we shouldn't // this behaviour should definitely be changed, we shouldn't
@@ -114,10 +84,13 @@ async fn _prepare_temporary_credential(validators: &[Url], raw_identity: &[u8])
voucher_info: hash_to_scalar(String::from("BandwidthVoucher").as_bytes()), voucher_info: hash_to_scalar(String::from("BandwidthVoucher").as_bytes()),
}; };
let bandwidth_credential = let bandwidth_credential = credentials::bandwidth::obtain_signature(
obtain_signature(&params, &bandwidth_credential_attributes, validators) &params,
.await &bandwidth_credential_attributes,
.expect("could not obtain bandwidth credential"); validators,
)
.await
.expect("could not obtain bandwidth credential");
prepare_for_spending( prepare_for_spending(
raw_identity, raw_identity,
@@ -136,7 +109,6 @@ async fn register_with_gateway(
let mut gateway_client = GatewayClient::new_init( let mut gateway_client = GatewayClient::new_init(
gateway.clients_address(), gateway.clients_address(),
gateway.identity_key, gateway.identity_key,
gateway.owner.clone(),
our_identity.clone(), our_identity.clone(),
timeout, timeout,
); );
@@ -220,7 +192,7 @@ fn show_address(config: &Config) {
println!("\nThe address of this client is: {}", client_recipient); println!("\nThe address of this client is: {}", client_recipient);
} }
pub async fn execute(matches: ArgMatches<'static>) { pub fn execute(matches: &ArgMatches) {
println!("Initialising client..."); println!("Initialising client...");
let id = matches.value_of("id").unwrap(); // required for now let id = matches.value_of("id").unwrap(); // required for now
@@ -238,7 +210,7 @@ pub async fn execute(matches: ArgMatches<'static>) {
// TODO: ideally that should be the last thing that's being done to config. // TODO: ideally that should be the last thing that's being done to config.
// However, we are later further overriding it with gateway id // However, we are later further overriding it with gateway id
config = override_config(config, &matches); config = override_config(config, matches);
if matches.is_present("fastmode") { if matches.is_present("fastmode") {
config.get_base_mut().set_high_default_traffic_volume(); config.get_base_mut().set_high_default_traffic_volume();
} }
@@ -251,19 +223,26 @@ pub async fn execute(matches: ArgMatches<'static>) {
let chosen_gateway_id = matches.value_of("gateway"); let chosen_gateway_id = matches.value_of("gateway");
let gateway_details = gateway_details( let registration_fut = async {
config.get_base().get_validator_api_endpoints(), let gate_details = gateway_details(
chosen_gateway_id, config.get_base().get_validator_api_endpoints(),
) chosen_gateway_id,
.await; )
let shared_keys = .await;
register_with_gateway(&gateway_details, key_manager.identity_keypair()).await; config
.get_base_mut()
.with_gateway_id(gate_details.identity_key.to_base58_string());
let shared_keys =
register_with_gateway(&gate_details, key_manager.identity_keypair()).await;
(shared_keys, gate_details.clients_address())
};
config.get_base_mut().with_gateway_endpoint( // TODO: is there perhaps a way to make it work without having to spawn entire runtime?
gateway_details.identity_key.to_base58_string(), let rt = tokio::runtime::Runtime::new().unwrap();
gateway_details.owner.clone(), let (shared_keys, gateway_listener) = rt.block_on(registration_fut);
gateway_details.clients_address(), config
); .get_base_mut()
.with_gateway_listener(gateway_listener);
key_manager.insert_gateway_shared_key(shared_keys); key_manager.insert_gateway_shared_key(shared_keys);
let pathfinder = ClientKeyPathfinder::new_from_config(config.get_base()); let pathfinder = ClientKeyPathfinder::new_from_config(config.get_base());
+1 -34
View File
@@ -5,18 +5,6 @@ use crate::client::config::{Config, SocketType};
use clap::ArgMatches; use clap::ArgMatches;
use url::Url; use url::Url;
pub(crate) const TESTNET_MODE_ARG_NAME: &str = "testnet-mode";
#[cfg(not(feature = "coconut"))]
pub(crate) const ETH_ENDPOINT_ARG_NAME: &str = "eth_endpoint";
#[cfg(not(feature = "coconut"))]
pub(crate) const ETH_PRIVATE_KEY_ARG_NAME: &str = "eth_private_key";
#[cfg(not(feature = "coconut"))]
pub(crate) const DEFAULT_ETH_ENDPOINT: &str =
"https://rinkeby.infura.io/v3/00000000000000000000000000000000";
#[cfg(not(feature = "coconut"))]
pub(crate) const DEFAULT_ETH_PRIVATE_KEY: &str =
"0000000000000000000000000000000000000000000000000000000000000001";
pub(crate) mod init; pub(crate) mod init;
pub(crate) mod run; pub(crate) mod run;
pub(crate) mod upgrade; pub(crate) mod upgrade;
@@ -32,7 +20,7 @@ fn parse_validators(raw: &str) -> Vec<Url> {
.collect() .collect()
} }
pub(crate) fn override_config(mut config: Config, matches: &ArgMatches<'_>) -> Config { pub(crate) fn override_config(mut config: Config, matches: &ArgMatches) -> Config {
if let Some(raw_validators) = matches.value_of("validators") { if let Some(raw_validators) = matches.value_of("validators") {
config config
.get_base_mut() .get_base_mut()
@@ -55,26 +43,5 @@ pub(crate) fn override_config(mut config: Config, matches: &ArgMatches<'_>) -> C
config = config.with_port(port.unwrap()); config = config.with_port(port.unwrap());
} }
#[cfg(not(feature = "coconut"))]
if let Some(eth_endpoint) = matches.value_of(ETH_ENDPOINT_ARG_NAME) {
config.get_base_mut().with_eth_endpoint(eth_endpoint);
} else if !cfg!(feature = "eth") {
config
.get_base_mut()
.with_eth_endpoint(DEFAULT_ETH_ENDPOINT);
}
#[cfg(not(feature = "coconut"))]
if let Some(eth_private_key) = matches.value_of(ETH_PRIVATE_KEY_ARG_NAME) {
config.get_base_mut().with_eth_private_key(eth_private_key);
} else if !cfg!(feature = "eth") {
config
.get_base_mut()
.with_eth_private_key(DEFAULT_ETH_PRIVATE_KEY);
}
if !cfg!(feature = "eth") || matches.is_present(TESTNET_MODE_ARG_NAME) {
config.get_base_mut().with_testnet_mode(true)
}
config config
} }
+4 -26
View File
@@ -4,16 +4,13 @@
use crate::client::config::Config; use crate::client::config::Config;
use crate::client::NymClient; use crate::client::NymClient;
use crate::commands::override_config; use crate::commands::override_config;
#[cfg(feature = "eth")]
#[cfg(not(feature = "coconut"))]
use crate::commands::{ETH_ENDPOINT_ARG_NAME, ETH_PRIVATE_KEY_ARG_NAME, TESTNET_MODE_ARG_NAME};
use clap::{App, Arg, ArgMatches}; use clap::{App, Arg, ArgMatches};
use config::NymConfig; use config::NymConfig;
use log::*; use log::*;
use version_checker::is_minor_version_compatible; use version_checker::is_minor_version_compatible;
pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> { pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
let app = App::new("run") App::new("run")
.about("Run the Nym client with provided configuration client optionally overriding set parameters") .about("Run the Nym client with provided configuration client optionally overriding set parameters")
.arg(Arg::with_name("id") .arg(Arg::with_name("id")
.long("id") .long("id")
@@ -41,26 +38,7 @@ pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
.long("port") .long("port")
.help("Port for the socket (if applicable) to listen on") .help("Port for the socket (if applicable) to listen on")
.takes_value(true) .takes_value(true)
);
#[cfg(feature = "eth")]
#[cfg(not(feature = "coconut"))]
let app = app
.arg(
Arg::with_name(TESTNET_MODE_ARG_NAME)
.long(TESTNET_MODE_ARG_NAME)
.help("Set this client to work in a testnet mode that would attempt to use gateway without bandwidth credential requirement. If this value is set, --eth_endpoint and --eth_private_key don't need to be set.")
.conflicts_with_all(&[ETH_ENDPOINT_ARG_NAME, ETH_PRIVATE_KEY_ARG_NAME])
) )
.arg(Arg::with_name(ETH_ENDPOINT_ARG_NAME)
.long(ETH_ENDPOINT_ARG_NAME)
.help("URL of an Ethereum full node that we want to use for getting bandwidth tokens from ERC20 tokens. If you don't want to set this value, use --testnet-mode instead")
.takes_value(true))
.arg(Arg::with_name(ETH_PRIVATE_KEY_ARG_NAME)
.long(ETH_PRIVATE_KEY_ARG_NAME)
.help("Ethereum private key used for obtaining bandwidth tokens from ERC20 tokens. If you don't want to set this value, use --testnet-mode instead")
.takes_value(true));
app
} }
// this only checks compatibility between config the binary. It does not take into consideration // this only checks compatibility between config the binary. It does not take into consideration
@@ -82,7 +60,7 @@ fn version_check(cfg: &Config) -> bool {
} }
} }
pub async fn execute(matches: ArgMatches<'static>) { pub fn execute(matches: &ArgMatches) {
let id = matches.value_of("id").unwrap(); let id = matches.value_of("id").unwrap();
let mut config = match Config::load_from_file(Some(id)) { let mut config = match Config::load_from_file(Some(id)) {
@@ -93,12 +71,12 @@ pub async fn execute(matches: ArgMatches<'static>) {
} }
}; };
config = override_config(config, &matches); config = override_config(config, matches);
if !version_check(&config) { if !version_check(&config) {
error!("failed the local version check"); error!("failed the local version check");
return; return;
} }
NymClient::new(config).run_forever().await; NymClient::new(config).run_forever();
} }
+3 -3
View File
@@ -95,7 +95,7 @@ fn parse_package_version() -> Version {
fn minor_0_12_upgrade( fn minor_0_12_upgrade(
mut config: Config, mut config: Config,
_matches: &ArgMatches<'_>, _matches: &ArgMatches,
config_version: &Version, config_version: &Version,
package_version: &Version, package_version: &Version,
) -> Config { ) -> Config {
@@ -131,7 +131,7 @@ fn minor_0_12_upgrade(
config config
} }
fn do_upgrade(mut config: Config, matches: &ArgMatches<'_>, package_version: Version) { fn do_upgrade(mut config: Config, matches: &ArgMatches, package_version: Version) {
loop { loop {
let config_version = parse_config_version(&config); let config_version = parse_config_version(&config);
@@ -151,7 +151,7 @@ fn do_upgrade(mut config: Config, matches: &ArgMatches<'_>, package_version: Ver
} }
} }
pub fn execute(matches: &ArgMatches<'_>) { pub fn execute(matches: &ArgMatches) {
let package_version = parse_package_version(); let package_version = parse_package_version();
let id = matches.value_of("id").unwrap(); let id = matches.value_of("id").unwrap();
+8 -41
View File
@@ -1,21 +1,19 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net> // Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
use clap::{crate_version, App, ArgMatches}; use clap::{App, ArgMatches};
pub mod client; pub mod client;
pub mod commands; pub mod commands;
pub mod websocket; pub mod websocket;
#[tokio::main] fn main() {
async fn main() {
dotenv::dotenv().ok(); dotenv::dotenv().ok();
setup_logging(); setup_logging();
println!("{}", banner()); println!("{}", banner());
let arg_matches = App::new("Nym Client") let arg_matches = App::new("Nym Client")
.version(crate_version!()) .version(env!("CARGO_PKG_VERSION"))
.long_version(&*long_version())
.author("Nymtech") .author("Nymtech")
.about("Implementation of the Nym Client") .about("Implementation of the Nym Client")
.subcommand(commands::init::command_args()) .subcommand(commands::init::command_args())
@@ -23,13 +21,13 @@ async fn main() {
.subcommand(commands::upgrade::command_args()) .subcommand(commands::upgrade::command_args())
.get_matches(); .get_matches();
execute(arg_matches).await; execute(arg_matches);
} }
async fn execute(matches: ArgMatches<'static>) { fn execute(matches: ArgMatches) {
match matches.subcommand() { match matches.subcommand() {
("init", Some(m)) => commands::init::execute(m.clone()).await, ("init", Some(m)) => commands::init::execute(m),
("run", Some(m)) => commands::run::execute(m.clone()).await, ("run", Some(m)) => commands::run::execute(m),
("upgrade", Some(m)) => commands::upgrade::execute(m), ("upgrade", Some(m)) => commands::upgrade::execute(m),
_ => println!("{}", usage()), _ => println!("{}", usage()),
} }
@@ -52,38 +50,7 @@ fn banner() -> String {
(client - version {:}) (client - version {:})
"#, "#,
crate_version!() env!("CARGO_PKG_VERSION")
)
}
fn long_version() -> String {
format!(
r#"
{:<20}{}
{:<20}{}
{:<20}{}
{:<20}{}
{:<20}{}
{:<20}{}
{:<20}{}
{:<20}{}
"#,
"Build Timestamp:",
env!("VERGEN_BUILD_TIMESTAMP"),
"Build Version:",
env!("VERGEN_BUILD_SEMVER"),
"Commit SHA:",
env!("VERGEN_GIT_SHA"),
"Commit Date:",
env!("VERGEN_GIT_COMMIT_TIMESTAMP"),
"Commit Branch:",
env!("VERGEN_GIT_BRANCH"),
"rustc Version:",
env!("VERGEN_RUSTC_SEMVER"),
"rustc Channel:",
env!("VERGEN_RUSTC_CHANNEL"),
"cargo Profile:",
env!("VERGEN_CARGO_PROFILE"),
) )
} }
+3 -2
View File
@@ -5,6 +5,7 @@ use super::handler::Handler;
use log::*; use log::*;
use std::{net::SocketAddr, process, sync::Arc}; use std::{net::SocketAddr, process, sync::Arc};
use tokio::io::AsyncWriteExt; use tokio::io::AsyncWriteExt;
use tokio::runtime;
use tokio::{sync::Notify, task::JoinHandle}; use tokio::{sync::Notify, task::JoinHandle};
enum State { enum State {
@@ -86,9 +87,9 @@ impl Listener {
} }
} }
pub(crate) fn start(mut self, handler: Handler) -> JoinHandle<()> { pub(crate) fn start(mut self, rt_handle: &runtime::Handle, handler: Handler) -> JoinHandle<()> {
info!("Running websocket on {:?}", self.address.to_string()); info!("Running websocket on {:?}", self.address.to_string());
tokio::spawn(async move { self.run(handler).await }) rt_handle.spawn(async move { self.run(handler).await })
} }
} }
+3 -3
View File
@@ -1,8 +1,8 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net> // Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
pub(crate) use handler::Handler;
pub(crate) use listener::Listener;
pub(crate) mod handler; pub(crate) mod handler;
pub(crate) mod listener; pub(crate) mod listener;
pub(crate) use handler::Handler;
pub(crate) use listener::Listener;
+1 -1
View File
@@ -2,7 +2,7 @@
name = "websocket-requests" name = "websocket-requests"
version = "0.1.0" version = "0.1.0"
authors = ["Jędrzej Stuczyński <andrew@nymtech.net>"] authors = ["Jędrzej Stuczyński <andrew@nymtech.net>"]
edition = "2021" edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+3 -8
View File
@@ -1,8 +1,8 @@
[package] [package]
name = "nym-socks5-client" name = "nym-socks5-client"
version = "1.0.0-rc.1" version = "0.11.0"
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"] authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
edition = "2021" edition = "2018"
rust-version = "1.56" rust-version = "1.56"
[lib] [lib]
@@ -32,18 +32,13 @@ crypto = { path = "../../common/crypto" }
gateway-client = { path = "../../common/client-libs/gateway-client" } gateway-client = { path = "../../common/client-libs/gateway-client" }
gateway-requests = { path = "../../gateway/gateway-requests" } gateway-requests = { path = "../../gateway/gateway-requests" }
nymsphinx = { path = "../../common/nymsphinx" } nymsphinx = { path = "../../common/nymsphinx" }
ordered-buffer = { path = "../../common/socks5/ordered-buffer" } ordered-buffer = {path = "../../common/socks5/ordered-buffer"}
socks5-requests = { path = "../../common/socks5/requests" } socks5-requests = { path = "../../common/socks5/requests" }
topology = { path = "../../common/topology" } topology = { path = "../../common/topology" }
pemstore = { path = "../../common/pemstore" } pemstore = { path = "../../common/pemstore" }
proxy-helpers = { path = "../../common/socks5/proxy-helpers" } proxy-helpers = { path = "../../common/socks5/proxy-helpers" }
validator-client = { path = "../../common/client-libs/validator-client" } validator-client = { path = "../../common/client-libs/validator-client" }
version-checker = { path = "../../common/version-checker" } version-checker = { path = "../../common/version-checker" }
network-defaults = { path = "../../common/network-defaults" }
[features] [features]
coconut = ["coconut-interface", "credentials", "gateway-requests/coconut", "gateway-client/coconut"] coconut = ["coconut-interface", "credentials", "gateway-requests/coconut", "gateway-client/coconut"]
eth = []
[build-dependencies]
vergen = { version = "5", default-features = false, features = ["build", "git", "rustc", "cargo"] }
-8
View File
@@ -1,8 +0,0 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use vergen::{vergen, Config};
fn main() {
vergen(Config::default()).expect("failed to extract build metadata")
}
+8 -27
View File
@@ -5,7 +5,7 @@ pub(crate) fn config_template() -> &'static str {
// While using normal toml marshalling would have been way simpler with less overhead, // While using normal toml marshalling would have been way simpler with less overhead,
// I think it's useful to have comments attached to the saved config file to explain behaviour of // I think it's useful to have comments attached to the saved config file to explain behaviour of
// particular fields. // particular fields.
// Note: any changes to the template must be reflected in the appropriate structs. // Note: any changes to the template must be reflected in the appropriate structs in verloc.
r#" r#"
# This is a TOML config file. # This is a TOML config file.
# For more information, see https://github.com/toml-lang/toml # For more information, see https://github.com/toml-lang/toml
@@ -19,10 +19,6 @@ version = '{{ client.version }}'
# Human readable ID of this particular client. # Human readable ID of this particular client.
id = '{{ client.id }}' id = '{{ client.id }}'
# Indicates whether this client is running in a testnet mode, thus attempting
# to claim bandwidth without presenting bandwidth credentials.
testnet_mode = {{ client.testnet_mode }}
# Addresses to APIs running on validator from which the client gets the view of the network. # Addresses to APIs running on validator from which the client gets the view of the network.
validator_api_urls = [ validator_api_urls = [
{{#each client.validator_api_urls }} {{#each client.validator_api_urls }}
@@ -46,19 +42,14 @@ public_encryption_key_file = '{{ client.public_encryption_key_file }}'
# sent but not received back. # sent but not received back.
reply_encryption_key_store_path = '{{ client.reply_encryption_key_store_path }}' reply_encryption_key_store_path = '{{ client.reply_encryption_key_store_path }}'
# Path to directory containing public/private keys used for bandwidth token purchase.
# Those are saved in case of emergency, to be able to reclaim bandwidth tokens.
# The public key is the name of the file, while the private key is the content.
backup_bandwidth_token_keys_dir = '{{ client.backup_bandwidth_token_keys_dir }}'
# Ethereum private key.
eth_private_key = '{{ client.eth_private_key }}'
# Addess to an Ethereum full node.
eth_endpoint = '{{ client.eth_endpoint }}'
##### additional client config options ##### ##### additional client config options #####
# ID of the gateway from which the client should be fetching messages.
gateway_id = '{{ client.gateway_id }}'
# Address of the gateway listener to which all client requests should be sent.
gateway_listener = '{{ client.gateway_listener }}'
# A gateway specific, optional, base58 stringified shared key used for # A gateway specific, optional, base58 stringified shared key used for
# communication with particular gateway. # communication with particular gateway.
gateway_shared_key_file = '{{ client.gateway_shared_key_file }}' gateway_shared_key_file = '{{ client.gateway_shared_key_file }}'
@@ -66,22 +57,12 @@ gateway_shared_key_file = '{{ client.gateway_shared_key_file }}'
# Path to file containing key used for encrypting and decrypting the content of an # Path to file containing key used for encrypting and decrypting the content of an
# acknowledgement so that nobody besides the client knows which packet it refers to. # acknowledgement so that nobody besides the client knows which packet it refers to.
ack_key_file = '{{ client.ack_key_file }}' ack_key_file = '{{ client.ack_key_file }}'
##### advanced configuration options ##### ##### advanced configuration options #####
# Absolute path to the home Nym Clients directory. # Absolute path to the home Nym Clients directory.
nym_root_directory = '{{ client.nym_root_directory }}' nym_root_directory = '{{ client.nym_root_directory }}'
[client.gateway_endpoint]
# ID of the gateway from which the client should be fetching messages.
gateway_id = '{{ client.gateway_endpoint.gateway_id }}'
# Address of the gateway owner to which the client should send messages.
gateway_owner = '{{ client.gateway_endpoint.gateway_owner }}'
# Address of the gateway listener to which all client requests should be sent.
gateway_listener = '{{ client.gateway_endpoint.gateway_listener }}'
##### socket config options ##### ##### socket config options #####
+101 -57
View File
@@ -1,6 +1,10 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net> // Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
use futures::channel::mpsc;
use log::*;
use tokio::runtime::Runtime;
use client_core::client::cover_traffic_stream::LoopCoverTrafficStream; use client_core::client::cover_traffic_stream::LoopCoverTrafficStream;
use client_core::client::inbound_messages::{ use client_core::client::inbound_messages::{
InputMessage, InputMessageReceiver, InputMessageSender, InputMessage, InputMessageReceiver, InputMessageSender,
@@ -18,14 +22,19 @@ use client_core::client::topology_control::{
TopologyAccessor, TopologyRefresher, TopologyRefresherConfig, TopologyAccessor, TopologyRefresher, TopologyRefresherConfig,
}; };
use client_core::config::persistence::key_pathfinder::ClientKeyPathfinder; use client_core::config::persistence::key_pathfinder::ClientKeyPathfinder;
#[cfg(feature = "coconut")]
use coconut_interface::{hash_to_scalar, Credential, Parameters};
#[cfg(feature = "coconut")]
use credentials::bandwidth::{
prepare_for_spending, BandwidthVoucherAttributes, BANDWIDTH_VALUE, TOTAL_ATTRIBUTES,
};
#[cfg(feature = "coconut")]
use credentials::obtain_aggregate_verification_key;
use crypto::asymmetric::identity; use crypto::asymmetric::identity;
use futures::channel::mpsc;
use gateway_client::bandwidth::BandwidthController;
use gateway_client::{ use gateway_client::{
AcknowledgementReceiver, AcknowledgementSender, GatewayClient, MixnetMessageReceiver, AcknowledgementReceiver, AcknowledgementSender, GatewayClient, MixnetMessageReceiver,
MixnetMessageSender, MixnetMessageSender,
}; };
use log::*;
use nymsphinx::addressing::clients::Recipient; use nymsphinx::addressing::clients::Recipient;
use nymsphinx::addressing::nodes::NodeIdentity; use nymsphinx::addressing::nodes::NodeIdentity;
@@ -42,6 +51,11 @@ pub struct NymClient {
/// key filepaths, etc. /// key filepaths, etc.
config: Config, config: Config,
/// Tokio runtime used for futures execution.
// TODO: JS: Personally I think I prefer the implicit way of using it that we've done with the
// gateway.
runtime: Runtime,
/// KeyManager object containing smart pointers to all relevant keys used by the client. /// KeyManager object containing smart pointers to all relevant keys used by the client.
key_manager: KeyManager, key_manager: KeyManager,
} }
@@ -52,6 +66,7 @@ impl NymClient {
let key_manager = KeyManager::load_keys(&pathfinder).expect("failed to load stored keys"); let key_manager = KeyManager::load_keys(&pathfinder).expect("failed to load stored keys");
NymClient { NymClient {
runtime: Runtime::new().unwrap(),
config, config,
key_manager, key_manager,
} }
@@ -75,6 +90,9 @@ impl NymClient {
mix_tx: BatchMixMessageSender, mix_tx: BatchMixMessageSender,
) { ) {
info!("Starting loop cover traffic stream..."); info!("Starting loop cover traffic stream...");
// we need to explicitly enter runtime due to "next_delay: time::delay_for(Default::default())"
// set in the constructor which HAS TO be called within context of a tokio runtime
let _guard = self.runtime.enter();
LoopCoverTrafficStream::new( LoopCoverTrafficStream::new(
self.key_manager.ack_key(), self.key_manager.ack_key(),
@@ -87,7 +105,7 @@ impl NymClient {
self.as_mix_recipient(), self.as_mix_recipient(),
topology_accessor, topology_accessor,
) )
.start(); .start(self.runtime.handle());
} }
fn start_real_traffic_controller( fn start_real_traffic_controller(
@@ -109,6 +127,10 @@ impl NymClient {
); );
info!("Starting real traffic stream..."); info!("Starting real traffic stream...");
// we need to explicitly enter runtime due to "next_delay: time::delay_for(Default::default())"
// set in the constructor [of OutQueueControl] which HAS TO be called within context of a tokio runtime
// When refactoring this restriction should definitely be removed.
let _guard = self.runtime.enter();
RealMessagesController::new( RealMessagesController::new(
controller_config, controller_config,
@@ -118,7 +140,7 @@ impl NymClient {
topology_accessor, topology_accessor,
reply_key_storage, reply_key_storage,
) )
.start(); .start(self.runtime.handle());
} }
// buffer controlling all messages fetched from provider // buffer controlling all messages fetched from provider
@@ -136,10 +158,45 @@ impl NymClient {
mixnet_receiver, mixnet_receiver,
reply_key_storage, reply_key_storage,
) )
.start() .start(self.runtime.handle())
} }
async fn start_gateway_client( #[cfg(feature = "coconut")]
async fn prepare_coconut_credential(&self) -> Credential {
let verification_key = obtain_aggregate_verification_key(
&self.config.get_base().get_validator_api_endpoints(),
)
.await
.expect("could not obtain aggregate verification key of validators");
let params = Parameters::new(TOTAL_ATTRIBUTES).unwrap();
let bandwidth_credential_attributes = BandwidthVoucherAttributes {
serial_number: params.random_scalar(),
binding_number: params.random_scalar(),
voucher_value: hash_to_scalar(BANDWIDTH_VALUE.to_be_bytes()),
voucher_info: hash_to_scalar(String::from("BandwidthVoucher").as_bytes()),
};
let bandwidth_credential = credentials::bandwidth::obtain_signature(
&params,
&bandwidth_credential_attributes,
&self.config.get_base().get_validator_api_endpoints(),
)
.await
.expect("could not obtain bandwidth credential");
// the above would presumably be loaded from a file
// the below would only be executed once we know where we want to spend it (i.e. which gateway and stuff)
prepare_for_spending(
&self.key_manager.identity_keypair().public_key().to_bytes(),
&bandwidth_credential,
&bandwidth_credential_attributes,
&verification_key,
)
.expect("could not prepare out bandwidth credential for spending")
}
fn start_gateway_client(
&mut self, &mut self,
mixnet_message_sender: MixnetMessageSender, mixnet_message_sender: MixnetMessageSender,
ack_sender: AcknowledgementSender, ack_sender: AcknowledgementSender,
@@ -148,10 +205,6 @@ impl NymClient {
if gateway_id.is_empty() { if gateway_id.is_empty() {
panic!("The identity of the gateway is unknown - did you run `nym-client` init?") panic!("The identity of the gateway is unknown - did you run `nym-client` init?")
} }
let gateway_owner = self.config.get_base().get_gateway_owner();
if gateway_owner.is_empty() {
panic!("The owner of the gateway is unknown - did you run `nym-client` init?")
}
let gateway_address = self.config.get_base().get_gateway_listener(); let gateway_address = self.config.get_base().get_gateway_listener();
if gateway_address.is_empty() { if gateway_address.is_empty() {
panic!("The address of the gateway is unknown - did you run `nym-client` init?") panic!("The address of the gateway is unknown - did you run `nym-client` init?")
@@ -160,45 +213,35 @@ impl NymClient {
let gateway_identity = identity::PublicKey::from_base58_string(gateway_id) let gateway_identity = identity::PublicKey::from_base58_string(gateway_id)
.expect("provided gateway id is invalid!"); .expect("provided gateway id is invalid!");
#[cfg(feature = "coconut")] self.runtime.block_on(async {
let bandwidth_controller = BandwidthController::new( #[cfg(feature = "coconut")]
self.config.get_base().get_validator_api_endpoints(), let coconut_credential = self.prepare_coconut_credential().await;
*self.key_manager.identity_keypair().public_key(),
);
#[cfg(not(feature = "coconut"))]
let bandwidth_controller = BandwidthController::new(
self.config.get_base().get_eth_endpoint(),
self.config.get_base().get_eth_private_key(),
self.config.get_base().get_backup_bandwidth_token_keys_dir(),
)
.expect("Could not create bandwidth controller");
let mut gateway_client = GatewayClient::new( let mut gateway_client = GatewayClient::new(
gateway_address, gateway_address,
self.key_manager.identity_keypair(), self.key_manager.identity_keypair(),
gateway_identity, gateway_identity,
gateway_owner, Some(self.key_manager.gateway_shared_key()),
Some(self.key_manager.gateway_shared_key()), mixnet_message_sender,
mixnet_message_sender, ack_sender,
ack_sender, self.config.get_base().get_gateway_response_timeout(),
self.config.get_base().get_gateway_response_timeout(), );
Some(bandwidth_controller),
);
if self.config.get_base().get_testnet_mode() { gateway_client
gateway_client.set_testnet_mode(true) .authenticate_and_start(
} #[cfg(feature = "coconut")]
gateway_client Some(coconut_credential),
.authenticate_and_start() )
.await .await
.expect("could not authenticate and start up the gateway connection"); .expect("could not authenticate and start up the gateway connection");
gateway_client gateway_client
})
} }
// future responsible for periodically polling directory server and updating // future responsible for periodically polling directory server and updating
// the current global view of topology // the current global view of topology
async fn start_topology_refresher(&mut self, topology_accessor: TopologyAccessor) { fn start_topology_refresher(&mut self, topology_accessor: TopologyAccessor) {
let topology_refresher_config = TopologyRefresherConfig::new( let topology_refresher_config = TopologyRefresherConfig::new(
self.config.get_base().get_validator_api_endpoints(), self.config.get_base().get_validator_api_endpoints(),
self.config.get_base().get_topology_refresh_rate(), self.config.get_base().get_topology_refresh_rate(),
@@ -209,10 +252,13 @@ impl NymClient {
// before returning, block entire runtime to refresh the current network view so that any // before returning, block entire runtime to refresh the current network view so that any
// components depending on topology would see a non-empty view // components depending on topology would see a non-empty view
info!("Obtaining initial network topology"); info!("Obtaining initial network topology");
topology_refresher.refresh().await; self.runtime.block_on(topology_refresher.refresh());
// TODO: a slightly more graceful termination here // TODO: a slightly more graceful termination here
if !topology_refresher.is_topology_routable().await { if !self
.runtime
.block_on(topology_refresher.is_topology_routable())
{
panic!( panic!(
"The current network topology seem to be insufficient to route any packets through\ "The current network topology seem to be insufficient to route any packets through\
- check if enough nodes and a gateway are online" - check if enough nodes and a gateway are online"
@@ -220,7 +266,7 @@ impl NymClient {
} }
info!("Starting topology refresher..."); info!("Starting topology refresher...");
topology_refresher.start(); topology_refresher.start(self.runtime.handle());
} }
// controller for sending sphinx packets to mixnet (either real traffic or cover traffic) // controller for sending sphinx packets to mixnet (either real traffic or cover traffic)
@@ -233,7 +279,7 @@ impl NymClient {
gateway_client: GatewayClient, gateway_client: GatewayClient,
) { ) {
info!("Starting mix traffic controller..."); info!("Starting mix traffic controller...");
MixTrafficController::new(mix_rx, gateway_client).start(); MixTrafficController::new(mix_rx, gateway_client).start(self.runtime.handle());
} }
fn start_socks5_listener( fn start_socks5_listener(
@@ -252,13 +298,14 @@ impl NymClient {
self.config.get_provider_mix_address(), self.config.get_provider_mix_address(),
self.as_mix_recipient(), self.as_mix_recipient(),
); );
tokio::spawn(async move { sphinx_socks.serve(msg_input, buffer_requester).await }); self.runtime
.spawn(async move { sphinx_socks.serve(msg_input, buffer_requester).await });
} }
/// blocking version of `start` method. Will run forever (or until SIGINT is sent) /// blocking version of `start` method. Will run forever (or until SIGINT is sent)
pub async fn run_forever(&mut self) { pub fn run_forever(&mut self) {
self.start().await; self.start();
if let Err(e) = tokio::signal::ctrl_c().await { if let Err(e) = self.runtime.block_on(tokio::signal::ctrl_c()) {
error!( error!(
"There was an error while capturing SIGINT - {:?}. We will terminate regardless", "There was an error while capturing SIGINT - {:?}. We will terminate regardless",
e e
@@ -270,7 +317,7 @@ impl NymClient {
); );
} }
pub async fn start(&mut self) { pub fn start(&mut self) {
info!("Starting nym client"); info!("Starting nym client");
// channels for inter-component communication // channels for inter-component communication
// TODO: make the channels be internally created by the relevant components // TODO: make the channels be internally created by the relevant components
@@ -302,17 +349,14 @@ impl NymClient {
// the components are started in very specific order. Unless you know what you are doing, // the components are started in very specific order. Unless you know what you are doing,
// do not change that. // do not change that.
self.start_topology_refresher(shared_topology_accessor.clone()) self.start_topology_refresher(shared_topology_accessor.clone());
.await;
self.start_received_messages_buffer_controller( self.start_received_messages_buffer_controller(
received_buffer_request_receiver, received_buffer_request_receiver,
mixnet_messages_receiver, mixnet_messages_receiver,
reply_key_storage.clone(), reply_key_storage.clone(),
); );
let gateway_client = self let gateway_client = self.start_gateway_client(mixnet_messages_sender, ack_sender);
.start_gateway_client(mixnet_messages_sender, ack_sender)
.await;
self.start_mix_traffic_controller(sphinx_message_receiver, gateway_client); self.start_mix_traffic_controller(sphinx_message_receiver, gateway_client);
self.start_real_traffic_controller( self.start_real_traffic_controller(
+38 -59
View File
@@ -1,43 +1,37 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net> // Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
use std::convert::TryInto;
use std::sync::Arc;
use std::time::Duration;
use clap::{App, Arg, ArgMatches}; use clap::{App, Arg, ArgMatches};
use rand::{prelude::SliceRandom, rngs::OsRng, thread_rng};
use url::Url;
use client_core::client::key_manager::KeyManager; use client_core::client::key_manager::KeyManager;
use client_core::config::persistence::key_pathfinder::ClientKeyPathfinder; use client_core::config::persistence::key_pathfinder::ClientKeyPathfinder;
#[cfg(feature = "coconut")] #[cfg(feature = "coconut")]
use coconut_interface::{hash_to_scalar, Credential, Parameters}; use coconut_interface::{hash_to_scalar, Credential, Parameters};
use config::NymConfig; use config::NymConfig;
#[cfg(feature = "coconut")] #[cfg(feature = "coconut")]
use credentials::coconut::bandwidth::{ use credentials::bandwidth::{
obtain_signature, prepare_for_spending, BandwidthVoucherAttributes, TOTAL_ATTRIBUTES, prepare_for_spending, BandwidthVoucherAttributes, BANDWIDTH_VALUE, TOTAL_ATTRIBUTES,
}; };
#[cfg(feature = "coconut")] #[cfg(feature = "coconut")]
use credentials::obtain_aggregate_verification_key; use credentials::obtain_aggregate_verification_key;
use crypto::asymmetric::{encryption, identity}; use crypto::asymmetric::{encryption, identity};
use gateway_client::GatewayClient; use gateway_client::GatewayClient;
use gateway_requests::registration::handshake::SharedKeys; use gateway_requests::registration::handshake::SharedKeys;
#[cfg(feature = "coconut")]
use network_defaults::BANDWIDTH_VALUE;
use nymsphinx::addressing::clients::Recipient; use nymsphinx::addressing::clients::Recipient;
use nymsphinx::addressing::nodes::NodeIdentity; use nymsphinx::addressing::nodes::NodeIdentity;
use rand::{prelude::SliceRandom, rngs::OsRng, thread_rng};
use std::convert::TryInto;
use std::sync::Arc;
use std::time::Duration;
use topology::{filter::VersionFilterable, gateway}; use topology::{filter::VersionFilterable, gateway};
use url::Url;
use crate::client::config::Config; use crate::client::config::Config;
use crate::commands::override_config; use crate::commands::override_config;
#[cfg(feature = "eth")]
#[cfg(not(feature = "coconut"))]
use crate::commands::{
DEFAULT_ETH_ENDPOINT, DEFAULT_ETH_PRIVATE_KEY, ETH_ENDPOINT_ARG_NAME, ETH_PRIVATE_KEY_ARG_NAME,
TESTNET_MODE_ARG_NAME,
};
pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> { pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
let app = App::new("init") App::new("init")
.about("Initialise a Nym client. Do this first!") .about("Initialise a Nym client. Do this first!")
.arg(Arg::with_name("id") .arg(Arg::with_name("id")
.long("id") .long("id")
@@ -71,31 +65,7 @@ pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
.long("fastmode") .long("fastmode")
.hidden(true) // this will prevent this flag from being displayed in `--help` .hidden(true) // this will prevent this flag from being displayed in `--help`
.help("Mostly debug-related option to increase default traffic rate so that you would not need to modify config post init") .help("Mostly debug-related option to increase default traffic rate so that you would not need to modify config post init")
);
#[cfg(feature = "eth")]
#[cfg(not(feature = "coconut"))]
let app = app
.arg(
Arg::with_name(TESTNET_MODE_ARG_NAME)
.long(TESTNET_MODE_ARG_NAME)
.help("Set this client to work in a testnet mode that would attempt to use gateway without bandwidth credential requirement. If this value is set, --eth_endpoint and --eth_private_key don't need to be set.")
.conflicts_with_all(&[ETH_ENDPOINT_ARG_NAME, ETH_PRIVATE_KEY_ARG_NAME])
) )
.arg(Arg::with_name(ETH_ENDPOINT_ARG_NAME)
.long(ETH_ENDPOINT_ARG_NAME)
.help("URL of an Ethereum full node that we want to use for getting bandwidth tokens from ERC20 tokens. If you don't want to set this value, use --testnet-mode instead")
.takes_value(true)
.default_value_if(TESTNET_MODE_ARG_NAME, None, DEFAULT_ETH_ENDPOINT)
.required(true))
.arg(Arg::with_name(ETH_PRIVATE_KEY_ARG_NAME)
.long(ETH_PRIVATE_KEY_ARG_NAME)
.help("Ethereum private key used for obtaining bandwidth tokens from ERC20 tokens. If you don't want to set this value, use --testnet-mode instead")
.takes_value(true)
.default_value_if(TESTNET_MODE_ARG_NAME, None, DEFAULT_ETH_PRIVATE_KEY)
.required(true)
);
app
} }
// this behaviour should definitely be changed, we shouldn't // this behaviour should definitely be changed, we shouldn't
@@ -114,10 +84,13 @@ async fn _prepare_temporary_credential(validators: &[Url], raw_identity: &[u8])
voucher_info: hash_to_scalar("BandwidthVoucher"), voucher_info: hash_to_scalar("BandwidthVoucher"),
}; };
let bandwidth_credential = let bandwidth_credential = credentials::bandwidth::obtain_signature(
obtain_signature(&params, &bandwidth_credential_attributes, validators) &params,
.await &bandwidth_credential_attributes,
.expect("could not obtain bandwidth credential"); validators,
)
.await
.expect("could not obtain bandwidth credential");
prepare_for_spending( prepare_for_spending(
raw_identity, raw_identity,
@@ -136,7 +109,6 @@ async fn register_with_gateway(
let mut gateway_client = GatewayClient::new_init( let mut gateway_client = GatewayClient::new_init(
gateway.clients_address(), gateway.clients_address(),
gateway.identity_key, gateway.identity_key,
gateway.owner.clone(),
our_identity.clone(), our_identity.clone(),
timeout, timeout,
); );
@@ -220,7 +192,7 @@ fn show_address(config: &Config) {
println!("\nThe address of this client is: {}", client_recipient); println!("\nThe address of this client is: {}", client_recipient);
} }
pub async fn execute(matches: ArgMatches<'static>) { pub fn execute(matches: &ArgMatches) {
println!("Initialising client..."); println!("Initialising client...");
let id = matches.value_of("id").unwrap(); // required for now let id = matches.value_of("id").unwrap(); // required for now
@@ -239,7 +211,7 @@ pub async fn execute(matches: ArgMatches<'static>) {
// TODO: ideally that should be the last thing that's being done to config. // TODO: ideally that should be the last thing that's being done to config.
// However, we are later further overriding it with gateway id // However, we are later further overriding it with gateway id
config = override_config(config, &matches); config = override_config(config, matches);
if matches.is_present("fastmode") { if matches.is_present("fastmode") {
config.get_base_mut().set_high_default_traffic_volume(); config.get_base_mut().set_high_default_traffic_volume();
} }
@@ -252,19 +224,26 @@ pub async fn execute(matches: ArgMatches<'static>) {
let chosen_gateway_id = matches.value_of("gateway"); let chosen_gateway_id = matches.value_of("gateway");
let gateway_details = gateway_details( let registration_fut = async {
config.get_base().get_validator_api_endpoints(), let gate_details = gateway_details(
chosen_gateway_id, config.get_base().get_validator_api_endpoints(),
) chosen_gateway_id,
.await; )
let shared_keys = .await;
register_with_gateway(&gateway_details, key_manager.identity_keypair()).await; config
.get_base_mut()
.with_gateway_id(gate_details.identity_key.to_base58_string());
let shared_keys =
register_with_gateway(&gate_details, key_manager.identity_keypair()).await;
(shared_keys, gate_details.clients_address())
};
config.get_base_mut().with_gateway_endpoint( // TODO: is there perhaps a way to make it work without having to spawn entire runtime?
gateway_details.identity_key.to_base58_string(), let rt = tokio::runtime::Runtime::new().unwrap();
gateway_details.owner.clone(), let (shared_keys, gateway_listener) = rt.block_on(registration_fut);
gateway_details.clients_address(), config
); .get_base_mut()
.with_gateway_listener(gateway_listener);
key_manager.insert_gateway_shared_key(shared_keys); key_manager.insert_gateway_shared_key(shared_keys);
let pathfinder = ClientKeyPathfinder::new_from_config(config.get_base()); let pathfinder = ClientKeyPathfinder::new_from_config(config.get_base());
+1 -34
View File
@@ -9,18 +9,6 @@ pub(crate) mod init;
pub(crate) mod run; pub(crate) mod run;
pub(crate) mod upgrade; pub(crate) mod upgrade;
pub(crate) const TESTNET_MODE_ARG_NAME: &str = "testnet-mode";
#[cfg(not(feature = "coconut"))]
pub(crate) const ETH_ENDPOINT_ARG_NAME: &str = "eth_endpoint";
#[cfg(not(feature = "coconut"))]
pub(crate) const ETH_PRIVATE_KEY_ARG_NAME: &str = "eth_private_key";
#[cfg(not(feature = "coconut"))]
pub(crate) const DEFAULT_ETH_ENDPOINT: &str =
"https://rinkeby.infura.io/v3/00000000000000000000000000000000";
#[cfg(not(feature = "coconut"))]
pub(crate) const DEFAULT_ETH_PRIVATE_KEY: &str =
"0000000000000000000000000000000000000000000000000000000000000001";
fn parse_validators(raw: &str) -> Vec<Url> { fn parse_validators(raw: &str) -> Vec<Url> {
raw.split(',') raw.split(',')
.map(|raw_validator| { .map(|raw_validator| {
@@ -32,7 +20,7 @@ fn parse_validators(raw: &str) -> Vec<Url> {
.collect() .collect()
} }
pub(crate) fn override_config(mut config: Config, matches: &ArgMatches<'_>) -> Config { pub(crate) fn override_config(mut config: Config, matches: &ArgMatches) -> Config {
if let Some(raw_validators) = matches.value_of("validators") { if let Some(raw_validators) = matches.value_of("validators") {
config config
.get_base_mut() .get_base_mut()
@@ -51,26 +39,5 @@ pub(crate) fn override_config(mut config: Config, matches: &ArgMatches<'_>) -> C
config = config.with_port(port.unwrap()); config = config.with_port(port.unwrap());
} }
#[cfg(not(feature = "coconut"))]
if let Some(eth_endpoint) = matches.value_of(ETH_ENDPOINT_ARG_NAME) {
config.get_base_mut().with_eth_endpoint(eth_endpoint);
} else if !cfg!(feature = "eth") {
config
.get_base_mut()
.with_eth_endpoint(DEFAULT_ETH_ENDPOINT);
}
#[cfg(not(feature = "coconut"))]
if let Some(eth_private_key) = matches.value_of(ETH_PRIVATE_KEY_ARG_NAME) {
config.get_base_mut().with_eth_private_key(eth_private_key);
} else if !cfg!(feature = "eth") {
config
.get_base_mut()
.with_eth_private_key(DEFAULT_ETH_PRIVATE_KEY);
}
if !cfg!(feature = "eth") || matches.is_present(TESTNET_MODE_ARG_NAME) {
config.get_base_mut().with_testnet_mode(true)
}
config config
} }
+4 -26
View File
@@ -4,16 +4,13 @@
use crate::client::config::Config; use crate::client::config::Config;
use crate::client::NymClient; use crate::client::NymClient;
use crate::commands::override_config; use crate::commands::override_config;
#[cfg(feature = "eth")]
#[cfg(not(feature = "coconut"))]
use crate::commands::{ETH_ENDPOINT_ARG_NAME, ETH_PRIVATE_KEY_ARG_NAME, TESTNET_MODE_ARG_NAME};
use clap::{App, Arg, ArgMatches}; use clap::{App, Arg, ArgMatches};
use config::NymConfig; use config::NymConfig;
use log::*; use log::*;
use version_checker::is_minor_version_compatible; use version_checker::is_minor_version_compatible;
pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> { pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
let app = App::new("run") App::new("run")
.about("Run the Nym client with provided configuration client optionally overriding set parameters") .about("Run the Nym client with provided configuration client optionally overriding set parameters")
.arg(Arg::with_name("id") .arg(Arg::with_name("id")
.long("id") .long("id")
@@ -47,26 +44,7 @@ pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
.long("port") .long("port")
.help("Port for the socket to listen on") .help("Port for the socket to listen on")
.takes_value(true) .takes_value(true)
);
#[cfg(feature = "eth")]
#[cfg(not(feature = "coconut"))]
let app = app
.arg(
Arg::with_name(TESTNET_MODE_ARG_NAME)
.long(TESTNET_MODE_ARG_NAME)
.help("Set this client to work in a testnet mode that would attempt to use gateway without bandwidth credential requirement. If this value is set, --eth_endpoint and --eth_private_key don't need to be set.")
.conflicts_with_all(&[ETH_ENDPOINT_ARG_NAME, ETH_PRIVATE_KEY_ARG_NAME])
) )
.arg(Arg::with_name(ETH_ENDPOINT_ARG_NAME)
.long(ETH_ENDPOINT_ARG_NAME)
.help("URL of an Ethereum full node that we want to use for getting bandwidth tokens from ERC20 tokens. If you don't want to set this value, use --testnet-mode instead")
.takes_value(true))
.arg(Arg::with_name(ETH_PRIVATE_KEY_ARG_NAME)
.long(ETH_PRIVATE_KEY_ARG_NAME)
.help("Ethereum private key used for obtaining bandwidth tokens from ERC20 tokens. If you don't want to set this value, use --testnet-mode instead")
.takes_value(true));
app
} }
// this only checks compatibility between config the binary. It does not take into consideration // this only checks compatibility between config the binary. It does not take into consideration
@@ -88,7 +66,7 @@ fn version_check(cfg: &Config) -> bool {
} }
} }
pub async fn execute(matches: ArgMatches<'static>) { pub fn execute(matches: &ArgMatches) {
let id = matches.value_of("id").unwrap(); let id = matches.value_of("id").unwrap();
let mut config = match Config::load_from_file(Some(id)) { let mut config = match Config::load_from_file(Some(id)) {
@@ -99,12 +77,12 @@ pub async fn execute(matches: ArgMatches<'static>) {
} }
}; };
config = override_config(config, &matches); config = override_config(config, matches);
if !version_check(&config) { if !version_check(&config) {
error!("failed the local version check"); error!("failed the local version check");
return; return;
} }
NymClient::new(config).run_forever().await; NymClient::new(config).run_forever();
} }
+3 -3
View File
@@ -95,7 +95,7 @@ fn parse_package_version() -> Version {
fn minor_0_12_upgrade( fn minor_0_12_upgrade(
mut config: Config, mut config: Config,
_matches: &ArgMatches<'_>, _matches: &ArgMatches,
config_version: &Version, config_version: &Version,
package_version: &Version, package_version: &Version,
) -> Config { ) -> Config {
@@ -131,7 +131,7 @@ fn minor_0_12_upgrade(
config config
} }
fn do_upgrade(mut config: Config, matches: &ArgMatches<'_>, package_version: Version) { fn do_upgrade(mut config: Config, matches: &ArgMatches, package_version: Version) {
loop { loop {
let config_version = parse_config_version(&config); let config_version = parse_config_version(&config);
@@ -151,7 +151,7 @@ fn do_upgrade(mut config: Config, matches: &ArgMatches<'_>, package_version: Ver
} }
} }
pub fn execute(matches: &ArgMatches<'_>) { pub fn execute(matches: &ArgMatches) {
let package_version = parse_package_version(); let package_version = parse_package_version();
let id = matches.value_of("id").unwrap(); let id = matches.value_of("id").unwrap();
+7 -40
View File
@@ -1,14 +1,13 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net> // Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
use clap::{crate_version, App, ArgMatches}; use clap::{App, ArgMatches};
pub mod client; pub mod client;
mod commands; mod commands;
pub mod socks; pub mod socks;
#[tokio::main] fn main() {
async fn main() {
dotenv::dotenv().ok(); dotenv::dotenv().ok();
setup_logging(); setup_logging();
println!("{}", banner()); println!("{}", banner());
@@ -16,20 +15,19 @@ async fn main() {
let arg_matches = App::new("Nym Socks5 Proxy") let arg_matches = App::new("Nym Socks5 Proxy")
.version(env!("CARGO_PKG_VERSION")) .version(env!("CARGO_PKG_VERSION"))
.author("Nymtech") .author("Nymtech")
.long_version(&*long_version())
.about("A Socks5 localhost proxy that converts incoming messages to Sphinx and sends them to a Nym address") .about("A Socks5 localhost proxy that converts incoming messages to Sphinx and sends them to a Nym address")
.subcommand(commands::init::command_args()) .subcommand(commands::init::command_args())
.subcommand(commands::run::command_args()) .subcommand(commands::run::command_args())
.subcommand(commands::upgrade::command_args()) .subcommand(commands::upgrade::command_args())
.get_matches(); .get_matches();
execute(arg_matches).await; execute(arg_matches);
} }
async fn execute(matches: ArgMatches<'static>) { fn execute(matches: ArgMatches) {
match matches.subcommand() { match matches.subcommand() {
("init", Some(m)) => commands::init::execute(m.clone()).await, ("init", Some(m)) => commands::init::execute(m),
("run", Some(m)) => commands::run::execute(m.clone()).await, ("run", Some(m)) => commands::run::execute(m),
("upgrade", Some(m)) => commands::upgrade::execute(m), ("upgrade", Some(m)) => commands::upgrade::execute(m),
_ => println!("{}", usage()), _ => println!("{}", usage()),
} }
@@ -52,38 +50,7 @@ fn banner() -> String {
(socks5 proxy - version {:}) (socks5 proxy - version {:})
"#, "#,
crate_version!() env!("CARGO_PKG_VERSION")
)
}
fn long_version() -> String {
format!(
r#"
{:<20}{}
{:<20}{}
{:<20}{}
{:<20}{}
{:<20}{}
{:<20}{}
{:<20}{}
{:<20}{}
"#,
"Build Timestamp:",
env!("VERGEN_BUILD_TIMESTAMP"),
"Build Version:",
env!("VERGEN_BUILD_SEMVER"),
"Commit SHA:",
env!("VERGEN_GIT_SHA"),
"Commit Date:",
env!("VERGEN_GIT_COMMIT_TIMESTAMP"),
"Commit Branch:",
env!("VERGEN_GIT_BRANCH"),
"rustc Version:",
env!("VERGEN_RUSTC_SEMVER"),
"rustc Channel:",
env!("VERGEN_RUSTC_CHANNEL"),
"cargo Profile:",
env!("VERGEN_CARGO_PROFILE"),
) )
} }
+5
View File
@@ -0,0 +1,5 @@
.DS_Store
/node_modules/
/src/node_modules/@sapper/
yarn-error.log
/__sapper__/
+33
View File
@@ -0,0 +1,33 @@
## Prerequisites
On Ubuntu-ish systems (not tested on Debian but may work):
```
sudo apt update && sudo apt install libwebkit2gtk-4.0-dev \
build-essential \
curl \
wget \
libssl-dev \
libgtk-3-dev \
libappindicator3-dev \
patchelf \
librsvg2-dev```
## Getting started
1. Start Sapper([docs](https://sapper.svelte.dev/docs/)) -> `yarn run dev`
2. Start Tauri([docs](https://tauri.studio/en/)) in another terminal -> `yarn tauri dev`
3. Start validator-api locally, or override `validator-urls` in `index.svelte`
## Getting around
+ Frontend -> `tauri-client/`
+ logic -> `tauri-client/src/routes/index.svelte`
+ assets -> `tauri-client/static`
+ Backend -> `tauri-client/src/src-tauri`
## Build standalone app
+ yarn tauri build [--debug]
File diff suppressed because it is too large Load Diff

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