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
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: 16
|
node-version: 16
|
||||||
- name: Keybase - Node Install
|
- name: Matrix - Node Install
|
||||||
run: npm install
|
run: npm install
|
||||||
working-directory: .github/workflows/support-files
|
working-directory: .github/workflows/support-files
|
||||||
- name: Keybase - Send Notification
|
- name: Matrix - Send Notification
|
||||||
env:
|
env:
|
||||||
NYM_NOTIFICATION_KIND: security
|
NYM_NOTIFICATION_KIND: security
|
||||||
NYM_PROJECT_NAME: "Daily security report"
|
NYM_PROJECT_NAME: "Daily security report"
|
||||||
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
|
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_SERVER: "${{ secrets.MATRIX_SERVER }}"
|
||||||
MATRIX_ROOM: "${{ secrets.MATRIX_ROOM }}"
|
MATRIX_ROOM: "${{ secrets.MATRIX_ROOM_AUDIT }}"
|
||||||
MATRIX_USER_ID: "${{ secrets.MATRIX_USER_ID }}"
|
MATRIX_USER_ID: "${{ secrets.MATRIX_USER_ID }}"
|
||||||
MATRIX_TOKEN: "${{ secrets.MATRIX_TOKEN }}"
|
MATRIX_TOKEN: "${{ secrets.MATRIX_TOKEN }}"
|
||||||
MATRIX_DEVICE_ID: "${{ secrets.MATRIX_DEVICE_ID }}"
|
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 }}
|
REMOTE_USER: ${{ secrets.CI_WWW_REMOTE_USER }}
|
||||||
TARGET: ${{ secrets.CI_WWW_REMOTE_TARGET }}/ts-${{ env.GITHUB_REF_SLUG }}-example
|
TARGET: ${{ secrets.CI_WWW_REMOTE_TARGET }}/ts-${{ env.GITHUB_REF_SLUG }}-example
|
||||||
EXCLUDE: "/dist/, /node_modules/"
|
EXCLUDE: "/dist/, /node_modules/"
|
||||||
- name: Keybase - Node Install
|
- name: Matrix - Node Install
|
||||||
run: npm install
|
run: npm install
|
||||||
working-directory: .github/workflows/support-files
|
working-directory: .github/workflows/support-files
|
||||||
- name: Keybase - Send Notification
|
- name: Matrix - Send Notification
|
||||||
env:
|
env:
|
||||||
NYM_NOTIFICATION_KIND: ts-packages
|
NYM_NOTIFICATION_KIND: ts-packages
|
||||||
NYM_PROJECT_NAME: "ts-packages"
|
NYM_PROJECT_NAME: "ts-packages"
|
||||||
@@ -54,10 +54,6 @@ jobs:
|
|||||||
NYM_CI_WWW_LOCATION: "ts-${{ env.GITHUB_REF_SLUG }}"
|
NYM_CI_WWW_LOCATION: "ts-${{ env.GITHUB_REF_SLUG }}"
|
||||||
GIT_COMMIT_MESSAGE: "${{ github.event.head_commit.message }}"
|
GIT_COMMIT_MESSAGE: "${{ github.event.head_commit.message }}"
|
||||||
GIT_BRANCH: "${GITHUB_REF##*/}"
|
GIT_BRANCH: "${GITHUB_REF##*/}"
|
||||||
KEYBASE_NYMBOT_USERNAME: "${{ secrets.KEYBASE_NYMBOT_USERNAME }}"
|
|
||||||
KEYBASE_NYMBOT_PAPERKEY: "${{ secrets.KEYBASE_NYMBOT_PAPERKEY }}"
|
|
||||||
KEYBASE_NYMBOT_TEAM: "${{ secrets.KEYBASE_NYMBOT_TEAM }}"
|
|
||||||
KEYBASE_NYM_CHANNEL: "ci-ts-packages"
|
|
||||||
IS_SUCCESS: "${{ job.status == 'success' }}"
|
IS_SUCCESS: "${{ job.status == 'success' }}"
|
||||||
MATRIX_SERVER: "${{ secrets.MATRIX_SERVER }}"
|
MATRIX_SERVER: "${{ secrets.MATRIX_SERVER }}"
|
||||||
MATRIX_ROOM: "${{ secrets.MATRIX_ROOM }}"
|
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:
|
on:
|
||||||
push:
|
push:
|
||||||
paths:
|
paths:
|
||||||
- 'nym-connect/**'
|
- 'nym-connect/desktop/**'
|
||||||
|
|
||||||
defaults:
|
defaults:
|
||||||
run:
|
run:
|
||||||
working-directory: nym-connect
|
working-directory: nym-connect/desktop
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
@@ -34,15 +34,15 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
SSH_PRIVATE_KEY: ${{ secrets.CI_WWW_SSH_PRIVATE_KEY }}
|
SSH_PRIVATE_KEY: ${{ secrets.CI_WWW_SSH_PRIVATE_KEY }}
|
||||||
ARGS: "-rltgoDzvO --delete"
|
ARGS: "-rltgoDzvO --delete"
|
||||||
SOURCE: "nym-connect/storybook-static/"
|
SOURCE: "nym-connect/desktop/storybook-static/"
|
||||||
REMOTE_HOST: ${{ secrets.CI_WWW_REMOTE_HOST }}
|
REMOTE_HOST: ${{ secrets.CI_WWW_REMOTE_HOST }}
|
||||||
REMOTE_USER: ${{ secrets.CI_WWW_REMOTE_USER }}
|
REMOTE_USER: ${{ secrets.CI_WWW_REMOTE_USER }}
|
||||||
TARGET: ${{ secrets.CI_WWW_REMOTE_TARGET }}/nym-connect-${{ env.GITHUB_REF_SLUG }}
|
TARGET: ${{ secrets.CI_WWW_REMOTE_TARGET }}/nym-connect-${{ env.GITHUB_REF_SLUG }}
|
||||||
EXCLUDE: "/dist/, /node_modules/"
|
EXCLUDE: "/dist/, /node_modules/"
|
||||||
- name: Keybase - Node Install
|
- name: Matrix - Node Install
|
||||||
run: npm install
|
run: npm install
|
||||||
working-directory: .github/workflows/support-files
|
working-directory: .github/workflows/support-files
|
||||||
- name: Keybase - Send Notification
|
- name: Matrix - Send Notification
|
||||||
env:
|
env:
|
||||||
NYM_NOTIFICATION_KIND: nym-connect
|
NYM_NOTIFICATION_KIND: nym-connect
|
||||||
NYM_PROJECT_NAME: "nym-connect"
|
NYM_PROJECT_NAME: "nym-connect"
|
||||||
@@ -50,10 +50,6 @@ jobs:
|
|||||||
NYM_CI_WWW_LOCATION: "nym-connect-${{ env.GITHUB_REF_SLUG }}"
|
NYM_CI_WWW_LOCATION: "nym-connect-${{ env.GITHUB_REF_SLUG }}"
|
||||||
GIT_COMMIT_MESSAGE: "${{ github.event.head_commit.message }}"
|
GIT_COMMIT_MESSAGE: "${{ github.event.head_commit.message }}"
|
||||||
GIT_BRANCH: "${GITHUB_REF##*/}"
|
GIT_BRANCH: "${GITHUB_REF##*/}"
|
||||||
KEYBASE_NYMBOT_USERNAME: "${{ secrets.KEYBASE_NYMBOT_USERNAME }}"
|
|
||||||
KEYBASE_NYMBOT_PAPERKEY: "${{ secrets.KEYBASE_NYMBOT_PAPERKEY }}"
|
|
||||||
KEYBASE_NYMBOT_TEAM: "${{ secrets.KEYBASE_NYMBOT_TEAM }}"
|
|
||||||
KEYBASE_NYM_CHANNEL: "ci-nym-connect"
|
|
||||||
IS_SUCCESS: "${{ job.status == 'success' }}"
|
IS_SUCCESS: "${{ job.status == 'success' }}"
|
||||||
MATRIX_SERVER: "${{ secrets.MATRIX_SERVER }}"
|
MATRIX_SERVER: "${{ secrets.MATRIX_SERVER }}"
|
||||||
MATRIX_ROOM: "${{ secrets.MATRIX_ROOM }}"
|
MATRIX_ROOM: "${{ secrets.MATRIX_ROOM }}"
|
||||||
@@ -1,28 +1,30 @@
|
|||||||
name: Nym Connect (rust)
|
name: Nym Connect - desktop (Rust)
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
paths:
|
paths:
|
||||||
- 'nym-connect/**'
|
- "nym-connect/desktop/src-tauri/**"
|
||||||
- 'clients/client-core/**'
|
- "nym-connect/desktop/src-tauri/Cargo.toml"
|
||||||
- 'clients/socks5/**'
|
- "clients/client-core/**"
|
||||||
- 'common/**'
|
- "clients/socks5/**"
|
||||||
- 'gateway/gateway-requests/**'
|
- "common/**"
|
||||||
- 'contracts/vesting/**'
|
- "gateway/gateway-requests/**"
|
||||||
- 'nym-api/nym-api-requests/**'
|
- "contracts/vesting/**"
|
||||||
|
- "nym-api/nym-api-requests/**"
|
||||||
pull_request:
|
pull_request:
|
||||||
paths:
|
paths:
|
||||||
- 'nym-connect/**'
|
- "nym-connect/desktop/src-tauri/**"
|
||||||
- 'clients/client-core/**'
|
- "nym-connect/desktop/src-tauri/Cargo.toml"
|
||||||
- 'clients/socks5/**'
|
- "clients/client-core/**"
|
||||||
- 'common/**'
|
- "clients/socks5/**"
|
||||||
- 'gateway/gateway-requests/**'
|
- "common/**"
|
||||||
- 'contracts/vesting/**'
|
- "gateway/gateway-requests/**"
|
||||||
- 'nym-api/nym-api-requests/**'
|
- "contracts/vesting/**"
|
||||||
|
- "nym-api/nym-api-requests/**"
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: [ self-hosted, custom-linux ]
|
runs-on: [self-hosted, custom-linux]
|
||||||
env:
|
env:
|
||||||
RUSTC_WRAPPER: /home/ubuntu/.cargo/bin/sccache
|
RUSTC_WRAPPER: /home/ubuntu/.cargo/bin/sccache
|
||||||
steps:
|
steps:
|
||||||
@@ -45,29 +47,29 @@ jobs:
|
|||||||
uses: actions-rs/cargo@v1
|
uses: actions-rs/cargo@v1
|
||||||
with:
|
with:
|
||||||
command: build
|
command: build
|
||||||
args: --manifest-path nym-connect/Cargo.toml --workspace
|
args: --manifest-path nym-connect/desktop/Cargo.toml --workspace
|
||||||
|
|
||||||
- name: Run all tests
|
- name: Run all tests
|
||||||
uses: actions-rs/cargo@v1
|
uses: actions-rs/cargo@v1
|
||||||
with:
|
with:
|
||||||
command: test
|
command: test
|
||||||
args: --manifest-path nym-connect/Cargo.toml --workspace
|
args: --manifest-path nym-connect/desktop/Cargo.toml --workspace
|
||||||
|
|
||||||
- name: Check formatting
|
- name: Check formatting
|
||||||
uses: actions-rs/cargo@v1
|
uses: actions-rs/cargo@v1
|
||||||
with:
|
with:
|
||||||
command: fmt
|
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
|
- uses: actions-rs/clippy-check@v1
|
||||||
name: Clippy checks
|
name: Clippy checks
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
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
|
- name: Run clippy
|
||||||
uses: actions-rs/cargo@v1
|
uses: actions-rs/cargo@v1
|
||||||
with:
|
with:
|
||||||
command: clippy
|
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:
|
on:
|
||||||
push:
|
push:
|
||||||
paths:
|
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/client-core/**"
|
||||||
- "clients/socks5/**"
|
- "clients/socks5/**"
|
||||||
- "common/**"
|
- "common/**"
|
||||||
@@ -12,7 +14,9 @@ on:
|
|||||||
- "nym-api/nym-api-requests/**"
|
- "nym-api/nym-api-requests/**"
|
||||||
pull_request:
|
pull_request:
|
||||||
paths:
|
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/client-core/**"
|
||||||
- "clients/socks5/**"
|
- "clients/socks5/**"
|
||||||
- "common/**"
|
- "common/**"
|
||||||
@@ -28,10 +32,9 @@ jobs:
|
|||||||
#RUSTC_WRAPPER: /home/ubuntu/.cargo/bin/sccache
|
#RUSTC_WRAPPER: /home/ubuntu/.cargo/bin/sccache
|
||||||
#defaults:
|
#defaults:
|
||||||
#run:
|
#run:
|
||||||
#working-directory: nym-connect-android/src-tauri/
|
#working-directory: nym-connect/mobile/src-tauri/
|
||||||
steps:
|
steps:
|
||||||
- name: Install Dependencies (Linux)
|
- name: Install Dependencies (Linux)
|
||||||
if: ${{ !env.ACT }}
|
|
||||||
run: |
|
run: |
|
||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get -y install \
|
sudo apt-get -y install \
|
||||||
@@ -46,7 +49,6 @@ jobs:
|
|||||||
librsvg2-dev \
|
librsvg2-dev \
|
||||||
libsoup-3.0-dev \
|
libsoup-3.0-dev \
|
||||||
libjavascriptcoregtk-4.1-dev
|
libjavascriptcoregtk-4.1-dev
|
||||||
#continue-on-error: true
|
|
||||||
|
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
@@ -58,13 +60,13 @@ jobs:
|
|||||||
components: clippy, rustfmt
|
components: clippy, rustfmt
|
||||||
|
|
||||||
- name: Check formatting
|
- 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
|
- 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
|
- 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
|
- 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:
|
jobs:
|
||||||
build:
|
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]
|
runs-on: [self-hosted, custom-runner-linux]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
@@ -19,6 +19,9 @@ jobs:
|
|||||||
override: true
|
override: true
|
||||||
components: rustfmt, clippy
|
components: rustfmt, clippy
|
||||||
|
|
||||||
|
- name: Install wasm-opt
|
||||||
|
run: cargo install wasm-opt
|
||||||
|
|
||||||
- name: Build release contracts
|
- name: Build release contracts
|
||||||
run: make wasm
|
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 }}
|
REMOTE_USER: ${{ secrets.CI_WWW_REMOTE_USER }}
|
||||||
TARGET: ${{ secrets.CI_WWW_REMOTE_TARGET }}/ne-sb-${{ env.GITHUB_REF_SLUG }}
|
TARGET: ${{ secrets.CI_WWW_REMOTE_TARGET }}/ne-sb-${{ env.GITHUB_REF_SLUG }}
|
||||||
EXCLUDE: "/dist/, /node_modules/"
|
EXCLUDE: "/dist/, /node_modules/"
|
||||||
- name: Keybase - Node Install
|
- name: Matrix - Node Install
|
||||||
run: npm install
|
run: npm install
|
||||||
working-directory: .github/workflows/support-files
|
working-directory: .github/workflows/support-files
|
||||||
- name: Keybase - Send Notification
|
- name: Matrix - Send Notification
|
||||||
env:
|
env:
|
||||||
NYM_NOTIFICATION_KIND: network-explorer
|
NYM_NOTIFICATION_KIND: network-explorer
|
||||||
NYM_PROJECT_NAME: "Network Explorer"
|
NYM_PROJECT_NAME: "Network Explorer"
|
||||||
@@ -69,10 +69,6 @@ jobs:
|
|||||||
NYM_CI_WWW_LOCATION_STORYBOOK: "ne-sb-${{ env.GITHUB_REF_SLUG }}"
|
NYM_CI_WWW_LOCATION_STORYBOOK: "ne-sb-${{ env.GITHUB_REF_SLUG }}"
|
||||||
GIT_COMMIT_MESSAGE: "${{ github.event.head_commit.message }}"
|
GIT_COMMIT_MESSAGE: "${{ github.event.head_commit.message }}"
|
||||||
GIT_BRANCH: "${GITHUB_REF##*/}"
|
GIT_BRANCH: "${GITHUB_REF##*/}"
|
||||||
KEYBASE_NYMBOT_USERNAME: "${{ secrets.KEYBASE_NYMBOT_USERNAME }}"
|
|
||||||
KEYBASE_NYMBOT_PAPERKEY: "${{ secrets.KEYBASE_NYMBOT_PAPERKEY }}"
|
|
||||||
KEYBASE_NYMBOT_TEAM: "${{ secrets.KEYBASE_NYMBOT_TEAM }}"
|
|
||||||
KEYBASE_NYM_CHANNEL: "ci-network-explorer"
|
|
||||||
IS_SUCCESS: "${{ job.status == 'success' }}"
|
IS_SUCCESS: "${{ job.status == 'success' }}"
|
||||||
MATRIX_SERVER: "${{ secrets.MATRIX_SERVER }}"
|
MATRIX_SERVER: "${{ secrets.MATRIX_SERVER }}"
|
||||||
MATRIX_ROOM: "${{ secrets.MATRIX_ROOM }}"
|
MATRIX_ROOM: "${{ secrets.MATRIX_ROOM }}"
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ jobs:
|
|||||||
matrix: ${{ steps.set-matrix.outputs.matrix }}
|
matrix: ${{ steps.set-matrix.outputs.matrix }}
|
||||||
steps:
|
steps:
|
||||||
# creates the matrix strategy from nightly_build_matrix_includes.json
|
# creates the matrix strategy from nightly_build_matrix_includes.json
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- id: set-matrix
|
- id: set-matrix
|
||||||
uses: JoshuaTheMiller/conditional-build-matrix@main
|
uses: JoshuaTheMiller/conditional-build-matrix@main
|
||||||
with:
|
with:
|
||||||
@@ -29,7 +29,7 @@ jobs:
|
|||||||
if: matrix.os == 'ubuntu-20.04'
|
if: matrix.os == 'ubuntu-20.04'
|
||||||
|
|
||||||
- name: Check out repository code
|
- name: Check out repository code
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Install rust toolchain
|
- name: Install rust toolchain
|
||||||
uses: actions-rs/toolchain@v1
|
uses: actions-rs/toolchain@v1
|
||||||
@@ -51,9 +51,9 @@ jobs:
|
|||||||
command: build
|
command: build
|
||||||
args: --workspace
|
args: --workspace
|
||||||
|
|
||||||
- name: Reclaim some disk space (because Windows is being annoying)
|
- name: Reclaim some disk space
|
||||||
uses: actions-rs/cargo@v1
|
uses: actions-rs/cargo@v1
|
||||||
if: ${{ matrix.os == 'windows-latest' }}
|
if: ${{ matrix.os == 'windows-latest' || matrix.os == 'ubuntu-20.04' }}
|
||||||
with:
|
with:
|
||||||
command: clean
|
command: clean
|
||||||
|
|
||||||
@@ -63,9 +63,9 @@ jobs:
|
|||||||
command: build
|
command: build
|
||||||
args: --workspace --examples
|
args: --workspace --examples
|
||||||
|
|
||||||
- name: Reclaim some disk space (because Windows is being annoying)
|
- name: Reclaim some disk space
|
||||||
uses: actions-rs/cargo@v1
|
uses: actions-rs/cargo@v1
|
||||||
if: ${{ matrix.os == 'windows-latest' }}
|
if: ${{ matrix.os == 'windows-latest' || matrix.os == 'ubuntu-20.04' }}
|
||||||
with:
|
with:
|
||||||
command: clean
|
command: clean
|
||||||
|
|
||||||
@@ -75,7 +75,7 @@ jobs:
|
|||||||
command: test
|
command: test
|
||||||
args: --workspace
|
args: --workspace
|
||||||
|
|
||||||
- name: Reclaim some disk space (because Windows is being annoying)
|
- name: Reclaim some disk space
|
||||||
uses: actions-rs/cargo@v1
|
uses: actions-rs/cargo@v1
|
||||||
if: ${{ matrix.os == 'windows-latest' || matrix.os == 'ubuntu-20.04' }}
|
if: ${{ matrix.os == 'windows-latest' || matrix.os == 'ubuntu-20.04' }}
|
||||||
with:
|
with:
|
||||||
@@ -88,9 +88,9 @@ jobs:
|
|||||||
command: test
|
command: test
|
||||||
args: --workspace -- --ignored
|
args: --workspace -- --ignored
|
||||||
|
|
||||||
- name: Reclaim some disk space (because Windows is being annoying)
|
- name: Reclaim some disk space
|
||||||
uses: actions-rs/cargo@v1
|
uses: actions-rs/cargo@v1
|
||||||
if: ${{ matrix.os == 'windows-latest' }}
|
if: ${{ matrix.os == 'windows-latest' || matrix.os == 'ubuntu-20.04' }}
|
||||||
with:
|
with:
|
||||||
command: clean
|
command: clean
|
||||||
|
|
||||||
@@ -147,17 +147,17 @@ jobs:
|
|||||||
- name: Collect jobs status
|
- name: Collect jobs status
|
||||||
uses: technote-space/workflow-conclusion-action@v2
|
uses: technote-space/workflow-conclusion-action@v2
|
||||||
- name: Check out repository code
|
- name: Check out repository code
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
- name: install npm
|
- name: install npm
|
||||||
uses: actions/setup-node@v3
|
uses: actions/setup-node@v3
|
||||||
if: env.WORKFLOW_CONCLUSION == 'failure'
|
if: env.WORKFLOW_CONCLUSION == 'failure'
|
||||||
with:
|
with:
|
||||||
node-version: 16
|
node-version: 16
|
||||||
- name: Keybase - Node Install
|
- name: Matrix - Node Install
|
||||||
if: env.WORKFLOW_CONCLUSION == 'failure'
|
if: env.WORKFLOW_CONCLUSION == 'failure'
|
||||||
run: npm install
|
run: npm install
|
||||||
working-directory: .github/workflows/support-files
|
working-directory: .github/workflows/support-files
|
||||||
- name: Keybase - Send Notification
|
- name: Matrix - Send Notification
|
||||||
if: env.WORKFLOW_CONCLUSION == 'failure'
|
if: env.WORKFLOW_CONCLUSION == 'failure'
|
||||||
env:
|
env:
|
||||||
NYM_NOTIFICATION_KIND: nightly
|
NYM_NOTIFICATION_KIND: nightly
|
||||||
@@ -165,13 +165,9 @@ jobs:
|
|||||||
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
|
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
|
||||||
GIT_COMMIT_MESSAGE: "${{ github.event.head_commit.message }}"
|
GIT_COMMIT_MESSAGE: "${{ github.event.head_commit.message }}"
|
||||||
GIT_BRANCH: "${GITHUB_REF##*/}"
|
GIT_BRANCH: "${GITHUB_REF##*/}"
|
||||||
KEYBASE_NYMBOT_USERNAME: "${{ secrets.KEYBASE_NYMBOT_USERNAME }}"
|
|
||||||
KEYBASE_NYMBOT_PAPERKEY: "${{ secrets.KEYBASE_NYMBOT_PAPERKEY }}"
|
|
||||||
KEYBASE_NYMBOT_TEAM: "${{ secrets.KEYBASE_NYMBOT_TEAM }}"
|
|
||||||
KEYBASE_NYM_CHANNEL: "ci-nightly"
|
|
||||||
IS_SUCCESS: "${{ env.WORKFLOW_CONCLUSION == 'success' }}"
|
IS_SUCCESS: "${{ env.WORKFLOW_CONCLUSION == 'success' }}"
|
||||||
MATRIX_SERVER: "${{ secrets.MATRIX_SERVER }}"
|
MATRIX_SERVER: "${{ secrets.MATRIX_SERVER }}"
|
||||||
MATRIX_ROOM: "${{ secrets.MATRIX_ROOM }}"
|
MATRIX_ROOM: "${{ secrets.MATRIX_ROOM_NIGHTLY }}"
|
||||||
MATRIX_USER_ID: "${{ secrets.MATRIX_USER_ID }}"
|
MATRIX_USER_ID: "${{ secrets.MATRIX_USER_ID }}"
|
||||||
MATRIX_TOKEN: "${{ secrets.MATRIX_TOKEN }}"
|
MATRIX_TOKEN: "${{ secrets.MATRIX_TOKEN }}"
|
||||||
MATRIX_DEVICE_ID: "${{ secrets.MATRIX_DEVICE_ID }}"
|
MATRIX_DEVICE_ID: "${{ secrets.MATRIX_DEVICE_ID }}"
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ jobs:
|
|||||||
run: git fetch --all
|
run: git fetch --all
|
||||||
- name: Set output variable to latest release branch
|
- name: Set output variable to latest release branch
|
||||||
id: step2
|
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:
|
build:
|
||||||
needs: [get_release,matrix_prep]
|
needs: [get_release,matrix_prep]
|
||||||
strategy:
|
strategy:
|
||||||
@@ -54,15 +54,33 @@ jobs:
|
|||||||
override: true
|
override: true
|
||||||
components: rustfmt, clippy
|
components: rustfmt, clippy
|
||||||
|
|
||||||
|
- name: Check formatting
|
||||||
|
uses: actions-rs/cargo@v1
|
||||||
|
with:
|
||||||
|
command: fmt
|
||||||
|
args: --all -- --check
|
||||||
|
|
||||||
- name: Build all binaries
|
- name: Build all binaries
|
||||||
uses: actions-rs/cargo@v1
|
uses: actions-rs/cargo@v1
|
||||||
with:
|
with:
|
||||||
command: build
|
command: build
|
||||||
args: --workspace
|
args: --workspace
|
||||||
|
|
||||||
- name: Reclaim some disk space (because Windows is being annoying)
|
- name: Reclaim some disk space
|
||||||
uses: actions-rs/cargo@v1
|
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:
|
with:
|
||||||
command: clean
|
command: clean
|
||||||
|
|
||||||
@@ -72,9 +90,9 @@ jobs:
|
|||||||
command: test
|
command: test
|
||||||
args: --workspace
|
args: --workspace
|
||||||
|
|
||||||
- name: Reclaim some disk space (because Windows is being annoying)
|
- name: Reclaim some disk space
|
||||||
uses: actions-rs/cargo@v1
|
uses: actions-rs/cargo@v1
|
||||||
if: ${{ matrix.os == 'windows-latest' }}
|
if: ${{ matrix.os == 'windows-latest' || matrix.os == 'ubuntu-20.04' }}
|
||||||
with:
|
with:
|
||||||
command: clean
|
command: clean
|
||||||
|
|
||||||
@@ -83,17 +101,11 @@ jobs:
|
|||||||
uses: actions-rs/cargo@v1
|
uses: actions-rs/cargo@v1
|
||||||
with:
|
with:
|
||||||
command: test
|
command: test
|
||||||
args: --workspace --all-features -- --ignored
|
args: --workspace -- --ignored
|
||||||
|
|
||||||
- name: Check formatting
|
- name: Reclaim some disk space
|
||||||
uses: actions-rs/cargo@v1
|
uses: actions-rs/cargo@v1
|
||||||
with:
|
if: ${{ matrix.os == 'windows-latest' || matrix.os == 'ubuntu-20.04' }}
|
||||||
command: fmt
|
|
||||||
args: --all -- --check
|
|
||||||
|
|
||||||
- name: Reclaim some disk space (because Windows is being annoying)
|
|
||||||
uses: actions-rs/cargo@v1
|
|
||||||
if: ${{ matrix.os == 'windows-latest' }}
|
|
||||||
with:
|
with:
|
||||||
command: clean
|
command: clean
|
||||||
|
|
||||||
@@ -102,7 +114,7 @@ jobs:
|
|||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
args: --all-features
|
args: --workspace
|
||||||
|
|
||||||
- name: Run clippy
|
- name: Run clippy
|
||||||
uses: actions-rs/cargo@v1
|
uses: actions-rs/cargo@v1
|
||||||
@@ -156,11 +168,11 @@ jobs:
|
|||||||
if: env.WORKFLOW_CONCLUSION == 'failure'
|
if: env.WORKFLOW_CONCLUSION == 'failure'
|
||||||
with:
|
with:
|
||||||
node-version: 16
|
node-version: 16
|
||||||
- name: Keybase - Node Install
|
- name: Matrix - Node Install
|
||||||
if: env.WORKFLOW_CONCLUSION == 'failure'
|
if: env.WORKFLOW_CONCLUSION == 'failure'
|
||||||
run: npm install
|
run: npm install
|
||||||
working-directory: .github/workflows/support-files
|
working-directory: .github/workflows/support-files
|
||||||
- name: Keybase - Send Notification
|
- name: Matrix - Send Notification
|
||||||
if: env.WORKFLOW_CONCLUSION == 'failure'
|
if: env.WORKFLOW_CONCLUSION == 'failure'
|
||||||
env:
|
env:
|
||||||
NYM_NOTIFICATION_KIND: nightly
|
NYM_NOTIFICATION_KIND: nightly
|
||||||
@@ -168,13 +180,9 @@ jobs:
|
|||||||
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
|
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
|
||||||
GIT_COMMIT_MESSAGE: "${{ github.event.head_commit.message }}"
|
GIT_COMMIT_MESSAGE: "${{ github.event.head_commit.message }}"
|
||||||
GIT_BRANCH_NAME: "${{needs.get_release.outputs.output1}}"
|
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' }}"
|
IS_SUCCESS: "${{ env.WORKFLOW_CONCLUSION == 'success' }}"
|
||||||
MATRIX_SERVER: "${{ secrets.MATRIX_SERVER }}"
|
MATRIX_SERVER: "${{ secrets.MATRIX_SERVER }}"
|
||||||
MATRIX_ROOM: "${{ secrets.MATRIX_ROOM }}"
|
MATRIX_ROOM: "${{ secrets.MATRIX_ROOM_NIGHTLY }}"
|
||||||
MATRIX_USER_ID: "${{ secrets.MATRIX_USER_ID }}"
|
MATRIX_USER_ID: "${{ secrets.MATRIX_USER_ID }}"
|
||||||
MATRIX_TOKEN: "${{ secrets.MATRIX_TOKEN }}"
|
MATRIX_TOKEN: "${{ secrets.MATRIX_TOKEN }}"
|
||||||
MATRIX_DEVICE_ID: "${{ secrets.MATRIX_DEVICE_ID }}"
|
MATRIX_DEVICE_ID: "${{ secrets.MATRIX_DEVICE_ID }}"
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ jobs:
|
|||||||
run: git fetch --all
|
run: git fetch --all
|
||||||
- name: Set output variable to latest release branch
|
- name: Set output variable to latest release branch
|
||||||
id: step2
|
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:
|
build:
|
||||||
needs: [get_release,matrix_prep]
|
needs: [get_release,matrix_prep]
|
||||||
strategy:
|
strategy:
|
||||||
@@ -54,6 +54,12 @@ jobs:
|
|||||||
override: true
|
override: true
|
||||||
components: rustfmt, clippy
|
components: rustfmt, clippy
|
||||||
|
|
||||||
|
- name: Check formatting
|
||||||
|
uses: actions-rs/cargo@v1
|
||||||
|
with:
|
||||||
|
command: fmt
|
||||||
|
args: --all -- --check
|
||||||
|
|
||||||
- name: Build all binaries
|
- name: Build all binaries
|
||||||
uses: actions-rs/cargo@v1
|
uses: actions-rs/cargo@v1
|
||||||
with:
|
with:
|
||||||
@@ -66,6 +72,18 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
command: clean
|
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
|
- name: Run all tests
|
||||||
uses: actions-rs/cargo@v1
|
uses: actions-rs/cargo@v1
|
||||||
with:
|
with:
|
||||||
@@ -74,7 +92,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Reclaim some disk space (because Windows is being annoying)
|
- name: Reclaim some disk space (because Windows is being annoying)
|
||||||
uses: actions-rs/cargo@v1
|
uses: actions-rs/cargo@v1
|
||||||
if: ${{ matrix.os == 'windows-latest' }}
|
if: ${{ matrix.os == 'windows-latest' || matrix.os == 'ubuntu-20.04' }}
|
||||||
with:
|
with:
|
||||||
command: clean
|
command: clean
|
||||||
|
|
||||||
@@ -83,13 +101,7 @@ jobs:
|
|||||||
uses: actions-rs/cargo@v1
|
uses: actions-rs/cargo@v1
|
||||||
with:
|
with:
|
||||||
command: test
|
command: test
|
||||||
args: --workspace --all-features -- --ignored
|
args: --workspace -- --ignored
|
||||||
|
|
||||||
- name: Check formatting
|
|
||||||
uses: actions-rs/cargo@v1
|
|
||||||
with:
|
|
||||||
command: fmt
|
|
||||||
args: --all -- --check
|
|
||||||
|
|
||||||
- name: Reclaim some disk space (because Windows is being annoying)
|
- name: Reclaim some disk space (because Windows is being annoying)
|
||||||
uses: actions-rs/cargo@v1
|
uses: actions-rs/cargo@v1
|
||||||
@@ -102,7 +114,7 @@ jobs:
|
|||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
args: --all-features
|
args: --workspace
|
||||||
|
|
||||||
- name: Run clippy
|
- name: Run clippy
|
||||||
uses: actions-rs/cargo@v1
|
uses: actions-rs/cargo@v1
|
||||||
@@ -156,11 +168,11 @@ jobs:
|
|||||||
if: env.WORKFLOW_CONCLUSION == 'failure'
|
if: env.WORKFLOW_CONCLUSION == 'failure'
|
||||||
with:
|
with:
|
||||||
node-version: 16
|
node-version: 16
|
||||||
- name: Keybase - Node Install
|
- name: Matrix - Node Install
|
||||||
if: env.WORKFLOW_CONCLUSION == 'failure'
|
if: env.WORKFLOW_CONCLUSION == 'failure'
|
||||||
run: npm install
|
run: npm install
|
||||||
working-directory: .github/workflows/support-files
|
working-directory: .github/workflows/support-files
|
||||||
- name: Keybase - Send Notification
|
- name: Matrix - Send Notification
|
||||||
if: env.WORKFLOW_CONCLUSION == 'failure'
|
if: env.WORKFLOW_CONCLUSION == 'failure'
|
||||||
env:
|
env:
|
||||||
NYM_NOTIFICATION_KIND: nightly
|
NYM_NOTIFICATION_KIND: nightly
|
||||||
@@ -168,13 +180,9 @@ jobs:
|
|||||||
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
|
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
|
||||||
GIT_COMMIT_MESSAGE: "${{ github.event.head_commit.message }}"
|
GIT_COMMIT_MESSAGE: "${{ github.event.head_commit.message }}"
|
||||||
GIT_BRANCH_NAME: "${{needs.get_release.outputs.output1}}"
|
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' }}"
|
IS_SUCCESS: "${{ env.WORKFLOW_CONCLUSION == 'success' }}"
|
||||||
MATRIX_SERVER: "${{ secrets.MATRIX_SERVER }}"
|
MATRIX_SERVER: "${{ secrets.MATRIX_SERVER }}"
|
||||||
MATRIX_ROOM: "${{ secrets.MATRIX_ROOM }}"
|
MATRIX_ROOM: "${{ secrets.MATRIX_ROOM_NIGHTLY }}"
|
||||||
MATRIX_USER_ID: "${{ secrets.MATRIX_USER_ID }}"
|
MATRIX_USER_ID: "${{ secrets.MATRIX_USER_ID }}"
|
||||||
MATRIX_TOKEN: "${{ secrets.MATRIX_TOKEN }}"
|
MATRIX_TOKEN: "${{ secrets.MATRIX_TOKEN }}"
|
||||||
MATRIX_DEVICE_ID: "${{ secrets.MATRIX_DEVICE_ID }}"
|
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:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
release:
|
release:
|
||||||
@@ -6,11 +6,11 @@ on:
|
|||||||
|
|
||||||
defaults:
|
defaults:
|
||||||
run:
|
run:
|
||||||
working-directory: nym-connect
|
working-directory: nym-connect/desktop
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
publish-tauri:
|
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:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
@@ -73,7 +73,7 @@ jobs:
|
|||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: nym-connect_1.0.0_x64.dmg
|
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
|
retention-days: 30
|
||||||
|
|
||||||
- name: Clean up keychain
|
- name: Clean up keychain
|
||||||
@@ -86,5 +86,5 @@ jobs:
|
|||||||
if: github.event_name == 'release'
|
if: github.event_name == 'release'
|
||||||
with:
|
with:
|
||||||
files: |
|
files: |
|
||||||
nym-connect/target/release/bundle/dmg/*.dmg
|
nym-connect/desktop/target/release/bundle/dmg/*.dmg
|
||||||
nym-connect/target/release/bundle/macos/*.app.tar.gz*
|
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:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
release:
|
release:
|
||||||
@@ -6,11 +6,11 @@ on:
|
|||||||
|
|
||||||
defaults:
|
defaults:
|
||||||
run:
|
run:
|
||||||
working-directory: nym-connect
|
working-directory: nym-connect/desktop
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
publish-tauri:
|
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:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
@@ -53,7 +53,7 @@ jobs:
|
|||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: nym-connect.AppImage.tar.gz
|
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
|
retention-days: 30
|
||||||
|
|
||||||
- name: Upload to release based on tag name
|
- name: Upload to release based on tag name
|
||||||
@@ -61,5 +61,5 @@ jobs:
|
|||||||
if: github.event_name == 'release'
|
if: github.event_name == 'release'
|
||||||
with:
|
with:
|
||||||
files: |
|
files: |
|
||||||
nym-connect/target/release/bundle/appimage/*.AppImage
|
nym-connect/desktop/target/release/bundle/appimage/*.AppImage
|
||||||
nym-connect/target/release/bundle/appimage/*.AppImage.tar.gz*
|
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:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
release:
|
release:
|
||||||
@@ -6,11 +6,11 @@ on:
|
|||||||
|
|
||||||
defaults:
|
defaults:
|
||||||
run:
|
run:
|
||||||
working-directory: nym-connect
|
working-directory: nym-connect/desktop
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
publish-tauri:
|
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:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
@@ -56,7 +56,7 @@ jobs:
|
|||||||
encodedString: ${{ secrets.WALLET_ADMIN_ADDRESS }}
|
encodedString: ${{ secrets.WALLET_ADMIN_ADDRESS }}
|
||||||
|
|
||||||
- name: Install app dependencies
|
- name: Install app dependencies
|
||||||
run: yarn
|
run: yarn --network-timeout 100000
|
||||||
|
|
||||||
- name: Build and sign it
|
- name: Build and sign it
|
||||||
env:
|
env:
|
||||||
@@ -72,7 +72,7 @@ jobs:
|
|||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: nym-connect_1.0.0_x64_en-US.msi
|
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
|
retention-days: 30
|
||||||
|
|
||||||
- name: Upload to release based on tag name
|
- name: Upload to release based on tag name
|
||||||
@@ -80,5 +80,5 @@ jobs:
|
|||||||
if: github.event_name == 'release'
|
if: github.event_name == 'release'
|
||||||
with:
|
with:
|
||||||
files: |
|
files: |
|
||||||
nym-connect/target/release/bundle/msi/*.msi
|
nym-connect/desktop/target/release/bundle/msi/*.msi
|
||||||
nym-connect/target/release/bundle/msi/*.msi.zip*
|
nym-connect/desktop/target/release/bundle/msi/*.msi.zip*
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ env:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
publish-nym:
|
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:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ defaults:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
publish-tauri:
|
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:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ defaults:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
publish-tauri:
|
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:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
name: Publish Nym Wallet (Windows 10)
|
name: Publish Nym Wallet (Windows 10)
|
||||||
on:
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
release:
|
release:
|
||||||
types: [created]
|
types: [created]
|
||||||
|
|
||||||
@@ -9,7 +10,7 @@ defaults:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
publish-tauri:
|
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:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
@@ -55,7 +56,7 @@ jobs:
|
|||||||
encodedString: ${{ secrets.WALLET_ADMIN_ADDRESS }}
|
encodedString: ${{ secrets.WALLET_ADMIN_ADDRESS }}
|
||||||
|
|
||||||
- name: Install app dependencies
|
- name: Install app dependencies
|
||||||
run: yarn
|
run: yarn --network-timeout 100000
|
||||||
|
|
||||||
- name: Build and sign it
|
- name: Build and sign it
|
||||||
env:
|
env:
|
||||||
@@ -67,8 +68,16 @@ jobs:
|
|||||||
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
|
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
|
||||||
run: yarn build
|
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
|
- name: Upload to release based on tag name
|
||||||
uses: softprops/action-gh-release@v1
|
uses: softprops/action-gh-release@v1
|
||||||
|
if: github.event_name == 'release'
|
||||||
with:
|
with:
|
||||||
files: |
|
files: |
|
||||||
nym-wallet/target/release/bundle/msi/*.msi
|
nym-wallet/target/release/bundle/msi/*.msi
|
||||||
|
|||||||
@@ -35,10 +35,10 @@ jobs:
|
|||||||
REMOTE_USER: ${{ secrets.CI_WWW_REMOTE_USER }}
|
REMOTE_USER: ${{ secrets.CI_WWW_REMOTE_USER }}
|
||||||
TARGET: ${{ secrets.CI_WWW_REMOTE_TARGET }}/wallet-${{ env.GITHUB_REF_SLUG }}
|
TARGET: ${{ secrets.CI_WWW_REMOTE_TARGET }}/wallet-${{ env.GITHUB_REF_SLUG }}
|
||||||
EXCLUDE: "/dist/, /node_modules/"
|
EXCLUDE: "/dist/, /node_modules/"
|
||||||
- name: Keybase - Node Install
|
- name: Matrix - Node Install
|
||||||
run: npm install
|
run: npm install
|
||||||
working-directory: .github/workflows/support-files
|
working-directory: .github/workflows/support-files
|
||||||
- name: Keybase - Send Notification
|
- name: Matrix - Send Notification
|
||||||
env:
|
env:
|
||||||
NYM_NOTIFICATION_KIND: nym-wallet
|
NYM_NOTIFICATION_KIND: nym-wallet
|
||||||
NYM_PROJECT_NAME: "nym-wallet"
|
NYM_PROJECT_NAME: "nym-wallet"
|
||||||
@@ -46,10 +46,6 @@ jobs:
|
|||||||
NYM_CI_WWW_LOCATION: "wallet-${{ env.GITHUB_REF_SLUG }}"
|
NYM_CI_WWW_LOCATION: "wallet-${{ env.GITHUB_REF_SLUG }}"
|
||||||
GIT_COMMIT_MESSAGE: "${{ github.event.head_commit.message }}"
|
GIT_COMMIT_MESSAGE: "${{ github.event.head_commit.message }}"
|
||||||
GIT_BRANCH: "${GITHUB_REF##*/}"
|
GIT_BRANCH: "${GITHUB_REF##*/}"
|
||||||
KEYBASE_NYMBOT_USERNAME: "${{ secrets.KEYBASE_NYMBOT_USERNAME }}"
|
|
||||||
KEYBASE_NYMBOT_PAPERKEY: "${{ secrets.KEYBASE_NYMBOT_PAPERKEY }}"
|
|
||||||
KEYBASE_NYMBOT_TEAM: "${{ secrets.KEYBASE_NYMBOT_TEAM }}"
|
|
||||||
KEYBASE_NYM_CHANNEL: "ci-nym-wallet"
|
|
||||||
IS_SUCCESS: "${{ job.status == 'success' }}"
|
IS_SUCCESS: "${{ job.status == 'success' }}"
|
||||||
MATRIX_SERVER: "${{ secrets.MATRIX_SERVER }}"
|
MATRIX_SERVER: "${{ secrets.MATRIX_SERVER }}"
|
||||||
MATRIX_ROOM: "${{ secrets.MATRIX_ROOM }}"
|
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_SERVER=
|
||||||
MATRIX_ROOM=
|
MATRIX_ROOM=
|
||||||
MATRIX_ROOM_OF_SHAME=
|
MATRIX_ROOM_OF_SHAME=
|
||||||
@@ -39,4 +35,4 @@ NYM_CI_WWW_BASE=example.com
|
|||||||
# Nightly builds
|
# Nightly builds
|
||||||
WORKFLOW_CONCLUSION=success
|
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
|
## 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
|
### Adding notifications to a GitHub Action
|
||||||
|
|
||||||
@@ -19,10 +19,11 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
NYM_NOTIFICATION_KIND: "my-component"
|
NYM_NOTIFICATION_KIND: "my-component"
|
||||||
GIT_BRANCH: "${GITHUB_REF##*/}"
|
GIT_BRANCH: "${GITHUB_REF##*/}"
|
||||||
KEYBASE_NYMBOT_USERNAME: "${{ secrets.KEYBASE_NYMBOT_USERNAME }}"
|
MATRIX_SERVER: "${{ secrets.MATRIX_SERVER }}"
|
||||||
KEYBASE_NYMBOT_PAPERKEY: "${{ secrets.KEYBASE_NYMBOT_PAPERKEY }}"
|
MATRIX_ROOM: "${{ secrets.MATRIX_ROOM }}"
|
||||||
KEYBASE_NYMBOT_TEAM: "${{ secrets.KEYBASE_NYMBOT_TEAM }}"
|
MATRIX_USER_ID: "${{ secrets.MATRIX_USER_ID }}"
|
||||||
KEYBASE_NYM_CHANNEL: "ci-network-explorer"
|
MATRIX_TOKEN: "${{ secrets.MATRIX_TOKEN }}"
|
||||||
|
MATRIX_DEVICE_ID: "${{ secrets.MATRIX_DEVICE_ID }}"
|
||||||
IS_SUCCESS: "${{ job.status == 'success' }}"
|
IS_SUCCESS: "${{ job.status == 'success' }}"
|
||||||
uses: docker://keybaseio/client:stable-node
|
uses: docker://keybaseio/client:stable-node
|
||||||
with:
|
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
|
1. Installing node packages needed at run time
|
||||||
2. Set the env vars as required:
|
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`
|
- `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
|
- 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`
|
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
|
### Running locally
|
||||||
|
|
||||||
@@ -43,7 +44,7 @@ You will need:
|
|||||||
- Node 16 LTS
|
- Node 16 LTS
|
||||||
- npm
|
- 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.
|
Then run `npm install` to get dependencies.
|
||||||
|
|
||||||
@@ -55,4 +56,4 @@ npm install
|
|||||||
cp .env.example .env
|
cp .env.example .env
|
||||||
vi .env
|
vi .env
|
||||||
npm run dev
|
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 }}
|
> :rocket: {{ env.NYM_PROJECT_NAME }}
|
||||||
|
>
|
||||||
> 🔴 **FAILURE** :cry:
|
> 🔴 **FAILURE** :cry:
|
||||||
|
>
|
||||||
> `branch` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/tree/{{ env.GIT_BRANCH_NAME }}
|
> `branch` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/tree/{{ env.GIT_BRANCH_NAME }}
|
||||||
|
>
|
||||||
> `commit` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/commit/{{ env.GITHUB_SHA }}
|
> `commit` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/commit/{{ env.GITHUB_SHA }}
|
||||||
|
>
|
||||||
> `build ` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/actions/runs/{{ env.GITHUB_RUN_ID }}
|
> `build ` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/actions/runs/{{ env.GITHUB_RUN_ID }}
|
||||||
|
>
|
||||||
|
|
||||||
Commit message:
|
Commit message:
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -1,10 +1,16 @@
|
|||||||
🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩
|
🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩
|
||||||
> :rocket: {{ env.NYM_PROJECT_NAME }} ➡️➡️➡️➡️➡️ **View output:** https://{{ env.NYM_CI_WWW_LOCATION }}.{{ env.NYM_CI_WWW_BASE }}/
|
> :rocket: {{ env.NYM_PROJECT_NAME }} ➡️➡️➡️➡️➡️ **View output:** https://{{ env.NYM_CI_WWW_LOCATION }}.{{ env.NYM_CI_WWW_BASE }}/
|
||||||
|
>
|
||||||
> `storybook`: https://{{ env.NYM_CI_WWW_LOCATION_STORYBOOK }}.{{ env.NYM_CI_WWW_BASE }}
|
> `storybook`: https://{{ env.NYM_CI_WWW_LOCATION_STORYBOOK }}.{{ env.NYM_CI_WWW_BASE }}
|
||||||
|
>
|
||||||
> ✅ **SUCCESS**
|
> ✅ **SUCCESS**
|
||||||
|
>
|
||||||
> `branch` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/tree/{{ env.GIT_BRANCH_NAME }}
|
> `branch` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/tree/{{ env.GIT_BRANCH_NAME }}
|
||||||
|
>
|
||||||
> `commit` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/commit/{{ env.GITHUB_SHA }}
|
> `commit` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/commit/{{ env.GITHUB_SHA }}
|
||||||
|
>
|
||||||
> `build ` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/actions/runs/{{ env.GITHUB_RUN_ID }}
|
> `build ` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/actions/runs/{{ env.GITHUB_RUN_ID }}
|
||||||
|
>
|
||||||
|
|
||||||
Commit message by `{{ env.GITHUB_ACTOR }}` at {{ timestamp }}:
|
Commit message by `{{ env.GITHUB_ACTOR }}` at {{ timestamp }}:
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -151,7 +151,7 @@ async function getMessageBody(context) {
|
|||||||
return `${icon} ${job.conclusion}: ${job.name} - ${job.html_url}`;
|
return `${icon} ${job.conclusion}: ${job.name} - ${job.html_url}`;
|
||||||
})
|
})
|
||||||
// and join with newlines for display in the template
|
// and join with newlines for display in the template
|
||||||
.join('\n');
|
.join('\n\n');
|
||||||
|
|
||||||
return template({ ...context, jobResults });
|
return template({ ...context, jobResults });
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,15 @@
|
|||||||
🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥
|
🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥
|
||||||
> :rocket: {{ env.NYM_PROJECT_NAME }}
|
> :rocket: {{ env.NYM_PROJECT_NAME }}
|
||||||
|
>
|
||||||
> 🔴 **FAILURE** :cry:
|
> 🔴 **FAILURE** :cry:
|
||||||
|
>
|
||||||
> `when` {{ timestamp }}
|
> `when` {{ timestamp }}
|
||||||
|
>
|
||||||
> `branch` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/tree/{{ env.GIT_BRANCH_NAME }}
|
> `branch` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/tree/{{ env.GIT_BRANCH_NAME }}
|
||||||
|
>
|
||||||
> `commit` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/commit/{{ env.GITHUB_SHA }}
|
> `commit` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/commit/{{ env.GITHUB_SHA }}
|
||||||
|
>
|
||||||
> `build ` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/actions/runs/{{ env.GITHUB_RUN_ID }}
|
> `build ` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/actions/runs/{{ env.GITHUB_RUN_ID }}
|
||||||
|
>
|
||||||
|
|
||||||
{{ jobResults }}
|
{{ jobResults }}
|
||||||
|
|||||||
@@ -1,9 +1,15 @@
|
|||||||
🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩
|
🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩
|
||||||
> :rocket: {{ env.NYM_PROJECT_NAME }}
|
> :rocket: {{ env.NYM_PROJECT_NAME }}
|
||||||
|
>
|
||||||
> ✅ **SUCCESS**
|
> ✅ **SUCCESS**
|
||||||
|
>
|
||||||
> `when` {{ timestamp }}
|
> `when` {{ timestamp }}
|
||||||
|
>
|
||||||
> `branch` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/tree/{{ env.GIT_BRANCH_NAME }}
|
> `branch` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/tree/{{ env.GIT_BRANCH_NAME }}
|
||||||
|
>
|
||||||
> `commit` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/commit/{{ env.GITHUB_SHA }}
|
> `commit` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/commit/{{ env.GITHUB_SHA }}
|
||||||
|
>
|
||||||
> `build ` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/actions/runs/{{ env.GITHUB_RUN_ID }}
|
> `build ` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/actions/runs/{{ env.GITHUB_RUN_ID }}
|
||||||
|
>
|
||||||
|
|
||||||
{{ jobResults }}
|
{{ jobResults }}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
require('dotenv').config();
|
require('dotenv').config();
|
||||||
|
|
||||||
const Bot = require('keybase-bot');
|
|
||||||
const { sendMatrixMessage } = require('./send_message_to_matrix');
|
const { sendMatrixMessage } = require('./send_message_to_matrix');
|
||||||
|
|
||||||
let context = {
|
let context = {
|
||||||
@@ -24,21 +23,6 @@ function validateContext() {
|
|||||||
'Please set env var NYM_PROJECT_NAME with the project name for displaying in notification messages',
|
'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_ROOM) {
|
||||||
if (!context.env.MATRIX_SERVER) {
|
if (!context.env.MATRIX_SERVER) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
@@ -84,12 +68,6 @@ function createTemplateContext() {
|
|||||||
|
|
||||||
context.kind = context.env.NYM_NOTIFICATION_KIND;
|
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) {
|
if (!context.env.GIT_BRANCH_NAME) {
|
||||||
context.env.GIT_BRANCH_NAME = context.env.GITHUB_REF.split('/')
|
context.env.GIT_BRANCH_NAME = context.env.GITHUB_REF.split('/')
|
||||||
.slice(2)
|
.slice(2)
|
||||||
@@ -99,40 +77,6 @@ function createTemplateContext() {
|
|||||||
context.status = process.env.IS_SUCCESS === 'true' ? 'success' : 'failure';
|
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
|
* Uses the `kind` set in the context to process the context and generate a notification message
|
||||||
* @returns {Promise<string>} A string notification message body
|
* @returns {Promise<string>} A string notification message body
|
||||||
@@ -169,7 +113,6 @@ async function main() {
|
|||||||
console.log(messageBody);
|
console.log(messageBody);
|
||||||
console.log('-----------------------------------------');
|
console.log('-----------------------------------------');
|
||||||
}
|
}
|
||||||
await sendKeybaseMessage(messageBody);
|
|
||||||
if(context.env.MATRIX_ROOM) {
|
if(context.env.MATRIX_ROOM) {
|
||||||
await sendMatrixMessage(context, messageBody, context.env.MATRIX_ROOM)
|
await sendMatrixMessage(context, messageBody, context.env.MATRIX_ROOM)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,12 +5,7 @@ const localStorage = new LocalStorage('./scratch');
|
|||||||
const {
|
const {
|
||||||
LocalStorageCryptoStore,
|
LocalStorageCryptoStore,
|
||||||
} = require('matrix-js-sdk/lib/crypto/store/localStorage-crypto-store');
|
} = require('matrix-js-sdk/lib/crypto/store/localStorage-crypto-store');
|
||||||
|
var showdown = require('showdown');
|
||||||
const vfile = require('to-vfile');
|
|
||||||
const unified = require('unified');
|
|
||||||
const remarkParse = require('remark-parse');
|
|
||||||
const remarkHtml = require('remark-html');
|
|
||||||
const emoji = require('remark-emoji');
|
|
||||||
|
|
||||||
// hide all matrix client output
|
// hide all matrix client output
|
||||||
console.error = (error) => console.log('❌ error: ', error);
|
console.error = (error) => console.log('❌ error: ', error);
|
||||||
@@ -59,17 +54,9 @@ function createClient(context, room, message) {
|
|||||||
return client;
|
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) {
|
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);
|
const client = createClient(contextArg, roomId, messageAsHtml);
|
||||||
await client.initCrypto();
|
await client.initCrypto();
|
||||||
await client.startClient({ initialSyncLimit: 1 });
|
await client.startClient({ initialSyncLimit: 1 });
|
||||||
|
|||||||
@@ -1,9 +1,14 @@
|
|||||||
🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥
|
🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥
|
||||||
> :rocket: {{ env.NYM_PROJECT_NAME }}
|
> :rocket: {{ env.NYM_PROJECT_NAME }}
|
||||||
|
>
|
||||||
> 🔴 **FAILURE** :cry:
|
> 🔴 **FAILURE** :cry:
|
||||||
|
>
|
||||||
> `branch` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/tree/{{ env.GIT_BRANCH_NAME }}
|
> `branch` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/tree/{{ env.GIT_BRANCH_NAME }}
|
||||||
|
>
|
||||||
> `commit` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/commit/{{ env.GITHUB_SHA }}
|
> `commit` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/commit/{{ env.GITHUB_SHA }}
|
||||||
|
>
|
||||||
> `build ` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/actions/runs/{{ env.GITHUB_RUN_ID }}
|
> `build ` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/actions/runs/{{ env.GITHUB_RUN_ID }}
|
||||||
|
>
|
||||||
|
|
||||||
Commit message:
|
Commit message:
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -1,9 +1,14 @@
|
|||||||
🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩
|
🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩
|
||||||
> :rocket: {{ env.NYM_PROJECT_NAME }} ➡️➡️➡️➡️➡️ **View storybook:** https://{{ env.NYM_CI_WWW_LOCATION }}.{{ env.NYM_CI_WWW_BASE }}/
|
> :rocket: {{ env.NYM_PROJECT_NAME }} ➡️➡️➡️➡️➡️ **View storybook:** https://{{ env.NYM_CI_WWW_LOCATION }}.{{ env.NYM_CI_WWW_BASE }}/
|
||||||
|
>
|
||||||
> ✅ **SUCCESS**
|
> ✅ **SUCCESS**
|
||||||
|
>
|
||||||
> `branch` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/tree/{{ env.GIT_BRANCH_NAME }}
|
> `branch` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/tree/{{ env.GIT_BRANCH_NAME }}
|
||||||
|
>
|
||||||
> `commit` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/commit/{{ env.GITHUB_SHA }}
|
> `commit` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/commit/{{ env.GITHUB_SHA }}
|
||||||
|
>
|
||||||
> `build ` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/actions/runs/{{ env.GITHUB_RUN_ID }}
|
> `build ` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/actions/runs/{{ env.GITHUB_RUN_ID }}
|
||||||
|
>
|
||||||
|
|
||||||
Commit message by `{{ env.GITHUB_ACTOR }}` at {{ timestamp }}:
|
Commit message by `{{ env.GITHUB_ACTOR }}` at {{ timestamp }}:
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -1,9 +1,14 @@
|
|||||||
🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥
|
🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥
|
||||||
> :rocket: {{ env.NYM_PROJECT_NAME }}
|
> :rocket: {{ env.NYM_PROJECT_NAME }}
|
||||||
|
>
|
||||||
> 🔴 **FAILURE** :cry:
|
> 🔴 **FAILURE** :cry:
|
||||||
|
>
|
||||||
> `branch` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/tree/{{ env.GIT_BRANCH_NAME }}
|
> `branch` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/tree/{{ env.GIT_BRANCH_NAME }}
|
||||||
|
>
|
||||||
> `commit` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/commit/{{ env.GITHUB_SHA }}
|
> `commit` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/commit/{{ env.GITHUB_SHA }}
|
||||||
|
>
|
||||||
> `build ` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/actions/runs/{{ env.GITHUB_RUN_ID }}
|
> `build ` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/actions/runs/{{ env.GITHUB_RUN_ID }}
|
||||||
|
>
|
||||||
|
|
||||||
Commit message:
|
Commit message:
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -1,13 +1,18 @@
|
|||||||
🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩
|
🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩
|
||||||
> :rocket: {{ env.NYM_PROJECT_NAME }}
|
> :rocket: {{ env.NYM_PROJECT_NAME }}
|
||||||
|
>
|
||||||
> ✅ **SUCCESS**
|
> ✅ **SUCCESS**
|
||||||
|
>
|
||||||
> ➡️➡️➡️➡️➡️ **View output:**
|
> ➡️➡️➡️➡️➡️ **View output:**
|
||||||
|
>
|
||||||
> `storybook`: https://{{ env.NYM_CI_WWW_LOCATION }}.{{ env.NYM_CI_WWW_BASE }}
|
> `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 }}
|
> `branch` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/tree/{{ env.GIT_BRANCH_NAME }}
|
||||||
|
>
|
||||||
> `commit` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/commit/{{ env.GITHUB_SHA }}
|
> `commit` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/commit/{{ env.GITHUB_SHA }}
|
||||||
|
>
|
||||||
> `build ` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/actions/runs/{{ env.GITHUB_RUN_ID }}
|
> `build ` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/actions/runs/{{ env.GITHUB_RUN_ID }}
|
||||||
|
>
|
||||||
|
|
||||||
Commit message by `{{ env.GITHUB_ACTOR }}` at {{ timestamp }}:
|
Commit message by `{{ env.GITHUB_ACTOR }}` at {{ timestamp }}:
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "send-keybase-message",
|
"name": "send-matrix-message",
|
||||||
"description": "Sends a notification message with the keybase package that fails when piped into the keybase CLI",
|
"description": "Sends a notification message with the matrix sdk",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@@ -10,7 +10,6 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"dotenv": "^16.0.0",
|
"dotenv": "^16.0.0",
|
||||||
"handlebars": "^4.7.7",
|
"handlebars": "^4.7.7",
|
||||||
"keybase-bot": "^3.6.1",
|
|
||||||
"matrix-js-sdk": "^9.3.0",
|
"matrix-js-sdk": "^9.3.0",
|
||||||
"node-localstorage": "^2.1.6",
|
"node-localstorage": "^2.1.6",
|
||||||
"octokit": "^1.7.1",
|
"octokit": "^1.7.1",
|
||||||
@@ -18,6 +17,7 @@
|
|||||||
"remark-emoji": "^2.2.0",
|
"remark-emoji": "^2.2.0",
|
||||||
"remark-html": "^13.0.2",
|
"remark-html": "^13.0.2",
|
||||||
"remark-parse": "^9.0.0",
|
"remark-parse": "^9.0.0",
|
||||||
|
"showdown": "^2.1.0",
|
||||||
"to-vfile": "^6.1.0",
|
"to-vfile": "^6.1.0",
|
||||||
"unified": "^9.2.2"
|
"unified": "^9.2.2"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,9 +1,14 @@
|
|||||||
🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥
|
🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥
|
||||||
> :rocket: {{ env.NYM_PROJECT_NAME }}
|
> :rocket: {{ env.NYM_PROJECT_NAME }}
|
||||||
|
>
|
||||||
> 🔴 **FAILURE** :cry:
|
> 🔴 **FAILURE** :cry:
|
||||||
|
>
|
||||||
> `branch` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/tree/{{ env.GIT_BRANCH_NAME }}
|
> `branch` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/tree/{{ env.GIT_BRANCH_NAME }}
|
||||||
|
>
|
||||||
> `commit` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/commit/{{ env.GITHUB_SHA }}
|
> `commit` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/commit/{{ env.GITHUB_SHA }}
|
||||||
|
>
|
||||||
> `build ` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/actions/runs/{{ env.GITHUB_RUN_ID }}
|
> `build ` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/actions/runs/{{ env.GITHUB_RUN_ID }}
|
||||||
|
>
|
||||||
|
|
||||||
Commit message:
|
Commit message:
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -1,14 +1,20 @@
|
|||||||
🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩
|
🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩
|
||||||
> :rocket: {{ env.NYM_PROJECT_NAME }}
|
> :rocket: {{ env.NYM_PROJECT_NAME }}
|
||||||
|
>
|
||||||
> ✅ **SUCCESS**
|
> ✅ **SUCCESS**
|
||||||
|
>
|
||||||
> ➡️➡️➡️➡️➡️ **View output:**
|
> ➡️➡️➡️➡️➡️ **View output:**
|
||||||
|
>
|
||||||
> `storybook`: https://{{ env.NYM_CI_WWW_LOCATION }}.{{ env.NYM_CI_WWW_BASE }}
|
> `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 }}
|
> `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 }}
|
> `branch` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/tree/{{ env.GIT_BRANCH_NAME }}
|
||||||
|
>
|
||||||
> `commit` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/commit/{{ env.GITHUB_SHA }}
|
> `commit` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/commit/{{ env.GITHUB_SHA }}
|
||||||
|
>
|
||||||
> `build ` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/actions/runs/{{ env.GITHUB_RUN_ID }}
|
> `build ` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/actions/runs/{{ env.GITHUB_RUN_ID }}
|
||||||
|
>
|
||||||
|
|
||||||
Commit message by `{{ env.GITHUB_ACTOR }}` at {{ timestamp }}:
|
Commit message 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:
|
paths:
|
||||||
- 'ts-packages/**'
|
- 'ts-packages/**'
|
||||||
- 'sdk/typescript/**'
|
- 'sdk/typescript/**'
|
||||||
- nym-connect
|
- 'nym-connect/desktop/src/**'
|
||||||
- nym-connect-android
|
- 'nym-connect/desktop/package.json'
|
||||||
- nym-wallet
|
- '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:
|
jobs:
|
||||||
build:
|
build:
|
||||||
@@ -23,12 +36,16 @@ jobs:
|
|||||||
node-version: 16
|
node-version: 16
|
||||||
- name: Setup yarn
|
- name: Setup yarn
|
||||||
run: npm install -g yarn
|
run: npm install -g yarn
|
||||||
|
- name: Install
|
||||||
|
run: yarn
|
||||||
|
- name: Build packages
|
||||||
|
run: yarn build
|
||||||
- name: Lint
|
- name: Lint
|
||||||
run: yarn && yarn lint && yarn tsc
|
run: yarn lint && yarn tsc
|
||||||
- name: Keybase - Node Install
|
- name: Matrix - Node Install
|
||||||
run: npm install
|
run: npm install
|
||||||
working-directory: .github/workflows/support-files
|
working-directory: .github/workflows/support-files
|
||||||
- name: Keybase - Send Notification
|
- name: Matrix - Send Notification
|
||||||
env:
|
env:
|
||||||
NYM_NOTIFICATION_KIND: ts-packages
|
NYM_NOTIFICATION_KIND: ts-packages
|
||||||
NYM_PROJECT_NAME: "ts-packages"
|
NYM_PROJECT_NAME: "ts-packages"
|
||||||
@@ -36,10 +53,6 @@ jobs:
|
|||||||
NYM_CI_WWW_LOCATION: "ts-${{ env.GITHUB_REF_SLUG }}"
|
NYM_CI_WWW_LOCATION: "ts-${{ env.GITHUB_REF_SLUG }}"
|
||||||
GIT_COMMIT_MESSAGE: "${{ github.event.head_commit.message }}"
|
GIT_COMMIT_MESSAGE: "${{ github.event.head_commit.message }}"
|
||||||
GIT_BRANCH: "${GITHUB_REF##*/}"
|
GIT_BRANCH: "${GITHUB_REF##*/}"
|
||||||
KEYBASE_NYMBOT_USERNAME: "${{ secrets.KEYBASE_NYMBOT_USERNAME }}"
|
|
||||||
KEYBASE_NYMBOT_PAPERKEY: "${{ secrets.KEYBASE_NYMBOT_PAPERKEY }}"
|
|
||||||
KEYBASE_NYMBOT_TEAM: "${{ secrets.KEYBASE_NYMBOT_TEAM }}"
|
|
||||||
KEYBASE_NYM_CHANNEL: "ci-ts-packages"
|
|
||||||
IS_SUCCESS: "${{ job.status == 'success' }}"
|
IS_SUCCESS: "${{ job.status == 'success' }}"
|
||||||
MATRIX_SERVER: "${{ secrets.MATRIX_SERVER }}"
|
MATRIX_SERVER: "${{ secrets.MATRIX_SERVER }}"
|
||||||
MATRIX_ROOM: "${{ secrets.MATRIX_ROOM }}"
|
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
|
Cargo.lock
|
||||||
nym-connect/Cargo.lock
|
nym-connect/Cargo.lock
|
||||||
.parcel-cache
|
.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).
|
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
|
### Added
|
||||||
|
|
||||||
- dkg rerun from scratch and dkg-specific epochs ([#2839])
|
- Remove Coconut feature flag ([#2793])
|
||||||
- nym-sdk: add support for surb storage ([#2870])
|
- Separate `nym-api` endpoints with values of "total-supply" and "circulating-supply" in `nym` ([#2964])
|
||||||
- nym-sdk: enable reply-SURBs by default ([#2874])
|
|
||||||
- remove coconut feature and unify builds ([#2890])
|
|
||||||
|
|
||||||
[#2839]: https://github.com/nymtech/nym/pull/2839
|
### Changed
|
||||||
[#2870]: https://github.com/nymtech/nym/pull/2870
|
|
||||||
[#2874]: https://github.com/nymtech/nym/pull/2874
|
|
||||||
[#2890]: https://github.com/nymtech/nym/pull/2890
|
|
||||||
|
|
||||||
# [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
|
### Added
|
||||||
|
|
||||||
@@ -73,12 +157,6 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
|
|||||||
|
|
||||||
### Added
|
### 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
|
- socks5: send status message for service ready, and network-requester error response in https://github.com/nymtech/nym/pull/2715
|
||||||
|
|
||||||
### Changed
|
### 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",
|
||||||
"clients/native/websocket-requests",
|
"clients/native/websocket-requests",
|
||||||
"clients/socks5",
|
"clients/socks5",
|
||||||
"common/bandwidth-claim-contract",
|
"common/bin-common",
|
||||||
"common/client-libs/gateway-client",
|
"common/client-libs/gateway-client",
|
||||||
"common/client-libs/mixnet-client",
|
"common/client-libs/mixnet-client",
|
||||||
"common/client-libs/validator-client",
|
"common/client-libs/validator-client",
|
||||||
"common/client-connections",
|
|
||||||
"common/coconut-interface",
|
"common/coconut-interface",
|
||||||
"common/commands",
|
"common/commands",
|
||||||
"common/config",
|
"common/config",
|
||||||
"common/build-information",
|
|
||||||
"common/cosmwasm-smart-contracts/coconut-bandwidth-contract",
|
"common/cosmwasm-smart-contracts/coconut-bandwidth-contract",
|
||||||
"common/cosmwasm-smart-contracts/coconut-dkg",
|
"common/cosmwasm-smart-contracts/coconut-dkg",
|
||||||
"common/cosmwasm-smart-contracts/contracts-common",
|
"common/cosmwasm-smart-contracts/contracts-common",
|
||||||
@@ -42,11 +40,10 @@ members = [
|
|||||||
"common/credential-storage",
|
"common/credential-storage",
|
||||||
"common/credentials",
|
"common/credentials",
|
||||||
"common/crypto",
|
"common/crypto",
|
||||||
"common/crypto/dkg",
|
"common/dkg",
|
||||||
"common/execute",
|
"common/execute",
|
||||||
"common/inclusion-probability",
|
"common/inclusion-probability",
|
||||||
"common/ledger",
|
"common/ledger",
|
||||||
"common/logging",
|
|
||||||
"common/mixnode-common",
|
"common/mixnode-common",
|
||||||
"common/network-defaults",
|
"common/network-defaults",
|
||||||
"common/nonexhaustive-delayqueue",
|
"common/nonexhaustive-delayqueue",
|
||||||
@@ -69,13 +66,13 @@ members = [
|
|||||||
"common/topology",
|
"common/topology",
|
||||||
"common/types",
|
"common/types",
|
||||||
"common/wasm-utils",
|
"common/wasm-utils",
|
||||||
"common/completions",
|
|
||||||
"explorer-api",
|
"explorer-api",
|
||||||
"gateway",
|
"gateway",
|
||||||
"gateway/gateway-requests",
|
"gateway/gateway-requests",
|
||||||
"integrations/bity",
|
"integrations/bity",
|
||||||
"mixnode",
|
"mixnode",
|
||||||
"sdk/rust/nym-sdk",
|
"sdk/rust/nym-sdk",
|
||||||
|
"service-providers/common",
|
||||||
"service-providers/network-requester",
|
"service-providers/network-requester",
|
||||||
"service-providers/network-statistics",
|
"service-providers/network-statistics",
|
||||||
"nym-api",
|
"nym-api",
|
||||||
@@ -96,13 +93,27 @@ default-members = [
|
|||||||
"explorer-api",
|
"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]
|
[workspace.package]
|
||||||
authors = ["Nym Technologies SA"]
|
authors = ["Nym Technologies SA"]
|
||||||
repository = "https://github.com/nymtech/nym"
|
repository = "https://github.com/nymtech/nym"
|
||||||
homepage = "https://nymtech.net"
|
homepage = "https://nymtech.net"
|
||||||
|
documentation = "https://nymtech.net"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
license = "Apache-2.0"
|
||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
|
async-trait = "0.1.64"
|
||||||
|
cfg-if = "1.0.0"
|
||||||
|
dotenvy = "0.15.6"
|
||||||
|
lazy_static = "1.4.0"
|
||||||
log = "0.4"
|
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: 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: test cargo-test-expensive
|
||||||
|
test-all-no-mobile: test-no-mobile cargo-test-expensive
|
||||||
no-clippy: build cargo-test wasm fmt
|
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
|
happy: fmt clippy-happy test
|
||||||
clippy-all: clippy-main clippy-all-contracts clippy-all-wallet clippy-all-connect clippy-all-wasm-client
|
happy-no-mobile: fmt-no-mobile clippy-happy-no-mobile test-no-mobile
|
||||||
clippy-happy: clippy-happy-main clippy-happy-contracts clippy-happy-wallet clippy-happy-connect
|
clippy-all: clippy-all-no-mobile clippy-all-connect-mobile
|
||||||
cargo-test: test-main test-contracts test-wallet test-connect
|
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
|
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
|
build: build-no-mobile build-connect-mobile
|
||||||
fmt: fmt-main fmt-contracts fmt-wallet fmt-connect fmt-wasm-client
|
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:
|
clippy-happy-main:
|
||||||
cargo clippy
|
cargo clippy
|
||||||
@@ -19,11 +28,17 @@ clippy-happy-wallet:
|
|||||||
cargo clippy --manifest-path nym-wallet/Cargo.toml
|
cargo clippy --manifest-path nym-wallet/Cargo.toml
|
||||||
|
|
||||||
clippy-happy-connect:
|
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:
|
clippy-main:
|
||||||
cargo clippy --workspace -- -D warnings
|
cargo clippy --workspace -- -D warnings
|
||||||
|
|
||||||
|
clippy-main-examples:
|
||||||
|
cargo clippy --workspace --examples -- -D warnings
|
||||||
|
|
||||||
clippy-wasm:
|
clippy-wasm:
|
||||||
cargo clippy --manifest-path clients/webassembly/Cargo.toml --target wasm32-unknown-unknown --workspace -- -D warnings
|
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
|
cargo clippy --workspace --manifest-path nym-wallet/Cargo.toml --all-features -- -D warnings
|
||||||
|
|
||||||
clippy-all-connect:
|
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:
|
clippy-all-wasm-client:
|
||||||
cargo clippy --workspace --manifest-path clients/webassembly/Cargo.toml --all-features --target wasm32-unknown-unknown -- -D warnings
|
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
|
cargo test --manifest-path nym-wallet/Cargo.toml --all-features -- --ignored
|
||||||
|
|
||||||
test-connect:
|
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:
|
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:
|
build-main:
|
||||||
cargo build --workspace
|
cargo build --workspace
|
||||||
|
|
||||||
|
build-main-examples:
|
||||||
|
cargo build --workspace --examples
|
||||||
|
|
||||||
build-contracts:
|
build-contracts:
|
||||||
cargo build --manifest-path contracts/Cargo.toml --workspace
|
cargo build --manifest-path contracts/Cargo.toml --workspace
|
||||||
|
|
||||||
@@ -74,7 +101,10 @@ build-wallet:
|
|||||||
cargo build --manifest-path nym-wallet/Cargo.toml --workspace
|
cargo build --manifest-path nym-wallet/Cargo.toml --workspace
|
||||||
|
|
||||||
build-connect:
|
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:
|
build-explorer-api:
|
||||||
cargo build --manifest-path explorer-api/Cargo.toml --workspace
|
cargo build --manifest-path explorer-api/Cargo.toml --workspace
|
||||||
@@ -95,13 +125,18 @@ fmt-wallet:
|
|||||||
cargo fmt --manifest-path nym-wallet/Cargo.toml --all
|
cargo fmt --manifest-path nym-wallet/Cargo.toml --all
|
||||||
|
|
||||||
fmt-connect:
|
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:
|
fmt-wasm-client:
|
||||||
cargo fmt --manifest-path clients/webassembly/Cargo.toml --all
|
cargo fmt --manifest-path clients/webassembly/Cargo.toml --all
|
||||||
|
|
||||||
wasm:
|
wasm:
|
||||||
RUSTFLAGS='-C link-arg=-s' cargo build --manifest-path contracts/Cargo.toml --release --target wasm32-unknown-unknown
|
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
|
mixnet-opt: wasm
|
||||||
cd contracts/mixnet && make opt
|
cd contracts/mixnet && make opt
|
||||||
@@ -110,5 +145,5 @@ generate-typescript:
|
|||||||
cd tools/ts-rs-cli && cargo run && cd ../..
|
cd tools/ts-rs-cli && cargo run && cd ../..
|
||||||
yarn types:lint:fix
|
yarn types:lint:fix
|
||||||
|
|
||||||
run-validator-tests:
|
run-api-tests:
|
||||||
cd nym-api/tests/functional_test && yarn test:qa
|
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.
|
* 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://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
|
### Building
|
||||||
|
|||||||
Vendored
BIN
Binary file not shown.
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "client-core"
|
name = "client-core"
|
||||||
version = "1.1.7"
|
version = "1.1.12"
|
||||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
|
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
rust-version = "1.66"
|
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
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
async-trait = { version = "0.1.58" }
|
async-trait = { workspace = true }
|
||||||
dirs = "4.0"
|
dirs = "4.0"
|
||||||
dashmap = "5.4.0"
|
dashmap = "5.4.0"
|
||||||
futures = "0.3"
|
futures = "0.3"
|
||||||
@@ -20,22 +20,26 @@ serde_json = "1.0.89"
|
|||||||
tap = "1.0.1"
|
tap = "1.0.1"
|
||||||
thiserror = "1.0.34"
|
thiserror = "1.0.34"
|
||||||
url = { version ="2.2", features = ["serde"] }
|
url = { version ="2.2", features = ["serde"] }
|
||||||
|
tungstenite = { version = "0.13.0", default-features = false }
|
||||||
tokio = { version = "1.24.1", features = ["macros"]}
|
tokio = { version = "1.24.1", features = ["macros"]}
|
||||||
time = "0.3.17"
|
time = "0.3.17"
|
||||||
|
|
||||||
# internal
|
# internal
|
||||||
config = { path = "../../common/config" }
|
nym-config = { path = "../../common/config" }
|
||||||
client-connections = { path = "../../common/client-connections" }
|
nym-crypto = { path = "../../common/crypto" }
|
||||||
crypto = { path = "../../common/crypto" }
|
|
||||||
gateway-client = { path = "../../common/client-libs/gateway-client" }
|
gateway-client = { path = "../../common/client-libs/gateway-client" }
|
||||||
#gateway-client = { path = "../../common/client-libs/gateway-client", default-features = false, features = ["wasm", "coconut"] }
|
#gateway-client = { path = "../../common/client-libs/gateway-client", default-features = false, features = ["wasm", "coconut"] }
|
||||||
gateway-requests = { path = "../../gateway/gateway-requests" }
|
gateway-requests = { path = "../../gateway/gateway-requests" }
|
||||||
nonexhaustive-delayqueue = { path = "../../common/nonexhaustive-delayqueue" }
|
nym-nonexhaustive-delayqueue = { path = "../../common/nonexhaustive-delayqueue" }
|
||||||
nymsphinx = { path = "../../common/nymsphinx" }
|
nym-sphinx = { path = "../../common/nymsphinx" }
|
||||||
pemstore = { path = "../../common/pemstore" }
|
nym-pemstore = { path = "../../common/pemstore" }
|
||||||
topology = { path = "../../common/topology" }
|
nym-topology = { path = "../../common/topology" }
|
||||||
validator-client = { path = "../../common/client-libs/validator-client", default-features = false }
|
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]
|
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.tokio-stream]
|
||||||
version = "0.1.11"
|
version = "0.1.11"
|
||||||
@@ -45,6 +49,9 @@ features = ["time"]
|
|||||||
version = "1.24.1"
|
version = "1.24.1"
|
||||||
features = ["time"]
|
features = ["time"]
|
||||||
|
|
||||||
|
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.tokio-tungstenite]
|
||||||
|
version = "0.14"
|
||||||
|
|
||||||
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.sqlx]
|
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.sqlx]
|
||||||
version = "0.6.2"
|
version = "0.6.2"
|
||||||
features = ["runtime-tokio-rustls", "sqlite", "macros", "migrate"]
|
features = ["runtime-tokio-rustls", "sqlite", "macros", "migrate"]
|
||||||
@@ -66,6 +73,7 @@ features = ["futures"]
|
|||||||
|
|
||||||
[target."cfg(target_arch = \"wasm32\")".dependencies.wasm-utils]
|
[target."cfg(target_arch = \"wasm32\")".dependencies.wasm-utils]
|
||||||
path = "../../common/wasm-utils"
|
path = "../../common/wasm-utils"
|
||||||
|
features = ["websocket"]
|
||||||
|
|
||||||
[target."cfg(target_arch = \"wasm32\")".dependencies.time]
|
[target."cfg(target_arch = \"wasm32\")".dependencies.time]
|
||||||
version = "0.3.17"
|
version = "0.3.17"
|
||||||
|
|||||||
@@ -15,14 +15,13 @@ use crate::client::replies::reply_controller::{ReplyControllerReceiver, ReplyCon
|
|||||||
use crate::client::replies::reply_storage::{
|
use crate::client::replies::reply_storage::{
|
||||||
CombinedReplyStorage, PersistentReplyStorage, ReplyStorageBackend, SentReplyKeys,
|
CombinedReplyStorage, PersistentReplyStorage, ReplyStorageBackend, SentReplyKeys,
|
||||||
};
|
};
|
||||||
|
use crate::client::topology_control::nym_api_provider::NymApiTopologyProvider;
|
||||||
use crate::client::topology_control::{
|
use crate::client::topology_control::{
|
||||||
TopologyAccessor, TopologyRefresher, TopologyRefresherConfig,
|
TopologyAccessor, TopologyRefresher, TopologyRefresherConfig,
|
||||||
};
|
};
|
||||||
use crate::config::{Config, DebugConfig, GatewayEndpointConfig};
|
use crate::config::{Config, DebugConfig, GatewayEndpointConfig};
|
||||||
use crate::error::ClientCoreError;
|
use crate::error::ClientCoreError;
|
||||||
use crate::spawn_future;
|
use crate::spawn_future;
|
||||||
use client_connections::{ConnectionCommandReceiver, ConnectionCommandSender, LaneQueueLengths};
|
|
||||||
use crypto::asymmetric::{encryption, identity};
|
|
||||||
use futures::channel::mpsc;
|
use futures::channel::mpsc;
|
||||||
use gateway_client::bandwidth::BandwidthController;
|
use gateway_client::bandwidth::BandwidthController;
|
||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
@@ -32,15 +31,19 @@ use gateway_client::{
|
|||||||
MixnetMessageSender,
|
MixnetMessageSender,
|
||||||
};
|
};
|
||||||
use log::{debug, info};
|
use log::{debug, info};
|
||||||
use nymsphinx::acknowledgements::AckKey;
|
use nym_crypto::asymmetric::{encryption, identity};
|
||||||
use nymsphinx::addressing::clients::Recipient;
|
use nym_sphinx::acknowledgements::AckKey;
|
||||||
use nymsphinx::addressing::nodes::NodeIdentity;
|
use nym_sphinx::addressing::clients::Recipient;
|
||||||
use nymsphinx::receiver::ReconstructedMessage;
|
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::sync::Arc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use tap::TapFallible;
|
use tap::TapFallible;
|
||||||
use task::{TaskClient, TaskManager};
|
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
use validator_client::nyxd::CosmWasmClient;
|
use validator_client::nyxd::CosmWasmClient;
|
||||||
|
|
||||||
@@ -51,11 +54,22 @@ pub mod non_wasm_helpers;
|
|||||||
|
|
||||||
pub mod helpers;
|
pub mod helpers;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct ClientInput {
|
pub struct ClientInput {
|
||||||
pub connection_command_sender: ConnectionCommandSender,
|
pub connection_command_sender: ConnectionCommandSender,
|
||||||
pub input_sender: InputMessageSender,
|
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 struct ClientOutput {
|
||||||
pub received_buffer_request_sender: ReceivedBufferRequestSender,
|
pub received_buffer_request_sender: ReceivedBufferRequestSender,
|
||||||
}
|
}
|
||||||
@@ -79,6 +93,7 @@ impl ClientOutput {
|
|||||||
pub struct ClientState {
|
pub struct ClientState {
|
||||||
pub shared_lane_queue_lengths: LaneQueueLengths,
|
pub shared_lane_queue_lengths: LaneQueueLengths,
|
||||||
pub reply_controller_sender: ReplyControllerSender,
|
pub reply_controller_sender: ReplyControllerSender,
|
||||||
|
pub topology_accessor: TopologyAccessor,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum ClientInputStatus {
|
pub enum ClientInputStatus {
|
||||||
@@ -143,6 +158,7 @@ pub struct BaseClientBuilder<'a, B, C: Clone> {
|
|||||||
nym_api_endpoints: Vec<Url>,
|
nym_api_endpoints: Vec<Url>,
|
||||||
reply_storage_backend: B,
|
reply_storage_backend: B,
|
||||||
|
|
||||||
|
custom_topology_provider: Option<Box<dyn TopologyProvider>>,
|
||||||
bandwidth_controller: Option<BandwidthController<C>>,
|
bandwidth_controller: Option<BandwidthController<C>>,
|
||||||
key_manager: KeyManager,
|
key_manager: KeyManager,
|
||||||
}
|
}
|
||||||
@@ -166,6 +182,7 @@ where
|
|||||||
bandwidth_controller,
|
bandwidth_controller,
|
||||||
reply_storage_backend,
|
reply_storage_backend,
|
||||||
key_manager,
|
key_manager,
|
||||||
|
custom_topology_provider: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -184,11 +201,17 @@ where
|
|||||||
disabled_credentials: credentials_toggle.is_disabled(),
|
disabled_credentials: credentials_toggle.is_disabled(),
|
||||||
nym_api_endpoints,
|
nym_api_endpoints,
|
||||||
reply_storage_backend,
|
reply_storage_backend,
|
||||||
|
custom_topology_provider: None,
|
||||||
bandwidth_controller,
|
bandwidth_controller,
|
||||||
key_manager,
|
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 {
|
pub fn as_mix_recipient(&self) -> Recipient {
|
||||||
Recipient::new(
|
Recipient::new(
|
||||||
*self.key_manager.identity_keypair().public_key(),
|
*self.key_manager.identity_keypair().public_key(),
|
||||||
@@ -293,7 +316,7 @@ where
|
|||||||
}
|
}
|
||||||
let gateway_address = self.gateway_config.gateway_listener.clone();
|
let gateway_address = self.gateway_config.gateway_listener.clone();
|
||||||
if gateway_address.is_empty() {
|
if gateway_address.is_empty() {
|
||||||
return Err(ClientCoreError::GatwayAddressUnknown);
|
return Err(ClientCoreError::GatewayAddressUnknown);
|
||||||
}
|
}
|
||||||
|
|
||||||
let gateway_identity = identity::PublicKey::from_base58_string(gateway_id)
|
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() {
|
let shared_key = if self.key_manager.is_gateway_key_set() {
|
||||||
Some(self.key_manager.gateway_shared_key())
|
Some(self.key_manager.gateway_shared_key())
|
||||||
} else {
|
} else {
|
||||||
|
log::info!("Gateway key not set! Will proceed anyway.");
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -329,25 +353,38 @@ where
|
|||||||
Ok(gateway_client)
|
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
|
// future responsible for periodically polling directory server and updating
|
||||||
// the current global view of topology
|
// the current global view of topology
|
||||||
async fn start_topology_refresher(
|
async fn start_topology_refresher(
|
||||||
nym_api_urls: Vec<Url>,
|
topology_provider: Box<dyn TopologyProvider>,
|
||||||
refresh_rate: Duration,
|
refresh_rate: Duration,
|
||||||
topology_accessor: TopologyAccessor,
|
topology_accessor: TopologyAccessor,
|
||||||
shutdown: TaskClient,
|
shutdown: TaskClient,
|
||||||
) -> Result<(), ClientCoreError> {
|
) -> Result<(), ClientCoreError> {
|
||||||
let topology_refresher_config = TopologyRefresherConfig::new(
|
let topology_refresher_config = TopologyRefresherConfig::new(refresh_rate);
|
||||||
nym_api_urls,
|
|
||||||
refresh_rate,
|
let mut topology_refresher = TopologyRefresher::new(
|
||||||
env!("CARGO_PKG_VERSION").to_string(),
|
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
|
// before returning, block entire runtime to refresh the current network view so that any
|
||||||
// components depending on topology would see a non-empty view
|
// components depending on topology would see a non-empty view
|
||||||
info!("Obtaining initial network topology");
|
info!("Obtaining initial network topology");
|
||||||
topology_refresher.refresh().await;
|
topology_refresher.try_refresh().await;
|
||||||
|
|
||||||
if let Err(err) = topology_refresher.ensure_topology_is_routable().await {
|
if let Err(err) = topology_refresher.ensure_topology_is_routable().await {
|
||||||
log::error!(
|
log::error!(
|
||||||
@@ -456,8 +493,12 @@ where
|
|||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
let topology_provider = Self::setup_topology_provider(
|
||||||
|
self.custom_topology_provider.take(),
|
||||||
|
self.nym_api_endpoints,
|
||||||
|
);
|
||||||
Self::start_topology_refresher(
|
Self::start_topology_refresher(
|
||||||
self.nym_api_endpoints.clone(),
|
topology_provider,
|
||||||
self.debug_config.topology_refresh_rate,
|
self.debug_config.topology_refresh_rate,
|
||||||
shared_topology_accessor.clone(),
|
shared_topology_accessor.clone(),
|
||||||
task_manager.subscribe(),
|
task_manager.subscribe(),
|
||||||
@@ -518,7 +559,7 @@ where
|
|||||||
self.debug_config,
|
self.debug_config,
|
||||||
self.key_manager.ack_key(),
|
self.key_manager.ack_key(),
|
||||||
self_address,
|
self_address,
|
||||||
shared_topology_accessor,
|
shared_topology_accessor.clone(),
|
||||||
sphinx_message_sender,
|
sphinx_message_sender,
|
||||||
task_manager.subscribe(),
|
task_manager.subscribe(),
|
||||||
);
|
);
|
||||||
@@ -542,6 +583,7 @@ where
|
|||||||
client_state: ClientState {
|
client_state: ClientState {
|
||||||
shared_lane_queue_lengths,
|
shared_lane_queue_lengths,
|
||||||
reply_controller_sender,
|
reply_controller_sender,
|
||||||
|
topology_accessor: shared_topology_accessor,
|
||||||
},
|
},
|
||||||
task_manager,
|
task_manager,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -7,11 +7,11 @@ use crate::spawn_future;
|
|||||||
use futures::task::{Context, Poll};
|
use futures::task::{Context, Poll};
|
||||||
use futures::{Future, Stream, StreamExt};
|
use futures::{Future, Stream, StreamExt};
|
||||||
use log::*;
|
use log::*;
|
||||||
use nymsphinx::acknowledgements::AckKey;
|
use nym_sphinx::acknowledgements::AckKey;
|
||||||
use nymsphinx::addressing::clients::Recipient;
|
use nym_sphinx::addressing::clients::Recipient;
|
||||||
use nymsphinx::cover::generate_loop_cover_packet;
|
use nym_sphinx::cover::generate_loop_cover_packet;
|
||||||
use nymsphinx::params::PacketSize;
|
use nym_sphinx::params::PacketSize;
|
||||||
use nymsphinx::utils::sample_poisson_duration;
|
use nym_sphinx::utils::sample_poisson_duration;
|
||||||
use rand::{rngs::OsRng, CryptoRng, Rng};
|
use rand::{rngs::OsRng, CryptoRng, Rng};
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
@@ -192,7 +192,7 @@ impl LoopCoverTrafficStream<OsRng> {
|
|||||||
// However it's still useful to alert the user that the gateway or the link to
|
// 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
|
// the gateway can't keep up. Either due to insufficient bandwidth on the
|
||||||
// client side, or that the gateway is overloaded.
|
// 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(_) => {
|
TrySendError::Closed(_) => {
|
||||||
log::warn!("Failed to send cover message - channel closed");
|
log::warn!("Failed to send cover message - channel closed");
|
||||||
@@ -213,7 +213,7 @@ impl LoopCoverTrafficStream<OsRng> {
|
|||||||
tokio::task::yield_now().await;
|
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
|
// we should set initial delay only when we actually start the stream
|
||||||
let sampled =
|
let sampled =
|
||||||
sample_poisson_duration(&mut self.rng, self.average_cover_message_sending_delay);
|
sample_poisson_duration(&mut self.rng, self.average_cover_message_sending_delay);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use client_connections::TransmissionLane;
|
use nym_sphinx::addressing::clients::Recipient;
|
||||||
use nymsphinx::addressing::clients::Recipient;
|
use nym_sphinx::anonymous_replies::requests::AnonymousSenderTag;
|
||||||
use nymsphinx::anonymous_replies::requests::AnonymousSenderTag;
|
use nym_task::connections::TransmissionLane;
|
||||||
|
|
||||||
pub type InputMessageSender = tokio::sync::mpsc::Sender<InputMessage>;
|
pub type InputMessageSender = tokio::sync::mpsc::Sender<InputMessage>;
|
||||||
pub type InputMessageReceiver = tokio::sync::mpsc::Receiver<InputMessage>;
|
pub type InputMessageReceiver = tokio::sync::mpsc::Receiver<InputMessage>;
|
||||||
@@ -77,4 +77,12 @@ impl InputMessage {
|
|||||||
lane,
|
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
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use crate::config::persistence::key_pathfinder::ClientKeyPathfinder;
|
use crate::config::persistence::key_pathfinder::ClientKeyPathfinder;
|
||||||
use crypto::asymmetric::{encryption, identity};
|
|
||||||
use gateway_requests::registration::handshake::SharedKeys;
|
use gateway_requests::registration::handshake::SharedKeys;
|
||||||
use log::*;
|
use log::*;
|
||||||
use nymsphinx::acknowledgements::AckKey;
|
use nym_crypto::asymmetric::{encryption, identity};
|
||||||
|
use nym_sphinx::acknowledgements::AckKey;
|
||||||
use rand::{CryptoRng, RngCore};
|
use rand::{CryptoRng, RngCore};
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
@@ -72,17 +72,17 @@ impl KeyManager {
|
|||||||
/// Loads previously stored client keys from the disk.
|
/// Loads previously stored client keys from the disk.
|
||||||
fn load_client_keys(client_pathfinder: &ClientKeyPathfinder) -> io::Result<Self> {
|
fn load_client_keys(client_pathfinder: &ClientKeyPathfinder) -> io::Result<Self> {
|
||||||
let identity_keypair: identity::KeyPair =
|
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.private_identity_key().to_owned(),
|
||||||
client_pathfinder.public_identity_key().to_owned(),
|
client_pathfinder.public_identity_key().to_owned(),
|
||||||
))?;
|
))?;
|
||||||
let encryption_keypair: encryption::KeyPair =
|
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.private_encryption_key().to_owned(),
|
||||||
client_pathfinder.public_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 {
|
Ok(KeyManager {
|
||||||
identity_keypair: Arc::new(identity_keypair),
|
identity_keypair: Arc::new(identity_keypair),
|
||||||
@@ -98,7 +98,7 @@ impl KeyManager {
|
|||||||
let mut key_manager = Self::load_client_keys(client_pathfinder)?;
|
let mut key_manager = Self::load_client_keys(client_pathfinder)?;
|
||||||
|
|
||||||
let gateway_shared_key: SharedKeys =
|
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));
|
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 mut key_manager = Self::load_client_keys(client_pathfinder)?;
|
||||||
|
|
||||||
let gateway_shared_key: Result<SharedKeys, io::Error> =
|
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
|
// It's ok if the gateway key was not found
|
||||||
let gateway_shared_key = match gateway_shared_key {
|
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
|
// 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.
|
// during `load_keys` to generate the said key.
|
||||||
pub fn store_keys(&self, client_pathfinder: &ClientKeyPathfinder) -> io::Result<()> {
|
pub fn store_keys(&self, client_pathfinder: &ClientKeyPathfinder) -> io::Result<()> {
|
||||||
pemstore::store_keypair(
|
nym_pemstore::store_keypair(
|
||||||
self.identity_keypair.as_ref(),
|
self.identity_keypair.as_ref(),
|
||||||
&pemstore::KeyPairPath::new(
|
&nym_pemstore::KeyPairPath::new(
|
||||||
client_pathfinder.private_identity_key().to_owned(),
|
client_pathfinder.private_identity_key().to_owned(),
|
||||||
client_pathfinder.public_identity_key().to_owned(),
|
client_pathfinder.public_identity_key().to_owned(),
|
||||||
),
|
),
|
||||||
)?;
|
)?;
|
||||||
pemstore::store_keypair(
|
nym_pemstore::store_keypair(
|
||||||
self.encryption_keypair.as_ref(),
|
self.encryption_keypair.as_ref(),
|
||||||
&pemstore::KeyPairPath::new(
|
&nym_pemstore::KeyPairPath::new(
|
||||||
client_pathfinder.private_encryption_key().to_owned(),
|
client_pathfinder.private_encryption_key().to_owned(),
|
||||||
client_pathfinder.public_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() {
|
match self.gateway_shared_key.as_ref() {
|
||||||
None => debug!("No gateway shared key available to store!"),
|
None => debug!("No gateway shared key available to store!"),
|
||||||
Some(gate_key) => {
|
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) => {
|
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::wasm_mockups::CosmWasmClient;
|
||||||
use gateway_client::GatewayClient;
|
use gateway_client::GatewayClient;
|
||||||
use log::*;
|
use log::*;
|
||||||
use nymsphinx::forwarding::packet::MixPacket;
|
use nym_sphinx::forwarding::packet::MixPacket;
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
use validator_client::nyxd::CosmWasmClient;
|
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 {
|
spawn_future(async move {
|
||||||
debug!("Started MixTrafficController with graceful shutdown support");
|
debug!("Started MixTrafficController with graceful shutdown support");
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -5,7 +5,7 @@ use super::action_controller::{AckActionSender, Action};
|
|||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
use gateway_client::AcknowledgementReceiver;
|
use gateway_client::AcknowledgementReceiver;
|
||||||
use log::*;
|
use log::*;
|
||||||
use nymsphinx::{
|
use nym_sphinx::{
|
||||||
acknowledgements::{identifier::recover_identifier, AckKey},
|
acknowledgements::{identifier::recover_identifier, AckKey},
|
||||||
chunking::fragment::{FragmentIdentifier, COVER_FRAG_ID},
|
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");
|
debug!("Started AcknowledgementListener with graceful shutdown support");
|
||||||
|
|
||||||
while !shutdown.is_shutdown() {
|
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::channel::mpsc;
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
use log::*;
|
use log::*;
|
||||||
use nonexhaustive_delayqueue::{Expired, NonExhaustiveDelayQueue, QueueKey};
|
use nym_nonexhaustive_delayqueue::{Expired, NonExhaustiveDelayQueue, QueueKey};
|
||||||
use nymsphinx::chunking::fragment::FragmentIdentifier;
|
use nym_sphinx::chunking::fragment::FragmentIdentifier;
|
||||||
use nymsphinx::Delay as SphinxDelay;
|
use nym_sphinx::Delay as SphinxDelay;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
@@ -216,7 +216,7 @@ impl ActionController {
|
|||||||
fn handle_expired_ack_timer(
|
fn handle_expired_ack_timer(
|
||||||
&mut self,
|
&mut self,
|
||||||
expired_ack: Expired<FragmentIdentifier>,
|
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
|
// 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
|
// 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");
|
debug!("Started ActionController with graceful shutdown support");
|
||||||
|
|
||||||
while !shutdown.is_shutdown() {
|
while !shutdown.is_shutdown() {
|
||||||
|
|||||||
+4
-4
@@ -4,10 +4,10 @@
|
|||||||
use crate::client::inbound_messages::{InputMessage, InputMessageReceiver};
|
use crate::client::inbound_messages::{InputMessage, InputMessageReceiver};
|
||||||
use crate::client::real_messages_control::message_handler::MessageHandler;
|
use crate::client::real_messages_control::message_handler::MessageHandler;
|
||||||
use crate::client::replies::reply_controller::ReplyControllerSender;
|
use crate::client::replies::reply_controller::ReplyControllerSender;
|
||||||
use client_connections::TransmissionLane;
|
|
||||||
use log::*;
|
use log::*;
|
||||||
use nymsphinx::addressing::clients::Recipient;
|
use nym_sphinx::addressing::clients::Recipient;
|
||||||
use nymsphinx::anonymous_replies::requests::AnonymousSenderTag;
|
use nym_sphinx::anonymous_replies::requests::AnonymousSenderTag;
|
||||||
|
use nym_task::connections::TransmissionLane;
|
||||||
use rand::{CryptoRng, Rng};
|
use rand::{CryptoRng, Rng};
|
||||||
|
|
||||||
/// Module responsible for dealing with the received messages: splitting them, creating acknowledgements,
|
/// 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");
|
debug!("Started InputMessageListener with graceful shutdown support");
|
||||||
|
|
||||||
while !shutdown.is_shutdown() {
|
while !shutdown.is_shutdown() {
|
||||||
|
|||||||
@@ -15,9 +15,9 @@ use action_controller::AckActionReceiver;
|
|||||||
use futures::channel::mpsc;
|
use futures::channel::mpsc;
|
||||||
use gateway_client::AcknowledgementReceiver;
|
use gateway_client::AcknowledgementReceiver;
|
||||||
use log::*;
|
use log::*;
|
||||||
use nymsphinx::anonymous_replies::requests::AnonymousSenderTag;
|
use nym_sphinx::anonymous_replies::requests::AnonymousSenderTag;
|
||||||
use nymsphinx::params::PacketSize;
|
use nym_sphinx::params::PacketSize;
|
||||||
use nymsphinx::{
|
use nym_sphinx::{
|
||||||
acknowledgements::AckKey,
|
acknowledgements::AckKey,
|
||||||
addressing::clients::Recipient,
|
addressing::clients::Recipient,
|
||||||
chunking::fragment::{Fragment, FragmentIdentifier},
|
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 acknowledgement_listener = self.acknowledgement_listener;
|
||||||
let mut input_message_listener = self.input_message_listener;
|
let mut input_message_listener = self.input_message_listener;
|
||||||
let mut retransmission_request_listener = self.retransmission_request_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::message_handler::{MessageHandler, PreparationError};
|
||||||
use crate::client::real_messages_control::real_traffic_stream::RealMessage;
|
use crate::client::real_messages_control::real_traffic_stream::RealMessage;
|
||||||
use crate::client::replies::reply_controller::ReplyControllerSender;
|
use crate::client::replies::reply_controller::ReplyControllerSender;
|
||||||
use client_connections::TransmissionLane;
|
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
use log::*;
|
use log::*;
|
||||||
use nymsphinx::addressing::clients::Recipient;
|
use nym_sphinx::addressing::clients::Recipient;
|
||||||
use nymsphinx::chunking::fragment::Fragment;
|
use nym_sphinx::chunking::fragment::Fragment;
|
||||||
use nymsphinx::preparer::PreparedFragment;
|
use nym_sphinx::preparer::PreparedFragment;
|
||||||
|
use nym_task::connections::TransmissionLane;
|
||||||
use rand::{CryptoRng, Rng};
|
use rand::{CryptoRng, Rng};
|
||||||
use std::sync::{Arc, Weak};
|
use std::sync::{Arc, Weak};
|
||||||
|
|
||||||
@@ -137,7 +137,7 @@ where
|
|||||||
.await
|
.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");
|
debug!("Started RetransmissionRequestListener with graceful shutdown support");
|
||||||
|
|
||||||
while !shutdown.is_shutdown() {
|
while !shutdown.is_shutdown() {
|
||||||
|
|||||||
+2
-2
@@ -5,7 +5,7 @@ use super::action_controller::{AckActionSender, Action};
|
|||||||
use super::SentPacketNotificationReceiver;
|
use super::SentPacketNotificationReceiver;
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
use log::*;
|
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.
|
/// Module responsible for starting up retransmission timers.
|
||||||
/// It is required because when we send our packet to the `real traffic stream` controlled
|
/// It is required because when we send our packet to the `real traffic stream` controlled
|
||||||
@@ -37,7 +37,7 @@ impl SentNotificationListener {
|
|||||||
.unwrap();
|
.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");
|
debug!("Started SentNotificationListener with graceful shutdown support");
|
||||||
|
|
||||||
while !shutdown.is_shutdown() {
|
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::real_messages_control::{AckActionSender, Action};
|
||||||
use crate::client::replies::reply_storage::{ReceivedReplySurbsMap, SentReplyKeys, UsedSenderTags};
|
use crate::client::replies::reply_storage::{ReceivedReplySurbsMap, SentReplyKeys, UsedSenderTags};
|
||||||
use crate::client::topology_control::{TopologyAccessor, TopologyReadPermit};
|
use crate::client::topology_control::{TopologyAccessor, TopologyReadPermit};
|
||||||
use client_connections::TransmissionLane;
|
|
||||||
use log::{debug, error, info, trace, warn};
|
use log::{debug, error, info, trace, warn};
|
||||||
use nymsphinx::acknowledgements::AckKey;
|
use nym_sphinx::acknowledgements::AckKey;
|
||||||
use nymsphinx::addressing::clients::Recipient;
|
use nym_sphinx::addressing::clients::Recipient;
|
||||||
use nymsphinx::anonymous_replies::requests::{AnonymousSenderTag, RepliableMessage, ReplyMessage};
|
use nym_sphinx::anonymous_replies::requests::{AnonymousSenderTag, RepliableMessage, ReplyMessage};
|
||||||
use nymsphinx::anonymous_replies::{ReplySurb, SurbEncryptionKey};
|
use nym_sphinx::anonymous_replies::{ReplySurb, SurbEncryptionKey};
|
||||||
use nymsphinx::chunking::fragment::{Fragment, FragmentIdentifier};
|
use nym_sphinx::chunking::fragment::{Fragment, FragmentIdentifier};
|
||||||
use nymsphinx::message::NymMessage;
|
use nym_sphinx::message::NymMessage;
|
||||||
use nymsphinx::params::{PacketSize, DEFAULT_NUM_MIX_HOPS};
|
use nym_sphinx::params::{PacketSize, DEFAULT_NUM_MIX_HOPS};
|
||||||
use nymsphinx::preparer::{MessagePreparer, PreparedFragment};
|
use nym_sphinx::preparer::{MessagePreparer, PreparedFragment};
|
||||||
use nymsphinx::Delay;
|
use nym_sphinx::Delay;
|
||||||
|
use nym_task::connections::TransmissionLane;
|
||||||
|
use nym_topology::{NymTopology, NymTopologyError};
|
||||||
use rand::{CryptoRng, Rng};
|
use rand::{CryptoRng, Rng};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use topology::{NymTopology, NymTopologyError};
|
|
||||||
|
|
||||||
// TODO: move that error elsewhere since it seems to be contaminating different files
|
// TODO: move that error elsewhere since it seems to be contaminating different files
|
||||||
#[derive(Debug, Clone, Error)]
|
#[derive(Debug, Clone, Error)]
|
||||||
|
|||||||
@@ -21,13 +21,13 @@ use crate::{
|
|||||||
},
|
},
|
||||||
spawn_future,
|
spawn_future,
|
||||||
};
|
};
|
||||||
use client_connections::{ConnectionCommandReceiver, LaneQueueLengths};
|
|
||||||
use futures::channel::mpsc;
|
use futures::channel::mpsc;
|
||||||
use gateway_client::AcknowledgementReceiver;
|
use gateway_client::AcknowledgementReceiver;
|
||||||
use log::*;
|
use log::*;
|
||||||
use nymsphinx::acknowledgements::AckKey;
|
use nym_sphinx::acknowledgements::AckKey;
|
||||||
use nymsphinx::addressing::clients::Recipient;
|
use nym_sphinx::addressing::clients::Recipient;
|
||||||
use nymsphinx::params::PacketSize;
|
use nym_sphinx::params::PacketSize;
|
||||||
|
use nym_task::connections::{ConnectionCommandReceiver, LaneQueueLengths};
|
||||||
use rand::{rngs::OsRng, CryptoRng, Rng};
|
use rand::{rngs::OsRng, CryptoRng, Rng};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
@@ -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 mut out_queue_control = self.out_queue_control;
|
||||||
let ack_control = self.ack_control;
|
let ack_control = self.ack_control;
|
||||||
let mut reply_control = self.reply_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::real_messages_control::acknowledgement_control::SentPacketNotificationSender;
|
||||||
use crate::client::topology_control::TopologyAccessor;
|
use crate::client::topology_control::TopologyAccessor;
|
||||||
use crate::client::transmission_buffer::TransmissionBuffer;
|
use crate::client::transmission_buffer::TransmissionBuffer;
|
||||||
use client_connections::{
|
|
||||||
ConnectionCommand, ConnectionCommandReceiver, ConnectionId, LaneQueueLengths, TransmissionLane,
|
|
||||||
};
|
|
||||||
use futures::task::{Context, Poll};
|
use futures::task::{Context, Poll};
|
||||||
use futures::{Future, Stream, StreamExt};
|
use futures::{Future, Stream, StreamExt};
|
||||||
use log::*;
|
use log::*;
|
||||||
use nymsphinx::acknowledgements::AckKey;
|
use nym_sphinx::acknowledgements::AckKey;
|
||||||
use nymsphinx::addressing::clients::Recipient;
|
use nym_sphinx::addressing::clients::Recipient;
|
||||||
use nymsphinx::chunking::fragment::FragmentIdentifier;
|
use nym_sphinx::chunking::fragment::FragmentIdentifier;
|
||||||
use nymsphinx::cover::generate_loop_cover_packet;
|
use nym_sphinx::cover::generate_loop_cover_packet;
|
||||||
use nymsphinx::forwarding::packet::MixPacket;
|
use nym_sphinx::forwarding::packet::MixPacket;
|
||||||
use nymsphinx::params::PacketSize;
|
use nym_sphinx::params::PacketSize;
|
||||||
use nymsphinx::preparer::PreparedFragment;
|
use nym_sphinx::preparer::PreparedFragment;
|
||||||
use nymsphinx::utils::sample_poisson_duration;
|
use nym_sphinx::utils::sample_poisson_duration;
|
||||||
|
use nym_task::connections::{
|
||||||
|
ConnectionCommand, ConnectionCommandReceiver, ConnectionId, LaneQueueLengths, TransmissionLane,
|
||||||
|
};
|
||||||
use rand::{CryptoRng, Rng};
|
use rand::{CryptoRng, Rng};
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
use std::sync::Arc;
|
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) {
|
if let Poll::Ready(Some(id)) = Pin::new(&mut self.client_connection_rx).poll_next(cx) {
|
||||||
match id {
|
match id {
|
||||||
ConnectionCommand::Close(id) => self.on_close_connection(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) {
|
if let Poll::Ready(Some(id)) = Pin::new(&mut self.client_connection_rx).poll_next(cx) {
|
||||||
match id {
|
match id {
|
||||||
ConnectionCommand::Close(id) => self.on_close_connection(id),
|
ConnectionCommand::Close(id) => self.on_close_connection(id),
|
||||||
ConnectionCommand::ActiveConnections(_) => panic!(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -462,7 +460,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[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;
|
use crate::error::ClientCoreStatusMessage;
|
||||||
|
|
||||||
let packets = self.transmission_buffer.total_size();
|
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");
|
debug!("Started OutQueueControl with graceful shutdown support");
|
||||||
|
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
|||||||
@@ -4,20 +4,20 @@
|
|||||||
use crate::client::replies::reply_controller::ReplyControllerSender;
|
use crate::client::replies::reply_controller::ReplyControllerSender;
|
||||||
use crate::client::replies::reply_storage::SentReplyKeys;
|
use crate::client::replies::reply_storage::SentReplyKeys;
|
||||||
use crate::spawn_future;
|
use crate::spawn_future;
|
||||||
use crypto::asymmetric::encryption;
|
|
||||||
use crypto::Digest;
|
|
||||||
use futures::channel::mpsc;
|
use futures::channel::mpsc;
|
||||||
use futures::lock::Mutex;
|
use futures::lock::Mutex;
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
use gateway_client::MixnetMessageReceiver;
|
use gateway_client::MixnetMessageReceiver;
|
||||||
use log::*;
|
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,
|
RepliableMessage, RepliableMessageContent, ReplyMessage, ReplyMessageContent,
|
||||||
};
|
};
|
||||||
use nymsphinx::anonymous_replies::{encryption_key::EncryptionKeyDigest, SurbEncryptionKey};
|
use nym_sphinx::anonymous_replies::{encryption_key::EncryptionKeyDigest, SurbEncryptionKey};
|
||||||
use nymsphinx::message::{NymMessage, PlainMessage};
|
use nym_sphinx::message::{NymMessage, PlainMessage};
|
||||||
use nymsphinx::params::ReplySurbKeyDigestAlgorithm;
|
use nym_sphinx::params::ReplySurbKeyDigestAlgorithm;
|
||||||
use nymsphinx::receiver::{MessageReceiver, MessageRecoveryError, ReconstructedMessage};
|
use nym_sphinx::receiver::{MessageReceiver, MessageRecoveryError, ReconstructedMessage};
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
@@ -47,7 +47,7 @@ struct ReceivedMessagesBufferInner {
|
|||||||
|
|
||||||
impl ReceivedMessagesBufferInner {
|
impl ReceivedMessagesBufferInner {
|
||||||
fn recover_from_fragment(&mut self, fragment_data: &[u8]) -> Option<NymMessage> {
|
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");
|
trace!("The message was a loop cover message! Skipping it");
|
||||||
return None;
|
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");
|
debug!("Started RequestReceiver with graceful shutdown support");
|
||||||
while !shutdown.is_shutdown() {
|
while !shutdown.is_shutdown() {
|
||||||
tokio::select! {
|
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");
|
debug!("Started FragmentedMessageReceiver with graceful shutdown support");
|
||||||
while !shutdown.is_shutdown() {
|
while !shutdown.is_shutdown() {
|
||||||
tokio::select! {
|
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 fragmented_message_receiver = self.fragmented_message_receiver;
|
||||||
let mut request_receiver = self.request_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::acknowledgement_control::PendingAcknowledgement;
|
||||||
use crate::client::real_messages_control::message_handler::{MessageHandler, PreparationError};
|
use crate::client::real_messages_control::message_handler::{MessageHandler, PreparationError};
|
||||||
use crate::client::replies::reply_storage::CombinedReplyStorage;
|
use crate::client::replies::reply_storage::CombinedReplyStorage;
|
||||||
use client_connections::{ConnectionId, TransmissionLane};
|
|
||||||
use futures::channel::oneshot;
|
use futures::channel::oneshot;
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
use log::{debug, error, info, trace, warn};
|
use log::{debug, error, info, trace, warn};
|
||||||
use nymsphinx::addressing::clients::Recipient;
|
use nym_sphinx::addressing::clients::Recipient;
|
||||||
use nymsphinx::anonymous_replies::requests::AnonymousSenderTag;
|
use nym_sphinx::anonymous_replies::requests::AnonymousSenderTag;
|
||||||
use nymsphinx::anonymous_replies::ReplySurb;
|
use nym_sphinx::anonymous_replies::ReplySurb;
|
||||||
use nymsphinx::chunking::fragment::{Fragment, FragmentIdentifier};
|
use nym_sphinx::chunking::fragment::{Fragment, FragmentIdentifier};
|
||||||
|
use nym_task::connections::{ConnectionId, TransmissionLane};
|
||||||
use rand::{CryptoRng, Rng};
|
use rand::{CryptoRng, Rng};
|
||||||
use std::cmp::{max, min};
|
use std::cmp::{max, min};
|
||||||
use std::collections::btree_map::Entry;
|
use std::collections::btree_map::Entry;
|
||||||
@@ -835,7 +835,7 @@ where
|
|||||||
// todo!()
|
// 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");
|
debug!("Started ReplyController with graceful shutdown support");
|
||||||
|
|
||||||
let polling_rate = Duration::from_secs(5);
|
let polling_rate = Duration::from_secs(5);
|
||||||
|
|||||||
@@ -2,12 +2,12 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use crate::client::real_messages_control::acknowledgement_control::PendingAcknowledgement;
|
use crate::client::real_messages_control::acknowledgement_control::PendingAcknowledgement;
|
||||||
use client_connections::{ConnectionId, TransmissionLane};
|
|
||||||
use futures::channel::{mpsc, oneshot};
|
use futures::channel::{mpsc, oneshot};
|
||||||
use log::error;
|
use log::error;
|
||||||
use nymsphinx::addressing::clients::Recipient;
|
use nym_sphinx::addressing::clients::Recipient;
|
||||||
use nymsphinx::anonymous_replies::requests::AnonymousSenderTag;
|
use nym_sphinx::anonymous_replies::requests::AnonymousSenderTag;
|
||||||
use nymsphinx::anonymous_replies::ReplySurb;
|
use nym_sphinx::anonymous_replies::ReplySurb;
|
||||||
|
use nym_task::connections::{ConnectionId, TransmissionLane};
|
||||||
use std::sync::Weak;
|
use std::sync::Weak;
|
||||||
|
|
||||||
pub(crate) fn new_control_channels() -> (ReplyControllerSender, ReplyControllerReceiver) {
|
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 crate::client::replies::reply_storage::{CombinedReplyStorage, ReplyStorageBackend};
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
|
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
// well, right now we don't have the browser storage : (
|
// well, right now we don't have the browser storage : (
|
||||||
// so we keep everything in memory
|
// so we keep everything in memory
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -27,6 +29,18 @@ impl Backend {
|
|||||||
impl ReplyStorageBackend for Backend {
|
impl ReplyStorageBackend for Backend {
|
||||||
type StorageError = <Empty as ReplyStorageBackend>::StorageError;
|
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(
|
async fn flush_surb_storage(
|
||||||
&mut self,
|
&mut self,
|
||||||
storage: &CombinedReplyStorage,
|
storage: &CombinedReplyStorage,
|
||||||
|
|||||||
@@ -56,4 +56,9 @@ pub enum StorageError {
|
|||||||
details: String,
|
details: String,
|
||||||
// err: Option<Box<dyn std::error::Error>>
|
// 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>
|
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// 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::manager::StorageManager;
|
||||||
use crate::client::replies::reply_storage::backend::fs_backend::models::{
|
use crate::client::replies::reply_storage::backend::fs_backend::models::{
|
||||||
ReplySurbStorageMetadata, StoredReplyKey, StoredReplySurb, StoredSenderTag, StoredSurbSender,
|
ReplySurbStorageMetadata, StoredReplyKey, StoredReplySurb, StoredSenderTag, StoredSurbSender,
|
||||||
@@ -11,7 +12,7 @@ use crate::client::replies::reply_storage::{
|
|||||||
};
|
};
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use log::{error, info, warn};
|
use log::{error, info, warn};
|
||||||
use nymsphinx::anonymous_replies::requests::AnonymousSenderTag;
|
use nym_sphinx::anonymous_replies::requests::AnonymousSenderTag;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use time::OffsetDateTime;
|
use time::OffsetDateTime;
|
||||||
@@ -154,18 +155,21 @@ impl Backend {
|
|||||||
// (assuming no key rotation has happened)
|
// (assuming no key rotation has happened)
|
||||||
// but the way it's currently coded, everyone will purge old data
|
// but the way it's currently coded, everyone will purge old data
|
||||||
let since_last_flush = OffsetDateTime::now_utc() - last_flush;
|
let since_last_flush = OffsetDateTime::now_utc() - last_flush;
|
||||||
if since_last_flush.whole_days() > 0 {
|
let days = since_last_flush.whole_days();
|
||||||
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 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?;
|
manager.delete_all_reply_surb_data().await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if since_last_flush.whole_days() > 1 {
|
if 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());
|
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?;
|
manager.delete_all_reply_keys().await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if since_last_flush.whole_days() > 2 {
|
if 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());
|
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?;
|
manager.delete_all_tags().await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -367,6 +371,20 @@ impl Backend {
|
|||||||
impl ReplyStorageBackend for Backend {
|
impl ReplyStorageBackend for Backend {
|
||||||
type StorageError = error::StorageError;
|
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 {
|
fn is_active(&self) -> bool {
|
||||||
self.manager.is_active()
|
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::backend::fs_backend::error::StorageError;
|
||||||
use crate::client::replies::reply_storage::key_storage::UsedReplyKey;
|
use crate::client::replies::reply_storage::key_storage::UsedReplyKey;
|
||||||
use crypto::generic_array::typenum::Unsigned;
|
use nym_crypto::generic_array::typenum::Unsigned;
|
||||||
use crypto::Digest;
|
use nym_crypto::Digest;
|
||||||
use nymsphinx::addressing::clients::{Recipient, RecipientBytes};
|
use nym_sphinx::addressing::clients::{Recipient, RecipientBytes};
|
||||||
use nymsphinx::anonymous_replies::encryption_key::EncryptionKeyDigest;
|
use nym_sphinx::anonymous_replies::encryption_key::EncryptionKeyDigest;
|
||||||
use nymsphinx::anonymous_replies::requests::{AnonymousSenderTag, SENDER_TAG_SIZE};
|
use nym_sphinx::anonymous_replies::requests::{AnonymousSenderTag, SENDER_TAG_SIZE};
|
||||||
use nymsphinx::anonymous_replies::{ReplySurb, SurbEncryptionKey, SurbEncryptionKeySize};
|
use nym_sphinx::anonymous_replies::{ReplySurb, SurbEncryptionKey, SurbEncryptionKeySize};
|
||||||
use nymsphinx::params::ReplySurbKeyDigestAlgorithm;
|
use nym_sphinx::params::ReplySurbKeyDigestAlgorithm;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub(crate) struct StoredSenderTag {
|
pub(crate) struct StoredSenderTag {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
use crate::client::replies::reply_storage::CombinedReplyStorage;
|
use crate::client::replies::reply_storage::CombinedReplyStorage;
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use std::error::Error;
|
use std::{error::Error, path::PathBuf};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
@@ -30,6 +30,16 @@ pub struct Empty {
|
|||||||
impl ReplyStorageBackend for Empty {
|
impl ReplyStorageBackend for Empty {
|
||||||
type StorageError = UndefinedError;
|
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(
|
async fn flush_surb_storage(
|
||||||
&mut self,
|
&mut self,
|
||||||
_storage: &CombinedReplyStorage,
|
_storage: &CombinedReplyStorage,
|
||||||
@@ -63,6 +73,11 @@ impl ReplyStorageBackend for Empty {
|
|||||||
pub trait ReplyStorageBackend: Sized {
|
pub trait ReplyStorageBackend: Sized {
|
||||||
type StorageError: Error + 'static;
|
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 {
|
fn is_active(&self) -> bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,8 +3,8 @@
|
|||||||
|
|
||||||
use dashmap::iter::Iter;
|
use dashmap::iter::Iter;
|
||||||
use dashmap::DashMap;
|
use dashmap::DashMap;
|
||||||
use nymsphinx::anonymous_replies::encryption_key::EncryptionKeyDigest;
|
use nym_sphinx::anonymous_replies::encryption_key::EncryptionKeyDigest;
|
||||||
use nymsphinx::anonymous_replies::SurbEncryptionKey;
|
use nym_sphinx::anonymous_replies::SurbEncryptionKey;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use time::OffsetDateTime;
|
use time::OffsetDateTime;
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ where
|
|||||||
pub async fn flush_on_shutdown(
|
pub async fn flush_on_shutdown(
|
||||||
mut self,
|
mut self,
|
||||||
mem_state: CombinedReplyStorage,
|
mem_state: CombinedReplyStorage,
|
||||||
mut shutdown: task::TaskClient,
|
mut shutdown: nym_task::TaskClient,
|
||||||
) {
|
) {
|
||||||
use log::{debug, error, info, warn};
|
use log::{debug, error, info, warn};
|
||||||
|
|
||||||
|
|||||||
@@ -4,8 +4,8 @@
|
|||||||
use dashmap::iter::Iter;
|
use dashmap::iter::Iter;
|
||||||
use dashmap::DashMap;
|
use dashmap::DashMap;
|
||||||
use log::trace;
|
use log::trace;
|
||||||
use nymsphinx::anonymous_replies::requests::AnonymousSenderTag;
|
use nym_sphinx::anonymous_replies::requests::AnonymousSenderTag;
|
||||||
use nymsphinx::anonymous_replies::ReplySurb;
|
use nym_sphinx::anonymous_replies::ReplySurb;
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use dashmap::DashMap;
|
use dashmap::DashMap;
|
||||||
use nymsphinx::addressing::clients::{Recipient, RecipientBytes};
|
use nym_sphinx::addressing::clients::{Recipient, RecipientBytes};
|
||||||
use nymsphinx::anonymous_replies::requests::AnonymousSenderTag;
|
use nym_sphinx::anonymous_replies::requests::AnonymousSenderTag;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
#[cfg(all(not(target_arch = "wasm32"), feature = "fs-surb-storage"))]
|
#[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::helpers::{get_time_now, Instant};
|
||||||
use crate::client::real_messages_control::real_traffic_stream::RealMessage;
|
use crate::client::real_messages_control::real_traffic_stream::RealMessage;
|
||||||
use client_connections::TransmissionLane;
|
use nym_sphinx::chunking::fragment::Fragment;
|
||||||
use nymsphinx::chunking::fragment::Fragment;
|
use nym_task::connections::TransmissionLane;
|
||||||
use rand::{seq::SliceRandom, Rng};
|
use rand::{seq::SliceRandom, Rng};
|
||||||
use std::{
|
use std::{
|
||||||
collections::{HashMap, HashSet, VecDeque},
|
collections::{HashMap, HashSet, VecDeque},
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use config::defaults::NymNetworkDetails;
|
use nym_config::defaults::NymNetworkDetails;
|
||||||
use config::{NymConfig, OptionalSet, DB_FILE_NAME};
|
use nym_config::{NymConfig, OptionalSet, CRED_DB_FILE_NAME};
|
||||||
use nymsphinx::params::PacketSize;
|
use nym_sphinx::params::PacketSize;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
@@ -171,10 +171,15 @@ impl<T> Config<T> {
|
|||||||
self
|
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;
|
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) {
|
pub fn with_gateway_id<S: Into<String>>(&mut self, id: S) {
|
||||||
self.client.gateway_endpoint.gateway_id = id.into();
|
self.client.gateway_endpoint.gateway_id = id.into();
|
||||||
}
|
}
|
||||||
@@ -430,8 +435,8 @@ impl GatewayEndpointConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<topology::gateway::Node> for GatewayEndpointConfig {
|
impl From<nym_topology::gateway::Node> for GatewayEndpointConfig {
|
||||||
fn from(node: topology::gateway::Node) -> GatewayEndpointConfig {
|
fn from(node: nym_topology::gateway::Node) -> GatewayEndpointConfig {
|
||||||
let gateway_listener = node.clients_address();
|
let gateway_listener = node.clients_address();
|
||||||
GatewayEndpointConfig {
|
GatewayEndpointConfig {
|
||||||
gateway_id: node.identity_key.to_base58_string(),
|
gateway_id: node.identity_key.to_base58_string(),
|
||||||
@@ -546,35 +551,35 @@ impl<T: NymConfig> Default for Client<T> {
|
|||||||
|
|
||||||
impl<T: NymConfig> Client<T> {
|
impl<T: NymConfig> Client<T> {
|
||||||
fn default_private_identity_key_file(id: &str) -> PathBuf {
|
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 {
|
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 {
|
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 {
|
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 {
|
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 {
|
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 {
|
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 {
|
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
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use crate::config::Config;
|
use crate::config::Config;
|
||||||
use config::NymConfig;
|
use nym_config::NymConfig;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use crypto::asymmetric::identity::Ed25519RecoveryError;
|
|
||||||
use gateway_client::error::GatewayClientError;
|
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;
|
use validator_client::ValidatorClientError;
|
||||||
|
|
||||||
#[derive(thiserror::Error, Debug)]
|
#[derive(thiserror::Error, Debug)]
|
||||||
@@ -53,7 +54,32 @@ pub enum ClientCoreError {
|
|||||||
GatewayOwnerUnknown,
|
GatewayOwnerUnknown,
|
||||||
|
|
||||||
#[error("The address of the gateway is unknown - did you run init?")]
|
#[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")]
|
#[error("failed to register receiver for reconstructed mixnet messages")]
|
||||||
FailedToRegisterReceiver,
|
FailedToRegisterReceiver,
|
||||||
|
|||||||
@@ -6,52 +6,223 @@ use crate::{
|
|||||||
config::{persistence::key_pathfinder::ClientKeyPathfinder, Config},
|
config::{persistence::key_pathfinder::ClientKeyPathfinder, Config},
|
||||||
error::ClientCoreError,
|
error::ClientCoreError,
|
||||||
};
|
};
|
||||||
use config::NymConfig;
|
use futures::{SinkExt, StreamExt};
|
||||||
use crypto::asymmetric::identity;
|
|
||||||
#[cfg(target_arch = "wasm32")]
|
|
||||||
use gateway_client::wasm_mockups::SigningNyxdClient;
|
|
||||||
use gateway_client::GatewayClient;
|
use gateway_client::GatewayClient;
|
||||||
use gateway_requests::registration::handshake::SharedKeys;
|
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 std::{sync::Arc, time::Duration};
|
||||||
use tap::TapFallible;
|
use tap::TapFallible;
|
||||||
use topology::{filter::VersionFilterable, gateway};
|
use tungstenite::Message;
|
||||||
use url::Url;
|
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"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
use validator_client::nyxd::SigningNyxdClient;
|
use validator_client::nyxd::SigningNyxdClient;
|
||||||
|
|
||||||
pub(super) async fn query_gateway_details(
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
validator_servers: Vec<Url>,
|
type WsConn = WebSocketStream<MaybeTlsStream<TcpStream>>;
|
||||||
chosen_gateway_id: Option<identity::PublicKey>,
|
|
||||||
) -> Result<gateway::Node, ClientCoreError> {
|
#[cfg(target_arch = "wasm32")]
|
||||||
let nym_api = validator_servers
|
use gateway_client::wasm_mockups::SigningNyxdClient;
|
||||||
.choose(&mut thread_rng())
|
#[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)?;
|
.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);
|
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
|
let valid_gateways = gateways
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter_map(|gateway| gateway.try_into().ok())
|
.filter_map(|gateway| gateway.try_into().ok())
|
||||||
.collect::<Vec<gateway::Node>>();
|
.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"));
|
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.
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
// (remember that in active topology all gateways have at least 100 reputation so should
|
async fn connect(endpoint: &str) -> Result<WsConn, ClientCoreError> {
|
||||||
// be working correctly)
|
match tokio::time::timeout(CONN_TIMEOUT, connect_async(endpoint)).await {
|
||||||
if let Some(gateway_id) = chosen_gateway_id {
|
Err(_elapsed) => Err(ClientCoreError::GatewayConnectionTimeout),
|
||||||
filtered_gateways
|
Ok(Err(conn_failure)) => Err(conn_failure.into()),
|
||||||
.iter()
|
Ok(Ok((stream, _))) => Ok(stream),
|
||||||
.find(|gateway| gateway.identity_key == gateway_id)
|
}
|
||||||
.ok_or_else(|| ClientCoreError::NoGatewayWithId(gateway_id.to_string()))
|
}
|
||||||
.cloned()
|
|
||||||
|
#[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 {
|
} else {
|
||||||
filtered_gateways
|
uniformly_random_gateway(&mut rng, gateways)
|
||||||
.choose(&mut rand::thread_rng())
|
|
||||||
.ok_or(ClientCoreError::NoGatewaysOnNetwork)
|
|
||||||
.cloned()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,13 +5,13 @@
|
|||||||
|
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
|
|
||||||
use nymsphinx::addressing::{clients::Recipient, nodes::NodeIdentity};
|
use nym_sphinx::addressing::{clients::Recipient, nodes::NodeIdentity};
|
||||||
use rand::rngs::OsRng;
|
use rand::rngs::OsRng;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use tap::TapFallible;
|
use tap::TapFallible;
|
||||||
|
|
||||||
use config::NymConfig;
|
use nym_config::NymConfig;
|
||||||
use crypto::asymmetric::{encryption, identity};
|
use nym_crypto::asymmetric::{encryption, identity};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
use crate::client::key_manager::KeyManager;
|
use crate::client::key_manager::KeyManager;
|
||||||
@@ -77,9 +77,11 @@ pub async fn register_with_gateway(
|
|||||||
key_manager: &mut KeyManager,
|
key_manager: &mut KeyManager,
|
||||||
nym_api_endpoints: Vec<Url>,
|
nym_api_endpoints: Vec<Url>,
|
||||||
chosen_gateway_id: Option<identity::PublicKey>,
|
chosen_gateway_id: Option<identity::PublicKey>,
|
||||||
|
by_latency: bool,
|
||||||
) -> Result<GatewayEndpointConfig, ClientCoreError> {
|
) -> Result<GatewayEndpointConfig, ClientCoreError> {
|
||||||
// Get the gateway details of the gateway we will use
|
// 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);
|
log::debug!("Querying gateway gives: {}", gateway);
|
||||||
|
|
||||||
let our_identity = key_manager.identity_keypair();
|
let our_identity = key_manager.identity_keypair();
|
||||||
@@ -102,6 +104,7 @@ pub async fn setup_gateway_from_config<C, T>(
|
|||||||
register_gateway: bool,
|
register_gateway: bool,
|
||||||
user_chosen_gateway_id: Option<identity::PublicKey>,
|
user_chosen_gateway_id: Option<identity::PublicKey>,
|
||||||
config: &Config<T>,
|
config: &Config<T>,
|
||||||
|
by_latency: bool,
|
||||||
) -> Result<GatewayEndpointConfig, ClientCoreError>
|
) -> Result<GatewayEndpointConfig, ClientCoreError>
|
||||||
where
|
where
|
||||||
C: NymConfig + ClientCoreConfigTrait,
|
C: NymConfig + ClientCoreConfigTrait,
|
||||||
@@ -117,9 +120,12 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Else, we preceed by querying the nym-api
|
// Else, we preceed by querying the nym-api
|
||||||
let gateway =
|
let gateway = helpers::query_gateway_details(
|
||||||
helpers::query_gateway_details(config.get_nym_api_endpoints(), user_chosen_gateway_id)
|
config.get_nym_api_endpoints(),
|
||||||
.await?;
|
user_chosen_gateway_id,
|
||||||
|
by_latency,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
log::debug!("Querying gateway gives: {}", gateway);
|
log::debug!("Querying gateway gives: {}", gateway);
|
||||||
|
|
||||||
// If we are not registering, just return this and assume the caller has the keys already and
|
// 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
|
where
|
||||||
T: NymConfig + ClientCoreConfigTrait,
|
T: NymConfig + ClientCoreConfigTrait,
|
||||||
{
|
{
|
||||||
T::load_from_file(Some(id))
|
T::load_from_file(id)
|
||||||
.map(|existing_config| existing_config.get_gateway_endpoint().clone())
|
.map(|existing_config| existing_config.get_gateway_endpoint().clone())
|
||||||
.map_err(|err| {
|
.map_err(|err| {
|
||||||
log::error!(
|
log::error!(
|
||||||
@@ -182,13 +188,13 @@ pub fn get_client_address_from_stored_keys<T>(
|
|||||||
config: &Config<T>,
|
config: &Config<T>,
|
||||||
) -> Result<Recipient, ClientCoreError>
|
) -> Result<Recipient, ClientCoreError>
|
||||||
where
|
where
|
||||||
T: config::NymConfig,
|
T: nym_config::NymConfig,
|
||||||
{
|
{
|
||||||
fn load_identity_keys(
|
fn load_identity_keys(
|
||||||
pathfinder: &ClientKeyPathfinder,
|
pathfinder: &ClientKeyPathfinder,
|
||||||
) -> Result<identity::KeyPair, ClientCoreError> {
|
) -> Result<identity::KeyPair, ClientCoreError> {
|
||||||
let identity_keypair: identity::KeyPair =
|
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.private_identity_key().to_owned(),
|
||||||
pathfinder.public_identity_key().to_owned(),
|
pathfinder.public_identity_key().to_owned(),
|
||||||
))
|
))
|
||||||
@@ -200,7 +206,7 @@ where
|
|||||||
pathfinder: &ClientKeyPathfinder,
|
pathfinder: &ClientKeyPathfinder,
|
||||||
) -> Result<encryption::KeyPair, ClientCoreError> {
|
) -> Result<encryption::KeyPair, ClientCoreError> {
|
||||||
let sphinx_keypair: encryption::KeyPair =
|
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.private_encryption_key().to_owned(),
|
||||||
pathfinder.public_encryption_key().to_owned(),
|
pathfinder.public_encryption_key().to_owned(),
|
||||||
))
|
))
|
||||||
|
|||||||
@@ -8,19 +8,20 @@ edition = "2021"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
bip39 = "1.0.1"
|
bip39 = "1.0.1"
|
||||||
clap = { version = "4.0", features = ["cargo", "derive"] }
|
clap = { version = "4.0", features = ["cargo", "derive"] }
|
||||||
|
log = "0.4"
|
||||||
rand = "0.7.3"
|
rand = "0.7.3"
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
thiserror = "1.0"
|
thiserror = "1.0"
|
||||||
url = "2.2"
|
url = "2.2"
|
||||||
tokio = { version = "1.24.1", features = ["rt-multi-thread", "net", "signal", "macros"] } # async runtime
|
tokio = { version = "1.24.1", features = ["rt-multi-thread", "net", "signal", "macros"] } # async runtime
|
||||||
|
|
||||||
coconut-interface = { path = "../../common/coconut-interface" }
|
nym-coconut-interface = { path = "../../common/coconut-interface" }
|
||||||
config = { path = "../../common/config" }
|
nym-config = { path = "../../common/config" }
|
||||||
completions = { path = "../../common/completions" }
|
nym-credentials = { path = "../../common/credentials" }
|
||||||
credentials = { path = "../../common/credentials" }
|
nym-credential-storage = { path = "../../common/credential-storage" }
|
||||||
credential-storage = { path = "../../common/credential-storage" }
|
nym-crypto = { path = "../../common/crypto", features = ["rand", "asymmetric", "symmetric", "aes", "hashing"] }
|
||||||
crypto = { path = "../../common/crypto", features = ["rand", "asymmetric", "symmetric", "aes", "hashing"] }
|
nym-bin-common = { path = "../../common/bin-common"}
|
||||||
network-defaults = { path = "../../common/network-defaults" }
|
nym-network-defaults = { path = "../../common/network-defaults" }
|
||||||
pemstore = { path = "../../common/pemstore" }
|
nym-pemstore = { path = "../../common/pemstore" }
|
||||||
validator-client = { path = "../../common/client-libs/validator-client", features = ["nyxd-client"] }
|
validator-client = { path = "../../common/client-libs/validator-client", features = ["nyxd-client"] }
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
use crate::error::Result;
|
use crate::error::Result;
|
||||||
use bip39::Mnemonic;
|
use bip39::Mnemonic;
|
||||||
use network_defaults::{NymNetworkDetails, VOUCHER_INFO};
|
use nym_network_defaults::{NymNetworkDetails, VOUCHER_INFO};
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
use validator_client::nyxd;
|
use validator_client::nyxd;
|
||||||
|
|||||||
@@ -1,29 +1,32 @@
|
|||||||
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use clap::{Args, Subcommand};
|
use clap::{ArgGroup, Args, Subcommand};
|
||||||
use completions::ArgShell;
|
use log::*;
|
||||||
|
use nym_bin_common::completions::ArgShell;
|
||||||
use rand::rngs::OsRng;
|
use rand::rngs::OsRng;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
use coconut_interface::{Base58, Parameters};
|
use nym_coconut_interface::{Base58, Parameters};
|
||||||
use credential_storage::storage::Storage;
|
use nym_credential_storage::storage::Storage;
|
||||||
use credential_storage::PersistentStorage;
|
use nym_credential_storage::PersistentStorage;
|
||||||
use credentials::coconut::bandwidth::{BandwidthVoucher, TOTAL_ATTRIBUTES};
|
use nym_credentials::coconut::bandwidth::{BandwidthVoucher, TOTAL_ATTRIBUTES};
|
||||||
use credentials::coconut::utils::obtain_aggregate_signature;
|
use nym_credentials::coconut::utils::obtain_aggregate_signature;
|
||||||
use crypto::asymmetric::{encryption, identity};
|
use nym_crypto::asymmetric::{encryption, identity};
|
||||||
use network_defaults::{NymNetworkDetails, VOUCHER_INFO};
|
use nym_network_defaults::VOUCHER_INFO;
|
||||||
use validator_client::nyxd::traits::DkgQueryClient;
|
use validator_client::nyxd::traits::DkgQueryClient;
|
||||||
use validator_client::nyxd::tx::Hash;
|
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::client::Client;
|
||||||
use crate::error::{CredentialClientError, Result};
|
use crate::error::{CredentialClientError, Result};
|
||||||
|
use crate::recovery_storage::RecoveryStorage;
|
||||||
use crate::state::{KeyPair, State};
|
use crate::state::{KeyPair, State};
|
||||||
|
|
||||||
#[derive(Subcommand)]
|
#[derive(Subcommand)]
|
||||||
pub(crate) enum Command {
|
pub(crate) enum Command {
|
||||||
/// Run the binary
|
/// Run the binary to obtain a credential
|
||||||
Run(Run),
|
Run(Run),
|
||||||
|
|
||||||
/// Generate shell completions
|
/// Generate shell completions
|
||||||
@@ -34,6 +37,11 @@ pub(crate) enum Command {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Args)]
|
#[derive(Args)]
|
||||||
|
#[clap(group(
|
||||||
|
ArgGroup::new("recov")
|
||||||
|
.required(true)
|
||||||
|
.args(&["amount", "recovery_mode"]),
|
||||||
|
))]
|
||||||
pub(crate) struct Run {
|
pub(crate) struct Run {
|
||||||
/// Home directory of the client that is supposed to use the credential.
|
/// Home directory of the client that is supposed to use the credential.
|
||||||
#[clap(long)]
|
#[clap(long)]
|
||||||
@@ -47,15 +55,25 @@ pub(crate) struct Run {
|
|||||||
#[clap(long)]
|
#[clap(long)]
|
||||||
pub(crate) mnemonic: String,
|
pub(crate) mnemonic: String,
|
||||||
|
|
||||||
/// The amount of utokens the credential will hold
|
/// The amount of utokens the credential will hold. If recovery mode is enabled, this value
|
||||||
#[clap(long)]
|
/// is not needed
|
||||||
|
#[clap(long, default_value = "0")]
|
||||||
pub(crate) amount: u64,
|
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> {
|
pub(crate) async fn deposit(nyxd_url: &str, mnemonic: &str, amount: u64) -> Result<State> {
|
||||||
let mut rng = OsRng;
|
let mut rng = OsRng;
|
||||||
let signing_keypair = KeyPair::from(identity::KeyPair::new(&mut rng));
|
let signing_keypair = KeyPair::from(identity::KeyPair::new(&mut rng));
|
||||||
let encryption_keypair = KeyPair::from(encryption::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 client = Client::new(nyxd_url, mnemonic);
|
||||||
let tx_hash = client
|
let tx_hash = client
|
||||||
@@ -67,46 +85,47 @@ pub(crate) async fn deposit(nyxd_url: &str, mnemonic: &str, amount: u64) -> Resu
|
|||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let state = State {
|
let voucher = BandwidthVoucher::new(
|
||||||
amount,
|
¶ms,
|
||||||
tx_hash,
|
amount.to_string(),
|
||||||
signing_keypair,
|
VOUCHER_INFO.to_string(),
|
||||||
encryption_keypair,
|
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)
|
Ok(state)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn get_credential(state: &State, shared_storage: PersistentStorage) -> Result<()> {
|
pub(crate) async fn get_credential<C: Clone + CosmWasmClient + Send + Sync>(
|
||||||
let network_details = NymNetworkDetails::new_from_env();
|
state: &State,
|
||||||
let config = Config::try_from_nym_network_details(&network_details)?;
|
client: validator_client::Client<C>,
|
||||||
let client = validator_client::Client::new_query(config)?;
|
shared_storage: PersistentStorage,
|
||||||
|
) -> Result<()> {
|
||||||
let epoch_id = client.nyxd.get_current_epoch().await?.epoch_id;
|
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 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(
|
let signature = obtain_aggregate_signature(
|
||||||
¶ms,
|
&state.params,
|
||||||
&bandwidth_credential_attributes,
|
&state.voucher,
|
||||||
&coconut_api_clients,
|
&coconut_api_clients,
|
||||||
|
threshold,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
println!("Signature: {:?}", signature.to_bs58());
|
info!("Signature: {:?}", signature.to_bs58());
|
||||||
shared_storage
|
shared_storage
|
||||||
.insert_coconut_credential(
|
.insert_coconut_credential(
|
||||||
state.amount.to_string(),
|
state.voucher.get_voucher_value(),
|
||||||
VOUCHER_INFO.to_string(),
|
VOUCHER_INFO.to_string(),
|
||||||
bandwidth_credential_attributes.get_private_attributes()[0].to_bs58(),
|
state.voucher.get_private_attributes()[0].to_bs58(),
|
||||||
bandwidth_credential_attributes.get_private_attributes()[1].to_bs58(),
|
state.voucher.get_private_attributes()[1].to_bs58(),
|
||||||
signature.to_bs58(),
|
signature.to_bs58(),
|
||||||
epoch_id.to_string(),
|
epoch_id.to_string(),
|
||||||
)
|
)
|
||||||
@@ -114,3 +133,33 @@ pub(crate) async fn get_credential(state: &State, shared_storage: PersistentStor
|
|||||||
|
|
||||||
Ok(())
|
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>
|
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
use std::time::SystemTimeError;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
use credential_storage::error::StorageError;
|
use nym_credential_storage::error::StorageError;
|
||||||
use credentials::error::Error as CredentialError;
|
use nym_credentials::error::Error as CredentialError;
|
||||||
use crypto::asymmetric::encryption::KeyRecoveryError;
|
use nym_crypto::asymmetric::encryption::KeyRecoveryError;
|
||||||
use crypto::asymmetric::identity::Ed25519RecoveryError;
|
use nym_crypto::asymmetric::identity::Ed25519RecoveryError;
|
||||||
use validator_client::nyxd::error::NyxdError;
|
use validator_client::nyxd::error::NyxdError;
|
||||||
use validator_client::ValidatorClientError;
|
use validator_client::ValidatorClientError;
|
||||||
|
|
||||||
@@ -14,6 +15,9 @@ pub type Result<T> = std::result::Result<T, CredentialClientError>;
|
|||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
pub enum CredentialClientError {
|
pub enum CredentialClientError {
|
||||||
|
#[error("IO error: {0}")]
|
||||||
|
IOError(#[from] std::io::Error),
|
||||||
|
|
||||||
#[error("Nyxd error: {0}")]
|
#[error("Nyxd error: {0}")]
|
||||||
Nyxd(#[from] NyxdError),
|
Nyxd(#[from] NyxdError),
|
||||||
|
|
||||||
@@ -34,4 +38,10 @@ pub enum CredentialClientError {
|
|||||||
|
|
||||||
#[error("Could not use shared storage")]
|
#[error("Could not use shared storage")]
|
||||||
SharedStorageError(#[from] StorageError),
|
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 client;
|
||||||
mod commands;
|
mod commands;
|
||||||
mod error;
|
mod error;
|
||||||
|
mod recovery_storage;
|
||||||
mod state;
|
mod state;
|
||||||
|
|
||||||
use commands::*;
|
use commands::*;
|
||||||
use completions::fig_generate;
|
|
||||||
use config::{DATA_DIR, DB_FILE_NAME};
|
|
||||||
use error::Result;
|
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 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)]
|
#[derive(Parser)]
|
||||||
#[clap(author = "Nymtech", version, about)]
|
#[clap(author = "Nymtech", version, about)]
|
||||||
@@ -25,19 +35,77 @@ struct Cli {
|
|||||||
pub(crate) command: Command,
|
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]
|
#[tokio::main]
|
||||||
async fn main() -> Result<()> {
|
async fn main() -> Result<()> {
|
||||||
let args = Cli::parse();
|
let args = Cli::parse();
|
||||||
|
setup_logging();
|
||||||
setup_env(args.config_env_file.as_ref());
|
setup_env(args.config_env_file.as_ref());
|
||||||
let bin_name = "nym-credential-client";
|
let bin_name = "nym-credential-client";
|
||||||
|
|
||||||
match args.command {
|
match args.command {
|
||||||
Command::Run(r) => {
|
Command::Run(r) => {
|
||||||
let db_path = r.client_home_directory.join(DATA_DIR).join(DB_FILE_NAME);
|
let db_path = r
|
||||||
let shared_storage = credential_storage::initialise_storage(db_path).await;
|
.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?;
|
let network_details = NymNetworkDetails::new_from_env();
|
||||||
get_credential(&state, shared_storage).await?;
|
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::Completions(c) => c.generate(&mut crate::Cli::command(), bin_name),
|
||||||
Command::GenerateFigSpec => fig_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>
|
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// 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(crate) struct KeyPair {
|
||||||
pub public_key: String,
|
pub public_key: String,
|
||||||
pub private_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(crate) struct State {
|
||||||
pub amount: u64,
|
pub voucher: BandwidthVoucher,
|
||||||
pub tx_hash: String,
|
pub params: Parameters,
|
||||||
pub signing_keypair: KeyPair,
|
|
||||||
pub encryption_keypair: KeyPair,
|
|
||||||
}
|
}
|
||||||
|
|||||||
+12
-16
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "nym-client"
|
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>"]
|
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"]
|
||||||
description = "Implementation of the Nym Client"
|
description = "Implementation of the Nym Client"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
@@ -34,25 +34,21 @@ tokio = { version = "1.24.1", features = ["rt-multi-thread", "net", "signal"] }
|
|||||||
tokio-tungstenite = "0.14" # websocket
|
tokio-tungstenite = "0.14" # websocket
|
||||||
|
|
||||||
## internal
|
## internal
|
||||||
build-information = { path = "../../common/build-information" }
|
nym-bin-common = { path = "../../common/bin-common" }
|
||||||
client-core = { path = "../client-core", features = ["fs-surb-storage"] }
|
client-core = { path = "../client-core", features = ["fs-surb-storage"] }
|
||||||
client-connections = { path = "../../common/client-connections" }
|
nym-coconut-interface = { path = "../../common/coconut-interface" }
|
||||||
coconut-interface = { path = "../../common/coconut-interface" }
|
nym-config = { path = "../../common/config" }
|
||||||
config = { path = "../../common/config" }
|
nym-credential-storage = { path = "../../common/credential-storage" }
|
||||||
completions = { path = "../../common/completions" }
|
nym-credentials = { path = "../../common/credentials" }
|
||||||
credential-storage = { path = "../../common/credential-storage" }
|
nym-crypto = { path = "../../common/crypto" }
|
||||||
credentials = { path = "../../common/credentials" }
|
|
||||||
crypto = { path = "../../common/crypto" }
|
|
||||||
logging = { path = "../../common/logging"}
|
|
||||||
gateway-client = { path = "../../common/client-libs/gateway-client" }
|
gateway-client = { path = "../../common/client-libs/gateway-client" }
|
||||||
gateway-requests = { path = "../../gateway/gateway-requests" }
|
gateway-requests = { path = "../../gateway/gateway-requests" }
|
||||||
network-defaults = { path = "../../common/network-defaults" }
|
nym-network-defaults = { path = "../../common/network-defaults" }
|
||||||
nymsphinx = { path = "../../common/nymsphinx" }
|
nym-sphinx = { path = "../../common/nymsphinx" }
|
||||||
pemstore = { path = "../../common/pemstore" }
|
nym-pemstore = { path = "../../common/pemstore" }
|
||||||
task = { path = "../../common/task" }
|
nym-task = { path = "../../common/task" }
|
||||||
topology = { path = "../../common/topology" }
|
nym-topology = { path = "../../common/topology" }
|
||||||
validator-client = { path = "../../common/client-libs/validator-client", features = ["nyxd-client"] }
|
validator-client = { path = "../../common/client-libs/validator-client", features = ["nyxd-client"] }
|
||||||
version-checker = { path = "../../common/version-checker" }
|
|
||||||
websocket-requests = { path = "websocket-requests" }
|
websocket-requests = { path = "websocket-requests" }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use futures::{SinkExt, StreamExt};
|
use futures::{SinkExt, StreamExt};
|
||||||
use nymsphinx::addressing::clients::Recipient;
|
use nym_sphinx::addressing::clients::Recipient;
|
||||||
use tokio::net::TcpStream;
|
use tokio::net::TcpStream;
|
||||||
use tokio_tungstenite::{
|
use tokio_tungstenite::{
|
||||||
connect_async, tungstenite::protocol::Message, MaybeTlsStream, WebSocketStream,
|
connect_async, tungstenite::protocol::Message, MaybeTlsStream, WebSocketStream,
|
||||||
|
|||||||
@@ -2,16 +2,19 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use crate::client::config::template::config_template;
|
use crate::client::config::template::config_template;
|
||||||
pub use client_core::config::Config as BaseConfig;
|
use client_core::config::ClientCoreConfigTrait;
|
||||||
pub use client_core::config::MISSING_VALUE;
|
use nym_config::defaults::DEFAULT_WEBSOCKET_LISTENING_PORT;
|
||||||
use client_core::config::{ClientCoreConfigTrait, DebugConfig};
|
use nym_config::{NymConfig, OptionalSet};
|
||||||
use config::defaults::DEFAULT_WEBSOCKET_LISTENING_PORT;
|
|
||||||
use config::{NymConfig, OptionalSet};
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
use std::net::{IpAddr, Ipv4Addr};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::str::FromStr;
|
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;
|
mod template;
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, PartialEq, Eq, Serialize, Clone, Copy)]
|
#[derive(Debug, Deserialize, PartialEq, Eq, Serialize, Clone, Copy)]
|
||||||
@@ -104,6 +107,11 @@ impl Config {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn with_host(mut self, host: IpAddr) -> Self {
|
||||||
|
self.socket.host = host;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
pub fn with_port(mut self, port: u16) -> Self {
|
pub fn with_port(mut self, port: u16) -> Self {
|
||||||
self.socket.listening_port = port;
|
self.socket.listening_port = port;
|
||||||
self
|
self
|
||||||
@@ -130,6 +138,10 @@ impl Config {
|
|||||||
self.socket.socket_type
|
self.socket.socket_type
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_listening_ip(&self) -> IpAddr {
|
||||||
|
self.socket.host
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_listening_port(&self) -> u16 {
|
pub fn get_listening_port(&self) -> u16 {
|
||||||
self.socket.listening_port
|
self.socket.listening_port
|
||||||
}
|
}
|
||||||
@@ -180,9 +192,10 @@ impl Config {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, PartialEq, Eq, Serialize)]
|
#[derive(Debug, Deserialize, PartialEq, Eq, Serialize)]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(default, deny_unknown_fields)]
|
||||||
pub struct Socket {
|
pub struct Socket {
|
||||||
socket_type: SocketType,
|
socket_type: SocketType,
|
||||||
|
host: IpAddr,
|
||||||
listening_port: u16,
|
listening_port: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -190,6 +203,7 @@ impl Default for Socket {
|
|||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Socket {
|
Socket {
|
||||||
socket_type: SocketType::WebSocket,
|
socket_type: SocketType::WebSocket,
|
||||||
|
host: IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)),
|
||||||
listening_port: DEFAULT_WEBSOCKET_LISTENING_PORT,
|
listening_port: DEFAULT_WEBSOCKET_LISTENING_PORT,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -93,6 +93,9 @@ socket_type = '{{ socket.socket_type }}'
|
|||||||
# will be listening for incoming requests
|
# will be listening for incoming requests
|
||||||
listening_port = {{ socket.listening_port }}
|
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 #####
|
##### 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