Compare commits
349 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f838ddffe2 | |||
| 7f7c33d10b | |||
| e7fdd3d076 | |||
| 4dc89bd65f | |||
| 9aa3b9507d | |||
| 61e88f304b | |||
| 7ff043d8df | |||
| c904d245d2 | |||
| d315a2a91b | |||
| 0741d05ab3 | |||
| 61aa920362 | |||
| 24b9b17e64 | |||
| 5e3e633c4b | |||
| f3cff902ba | |||
| 4fe1b4c26f | |||
| cb24a08b06 | |||
| 597a53d11a | |||
| 639deeb502 | |||
| 03e082725e | |||
| 3e3307887e | |||
| d85683aaa8 | |||
| e89ed985fc | |||
| 45ebd7c37a | |||
| 3506020e55 | |||
| eca77d684b | |||
| e263a4a21f | |||
| dc4353c682 | |||
| e1d8069967 | |||
| 060726b7a3 | |||
| f72ccb0f0d | |||
| 2ff6bfbdd8 | |||
| d4f0b4772b | |||
| 17d258d094 | |||
| 8288d38257 | |||
| 1cd560c85e | |||
| 9018642992 | |||
| 04e652441e | |||
| ccf5990bc7 | |||
| 3d7c9ee2b8 | |||
| ad35c4006e | |||
| 2ec790e851 | |||
| 8f8cec0785 | |||
| 4a80cd301b | |||
| 63524eceff | |||
| a477b007e1 | |||
| 5b81510325 | |||
| 3bef973326 | |||
| bc5bb271d8 | |||
| 158e3cb073 | |||
| 36fb0eba29 | |||
| 1b37e85418 | |||
| 6a93497c8f | |||
| b8ee3465f8 | |||
| a7dfb36a84 | |||
| 14a7b5bdc8 | |||
| ffbd76539a | |||
| bdcc19e86a | |||
| 7929bac685 | |||
| f590aad42c | |||
| ec23f3dcb7 | |||
| 9644eb4329 | |||
| 7a4c6e4ed4 | |||
| d5ad504104 | |||
| d684f6d7ae | |||
| 1ba6444e72 | |||
| dc08b1170a | |||
| f0d9703587 | |||
| aa78bf702c | |||
| cd9cdfa5bb | |||
| 7e1e86bc77 | |||
| 2178f2b509 | |||
| c08efef8ed | |||
| 6d29774744 | |||
| af6bab7703 | |||
| 7033f92d82 | |||
| 128dfa6d81 | |||
| 8ed808124e | |||
| 0deef37778 | |||
| d759462e4e | |||
| f36cb3a00b | |||
| 6428f90b5a | |||
| e2d00fb002 | |||
| 0b0ec075bb | |||
| dc556706c1 | |||
| cca4d21e7c | |||
| 01f4773a5d | |||
| 6d15b444a0 | |||
| 18a3366cf3 | |||
| ea161329dc | |||
| 02a621ed8b | |||
| 5784e7519f | |||
| 323d5fbb3c | |||
| 2d89ec51c5 | |||
| 8927824d59 | |||
| 665f093bcf | |||
| 4b77312bee | |||
| f4bee0eed0 | |||
| 905ffc257a | |||
| 2419beccaf | |||
| 2ad5893a78 | |||
| c8e2d25e7a | |||
| cfea2c3aa3 | |||
| f59dc2a361 | |||
| 72f9f58fce | |||
| 2f2dfff53d | |||
| c8f8c9cb07 | |||
| 9afc21170a | |||
| 97d06d3859 | |||
| b02ee65870 | |||
| d9cec11f63 | |||
| 81028c554f | |||
| ffc6f5e963 | |||
| 6fdf70c609 | |||
| ab2a9f24c3 | |||
| 73f3f8cfab | |||
| 20c77e6987 | |||
| 630b1259d1 | |||
| 8c50492d43 | |||
| ae56d3685c | |||
| 6295d28972 | |||
| 8a8faf03d1 | |||
| e09b2ab7d6 | |||
| 2553d633ae | |||
| f5bcb8be6f | |||
| 24823356fc | |||
| cfa8854ada | |||
| 17d5cea636 | |||
| fceef1afa6 | |||
| 6c62332409 | |||
| 650d3eeae0 | |||
| 9b7f98518c | |||
| 1ba23cf4b5 | |||
| 300df601fa | |||
| 699b032f2a | |||
| 7c86ef4cbc | |||
| 2dc3999c77 | |||
| 7b7cac5054 | |||
| 5f7270acc8 | |||
| 4e829ef540 | |||
| ba64c4f8b3 | |||
| 2b5c426d67 | |||
| ceec4da27d | |||
| af9df88a48 | |||
| 4ecd252561 | |||
| 19c1ef66c8 | |||
| 13e3a79a93 | |||
| d867e0e244 | |||
| 316e984b0a | |||
| 71b5477334 | |||
| c15a081e6f | |||
| add92c7b5e | |||
| 1080cf4afe | |||
| 4e2fae8878 | |||
| fbae1d7963 | |||
| 495aec39f5 | |||
| 06c9c54cdb | |||
| ba90e740e2 | |||
| 1f36b53b64 | |||
| 23fb48316a | |||
| 312cd65d20 | |||
| b3b4b5ff36 | |||
| 79e51252a8 | |||
| cc1c9a75b4 | |||
| 5813e9212b | |||
| 6ce743fbd5 | |||
| 025f5da39e | |||
| ddd9498c0b | |||
| b62e221aad | |||
| 69c8891f82 | |||
| c2326f35a6 | |||
| bda32cfef3 | |||
| b3425a6a6e | |||
| 9e7c77ca6a | |||
| 92a755dc6c | |||
| 39e75850ff | |||
| 4587d5da26 | |||
| 586d5f658b | |||
| 9912e445a4 | |||
| 02397832f4 | |||
| 03fa8c17d7 | |||
| 964955f740 | |||
| b1121dabb9 | |||
| caff2077ae | |||
| b980bfcab8 | |||
| 57822e3c0d | |||
| b98bf46675 | |||
| 1417eeeddb | |||
| 31389dd886 | |||
| 36cf36aaae | |||
| dd08621329 | |||
| ca7ee04e47 | |||
| 0130881616 | |||
| cde247df46 | |||
| 448b2353ab | |||
| 46e2c74a98 | |||
| ce79d5a3bc | |||
| fede9cc194 | |||
| c75c5e0903 | |||
| ec00918524 | |||
| 9a43595e04 | |||
| 49334c0540 | |||
| 4a2f30a581 | |||
| bbb3287029 | |||
| 6a82285342 | |||
| 494f1d5199 | |||
| 22ee87d87e | |||
| a8e62bde26 | |||
| 22df65aad7 | |||
| c4e86337e5 | |||
| 2d3bb78819 | |||
| 1ec11dda24 | |||
| 723b4b4754 | |||
| 4e239ac9b7 | |||
| dafb69d2d6 | |||
| e225c1ee1b | |||
| 1feb53cc87 | |||
| 4c919f520a | |||
| bb64d8c03e | |||
| 580cc58f42 | |||
| bc75dd7e15 | |||
| 40af0f94b0 | |||
| c9c68ab2cb | |||
| 26c5fa7262 | |||
| b5adf2bb42 | |||
| 254ea6af42 | |||
| a971694ff7 | |||
| 2d59236ee8 | |||
| 17322ccda2 | |||
| 3d2e7d32d9 | |||
| 0b93215941 | |||
| 8f4fd62957 | |||
| 4844ac953a | |||
| aab094984e | |||
| a5056007d4 | |||
| 9c77e15a2c | |||
| c8bd6b99fa | |||
| 081d6097b6 | |||
| 4820258270 | |||
| e41a59fddc | |||
| 130491e80f | |||
| 165e7d8b27 | |||
| 3c97d0d16b | |||
| 16ae72fbd9 | |||
| bc55c10e19 | |||
| a925c39642 | |||
| 4fa018540c | |||
| e2b69b79e7 | |||
| d23fb366e4 | |||
| be369c2023 | |||
| 7e90ff8b85 | |||
| f5c5b342bb | |||
| af9cf52b1e | |||
| 3d500c25c5 | |||
| 3b9fb9088d | |||
| c95b5f0982 | |||
| 7cca3c716a | |||
| 9348722b84 | |||
| fd1fb7ca7b | |||
| 6252b66724 | |||
| b770cab3f0 | |||
| 726a406797 | |||
| 4652d65874 | |||
| a4ca94ccef | |||
| e69552b19d | |||
| e3cc43487a | |||
| 41be555aa6 | |||
| bdc0bcbd56 | |||
| 0baa8b2c92 | |||
| 2ab969b2c6 | |||
| 9f2e7e16e5 | |||
| 1c99446bcc | |||
| 90d9c9ec41 | |||
| 2e38c5e38e | |||
| dbb7a27441 | |||
| 89c05387f8 | |||
| 7952277c4b | |||
| c5866db137 | |||
| 37187c79cc | |||
| 24839770ff | |||
| 0238499e33 | |||
| 3363230c4c | |||
| 1f8b373780 | |||
| 7ac3ec3598 | |||
| 77ae71eba4 | |||
| d4b836277e | |||
| b92ee84874 | |||
| 2eb0ce381a | |||
| 037cd54573 | |||
| 9f42f0152b | |||
| 5217edcca3 | |||
| e306effdac | |||
| dc2b1c6d2a | |||
| 4232801e80 | |||
| 96df3ad4ce | |||
| d614a2b81b | |||
| d27245e184 | |||
| 5dbfcadfdb | |||
| 035dada0e0 | |||
| 1d867156e3 | |||
| ed9be47ec4 | |||
| 3aa2e6c54d | |||
| eb96fc72b9 | |||
| 59cec6f03c | |||
| c0a0d89a90 | |||
| 3099f2ead3 | |||
| baf88ce10a | |||
| 362e7f2fea | |||
| d89081d8a1 | |||
| eeba17a01f | |||
| 25762900fa | |||
| 3bc7f281b4 | |||
| 3e23bdf3c0 | |||
| 5a89e894a9 | |||
| 795977a75d | |||
| 8dbddb7b7e | |||
| 4e057cd250 | |||
| b62c969a7c | |||
| be1ec79b01 | |||
| 5d10e62450 | |||
| 64acddead6 | |||
| 8bbf766eeb | |||
| d7cd942dec | |||
| a9124a63f9 | |||
| b0d7169b39 | |||
| d57b486bf4 | |||
| ef8ecd42a3 | |||
| 02e1dc01af | |||
| b29bd8bcc3 | |||
| 9ad9fd36e2 | |||
| bd61679c58 | |||
| 21e636616d | |||
| 9881a94757 | |||
| 76b07d487b | |||
| f04fc452dc | |||
| be90d03129 | |||
| 0a3e42700c | |||
| 55d554701c | |||
| 19c4769260 | |||
| 71aadc8e1b | |||
| 95340b5817 | |||
| 12751665bb | |||
| 01b86bcc0d | |||
| c6ce8caaf7 | |||
| 265713b9d2 | |||
| c9af4721f3 | |||
| 8c0ab7c697 | |||
| 92b220ca4b | |||
| c218cba96c | |||
| c958975fff |
@@ -39,20 +39,16 @@ jobs:
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
- name: Keybase - Node Install
|
||||
- name: Matrix - Node Install
|
||||
run: npm install
|
||||
working-directory: .github/workflows/support-files
|
||||
- name: Keybase - Send Notification
|
||||
- name: Matrix - Send Notification
|
||||
env:
|
||||
NYM_NOTIFICATION_KIND: security
|
||||
NYM_PROJECT_NAME: "Daily security report"
|
||||
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
|
||||
KEYBASE_NYMBOT_USERNAME: "${{ secrets.KEYBASE_NYMBOT_USERNAME }}"
|
||||
KEYBASE_NYMBOT_PAPERKEY: "${{ secrets.KEYBASE_NYMBOT_PAPERKEY }}"
|
||||
KEYBASE_NYMBOT_TEAM: "${{ secrets.KEYBASE_NYMBOT_TEAM }}"
|
||||
KEYBASE_NYM_CHANNEL: "security"
|
||||
MATRIX_SERVER: "${{ secrets.MATRIX_SERVER }}"
|
||||
MATRIX_ROOM: "${{ secrets.MATRIX_ROOM }}"
|
||||
MATRIX_ROOM: "${{ secrets.MATRIX_ROOM_AUDIT }}"
|
||||
MATRIX_USER_ID: "${{ secrets.MATRIX_USER_ID }}"
|
||||
MATRIX_TOKEN: "${{ secrets.MATRIX_TOKEN }}"
|
||||
MATRIX_DEVICE_ID: "${{ secrets.MATRIX_DEVICE_ID }}"
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
name: Build and upload binaries to CI
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
paths:
|
||||
- 'clients/**'
|
||||
- 'common/**'
|
||||
- 'contracts/**'
|
||||
- 'explorer-api/**'
|
||||
- 'gateway/**'
|
||||
- 'integrations/**'
|
||||
- 'mixnode/**'
|
||||
- 'sdk/rust/nym-sdk/**'
|
||||
- 'service-providers/**'
|
||||
- 'nym-api/**'
|
||||
- 'nym-outfox/**'
|
||||
- 'tools/nym-cli/**'
|
||||
- 'tools/ts-rs-cli/**'
|
||||
pull_request:
|
||||
paths:
|
||||
- 'clients/**'
|
||||
- 'common/**'
|
||||
- 'contracts/**'
|
||||
- 'explorer-api/**'
|
||||
- 'gateway/**'
|
||||
- 'integrations/**'
|
||||
- 'mixnode/**'
|
||||
- 'sdk/rust/nym-sdk/**'
|
||||
- 'service-providers/**'
|
||||
- 'nym-api/**'
|
||||
- 'nym-outfox/**'
|
||||
- 'tools/nym-cli/**'
|
||||
- 'tools/ts-rs-cli/**'
|
||||
|
||||
env:
|
||||
NETWORK: mainnet
|
||||
|
||||
jobs:
|
||||
publish-nym:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform: [ubuntu-20.04]
|
||||
|
||||
runs-on: ${{ matrix.platform }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Prepare build output directory
|
||||
shell: bash
|
||||
env:
|
||||
OUTPUT_DIR: ci-builds/${{ github.ref_name }}
|
||||
run: |
|
||||
rm -rf ci-builds || true
|
||||
mkdir -p $OUTPUT_DIR
|
||||
echo $OUTPUT_DIR
|
||||
|
||||
- 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 libudev-dev squashfs-tools
|
||||
continue-on-error: true
|
||||
|
||||
- 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 --all
|
||||
|
||||
- name: Install Rust stable
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
target: wasm32-unknown-unknown
|
||||
override: true
|
||||
components: rustfmt, clippy
|
||||
|
||||
- name: Install wasm-opt
|
||||
run: cargo install wasm-opt
|
||||
|
||||
- name: Build release contracts
|
||||
run: make wasm
|
||||
|
||||
- name: Prepare build output
|
||||
shell: bash
|
||||
env:
|
||||
OUTPUT_DIR: ci-builds/${{ github.ref_name }}
|
||||
run: |
|
||||
cp target/release/nym-client $OUTPUT_DIR
|
||||
cp target/release/nym-gateway $OUTPUT_DIR
|
||||
cp target/release/nym-mixnode $OUTPUT_DIR
|
||||
cp target/release/nym-socks5-client $OUTPUT_DIR
|
||||
cp target/release/nym-api $OUTPUT_DIR
|
||||
cp target/release/nym-network-requester $OUTPUT_DIR
|
||||
cp target/release/nym-network-statistics $OUTPUT_DIR
|
||||
cp target/release/nym-cli $OUTPUT_DIR
|
||||
cp target/release/credential $OUTPUT_DIR
|
||||
|
||||
cp contracts/target/wasm32-unknown-unknown/release/mixnet_contract.wasm $OUTPUT_DIR
|
||||
cp contracts/target/wasm32-unknown-unknown/release/vesting_contract.wasm $OUTPUT_DIR
|
||||
|
||||
- name: Deploy branch to CI www
|
||||
continue-on-error: true
|
||||
uses: easingthemes/ssh-deploy@main
|
||||
env:
|
||||
SSH_PRIVATE_KEY: ${{ secrets.CI_WWW_SSH_PRIVATE_KEY }}
|
||||
ARGS: "-avzr"
|
||||
SOURCE: "ci-builds/"
|
||||
REMOTE_HOST: ${{ secrets.CI_WWW_REMOTE_HOST }}
|
||||
REMOTE_USER: ${{ secrets.CI_WWW_REMOTE_USER }}
|
||||
TARGET: ${{ secrets.CI_WWW_REMOTE_TARGET }}/builds/
|
||||
EXCLUDE: "/dist/, /node_modules/"
|
||||
@@ -43,10 +43,10 @@ jobs:
|
||||
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
|
||||
- name: Matrix - Node Install
|
||||
run: npm install
|
||||
working-directory: .github/workflows/support-files
|
||||
- name: Keybase - Send Notification
|
||||
- name: Matrix - Send Notification
|
||||
env:
|
||||
NYM_NOTIFICATION_KIND: ts-packages
|
||||
NYM_PROJECT_NAME: "ts-packages"
|
||||
@@ -54,10 +54,6 @@ jobs:
|
||||
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' }}"
|
||||
MATRIX_SERVER: "${{ secrets.MATRIX_SERVER }}"
|
||||
MATRIX_ROOM: "${{ secrets.MATRIX_ROOM }}"
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
name: check-merge-conflicts
|
||||
|
||||
# Check that the latest release branch merges into master and develop without
|
||||
# any conflicts that git is not able to resolve
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: '5 6 * * *'
|
||||
|
||||
jobs:
|
||||
get_release:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
output1: ${{ steps.step2.outputs.latest_release }}
|
||||
steps:
|
||||
- name: Check out repository code
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Set output variable to latest release branch
|
||||
id: step2
|
||||
run: echo "latest_release=$(git branch -r | grep -E 'release/v[0-9]+\.[0-9]+\.[0-9]+$' | sort -V | tail -n 1)" >> $GITHUB_OUTPUT
|
||||
|
||||
check-merge-release-into-master:
|
||||
name: Check that the release branch merges into master
|
||||
needs: get_release
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Setup git user
|
||||
run: |
|
||||
git config --global user.name "ci"
|
||||
git config --global user.email "ci@localhost"
|
||||
- name: Check merge release branch into master
|
||||
run: |
|
||||
./.github/workflows/support-files/git-merge-check.sh origin/master $branch1
|
||||
env:
|
||||
branch1: ${{needs.get_release.outputs.output1}}
|
||||
|
||||
check-merge-release-into-develop:
|
||||
name: Check that the release branch merges into develop
|
||||
needs: get_release
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Setup git user
|
||||
run: |
|
||||
git config --global user.name "ci"
|
||||
git config --global user.email "ci@localhost"
|
||||
- name: Check merge release branch into develop
|
||||
run: |
|
||||
./.github/workflows/support-files/git-merge-check.sh origin/develop $branch1
|
||||
env:
|
||||
branch1: ${{needs.get_release.outputs.output1}}
|
||||
@@ -0,0 +1,56 @@
|
||||
name: Run config checks on all binaries
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
release:
|
||||
types: [created]
|
||||
push:
|
||||
paths:
|
||||
- 'clients/**'
|
||||
- 'common/**'
|
||||
- 'contracts/**'
|
||||
- 'integrations/**'
|
||||
- 'mixnode/**'
|
||||
- 'sdk/rust/nym-sdk/**'
|
||||
- 'service-providers/**'
|
||||
pull_request:
|
||||
paths:
|
||||
- 'clients/**'
|
||||
- 'common/**'
|
||||
- 'gateway/**'
|
||||
- 'integrations/**'
|
||||
- 'mixnode/**'
|
||||
- 'sdk/rust/nym-sdk/**'
|
||||
- 'service-providers/**'
|
||||
|
||||
env:
|
||||
NETWORK: mainnet
|
||||
|
||||
jobs:
|
||||
publish-nym:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform: [custom-runner-linux]
|
||||
|
||||
runs-on: ${{ matrix.platform }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Install Dependencies (Linux)
|
||||
run: sudo apt-get update && sudo apt-get -y install jq vim libwebkit2gtk-4.0-dev build-essential curl wget libssl-dev libgtk-3-dev libudev-dev squashfs-tools
|
||||
continue-on-error: true
|
||||
|
||||
- name: Install Rust stable
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
|
||||
- name: Branch name
|
||||
run: echo running on branch ${GITHUB_REF##*/}
|
||||
|
||||
- name: Run tests against binaries
|
||||
run: ./build_and_run.sh ${{ github.head_ref || github.ref_name }}
|
||||
working-directory: tests/
|
||||
|
||||
|
||||
@@ -0,0 +1,138 @@
|
||||
name: Nym Connect - Android APK Build
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- "release/nc-android-v[0-9].[0-9].[0-9]*"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build APK
|
||||
runs-on: custom-runner-linux
|
||||
env:
|
||||
ANDROID_HOME: ${{ github.workspace }}/android-sdk
|
||||
NDK_VERSION: 25.1.8937393
|
||||
NDK_HOME: ${{ github.workspace }}/android-sdk/ndk/25.1.8937393
|
||||
SDK_PLATFORM_VERSION: android-33
|
||||
SDK_BUILDTOOLS_VERSION: 33.0.1
|
||||
|
||||
steps:
|
||||
- name: Install Dependencies (Linux)
|
||||
# https://next--tauri.netlify.app/next/guides/getting-started/prerequisites/linux/#1-system-dependencies
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get -y install \
|
||||
build-essential \
|
||||
unzip \
|
||||
curl \
|
||||
wget \
|
||||
libssl-dev \
|
||||
squashfs-tools \
|
||||
librsvg2-dev
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Install Java
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
distribution: "temurin"
|
||||
java-version: "17"
|
||||
|
||||
- name: Install Android SDK manager
|
||||
# https://developer.android.com/studio/command-line/sdkmanager
|
||||
run: |
|
||||
curl -sS https://dl.google.com/android/repository/commandlinetools-linux-9477386_latest.zip -o cmdline-tools.zip
|
||||
unzip cmdline-tools.zip
|
||||
mkdir -p $ANDROID_HOME/cmdline-tools/latest
|
||||
mv cmdline-tools/* $ANDROID_HOME/cmdline-tools/latest
|
||||
rm -rf cmdline-tools
|
||||
|
||||
- name: Install Android S/NDK
|
||||
run: |
|
||||
echo y | $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager --licenses
|
||||
echo y | $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager \
|
||||
"platforms;$SDK_PLATFORM_VERSION" \
|
||||
"platform-tools" \
|
||||
"ndk;$NDK_VERSION" \
|
||||
"build-tools;$SDK_BUILDTOOLS_VERSION"
|
||||
|
||||
- name: Install Rust toolchain
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
|
||||
# TODO this step takes a considerable amount of time
|
||||
# We could avoid to compile from source tauri-cli and use instead
|
||||
# pre-compiled binary provided by the node package `@tauri-apps/cli`
|
||||
# But when using the later the build fails for some reason
|
||||
# so keep installing and using tauri-cli
|
||||
- name: Install tauri cli
|
||||
run: cargo install tauri-cli --version "^2.0.0-alpha.2"
|
||||
|
||||
- name: Install rust android targets
|
||||
run: |
|
||||
rustup target add aarch64-linux-android \
|
||||
armv7-linux-androideabi \
|
||||
i686-linux-android \
|
||||
x86_64-linux-android
|
||||
|
||||
- name: Setup Nodejs
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 18
|
||||
|
||||
- name: Install yarn
|
||||
run: |
|
||||
npm i -g yarn
|
||||
yarn --version
|
||||
|
||||
- name: Build frontend code
|
||||
run: |
|
||||
yarn install --frozen-lockfile
|
||||
yarn build
|
||||
yarn workspace @nym/nym-connect-mobile webpack:prod
|
||||
|
||||
- name: Build APK
|
||||
working-directory: nym-connect/mobile
|
||||
env:
|
||||
# NODE_TAURI_CLI=${{ github.workspace }}/nym-connect/mobile/node_modules/.bin/tauri
|
||||
ANDROID_SDK_ROOT: ${{ env.ANDROID_HOME }}
|
||||
WRY_ANDROID_PACKAGE: net.nymtech.nym_connect
|
||||
WRY_ANDROID_LIBRARY: nym_connect
|
||||
# TODO build with release profile (--release), it will requires
|
||||
# to sign the APK. For now build with debug profile to avoid that
|
||||
# TODO build using `yarn tauri`, provide NODE_TAURI_CLI, see TODO notes above
|
||||
run: cargo tauri android build --debug --apk --split-per-abi -t aarch64
|
||||
|
||||
# TODO add the version number to APK name
|
||||
- name: Rename APK artifact
|
||||
run: |
|
||||
mkdir apk/
|
||||
mv nym-connect/mobile/src-tauri/gen/android/nym_connect/app/build/outputs/apk/arm64/debug/app-arm64-debug.apk \
|
||||
apk/nym-connect-arm64-debug.apk
|
||||
mv nym-connect/mobile/src-tauri/gen/android/nym_connect/app/build/outputs/apk/x86_64/debug/app-x86_64-debug.apk \
|
||||
apk/nym-connect-x86_64-debug.apk
|
||||
|
||||
- name: Upload APK artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: nc-apk-debug
|
||||
path: |
|
||||
apk/nym-connect-arm64-debug.apk
|
||||
apk/nym-connect-x86_64-debug.apk
|
||||
|
||||
# publish:
|
||||
# name: Publish APK
|
||||
# needs: build
|
||||
# runs-on: ubuntu-latest
|
||||
# steps:
|
||||
# - name: Checkout
|
||||
# uses: actions/checkout@v3
|
||||
# - name: Download binary artifact
|
||||
# uses: actions/download-artifact@v3
|
||||
# with:
|
||||
# name: nc-apk-debug
|
||||
# path: apk
|
||||
# # TODO add a step to upload the APK somewhere
|
||||
# - name: Publish
|
||||
# uses: ???
|
||||
@@ -1,13 +1,13 @@
|
||||
name: CI for nym-connect
|
||||
name: CI for nym-connect - Desktop
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- 'nym-connect/**'
|
||||
- 'nym-connect/desktop/**'
|
||||
|
||||
defaults:
|
||||
run:
|
||||
working-directory: nym-connect
|
||||
working-directory: nym-connect/desktop
|
||||
|
||||
jobs:
|
||||
build:
|
||||
@@ -34,15 +34,15 @@ jobs:
|
||||
env:
|
||||
SSH_PRIVATE_KEY: ${{ secrets.CI_WWW_SSH_PRIVATE_KEY }}
|
||||
ARGS: "-rltgoDzvO --delete"
|
||||
SOURCE: "nym-connect/storybook-static/"
|
||||
SOURCE: "nym-connect/desktop/storybook-static/"
|
||||
REMOTE_HOST: ${{ secrets.CI_WWW_REMOTE_HOST }}
|
||||
REMOTE_USER: ${{ secrets.CI_WWW_REMOTE_USER }}
|
||||
TARGET: ${{ secrets.CI_WWW_REMOTE_TARGET }}/nym-connect-${{ env.GITHUB_REF_SLUG }}
|
||||
EXCLUDE: "/dist/, /node_modules/"
|
||||
- name: Keybase - Node Install
|
||||
- name: Matrix - Node Install
|
||||
run: npm install
|
||||
working-directory: .github/workflows/support-files
|
||||
- name: Keybase - Send Notification
|
||||
- name: Matrix - Send Notification
|
||||
env:
|
||||
NYM_NOTIFICATION_KIND: nym-connect
|
||||
NYM_PROJECT_NAME: "nym-connect"
|
||||
@@ -50,10 +50,6 @@ jobs:
|
||||
NYM_CI_WWW_LOCATION: "nym-connect-${{ 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-nym-connect"
|
||||
IS_SUCCESS: "${{ job.status == 'success' }}"
|
||||
MATRIX_SERVER: "${{ secrets.MATRIX_SERVER }}"
|
||||
MATRIX_ROOM: "${{ secrets.MATRIX_ROOM }}"
|
||||
@@ -1,28 +1,30 @@
|
||||
name: Nym Connect (rust)
|
||||
name: Nym Connect - desktop (Rust)
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- 'nym-connect/**'
|
||||
- 'clients/client-core/**'
|
||||
- 'clients/socks5/**'
|
||||
- 'common/**'
|
||||
- 'gateway/gateway-requests/**'
|
||||
- 'contracts/vesting/**'
|
||||
- 'nym-api/nym-api-requests/**'
|
||||
- "nym-connect/desktop/src-tauri/**"
|
||||
- "nym-connect/desktop/src-tauri/Cargo.toml"
|
||||
- "clients/client-core/**"
|
||||
- "clients/socks5/**"
|
||||
- "common/**"
|
||||
- "gateway/gateway-requests/**"
|
||||
- "contracts/vesting/**"
|
||||
- "nym-api/nym-api-requests/**"
|
||||
pull_request:
|
||||
paths:
|
||||
- 'nym-connect/**'
|
||||
- 'clients/client-core/**'
|
||||
- 'clients/socks5/**'
|
||||
- 'common/**'
|
||||
- 'gateway/gateway-requests/**'
|
||||
- 'contracts/vesting/**'
|
||||
- 'nym-api/nym-api-requests/**'
|
||||
- "nym-connect/desktop/src-tauri/**"
|
||||
- "nym-connect/desktop/src-tauri/Cargo.toml"
|
||||
- "clients/client-core/**"
|
||||
- "clients/socks5/**"
|
||||
- "common/**"
|
||||
- "gateway/gateway-requests/**"
|
||||
- "contracts/vesting/**"
|
||||
- "nym-api/nym-api-requests/**"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: [ self-hosted, custom-linux ]
|
||||
runs-on: [self-hosted, custom-linux]
|
||||
env:
|
||||
RUSTC_WRAPPER: /home/ubuntu/.cargo/bin/sccache
|
||||
steps:
|
||||
@@ -45,29 +47,29 @@ jobs:
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: build
|
||||
args: --manifest-path nym-connect/Cargo.toml --workspace
|
||||
args: --manifest-path nym-connect/desktop/Cargo.toml --workspace
|
||||
|
||||
- name: Run all tests
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: test
|
||||
args: --manifest-path nym-connect/Cargo.toml --workspace
|
||||
args: --manifest-path nym-connect/desktop/Cargo.toml --workspace
|
||||
|
||||
- name: Check formatting
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: fmt
|
||||
args: --manifest-path nym-connect/Cargo.toml --all -- --check
|
||||
args: --manifest-path nym-connect/desktop/Cargo.toml --all -- --check
|
||||
|
||||
- uses: actions-rs/clippy-check@v1
|
||||
name: Clippy checks
|
||||
continue-on-error: true
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
args: --manifest-path nym-connect/Cargo.toml --workspace --all-features
|
||||
args: --manifest-path nym-connect/desktop/Cargo.toml --workspace --all-features
|
||||
|
||||
- name: Run clippy
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: clippy
|
||||
args: --manifest-path nym-connect/Cargo.toml --workspace --all-features -- -D warnings
|
||||
args: --manifest-path nym-connect/desktop/Cargo.toml --workspace --all-features -- -D warnings
|
||||
@@ -1,9 +1,11 @@
|
||||
name: Nym Connect for Android (rust)
|
||||
name: Nym Connect - mobile (Rust)
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- "nym-connect-android/src-tauri/**"
|
||||
- "nym-connect/mobile/src-tauri/**"
|
||||
- "nym-connect/mobile/src-tauri/Cargo.toml"
|
||||
- "!nym-connect/mobile/src-tauri/gen/**"
|
||||
- "clients/client-core/**"
|
||||
- "clients/socks5/**"
|
||||
- "common/**"
|
||||
@@ -12,7 +14,9 @@ on:
|
||||
- "nym-api/nym-api-requests/**"
|
||||
pull_request:
|
||||
paths:
|
||||
- "nym-connect-android/src-tauri/**"
|
||||
- "nym-connect/mobile/src-tauri/**"
|
||||
- "nym-connect/mobile/src-tauri/Cargo.toml"
|
||||
- "!nym-connect/mobile/src-tauri/gen/**"
|
||||
- "clients/client-core/**"
|
||||
- "clients/socks5/**"
|
||||
- "common/**"
|
||||
@@ -28,10 +32,9 @@ jobs:
|
||||
#RUSTC_WRAPPER: /home/ubuntu/.cargo/bin/sccache
|
||||
#defaults:
|
||||
#run:
|
||||
#working-directory: nym-connect-android/src-tauri/
|
||||
#working-directory: nym-connect/mobile/src-tauri/
|
||||
steps:
|
||||
- name: Install Dependencies (Linux)
|
||||
if: ${{ !env.ACT }}
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get -y install \
|
||||
@@ -46,7 +49,6 @@ jobs:
|
||||
librsvg2-dev \
|
||||
libsoup-3.0-dev \
|
||||
libjavascriptcoregtk-4.1-dev
|
||||
#continue-on-error: true
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
@@ -58,13 +60,13 @@ jobs:
|
||||
components: clippy, rustfmt
|
||||
|
||||
- name: Check formatting
|
||||
run: cargo fmt --manifest-path nym-connect-android/src-tauri/Cargo.toml -- --check
|
||||
run: cargo fmt --manifest-path nym-connect/mobile/src-tauri/Cargo.toml -- --check
|
||||
|
||||
- name: Build all binaries
|
||||
run: cargo build --manifest-path nym-connect-android/src-tauri/Cargo.toml
|
||||
run: cargo build --manifest-path nym-connect/mobile/src-tauri/Cargo.toml
|
||||
|
||||
- name: Run all tests
|
||||
run: cargo test --manifest-path nym-connect-android/src-tauri/Cargo.toml
|
||||
run: cargo test --manifest-path nym-connect/mobile/src-tauri/Cargo.toml
|
||||
|
||||
- name: Clippy
|
||||
run: cargo clippy --manifest-path nym-connect-android/src-tauri/Cargo.toml --all-targets -- -D warnings
|
||||
run: cargo clippy --manifest-path nym-connect/mobile/src-tauri/Cargo.toml --all-targets -- -D warnings
|
||||
@@ -6,7 +6,7 @@ on:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
if: ${{ startsWith(github.ref, 'refs/tags/nym-contracts-') && github.event_name == 'release' }}
|
||||
if: ${{ (startsWith(github.ref, 'refs/tags/nym-contracts-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
|
||||
runs-on: [self-hosted, custom-runner-linux]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
@@ -19,6 +19,9 @@ jobs:
|
||||
override: true
|
||||
components: rustfmt, clippy
|
||||
|
||||
- name: Install wasm-opt
|
||||
run: cargo install wasm-opt
|
||||
|
||||
- name: Build release contracts
|
||||
run: make wasm
|
||||
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
name: CI for Network Explorer API
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
release:
|
||||
types: [created]
|
||||
|
||||
env:
|
||||
NETWORK: mainnet
|
||||
|
||||
jobs:
|
||||
publish-nym:
|
||||
if: ${{ startsWith(github.ref, 'refs/tags/nym-explorer-api-') && (github.event_name == 'release' || github.event_name == 'workflow_dispatch') }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform: [ubuntu-20.04]
|
||||
|
||||
runs-on: ${{ matrix.platform }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- 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 libudev-dev squashfs-tools
|
||||
continue-on-error: true
|
||||
|
||||
- name: Check the release tag starts with `nym-explorer-api-`
|
||||
uses: actions/github-script@v3
|
||||
with:
|
||||
script: |
|
||||
core.setFailed('Release tag did not start with nym-explorer-api-...')
|
||||
|
||||
- name: Install Rust stable
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
|
||||
- name: Build all explorer-api
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: build
|
||||
args: --manifest-path explorer-api/Cargo.toml --workspace --release
|
||||
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: my-artifact
|
||||
path: |
|
||||
target/release/explorer-api
|
||||
retention-days: 30
|
||||
|
||||
- name: Upload to release based on tag name
|
||||
uses: softprops/action-gh-release@v1
|
||||
if: github.event_name == 'release'
|
||||
with:
|
||||
files: |
|
||||
target/release/explorer-api
|
||||
@@ -57,10 +57,10 @@ jobs:
|
||||
REMOTE_USER: ${{ secrets.CI_WWW_REMOTE_USER }}
|
||||
TARGET: ${{ secrets.CI_WWW_REMOTE_TARGET }}/ne-sb-${{ env.GITHUB_REF_SLUG }}
|
||||
EXCLUDE: "/dist/, /node_modules/"
|
||||
- name: Keybase - Node Install
|
||||
- name: Matrix - Node Install
|
||||
run: npm install
|
||||
working-directory: .github/workflows/support-files
|
||||
- name: Keybase - Send Notification
|
||||
- name: Matrix - Send Notification
|
||||
env:
|
||||
NYM_NOTIFICATION_KIND: network-explorer
|
||||
NYM_PROJECT_NAME: "Network Explorer"
|
||||
@@ -69,10 +69,6 @@ jobs:
|
||||
NYM_CI_WWW_LOCATION_STORYBOOK: "ne-sb-${{ 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-network-explorer"
|
||||
IS_SUCCESS: "${{ job.status == 'success' }}"
|
||||
MATRIX_SERVER: "${{ secrets.MATRIX_SERVER }}"
|
||||
MATRIX_ROOM: "${{ secrets.MATRIX_ROOM }}"
|
||||
|
||||
@@ -10,7 +10,7 @@ jobs:
|
||||
matrix: ${{ steps.set-matrix.outputs.matrix }}
|
||||
steps:
|
||||
# creates the matrix strategy from nightly_build_matrix_includes.json
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- id: set-matrix
|
||||
uses: JoshuaTheMiller/conditional-build-matrix@main
|
||||
with:
|
||||
@@ -29,7 +29,7 @@ jobs:
|
||||
if: matrix.os == 'ubuntu-20.04'
|
||||
|
||||
- name: Check out repository code
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Install rust toolchain
|
||||
uses: actions-rs/toolchain@v1
|
||||
@@ -51,9 +51,9 @@ jobs:
|
||||
command: build
|
||||
args: --workspace
|
||||
|
||||
- name: Reclaim some disk space (because Windows is being annoying)
|
||||
- name: Reclaim some disk space
|
||||
uses: actions-rs/cargo@v1
|
||||
if: ${{ matrix.os == 'windows-latest' }}
|
||||
if: ${{ matrix.os == 'windows-latest' || matrix.os == 'ubuntu-20.04' }}
|
||||
with:
|
||||
command: clean
|
||||
|
||||
@@ -63,9 +63,9 @@ jobs:
|
||||
command: build
|
||||
args: --workspace --examples
|
||||
|
||||
- name: Reclaim some disk space (because Windows is being annoying)
|
||||
- name: Reclaim some disk space
|
||||
uses: actions-rs/cargo@v1
|
||||
if: ${{ matrix.os == 'windows-latest' }}
|
||||
if: ${{ matrix.os == 'windows-latest' || matrix.os == 'ubuntu-20.04' }}
|
||||
with:
|
||||
command: clean
|
||||
|
||||
@@ -75,7 +75,7 @@ jobs:
|
||||
command: test
|
||||
args: --workspace
|
||||
|
||||
- name: Reclaim some disk space (because Windows is being annoying)
|
||||
- name: Reclaim some disk space
|
||||
uses: actions-rs/cargo@v1
|
||||
if: ${{ matrix.os == 'windows-latest' || matrix.os == 'ubuntu-20.04' }}
|
||||
with:
|
||||
@@ -88,9 +88,9 @@ jobs:
|
||||
command: test
|
||||
args: --workspace -- --ignored
|
||||
|
||||
- name: Reclaim some disk space (because Windows is being annoying)
|
||||
- name: Reclaim some disk space
|
||||
uses: actions-rs/cargo@v1
|
||||
if: ${{ matrix.os == 'windows-latest' }}
|
||||
if: ${{ matrix.os == 'windows-latest' || matrix.os == 'ubuntu-20.04' }}
|
||||
with:
|
||||
command: clean
|
||||
|
||||
@@ -147,17 +147,17 @@ jobs:
|
||||
- name: Collect jobs status
|
||||
uses: technote-space/workflow-conclusion-action@v2
|
||||
- name: Check out repository code
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
- name: install npm
|
||||
uses: actions/setup-node@v3
|
||||
if: env.WORKFLOW_CONCLUSION == 'failure'
|
||||
with:
|
||||
node-version: 16
|
||||
- name: Keybase - Node Install
|
||||
- name: Matrix - Node Install
|
||||
if: env.WORKFLOW_CONCLUSION == 'failure'
|
||||
run: npm install
|
||||
working-directory: .github/workflows/support-files
|
||||
- name: Keybase - Send Notification
|
||||
- name: Matrix - Send Notification
|
||||
if: env.WORKFLOW_CONCLUSION == 'failure'
|
||||
env:
|
||||
NYM_NOTIFICATION_KIND: nightly
|
||||
@@ -165,13 +165,9 @@ jobs:
|
||||
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' }}"
|
||||
MATRIX_SERVER: "${{ secrets.MATRIX_SERVER }}"
|
||||
MATRIX_ROOM: "${{ secrets.MATRIX_ROOM }}"
|
||||
MATRIX_ROOM: "${{ secrets.MATRIX_ROOM_NIGHTLY }}"
|
||||
MATRIX_USER_ID: "${{ secrets.MATRIX_USER_ID }}"
|
||||
MATRIX_TOKEN: "${{ secrets.MATRIX_TOKEN }}"
|
||||
MATRIX_DEVICE_ID: "${{ secrets.MATRIX_DEVICE_ID }}"
|
||||
|
||||
@@ -28,7 +28,7 @@ jobs:
|
||||
run: git fetch --all
|
||||
- name: Set output variable to latest release branch
|
||||
id: step2
|
||||
run: echo "latest_release=$(git branch -r | grep -E 'release/v[0-9]+\.[0-9]+\.[0-9]+' | tail -n 1 | sed 's/ origin\///')" >> $GITHUB_OUTPUT
|
||||
run: echo "latest_release=$(git branch -r | grep -E 'release/v[0-9]+\.[0-9]+\.[0-9]+$' | sort -V | tail -n 1 | sed 's/ origin\///')" >> $GITHUB_OUTPUT
|
||||
build:
|
||||
needs: [get_release,matrix_prep]
|
||||
strategy:
|
||||
@@ -54,15 +54,33 @@ jobs:
|
||||
override: true
|
||||
components: rustfmt, clippy
|
||||
|
||||
- name: Check formatting
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: fmt
|
||||
args: --all -- --check
|
||||
|
||||
- name: Build all binaries
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: build
|
||||
args: --workspace
|
||||
|
||||
- name: Reclaim some disk space (because Windows is being annoying)
|
||||
- name: Reclaim some disk space
|
||||
uses: actions-rs/cargo@v1
|
||||
if: ${{ matrix.os == 'windows-latest' }}
|
||||
if: ${{ matrix.os == 'windows-latest' || matrix.os == 'ubuntu-20.04' }}
|
||||
with:
|
||||
command: clean
|
||||
|
||||
- name: Build all examples
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: build
|
||||
args: --workspace --examples
|
||||
|
||||
- name: Reclaim some disk space
|
||||
uses: actions-rs/cargo@v1
|
||||
if: ${{ matrix.os == 'windows-latest' || matrix.os == 'ubuntu-20.04' }}
|
||||
with:
|
||||
command: clean
|
||||
|
||||
@@ -72,9 +90,9 @@ jobs:
|
||||
command: test
|
||||
args: --workspace
|
||||
|
||||
- name: Reclaim some disk space (because Windows is being annoying)
|
||||
- name: Reclaim some disk space
|
||||
uses: actions-rs/cargo@v1
|
||||
if: ${{ matrix.os == 'windows-latest' }}
|
||||
if: ${{ matrix.os == 'windows-latest' || matrix.os == 'ubuntu-20.04' }}
|
||||
with:
|
||||
command: clean
|
||||
|
||||
@@ -83,17 +101,11 @@ jobs:
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: test
|
||||
args: --workspace --all-features -- --ignored
|
||||
args: --workspace -- --ignored
|
||||
|
||||
- name: Check formatting
|
||||
- name: Reclaim some disk space
|
||||
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' }}
|
||||
if: ${{ matrix.os == 'windows-latest' || matrix.os == 'ubuntu-20.04' }}
|
||||
with:
|
||||
command: clean
|
||||
|
||||
@@ -102,7 +114,7 @@ jobs:
|
||||
continue-on-error: true
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
args: --all-features
|
||||
args: --workspace
|
||||
|
||||
- name: Run clippy
|
||||
uses: actions-rs/cargo@v1
|
||||
@@ -156,11 +168,11 @@ jobs:
|
||||
if: env.WORKFLOW_CONCLUSION == 'failure'
|
||||
with:
|
||||
node-version: 16
|
||||
- name: Keybase - Node Install
|
||||
- name: Matrix - Node Install
|
||||
if: env.WORKFLOW_CONCLUSION == 'failure'
|
||||
run: npm install
|
||||
working-directory: .github/workflows/support-files
|
||||
- name: Keybase - Send Notification
|
||||
- name: Matrix - Send Notification
|
||||
if: env.WORKFLOW_CONCLUSION == 'failure'
|
||||
env:
|
||||
NYM_NOTIFICATION_KIND: nightly
|
||||
@@ -168,13 +180,9 @@ jobs:
|
||||
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
|
||||
GIT_COMMIT_MESSAGE: "${{ github.event.head_commit.message }}"
|
||||
GIT_BRANCH_NAME: "${{needs.get_release.outputs.output1}}"
|
||||
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-release"
|
||||
IS_SUCCESS: "${{ env.WORKFLOW_CONCLUSION == 'success' }}"
|
||||
MATRIX_SERVER: "${{ secrets.MATRIX_SERVER }}"
|
||||
MATRIX_ROOM: "${{ secrets.MATRIX_ROOM }}"
|
||||
MATRIX_ROOM: "${{ secrets.MATRIX_ROOM_NIGHTLY }}"
|
||||
MATRIX_USER_ID: "${{ secrets.MATRIX_USER_ID }}"
|
||||
MATRIX_TOKEN: "${{ secrets.MATRIX_TOKEN }}"
|
||||
MATRIX_DEVICE_ID: "${{ secrets.MATRIX_DEVICE_ID }}"
|
||||
|
||||
@@ -28,7 +28,7 @@ jobs:
|
||||
run: git fetch --all
|
||||
- name: Set output variable to latest release branch
|
||||
id: step2
|
||||
run: echo "latest_release=$(git branch -r | grep -E 'release/v[0-9]+\.[0-9]+\.[0-9]+' | tail -n 2 | head -n 1 | sed 's/ origin\///')" >> $GITHUB_OUTPUT
|
||||
run: echo "latest_release=$(git branch -r | grep -E 'release/v[0-9]+\.[0-9]+\.[0-9]+$' | sort -V | tail -n 2 | head -n 1 | sed 's/ origin\///')" >> $GITHUB_OUTPUT
|
||||
build:
|
||||
needs: [get_release,matrix_prep]
|
||||
strategy:
|
||||
@@ -54,6 +54,12 @@ jobs:
|
||||
override: true
|
||||
components: rustfmt, clippy
|
||||
|
||||
- name: Check formatting
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: fmt
|
||||
args: --all -- --check
|
||||
|
||||
- name: Build all binaries
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
@@ -66,6 +72,18 @@ jobs:
|
||||
with:
|
||||
command: clean
|
||||
|
||||
- name: Build all examples
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: build
|
||||
args: --workspace --examples
|
||||
|
||||
- name: Reclaim some disk space (because Windows is being annoying)
|
||||
uses: actions-rs/cargo@v1
|
||||
if: ${{ matrix.os == 'windows-latest' }}
|
||||
with:
|
||||
command: clean
|
||||
|
||||
- name: Run all tests
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
@@ -74,7 +92,7 @@ jobs:
|
||||
|
||||
- name: Reclaim some disk space (because Windows is being annoying)
|
||||
uses: actions-rs/cargo@v1
|
||||
if: ${{ matrix.os == 'windows-latest' }}
|
||||
if: ${{ matrix.os == 'windows-latest' || matrix.os == 'ubuntu-20.04' }}
|
||||
with:
|
||||
command: clean
|
||||
|
||||
@@ -83,13 +101,7 @@ jobs:
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: test
|
||||
args: --workspace --all-features -- --ignored
|
||||
|
||||
- name: Check formatting
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: fmt
|
||||
args: --all -- --check
|
||||
args: --workspace -- --ignored
|
||||
|
||||
- name: Reclaim some disk space (because Windows is being annoying)
|
||||
uses: actions-rs/cargo@v1
|
||||
@@ -102,7 +114,7 @@ jobs:
|
||||
continue-on-error: true
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
args: --all-features
|
||||
args: --workspace
|
||||
|
||||
- name: Run clippy
|
||||
uses: actions-rs/cargo@v1
|
||||
@@ -156,11 +168,11 @@ jobs:
|
||||
if: env.WORKFLOW_CONCLUSION == 'failure'
|
||||
with:
|
||||
node-version: 16
|
||||
- name: Keybase - Node Install
|
||||
- name: Matrix - Node Install
|
||||
if: env.WORKFLOW_CONCLUSION == 'failure'
|
||||
run: npm install
|
||||
working-directory: .github/workflows/support-files
|
||||
- name: Keybase - Send Notification
|
||||
- name: Matrix - Send Notification
|
||||
if: env.WORKFLOW_CONCLUSION == 'failure'
|
||||
env:
|
||||
NYM_NOTIFICATION_KIND: nightly
|
||||
@@ -168,13 +180,9 @@ jobs:
|
||||
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
|
||||
GIT_COMMIT_MESSAGE: "${{ github.event.head_commit.message }}"
|
||||
GIT_BRANCH_NAME: "${{needs.get_release.outputs.output1}}"
|
||||
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-release"
|
||||
IS_SUCCESS: "${{ env.WORKFLOW_CONCLUSION == 'success' }}"
|
||||
MATRIX_SERVER: "${{ secrets.MATRIX_SERVER }}"
|
||||
MATRIX_ROOM: "${{ secrets.MATRIX_ROOM }}"
|
||||
MATRIX_ROOM: "${{ secrets.MATRIX_ROOM_NIGHTLY }}"
|
||||
MATRIX_USER_ID: "${{ secrets.MATRIX_USER_ID }}"
|
||||
MATRIX_TOKEN: "${{ secrets.MATRIX_TOKEN }}"
|
||||
MATRIX_DEVICE_ID: "${{ secrets.MATRIX_DEVICE_ID }}"
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
name: Publish Nym CLI binaries
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
release:
|
||||
types: [created]
|
||||
|
||||
env:
|
||||
NETWORK: mainnet
|
||||
|
||||
jobs:
|
||||
publish-nym-cli:
|
||||
if: ${{ startsWith(github.ref, 'refs/tags/nym-cli-') && (github.event_name == 'release' || github.event_name = 'workflow_dispatch') }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform: [ubuntu-20.04, windows-latest, macos-latest]
|
||||
|
||||
runs-on: ${{ matrix.platform }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Check the release tag starts with `nym-cli-`
|
||||
uses: actions/github-script@v3
|
||||
with:
|
||||
script: |
|
||||
core.setFailed('Release tag did not start with nym-cli-...')
|
||||
|
||||
- name: Install Rust stable
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
|
||||
- name: Build binary
|
||||
run: make build-nym-cli
|
||||
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: nym-cli-${{ matrix.platform }}
|
||||
path: |
|
||||
target/release/nym-cli*
|
||||
retention-days: 30
|
||||
|
||||
- name: Upload to release based on tag name
|
||||
uses: softprops/action-gh-release@v1
|
||||
if: github.event_name == 'release'
|
||||
with:
|
||||
files: |
|
||||
target/release/nym-cli
|
||||
@@ -1,4 +1,4 @@
|
||||
name: Publish Nym Connect (MacOS)
|
||||
name: Publish Nym Connect - desktop (MacOS)
|
||||
on:
|
||||
workflow_dispatch:
|
||||
release:
|
||||
@@ -6,11 +6,11 @@ on:
|
||||
|
||||
defaults:
|
||||
run:
|
||||
working-directory: nym-connect
|
||||
working-directory: nym-connect/desktop
|
||||
|
||||
jobs:
|
||||
publish-tauri:
|
||||
if: ${{ startsWith(github.ref, 'refs/tags/nym-connect-') && github.event_name == 'release' }}
|
||||
if: ${{ (startsWith(github.ref, 'refs/tags/nym-connect-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
@@ -73,7 +73,7 @@ jobs:
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: nym-connect_1.0.0_x64.dmg
|
||||
path: nym-connect/target/release/bundle/dmg/nym-connect_1.0.0_x64.dmg
|
||||
path: nym-connect/desktop/target/release/bundle/dmg/nym-connect_1.0.0_x64.dmg
|
||||
retention-days: 30
|
||||
|
||||
- name: Clean up keychain
|
||||
@@ -86,5 +86,5 @@ jobs:
|
||||
if: github.event_name == 'release'
|
||||
with:
|
||||
files: |
|
||||
nym-connect/target/release/bundle/dmg/*.dmg
|
||||
nym-connect/target/release/bundle/macos/*.app.tar.gz*
|
||||
nym-connect/desktop/target/release/bundle/dmg/*.dmg
|
||||
nym-connect/desktop/target/release/bundle/macos/*.app.tar.gz*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
name: Publish Nym Connect (Ubuntu)
|
||||
name: Publish Nym Connect - desktop (Ubuntu)
|
||||
on:
|
||||
workflow_dispatch:
|
||||
release:
|
||||
@@ -6,11 +6,11 @@ on:
|
||||
|
||||
defaults:
|
||||
run:
|
||||
working-directory: nym-connect
|
||||
working-directory: nym-connect/desktop
|
||||
|
||||
jobs:
|
||||
publish-tauri:
|
||||
if: ${{ startsWith(github.ref, 'refs/tags/nym-connect-') && github.event_name == 'release' }}
|
||||
if: ${{ (startsWith(github.ref, 'refs/tags/nym-connect-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
@@ -53,7 +53,7 @@ jobs:
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: nym-connect.AppImage.tar.gz
|
||||
path: nym-connect/target/release/bundle/appimage/nym-connect_1.0.0_amd64.AppImage
|
||||
path: nym-connect/desktop/target/release/bundle/appimage/nym-connect_1.0.0_amd64.AppImage
|
||||
retention-days: 30
|
||||
|
||||
- name: Upload to release based on tag name
|
||||
@@ -61,5 +61,5 @@ jobs:
|
||||
if: github.event_name == 'release'
|
||||
with:
|
||||
files: |
|
||||
nym-connect/target/release/bundle/appimage/*.AppImage
|
||||
nym-connect/target/release/bundle/appimage/*.AppImage.tar.gz*
|
||||
nym-connect/desktop/target/release/bundle/appimage/*.AppImage
|
||||
nym-connect/desktop/target/release/bundle/appimage/*.AppImage.tar.gz*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
name: Publish Nym Connect (Windows 10)
|
||||
name: Publish Nym Connect - desktop (Windows 10)
|
||||
on:
|
||||
workflow_dispatch:
|
||||
release:
|
||||
@@ -6,11 +6,11 @@ on:
|
||||
|
||||
defaults:
|
||||
run:
|
||||
working-directory: nym-connect
|
||||
working-directory: nym-connect/desktop
|
||||
|
||||
jobs:
|
||||
publish-tauri:
|
||||
if: ${{ startsWith(github.ref, 'refs/tags/nym-connect-') && github.event_name == 'release' }}
|
||||
if: ${{ (startsWith(github.ref, 'refs/tags/nym-connect-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
@@ -56,7 +56,7 @@ jobs:
|
||||
encodedString: ${{ secrets.WALLET_ADMIN_ADDRESS }}
|
||||
|
||||
- name: Install app dependencies
|
||||
run: yarn
|
||||
run: yarn --network-timeout 100000
|
||||
|
||||
- name: Build and sign it
|
||||
env:
|
||||
@@ -72,7 +72,7 @@ jobs:
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: nym-connect_1.0.0_x64_en-US.msi
|
||||
path: nym-connect/target/release/bundle/msi/nym-connect_1.0.0_x64_en-US.msi
|
||||
path: nym-connect/desktop/target/release/bundle/msi/nym-connect_1.0.0_x64_en-US.msi
|
||||
retention-days: 30
|
||||
|
||||
- name: Upload to release based on tag name
|
||||
@@ -80,5 +80,5 @@ jobs:
|
||||
if: github.event_name == 'release'
|
||||
with:
|
||||
files: |
|
||||
nym-connect/target/release/bundle/msi/*.msi
|
||||
nym-connect/target/release/bundle/msi/*.msi.zip*
|
||||
nym-connect/desktop/target/release/bundle/msi/*.msi
|
||||
nym-connect/desktop/target/release/bundle/msi/*.msi.zip*
|
||||
|
||||
@@ -16,7 +16,7 @@ env:
|
||||
|
||||
jobs:
|
||||
publish-nym:
|
||||
if: ${{ startsWith(github.ref, 'refs/tags/nym-binaries-') && github.event_name == 'release' }}
|
||||
if: ${{ (startsWith(github.ref, 'refs/tags/nym-binaries-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
|
||||
@@ -10,7 +10,7 @@ defaults:
|
||||
|
||||
jobs:
|
||||
publish-tauri:
|
||||
if: ${{ startsWith(github.ref, 'refs/tags/nym-wallet-') && github.event_name == 'release' }}
|
||||
if: ${{ (startsWith(github.ref, 'refs/tags/nym-wallet-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
|
||||
@@ -9,7 +9,7 @@ defaults:
|
||||
|
||||
jobs:
|
||||
publish-tauri:
|
||||
if: ${{ startsWith(github.ref, 'refs/tags/nym-wallet-') && github.event_name == 'release' }}
|
||||
if: ${{ (startsWith(github.ref, 'refs/tags/nym-wallet-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
name: Publish Nym Wallet (Windows 10)
|
||||
on:
|
||||
workflow_dispatch:
|
||||
release:
|
||||
types: [created]
|
||||
|
||||
@@ -9,7 +10,7 @@ defaults:
|
||||
|
||||
jobs:
|
||||
publish-tauri:
|
||||
if: ${{ startsWith(github.ref, 'refs/tags/nym-wallet-') && github.event_name == 'release' }}
|
||||
if: ${{ (startsWith(github.ref, 'refs/tags/nym-wallet-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
@@ -55,7 +56,7 @@ jobs:
|
||||
encodedString: ${{ secrets.WALLET_ADMIN_ADDRESS }}
|
||||
|
||||
- name: Install app dependencies
|
||||
run: yarn
|
||||
run: yarn --network-timeout 100000
|
||||
|
||||
- name: Build and sign it
|
||||
env:
|
||||
@@ -67,8 +68,16 @@ jobs:
|
||||
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
|
||||
run: yarn build
|
||||
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: nym-wallet_1.0.0_x64_en-US.msi
|
||||
path: nym-wallet/target/release/bundle/msi/nym-wallet_1.*.msi
|
||||
retention-days: 30
|
||||
|
||||
- name: Upload to release based on tag name
|
||||
uses: softprops/action-gh-release@v1
|
||||
if: github.event_name == 'release'
|
||||
with:
|
||||
files: |
|
||||
nym-wallet/target/release/bundle/msi/*.msi
|
||||
|
||||
@@ -35,10 +35,10 @@ jobs:
|
||||
REMOTE_USER: ${{ secrets.CI_WWW_REMOTE_USER }}
|
||||
TARGET: ${{ secrets.CI_WWW_REMOTE_TARGET }}/wallet-${{ env.GITHUB_REF_SLUG }}
|
||||
EXCLUDE: "/dist/, /node_modules/"
|
||||
- name: Keybase - Node Install
|
||||
- name: Matrix - Node Install
|
||||
run: npm install
|
||||
working-directory: .github/workflows/support-files
|
||||
- name: Keybase - Send Notification
|
||||
- name: Matrix - Send Notification
|
||||
env:
|
||||
NYM_NOTIFICATION_KIND: nym-wallet
|
||||
NYM_PROJECT_NAME: "nym-wallet"
|
||||
@@ -46,10 +46,6 @@ jobs:
|
||||
NYM_CI_WWW_LOCATION: "wallet-${{ 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-nym-wallet"
|
||||
IS_SUCCESS: "${{ job.status == 'success' }}"
|
||||
MATRIX_SERVER: "${{ secrets.MATRIX_SERVER }}"
|
||||
MATRIX_ROOM: "${{ secrets.MATRIX_ROOM }}"
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
name: CI for Nym API Tests
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
paths:
|
||||
- "nym-api/**"
|
||||
|
||||
defaults:
|
||||
run:
|
||||
working-directory: nym-api/tests
|
||||
|
||||
jobs:
|
||||
test:
|
||||
name: nym-api tests
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Install npm
|
||||
run: npm install
|
||||
|
||||
- name: Node v18
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 18.1.0
|
||||
|
||||
- name: Install yarn
|
||||
run: yarn install
|
||||
|
||||
- name: Run yarn
|
||||
run: yarn
|
||||
|
||||
- name: Run tests
|
||||
run: yarn test:qa
|
||||
working-directory: nym-api/tests
|
||||
@@ -1,7 +1,3 @@
|
||||
KEYBASE_NYM_CHANNEL=
|
||||
KEYBASE_NYMBOT_USERNAME=
|
||||
KEYBASE_NYMBOT_PAPERKEY=
|
||||
|
||||
MATRIX_SERVER=
|
||||
MATRIX_ROOM=
|
||||
MATRIX_ROOM_OF_SHAME=
|
||||
@@ -39,4 +35,4 @@ NYM_CI_WWW_BASE=example.com
|
||||
# Nightly builds
|
||||
WORKFLOW_CONCLUSION=success
|
||||
|
||||
SHOW_DEBUG=true
|
||||
SHOW_DEBUG=true
|
||||
|
||||
@@ -4,7 +4,7 @@ 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.
|
||||
These scripts send CI notifications to Matrix by creating messages from templates and env vars passed from GitHub Actions.
|
||||
|
||||
### Adding notifications to a GitHub Action
|
||||
|
||||
@@ -19,10 +19,11 @@ jobs:
|
||||
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"
|
||||
MATRIX_SERVER: "${{ secrets.MATRIX_SERVER }}"
|
||||
MATRIX_ROOM: "${{ secrets.MATRIX_ROOM }}"
|
||||
MATRIX_USER_ID: "${{ secrets.MATRIX_USER_ID }}"
|
||||
MATRIX_TOKEN: "${{ secrets.MATRIX_TOKEN }}"
|
||||
MATRIX_DEVICE_ID: "${{ secrets.MATRIX_DEVICE_ID }}"
|
||||
IS_SUCCESS: "${{ job.status == 'success' }}"
|
||||
uses: docker://keybaseio/client:stable-node
|
||||
with:
|
||||
@@ -34,8 +35,8 @@ 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`
|
||||
- Matrix credentials, room 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
|
||||
|
||||
@@ -43,7 +44,7 @@ You will need:
|
||||
- Node 16 LTS
|
||||
- npm
|
||||
|
||||
Copy `.github/workflows/support-files/.env.example` to `.github/workflows/support-files/.env` and valid Keybase credentials.
|
||||
Copy `.github/workflows/support-files/.env.example` to `.github/workflows/support-files/.env` and valid Matrix credentials.
|
||||
|
||||
Then run `npm install` to get dependencies.
|
||||
|
||||
@@ -55,4 +56,4 @@ npm install
|
||||
cp .env.example .env
|
||||
vi .env
|
||||
npm run dev
|
||||
```
|
||||
```
|
||||
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
#
|
||||
# Basic usage:
|
||||
# ./git-merge-check origin/develop origin/release/v1.1.9
|
||||
#
|
||||
|
||||
set -x
|
||||
|
||||
set -o nounset
|
||||
set -o pipefail
|
||||
|
||||
# Start from branch ...
|
||||
branch1=$1
|
||||
|
||||
# ... and try to merge in
|
||||
branch2=$2
|
||||
|
||||
echo "Checking if $branch2 merges without conflicts into $branch1..."
|
||||
|
||||
git checkout -q $branch1 || exit 1
|
||||
|
||||
# There are two options here as far as I see on what we should check for. Either
|
||||
#
|
||||
# (A) check for CONFLICT in any file except whitelist (such as .lock files)
|
||||
# (B) check for "Automatic merge failed"
|
||||
#
|
||||
# Both of these options have drawbacks.
|
||||
#
|
||||
# The first (A) has the problem in that maybe we don't want to fail if the
|
||||
# changes can be automatically merged (duh), but at least we are not pestered
|
||||
# about constant lock file changes.
|
||||
# The second (B) has the problem that it's difficult to filter out automatic
|
||||
# merge fails for files we don't care about (.lock files).
|
||||
#
|
||||
# The ideal solution would be to check for automatic merge fails for files
|
||||
# except those on a whitelist (e.g. lock files).
|
||||
|
||||
# For now I choose to use (B) here, because I hope it might be less noisy
|
||||
|
||||
# Alternative A
|
||||
#output=$(git merge --no-commit --no-ff $branch2 | grep -v .lock)
|
||||
#merge_failed=$(echo $output | grep -v "CONFLICT")
|
||||
#return_code=$?
|
||||
|
||||
# Alternative B
|
||||
output=$(git merge --no-commit --no-ff $branch2)
|
||||
merge_failed=$(echo $output | grep -v "Automatic merge failed")
|
||||
return_code=$?
|
||||
|
||||
# Restore
|
||||
|
||||
git merge --abort
|
||||
git checkout -q -
|
||||
|
||||
if [ $return_code -eq 0 ]; then
|
||||
echo "Merge check success"
|
||||
else
|
||||
echo "Merge check failed"
|
||||
fi
|
||||
|
||||
exit $return_code
|
||||
@@ -1,9 +1,14 @@
|
||||
🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥
|
||||
> :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:
|
||||
```
|
||||
|
||||
@@ -1,10 +1,16 @@
|
||||
🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩
|
||||
> :rocket: {{ env.NYM_PROJECT_NAME }} ➡️➡️➡️➡️➡️ **View output:** https://{{ env.NYM_CI_WWW_LOCATION }}.{{ env.NYM_CI_WWW_BASE }}/
|
||||
>
|
||||
> `storybook`: https://{{ env.NYM_CI_WWW_LOCATION_STORYBOOK }}.{{ env.NYM_CI_WWW_BASE }}
|
||||
>
|
||||
> ✅ **SUCCESS**
|
||||
>
|
||||
> `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 }}:
|
||||
```
|
||||
|
||||
@@ -151,7 +151,7 @@ async function getMessageBody(context) {
|
||||
return `${icon} ${job.conclusion}: ${job.name} - ${job.html_url}`;
|
||||
})
|
||||
// and join with newlines for display in the template
|
||||
.join('\n');
|
||||
.join('\n\n');
|
||||
|
||||
return template({ ...context, jobResults });
|
||||
}
|
||||
|
||||
@@ -1,9 +1,15 @@
|
||||
🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥
|
||||
> :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 +1,15 @@
|
||||
🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩
|
||||
> :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 }}
|
||||
{{ jobResults }}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
require('dotenv').config();
|
||||
|
||||
const Bot = require('keybase-bot');
|
||||
const { sendMatrixMessage } = require('./send_message_to_matrix');
|
||||
|
||||
let context = {
|
||||
@@ -24,21 +23,6 @@ function validateContext() {
|
||||
'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',
|
||||
);
|
||||
}
|
||||
if (context.env.MATRIX_ROOM) {
|
||||
if (!context.env.MATRIX_SERVER) {
|
||||
throw new Error(
|
||||
@@ -84,12 +68,6 @@ function createTemplateContext() {
|
||||
|
||||
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)
|
||||
@@ -99,40 +77,6 @@ function createTemplateContext() {
|
||||
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: context.env.KEYBASE_NYMBOT_TEAM || '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
|
||||
@@ -169,7 +113,6 @@ async function main() {
|
||||
console.log(messageBody);
|
||||
console.log('-----------------------------------------');
|
||||
}
|
||||
await sendKeybaseMessage(messageBody);
|
||||
if(context.env.MATRIX_ROOM) {
|
||||
await sendMatrixMessage(context, messageBody, context.env.MATRIX_ROOM)
|
||||
}
|
||||
|
||||
@@ -5,12 +5,7 @@ const localStorage = new LocalStorage('./scratch');
|
||||
const {
|
||||
LocalStorageCryptoStore,
|
||||
} = require('matrix-js-sdk/lib/crypto/store/localStorage-crypto-store');
|
||||
|
||||
const vfile = require('to-vfile');
|
||||
const unified = require('unified');
|
||||
const remarkParse = require('remark-parse');
|
||||
const remarkHtml = require('remark-html');
|
||||
const emoji = require('remark-emoji');
|
||||
var showdown = require('showdown');
|
||||
|
||||
// hide all matrix client output
|
||||
console.error = (error) => console.log('❌ error: ', error);
|
||||
@@ -59,17 +54,9 @@ function createClient(context, room, message) {
|
||||
return client;
|
||||
}
|
||||
|
||||
async function markdownToHtml(messageAsMarkdown) {
|
||||
const file = await unified()
|
||||
.use(emoji)
|
||||
.use(remarkParse)
|
||||
.use(remarkHtml)
|
||||
.process(await vfile({ path: 'test.md', contents: messageAsMarkdown}));
|
||||
return String(file);
|
||||
}
|
||||
|
||||
async function sendMatrixMessage(contextArg, messageAsMarkdown, roomId) {
|
||||
const messageAsHtml = await markdownToHtml(messageAsMarkdown);
|
||||
const converter = new showdown.Converter();
|
||||
const messageAsHtml = converter.makeHtml(messageAsMarkdown);
|
||||
const client = createClient(contextArg, roomId, messageAsHtml);
|
||||
await client.initCrypto();
|
||||
await client.startClient({ initialSyncLimit: 1 });
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥
|
||||
> :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:
|
||||
```
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩
|
||||
> :rocket: {{ env.NYM_PROJECT_NAME }} ➡️➡️➡️➡️➡️ **View storybook:** https://{{ env.NYM_CI_WWW_LOCATION }}.{{ env.NYM_CI_WWW_BASE }}/
|
||||
>
|
||||
> ✅ **SUCCESS**
|
||||
>
|
||||
> `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 }}:
|
||||
```
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥
|
||||
> :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:
|
||||
```
|
||||
|
||||
@@ -1,13 +1,18 @@
|
||||
🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩
|
||||
> :rocket: {{ env.NYM_PROJECT_NAME }}
|
||||
>
|
||||
> ✅ **SUCCESS**
|
||||
|
||||
>
|
||||
> ➡️➡️➡️➡️➡️ **View output:**
|
||||
>
|
||||
> `storybook`: https://{{ env.NYM_CI_WWW_LOCATION }}.{{ 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 }}:
|
||||
```
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "send-keybase-message",
|
||||
"description": "Sends a notification message with the keybase package that fails when piped into the keybase CLI",
|
||||
"name": "send-matrix-message",
|
||||
"description": "Sends a notification message with the matrix sdk",
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
@@ -10,7 +10,6 @@
|
||||
"dependencies": {
|
||||
"dotenv": "^16.0.0",
|
||||
"handlebars": "^4.7.7",
|
||||
"keybase-bot": "^3.6.1",
|
||||
"matrix-js-sdk": "^9.3.0",
|
||||
"node-localstorage": "^2.1.6",
|
||||
"octokit": "^1.7.1",
|
||||
@@ -18,6 +17,7 @@
|
||||
"remark-emoji": "^2.2.0",
|
||||
"remark-html": "^13.0.2",
|
||||
"remark-parse": "^9.0.0",
|
||||
"showdown": "^2.1.0",
|
||||
"to-vfile": "^6.1.0",
|
||||
"unified": "^9.2.2"
|
||||
},
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥
|
||||
> :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:
|
||||
```
|
||||
|
||||
@@ -1,14 +1,20 @@
|
||||
🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩
|
||||
> :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 }}:
|
||||
```
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
name: tag-and-release
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
nym_binaries_version:
|
||||
description: 'Version of the nym-binaries tag'
|
||||
required: false
|
||||
type: string
|
||||
nym_wallet_version:
|
||||
description: 'Version of the nym-wallet tag'
|
||||
required: false
|
||||
type: string
|
||||
nym_connect_version:
|
||||
description: 'Version of the nym-connect tag'
|
||||
required: false
|
||||
type: string
|
||||
|
||||
jobs:
|
||||
tag-components:
|
||||
uses: nymtech/reusable-workflows/.github/workflows/tag-components.yml@master
|
||||
with:
|
||||
nym_binaries_version: ${{ input.nym_binaries_version }}
|
||||
nym_wallet_version: ${{ input.nym_wallet_version }}
|
||||
nym_connect_version: ${{ input.nym_connect_version }}
|
||||
|
||||
create-nym-binaries-release:
|
||||
if: ${{ input.nym_binaries_version }}
|
||||
uses: nymtech/reusable-workflows/.github/workflows/create-binaries-release.yml@master
|
||||
with:
|
||||
version: ${{ input.nym_binaries_version }}
|
||||
needs: ["tag-components"]
|
||||
|
||||
create-nym-wallet-release:
|
||||
if: ${{ input.nym_wallet_version }}
|
||||
uses: nymtech/reusable-workflows/.github/workflows/create-wallet-release.yml@master
|
||||
with:
|
||||
version: ${{ input.nym_wallet_version }}
|
||||
needs: ["tag-components"]
|
||||
|
||||
create-nym-connect-release:
|
||||
if: ${{ input.nym_connect_version }}
|
||||
uses: nymtech/reusable-workflows/.github/workflows/create-connect-release.yml@master
|
||||
with:
|
||||
version: ${{ input.nym_connect_version }}
|
||||
needs: ["tag-components"]
|
||||
@@ -5,9 +5,22 @@ on:
|
||||
paths:
|
||||
- 'ts-packages/**'
|
||||
- 'sdk/typescript/**'
|
||||
- nym-connect
|
||||
- nym-connect-android
|
||||
- nym-wallet
|
||||
- 'nym-connect/desktop/src/**'
|
||||
- 'nym-connect/desktop/package.json'
|
||||
- 'nym-connect/mobile/src/**'
|
||||
- 'nym-connect/mobile/package.json'
|
||||
- 'nym-wallet/src/**'
|
||||
- 'nym-wallet/package.json'
|
||||
pull_request:
|
||||
paths:
|
||||
- 'ts-packages/**'
|
||||
- 'sdk/typescript/**'
|
||||
- 'nym-connect/desktop/src/**'
|
||||
- 'nym-connect/desktop/package.json'
|
||||
- 'nym-connect/mobile/src/**'
|
||||
- 'nym-connect/mobile/package.json'
|
||||
- 'nym-wallet/src/**'
|
||||
- 'nym-wallet/package.json'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
@@ -23,12 +36,16 @@ jobs:
|
||||
node-version: 16
|
||||
- name: Setup yarn
|
||||
run: npm install -g yarn
|
||||
- name: Install
|
||||
run: yarn
|
||||
- name: Build packages
|
||||
run: yarn build
|
||||
- name: Lint
|
||||
run: yarn && yarn lint && yarn tsc
|
||||
- name: Keybase - Node Install
|
||||
run: yarn lint && yarn tsc
|
||||
- name: Matrix - Node Install
|
||||
run: npm install
|
||||
working-directory: .github/workflows/support-files
|
||||
- name: Keybase - Send Notification
|
||||
- name: Matrix - Send Notification
|
||||
env:
|
||||
NYM_NOTIFICATION_KIND: ts-packages
|
||||
NYM_PROJECT_NAME: "ts-packages"
|
||||
@@ -36,10 +53,6 @@ jobs:
|
||||
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' }}"
|
||||
MATRIX_SERVER: "${{ secrets.MATRIX_SERVER }}"
|
||||
MATRIX_ROOM: "${{ secrets.MATRIX_ROOM }}"
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
name: update-versions-and-changelog
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
release_version:
|
||||
description: "Release version, usually the milestone title"
|
||||
required: true
|
||||
type: string
|
||||
milestone_id:
|
||||
description: "Milestone ID, check the URL when you're on the specific milestone page"
|
||||
required: true
|
||||
type: string
|
||||
|
||||
env:
|
||||
CI_BOT_AUTHOR: "Nym bot"
|
||||
CI_BOT_EMAIL: "nym-bot@users.noreply.github.com"
|
||||
|
||||
jobs:
|
||||
update-versions:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: checkout-source
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
ref: "release/${{ inputs.release_version }}"
|
||||
path: "nym"
|
||||
|
||||
- name: checkout-ci-tools-repo
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
repository: "nymtech/ci-tools"
|
||||
ref: "master"
|
||||
path: "ci-tools"
|
||||
token: "${{ secrets.ACCESS_TOKEN_PRIVATE_REPOS }}"
|
||||
|
||||
- name: Install Rust stable
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
|
||||
- name: install-version-bumper
|
||||
run: "cargo install --path ."
|
||||
working-directory: "ci-tools/version-bumper"
|
||||
|
||||
- name: run-version-bumper
|
||||
run: "version-bumper bump binaries --nym-repo-directory nym"
|
||||
|
||||
- name: push-changes-to-branch
|
||||
run: |
|
||||
git config --global user.name "${{ env.CI_BOT_AUTHOR }}"
|
||||
git config --global user.email "${{ env.CI_BOT_EMAIL }}"
|
||||
git checkout -b release/${{ inputs.release_version }}-preparation
|
||||
git commit -am "chore: version bump in preparation for release"
|
||||
git push -u origin release/${{ inputs.release_version }}-preparation
|
||||
working-directory: "nym"
|
||||
|
||||
update-changelog:
|
||||
runs-on: ubuntu-22.04
|
||||
needs: [update-versions]
|
||||
steps:
|
||||
- name: checkout-source
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
ref: "release/${{ inputs.release_version }}"
|
||||
path: "nym"
|
||||
|
||||
- name: checkout-ci-tools-repo
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
repository: "nymtech/ci-tools"
|
||||
ref: "master"
|
||||
path: "ci-tools"
|
||||
token: "${{ secrets.ACCESS_TOKEN_PRIVATE_REPOS }}"
|
||||
|
||||
- name: Install Rust stable
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
|
||||
- name: install-changelog-updater
|
||||
run: "cargo install --path ."
|
||||
working-directory: "ci-tools/changelog-updater"
|
||||
|
||||
- name: run-changelog-updater
|
||||
run: "changelog-updater mix ${{ inputs.milestone_id }} release/${{ inputs.release_version }}"
|
||||
|
||||
- name: push-changes-to-branch
|
||||
run: |
|
||||
git config --global user.name "${{ env.CI_BOT_AUTHOR }}"
|
||||
git config --global user.email "${{ env.CI_BOT_EMAIL }}"
|
||||
git checkout release/${{ inputs.release_version }}-preparation
|
||||
git commit -am "chore: update changelog preparation for release"
|
||||
git push
|
||||
working-directory: "nym"
|
||||
+2
-1
@@ -42,4 +42,5 @@ envs/qwerty.env
|
||||
Cargo.lock
|
||||
nym-connect/Cargo.lock
|
||||
.parcel-cache
|
||||
.DS_Store
|
||||
**/.DS_Store
|
||||
cpu-cycles/libcpucycles/build
|
||||
+94
-16
@@ -2,22 +2,106 @@
|
||||
|
||||
Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
# [Unreleased]
|
||||
## [Unreleased]
|
||||
|
||||
## [v1.1.12] (2023-03-07)
|
||||
|
||||
- Fix generated docs for mixnet and vesting contract on docs.rs ([#3093])
|
||||
- Introduce a way of injecting topology into the client ([#3044])
|
||||
- Update mixnet TypeScript client methods #1 ([#2783])
|
||||
- Update tooltips for routing and average score ([#3133])
|
||||
- update selected service provider description style ([#3128])
|
||||
|
||||
[#3093]: https://github.com/nymtech/nym/issues/3093
|
||||
[#3044]: https://github.com/nymtech/nym/issues/3044
|
||||
[#2783]: https://github.com/nymtech/nym/issues/2783
|
||||
[#3133]: https://github.com/nymtech/nym/pull/3133
|
||||
[#3128]: https://github.com/nymtech/nym/pull/3128
|
||||
|
||||
## [v1.1.11] (2023-02-28)
|
||||
|
||||
- Fix empty dealer set loop ([#3105])
|
||||
- The nym-api db.sqlite is broken when trying to run against it it in `enabled-credentials-mode true` there is an ordering issue with migrations when using the credential binary to purchase bandwidth ([#3100])
|
||||
- Feature/latency based gateway selection ([#3081])
|
||||
- Fix the credential binary to handle transactions to sleep when in non-inProgress epochs ([#3057])
|
||||
- Publish mixnet contract to crates.io ([#1919])
|
||||
- Publish vesting contract to crates.io ([#1920])
|
||||
- Feature/update checker to use master ([#3097])
|
||||
- Feature/improve binary checks ([#3094])
|
||||
|
||||
[#3105]: https://github.com/nymtech/nym/issues/3105
|
||||
[#3100]: https://github.com/nymtech/nym/issues/3100
|
||||
[#3081]: https://github.com/nymtech/nym/pull/3081
|
||||
[#3057]: https://github.com/nymtech/nym/issues/3057
|
||||
[#1919]: https://github.com/nymtech/nym/issues/1919
|
||||
[#1920]: https://github.com/nymtech/nym/issues/1920
|
||||
[#3097]: https://github.com/nymtech/nym/pull/3097
|
||||
[#3094]: https://github.com/nymtech/nym/pull/3094
|
||||
|
||||
## [v1.1.10] (2023-02-21)
|
||||
|
||||
- Verloc listener causing mixnode unexpected shutdown ([#3038])
|
||||
- rust-sdk - update API following implementation experience with the network-requester ([#3001])
|
||||
- Prevent coconut deposits in incompatible states ([#2991])
|
||||
- Support unavailable signer within threshold ([#2987])
|
||||
- Implement DKG re-sharing ([#2935])
|
||||
- contracts: add nym prefix to mixnet and vesting contract packages ([#2855])
|
||||
- Introduce common interface for all service providers to allow obtaining information such as whether they're online, what binary version they're running, etc. ([#2758])
|
||||
- Add client functionality to nym-network-requester ([#1900])
|
||||
- nym-api: uptime rework ([#3053])
|
||||
- ci: update typescript-lint.yml ([#3035])
|
||||
- contracts: add nym prefix to mixnet and vesting contract packages ([#2855])
|
||||
|
||||
[#3038]: https://github.com/nymtech/nym/issues/3038
|
||||
[#3001]: https://github.com/nymtech/nym/issues/3001
|
||||
[#2991]: https://github.com/nymtech/nym/issues/2991
|
||||
[#2987]: https://github.com/nymtech/nym/issues/2987
|
||||
[#2935]: https://github.com/nymtech/nym/issues/2935
|
||||
[#2855]: https://github.com/nymtech/nym/pull/2855
|
||||
[#2758]: https://github.com/nymtech/nym/issues/2758
|
||||
[#1900]: https://github.com/nymtech/nym/issues/1900
|
||||
[#3053]: https://github.com/nymtech/nym/pull/3053
|
||||
[#3035]: https://github.com/nymtech/nym/pull/3035
|
||||
[#2855]: https://github.com/nymtech/nym/pull/2855
|
||||
|
||||
## [v1.1.9] (2023-02-07)
|
||||
|
||||
### Added
|
||||
|
||||
- dkg rerun from scratch and dkg-specific epochs ([#2839])
|
||||
- nym-sdk: add support for surb storage ([#2870])
|
||||
- nym-sdk: enable reply-SURBs by default ([#2874])
|
||||
- remove coconut feature and unify builds ([#2890])
|
||||
- Remove Coconut feature flag ([#2793])
|
||||
- Separate `nym-api` endpoints with values of "total-supply" and "circulating-supply" in `nym` ([#2964])
|
||||
|
||||
[#2839]: https://github.com/nymtech/nym/pull/2839
|
||||
[#2870]: https://github.com/nymtech/nym/pull/2870
|
||||
[#2874]: https://github.com/nymtech/nym/pull/2874
|
||||
[#2890]: https://github.com/nymtech/nym/pull/2890
|
||||
### Changed
|
||||
|
||||
# [v1.1.7] (2023-01-24)
|
||||
- native-client: is now capable of listening for requests on sockets different than `127.0.0.1` ([#2912]). This can be specified via `--host` flag during `init` or `run`. Alternatively a custom `host` can be set in `config.toml` file under `socket` section.
|
||||
- mixnode, gateway: fix unexpected shutdown on corrupted connection ([#2963])
|
||||
|
||||
[#2793]: https://github.com/nymtech/nym/issues/2793
|
||||
[#2912]: https://github.com/nymtech/nym/issues/2912
|
||||
[#2964]: https://github.com/nymtech/nym/issues/2964
|
||||
[#2963]: https://github.com/nymtech/nym/issues/3017
|
||||
|
||||
## [v1.1.8] (2023-01-31)
|
||||
|
||||
### Added
|
||||
|
||||
- Rust SDK - Support SURBS (anonymous send + storage) ([#2754])
|
||||
- dkg rerun from scratch and dkg-specific epochs ([#2810])
|
||||
- Rename `'initial_supply'` field to `'total_supply'` in the circulating supply endpoint ([#2931])
|
||||
- Circulating supply api endpoint (read the note inside before testing/deploying) ([#1902])
|
||||
|
||||
### Changed
|
||||
|
||||
- nym-api: an `--id` flag is now always explicitly required ([#2873])
|
||||
|
||||
[#2754]: https://github.com/nymtech/nym/issues/2754
|
||||
[#2810]: https://github.com/nymtech/nym/issues/2810
|
||||
[#2931]: https://github.com/nymtech/nym/issues/2931
|
||||
[#1902]: https://github.com/nymtech/nym/issues/1902
|
||||
[#2873]: https://github.com/nymtech/nym/issues/2873
|
||||
|
||||
|
||||
## [v1.1.7] (2023-01-24)
|
||||
|
||||
### Added
|
||||
|
||||
@@ -73,12 +157,6 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
|
||||
|
||||
### Added
|
||||
|
||||
### Changed
|
||||
|
||||
## [v1.1.5] (2023-01-10)
|
||||
|
||||
### Added
|
||||
|
||||
- socks5: send status message for service ready, and network-requester error response in https://github.com/nymtech/nym/pull/2715
|
||||
|
||||
### Changed
|
||||
|
||||
Generated
+848
-1000
File diff suppressed because it is too large
Load Diff
+18
-7
@@ -22,15 +22,13 @@ members = [
|
||||
"clients/native",
|
||||
"clients/native/websocket-requests",
|
||||
"clients/socks5",
|
||||
"common/bandwidth-claim-contract",
|
||||
"common/bin-common",
|
||||
"common/client-libs/gateway-client",
|
||||
"common/client-libs/mixnet-client",
|
||||
"common/client-libs/validator-client",
|
||||
"common/client-connections",
|
||||
"common/coconut-interface",
|
||||
"common/commands",
|
||||
"common/config",
|
||||
"common/build-information",
|
||||
"common/cosmwasm-smart-contracts/coconut-bandwidth-contract",
|
||||
"common/cosmwasm-smart-contracts/coconut-dkg",
|
||||
"common/cosmwasm-smart-contracts/contracts-common",
|
||||
@@ -42,11 +40,10 @@ members = [
|
||||
"common/credential-storage",
|
||||
"common/credentials",
|
||||
"common/crypto",
|
||||
"common/crypto/dkg",
|
||||
"common/dkg",
|
||||
"common/execute",
|
||||
"common/inclusion-probability",
|
||||
"common/ledger",
|
||||
"common/logging",
|
||||
"common/mixnode-common",
|
||||
"common/network-defaults",
|
||||
"common/nonexhaustive-delayqueue",
|
||||
@@ -69,13 +66,13 @@ members = [
|
||||
"common/topology",
|
||||
"common/types",
|
||||
"common/wasm-utils",
|
||||
"common/completions",
|
||||
"explorer-api",
|
||||
"gateway",
|
||||
"gateway/gateway-requests",
|
||||
"integrations/bity",
|
||||
"mixnode",
|
||||
"sdk/rust/nym-sdk",
|
||||
"service-providers/common",
|
||||
"service-providers/network-requester",
|
||||
"service-providers/network-statistics",
|
||||
"nym-api",
|
||||
@@ -96,13 +93,27 @@ default-members = [
|
||||
"explorer-api",
|
||||
]
|
||||
|
||||
exclude = ["explorer", "contracts", "clients/webassembly", "nym-wallet", "nym-connect", "nym-connect-android"]
|
||||
exclude = ["explorer", "contracts", "clients/webassembly", "nym-wallet", "nym-connect/mobile/src-tauri", "nym-connect/desktop"]
|
||||
|
||||
[workspace.package]
|
||||
authors = ["Nym Technologies SA"]
|
||||
repository = "https://github.com/nymtech/nym"
|
||||
homepage = "https://nymtech.net"
|
||||
documentation = "https://nymtech.net"
|
||||
edition = "2021"
|
||||
license = "Apache-2.0"
|
||||
|
||||
[workspace.dependencies]
|
||||
async-trait = "0.1.64"
|
||||
cfg-if = "1.0.0"
|
||||
dotenvy = "0.15.6"
|
||||
lazy_static = "1.4.0"
|
||||
log = "0.4"
|
||||
once_cell = "1.7.2"
|
||||
rand = "0.8.5"
|
||||
serde = "1.0.152"
|
||||
serde_json = "1.0.91"
|
||||
tap = "1.0.1"
|
||||
thiserror = "1.0.38"
|
||||
tokio = "1.24.1"
|
||||
url = "2.2"
|
||||
|
||||
@@ -1,13 +1,22 @@
|
||||
test: clippy-all cargo-test wasm fmt
|
||||
test-no-mobile: clippy-all-no-mobile cargo-test-no-mobile wasm fmt-no-mobile
|
||||
test-all: test cargo-test-expensive
|
||||
test-all-no-mobile: test-no-mobile cargo-test-expensive
|
||||
no-clippy: build cargo-test wasm fmt
|
||||
no-clippy-no-mobile: build-no-mobile cargo-test-no-mobile wasm fmt-no-mobile
|
||||
happy: fmt clippy-happy test
|
||||
clippy-all: clippy-main clippy-all-contracts clippy-all-wallet clippy-all-connect clippy-all-wasm-client
|
||||
clippy-happy: clippy-happy-main clippy-happy-contracts clippy-happy-wallet clippy-happy-connect
|
||||
cargo-test: test-main test-contracts test-wallet test-connect
|
||||
happy-no-mobile: fmt-no-mobile clippy-happy-no-mobile test-no-mobile
|
||||
clippy-all: clippy-all-no-mobile clippy-all-connect-mobile
|
||||
clippy-all-no-mobile: clippy-main clippy-main-examples clippy-all-contracts clippy-all-wallet clippy-all-connect clippy-all-wasm-client
|
||||
clippy-happy: clippy-happy-no-mobile clippy-happy-connect-mobile
|
||||
clippy-happy-no-mobile: clippy-happy-main clippy-happy-contracts clippy-happy-wallet clippy-happy-connect
|
||||
cargo-test: cargo-test-no-mobile test-connect-mobile
|
||||
cargo-test-no-mobile: test-main test-contracts test-wallet test-connect
|
||||
cargo-test-expensive: test-main-expensive test-contracts-expensive test-wallet-expensive test-connect-expensive
|
||||
build: build-contracts build-wallet build-main build-connect build-wasm-client
|
||||
fmt: fmt-main fmt-contracts fmt-wallet fmt-connect fmt-wasm-client
|
||||
build: build-no-mobile build-connect-mobile
|
||||
build-no-mobile: build-contracts build-wallet build-main build-main-examples build-connect build-wasm-client
|
||||
fmt: fmt-no-mobile fmt-connect-mobile
|
||||
fmt-no-mobile: fmt-main fmt-contracts fmt-wallet fmt-connect fmt-wasm-client
|
||||
|
||||
clippy-happy-main:
|
||||
cargo clippy
|
||||
@@ -19,11 +28,17 @@ clippy-happy-wallet:
|
||||
cargo clippy --manifest-path nym-wallet/Cargo.toml
|
||||
|
||||
clippy-happy-connect:
|
||||
cargo clippy --manifest-path nym-connect/Cargo.toml
|
||||
cargo clippy --manifest-path nym-connect/desktop/Cargo.toml
|
||||
|
||||
clippy-happy-connect-mobile:
|
||||
cargo clippy --manifest-path nym-connect/mobile/src-tauri/Cargo.toml
|
||||
|
||||
clippy-main:
|
||||
cargo clippy --workspace -- -D warnings
|
||||
|
||||
clippy-main-examples:
|
||||
cargo clippy --workspace --examples -- -D warnings
|
||||
|
||||
clippy-wasm:
|
||||
cargo clippy --manifest-path clients/webassembly/Cargo.toml --target wasm32-unknown-unknown --workspace -- -D warnings
|
||||
|
||||
@@ -35,7 +50,10 @@ clippy-all-wallet:
|
||||
cargo clippy --workspace --manifest-path nym-wallet/Cargo.toml --all-features -- -D warnings
|
||||
|
||||
clippy-all-connect:
|
||||
cargo clippy --workspace --manifest-path nym-connect/Cargo.toml --all-features -- -D warnings
|
||||
cargo clippy --workspace --manifest-path nym-connect/desktop/Cargo.toml --all-features -- -D warnings
|
||||
|
||||
clippy-all-connect-mobile:
|
||||
cargo clippy --workspace --manifest-path nym-connect/mobile/src-tauri/Cargo.toml --all-features -- -D warnings
|
||||
|
||||
clippy-all-wasm-client:
|
||||
cargo clippy --workspace --manifest-path clients/webassembly/Cargo.toml --all-features --target wasm32-unknown-unknown -- -D warnings
|
||||
@@ -59,14 +77,23 @@ test-wallet-expensive:
|
||||
cargo test --manifest-path nym-wallet/Cargo.toml --all-features -- --ignored
|
||||
|
||||
test-connect:
|
||||
cargo test --manifest-path nym-connect/Cargo.toml --all-features
|
||||
cargo test --manifest-path nym-connect/desktop/Cargo.toml --all-features
|
||||
|
||||
test-connect-expensive:
|
||||
cargo test --manifest-path nym-connect/Cargo.toml --all-features -- --ignored
|
||||
cargo test --manifest-path nym-connect/desktop/Cargo.toml --all-features -- --ignored
|
||||
|
||||
test-connect-mobile:
|
||||
cargo test --manifest-path nym-connect/mobile/src-tauri/Cargo.toml --all-features
|
||||
|
||||
test-connect-mobile-expensive:
|
||||
cargo test --manifest-path nym-connect/mobile/src-tauri/Cargo.toml --all-features -- --ignored
|
||||
|
||||
build-main:
|
||||
cargo build --workspace
|
||||
|
||||
build-main-examples:
|
||||
cargo build --workspace --examples
|
||||
|
||||
build-contracts:
|
||||
cargo build --manifest-path contracts/Cargo.toml --workspace
|
||||
|
||||
@@ -74,7 +101,10 @@ build-wallet:
|
||||
cargo build --manifest-path nym-wallet/Cargo.toml --workspace
|
||||
|
||||
build-connect:
|
||||
cargo build --manifest-path nym-connect/Cargo.toml --workspace
|
||||
cargo build --manifest-path nym-connect/desktop/Cargo.toml --workspace
|
||||
|
||||
build-connect-mobile:
|
||||
cargo build --manifest-path nym-connect/mobile/src-tauri/Cargo.toml --workspace
|
||||
|
||||
build-explorer-api:
|
||||
cargo build --manifest-path explorer-api/Cargo.toml --workspace
|
||||
@@ -95,13 +125,18 @@ fmt-wallet:
|
||||
cargo fmt --manifest-path nym-wallet/Cargo.toml --all
|
||||
|
||||
fmt-connect:
|
||||
cargo fmt --manifest-path nym-connect/Cargo.toml --all
|
||||
cargo fmt --manifest-path nym-connect/desktop/Cargo.toml --all
|
||||
|
||||
fmt-connect-mobile:
|
||||
cargo fmt --manifest-path nym-connect/mobile/src-tauri/Cargo.toml --all
|
||||
|
||||
fmt-wasm-client:
|
||||
cargo fmt --manifest-path clients/webassembly/Cargo.toml --all
|
||||
|
||||
wasm:
|
||||
RUSTFLAGS='-C link-arg=-s' cargo build --manifest-path contracts/Cargo.toml --release --target wasm32-unknown-unknown
|
||||
wasm-opt -Os contracts/target/wasm32-unknown-unknown/release/vesting_contract.wasm -o contracts/target/wasm32-unknown-unknown/release/vesting_contract.wasm
|
||||
wasm-opt -Os contracts/target/wasm32-unknown-unknown/release/mixnet_contract.wasm -o contracts/target/wasm32-unknown-unknown/release/mixnet_contract.wasm
|
||||
|
||||
mixnet-opt: wasm
|
||||
cd contracts/mixnet && make opt
|
||||
@@ -110,5 +145,5 @@ generate-typescript:
|
||||
cd tools/ts-rs-cli && cargo run && cd ../..
|
||||
yarn types:lint:fix
|
||||
|
||||
run-validator-tests:
|
||||
cd nym-api/tests/functional_test && yarn test:qa
|
||||
run-api-tests:
|
||||
cd nym-api/tests/functional_test && yarn test:qa
|
||||
|
||||
@@ -16,7 +16,7 @@ The platform is composed of multiple Rust crates. Top-level executable binary cr
|
||||
* nym-wallet - a desktop wallet implemented using the [Tauri](https://tauri.studio/en/docs/about/intro) framework.
|
||||
|
||||
[](https://opensource.org/licenses/Apache-2.0)
|
||||
[](https://github.com/nymtech/nym/actions?query=branch%3Adevelop)
|
||||
[](https://github.com/nymtech/nym/actions?query=branch%3Adevelop)
|
||||
|
||||
|
||||
### Building
|
||||
|
||||
Vendored
BIN
Binary file not shown.
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "client-core"
|
||||
version = "1.1.7"
|
||||
version = "1.1.12"
|
||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
|
||||
edition = "2021"
|
||||
rust-version = "1.66"
|
||||
@@ -8,7 +8,7 @@ rust-version = "1.66"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
async-trait = { version = "0.1.58" }
|
||||
async-trait = { workspace = true }
|
||||
dirs = "4.0"
|
||||
dashmap = "5.4.0"
|
||||
futures = "0.3"
|
||||
@@ -20,22 +20,26 @@ serde_json = "1.0.89"
|
||||
tap = "1.0.1"
|
||||
thiserror = "1.0.34"
|
||||
url = { version ="2.2", features = ["serde"] }
|
||||
tungstenite = { version = "0.13.0", default-features = false }
|
||||
tokio = { version = "1.24.1", features = ["macros"]}
|
||||
time = "0.3.17"
|
||||
|
||||
# internal
|
||||
config = { path = "../../common/config" }
|
||||
client-connections = { path = "../../common/client-connections" }
|
||||
crypto = { path = "../../common/crypto" }
|
||||
nym-config = { path = "../../common/config" }
|
||||
nym-crypto = { path = "../../common/crypto" }
|
||||
gateway-client = { path = "../../common/client-libs/gateway-client" }
|
||||
#gateway-client = { path = "../../common/client-libs/gateway-client", default-features = false, features = ["wasm", "coconut"] }
|
||||
gateway-requests = { path = "../../gateway/gateway-requests" }
|
||||
nonexhaustive-delayqueue = { path = "../../common/nonexhaustive-delayqueue" }
|
||||
nymsphinx = { path = "../../common/nymsphinx" }
|
||||
pemstore = { path = "../../common/pemstore" }
|
||||
topology = { path = "../../common/topology" }
|
||||
nym-nonexhaustive-delayqueue = { path = "../../common/nonexhaustive-delayqueue" }
|
||||
nym-sphinx = { path = "../../common/nymsphinx" }
|
||||
nym-pemstore = { path = "../../common/pemstore" }
|
||||
nym-topology = { path = "../../common/topology" }
|
||||
validator-client = { path = "../../common/client-libs/validator-client", default-features = false }
|
||||
task = { path = "../../common/task" }
|
||||
nym-task = { path = "../../common/task" }
|
||||
|
||||
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.validator-client]
|
||||
path = "../../common/client-libs/validator-client"
|
||||
features = ["nyxd-client"]
|
||||
|
||||
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.tokio-stream]
|
||||
version = "0.1.11"
|
||||
@@ -45,6 +49,9 @@ features = ["time"]
|
||||
version = "1.24.1"
|
||||
features = ["time"]
|
||||
|
||||
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.tokio-tungstenite]
|
||||
version = "0.14"
|
||||
|
||||
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.sqlx]
|
||||
version = "0.6.2"
|
||||
features = ["runtime-tokio-rustls", "sqlite", "macros", "migrate"]
|
||||
@@ -66,6 +73,7 @@ features = ["futures"]
|
||||
|
||||
[target."cfg(target_arch = \"wasm32\")".dependencies.wasm-utils]
|
||||
path = "../../common/wasm-utils"
|
||||
features = ["websocket"]
|
||||
|
||||
[target."cfg(target_arch = \"wasm32\")".dependencies.time]
|
||||
version = "0.3.17"
|
||||
|
||||
@@ -15,14 +15,13 @@ use crate::client::replies::reply_controller::{ReplyControllerReceiver, ReplyCon
|
||||
use crate::client::replies::reply_storage::{
|
||||
CombinedReplyStorage, PersistentReplyStorage, ReplyStorageBackend, SentReplyKeys,
|
||||
};
|
||||
use crate::client::topology_control::nym_api_provider::NymApiTopologyProvider;
|
||||
use crate::client::topology_control::{
|
||||
TopologyAccessor, TopologyRefresher, TopologyRefresherConfig,
|
||||
};
|
||||
use crate::config::{Config, DebugConfig, GatewayEndpointConfig};
|
||||
use crate::error::ClientCoreError;
|
||||
use crate::spawn_future;
|
||||
use client_connections::{ConnectionCommandReceiver, ConnectionCommandSender, LaneQueueLengths};
|
||||
use crypto::asymmetric::{encryption, identity};
|
||||
use futures::channel::mpsc;
|
||||
use gateway_client::bandwidth::BandwidthController;
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
@@ -32,15 +31,19 @@ use gateway_client::{
|
||||
MixnetMessageSender,
|
||||
};
|
||||
use log::{debug, info};
|
||||
use nymsphinx::acknowledgements::AckKey;
|
||||
use nymsphinx::addressing::clients::Recipient;
|
||||
use nymsphinx::addressing::nodes::NodeIdentity;
|
||||
use nymsphinx::receiver::ReconstructedMessage;
|
||||
use nym_crypto::asymmetric::{encryption, identity};
|
||||
use nym_sphinx::acknowledgements::AckKey;
|
||||
use nym_sphinx::addressing::clients::Recipient;
|
||||
use nym_sphinx::addressing::nodes::NodeIdentity;
|
||||
use nym_sphinx::receiver::ReconstructedMessage;
|
||||
use nym_task::connections::{ConnectionCommandReceiver, ConnectionCommandSender, LaneQueueLengths};
|
||||
use nym_task::{TaskClient, TaskManager};
|
||||
use nym_topology::provider_trait::TopologyProvider;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use tap::TapFallible;
|
||||
use task::{TaskClient, TaskManager};
|
||||
use url::Url;
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
use validator_client::nyxd::CosmWasmClient;
|
||||
|
||||
@@ -51,11 +54,22 @@ pub mod non_wasm_helpers;
|
||||
|
||||
pub mod helpers;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ClientInput {
|
||||
pub connection_command_sender: ConnectionCommandSender,
|
||||
pub input_sender: InputMessageSender,
|
||||
}
|
||||
|
||||
impl ClientInput {
|
||||
pub async fn send(
|
||||
&self,
|
||||
message: InputMessage,
|
||||
) -> Result<(), tokio::sync::mpsc::error::SendError<InputMessage>> {
|
||||
self.input_sender.send(message).await
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ClientOutput {
|
||||
pub received_buffer_request_sender: ReceivedBufferRequestSender,
|
||||
}
|
||||
@@ -79,6 +93,7 @@ impl ClientOutput {
|
||||
pub struct ClientState {
|
||||
pub shared_lane_queue_lengths: LaneQueueLengths,
|
||||
pub reply_controller_sender: ReplyControllerSender,
|
||||
pub topology_accessor: TopologyAccessor,
|
||||
}
|
||||
|
||||
pub enum ClientInputStatus {
|
||||
@@ -143,6 +158,7 @@ pub struct BaseClientBuilder<'a, B, C: Clone> {
|
||||
nym_api_endpoints: Vec<Url>,
|
||||
reply_storage_backend: B,
|
||||
|
||||
custom_topology_provider: Option<Box<dyn TopologyProvider>>,
|
||||
bandwidth_controller: Option<BandwidthController<C>>,
|
||||
key_manager: KeyManager,
|
||||
}
|
||||
@@ -166,6 +182,7 @@ where
|
||||
bandwidth_controller,
|
||||
reply_storage_backend,
|
||||
key_manager,
|
||||
custom_topology_provider: None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -184,11 +201,17 @@ where
|
||||
disabled_credentials: credentials_toggle.is_disabled(),
|
||||
nym_api_endpoints,
|
||||
reply_storage_backend,
|
||||
custom_topology_provider: None,
|
||||
bandwidth_controller,
|
||||
key_manager,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_topology_provider(mut self, provider: Box<dyn TopologyProvider>) -> Self {
|
||||
self.custom_topology_provider = Some(provider);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn as_mix_recipient(&self) -> Recipient {
|
||||
Recipient::new(
|
||||
*self.key_manager.identity_keypair().public_key(),
|
||||
@@ -293,7 +316,7 @@ where
|
||||
}
|
||||
let gateway_address = self.gateway_config.gateway_listener.clone();
|
||||
if gateway_address.is_empty() {
|
||||
return Err(ClientCoreError::GatwayAddressUnknown);
|
||||
return Err(ClientCoreError::GatewayAddressUnknown);
|
||||
}
|
||||
|
||||
let gateway_identity = identity::PublicKey::from_base58_string(gateway_id)
|
||||
@@ -303,6 +326,7 @@ where
|
||||
let shared_key = if self.key_manager.is_gateway_key_set() {
|
||||
Some(self.key_manager.gateway_shared_key())
|
||||
} else {
|
||||
log::info!("Gateway key not set! Will proceed anyway.");
|
||||
None
|
||||
};
|
||||
|
||||
@@ -329,25 +353,38 @@ where
|
||||
Ok(gateway_client)
|
||||
}
|
||||
|
||||
fn setup_topology_provider(
|
||||
custom_provider: Option<Box<dyn TopologyProvider>>,
|
||||
nym_api_urls: Vec<Url>,
|
||||
) -> Box<dyn TopologyProvider> {
|
||||
// if no custom provider was ... provided ..., create one using nym-api
|
||||
custom_provider.unwrap_or_else(|| {
|
||||
Box::new(NymApiTopologyProvider::new(
|
||||
nym_api_urls,
|
||||
env!("CARGO_PKG_VERSION").to_string(),
|
||||
))
|
||||
})
|
||||
}
|
||||
|
||||
// future responsible for periodically polling directory server and updating
|
||||
// the current global view of topology
|
||||
async fn start_topology_refresher(
|
||||
nym_api_urls: Vec<Url>,
|
||||
topology_provider: Box<dyn TopologyProvider>,
|
||||
refresh_rate: Duration,
|
||||
topology_accessor: TopologyAccessor,
|
||||
shutdown: TaskClient,
|
||||
) -> Result<(), ClientCoreError> {
|
||||
let topology_refresher_config = TopologyRefresherConfig::new(
|
||||
nym_api_urls,
|
||||
refresh_rate,
|
||||
env!("CARGO_PKG_VERSION").to_string(),
|
||||
let topology_refresher_config = TopologyRefresherConfig::new(refresh_rate);
|
||||
|
||||
let mut topology_refresher = TopologyRefresher::new(
|
||||
topology_refresher_config,
|
||||
topology_accessor,
|
||||
topology_provider,
|
||||
);
|
||||
let mut topology_refresher =
|
||||
TopologyRefresher::new(topology_refresher_config, topology_accessor);
|
||||
// before returning, block entire runtime to refresh the current network view so that any
|
||||
// components depending on topology would see a non-empty view
|
||||
info!("Obtaining initial network topology");
|
||||
topology_refresher.refresh().await;
|
||||
topology_refresher.try_refresh().await;
|
||||
|
||||
if let Err(err) = topology_refresher.ensure_topology_is_routable().await {
|
||||
log::error!(
|
||||
@@ -456,8 +493,12 @@ where
|
||||
)
|
||||
.await?;
|
||||
|
||||
let topology_provider = Self::setup_topology_provider(
|
||||
self.custom_topology_provider.take(),
|
||||
self.nym_api_endpoints,
|
||||
);
|
||||
Self::start_topology_refresher(
|
||||
self.nym_api_endpoints.clone(),
|
||||
topology_provider,
|
||||
self.debug_config.topology_refresh_rate,
|
||||
shared_topology_accessor.clone(),
|
||||
task_manager.subscribe(),
|
||||
@@ -518,7 +559,7 @@ where
|
||||
self.debug_config,
|
||||
self.key_manager.ack_key(),
|
||||
self_address,
|
||||
shared_topology_accessor,
|
||||
shared_topology_accessor.clone(),
|
||||
sphinx_message_sender,
|
||||
task_manager.subscribe(),
|
||||
);
|
||||
@@ -542,6 +583,7 @@ where
|
||||
client_state: ClientState {
|
||||
shared_lane_queue_lengths,
|
||||
reply_controller_sender,
|
||||
topology_accessor: shared_topology_accessor,
|
||||
},
|
||||
task_manager,
|
||||
})
|
||||
|
||||
@@ -7,11 +7,11 @@ use crate::spawn_future;
|
||||
use futures::task::{Context, Poll};
|
||||
use futures::{Future, Stream, StreamExt};
|
||||
use log::*;
|
||||
use nymsphinx::acknowledgements::AckKey;
|
||||
use nymsphinx::addressing::clients::Recipient;
|
||||
use nymsphinx::cover::generate_loop_cover_packet;
|
||||
use nymsphinx::params::PacketSize;
|
||||
use nymsphinx::utils::sample_poisson_duration;
|
||||
use nym_sphinx::acknowledgements::AckKey;
|
||||
use nym_sphinx::addressing::clients::Recipient;
|
||||
use nym_sphinx::cover::generate_loop_cover_packet;
|
||||
use nym_sphinx::params::PacketSize;
|
||||
use nym_sphinx::utils::sample_poisson_duration;
|
||||
use rand::{rngs::OsRng, CryptoRng, Rng};
|
||||
use std::pin::Pin;
|
||||
use std::sync::Arc;
|
||||
@@ -192,7 +192,7 @@ impl LoopCoverTrafficStream<OsRng> {
|
||||
// However it's still useful to alert the user that the gateway or the link to
|
||||
// the gateway can't keep up. Either due to insufficient bandwidth on the
|
||||
// client side, or that the gateway is overloaded.
|
||||
log::warn!("Failed to send sphinx packet - gateway or connection to gatway can't keep up");
|
||||
log::warn!("Failed to send sphinx packet - gateway or connection to gateway can't keep up");
|
||||
}
|
||||
TrySendError::Closed(_) => {
|
||||
log::warn!("Failed to send cover message - channel closed");
|
||||
@@ -213,7 +213,7 @@ impl LoopCoverTrafficStream<OsRng> {
|
||||
tokio::task::yield_now().await;
|
||||
}
|
||||
|
||||
pub fn start_with_shutdown(mut self, mut shutdown: task::TaskClient) {
|
||||
pub fn start_with_shutdown(mut self, mut shutdown: nym_task::TaskClient) {
|
||||
// we should set initial delay only when we actually start the stream
|
||||
let sampled =
|
||||
sample_poisson_duration(&mut self.rng, self.average_cover_message_sending_delay);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use client_connections::TransmissionLane;
|
||||
use nymsphinx::addressing::clients::Recipient;
|
||||
use nymsphinx::anonymous_replies::requests::AnonymousSenderTag;
|
||||
use nym_sphinx::addressing::clients::Recipient;
|
||||
use nym_sphinx::anonymous_replies::requests::AnonymousSenderTag;
|
||||
use nym_task::connections::TransmissionLane;
|
||||
|
||||
pub type InputMessageSender = tokio::sync::mpsc::Sender<InputMessage>;
|
||||
pub type InputMessageReceiver = tokio::sync::mpsc::Receiver<InputMessage>;
|
||||
@@ -77,4 +77,12 @@ impl InputMessage {
|
||||
lane,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn lane(&self) -> &TransmissionLane {
|
||||
match self {
|
||||
InputMessage::Regular { lane, .. }
|
||||
| InputMessage::Anonymous { lane, .. }
|
||||
| InputMessage::Reply { lane, .. } => lane,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::config::persistence::key_pathfinder::ClientKeyPathfinder;
|
||||
use crypto::asymmetric::{encryption, identity};
|
||||
use gateway_requests::registration::handshake::SharedKeys;
|
||||
use log::*;
|
||||
use nymsphinx::acknowledgements::AckKey;
|
||||
use nym_crypto::asymmetric::{encryption, identity};
|
||||
use nym_sphinx::acknowledgements::AckKey;
|
||||
use rand::{CryptoRng, RngCore};
|
||||
use std::io;
|
||||
use std::sync::Arc;
|
||||
@@ -72,17 +72,17 @@ impl KeyManager {
|
||||
/// Loads previously stored client keys from the disk.
|
||||
fn load_client_keys(client_pathfinder: &ClientKeyPathfinder) -> io::Result<Self> {
|
||||
let identity_keypair: identity::KeyPair =
|
||||
pemstore::load_keypair(&pemstore::KeyPairPath::new(
|
||||
nym_pemstore::load_keypair(&nym_pemstore::KeyPairPath::new(
|
||||
client_pathfinder.private_identity_key().to_owned(),
|
||||
client_pathfinder.public_identity_key().to_owned(),
|
||||
))?;
|
||||
let encryption_keypair: encryption::KeyPair =
|
||||
pemstore::load_keypair(&pemstore::KeyPairPath::new(
|
||||
nym_pemstore::load_keypair(&nym_pemstore::KeyPairPath::new(
|
||||
client_pathfinder.private_encryption_key().to_owned(),
|
||||
client_pathfinder.public_encryption_key().to_owned(),
|
||||
))?;
|
||||
|
||||
let ack_key: AckKey = pemstore::load_key(client_pathfinder.ack_key())?;
|
||||
let ack_key: AckKey = nym_pemstore::load_key(client_pathfinder.ack_key())?;
|
||||
|
||||
Ok(KeyManager {
|
||||
identity_keypair: Arc::new(identity_keypair),
|
||||
@@ -98,7 +98,7 @@ impl KeyManager {
|
||||
let mut key_manager = Self::load_client_keys(client_pathfinder)?;
|
||||
|
||||
let gateway_shared_key: SharedKeys =
|
||||
pemstore::load_key(client_pathfinder.gateway_shared_key())?;
|
||||
nym_pemstore::load_key(client_pathfinder.gateway_shared_key())?;
|
||||
|
||||
key_manager.gateway_shared_key = Some(Arc::new(gateway_shared_key));
|
||||
|
||||
@@ -113,7 +113,7 @@ impl KeyManager {
|
||||
let mut key_manager = Self::load_client_keys(client_pathfinder)?;
|
||||
|
||||
let gateway_shared_key: Result<SharedKeys, io::Error> =
|
||||
pemstore::load_key(client_pathfinder.gateway_shared_key());
|
||||
nym_pemstore::load_key(client_pathfinder.gateway_shared_key());
|
||||
|
||||
// It's ok if the gateway key was not found
|
||||
let gateway_shared_key = match gateway_shared_key {
|
||||
@@ -132,27 +132,27 @@ impl KeyManager {
|
||||
// it is done so for the consistency sake so that you wouldn't require an rng instance
|
||||
// during `load_keys` to generate the said key.
|
||||
pub fn store_keys(&self, client_pathfinder: &ClientKeyPathfinder) -> io::Result<()> {
|
||||
pemstore::store_keypair(
|
||||
nym_pemstore::store_keypair(
|
||||
self.identity_keypair.as_ref(),
|
||||
&pemstore::KeyPairPath::new(
|
||||
&nym_pemstore::KeyPairPath::new(
|
||||
client_pathfinder.private_identity_key().to_owned(),
|
||||
client_pathfinder.public_identity_key().to_owned(),
|
||||
),
|
||||
)?;
|
||||
pemstore::store_keypair(
|
||||
nym_pemstore::store_keypair(
|
||||
self.encryption_keypair.as_ref(),
|
||||
&pemstore::KeyPairPath::new(
|
||||
&nym_pemstore::KeyPairPath::new(
|
||||
client_pathfinder.private_encryption_key().to_owned(),
|
||||
client_pathfinder.public_encryption_key().to_owned(),
|
||||
),
|
||||
)?;
|
||||
|
||||
pemstore::store_key(self.ack_key.as_ref(), client_pathfinder.ack_key())?;
|
||||
nym_pemstore::store_key(self.ack_key.as_ref(), client_pathfinder.ack_key())?;
|
||||
|
||||
match self.gateway_shared_key.as_ref() {
|
||||
None => debug!("No gateway shared key available to store!"),
|
||||
Some(gate_key) => {
|
||||
pemstore::store_key(gate_key.as_ref(), client_pathfinder.gateway_shared_key())?
|
||||
nym_pemstore::store_key(gate_key.as_ref(), client_pathfinder.gateway_shared_key())?
|
||||
}
|
||||
}
|
||||
|
||||
@@ -168,7 +168,7 @@ impl KeyManager {
|
||||
))
|
||||
}
|
||||
Some(gate_key) => {
|
||||
pemstore::store_key(gate_key.as_ref(), client_pathfinder.gateway_shared_key())?
|
||||
nym_pemstore::store_key(gate_key.as_ref(), client_pathfinder.gateway_shared_key())?
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ use crate::spawn_future;
|
||||
use gateway_client::wasm_mockups::CosmWasmClient;
|
||||
use gateway_client::GatewayClient;
|
||||
use log::*;
|
||||
use nymsphinx::forwarding::packet::MixPacket;
|
||||
use nym_sphinx::forwarding::packet::MixPacket;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
use validator_client::nyxd::CosmWasmClient;
|
||||
|
||||
@@ -76,7 +76,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub fn start_with_shutdown(mut self, mut shutdown: task::TaskClient) {
|
||||
pub fn start_with_shutdown(mut self, mut shutdown: nym_task::TaskClient) {
|
||||
spawn_future(async move {
|
||||
debug!("Started MixTrafficController with graceful shutdown support");
|
||||
|
||||
|
||||
+2
-2
@@ -5,7 +5,7 @@ use super::action_controller::{AckActionSender, Action};
|
||||
use futures::StreamExt;
|
||||
use gateway_client::AcknowledgementReceiver;
|
||||
use log::*;
|
||||
use nymsphinx::{
|
||||
use nym_sphinx::{
|
||||
acknowledgements::{identifier::recover_identifier, AckKey},
|
||||
chunking::fragment::{FragmentIdentifier, COVER_FRAG_ID},
|
||||
};
|
||||
@@ -65,7 +65,7 @@ impl AcknowledgementListener {
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) async fn run_with_shutdown(&mut self, mut shutdown: task::TaskClient) {
|
||||
pub(super) async fn run_with_shutdown(&mut self, mut shutdown: nym_task::TaskClient) {
|
||||
debug!("Started AcknowledgementListener with graceful shutdown support");
|
||||
|
||||
while !shutdown.is_shutdown() {
|
||||
|
||||
+5
-5
@@ -6,9 +6,9 @@ use crate::client::real_messages_control::acknowledgement_control::Retransmissio
|
||||
use futures::channel::mpsc;
|
||||
use futures::StreamExt;
|
||||
use log::*;
|
||||
use nonexhaustive_delayqueue::{Expired, NonExhaustiveDelayQueue, QueueKey};
|
||||
use nymsphinx::chunking::fragment::FragmentIdentifier;
|
||||
use nymsphinx::Delay as SphinxDelay;
|
||||
use nym_nonexhaustive_delayqueue::{Expired, NonExhaustiveDelayQueue, QueueKey};
|
||||
use nym_sphinx::chunking::fragment::FragmentIdentifier;
|
||||
use nym_sphinx::Delay as SphinxDelay;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
@@ -216,7 +216,7 @@ impl ActionController {
|
||||
fn handle_expired_ack_timer(
|
||||
&mut self,
|
||||
expired_ack: Expired<FragmentIdentifier>,
|
||||
task_client: &mut task::TaskClient,
|
||||
task_client: &mut nym_task::TaskClient,
|
||||
) {
|
||||
// I'm honestly not sure how to handle it, because getting it means other things in our
|
||||
// system are already misbehaving. If we ever see this panic, then I guess we should worry
|
||||
@@ -260,7 +260,7 @@ impl ActionController {
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) async fn run_with_shutdown(&mut self, mut shutdown: task::TaskClient) {
|
||||
pub(super) async fn run_with_shutdown(&mut self, mut shutdown: nym_task::TaskClient) {
|
||||
debug!("Started ActionController with graceful shutdown support");
|
||||
|
||||
while !shutdown.is_shutdown() {
|
||||
|
||||
+4
-4
@@ -4,10 +4,10 @@
|
||||
use crate::client::inbound_messages::{InputMessage, InputMessageReceiver};
|
||||
use crate::client::real_messages_control::message_handler::MessageHandler;
|
||||
use crate::client::replies::reply_controller::ReplyControllerSender;
|
||||
use client_connections::TransmissionLane;
|
||||
use log::*;
|
||||
use nymsphinx::addressing::clients::Recipient;
|
||||
use nymsphinx::anonymous_replies::requests::AnonymousSenderTag;
|
||||
use nym_sphinx::addressing::clients::Recipient;
|
||||
use nym_sphinx::anonymous_replies::requests::AnonymousSenderTag;
|
||||
use nym_task::connections::TransmissionLane;
|
||||
use rand::{CryptoRng, Rng};
|
||||
|
||||
/// Module responsible for dealing with the received messages: splitting them, creating acknowledgements,
|
||||
@@ -109,7 +109,7 @@ where
|
||||
};
|
||||
}
|
||||
|
||||
pub(super) async fn run_with_shutdown(&mut self, mut shutdown: task::TaskClient) {
|
||||
pub(super) async fn run_with_shutdown(&mut self, mut shutdown: nym_task::TaskClient) {
|
||||
debug!("Started InputMessageListener with graceful shutdown support");
|
||||
|
||||
while !shutdown.is_shutdown() {
|
||||
|
||||
@@ -15,9 +15,9 @@ use action_controller::AckActionReceiver;
|
||||
use futures::channel::mpsc;
|
||||
use gateway_client::AcknowledgementReceiver;
|
||||
use log::*;
|
||||
use nymsphinx::anonymous_replies::requests::AnonymousSenderTag;
|
||||
use nymsphinx::params::PacketSize;
|
||||
use nymsphinx::{
|
||||
use nym_sphinx::anonymous_replies::requests::AnonymousSenderTag;
|
||||
use nym_sphinx::params::PacketSize;
|
||||
use nym_sphinx::{
|
||||
acknowledgements::AckKey,
|
||||
addressing::clients::Recipient,
|
||||
chunking::fragment::{Fragment, FragmentIdentifier},
|
||||
@@ -249,7 +249,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn start_with_shutdown(self, shutdown: task::TaskClient) {
|
||||
pub(super) fn start_with_shutdown(self, shutdown: nym_task::TaskClient) {
|
||||
let mut acknowledgement_listener = self.acknowledgement_listener;
|
||||
let mut input_message_listener = self.input_message_listener;
|
||||
let mut retransmission_request_listener = self.retransmission_request_listener;
|
||||
|
||||
+5
-5
@@ -9,12 +9,12 @@ use crate::client::real_messages_control::acknowledgement_control::PacketDestina
|
||||
use crate::client::real_messages_control::message_handler::{MessageHandler, PreparationError};
|
||||
use crate::client::real_messages_control::real_traffic_stream::RealMessage;
|
||||
use crate::client::replies::reply_controller::ReplyControllerSender;
|
||||
use client_connections::TransmissionLane;
|
||||
use futures::StreamExt;
|
||||
use log::*;
|
||||
use nymsphinx::addressing::clients::Recipient;
|
||||
use nymsphinx::chunking::fragment::Fragment;
|
||||
use nymsphinx::preparer::PreparedFragment;
|
||||
use nym_sphinx::addressing::clients::Recipient;
|
||||
use nym_sphinx::chunking::fragment::Fragment;
|
||||
use nym_sphinx::preparer::PreparedFragment;
|
||||
use nym_task::connections::TransmissionLane;
|
||||
use rand::{CryptoRng, Rng};
|
||||
use std::sync::{Arc, Weak};
|
||||
|
||||
@@ -137,7 +137,7 @@ where
|
||||
.await
|
||||
}
|
||||
|
||||
pub(super) async fn run_with_shutdown(&mut self, mut shutdown: task::TaskClient) {
|
||||
pub(super) async fn run_with_shutdown(&mut self, mut shutdown: nym_task::TaskClient) {
|
||||
debug!("Started RetransmissionRequestListener with graceful shutdown support");
|
||||
|
||||
while !shutdown.is_shutdown() {
|
||||
|
||||
+2
-2
@@ -5,7 +5,7 @@ use super::action_controller::{AckActionSender, Action};
|
||||
use super::SentPacketNotificationReceiver;
|
||||
use futures::StreamExt;
|
||||
use log::*;
|
||||
use nymsphinx::chunking::fragment::{FragmentIdentifier, COVER_FRAG_ID};
|
||||
use nym_sphinx::chunking::fragment::{FragmentIdentifier, COVER_FRAG_ID};
|
||||
|
||||
/// Module responsible for starting up retransmission timers.
|
||||
/// It is required because when we send our packet to the `real traffic stream` controlled
|
||||
@@ -37,7 +37,7 @@ impl SentNotificationListener {
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
pub(super) async fn run_with_shutdown(&mut self, mut shutdown: task::TaskClient) {
|
||||
pub(super) async fn run_with_shutdown(&mut self, mut shutdown: nym_task::TaskClient) {
|
||||
debug!("Started SentNotificationListener with graceful shutdown support");
|
||||
|
||||
while !shutdown.is_shutdown() {
|
||||
|
||||
@@ -8,23 +8,23 @@ use crate::client::real_messages_control::real_traffic_stream::{
|
||||
use crate::client::real_messages_control::{AckActionSender, Action};
|
||||
use crate::client::replies::reply_storage::{ReceivedReplySurbsMap, SentReplyKeys, UsedSenderTags};
|
||||
use crate::client::topology_control::{TopologyAccessor, TopologyReadPermit};
|
||||
use client_connections::TransmissionLane;
|
||||
use log::{debug, error, info, trace, warn};
|
||||
use nymsphinx::acknowledgements::AckKey;
|
||||
use nymsphinx::addressing::clients::Recipient;
|
||||
use nymsphinx::anonymous_replies::requests::{AnonymousSenderTag, RepliableMessage, ReplyMessage};
|
||||
use nymsphinx::anonymous_replies::{ReplySurb, SurbEncryptionKey};
|
||||
use nymsphinx::chunking::fragment::{Fragment, FragmentIdentifier};
|
||||
use nymsphinx::message::NymMessage;
|
||||
use nymsphinx::params::{PacketSize, DEFAULT_NUM_MIX_HOPS};
|
||||
use nymsphinx::preparer::{MessagePreparer, PreparedFragment};
|
||||
use nymsphinx::Delay;
|
||||
use nym_sphinx::acknowledgements::AckKey;
|
||||
use nym_sphinx::addressing::clients::Recipient;
|
||||
use nym_sphinx::anonymous_replies::requests::{AnonymousSenderTag, RepliableMessage, ReplyMessage};
|
||||
use nym_sphinx::anonymous_replies::{ReplySurb, SurbEncryptionKey};
|
||||
use nym_sphinx::chunking::fragment::{Fragment, FragmentIdentifier};
|
||||
use nym_sphinx::message::NymMessage;
|
||||
use nym_sphinx::params::{PacketSize, DEFAULT_NUM_MIX_HOPS};
|
||||
use nym_sphinx::preparer::{MessagePreparer, PreparedFragment};
|
||||
use nym_sphinx::Delay;
|
||||
use nym_task::connections::TransmissionLane;
|
||||
use nym_topology::{NymTopology, NymTopologyError};
|
||||
use rand::{CryptoRng, Rng};
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use thiserror::Error;
|
||||
use topology::{NymTopology, NymTopologyError};
|
||||
|
||||
// TODO: move that error elsewhere since it seems to be contaminating different files
|
||||
#[derive(Debug, Clone, Error)]
|
||||
|
||||
@@ -21,13 +21,13 @@ use crate::{
|
||||
},
|
||||
spawn_future,
|
||||
};
|
||||
use client_connections::{ConnectionCommandReceiver, LaneQueueLengths};
|
||||
use futures::channel::mpsc;
|
||||
use gateway_client::AcknowledgementReceiver;
|
||||
use log::*;
|
||||
use nymsphinx::acknowledgements::AckKey;
|
||||
use nymsphinx::addressing::clients::Recipient;
|
||||
use nymsphinx::params::PacketSize;
|
||||
use nym_sphinx::acknowledgements::AckKey;
|
||||
use nym_sphinx::addressing::clients::Recipient;
|
||||
use nym_sphinx::params::PacketSize;
|
||||
use nym_task::connections::{ConnectionCommandReceiver, LaneQueueLengths};
|
||||
use rand::{rngs::OsRng, CryptoRng, Rng};
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
@@ -270,7 +270,7 @@ impl RealMessagesController<OsRng> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn start_with_shutdown(self, shutdown: task::TaskClient) {
|
||||
pub fn start_with_shutdown(self, shutdown: nym_task::TaskClient) {
|
||||
let mut out_queue_control = self.out_queue_control;
|
||||
let ack_control = self.ack_control;
|
||||
let mut reply_control = self.reply_control;
|
||||
|
||||
@@ -6,20 +6,20 @@ use crate::client::mix_traffic::BatchMixMessageSender;
|
||||
use crate::client::real_messages_control::acknowledgement_control::SentPacketNotificationSender;
|
||||
use crate::client::topology_control::TopologyAccessor;
|
||||
use crate::client::transmission_buffer::TransmissionBuffer;
|
||||
use client_connections::{
|
||||
ConnectionCommand, ConnectionCommandReceiver, ConnectionId, LaneQueueLengths, TransmissionLane,
|
||||
};
|
||||
use futures::task::{Context, Poll};
|
||||
use futures::{Future, Stream, StreamExt};
|
||||
use log::*;
|
||||
use nymsphinx::acknowledgements::AckKey;
|
||||
use nymsphinx::addressing::clients::Recipient;
|
||||
use nymsphinx::chunking::fragment::FragmentIdentifier;
|
||||
use nymsphinx::cover::generate_loop_cover_packet;
|
||||
use nymsphinx::forwarding::packet::MixPacket;
|
||||
use nymsphinx::params::PacketSize;
|
||||
use nymsphinx::preparer::PreparedFragment;
|
||||
use nymsphinx::utils::sample_poisson_duration;
|
||||
use nym_sphinx::acknowledgements::AckKey;
|
||||
use nym_sphinx::addressing::clients::Recipient;
|
||||
use nym_sphinx::chunking::fragment::FragmentIdentifier;
|
||||
use nym_sphinx::cover::generate_loop_cover_packet;
|
||||
use nym_sphinx::forwarding::packet::MixPacket;
|
||||
use nym_sphinx::params::PacketSize;
|
||||
use nym_sphinx::preparer::PreparedFragment;
|
||||
use nym_sphinx::utils::sample_poisson_duration;
|
||||
use nym_task::connections::{
|
||||
ConnectionCommand, ConnectionCommandReceiver, ConnectionId, LaneQueueLengths, TransmissionLane,
|
||||
};
|
||||
use rand::{CryptoRng, Rng};
|
||||
use std::pin::Pin;
|
||||
use std::sync::Arc;
|
||||
@@ -342,7 +342,6 @@ where
|
||||
if let Poll::Ready(Some(id)) = Pin::new(&mut self.client_connection_rx).poll_next(cx) {
|
||||
match id {
|
||||
ConnectionCommand::Close(id) => self.on_close_connection(id),
|
||||
ConnectionCommand::ActiveConnections(_) => panic!(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -421,7 +420,6 @@ where
|
||||
if let Poll::Ready(Some(id)) = Pin::new(&mut self.client_connection_rx).poll_next(cx) {
|
||||
match id {
|
||||
ConnectionCommand::Close(id) => self.on_close_connection(id),
|
||||
ConnectionCommand::ActiveConnections(_) => panic!(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -462,7 +460,7 @@ where
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
fn log_status(&self, shutdown: &mut task::TaskClient) {
|
||||
fn log_status(&self, shutdown: &mut nym_task::TaskClient) {
|
||||
use crate::error::ClientCoreStatusMessage;
|
||||
|
||||
let packets = self.transmission_buffer.total_size();
|
||||
@@ -503,7 +501,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) async fn run_with_shutdown(&mut self, mut shutdown: task::TaskClient) {
|
||||
pub(super) async fn run_with_shutdown(&mut self, mut shutdown: nym_task::TaskClient) {
|
||||
debug!("Started OutQueueControl with graceful shutdown support");
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
|
||||
@@ -4,20 +4,20 @@
|
||||
use crate::client::replies::reply_controller::ReplyControllerSender;
|
||||
use crate::client::replies::reply_storage::SentReplyKeys;
|
||||
use crate::spawn_future;
|
||||
use crypto::asymmetric::encryption;
|
||||
use crypto::Digest;
|
||||
use futures::channel::mpsc;
|
||||
use futures::lock::Mutex;
|
||||
use futures::StreamExt;
|
||||
use gateway_client::MixnetMessageReceiver;
|
||||
use log::*;
|
||||
use nymsphinx::anonymous_replies::requests::{
|
||||
use nym_crypto::asymmetric::encryption;
|
||||
use nym_crypto::Digest;
|
||||
use nym_sphinx::anonymous_replies::requests::{
|
||||
RepliableMessage, RepliableMessageContent, ReplyMessage, ReplyMessageContent,
|
||||
};
|
||||
use nymsphinx::anonymous_replies::{encryption_key::EncryptionKeyDigest, SurbEncryptionKey};
|
||||
use nymsphinx::message::{NymMessage, PlainMessage};
|
||||
use nymsphinx::params::ReplySurbKeyDigestAlgorithm;
|
||||
use nymsphinx::receiver::{MessageReceiver, MessageRecoveryError, ReconstructedMessage};
|
||||
use nym_sphinx::anonymous_replies::{encryption_key::EncryptionKeyDigest, SurbEncryptionKey};
|
||||
use nym_sphinx::message::{NymMessage, PlainMessage};
|
||||
use nym_sphinx::params::ReplySurbKeyDigestAlgorithm;
|
||||
use nym_sphinx::receiver::{MessageReceiver, MessageRecoveryError, ReconstructedMessage};
|
||||
use std::collections::HashSet;
|
||||
use std::sync::Arc;
|
||||
|
||||
@@ -47,7 +47,7 @@ struct ReceivedMessagesBufferInner {
|
||||
|
||||
impl ReceivedMessagesBufferInner {
|
||||
fn recover_from_fragment(&mut self, fragment_data: &[u8]) -> Option<NymMessage> {
|
||||
if nymsphinx::cover::is_cover(fragment_data) {
|
||||
if nym_sphinx::cover::is_cover(fragment_data) {
|
||||
trace!("The message was a loop cover message! Skipping it");
|
||||
return None;
|
||||
}
|
||||
@@ -399,7 +399,7 @@ impl RequestReceiver {
|
||||
}
|
||||
}
|
||||
|
||||
async fn run_with_shutdown(&mut self, mut shutdown: task::TaskClient) {
|
||||
async fn run_with_shutdown(&mut self, mut shutdown: nym_task::TaskClient) {
|
||||
debug!("Started RequestReceiver with graceful shutdown support");
|
||||
while !shutdown.is_shutdown() {
|
||||
tokio::select! {
|
||||
@@ -438,7 +438,7 @@ impl FragmentedMessageReceiver {
|
||||
}
|
||||
}
|
||||
|
||||
async fn run_with_shutdown(&mut self, mut shutdown: task::TaskClient) {
|
||||
async fn run_with_shutdown(&mut self, mut shutdown: nym_task::TaskClient) {
|
||||
debug!("Started FragmentedMessageReceiver with graceful shutdown support");
|
||||
while !shutdown.is_shutdown() {
|
||||
tokio::select! {
|
||||
@@ -488,7 +488,7 @@ impl ReceivedMessagesBufferController {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn start_with_shutdown(self, shutdown: task::TaskClient) {
|
||||
pub fn start_with_shutdown(self, shutdown: nym_task::TaskClient) {
|
||||
let mut fragmented_message_receiver = self.fragmented_message_receiver;
|
||||
let mut request_receiver = self.request_receiver;
|
||||
|
||||
|
||||
@@ -4,14 +4,14 @@
|
||||
use crate::client::real_messages_control::acknowledgement_control::PendingAcknowledgement;
|
||||
use crate::client::real_messages_control::message_handler::{MessageHandler, PreparationError};
|
||||
use crate::client::replies::reply_storage::CombinedReplyStorage;
|
||||
use client_connections::{ConnectionId, TransmissionLane};
|
||||
use futures::channel::oneshot;
|
||||
use futures::StreamExt;
|
||||
use log::{debug, error, info, trace, warn};
|
||||
use nymsphinx::addressing::clients::Recipient;
|
||||
use nymsphinx::anonymous_replies::requests::AnonymousSenderTag;
|
||||
use nymsphinx::anonymous_replies::ReplySurb;
|
||||
use nymsphinx::chunking::fragment::{Fragment, FragmentIdentifier};
|
||||
use nym_sphinx::addressing::clients::Recipient;
|
||||
use nym_sphinx::anonymous_replies::requests::AnonymousSenderTag;
|
||||
use nym_sphinx::anonymous_replies::ReplySurb;
|
||||
use nym_sphinx::chunking::fragment::{Fragment, FragmentIdentifier};
|
||||
use nym_task::connections::{ConnectionId, TransmissionLane};
|
||||
use rand::{CryptoRng, Rng};
|
||||
use std::cmp::{max, min};
|
||||
use std::collections::btree_map::Entry;
|
||||
@@ -835,7 +835,7 @@ where
|
||||
// todo!()
|
||||
// }
|
||||
|
||||
pub(crate) async fn run_with_shutdown(&mut self, mut shutdown: task::TaskClient) {
|
||||
pub(crate) async fn run_with_shutdown(&mut self, mut shutdown: nym_task::TaskClient) {
|
||||
debug!("Started ReplyController with graceful shutdown support");
|
||||
|
||||
let polling_rate = Duration::from_secs(5);
|
||||
|
||||
@@ -2,12 +2,12 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::client::real_messages_control::acknowledgement_control::PendingAcknowledgement;
|
||||
use client_connections::{ConnectionId, TransmissionLane};
|
||||
use futures::channel::{mpsc, oneshot};
|
||||
use log::error;
|
||||
use nymsphinx::addressing::clients::Recipient;
|
||||
use nymsphinx::anonymous_replies::requests::AnonymousSenderTag;
|
||||
use nymsphinx::anonymous_replies::ReplySurb;
|
||||
use nym_sphinx::addressing::clients::Recipient;
|
||||
use nym_sphinx::anonymous_replies::requests::AnonymousSenderTag;
|
||||
use nym_sphinx::anonymous_replies::ReplySurb;
|
||||
use nym_task::connections::{ConnectionId, TransmissionLane};
|
||||
use std::sync::Weak;
|
||||
|
||||
pub(crate) fn new_control_channels() -> (ReplyControllerSender, ReplyControllerReceiver) {
|
||||
|
||||
@@ -5,6 +5,8 @@ use crate::client::replies::reply_storage::backend::Empty;
|
||||
use crate::client::replies::reply_storage::{CombinedReplyStorage, ReplyStorageBackend};
|
||||
use async_trait::async_trait;
|
||||
|
||||
use std::path::PathBuf;
|
||||
|
||||
// well, right now we don't have the browser storage : (
|
||||
// so we keep everything in memory
|
||||
#[derive(Debug)]
|
||||
@@ -27,6 +29,18 @@ impl Backend {
|
||||
impl ReplyStorageBackend for Backend {
|
||||
type StorageError = <Empty as ReplyStorageBackend>::StorageError;
|
||||
|
||||
async fn new(
|
||||
debug_config: &crate::config::DebugConfig,
|
||||
_db_path: Option<PathBuf>,
|
||||
) -> Result<Self, Self::StorageError> {
|
||||
Ok(Backend {
|
||||
empty: Empty {
|
||||
min_surb_threshold: debug_config.minimum_reply_surb_storage_threshold,
|
||||
max_surb_threshold: debug_config.maximum_reply_surb_storage_threshold,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
async fn flush_surb_storage(
|
||||
&mut self,
|
||||
storage: &CombinedReplyStorage,
|
||||
|
||||
@@ -56,4 +56,9 @@ pub enum StorageError {
|
||||
details: String,
|
||||
// err: Option<Box<dyn std::error::Error>>
|
||||
},
|
||||
|
||||
#[error("failed to create storage")]
|
||||
FailedToCreateStorage {
|
||||
source: Box<dyn std::error::Error + Send + Sync>,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::client::base_client::non_wasm_helpers;
|
||||
use crate::client::replies::reply_storage::backend::fs_backend::manager::StorageManager;
|
||||
use crate::client::replies::reply_storage::backend::fs_backend::models::{
|
||||
ReplySurbStorageMetadata, StoredReplyKey, StoredReplySurb, StoredSenderTag, StoredSurbSender,
|
||||
@@ -11,7 +12,7 @@ use crate::client::replies::reply_storage::{
|
||||
};
|
||||
use async_trait::async_trait;
|
||||
use log::{error, info, warn};
|
||||
use nymsphinx::anonymous_replies::requests::AnonymousSenderTag;
|
||||
use nym_sphinx::anonymous_replies::requests::AnonymousSenderTag;
|
||||
use std::fs;
|
||||
use std::path::{Path, PathBuf};
|
||||
use time::OffsetDateTime;
|
||||
@@ -154,18 +155,21 @@ impl Backend {
|
||||
// (assuming no key rotation has happened)
|
||||
// but the way it's currently coded, everyone will purge old data
|
||||
let since_last_flush = OffsetDateTime::now_utc() - last_flush;
|
||||
if since_last_flush.whole_days() > 0 {
|
||||
info!("it's been over {} days and {} hours since we last used our data store. our reply surbs are already outdated - we're going to purge them now.", since_last_flush.whole_days(), since_last_flush.whole_hours());
|
||||
let days = since_last_flush.whole_days();
|
||||
let hours = since_last_flush.whole_hours() % 24;
|
||||
|
||||
if days > 0 {
|
||||
info!("it's been over {days} days and {hours} hours since we last used our data store. our reply surbs are already outdated - we're going to purge them now.");
|
||||
manager.delete_all_reply_surb_data().await?;
|
||||
}
|
||||
|
||||
if since_last_flush.whole_days() > 1 {
|
||||
info!("it's been over {} days and {} hours since we last used our data store. our reply keys are already outdated - we're going to purge them now.", since_last_flush.whole_days(), since_last_flush.whole_hours());
|
||||
if days > 1 {
|
||||
info!("it's been over {days} days and {hours} hours since we last used our data store. our reply keys are already outdated - we're going to purge them now.");
|
||||
manager.delete_all_reply_keys().await?;
|
||||
}
|
||||
|
||||
if since_last_flush.whole_days() > 2 {
|
||||
info!("it's been over {} days and {} hours since we last used our data store. our used sender tags are already outdated - we're going to purge them now.", since_last_flush.whole_days(), since_last_flush.whole_hours());
|
||||
if days > 2 {
|
||||
info!("it's been over {days} days and {hours} hours since we last used our data store. our used sender tags are already outdated - we're going to purge them now.");
|
||||
manager.delete_all_tags().await?;
|
||||
}
|
||||
|
||||
@@ -367,6 +371,20 @@ impl Backend {
|
||||
impl ReplyStorageBackend for Backend {
|
||||
type StorageError = error::StorageError;
|
||||
|
||||
async fn new(
|
||||
debug_config: &crate::config::DebugConfig,
|
||||
db_path: Option<PathBuf>,
|
||||
) -> Result<Self, Self::StorageError> {
|
||||
non_wasm_helpers::setup_fs_reply_surb_backend(db_path, debug_config)
|
||||
.await
|
||||
.map_err(|err| {
|
||||
log::error!("Failed to create storage: {err}");
|
||||
Self::StorageError::FailedToCreateStorage {
|
||||
source: Box::new(err),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn is_active(&self) -> bool {
|
||||
self.manager.is_active()
|
||||
}
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
|
||||
use crate::client::replies::reply_storage::backend::fs_backend::error::StorageError;
|
||||
use crate::client::replies::reply_storage::key_storage::UsedReplyKey;
|
||||
use crypto::generic_array::typenum::Unsigned;
|
||||
use crypto::Digest;
|
||||
use nymsphinx::addressing::clients::{Recipient, RecipientBytes};
|
||||
use nymsphinx::anonymous_replies::encryption_key::EncryptionKeyDigest;
|
||||
use nymsphinx::anonymous_replies::requests::{AnonymousSenderTag, SENDER_TAG_SIZE};
|
||||
use nymsphinx::anonymous_replies::{ReplySurb, SurbEncryptionKey, SurbEncryptionKeySize};
|
||||
use nymsphinx::params::ReplySurbKeyDigestAlgorithm;
|
||||
use nym_crypto::generic_array::typenum::Unsigned;
|
||||
use nym_crypto::Digest;
|
||||
use nym_sphinx::addressing::clients::{Recipient, RecipientBytes};
|
||||
use nym_sphinx::anonymous_replies::encryption_key::EncryptionKeyDigest;
|
||||
use nym_sphinx::anonymous_replies::requests::{AnonymousSenderTag, SENDER_TAG_SIZE};
|
||||
use nym_sphinx::anonymous_replies::{ReplySurb, SurbEncryptionKey, SurbEncryptionKeySize};
|
||||
use nym_sphinx::params::ReplySurbKeyDigestAlgorithm;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct StoredSenderTag {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
use crate::client::replies::reply_storage::CombinedReplyStorage;
|
||||
use async_trait::async_trait;
|
||||
use std::error::Error;
|
||||
use std::{error::Error, path::PathBuf};
|
||||
use thiserror::Error;
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
@@ -30,6 +30,16 @@ pub struct Empty {
|
||||
impl ReplyStorageBackend for Empty {
|
||||
type StorageError = UndefinedError;
|
||||
|
||||
async fn new(
|
||||
debug_config: &crate::config::DebugConfig,
|
||||
_db_path: Option<PathBuf>,
|
||||
) -> Result<Self, Self::StorageError> {
|
||||
Ok(Self {
|
||||
min_surb_threshold: debug_config.minimum_reply_surb_storage_threshold,
|
||||
max_surb_threshold: debug_config.maximum_reply_surb_storage_threshold,
|
||||
})
|
||||
}
|
||||
|
||||
async fn flush_surb_storage(
|
||||
&mut self,
|
||||
_storage: &CombinedReplyStorage,
|
||||
@@ -63,6 +73,11 @@ impl ReplyStorageBackend for Empty {
|
||||
pub trait ReplyStorageBackend: Sized {
|
||||
type StorageError: Error + 'static;
|
||||
|
||||
async fn new(
|
||||
debug_config: &crate::config::DebugConfig,
|
||||
db_path: Option<PathBuf>,
|
||||
) -> Result<Self, Self::StorageError>;
|
||||
|
||||
fn is_active(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
|
||||
use dashmap::iter::Iter;
|
||||
use dashmap::DashMap;
|
||||
use nymsphinx::anonymous_replies::encryption_key::EncryptionKeyDigest;
|
||||
use nymsphinx::anonymous_replies::SurbEncryptionKey;
|
||||
use nym_sphinx::anonymous_replies::encryption_key::EncryptionKeyDigest;
|
||||
use nym_sphinx::anonymous_replies::SurbEncryptionKey;
|
||||
use std::ops::Deref;
|
||||
use std::sync::Arc;
|
||||
use time::OffsetDateTime;
|
||||
|
||||
@@ -37,7 +37,7 @@ where
|
||||
pub async fn flush_on_shutdown(
|
||||
mut self,
|
||||
mem_state: CombinedReplyStorage,
|
||||
mut shutdown: task::TaskClient,
|
||||
mut shutdown: nym_task::TaskClient,
|
||||
) {
|
||||
use log::{debug, error, info, warn};
|
||||
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
use dashmap::iter::Iter;
|
||||
use dashmap::DashMap;
|
||||
use log::trace;
|
||||
use nymsphinx::anonymous_replies::requests::AnonymousSenderTag;
|
||||
use nymsphinx::anonymous_replies::ReplySurb;
|
||||
use nym_sphinx::anonymous_replies::requests::AnonymousSenderTag;
|
||||
use nym_sphinx::anonymous_replies::ReplySurb;
|
||||
use std::collections::VecDeque;
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
use std::sync::Arc;
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use dashmap::DashMap;
|
||||
use nymsphinx::addressing::clients::{Recipient, RecipientBytes};
|
||||
use nymsphinx::anonymous_replies::requests::AnonymousSenderTag;
|
||||
use nym_sphinx::addressing::clients::{Recipient, RecipientBytes};
|
||||
use nym_sphinx::anonymous_replies::requests::AnonymousSenderTag;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[cfg(all(not(target_arch = "wasm32"), feature = "fs-surb-storage"))]
|
||||
|
||||
@@ -1,336 +0,0 @@
|
||||
// Copyright 2021-2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::spawn_future;
|
||||
use futures::StreamExt;
|
||||
use log::*;
|
||||
use nymsphinx::addressing::clients::Recipient;
|
||||
use nymsphinx::params::DEFAULT_NUM_MIX_HOPS;
|
||||
use rand::seq::SliceRandom;
|
||||
use rand::thread_rng;
|
||||
use std::ops::Deref;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use tokio::sync::{RwLock, RwLockReadGuard};
|
||||
use topology::{nym_topology_from_detailed, NymTopology, NymTopologyError};
|
||||
use url::Url;
|
||||
|
||||
// I'm extremely curious why compiler NEVER complained about lack of Debug here before
|
||||
#[derive(Debug)]
|
||||
pub struct TopologyAccessorInner(Option<NymTopology>);
|
||||
|
||||
impl AsRef<Option<NymTopology>> for TopologyAccessorInner {
|
||||
fn as_ref(&self) -> &Option<NymTopology> {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl TopologyAccessorInner {
|
||||
fn new() -> Self {
|
||||
TopologyAccessorInner(None)
|
||||
}
|
||||
|
||||
fn update(&mut self, new: Option<NymTopology>) {
|
||||
self.0 = new;
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TopologyReadPermit<'a> {
|
||||
permit: RwLockReadGuard<'a, TopologyAccessorInner>,
|
||||
}
|
||||
|
||||
impl<'a> Deref for TopologyReadPermit<'a> {
|
||||
type Target = TopologyAccessorInner;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.permit
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> TopologyReadPermit<'a> {
|
||||
/// Using provided topology read permit, tries to get an immutable reference to the underlying
|
||||
/// topology. For obvious reasons the lifetime of the topology reference is bound to the permit.
|
||||
pub(super) fn try_get_valid_topology_ref(
|
||||
&'a self,
|
||||
ack_recipient: &Recipient,
|
||||
packet_recipient: Option<&Recipient>,
|
||||
) -> Result<&'a NymTopology, NymTopologyError> {
|
||||
// 1. Have we managed to get anything from the refresher, i.e. have the nym-api queries gone through?
|
||||
let topology = self
|
||||
.permit
|
||||
.as_ref()
|
||||
.as_ref()
|
||||
.ok_or(NymTopologyError::EmptyNetworkTopology)?;
|
||||
|
||||
// 2. does it have any mixnode at all?
|
||||
// 3. does it have any gateways at all?
|
||||
// 4. does it have a mixnode on each layer?
|
||||
topology.ensure_can_construct_path_through(DEFAULT_NUM_MIX_HOPS)?;
|
||||
|
||||
// 5. does it contain OUR gateway (so that we could create an ack packet)?
|
||||
if !topology.gateway_exists(ack_recipient.gateway()) {
|
||||
return Err(NymTopologyError::NonExistentGatewayError {
|
||||
identity_key: ack_recipient.gateway().to_base58_string(),
|
||||
});
|
||||
}
|
||||
|
||||
// 6. for our target recipient, does it contain THEIR gateway (so that we could create
|
||||
if let Some(recipient) = packet_recipient {
|
||||
if !topology.gateway_exists(recipient.gateway()) {
|
||||
return Err(NymTopologyError::NonExistentGatewayError {
|
||||
identity_key: recipient.gateway().to_base58_string(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Ok(topology)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<RwLockReadGuard<'a, TopologyAccessorInner>> for TopologyReadPermit<'a> {
|
||||
fn from(read_permit: RwLockReadGuard<'a, TopologyAccessorInner>) -> Self {
|
||||
TopologyReadPermit {
|
||||
permit: read_permit,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct TopologyAccessor {
|
||||
// `RwLock` *seems to* be the better approach for this as write access is only requested every
|
||||
// few seconds, while reads are needed every single packet generated.
|
||||
// However, proper benchmarks will be needed to determine if `RwLock` is indeed a better
|
||||
// approach than a `Mutex`
|
||||
inner: Arc<RwLock<TopologyAccessorInner>>,
|
||||
}
|
||||
|
||||
impl TopologyAccessor {
|
||||
pub fn new() -> Self {
|
||||
TopologyAccessor {
|
||||
inner: Arc::new(RwLock::new(TopologyAccessorInner::new())),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get_read_permit(&self) -> TopologyReadPermit<'_> {
|
||||
self.inner.read().await.into()
|
||||
}
|
||||
|
||||
async fn update_global_topology(&self, new_topology: Option<NymTopology>) {
|
||||
self.inner.write().await.update(new_topology);
|
||||
}
|
||||
|
||||
// only used by the client at startup to get a slightly more reasonable error message
|
||||
// (currently displays as unused because health checker is disabled due to required changes)
|
||||
pub async fn ensure_is_routable(&self) -> Result<(), NymTopologyError> {
|
||||
match &self.inner.read().await.0 {
|
||||
None => Err(NymTopologyError::EmptyNetworkTopology),
|
||||
Some(ref topology) => topology.ensure_can_construct_path_through(DEFAULT_NUM_MIX_HOPS),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for TopologyAccessor {
|
||||
fn default() -> Self {
|
||||
TopologyAccessor::new()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TopologyRefresherConfig {
|
||||
nym_api_urls: Vec<Url>,
|
||||
refresh_rate: Duration,
|
||||
client_version: String,
|
||||
}
|
||||
|
||||
impl TopologyRefresherConfig {
|
||||
pub fn new(nym_api_urls: Vec<Url>, refresh_rate: Duration, client_version: String) -> Self {
|
||||
TopologyRefresherConfig {
|
||||
nym_api_urls,
|
||||
refresh_rate,
|
||||
client_version,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TopologyRefresher {
|
||||
validator_client: validator_client::client::NymApiClient,
|
||||
client_version: String,
|
||||
|
||||
nym_api_urls: Vec<Url>,
|
||||
topology_accessor: TopologyAccessor,
|
||||
refresh_rate: Duration,
|
||||
|
||||
currently_used_api: usize,
|
||||
was_latest_valid: bool,
|
||||
}
|
||||
|
||||
impl TopologyRefresher {
|
||||
pub fn new(mut cfg: TopologyRefresherConfig, topology_accessor: TopologyAccessor) -> Self {
|
||||
cfg.nym_api_urls.shuffle(&mut thread_rng());
|
||||
|
||||
TopologyRefresher {
|
||||
validator_client: validator_client::client::NymApiClient::new(
|
||||
cfg.nym_api_urls[0].clone(),
|
||||
),
|
||||
client_version: cfg.client_version,
|
||||
nym_api_urls: cfg.nym_api_urls,
|
||||
topology_accessor,
|
||||
refresh_rate: cfg.refresh_rate,
|
||||
currently_used_api: 0,
|
||||
was_latest_valid: true,
|
||||
}
|
||||
}
|
||||
|
||||
fn use_next_nym_api(&mut self) {
|
||||
if self.nym_api_urls.len() == 1 {
|
||||
warn!("There's only a single nym API available - it won't be possible to use a different one");
|
||||
return;
|
||||
}
|
||||
|
||||
self.currently_used_api = (self.currently_used_api + 1) % self.nym_api_urls.len();
|
||||
self.validator_client
|
||||
.change_nym_api(self.nym_api_urls[self.currently_used_api].clone())
|
||||
}
|
||||
|
||||
/// Verifies whether nodes a reasonably distributed among all mix layers.
|
||||
///
|
||||
/// In ideal world we would have 33% nodes on layer 1, 33% on layer 2 and 33% on layer 3.
|
||||
/// However, this is a rather unrealistic expectation, instead we check whether there exists
|
||||
/// a layer with more than 66% of nodes or with fewer than 15% and if so, we trigger a failure.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `topology`: active topology constructed from validator api data
|
||||
fn check_layer_distribution(&self, active_topology: &NymTopology) -> bool {
|
||||
let mixes = active_topology.mixes();
|
||||
let mixnodes_count = active_topology.num_mixnodes();
|
||||
|
||||
if active_topology.gateways().is_empty() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// trivial check to see if have at least a single node on each layer (regardless of active set size)
|
||||
if mixes.get(&1).is_none() || mixes.get(&2).is_none() || mixes.get(&3).is_none() {
|
||||
return false;
|
||||
}
|
||||
|
||||
let upper_bound = (mixnodes_count as f32 * 0.66) as usize;
|
||||
let lower_bound = (mixnodes_count as f32 * 0.15) as usize;
|
||||
|
||||
let layer1 = mixes.get(&1).unwrap().len();
|
||||
let layer2 = mixes.get(&2).unwrap().len();
|
||||
let layer3 = mixes.get(&3).unwrap().len();
|
||||
|
||||
if layer1 < lower_bound || layer1 > upper_bound {
|
||||
warn!(
|
||||
"nodes: {}, layer1: {}, layer2: {}, layer3: {}",
|
||||
mixnodes_count, layer1, layer2, layer3
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
if layer2 < lower_bound || layer2 > upper_bound {
|
||||
warn!(
|
||||
"nodes: {}, layer1: {}, layer2: {}, layer3: {}",
|
||||
mixnodes_count, layer1, layer2, layer3
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
if layer3 < lower_bound || layer3 > upper_bound {
|
||||
warn!(
|
||||
"nodes: {}, layer1: {}, layer2: {}, layer3: {}",
|
||||
mixnodes_count, layer1, layer2, layer3
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
async fn get_current_compatible_topology(&self) -> Option<NymTopology> {
|
||||
// TODO: optimization for the future:
|
||||
// only refresh mixnodes on timer and refresh gateways only when
|
||||
// we have to send to a new, unknown, gateway
|
||||
|
||||
let mixnodes = match self.validator_client.get_cached_active_mixnodes().await {
|
||||
Err(err) => {
|
||||
error!("failed to get network mixnodes - {err}");
|
||||
return None;
|
||||
}
|
||||
Ok(mixes) => mixes,
|
||||
};
|
||||
|
||||
let gateways = match self.validator_client.get_cached_gateways().await {
|
||||
Err(err) => {
|
||||
error!("failed to get network gateways - {err}");
|
||||
return None;
|
||||
}
|
||||
Ok(gateways) => gateways,
|
||||
};
|
||||
|
||||
let topology = nym_topology_from_detailed(mixnodes, gateways)
|
||||
.filter_system_version(&self.client_version);
|
||||
|
||||
if !self.check_layer_distribution(&topology) {
|
||||
warn!("The current filtered active topology has extremely skewed layer distribution. It cannot be used.");
|
||||
None
|
||||
} else {
|
||||
Some(topology)
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn refresh(&mut self) {
|
||||
trace!("Refreshing the topology");
|
||||
let new_topology = self.get_current_compatible_topology().await;
|
||||
|
||||
if new_topology.is_none() {
|
||||
self.use_next_nym_api();
|
||||
}
|
||||
|
||||
if new_topology.is_none() && self.was_latest_valid {
|
||||
// if we failed to grab this topology, but the one before it was alright, let's assume
|
||||
// validator had a tiny hiccup and use the old data
|
||||
warn!("we're going to keep on using the old topology for this iteration");
|
||||
self.was_latest_valid = false;
|
||||
return;
|
||||
} else if new_topology.is_some() {
|
||||
self.was_latest_valid = true;
|
||||
}
|
||||
|
||||
self.topology_accessor
|
||||
.update_global_topology(new_topology)
|
||||
.await;
|
||||
}
|
||||
|
||||
pub async fn ensure_topology_is_routable(&self) -> Result<(), NymTopologyError> {
|
||||
self.topology_accessor.ensure_is_routable().await
|
||||
}
|
||||
|
||||
pub fn start_with_shutdown(mut self, mut shutdown: task::TaskClient) {
|
||||
spawn_future(async move {
|
||||
debug!("Started TopologyRefresher with graceful shutdown support");
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
let mut interval = tokio_stream::wrappers::IntervalStream::new(tokio::time::interval(
|
||||
self.refresh_rate,
|
||||
));
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
let mut interval =
|
||||
gloo_timers::future::IntervalStream::new(self.refresh_rate.as_millis() as u32);
|
||||
|
||||
while !shutdown.is_shutdown() {
|
||||
tokio::select! {
|
||||
_ = interval.next() => {
|
||||
self.refresh().await;
|
||||
},
|
||||
_ = shutdown.recv() => {
|
||||
log::trace!("TopologyRefresher: Received shutdown");
|
||||
},
|
||||
}
|
||||
}
|
||||
shutdown.recv_timeout().await;
|
||||
log::debug!("TopologyRefresher: Exiting");
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use nym_sphinx::addressing::clients::Recipient;
|
||||
use nym_sphinx::params::DEFAULT_NUM_MIX_HOPS;
|
||||
use nym_topology::{NymTopology, NymTopologyError};
|
||||
use std::ops::Deref;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::{Notify, RwLock, RwLockReadGuard};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct TopologyAccessorInner {
|
||||
controlled_manually: AtomicBool,
|
||||
released_manual_control: Notify,
|
||||
// `RwLock` *seems to* be the better approach for this as write access is only requested every
|
||||
// few seconds, while reads are needed every single packet generated.
|
||||
// However, proper benchmarks will be needed to determine if `RwLock` is indeed a better
|
||||
// approach than a `Mutex`
|
||||
topology: RwLock<Option<NymTopology>>,
|
||||
}
|
||||
|
||||
impl TopologyAccessorInner {
|
||||
fn new() -> Self {
|
||||
TopologyAccessorInner {
|
||||
controlled_manually: AtomicBool::new(false),
|
||||
released_manual_control: Notify::new(),
|
||||
topology: RwLock::new(None),
|
||||
}
|
||||
}
|
||||
|
||||
async fn update(&self, new: Option<NymTopology>) {
|
||||
*self.topology.write().await = new;
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TopologyReadPermit<'a> {
|
||||
permit: RwLockReadGuard<'a, Option<NymTopology>>,
|
||||
}
|
||||
|
||||
impl<'a> Deref for TopologyReadPermit<'a> {
|
||||
type Target = Option<NymTopology>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.permit
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> TopologyReadPermit<'a> {
|
||||
/// Using provided topology read permit, tries to get an immutable reference to the underlying
|
||||
/// topology. For obvious reasons the lifetime of the topology reference is bound to the permit.
|
||||
pub(crate) fn try_get_valid_topology_ref(
|
||||
&'a self,
|
||||
ack_recipient: &Recipient,
|
||||
packet_recipient: Option<&Recipient>,
|
||||
) -> Result<&'a NymTopology, NymTopologyError> {
|
||||
// 1. Have we managed to get anything from the refresher, i.e. have the nym-api queries gone through?
|
||||
let topology = self
|
||||
.permit
|
||||
.as_ref()
|
||||
.ok_or(NymTopologyError::EmptyNetworkTopology)?;
|
||||
|
||||
// 2. does it have any mixnode at all?
|
||||
// 3. does it have any gateways at all?
|
||||
// 4. does it have a mixnode on each layer?
|
||||
topology.ensure_can_construct_path_through(DEFAULT_NUM_MIX_HOPS)?;
|
||||
|
||||
// 5. does it contain OUR gateway (so that we could create an ack packet)?
|
||||
if !topology.gateway_exists(ack_recipient.gateway()) {
|
||||
return Err(NymTopologyError::NonExistentGatewayError {
|
||||
identity_key: ack_recipient.gateway().to_base58_string(),
|
||||
});
|
||||
}
|
||||
|
||||
// 6. for our target recipient, does it contain THEIR gateway (so that we could create
|
||||
if let Some(recipient) = packet_recipient {
|
||||
if !topology.gateway_exists(recipient.gateway()) {
|
||||
return Err(NymTopologyError::NonExistentGatewayError {
|
||||
identity_key: recipient.gateway().to_base58_string(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Ok(topology)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<RwLockReadGuard<'a, Option<NymTopology>>> for TopologyReadPermit<'a> {
|
||||
fn from(read_permit: RwLockReadGuard<'a, Option<NymTopology>>) -> Self {
|
||||
TopologyReadPermit {
|
||||
permit: read_permit,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct TopologyAccessor {
|
||||
inner: Arc<TopologyAccessorInner>,
|
||||
}
|
||||
|
||||
impl TopologyAccessor {
|
||||
pub fn new() -> Self {
|
||||
TopologyAccessor {
|
||||
inner: Arc::new(TopologyAccessorInner::new()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn controlled_manually(&self) -> bool {
|
||||
self.inner.controlled_manually.load(Ordering::SeqCst)
|
||||
}
|
||||
|
||||
pub async fn get_read_permit(&self) -> TopologyReadPermit<'_> {
|
||||
self.inner.topology.read().await.into()
|
||||
}
|
||||
|
||||
pub(crate) async fn update_global_topology(&self, new_topology: Option<NymTopology>) {
|
||||
self.inner.update(new_topology).await;
|
||||
}
|
||||
|
||||
pub(crate) async fn wait_for_released_manual_control(&self) {
|
||||
self.inner.released_manual_control.notified().await
|
||||
}
|
||||
|
||||
pub async fn current_topology(&self) -> Option<NymTopology> {
|
||||
self.inner.topology.read().await.clone()
|
||||
}
|
||||
|
||||
pub async fn manually_change_topology(&self, new_topology: NymTopology) {
|
||||
self.inner.controlled_manually.store(true, Ordering::SeqCst);
|
||||
self.inner.update(Some(new_topology)).await;
|
||||
}
|
||||
|
||||
pub fn release_manual_control(&self) {
|
||||
self.inner
|
||||
.controlled_manually
|
||||
.store(false, Ordering::SeqCst);
|
||||
self.inner.released_manual_control.notify_waiters();
|
||||
}
|
||||
|
||||
// only used by the client at startup to get a slightly more reasonable error message
|
||||
// (currently displays as unused because health checker is disabled due to required changes)
|
||||
pub async fn ensure_is_routable(&self) -> Result<(), NymTopologyError> {
|
||||
match self.inner.topology.read().await.deref() {
|
||||
None => Err(NymTopologyError::EmptyNetworkTopology),
|
||||
Some(ref topology) => topology.ensure_can_construct_path_through(DEFAULT_NUM_MIX_HOPS),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for TopologyAccessor {
|
||||
fn default() -> Self {
|
||||
TopologyAccessor::new()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::spawn_future;
|
||||
pub(crate) use accessor::{TopologyAccessor, TopologyReadPermit};
|
||||
use futures::StreamExt;
|
||||
use log::*;
|
||||
use nym_topology::provider_trait::TopologyProvider;
|
||||
use nym_topology::NymTopologyError;
|
||||
use std::time::Duration;
|
||||
|
||||
mod accessor;
|
||||
pub(crate) mod nym_api_provider;
|
||||
|
||||
// TODO: move it to config later
|
||||
const MAX_FAILURE_COUNT: usize = 10;
|
||||
|
||||
pub struct TopologyRefresherConfig {
|
||||
refresh_rate: Duration,
|
||||
}
|
||||
|
||||
impl TopologyRefresherConfig {
|
||||
pub fn new(refresh_rate: Duration) -> Self {
|
||||
TopologyRefresherConfig { refresh_rate }
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TopologyRefresher {
|
||||
topology_provider: Box<dyn TopologyProvider>,
|
||||
topology_accessor: TopologyAccessor,
|
||||
|
||||
refresh_rate: Duration,
|
||||
consecutive_failure_count: usize,
|
||||
}
|
||||
|
||||
impl TopologyRefresher {
|
||||
pub fn new(
|
||||
cfg: TopologyRefresherConfig,
|
||||
topology_accessor: TopologyAccessor,
|
||||
topology_provider: Box<dyn TopologyProvider>,
|
||||
) -> Self {
|
||||
TopologyRefresher {
|
||||
topology_provider,
|
||||
topology_accessor,
|
||||
refresh_rate: cfg.refresh_rate,
|
||||
consecutive_failure_count: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn change_topology_provider(&mut self, provider: Box<dyn TopologyProvider>) {
|
||||
self.topology_provider = provider;
|
||||
}
|
||||
|
||||
pub async fn try_refresh(&mut self) {
|
||||
trace!("Refreshing the topology");
|
||||
|
||||
if self.topology_accessor.controlled_manually() {
|
||||
info!("topology is being controlled manually - we're going to wait until the control is released...");
|
||||
self.topology_accessor
|
||||
.wait_for_released_manual_control()
|
||||
.await;
|
||||
}
|
||||
|
||||
let new_topology = self.topology_provider.get_new_topology().await;
|
||||
if new_topology.is_none() {
|
||||
warn!("failed to obtain new network topology");
|
||||
}
|
||||
|
||||
if new_topology.is_none() && self.consecutive_failure_count < MAX_FAILURE_COUNT {
|
||||
// if we failed to grab this topology, but the one before it was alright, let's assume
|
||||
// validator had a tiny hiccup and use the old data
|
||||
warn!("we're going to keep on using the old topology for this iteration");
|
||||
self.consecutive_failure_count += 1;
|
||||
return;
|
||||
} else if new_topology.is_some() {
|
||||
self.consecutive_failure_count = 0;
|
||||
}
|
||||
|
||||
self.topology_accessor
|
||||
.update_global_topology(new_topology)
|
||||
.await;
|
||||
}
|
||||
|
||||
pub async fn ensure_topology_is_routable(&self) -> Result<(), NymTopologyError> {
|
||||
self.topology_accessor.ensure_is_routable().await
|
||||
}
|
||||
|
||||
pub fn start_with_shutdown(mut self, mut shutdown: nym_task::TaskClient) {
|
||||
spawn_future(async move {
|
||||
debug!("Started TopologyRefresher with graceful shutdown support");
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
let mut interval = tokio_stream::wrappers::IntervalStream::new(tokio::time::interval(
|
||||
self.refresh_rate,
|
||||
));
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
let mut interval =
|
||||
gloo_timers::future::IntervalStream::new(self.refresh_rate.as_millis() as u32);
|
||||
|
||||
while !shutdown.is_shutdown() {
|
||||
tokio::select! {
|
||||
_ = interval.next() => {
|
||||
self.try_refresh().await;
|
||||
},
|
||||
_ = shutdown.recv() => {
|
||||
log::trace!("TopologyRefresher: Received shutdown");
|
||||
},
|
||||
}
|
||||
}
|
||||
shutdown.recv_timeout().await;
|
||||
log::debug!("TopologyRefresher: Exiting");
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use async_trait::async_trait;
|
||||
use log::{error, warn};
|
||||
use nym_topology::provider_trait::TopologyProvider;
|
||||
use nym_topology::{nym_topology_from_detailed, NymTopology, NymTopologyError};
|
||||
use rand::prelude::SliceRandom;
|
||||
use rand::thread_rng;
|
||||
use url::Url;
|
||||
|
||||
pub(crate) struct NymApiTopologyProvider {
|
||||
validator_client: validator_client::client::NymApiClient,
|
||||
nym_api_urls: Vec<Url>,
|
||||
|
||||
client_version: String,
|
||||
currently_used_api: usize,
|
||||
}
|
||||
|
||||
impl NymApiTopologyProvider {
|
||||
pub(crate) fn new(mut nym_api_urls: Vec<Url>, client_version: String) -> Self {
|
||||
nym_api_urls.shuffle(&mut thread_rng());
|
||||
|
||||
NymApiTopologyProvider {
|
||||
validator_client: validator_client::client::NymApiClient::new(nym_api_urls[0].clone()),
|
||||
nym_api_urls,
|
||||
client_version,
|
||||
currently_used_api: 0,
|
||||
}
|
||||
}
|
||||
|
||||
fn use_next_nym_api(&mut self) {
|
||||
if self.nym_api_urls.len() == 1 {
|
||||
warn!("There's only a single nym API available - it won't be possible to use a different one");
|
||||
return;
|
||||
}
|
||||
|
||||
self.currently_used_api = (self.currently_used_api + 1) % self.nym_api_urls.len();
|
||||
self.validator_client
|
||||
.change_nym_api(self.nym_api_urls[self.currently_used_api].clone())
|
||||
}
|
||||
|
||||
/// Verifies whether nodes a reasonably distributed among all mix layers.
|
||||
///
|
||||
/// In ideal world we would have 33% nodes on layer 1, 33% on layer 2 and 33% on layer 3.
|
||||
/// However, this is a rather unrealistic expectation, instead we check whether there exists
|
||||
/// a layer with more than 66% of nodes or with fewer than 15% and if so, we trigger a failure.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `topology`: active topology constructed from validator api data
|
||||
fn check_layer_distribution(
|
||||
&self,
|
||||
active_topology: &NymTopology,
|
||||
) -> Result<(), NymTopologyError> {
|
||||
let lower_threshold = 0.15;
|
||||
let upper_threshold = 0.66;
|
||||
active_topology.ensure_even_layer_distribution(lower_threshold, upper_threshold)
|
||||
}
|
||||
|
||||
async fn get_current_compatible_topology(&mut self) -> Option<NymTopology> {
|
||||
let mixnodes = match self.validator_client.get_cached_active_mixnodes().await {
|
||||
Err(err) => {
|
||||
error!("failed to get network mixnodes - {err}");
|
||||
return None;
|
||||
}
|
||||
Ok(mixes) => mixes,
|
||||
};
|
||||
|
||||
let gateways = match self.validator_client.get_cached_gateways().await {
|
||||
Err(err) => {
|
||||
error!("failed to get network gateways - {err}");
|
||||
return None;
|
||||
}
|
||||
Ok(gateways) => gateways,
|
||||
};
|
||||
|
||||
let topology = nym_topology_from_detailed(mixnodes, gateways)
|
||||
.filter_system_version(&self.client_version);
|
||||
|
||||
if let Err(err) = self.check_layer_distribution(&topology) {
|
||||
warn!("The current filtered active topology has extremely skewed layer distribution. It cannot be used: {err}");
|
||||
self.use_next_nym_api();
|
||||
None
|
||||
} else {
|
||||
Some(topology)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// hehe, wasm
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
#[async_trait]
|
||||
impl TopologyProvider for NymApiTopologyProvider {
|
||||
async fn get_new_topology(&mut self) -> Option<NymTopology> {
|
||||
self.get_current_compatible_topology().await
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
#[async_trait(?Send)]
|
||||
impl TopologyProvider for NymApiTopologyProvider {
|
||||
async fn get_new_topology(&mut self) -> Option<NymTopology> {
|
||||
self.get_current_compatible_topology().await
|
||||
}
|
||||
}
|
||||
@@ -3,8 +3,8 @@
|
||||
|
||||
use crate::client::helpers::{get_time_now, Instant};
|
||||
use crate::client::real_messages_control::real_traffic_stream::RealMessage;
|
||||
use client_connections::TransmissionLane;
|
||||
use nymsphinx::chunking::fragment::Fragment;
|
||||
use nym_sphinx::chunking::fragment::Fragment;
|
||||
use nym_task::connections::TransmissionLane;
|
||||
use rand::{seq::SliceRandom, Rng};
|
||||
use std::{
|
||||
collections::{HashMap, HashSet, VecDeque},
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use config::defaults::NymNetworkDetails;
|
||||
use config::{NymConfig, OptionalSet, DB_FILE_NAME};
|
||||
use nymsphinx::params::PacketSize;
|
||||
use nym_config::defaults::NymNetworkDetails;
|
||||
use nym_config::{NymConfig, OptionalSet, CRED_DB_FILE_NAME};
|
||||
use nym_sphinx::params::PacketSize;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::marker::PhantomData;
|
||||
use std::path::PathBuf;
|
||||
@@ -171,10 +171,15 @@ impl<T> Config<T> {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_gateway_endpoint(&mut self, gateway_endpoint: GatewayEndpointConfig) {
|
||||
pub fn set_gateway_endpoint(&mut self, gateway_endpoint: GatewayEndpointConfig) {
|
||||
self.client.gateway_endpoint = gateway_endpoint;
|
||||
}
|
||||
|
||||
pub fn with_gateway_endpoint(mut self, gateway_endpoint: GatewayEndpointConfig) -> Self {
|
||||
self.client.gateway_endpoint = gateway_endpoint;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_gateway_id<S: Into<String>>(&mut self, id: S) {
|
||||
self.client.gateway_endpoint.gateway_id = id.into();
|
||||
}
|
||||
@@ -430,8 +435,8 @@ impl GatewayEndpointConfig {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<topology::gateway::Node> for GatewayEndpointConfig {
|
||||
fn from(node: topology::gateway::Node) -> GatewayEndpointConfig {
|
||||
impl From<nym_topology::gateway::Node> for GatewayEndpointConfig {
|
||||
fn from(node: nym_topology::gateway::Node) -> GatewayEndpointConfig {
|
||||
let gateway_listener = node.clients_address();
|
||||
GatewayEndpointConfig {
|
||||
gateway_id: node.identity_key.to_base58_string(),
|
||||
@@ -546,35 +551,35 @@ impl<T: NymConfig> Default for Client<T> {
|
||||
|
||||
impl<T: NymConfig> Client<T> {
|
||||
fn default_private_identity_key_file(id: &str) -> PathBuf {
|
||||
T::default_data_directory(Some(id)).join("private_identity.pem")
|
||||
T::default_data_directory(id).join("private_identity.pem")
|
||||
}
|
||||
|
||||
fn default_public_identity_key_file(id: &str) -> PathBuf {
|
||||
T::default_data_directory(Some(id)).join("public_identity.pem")
|
||||
T::default_data_directory(id).join("public_identity.pem")
|
||||
}
|
||||
|
||||
fn default_private_encryption_key_file(id: &str) -> PathBuf {
|
||||
T::default_data_directory(Some(id)).join("private_encryption.pem")
|
||||
T::default_data_directory(id).join("private_encryption.pem")
|
||||
}
|
||||
|
||||
fn default_public_encryption_key_file(id: &str) -> PathBuf {
|
||||
T::default_data_directory(Some(id)).join("public_encryption.pem")
|
||||
T::default_data_directory(id).join("public_encryption.pem")
|
||||
}
|
||||
|
||||
fn default_gateway_shared_key_file(id: &str) -> PathBuf {
|
||||
T::default_data_directory(Some(id)).join("gateway_shared.pem")
|
||||
T::default_data_directory(id).join("gateway_shared.pem")
|
||||
}
|
||||
|
||||
fn default_ack_key_file(id: &str) -> PathBuf {
|
||||
T::default_data_directory(Some(id)).join("ack_key.pem")
|
||||
T::default_data_directory(id).join("ack_key.pem")
|
||||
}
|
||||
|
||||
fn default_reply_surb_database_path(id: &str) -> PathBuf {
|
||||
T::default_data_directory(Some(id)).join("persistent_reply_store.sqlite")
|
||||
T::default_data_directory(id).join("persistent_reply_store.sqlite")
|
||||
}
|
||||
|
||||
fn default_database_path(id: &str) -> PathBuf {
|
||||
T::default_data_directory(Some(id)).join(DB_FILE_NAME)
|
||||
T::default_data_directory(id).join(CRED_DB_FILE_NAME)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::config::Config;
|
||||
use config::NymConfig;
|
||||
use nym_config::NymConfig;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
#[derive(Debug)]
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crypto::asymmetric::identity::Ed25519RecoveryError;
|
||||
use gateway_client::error::GatewayClientError;
|
||||
use topology::NymTopologyError;
|
||||
use nym_crypto::asymmetric::identity::Ed25519RecoveryError;
|
||||
use nym_topology::gateway::GatewayConversionError;
|
||||
use nym_topology::NymTopologyError;
|
||||
use validator_client::ValidatorClientError;
|
||||
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
@@ -53,7 +54,32 @@ pub enum ClientCoreError {
|
||||
GatewayOwnerUnknown,
|
||||
|
||||
#[error("The address of the gateway is unknown - did you run init?")]
|
||||
GatwayAddressUnknown,
|
||||
GatewayAddressUnknown,
|
||||
|
||||
#[error("The gateway is malformed: {source}")]
|
||||
MalformedGateway {
|
||||
#[from]
|
||||
source: GatewayConversionError,
|
||||
},
|
||||
|
||||
#[error("failed to establish connection to gateway: {source}")]
|
||||
GatewayConnectionFailure {
|
||||
#[from]
|
||||
source: tungstenite::Error,
|
||||
},
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
#[error("failed to establish gateway connection (wasm)")]
|
||||
GatewayJsConnectionFailure,
|
||||
|
||||
#[error("Gateway connection was abruptly closed")]
|
||||
GatewayConnectionAbruptlyClosed,
|
||||
|
||||
#[error("Timed out while trying to establish gateway connection")]
|
||||
GatewayConnectionTimeout,
|
||||
|
||||
#[error("No ping measurements for the gateway ({identity}) performed")]
|
||||
NoGatewayMeasurements { identity: String },
|
||||
|
||||
#[error("failed to register receiver for reconstructed mixnet messages")]
|
||||
FailedToRegisterReceiver,
|
||||
|
||||
@@ -6,52 +6,223 @@ use crate::{
|
||||
config::{persistence::key_pathfinder::ClientKeyPathfinder, Config},
|
||||
error::ClientCoreError,
|
||||
};
|
||||
use config::NymConfig;
|
||||
use crypto::asymmetric::identity;
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
use gateway_client::wasm_mockups::SigningNyxdClient;
|
||||
use futures::{SinkExt, StreamExt};
|
||||
use gateway_client::GatewayClient;
|
||||
use gateway_requests::registration::handshake::SharedKeys;
|
||||
use rand::{seq::SliceRandom, thread_rng};
|
||||
use log::{debug, info, trace, warn};
|
||||
use nym_config::NymConfig;
|
||||
use nym_crypto::asymmetric::identity;
|
||||
use nym_topology::{filter::VersionFilterable, gateway};
|
||||
use rand::{seq::SliceRandom, thread_rng, Rng};
|
||||
use std::{sync::Arc, time::Duration};
|
||||
use tap::TapFallible;
|
||||
use topology::{filter::VersionFilterable, gateway};
|
||||
use tungstenite::Message;
|
||||
use url::Url;
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
use tokio::net::TcpStream;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
use tokio::time::Instant;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
use tokio_tungstenite::connect_async;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
use tokio_tungstenite::{MaybeTlsStream, WebSocketStream};
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
use validator_client::nyxd::SigningNyxdClient;
|
||||
|
||||
pub(super) async fn query_gateway_details(
|
||||
validator_servers: Vec<Url>,
|
||||
chosen_gateway_id: Option<identity::PublicKey>,
|
||||
) -> Result<gateway::Node, ClientCoreError> {
|
||||
let nym_api = validator_servers
|
||||
.choose(&mut thread_rng())
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
type WsConn = WebSocketStream<MaybeTlsStream<TcpStream>>;
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
use gateway_client::wasm_mockups::SigningNyxdClient;
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
use wasm_timer::Instant;
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
use wasm_utils::websocket::JSWebsocket;
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
type WsConn = JSWebsocket;
|
||||
|
||||
const MEASUREMENTS: usize = 3;
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
const CONN_TIMEOUT: Duration = Duration::from_millis(1500);
|
||||
const PING_TIMEOUT: Duration = Duration::from_millis(1000);
|
||||
|
||||
struct GatewayWithLatency {
|
||||
gateway: gateway::Node,
|
||||
latency: Duration,
|
||||
}
|
||||
|
||||
impl GatewayWithLatency {
|
||||
fn new(gateway: gateway::Node, latency: Duration) -> Self {
|
||||
GatewayWithLatency { gateway, latency }
|
||||
}
|
||||
}
|
||||
|
||||
async fn current_gateways<R: Rng>(
|
||||
rng: &mut R,
|
||||
nym_apis: Vec<Url>,
|
||||
) -> Result<Vec<gateway::Node>, ClientCoreError> {
|
||||
let nym_api = nym_apis
|
||||
.choose(rng)
|
||||
.ok_or(ClientCoreError::ListOfNymApisIsEmpty)?;
|
||||
let validator_client = validator_client::client::NymApiClient::new(nym_api.clone());
|
||||
let client = validator_client::client::NymApiClient::new(nym_api.clone());
|
||||
|
||||
log::trace!("Fetching list of gateways from: {}", nym_api);
|
||||
let gateways = validator_client.get_cached_gateways().await?;
|
||||
|
||||
let gateways = client.get_cached_gateways().await?;
|
||||
let valid_gateways = gateways
|
||||
.into_iter()
|
||||
.filter_map(|gateway| gateway.try_into().ok())
|
||||
.collect::<Vec<gateway::Node>>();
|
||||
|
||||
// we were always filtering by version so I'm not removing that 'feature'
|
||||
let filtered_gateways = valid_gateways.filter_by_version(env!("CARGO_PKG_VERSION"));
|
||||
Ok(filtered_gateways)
|
||||
}
|
||||
|
||||
// if we have chosen particular gateway - use it, otherwise choose a random one.
|
||||
// (remember that in active topology all gateways have at least 100 reputation so should
|
||||
// be working correctly)
|
||||
if let Some(gateway_id) = chosen_gateway_id {
|
||||
filtered_gateways
|
||||
.iter()
|
||||
.find(|gateway| gateway.identity_key == gateway_id)
|
||||
.ok_or_else(|| ClientCoreError::NoGatewayWithId(gateway_id.to_string()))
|
||||
.cloned()
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
async fn connect(endpoint: &str) -> Result<WsConn, ClientCoreError> {
|
||||
match tokio::time::timeout(CONN_TIMEOUT, connect_async(endpoint)).await {
|
||||
Err(_elapsed) => Err(ClientCoreError::GatewayConnectionTimeout),
|
||||
Ok(Err(conn_failure)) => Err(conn_failure.into()),
|
||||
Ok(Ok((stream, _))) => Ok(stream),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
async fn connect(endpoint: &str) -> Result<WsConn, ClientCoreError> {
|
||||
JSWebsocket::new(endpoint).map_err(|_| ClientCoreError::GatewayJsConnectionFailure)
|
||||
}
|
||||
|
||||
async fn measure_latency(gateway: gateway::Node) -> Result<GatewayWithLatency, ClientCoreError> {
|
||||
let addr = gateway.clients_address();
|
||||
trace!(
|
||||
"establishing connection to {} ({addr})...",
|
||||
gateway.identity_key,
|
||||
);
|
||||
let mut stream = connect(&addr).await?;
|
||||
|
||||
let mut results = Vec::new();
|
||||
for _ in 0..MEASUREMENTS {
|
||||
let measurement_future = async {
|
||||
let ping_content = vec![1, 2, 3];
|
||||
let start = Instant::now();
|
||||
stream.send(Message::Ping(ping_content.clone())).await?;
|
||||
|
||||
match stream.next().await {
|
||||
Some(Ok(Message::Pong(content))) => {
|
||||
if content == ping_content {
|
||||
let elapsed = Instant::now().duration_since(start);
|
||||
trace!("current ping time: {elapsed:?}");
|
||||
results.push(elapsed);
|
||||
} else {
|
||||
warn!("received a pong message with different content? wtf.")
|
||||
}
|
||||
}
|
||||
Some(Ok(_)) => warn!("received a message that's not a pong!"),
|
||||
Some(Err(err)) => return Err(err.into()),
|
||||
None => return Err(ClientCoreError::GatewayConnectionAbruptlyClosed),
|
||||
}
|
||||
|
||||
Ok::<(), ClientCoreError>(())
|
||||
};
|
||||
|
||||
// thanks to wasm we can't use tokio::time::timeout : (
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
let timeout = tokio::time::sleep(PING_TIMEOUT);
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
tokio::pin!(timeout);
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
let mut timeout = wasm_timer::Delay::new(PING_TIMEOUT);
|
||||
|
||||
tokio::select! {
|
||||
_ = &mut timeout => {
|
||||
warn!("timed out while trying to perform measurement...")
|
||||
}
|
||||
res = measurement_future => res?,
|
||||
}
|
||||
}
|
||||
|
||||
let count = results.len() as u64;
|
||||
if count == 0 {
|
||||
return Err(ClientCoreError::NoGatewayMeasurements {
|
||||
identity: gateway.identity_key.to_base58_string(),
|
||||
});
|
||||
}
|
||||
|
||||
let sum: Duration = results.into_iter().sum();
|
||||
let avg = Duration::from_nanos(sum.as_nanos() as u64 / count);
|
||||
|
||||
Ok(GatewayWithLatency::new(gateway, avg))
|
||||
}
|
||||
|
||||
async fn choose_gateway_by_latency<R: Rng>(
|
||||
rng: &mut R,
|
||||
gateways: Vec<gateway::Node>,
|
||||
) -> Result<gateway::Node, ClientCoreError> {
|
||||
info!("choosing gateway by latency...");
|
||||
|
||||
let mut gateways_with_latency = Vec::new();
|
||||
for gateway in gateways {
|
||||
let id = *gateway.identity();
|
||||
trace!("measuring latency to {id}...");
|
||||
let with_latency = match measure_latency(gateway).await {
|
||||
Ok(res) => res,
|
||||
Err(err) => {
|
||||
warn!("failed to measure {id}: {err}");
|
||||
continue;
|
||||
}
|
||||
};
|
||||
debug!(
|
||||
"{id} ({}): {:?}",
|
||||
with_latency.gateway.location, with_latency.latency
|
||||
);
|
||||
gateways_with_latency.push(with_latency)
|
||||
}
|
||||
|
||||
let chosen = gateways_with_latency
|
||||
.choose_weighted(rng, |item| 1. / item.latency.as_secs_f32())
|
||||
.expect("invalid selection weight!");
|
||||
|
||||
info!(
|
||||
"chose gateway {} (located at {}) with average latency of {:?}",
|
||||
chosen.gateway.identity_key, chosen.gateway.location, chosen.latency
|
||||
);
|
||||
|
||||
Ok(chosen.gateway.clone())
|
||||
}
|
||||
|
||||
fn uniformly_random_gateway<R: Rng>(
|
||||
rng: &mut R,
|
||||
gateways: Vec<gateway::Node>,
|
||||
) -> Result<gateway::Node, ClientCoreError> {
|
||||
gateways
|
||||
.choose(rng)
|
||||
.ok_or(ClientCoreError::NoGatewaysOnNetwork)
|
||||
.cloned()
|
||||
}
|
||||
|
||||
pub(super) async fn query_gateway_details(
|
||||
validator_servers: Vec<Url>,
|
||||
chosen_gateway_id: Option<identity::PublicKey>,
|
||||
by_latency: bool,
|
||||
) -> Result<gateway::Node, ClientCoreError> {
|
||||
let mut rng = thread_rng();
|
||||
let gateways = current_gateways(&mut rng, validator_servers).await?;
|
||||
|
||||
// if we set an explicit gateway, use that one and nothing else
|
||||
if let Some(explicitly_chosen) = chosen_gateway_id {
|
||||
gateways
|
||||
.into_iter()
|
||||
.find(|gateway| gateway.identity_key == explicitly_chosen)
|
||||
.ok_or_else(|| ClientCoreError::NoGatewayWithId(explicitly_chosen.to_string()))
|
||||
} else if by_latency {
|
||||
choose_gateway_by_latency(&mut rng, gateways).await
|
||||
} else {
|
||||
filtered_gateways
|
||||
.choose(&mut rand::thread_rng())
|
||||
.ok_or(ClientCoreError::NoGatewaysOnNetwork)
|
||||
.cloned()
|
||||
uniformly_random_gateway(&mut rng, gateways)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,13 +5,13 @@
|
||||
|
||||
use std::fmt::Display;
|
||||
|
||||
use nymsphinx::addressing::{clients::Recipient, nodes::NodeIdentity};
|
||||
use nym_sphinx::addressing::{clients::Recipient, nodes::NodeIdentity};
|
||||
use rand::rngs::OsRng;
|
||||
use serde::Serialize;
|
||||
use tap::TapFallible;
|
||||
|
||||
use config::NymConfig;
|
||||
use crypto::asymmetric::{encryption, identity};
|
||||
use nym_config::NymConfig;
|
||||
use nym_crypto::asymmetric::{encryption, identity};
|
||||
use url::Url;
|
||||
|
||||
use crate::client::key_manager::KeyManager;
|
||||
@@ -77,9 +77,11 @@ pub async fn register_with_gateway(
|
||||
key_manager: &mut KeyManager,
|
||||
nym_api_endpoints: Vec<Url>,
|
||||
chosen_gateway_id: Option<identity::PublicKey>,
|
||||
by_latency: bool,
|
||||
) -> Result<GatewayEndpointConfig, ClientCoreError> {
|
||||
// Get the gateway details of the gateway we will use
|
||||
let gateway = helpers::query_gateway_details(nym_api_endpoints, chosen_gateway_id).await?;
|
||||
let gateway =
|
||||
helpers::query_gateway_details(nym_api_endpoints, chosen_gateway_id, by_latency).await?;
|
||||
log::debug!("Querying gateway gives: {}", gateway);
|
||||
|
||||
let our_identity = key_manager.identity_keypair();
|
||||
@@ -102,6 +104,7 @@ pub async fn setup_gateway_from_config<C, T>(
|
||||
register_gateway: bool,
|
||||
user_chosen_gateway_id: Option<identity::PublicKey>,
|
||||
config: &Config<T>,
|
||||
by_latency: bool,
|
||||
) -> Result<GatewayEndpointConfig, ClientCoreError>
|
||||
where
|
||||
C: NymConfig + ClientCoreConfigTrait,
|
||||
@@ -117,9 +120,12 @@ where
|
||||
}
|
||||
|
||||
// Else, we preceed by querying the nym-api
|
||||
let gateway =
|
||||
helpers::query_gateway_details(config.get_nym_api_endpoints(), user_chosen_gateway_id)
|
||||
.await?;
|
||||
let gateway = helpers::query_gateway_details(
|
||||
config.get_nym_api_endpoints(),
|
||||
user_chosen_gateway_id,
|
||||
by_latency,
|
||||
)
|
||||
.await?;
|
||||
log::debug!("Querying gateway gives: {}", gateway);
|
||||
|
||||
// If we are not registering, just return this and assume the caller has the keys already and
|
||||
@@ -149,7 +155,7 @@ pub fn load_existing_gateway_config<T>(id: &str) -> Result<GatewayEndpointConfig
|
||||
where
|
||||
T: NymConfig + ClientCoreConfigTrait,
|
||||
{
|
||||
T::load_from_file(Some(id))
|
||||
T::load_from_file(id)
|
||||
.map(|existing_config| existing_config.get_gateway_endpoint().clone())
|
||||
.map_err(|err| {
|
||||
log::error!(
|
||||
@@ -182,13 +188,13 @@ pub fn get_client_address_from_stored_keys<T>(
|
||||
config: &Config<T>,
|
||||
) -> Result<Recipient, ClientCoreError>
|
||||
where
|
||||
T: config::NymConfig,
|
||||
T: nym_config::NymConfig,
|
||||
{
|
||||
fn load_identity_keys(
|
||||
pathfinder: &ClientKeyPathfinder,
|
||||
) -> Result<identity::KeyPair, ClientCoreError> {
|
||||
let identity_keypair: identity::KeyPair =
|
||||
pemstore::load_keypair(&pemstore::KeyPairPath::new(
|
||||
nym_pemstore::load_keypair(&nym_pemstore::KeyPairPath::new(
|
||||
pathfinder.private_identity_key().to_owned(),
|
||||
pathfinder.public_identity_key().to_owned(),
|
||||
))
|
||||
@@ -200,7 +206,7 @@ where
|
||||
pathfinder: &ClientKeyPathfinder,
|
||||
) -> Result<encryption::KeyPair, ClientCoreError> {
|
||||
let sphinx_keypair: encryption::KeyPair =
|
||||
pemstore::load_keypair(&pemstore::KeyPairPath::new(
|
||||
nym_pemstore::load_keypair(&nym_pemstore::KeyPairPath::new(
|
||||
pathfinder.private_encryption_key().to_owned(),
|
||||
pathfinder.public_encryption_key().to_owned(),
|
||||
))
|
||||
|
||||
@@ -8,19 +8,20 @@ edition = "2021"
|
||||
[dependencies]
|
||||
bip39 = "1.0.1"
|
||||
clap = { version = "4.0", features = ["cargo", "derive"] }
|
||||
log = "0.4"
|
||||
rand = "0.7.3"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
thiserror = "1.0"
|
||||
url = "2.2"
|
||||
tokio = { version = "1.24.1", features = ["rt-multi-thread", "net", "signal", "macros"] } # async runtime
|
||||
|
||||
coconut-interface = { path = "../../common/coconut-interface" }
|
||||
config = { path = "../../common/config" }
|
||||
completions = { path = "../../common/completions" }
|
||||
credentials = { path = "../../common/credentials" }
|
||||
credential-storage = { path = "../../common/credential-storage" }
|
||||
crypto = { path = "../../common/crypto", features = ["rand", "asymmetric", "symmetric", "aes", "hashing"] }
|
||||
network-defaults = { path = "../../common/network-defaults" }
|
||||
pemstore = { path = "../../common/pemstore" }
|
||||
nym-coconut-interface = { path = "../../common/coconut-interface" }
|
||||
nym-config = { path = "../../common/config" }
|
||||
nym-credentials = { path = "../../common/credentials" }
|
||||
nym-credential-storage = { path = "../../common/credential-storage" }
|
||||
nym-crypto = { path = "../../common/crypto", features = ["rand", "asymmetric", "symmetric", "aes", "hashing"] }
|
||||
nym-bin-common = { path = "../../common/bin-common"}
|
||||
nym-network-defaults = { path = "../../common/network-defaults" }
|
||||
nym-pemstore = { path = "../../common/pemstore" }
|
||||
validator-client = { path = "../../common/client-libs/validator-client", features = ["nyxd-client"] }
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
use crate::error::Result;
|
||||
use bip39::Mnemonic;
|
||||
use network_defaults::{NymNetworkDetails, VOUCHER_INFO};
|
||||
use nym_network_defaults::{NymNetworkDetails, VOUCHER_INFO};
|
||||
use std::str::FromStr;
|
||||
use url::Url;
|
||||
use validator_client::nyxd;
|
||||
|
||||
@@ -1,29 +1,32 @@
|
||||
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use clap::{Args, Subcommand};
|
||||
use completions::ArgShell;
|
||||
use clap::{ArgGroup, Args, Subcommand};
|
||||
use log::*;
|
||||
use nym_bin_common::completions::ArgShell;
|
||||
use rand::rngs::OsRng;
|
||||
use std::str::FromStr;
|
||||
|
||||
use coconut_interface::{Base58, Parameters};
|
||||
use credential_storage::storage::Storage;
|
||||
use credential_storage::PersistentStorage;
|
||||
use credentials::coconut::bandwidth::{BandwidthVoucher, TOTAL_ATTRIBUTES};
|
||||
use credentials::coconut::utils::obtain_aggregate_signature;
|
||||
use crypto::asymmetric::{encryption, identity};
|
||||
use network_defaults::{NymNetworkDetails, VOUCHER_INFO};
|
||||
use nym_coconut_interface::{Base58, Parameters};
|
||||
use nym_credential_storage::storage::Storage;
|
||||
use nym_credential_storage::PersistentStorage;
|
||||
use nym_credentials::coconut::bandwidth::{BandwidthVoucher, TOTAL_ATTRIBUTES};
|
||||
use nym_credentials::coconut::utils::obtain_aggregate_signature;
|
||||
use nym_crypto::asymmetric::{encryption, identity};
|
||||
use nym_network_defaults::VOUCHER_INFO;
|
||||
use validator_client::nyxd::traits::DkgQueryClient;
|
||||
use validator_client::nyxd::tx::Hash;
|
||||
use validator_client::{CoconutApiClient, Config};
|
||||
use validator_client::nyxd::CosmWasmClient;
|
||||
use validator_client::CoconutApiClient;
|
||||
|
||||
use crate::client::Client;
|
||||
use crate::error::{CredentialClientError, Result};
|
||||
use crate::recovery_storage::RecoveryStorage;
|
||||
use crate::state::{KeyPair, State};
|
||||
|
||||
#[derive(Subcommand)]
|
||||
pub(crate) enum Command {
|
||||
/// Run the binary
|
||||
/// Run the binary to obtain a credential
|
||||
Run(Run),
|
||||
|
||||
/// Generate shell completions
|
||||
@@ -34,6 +37,11 @@ pub(crate) enum Command {
|
||||
}
|
||||
|
||||
#[derive(Args)]
|
||||
#[clap(group(
|
||||
ArgGroup::new("recov")
|
||||
.required(true)
|
||||
.args(&["amount", "recovery_mode"]),
|
||||
))]
|
||||
pub(crate) struct Run {
|
||||
/// Home directory of the client that is supposed to use the credential.
|
||||
#[clap(long)]
|
||||
@@ -47,15 +55,25 @@ pub(crate) struct Run {
|
||||
#[clap(long)]
|
||||
pub(crate) mnemonic: String,
|
||||
|
||||
/// The amount of utokens the credential will hold
|
||||
#[clap(long)]
|
||||
/// The amount of utokens the credential will hold. If recovery mode is enabled, this value
|
||||
/// is not needed
|
||||
#[clap(long, default_value = "0")]
|
||||
pub(crate) amount: u64,
|
||||
|
||||
/// Path to a directory used to store recovery files for unconsumed deposits
|
||||
#[clap(long)]
|
||||
pub(crate) recovery_dir: std::path::PathBuf,
|
||||
|
||||
/// Recovery mode, when enabled, tries to recover any deposit data dumped in recovery_dir
|
||||
#[clap(long)]
|
||||
pub(crate) recovery_mode: bool,
|
||||
}
|
||||
|
||||
pub(crate) async fn deposit(nyxd_url: &str, mnemonic: &str, amount: u64) -> Result<State> {
|
||||
let mut rng = OsRng;
|
||||
let signing_keypair = KeyPair::from(identity::KeyPair::new(&mut rng));
|
||||
let encryption_keypair = KeyPair::from(encryption::KeyPair::new(&mut rng));
|
||||
let params = Parameters::new(TOTAL_ATTRIBUTES).unwrap();
|
||||
|
||||
let client = Client::new(nyxd_url, mnemonic);
|
||||
let tx_hash = client
|
||||
@@ -67,46 +85,47 @@ pub(crate) async fn deposit(nyxd_url: &str, mnemonic: &str, amount: u64) -> Resu
|
||||
)
|
||||
.await?;
|
||||
|
||||
let state = State {
|
||||
amount,
|
||||
tx_hash,
|
||||
signing_keypair,
|
||||
encryption_keypair,
|
||||
};
|
||||
let voucher = BandwidthVoucher::new(
|
||||
¶ms,
|
||||
amount.to_string(),
|
||||
VOUCHER_INFO.to_string(),
|
||||
Hash::from_str(&tx_hash).map_err(|_| CredentialClientError::InvalidTxHash)?,
|
||||
identity::PrivateKey::from_base58_string(&signing_keypair.private_key)?,
|
||||
encryption::PrivateKey::from_base58_string(&encryption_keypair.private_key)?,
|
||||
);
|
||||
|
||||
let state = State { voucher, params };
|
||||
|
||||
Ok(state)
|
||||
}
|
||||
|
||||
pub(crate) async fn get_credential(state: &State, shared_storage: PersistentStorage) -> Result<()> {
|
||||
let network_details = NymNetworkDetails::new_from_env();
|
||||
let config = Config::try_from_nym_network_details(&network_details)?;
|
||||
let client = validator_client::Client::new_query(config)?;
|
||||
pub(crate) async fn get_credential<C: Clone + CosmWasmClient + Send + Sync>(
|
||||
state: &State,
|
||||
client: validator_client::Client<C>,
|
||||
shared_storage: PersistentStorage,
|
||||
) -> Result<()> {
|
||||
let epoch_id = client.nyxd.get_current_epoch().await?.epoch_id;
|
||||
let threshold = client
|
||||
.nyxd
|
||||
.get_current_epoch_threshold()
|
||||
.await?
|
||||
.ok_or(CredentialClientError::NoThreshold)?;
|
||||
let coconut_api_clients = CoconutApiClient::all_coconut_api_clients(&client, epoch_id).await?;
|
||||
|
||||
let params = Parameters::new(TOTAL_ATTRIBUTES).unwrap();
|
||||
let bandwidth_credential_attributes = BandwidthVoucher::new(
|
||||
¶ms,
|
||||
state.amount.to_string(),
|
||||
VOUCHER_INFO.to_string(),
|
||||
Hash::from_str(&state.tx_hash).map_err(|_| CredentialClientError::InvalidTxHash)?,
|
||||
identity::PrivateKey::from_base58_string(&state.signing_keypair.private_key)?,
|
||||
encryption::PrivateKey::from_base58_string(&state.encryption_keypair.private_key)?,
|
||||
);
|
||||
|
||||
let signature = obtain_aggregate_signature(
|
||||
¶ms,
|
||||
&bandwidth_credential_attributes,
|
||||
&state.params,
|
||||
&state.voucher,
|
||||
&coconut_api_clients,
|
||||
threshold,
|
||||
)
|
||||
.await?;
|
||||
println!("Signature: {:?}", signature.to_bs58());
|
||||
info!("Signature: {:?}", signature.to_bs58());
|
||||
shared_storage
|
||||
.insert_coconut_credential(
|
||||
state.amount.to_string(),
|
||||
state.voucher.get_voucher_value(),
|
||||
VOUCHER_INFO.to_string(),
|
||||
bandwidth_credential_attributes.get_private_attributes()[0].to_bs58(),
|
||||
bandwidth_credential_attributes.get_private_attributes()[1].to_bs58(),
|
||||
state.voucher.get_private_attributes()[0].to_bs58(),
|
||||
state.voucher.get_private_attributes()[1].to_bs58(),
|
||||
signature.to_bs58(),
|
||||
epoch_id.to_string(),
|
||||
)
|
||||
@@ -114,3 +133,33 @@ pub(crate) async fn get_credential(state: &State, shared_storage: PersistentStor
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) async fn recover_credentials<C: Clone + CosmWasmClient + Send + Sync>(
|
||||
client: validator_client::Client<C>,
|
||||
recovery_storage: &RecoveryStorage,
|
||||
shared_storage: PersistentStorage,
|
||||
) -> Result<()> {
|
||||
for voucher in recovery_storage.unconsumed_vouchers()? {
|
||||
let state = State {
|
||||
voucher,
|
||||
params: Parameters::new(TOTAL_ATTRIBUTES).unwrap(),
|
||||
};
|
||||
if let Err(e) = get_credential(&state, client.clone(), shared_storage.clone()).await {
|
||||
error!(
|
||||
"Could not recover deposit {} due to {:?}, try again later",
|
||||
state.voucher.tx_hash(),
|
||||
e
|
||||
)
|
||||
} else {
|
||||
info!(
|
||||
"Converted deposit {} to a credential, removing recovery data for it",
|
||||
state.voucher.tx_hash()
|
||||
);
|
||||
if let Err(e) = recovery_storage.remove_voucher(state.voucher.tx_hash().to_string()) {
|
||||
warn!("Could not remove recovery data - {:?}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use std::time::SystemTimeError;
|
||||
use thiserror::Error;
|
||||
|
||||
use credential_storage::error::StorageError;
|
||||
use credentials::error::Error as CredentialError;
|
||||
use crypto::asymmetric::encryption::KeyRecoveryError;
|
||||
use crypto::asymmetric::identity::Ed25519RecoveryError;
|
||||
use nym_credential_storage::error::StorageError;
|
||||
use nym_credentials::error::Error as CredentialError;
|
||||
use nym_crypto::asymmetric::encryption::KeyRecoveryError;
|
||||
use nym_crypto::asymmetric::identity::Ed25519RecoveryError;
|
||||
use validator_client::nyxd::error::NyxdError;
|
||||
use validator_client::ValidatorClientError;
|
||||
|
||||
@@ -14,6 +15,9 @@ pub type Result<T> = std::result::Result<T, CredentialClientError>;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum CredentialClientError {
|
||||
#[error("IO error: {0}")]
|
||||
IOError(#[from] std::io::Error),
|
||||
|
||||
#[error("Nyxd error: {0}")]
|
||||
Nyxd(#[from] NyxdError),
|
||||
|
||||
@@ -34,4 +38,10 @@ pub enum CredentialClientError {
|
||||
|
||||
#[error("Could not use shared storage")]
|
||||
SharedStorageError(#[from] StorageError),
|
||||
|
||||
#[error("Could not get system time")]
|
||||
SysTimeError(#[from] SystemTimeError),
|
||||
|
||||
#[error("Threshold not set yet")]
|
||||
NoThreshold,
|
||||
}
|
||||
|
||||
@@ -4,15 +4,25 @@
|
||||
mod client;
|
||||
mod commands;
|
||||
mod error;
|
||||
mod recovery_storage;
|
||||
mod state;
|
||||
|
||||
use commands::*;
|
||||
use completions::fig_generate;
|
||||
use config::{DATA_DIR, DB_FILE_NAME};
|
||||
use error::Result;
|
||||
use network_defaults::setup_env;
|
||||
use log::*;
|
||||
use nym_bin_common::completions::fig_generate;
|
||||
use nym_config::{CRED_DB_FILE_NAME, DATA_DIR};
|
||||
use nym_network_defaults::{setup_env, NymNetworkDetails};
|
||||
use std::process::exit;
|
||||
use std::time::{Duration, SystemTime};
|
||||
|
||||
use clap::{CommandFactory, Parser};
|
||||
use nym_bin_common::logging::setup_logging;
|
||||
use validator_client::nyxd::traits::DkgQueryClient;
|
||||
use validator_client::nyxd::CosmWasmClient;
|
||||
use validator_client::Config;
|
||||
|
||||
const SAFETY_BUFFER_SECS: u64 = 60; // 1 minute
|
||||
|
||||
#[derive(Parser)]
|
||||
#[clap(author = "Nymtech", version, about)]
|
||||
@@ -25,19 +35,77 @@ struct Cli {
|
||||
pub(crate) command: Command,
|
||||
}
|
||||
|
||||
async fn block_until_coconut_is_available<C: Clone + CosmWasmClient + Send + Sync>(
|
||||
client: &validator_client::Client<C>,
|
||||
) -> Result<()> {
|
||||
loop {
|
||||
let epoch = client.nyxd.get_current_epoch().await?;
|
||||
let current_timestamp_secs = SystemTime::now()
|
||||
.duration_since(SystemTime::UNIX_EPOCH)?
|
||||
.as_secs();
|
||||
if epoch.state.is_final() {
|
||||
if current_timestamp_secs + SAFETY_BUFFER_SECS >= epoch.finish_timestamp.seconds() {
|
||||
info!("In the next {} minute(s), a transition will take place in the coconut system. Deposits should be halted in this time for safety reasons.", SAFETY_BUFFER_SECS / 60);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
break;
|
||||
} else {
|
||||
// Use 1 additional second to not start the next iteration immediately and spam get_current_epoch queries
|
||||
let secs_until_final = epoch
|
||||
.final_timestamp_secs()
|
||||
.saturating_sub(current_timestamp_secs)
|
||||
+ 1;
|
||||
info!("Approximately {} seconds until coconut is available. Sleeping until then. You can safely kill the process at any moment.", secs_until_final);
|
||||
std::thread::sleep(Duration::from_secs(secs_until_final));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<()> {
|
||||
let args = Cli::parse();
|
||||
setup_logging();
|
||||
setup_env(args.config_env_file.as_ref());
|
||||
let bin_name = "nym-credential-client";
|
||||
|
||||
match args.command {
|
||||
Command::Run(r) => {
|
||||
let db_path = r.client_home_directory.join(DATA_DIR).join(DB_FILE_NAME);
|
||||
let shared_storage = credential_storage::initialise_storage(db_path).await;
|
||||
let db_path = r
|
||||
.client_home_directory
|
||||
.join(DATA_DIR)
|
||||
.join(CRED_DB_FILE_NAME);
|
||||
let shared_storage = nym_credential_storage::initialise_storage(db_path).await;
|
||||
let recovery_storage = recovery_storage::RecoveryStorage::new(r.recovery_dir)?;
|
||||
|
||||
let state = deposit(&r.nyxd_url, &r.mnemonic, r.amount).await?;
|
||||
get_credential(&state, shared_storage).await?;
|
||||
let network_details = NymNetworkDetails::new_from_env();
|
||||
let config = Config::try_from_nym_network_details(&network_details)?;
|
||||
let client = validator_client::Client::new_query(config)?;
|
||||
|
||||
block_until_coconut_is_available(&client).await?;
|
||||
info!("Starting depositing funds, don't kill the process");
|
||||
|
||||
if !r.recovery_mode {
|
||||
let state = deposit(&r.nyxd_url, &r.mnemonic, r.amount).await?;
|
||||
if get_credential(&state, client, shared_storage)
|
||||
.await
|
||||
.is_err()
|
||||
{
|
||||
warn!("Failed to obtain credential. Dumping recovery data.",);
|
||||
match recovery_storage.insert_voucher(&state.voucher) {
|
||||
Ok(file_path) => {
|
||||
warn!("Dumped recovery data to {:?}. Try using recovery mode to convert it to a credential", file_path);
|
||||
}
|
||||
Err(e) => {
|
||||
error!("Could not dump recovery data to file system due to {:?}, the deposit will be lost!", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
recover_credentials(client, &recovery_storage, shared_storage).await?;
|
||||
}
|
||||
}
|
||||
Command::Completions(c) => c.generate(&mut crate::Cli::command(), bin_name),
|
||||
Command::GenerateFigSpec => fig_generate(&mut crate::Cli::command(), bin_name),
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use nym_credentials::coconut::bandwidth::BandwidthVoucher;
|
||||
use std::fs::{create_dir_all, read_dir, File};
|
||||
use std::io::{Read, Write};
|
||||
use std::path::PathBuf;
|
||||
|
||||
pub struct RecoveryStorage {
|
||||
recovery_dir: PathBuf,
|
||||
}
|
||||
|
||||
impl RecoveryStorage {
|
||||
pub fn new(recovery_dir: PathBuf) -> std::io::Result<Self> {
|
||||
create_dir_all(&recovery_dir)?;
|
||||
Ok(Self { recovery_dir })
|
||||
}
|
||||
|
||||
pub fn unconsumed_vouchers(&self) -> std::io::Result<impl Iterator<Item = BandwidthVoucher>> {
|
||||
Ok(read_dir(&self.recovery_dir)?
|
||||
.filter_map(|entry| entry.ok())
|
||||
.filter_map(|entry| {
|
||||
let path = entry.path();
|
||||
if path.is_file() {
|
||||
Some(path)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.filter_map(|path| File::open(path).ok())
|
||||
.filter_map(|mut f| {
|
||||
let mut buff = Vec::new();
|
||||
if f.read_to_end(&mut buff).is_ok() {
|
||||
Some(buff)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.filter_map(|buff| BandwidthVoucher::try_from_bytes(&buff).ok()))
|
||||
}
|
||||
|
||||
pub fn insert_voucher(&self, voucher: &BandwidthVoucher) -> std::io::Result<PathBuf> {
|
||||
let file_name = voucher.tx_hash().to_string();
|
||||
let file_path = self.recovery_dir.join(file_name);
|
||||
let mut file = File::create(&file_path)?;
|
||||
let buff = voucher.to_bytes();
|
||||
file.write_all(&buff)?;
|
||||
|
||||
Ok(file_path)
|
||||
}
|
||||
|
||||
pub fn remove_voucher(&self, file_name: String) -> std::io::Result<()> {
|
||||
let file_path = self.recovery_dir.join(file_name);
|
||||
std::fs::remove_file(file_path)
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use nym_coconut_interface::Parameters;
|
||||
use nym_credentials::coconut::bandwidth::BandwidthVoucher;
|
||||
|
||||
use crypto::asymmetric::{encryption, identity};
|
||||
use nym_crypto::asymmetric::{encryption, identity};
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
pub(crate) struct KeyPair {
|
||||
pub public_key: String,
|
||||
pub private_key: String,
|
||||
@@ -29,10 +29,7 @@ impl From<encryption::KeyPair> for KeyPair {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
pub(crate) struct State {
|
||||
pub amount: u64,
|
||||
pub tx_hash: String,
|
||||
pub signing_keypair: KeyPair,
|
||||
pub encryption_keypair: KeyPair,
|
||||
pub voucher: BandwidthVoucher,
|
||||
pub params: Parameters,
|
||||
}
|
||||
|
||||
+12
-16
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "nym-client"
|
||||
version = "1.1.7"
|
||||
version = "1.1.12"
|
||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"]
|
||||
description = "Implementation of the Nym Client"
|
||||
edition = "2021"
|
||||
@@ -34,25 +34,21 @@ tokio = { version = "1.24.1", features = ["rt-multi-thread", "net", "signal"] }
|
||||
tokio-tungstenite = "0.14" # websocket
|
||||
|
||||
## internal
|
||||
build-information = { path = "../../common/build-information" }
|
||||
nym-bin-common = { path = "../../common/bin-common" }
|
||||
client-core = { path = "../client-core", features = ["fs-surb-storage"] }
|
||||
client-connections = { path = "../../common/client-connections" }
|
||||
coconut-interface = { path = "../../common/coconut-interface" }
|
||||
config = { path = "../../common/config" }
|
||||
completions = { path = "../../common/completions" }
|
||||
credential-storage = { path = "../../common/credential-storage" }
|
||||
credentials = { path = "../../common/credentials" }
|
||||
crypto = { path = "../../common/crypto" }
|
||||
logging = { path = "../../common/logging"}
|
||||
nym-coconut-interface = { path = "../../common/coconut-interface" }
|
||||
nym-config = { path = "../../common/config" }
|
||||
nym-credential-storage = { path = "../../common/credential-storage" }
|
||||
nym-credentials = { path = "../../common/credentials" }
|
||||
nym-crypto = { path = "../../common/crypto" }
|
||||
gateway-client = { path = "../../common/client-libs/gateway-client" }
|
||||
gateway-requests = { path = "../../gateway/gateway-requests" }
|
||||
network-defaults = { path = "../../common/network-defaults" }
|
||||
nymsphinx = { path = "../../common/nymsphinx" }
|
||||
pemstore = { path = "../../common/pemstore" }
|
||||
task = { path = "../../common/task" }
|
||||
topology = { path = "../../common/topology" }
|
||||
nym-network-defaults = { path = "../../common/network-defaults" }
|
||||
nym-sphinx = { path = "../../common/nymsphinx" }
|
||||
nym-pemstore = { path = "../../common/pemstore" }
|
||||
nym-task = { path = "../../common/task" }
|
||||
nym-topology = { path = "../../common/topology" }
|
||||
validator-client = { path = "../../common/client-libs/validator-client", features = ["nyxd-client"] }
|
||||
version-checker = { path = "../../common/version-checker" }
|
||||
websocket-requests = { path = "websocket-requests" }
|
||||
|
||||
[dev-dependencies]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use futures::{SinkExt, StreamExt};
|
||||
use nymsphinx::addressing::clients::Recipient;
|
||||
use nym_sphinx::addressing::clients::Recipient;
|
||||
use tokio::net::TcpStream;
|
||||
use tokio_tungstenite::{
|
||||
connect_async, tungstenite::protocol::Message, MaybeTlsStream, WebSocketStream,
|
||||
|
||||
@@ -2,16 +2,19 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::client::config::template::config_template;
|
||||
pub use client_core::config::Config as BaseConfig;
|
||||
pub use client_core::config::MISSING_VALUE;
|
||||
use client_core::config::{ClientCoreConfigTrait, DebugConfig};
|
||||
use config::defaults::DEFAULT_WEBSOCKET_LISTENING_PORT;
|
||||
use config::{NymConfig, OptionalSet};
|
||||
use client_core::config::ClientCoreConfigTrait;
|
||||
use nym_config::defaults::DEFAULT_WEBSOCKET_LISTENING_PORT;
|
||||
use nym_config::{NymConfig, OptionalSet};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt::Debug;
|
||||
use std::net::{IpAddr, Ipv4Addr};
|
||||
use std::path::PathBuf;
|
||||
use std::str::FromStr;
|
||||
|
||||
pub use client_core::config::Config as BaseConfig;
|
||||
pub use client_core::config::MISSING_VALUE;
|
||||
pub use client_core::config::{DebugConfig, GatewayEndpointConfig};
|
||||
|
||||
mod template;
|
||||
|
||||
#[derive(Debug, Deserialize, PartialEq, Eq, Serialize, Clone, Copy)]
|
||||
@@ -104,6 +107,11 @@ impl Config {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_host(mut self, host: IpAddr) -> Self {
|
||||
self.socket.host = host;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_port(mut self, port: u16) -> Self {
|
||||
self.socket.listening_port = port;
|
||||
self
|
||||
@@ -130,6 +138,10 @@ impl Config {
|
||||
self.socket.socket_type
|
||||
}
|
||||
|
||||
pub fn get_listening_ip(&self) -> IpAddr {
|
||||
self.socket.host
|
||||
}
|
||||
|
||||
pub fn get_listening_port(&self) -> u16 {
|
||||
self.socket.listening_port
|
||||
}
|
||||
@@ -180,9 +192,10 @@ impl Config {
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, PartialEq, Eq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
pub struct Socket {
|
||||
socket_type: SocketType,
|
||||
host: IpAddr,
|
||||
listening_port: u16,
|
||||
}
|
||||
|
||||
@@ -190,6 +203,7 @@ impl Default for Socket {
|
||||
fn default() -> Self {
|
||||
Socket {
|
||||
socket_type: SocketType::WebSocket,
|
||||
host: IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)),
|
||||
listening_port: DEFAULT_WEBSOCKET_LISTENING_PORT,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,6 +93,9 @@ socket_type = '{{ socket.socket_type }}'
|
||||
# will be listening for incoming requests
|
||||
listening_port = {{ socket.listening_port }}
|
||||
|
||||
# if applicable (for the case of 'WebSocket'), the ip address on which the client
|
||||
# will be listening for incoming requests
|
||||
host = '{{ socket.host }}'
|
||||
|
||||
##### logging configuration options #####
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user