Compare commits

..

22 Commits

Author SHA1 Message Date
Simon Wicky edfb75b9ef remove test client 2023-03-28 16:12:21 +02:00
Simon Wicky 298591b9e0 Merge commit '009b2131f61dc447ad08b5f1df1e2eef44cde1d2' into simon/instrumented 2023-03-28 13:45:37 +00:00
Simon Wicky 009b2131f6 instrumentation 2023-03-28 13:24:45 +00:00
Simon Wicky e5af0f5d5e Merge commit '3cad2dbb341c23592d22856ced5c8020a7ea20b7' into simon/instrumented 2023-03-28 13:21:46 +00:00
Simon Wicky 3cad2dbb34 Merge remote-tracking branch 'origin/simon/instrumented' into simon/instrumented 2023-03-28 13:18:53 +00:00
Simon Wicky e95e33cd70 Merge commit '6d44fe818ea4c74f476cc6d79434cc8619b45c0c' into simon/instrumented 2023-03-28 13:17:09 +00:00
Simon Wicky 5281895d5b mixnode instrumentation 2023-03-28 12:39:06 +00:00
Simon Wicky 263db0dbc3 Merge commit '6d44fe818ea4c74f476cc6d79434cc8619b45c0c' into Simon/1.1.4 2023-03-28 11:55:06 +00:00
Simon Wicky 6d44fe818e Merge commit '2878e9be9d0c397a746a8c942b818ac1168dff6f' into simon 2023-03-28 11:50:17 +02:00
Simon Wicky b8ec48cf07 small changes to warmup phase 2023-03-28 09:41:35 +00:00
Simon Wicky 99227e837c disable some epoch operations 2023-03-23 07:52:39 +00:00
Simon Wicky 34cb142595 packet size the end 2023-03-22 08:40:33 +00:00
Simon Wicky 2988ae4459 packet size in config 2023-03-10 14:16:53 +00:00
Simon Wicky e653b632ba packet sizes support 2023-03-10 13:18:19 +00:00
Simon Wicky eb216a06b3 redirect mixnodes/active to mixnodes 2023-03-10 13:18:15 +00:00
Simon Wicky 921f01a789 Merge commit 'f4d0a120bb7f552591c415ece31d9f75bd6ec33e' into Simon/1.1.5 2023-01-31 09:31:24 +00:00
Simon Wicky 27bf8b2e00 tracing first part 2023-01-31 09:25:15 +00:00
Simon Wicky e82a669cd3 merge 1.1.5 2023-01-11 15:17:15 +00:00
Simon Wicky 2015443a90 set default packetsize back to 2 2023-01-10 10:23:51 +00:00
Simon Wicky 2c2823f9e1 test instrumentation 2022-12-21 08:31:16 +00:00
Simon Wicky 52b41a5697 add packet sizes support 2022-12-21 08:06:23 +00:00
Simon Wicky 9ee6ae44e2 remove override config, and active nodes 2022-12-21 08:06:13 +00:00
1751 changed files with 62645 additions and 110351 deletions
+22 -17
View File
@@ -11,25 +11,30 @@
# In each subsection folders are ordered first by depth, then alphabetically. # In each subsection folders are ordered first by depth, then alphabetically.
# This should make it easy to add new rules without breaking existing ones. # This should make it easy to add new rules without breaking existing ones.
# contracts # Something weird not covered by anything else
/contracts/mixnet @durch @jstuczyn * @futurechimp @mmsinclair
/contracts/vesting @durch @jstuczyn
/contracts/service-provider-directory @octol
# crypto code # Rust rules:
/common/crypto/ @jstuczyn *.rs @durch @futurechimp @jstuczyn @neacsu @octol
/common/nymcoconut/ @jstuczyn Cargo.* @durch @futurechimp @jstuczyn @neacsu @octol
/common/dkg/ @jstuczyn
/common/nymsphinx/ @jstuczyn
# rust sdk # JS rules:
/sdk/rust/ @octol *.js @mmsinclair @fmtabbara
*.ts @mmsinclair @fmtabbara
*.tsx @mmsinclair @fmtabbara
*.jsx @mmsinclair @fmtabbara
# nym-connect (rust) # Something looking like possible documentation rules:
/nym-connect/desktop/src-tauri/ @octol *.md @mfahampshire
# nym-wallet (rust) # our docker scripts
/nym-wallet/src-tauri/ @octol /docker/ @neacsu
# documentation # if there are any changes in the core crypto, I feel like Ania should take a look:
/documentation @mfahampshire /common/crypto/ @aniampio
/common/nymsphinx/ @aniampio
# Explorer and wallet should probably get looked by the product team
/explorer/ @nymtech/product
/nym-wallet/ @nymtech/product
/wallet-web/ @nymtech/product
-14
View File
@@ -1,14 +0,0 @@
---
name: 'Documentation'
about: Suggest a fix or enhancement to the documentation or developer portal content
title: "[DOCS]"
labels: documentation, needs-triage
assignees: mfahampshire
---
Is your issue either:
- [ ] a fix to existing documentation (e.g. fixing a broken link or incorrect command)
- [ ] an enhancement (e.g. adding a description for an undocumented feature)
Please briefly describe your issue:
+1 -1
View File
@@ -2,7 +2,7 @@
name: Feature request name: Feature request
about: Suggest an enhancement to the product about: Suggest an enhancement to the product
title: "[Feature Request]" title: "[Feature Request]"
labels: enhancement, needs-triage labels: enhancement
assignees: '' assignees: ''
--- ---
+1 -1
View File
@@ -2,7 +2,7 @@
name: Report name: Report
about: To help identify and reproduce issues about: To help identify and reproduce issues
title: "[Issue]" title: "[Issue]"
labels: bug, bug-needs-triage, qa, needs-triage labels: bug, bug-needs-triage, qa
assignees: tommyv1987 assignees: tommyv1987
--- ---
-16
View File
@@ -1,16 +0,0 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
version: 2
updates:
# Maintain dependencies for GitHub Actions
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "daily"
commit-message:
prefix: build
prefix-development: chore
include: scope
+1 -1
View File
@@ -38,7 +38,7 @@ jobs:
- name: install npm - name: install npm
uses: actions/setup-node@v3 uses: actions/setup-node@v3
with: with:
node-version: 18 node-version: 16
- name: Matrix - Node Install - name: Matrix - Node Install
run: npm install run: npm install
working-directory: .github/workflows/support-files working-directory: .github/workflows/support-files
@@ -63,7 +63,7 @@ jobs:
- name: Install Rust stable - name: Install Rust stable
uses: actions-rs/toolchain@v1 uses: actions-rs/toolchain@v1
with: with:
toolchain: 1.69.0 toolchain: stable
- name: Build all binaries - name: Build all binaries
uses: actions-rs/cargo@v1 uses: actions-rs/cargo@v1
@@ -74,13 +74,13 @@ jobs:
- name: Install Rust stable - name: Install Rust stable
uses: actions-rs/toolchain@v1 uses: actions-rs/toolchain@v1
with: with:
toolchain: 1.69.0 toolchain: stable
target: wasm32-unknown-unknown target: wasm32-unknown-unknown
override: true override: true
components: rustfmt, clippy components: rustfmt, clippy
- name: Install wasm-opt - name: Install wasm-opt
run: cargo install --version 0.112.0 wasm-opt run: cargo install --version 0.110.0 wasm-opt
- name: Build release contracts - name: Build release contracts
run: make wasm run: make wasm
@@ -98,7 +98,7 @@ jobs:
cp target/release/nym-network-requester $OUTPUT_DIR cp target/release/nym-network-requester $OUTPUT_DIR
cp target/release/nym-network-statistics $OUTPUT_DIR cp target/release/nym-network-statistics $OUTPUT_DIR
cp target/release/nym-cli $OUTPUT_DIR cp target/release/nym-cli $OUTPUT_DIR
cp target/release/nym-credential-client $OUTPUT_DIR cp target/release/credential $OUTPUT_DIR
cp target/release/explorer-api $OUTPUT_DIR cp target/release/explorer-api $OUTPUT_DIR
cp contracts/target/wasm32-unknown-unknown/release/mixnet_contract.wasm $OUTPUT_DIR cp contracts/target/wasm32-unknown-unknown/release/mixnet_contract.wasm $OUTPUT_DIR
@@ -107,8 +107,6 @@ jobs:
cp contracts/target/wasm32-unknown-unknown/release/nym_coconut_dkg.wasm $OUTPUT_DIR cp contracts/target/wasm32-unknown-unknown/release/nym_coconut_dkg.wasm $OUTPUT_DIR
cp contracts/target/wasm32-unknown-unknown/release/cw3_flex_multisig.wasm $OUTPUT_DIR cp contracts/target/wasm32-unknown-unknown/release/cw3_flex_multisig.wasm $OUTPUT_DIR
cp contracts/target/wasm32-unknown-unknown/release/cw4_group.wasm $OUTPUT_DIR cp contracts/target/wasm32-unknown-unknown/release/cw4_group.wasm $OUTPUT_DIR
cp contracts/target/wasm32-unknown-unknown/release/nym_service_provider_directory.wasm $OUTPUT_DIR
cp contracts/target/wasm32-unknown-unknown/release/nym_name_service.wasm $OUTPUT_DIR
- name: Deploy branch to CI www - name: Deploy branch to CI www
continue-on-error: true continue-on-error: true
+1 -1
View File
@@ -16,7 +16,7 @@ jobs:
- uses: rlespinasse/github-slug-action@v3.x - uses: rlespinasse/github-slug-action@v3.x
- uses: actions/setup-node@v3 - uses: actions/setup-node@v3
with: with:
node-version: 18 node-version: 16
- name: Setup yarn - name: Setup yarn
run: npm install -g yarn run: npm install -g yarn
- name: Build - name: Build
-4
View File
@@ -9,14 +9,12 @@ on:
- 'gateway/**' - 'gateway/**'
- 'integrations/**' - 'integrations/**'
- 'mixnode/**' - 'mixnode/**'
- 'sdk/lib/socks5-listener/**'
- 'sdk/rust/nym-sdk/**' - 'sdk/rust/nym-sdk/**'
- 'service-providers/**' - 'service-providers/**'
- 'nym-api/**' - 'nym-api/**'
- 'nym-outfox/**' - 'nym-outfox/**'
- 'tools/nym-cli/**' - 'tools/nym-cli/**'
- 'tools/ts-rs-cli/**' - 'tools/ts-rs-cli/**'
- 'Cargo.toml'
pull_request: pull_request:
paths: paths:
- 'clients/**' - 'clients/**'
@@ -25,14 +23,12 @@ on:
- 'gateway/**' - 'gateway/**'
- 'integrations/**' - 'integrations/**'
- 'mixnode/**' - 'mixnode/**'
- 'sdk/lib/socks5-listener/**'
- 'sdk/rust/nym-sdk/**' - 'sdk/rust/nym-sdk/**'
- 'service-providers/**' - 'service-providers/**'
- 'nym-api/**' - 'nym-api/**'
- 'nym-outfox/**' - 'nym-outfox/**'
- 'tools/nym-cli/**' - 'tools/nym-cli/**'
- 'tools/ts-rs-cli/**' - 'tools/ts-rs-cli/**'
- 'Cargo.toml'
jobs: jobs:
build: build:
-76
View File
@@ -1,76 +0,0 @@
name: CD dev-portal
on:
push:
branches: master
paths:
- 'documentation/dev-portal/**'
jobs:
build:
runs-on: custom-runner-linux
steps:
- uses: actions/checkout@v3
- name: Install rsync
run: sudo apt-get install rsync
- uses: rlespinasse/github-slug-action@v3.x
- uses: actions/setup-node@v3
with:
node-version: 18
- name: Install Rust stable
uses: actions-rs/toolchain@v1
with:
toolchain: stable
- name: Install mdbook
run: (test -x $HOME/.cargo/bin/mdbook || cargo install --vers "^0.4" mdbook)
- name: Install mdbook plugins
run: |
cargo install --vers "^0.2.0" mdbook-variables && cargo install \
--vers "^1.8.0" mdbook-admonish && cargo install --vers \
"^0.1.2" mdbook-last-changed && cargo install --vers "^0.1.2" \
mdbook-theme && cargo install --vers "^0.7.7" mdbook-linkcheck
- name: Clean website
run: cd documentation/dev-portal && mdbook clean
- name: Build website
run: cd documentation/dev-portal && mdbook build
- name: Deploy branch master to dev
continue-on-error: true
uses: easingthemes/ssh-deploy@main
env:
SSH_PRIVATE_KEY: ${{ secrets.CD_WWW_SSH_PRIVATE_KEY }}
ARGS: "-rltgoDzvO --delete"
SOURCE: "documentation/dev-portal/book/html/"
REMOTE_HOST: ${{ secrets.CD_WWW_REMOTE_HOST_DEV }}
REMOTE_USER: ${{ secrets.CD_WWW_REMOTE_USER }}
TARGET: ${{ secrets.CD_WWW_REMOTE_TARGET_DEVP }}/
EXCLUDE: "/dist/, /node_modules/"
- name: Deploy branch master to prod
uses: easingthemes/ssh-deploy@main
env:
SSH_PRIVATE_KEY: ${{ secrets.CD_WWW_SSH_PRIVATE_KEY }}
ARGS: "-rltgoDzvO --delete"
SOURCE: "documentation/dev-portal/book/html/"
REMOTE_HOST: ${{ secrets.CD_WWW_REMOTE_HOST_PROD }}
REMOTE_USER: ${{ secrets.CD_WWW_REMOTE_USER }}
TARGET: ${{ secrets.CD_WWW_REMOTE_TARGET_DEVP }}/
EXCLUDE: "/dist/, /node_modules/"
- name: Matrix - Node Install
run: npm install
working-directory: .github/workflows/support-files
- name: Matrix - Send Notification
env:
NYM_NOTIFICATION_KIND: cd-dev
NYM_PROJECT_NAME: "Dev portal CD"
NYM_CI_WWW_BASE: "${{ secrets.NYM_CD_WWW_BASE }}"
NYM_CI_WWW_LOCATION: "${{ env.GITHUB_REF_SLUG }}"
GIT_COMMIT_MESSAGE: "${{ github.event.head_commit.message }}"
GIT_BRANCH: "${GITHUB_REF##*/}"
MATRIX_SERVER: "${{ secrets.MATRIX_SERVER }}"
MATRIX_ROOM: "${{ secrets.MATRIX_ROOM_DEVP }}"
MATRIX_USER_ID: "${{ secrets.MATRIX_USER_ID }}"
MATRIX_TOKEN: "${{ secrets.MATRIX_TOKEN }}"
MATRIX_DEVICE_ID: "${{ secrets.MATRIX_DEVICE_ID }}"
IS_SUCCESS: "${{ job.status == 'success' }}"
uses: docker://keybaseio/client:stable-node
with:
args: .github/workflows/support-files/notifications/entry_point.sh
-82
View File
@@ -1,82 +0,0 @@
name: CD docs
on:
push:
branches: master
paths:
- 'documentation/docs/**'
jobs:
build:
runs-on: custom-runner-linux
steps:
- uses: actions/checkout@v3
- name: Install rsync
run: sudo apt-get install rsync
- uses: rlespinasse/github-slug-action@v3.x
- uses: actions/setup-node@v3
with:
node-version: 18
- 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 mdbook
run: (test -x $HOME/.cargo/bin/mdbook || cargo install --vers "^0.4" mdbook)
- name: Install mdbook plugins
run: |
cargo install --vers "^0.2.0" mdbook-variables && cargo install \
--vers "^1.8.0" mdbook-admonish && cargo install --vers \
"^0.1.2" mdbook-last-changed && cargo install --vers "^0.1.2" \
mdbook-theme && cargo install --vers "^0.7.7" mdbook-linkcheck && \
cargo install --vers "^0.5.0" mdbook-cmdrun
- name: Clean website
run: cd documentation/docs && mdbook clean
- name: Build website
run: cd documentation/docs && mdbook build
- name: Deploy branch master to dev
continue-on-error: true
uses: easingthemes/ssh-deploy@main
env:
SSH_PRIVATE_KEY: ${{ secrets.CD_WWW_SSH_PRIVATE_KEY }}
ARGS: "-rltgoDzvO --delete"
SOURCE: "documentation/docs/book/"
REMOTE_HOST: ${{ secrets.CD_WWW_REMOTE_HOST_DEV }}
REMOTE_USER: ${{ secrets.CD_WWW_REMOTE_USER }}
TARGET: ${{ secrets.CD_WWW_REMOTE_TARGET }}/
EXCLUDE: "/dist/, /node_modules/"
- name: Deploy branch master to prod
uses: easingthemes/ssh-deploy@main
env:
SSH_PRIVATE_KEY: ${{ secrets.CD_WWW_SSH_PRIVATE_KEY }}
ARGS: "-rltgoDzvO --delete"
SOURCE: "documentation/docs/book/"
REMOTE_HOST: ${{ secrets.CD_WWW_REMOTE_HOST_PROD }}
REMOTE_USER: ${{ secrets.CD_WWW_REMOTE_USER }}
TARGET: ${{ secrets.CD_WWW_REMOTE_TARGET }}/
EXCLUDE: "/dist/, /node_modules/"
- name: Matrix - Node Install
run: npm install
working-directory: .github/workflows/support-files
- name: Matrix - Send Notification
env:
NYM_NOTIFICATION_KIND: cd-docs
NYM_PROJECT_NAME: "Docs CD"
NYM_CI_WWW_BASE: "${{ secrets.NYM_CD_WWW_BASE }}"
NYM_CI_WWW_LOCATION: "${{ env.GITHUB_REF_SLUG }}"
GIT_COMMIT_MESSAGE: "${{ github.event.head_commit.message }}"
GIT_BRANCH: "${GITHUB_REF##*/}"
MATRIX_SERVER: "${{ secrets.MATRIX_SERVER }}"
MATRIX_ROOM: "${{ secrets.MATRIX_ROOM_DOCS }}"
MATRIX_USER_ID: "${{ secrets.MATRIX_USER_ID }}"
MATRIX_TOKEN: "${{ secrets.MATRIX_TOKEN }}"
MATRIX_DEVICE_ID: "${{ secrets.MATRIX_DEVICE_ID }}"
IS_SUCCESS: "${{ job.status == 'success' }}"
uses: docker://keybaseio/client:stable-node
with:
args: .github/workflows/support-files/notifications/entry_point.sh
-66
View File
@@ -1,66 +0,0 @@
name: CI dev-portal
on:
push:
branches-ignore: master
paths:
- 'documentation/dev-portal/**'
jobs:
build:
runs-on: custom-runner-linux
steps:
- uses: actions/checkout@v3
- name: Install rsync
run: sudo apt-get install rsync
- uses: rlespinasse/github-slug-action@v3.x
- uses: actions/setup-node@v3
with:
node-version: 18
- name: Install Rust stable
uses: actions-rs/toolchain@v1
with:
toolchain: stable
- name: Install mdbook
run: (test -x $HOME/.cargo/bin/mdbook || cargo install --vers "^0.4" mdbook)
- name: Install mdbook plugins
run: |
cargo install --vers "^0.2.0" mdbook-variables && cargo install \
--vers "^1.8.0" mdbook-admonish && cargo install --vers \
"^0.1.2" mdbook-last-changed && cargo install --vers "^0.1.2" mdbook-theme \
&& cargo install --vers "^0.7.7" mdbook-linkcheck
- name: Clean website
run: cd documentation/dev-portal && mdbook clean
- name: Build website
run: cd documentation/dev-portal && mdbook build
- 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: "-rltgoDzvO --delete"
SOURCE: "documentation/dev-portal/book/html/"
REMOTE_HOST: ${{ secrets.CI_WWW_REMOTE_HOST }}
REMOTE_USER: ${{ secrets.CI_WWW_REMOTE_USER }}
TARGET: ${{ secrets.CI_WWW_REMOTE_TARGET }}/dev-portal-${{ env.GITHUB_REF_SLUG }}
EXCLUDE: "/dist/, /node_modules/"
- name: Matrix - Node Install
run: npm install
working-directory: .github/workflows/support-files
- name: Matrix - Send Notification
env:
NYM_NOTIFICATION_KIND: ci-dev
NYM_PROJECT_NAME: "Dev portal CI"
NYM_CI_WWW_BASE: "${{ secrets.NYM_CI_WWW_BASE }}"
NYM_CI_WWW_LOCATION: "dev-portal-${{ env.GITHUB_REF_SLUG }}"
GIT_COMMIT_MESSAGE: "${{ github.event.head_commit.message }}"
GIT_BRANCH: "${GITHUB_REF##*/}"
MATRIX_SERVER: "${{ secrets.MATRIX_SERVER }}"
MATRIX_ROOM: "${{ secrets.MATRIX_ROOM_DEVP }}"
MATRIX_USER_ID: "${{ secrets.MATRIX_USER_ID }}"
MATRIX_TOKEN: "${{ secrets.MATRIX_TOKEN }}"
MATRIX_DEVICE_ID: "${{ secrets.MATRIX_DEVICE_ID }}"
IS_SUCCESS: "${{ job.status == 'success' }}"
uses: docker://keybaseio/client:stable-node
with:
args: .github/workflows/support-files/notifications/entry_point.sh
-72
View File
@@ -1,72 +0,0 @@
name: CI docs
on:
push:
branches-ignore: master
paths:
- 'documentation/docs/**'
jobs:
build:
runs-on: custom-runner-linux
steps:
- uses: actions/checkout@v3
- name: Install rsync
run: sudo apt-get install rsync
- uses: rlespinasse/github-slug-action@v3.x
- uses: actions/setup-node@v3
with:
node-version: 18
- 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 mdbook
run: (test -x $HOME/.cargo/bin/mdbook || cargo install --vers "^0.4" mdbook)
- name: Install mdbook plugins
run: |
cargo install --vers "^0.2.0" mdbook-variables && cargo install \
--vers "^1.8.0" mdbook-admonish && cargo install --vers \
"^0.1.2" mdbook-last-changed && cargo install --vers "^0.1.2" \
mdbook-theme && cargo install --vers "^0.7.7" mdbook-linkcheck && \
cargo install --vers "^0.5.0" mdbook-cmdrun
- name: Clean website
run: cd documentation/docs && mdbook clean
- name: Build website
run: cd documentation/docs && mdbook build
- 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: "-rltgoDzvO --delete"
SOURCE: "documentation/docs/book/"
REMOTE_HOST: ${{ secrets.CI_WWW_REMOTE_HOST }}
REMOTE_USER: ${{ secrets.CI_WWW_REMOTE_USER }}
TARGET: ${{ secrets.CI_WWW_REMOTE_TARGET }}/docs-${{ env.GITHUB_REF_SLUG }}
EXCLUDE: "/dist/, /node_modules/"
- name: Matrix - Node Install
run: npm install
working-directory: .github/workflows/support-files
- name: Matrix - Send Notification
env:
NYM_NOTIFICATION_KIND: ci-docs
NYM_PROJECT_NAME: "Docs CI"
NYM_CI_WWW_BASE: "${{ secrets.NYM_CI_WWW_BASE }}"
NYM_CI_WWW_LOCATION: "docs-${{ env.GITHUB_REF_SLUG }}"
GIT_COMMIT_MESSAGE: "${{ github.event.head_commit.message }}"
GIT_BRANCH: "${GITHUB_REF##*/}"
MATRIX_SERVER: "${{ secrets.MATRIX_SERVER }}"
MATRIX_ROOM: "${{ secrets.MATRIX_ROOM_DOCS }}"
MATRIX_USER_ID: "${{ secrets.MATRIX_USER_ID }}"
MATRIX_TOKEN: "${{ secrets.MATRIX_TOKEN }}"
MATRIX_DEVICE_ID: "${{ secrets.MATRIX_DEVICE_ID }}"
IS_SUCCESS: "${{ job.status == 'success' }}"
uses: docker://keybaseio/client:stable-node
with:
args: .github/workflows/support-files/notifications/entry_point.sh
+138
View File
@@ -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: ???
+2 -13
View File
@@ -20,22 +20,11 @@ jobs:
- uses: rlespinasse/github-slug-action@v3.x - uses: rlespinasse/github-slug-action@v3.x
- uses: actions/setup-node@v3 - uses: actions/setup-node@v3
with: with:
node-version: 18 node-version: 16
- name: Install Yarn - name: Install Yarn
run: npm install -g yarn run: npm install -g yarn
- name: Install Rust stable - run: yarn
uses: actions-rs/toolchain@v1
with:
toolchain: stable
- name: Install wasm-pack
run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
- name: Install project dependencies
run: cd ../.. && yarn --network-timeout 100000
- name: Install app dependencies
run: yarn
continue-on-error: true continue-on-error: true
- name: Set environment from the example - name: Set environment from the example
run: cp .env.sample .env run: cp .env.sample .env
- run: yarn storybook:build - run: yarn storybook:build
+1 -1
View File
@@ -20,7 +20,7 @@ jobs:
components: rustfmt, clippy components: rustfmt, clippy
- name: Install wasm-opt - name: Install wasm-opt
run: cargo install --version 0.112.0 wasm-opt run: cargo install --version 0.110.0 wasm-opt
- name: Build release contracts - name: Build release contracts
run: make wasm run: make wasm
+1 -2
View File
@@ -30,7 +30,6 @@ jobs:
continue-on-error: ${{ matrix.rust == 'nightly' }} continue-on-error: ${{ matrix.rust == 'nightly' }}
needs: matrix_prep needs: matrix_prep
strategy: strategy:
fail-fast: false
matrix: ${{fromJson(needs.matrix_prep.outputs.matrix)}} matrix: ${{fromJson(needs.matrix_prep.outputs.matrix)}}
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
@@ -64,4 +63,4 @@ jobs:
if: ${{ matrix.rust != 'nightly' }} if: ${{ matrix.rust != 'nightly' }}
with: with:
command: clippy command: clippy
args: --manifest-path contracts/Cargo.toml --workspace --all-targets -- -D warnings args: --manifest-path contracts/Cargo.toml --workspace -- -D warnings
-13
View File
@@ -1,13 +0,0 @@
name: Greetings
on: [pull_request_target, issues]
jobs:
greeting:
runs-on: ubuntu-latest
steps:
- uses: actions/first-interaction@v1
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
issue-message: 'Thank you for raising this issue'
pr-message: 'Thank you for making this first PR'
@@ -0,0 +1,24 @@
name: Linting for Network Explorer (eslint/prettier)
on:
pull_request:
paths:
- 'explorer/**'
defaults:
run:
working-directory: explorer
jobs:
build:
runs-on: custom-runner-linux
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v3
with:
node-version: 16
- name: Setup yarn
run: npm install -g yarn
- name: Run ESLint
# GitHub should automatically annotate the PR
run: yarn && yarn lint
+1 -1
View File
@@ -21,7 +21,7 @@ jobs:
- uses: rlespinasse/github-slug-action@v3.x - uses: rlespinasse/github-slug-action@v3.x
- uses: actions/setup-node@v3 - uses: actions/setup-node@v3
with: with:
node-version: 18 node-version: 16
- name: Setup yarn - name: Setup yarn
run: npm install -g yarn run: npm install -g yarn
continue-on-error: true continue-on-error: true
+1 -1
View File
@@ -152,7 +152,7 @@ jobs:
uses: actions/setup-node@v3 uses: actions/setup-node@v3
if: env.WORKFLOW_CONCLUSION == 'failure' if: env.WORKFLOW_CONCLUSION == 'failure'
with: with:
node-version: 18 node-version: 16
- name: Matrix - Node Install - name: Matrix - Node Install
if: env.WORKFLOW_CONCLUSION == 'failure' if: env.WORKFLOW_CONCLUSION == 'failure'
run: npm install run: npm install
@@ -6,7 +6,7 @@
}, },
{ {
"os":"windows10", "os":"windows-latest",
"rust":"stable", "rust":"stable",
"runOnEvent":"schedule" "runOnEvent":"schedule"
}, },
@@ -22,7 +22,7 @@
"runOnEvent":"schedule" "runOnEvent":"schedule"
}, },
{ {
"os":"windows10", "os":"windows-latest",
"rust":"beta", "rust":"beta",
"runOnEvent":"schedule" "runOnEvent":"schedule"
}, },
@@ -38,7 +38,7 @@
"runOnEvent":"schedule" "runOnEvent":"schedule"
}, },
{ {
"os":"windows10", "os":"windows-latest",
"rust":"nightly", "rust":"nightly",
"runOnEvent":"schedule" "runOnEvent":"schedule"
}, },
+1 -1
View File
@@ -167,7 +167,7 @@ jobs:
uses: actions/setup-node@v3 uses: actions/setup-node@v3
if: env.WORKFLOW_CONCLUSION == 'failure' if: env.WORKFLOW_CONCLUSION == 'failure'
with: with:
node-version: 18 node-version: 16
- name: Matrix - Node Install - name: Matrix - Node Install
if: env.WORKFLOW_CONCLUSION == 'failure' if: env.WORKFLOW_CONCLUSION == 'failure'
run: npm install run: npm install
+1 -1
View File
@@ -167,7 +167,7 @@ jobs:
uses: actions/setup-node@v3 uses: actions/setup-node@v3
if: env.WORKFLOW_CONCLUSION == 'failure' if: env.WORKFLOW_CONCLUSION == 'failure'
with: with:
node-version: 18 node-version: 16
- name: Matrix - Node Install - name: Matrix - Node Install
if: env.WORKFLOW_CONCLUSION == 'failure' if: env.WORKFLOW_CONCLUSION == 'failure'
run: npm install run: npm install
@@ -15,36 +15,19 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
platform: [macos-latest] platform: [macos-latest]
runs-on: ${{ matrix.platform }} runs-on: ${{ matrix.platform }}
outputs:
release_id: ${{ steps.create-release.outputs.id }}
release_date: ${{ fromJSON(steps.create-release.outputs.assets)[0].created_at }}
version: ${{ steps.release-info.outputs.version }}
filename: ${{ steps.release-info.outputs.filename }}
file_hash: ${{ steps.release-info.outputs.file_hash }}
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- name: Node - name: Node v16
uses: actions/setup-node@v3 uses: actions/setup-node@v3
with: with:
node-version: 18 node-version: 16
- name: Install Rust stable - name: Install Rust stable
uses: actions-rs/toolchain@v1 uses: actions-rs/toolchain@v1
with: with:
toolchain: stable toolchain: stable
target: wasm32-unknown-unknown
- name: Install wasm-pack
run: |
export WASM_PACK_VERSION="v0.12.1"
curl -LO https://github.com/rustwasm/wasm-pack/releases/download/${WASM_PACK_VERSION}/wasm-pack-${WASM_PACK_VERSION}-x86_64-apple-darwin.tar.gz
tar xvzf wasm-pack-${WASM_PACK_VERSION}-x86_64-apple-darwin.tar.gz -C $HOME/.cargo/bin --strip-components=1
rm wasm-pack-${WASM_PACK_VERSION}-x86_64-apple-darwin.tar.gz
- name: Install the Apple developer certificate for code signing - name: Install the Apple developer certificate for code signing
env: env:
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }} APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
@@ -68,15 +51,11 @@ jobs:
security list-keychain -d user -s $KEYCHAIN_PATH security list-keychain -d user -s $KEYCHAIN_PATH
- name: Create env file - name: Create env file
uses: timheuer/base64-to-file@v1.2 uses: timheuer/base64-to-file@v1.1
with: with:
fileName: '.env' fileName: '.env'
encodedString: ${{ secrets.WALLET_ADMIN_ADDRESS }} encodedString: ${{ secrets.WALLET_ADMIN_ADDRESS }}
- name: Install project dependencies
shell: bash
run: cd .. && yarn --network-timeout 100000
- name: Install app dependencies and build it - name: Install app dependencies and build it
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -88,15 +67,13 @@ jobs:
APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }} APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }} TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }} TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
SENTRY_DSN_RUST: ${{ secrets.SENTRY_DSN_RUST }}
SENTRY_DSN_JS: ${{ secrets.SENTRY_DSN_JS }}
run: yarn && yarn build run: yarn && yarn build
- name: Upload Artifact - name: Upload Artifact
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/desktop/target/release/bundle/dmg/nym-connect_1*_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
@@ -104,39 +81,10 @@ jobs:
run: | run: |
security delete-keychain $RUNNER_TEMP/app-signing.keychain-db security delete-keychain $RUNNER_TEMP/app-signing.keychain-db
- id: create-release - 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' if: github.event_name == 'release'
with: with:
files: | files: |
nym-connect/desktop/target/release/bundle/dmg/*.dmg nym-connect/desktop/target/release/bundle/dmg/*.dmg
nym-connect/desktop/target/release/bundle/macos/*.app.tar.gz* nym-connect/desktop/target/release/bundle/macos/*.app.tar.gz*
- id: release-info
name: Prepare release info
run: |
ref=${{ github.ref_name }}
semver="${ref##nym-connect-}" && semver="${semver##v}"
echo "version=${semver}" >> "$GITHUB_OUTPUT"
echo "filename=nym-connect_${version}_x64_en-US.msi" >> "$GITHUB_OUTPUT"
echo "file_hash=${{ hashFiles('nym-connect/desktop/target/release/bundle/dmg/nym-connect_*_x64.dmg') }}" >> "$GITHUB_OUTPUT"
push-release-data:
if: ${{ (startsWith(github.ref, 'refs/tags/nym-connect-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
uses: ./.github/workflows/push-release-data.yml
needs: publish-tauri
with:
release_tag: ${{ github.ref_name }}
release_id: ${{ needs.publish-tauri.outputs.release_id }}
release_date: ${{ needs.publish-tauri.outputs.release_date }}
download_base_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}
changelog_url: https://github.com/nymtech/nym/blob/${{ github.ref_name }}/nym-connect/desktop/CHANGELOG.md
archive_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}/nym-connect.app.tar.gz
sig_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}/nym-connect.app.tar.gz.sig
version: ${{ needs.publish-tauri.outputs.version }}
filename: ${{ needs.publish-tauri.outputs.filename }}
file_hash: ${{ needs.publish-tauri.outputs.file_hash }}
name: NymConnect
category: connect
platform: MacOS
secrets: inherit
@@ -15,15 +15,8 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
platform: [custom-runner-linux] platform: [custom-runner-linux]
runs-on: ${{ matrix.platform }} runs-on: ${{ matrix.platform }}
outputs:
release_id: ${{ steps.create-release.outputs.id }}
release_date: ${{ fromJSON(steps.create-release.outputs.assets)[0].created_at }}
version: ${{ steps.release-info.outputs.version }}
filename: ${{ steps.release-info.outputs.filename }}
file_hash: ${{ steps.release-info.outputs.file_hash }}
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
@@ -33,25 +26,19 @@ jobs:
sudo apt-get install -y webkit2gtk-4.0 libayatana-appindicator3-dev sudo apt-get install -y webkit2gtk-4.0 libayatana-appindicator3-dev
continue-on-error: true continue-on-error: true
- name: Node - name: Node v16
uses: actions/setup-node@v3 uses: actions/setup-node@v3
with: with:
node-version: 18 node-version: 16
- name: Install Rust stable - name: Install Rust stable
uses: actions-rs/toolchain@v1 uses: actions-rs/toolchain@v1
with: with:
toolchain: stable toolchain: stable
- name: Install project dependencies
shell: bash
run: cd .. && yarn --network-timeout 100000
- name: Install app dependencies - name: Install app dependencies
run: yarn run: yarn
- name: Create env file - name: Create env file
uses: timheuer/base64-to-file@v1.2 uses: timheuer/base64-to-file@v1.1
with: with:
fileName: '.env' fileName: '.env'
encodedString: ${{ secrets.WALLET_ADMIN_ADDRESS }} encodedString: ${{ secrets.WALLET_ADMIN_ADDRESS }}
@@ -61,48 +48,18 @@ jobs:
env: env:
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }} TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }} TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
SENTRY_DSN_RUST: ${{ secrets.SENTRY_DSN_RUST }}
SENTRY_DSN_JS: ${{ secrets.SENTRY_DSN_JS }}
- name: Upload Artifact - name: Upload Artifact
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/desktop/target/release/bundle/appimage/nym-connect_1*_amd64.AppImage path: nym-connect/desktop/target/release/bundle/appimage/nym-connect_1.0.0_amd64.AppImage
retention-days: 30 retention-days: 30
- id: create-release - 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' if: github.event_name == 'release'
with: with:
files: | files: |
nym-connect/desktop/target/release/bundle/appimage/*.AppImage nym-connect/desktop/target/release/bundle/appimage/*.AppImage
nym-connect/desktop/target/release/bundle/appimage/*.AppImage.tar.gz* nym-connect/desktop/target/release/bundle/appimage/*.AppImage.tar.gz*
- id: release-info
name: Prepare release info
run: |
ref=${{ github.ref_name }}
semver="${ref##nym-connect-}" && semver="${semver##v}"
echo "version=${semver}" >> "$GITHUB_OUTPUT"
echo "filename=nym-connect_${version}_amd64.AppImage" >> "$GITHUB_OUTPUT"
echo "file_hash=${{ hashFiles('nym-connect/desktop/target/release/bundle/appimage/nym-connect_*_amd64.AppImage') }}" >> "$GITHUB_OUTPUT"
push-release-data:
if: ${{ (startsWith(github.ref, 'refs/tags/nym-connect-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
uses: ./.github/workflows/push-release-data.yml
needs: publish-tauri
with:
release_tag: ${{ github.ref_name }}
release_id: ${{ needs.publish-tauri.outputs.release_id }}
release_date: ${{ needs.publish-tauri.outputs.release_date }}
download_base_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}
changelog_url: https://github.com/nymtech/nym/blob/${{ github.ref_name }}/nym-connect/desktop/CHANGELOG.md
archive_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}/nym-connect_${{ needs.publish-tauri.outputs.version }}_amd64.AppImage.tar.gz
sig_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}/nym-connect_${{ needs.publish-tauri.outputs.version }}_amd64.AppImage.tar.gz.sig
version: ${{ needs.publish-tauri.outputs.version }}
filename: ${{ needs.publish-tauri.outputs.filename }}
file_hash: ${{ needs.publish-tauri.outputs.file_hash }}
name: NymConnect
category: connect
platform: Ubuntu
secrets: inherit
@@ -15,15 +15,8 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
platform: [windows10] platform: [windows10]
runs-on: ${{ matrix.platform }} runs-on: ${{ matrix.platform }}
outputs:
release_id: ${{ steps.create-release.outputs.id }}
release_date: ${{ fromJSON(steps.create-release.outputs.assets)[0].created_at }}
version: ${{ steps.release-info.outputs.version }}
filename: ${{ steps.release-info.outputs.filename }}
file_hash: ${{ steps.release-info.outputs.file_hash }}
steps: steps:
- name: Clean up first - name: Clean up first
continue-on-error: true continue-on-error: true
@@ -46,10 +39,10 @@ jobs:
Remove-Item -path certificate -include tempCert.txt Remove-Item -path certificate -include tempCert.txt
Import-PfxCertificate -FilePath certificate/certificate.pfx -CertStoreLocation Cert:\CurrentUser\My -Password (ConvertTo-SecureString -String $env:WINDOWS_CERTIFICATE_PASSWORD -Force -AsPlainText) Import-PfxCertificate -FilePath certificate/certificate.pfx -CertStoreLocation Cert:\CurrentUser\My -Password (ConvertTo-SecureString -String $env:WINDOWS_CERTIFICATE_PASSWORD -Force -AsPlainText)
- name: Node - name: Node v16
uses: actions/setup-node@v3 uses: actions/setup-node@v3
with: with:
node-version: 18 node-version: 16
- name: Install Rust stable - name: Install Rust stable
uses: actions-rs/toolchain@v1 uses: actions-rs/toolchain@v1
@@ -57,21 +50,15 @@ jobs:
toolchain: stable toolchain: stable
- name: Create env file - name: Create env file
uses: timheuer/base64-to-file@v1.2 uses: timheuer/base64-to-file@v1.1
with: with:
fileName: '.env' fileName: '.env'
encodedString: ${{ secrets.WALLET_ADMIN_ADDRESS }} encodedString: ${{ secrets.WALLET_ADMIN_ADDRESS }}
- name: Install project dependencies
shell: bash
run: cd .. && yarn --network-timeout 100000
- name: Install app dependencies - name: Install app dependencies
shell: bash
run: yarn --network-timeout 100000 run: yarn --network-timeout 100000
- name: Build and sign it - name: Build and sign it
shell: bash
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
ENABLE_CODE_SIGNING: ${{ secrets.WINDOWS_CERTIFICATE }} ENABLE_CODE_SIGNING: ${{ secrets.WINDOWS_CERTIFICATE }}
@@ -79,51 +66,19 @@ jobs:
WINDOWS_CERTIFICATE_PASSWORD: ${{ secrets.WINDOWS_CERTIFICATE_PASSWORD }} WINDOWS_CERTIFICATE_PASSWORD: ${{ secrets.WINDOWS_CERTIFICATE_PASSWORD }}
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }} TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }} TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
SENTRY_DSN_RUST: ${{ secrets.SENTRY_DSN_RUST }}
SENTRY_DSN_JS: ${{ secrets.SENTRY_DSN_JS }}
run: yarn build run: yarn build
- name: Upload Artifact - name: Upload Artifact
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/desktop/target/release/bundle/msi/nym-connect_1*_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
- id: create-release - 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' if: github.event_name == 'release'
with: with:
files: | files: |
nym-connect/desktop/target/release/bundle/msi/*.msi nym-connect/desktop/target/release/bundle/msi/*.msi
nym-connect/desktop/target/release/bundle/msi/*.msi.zip* nym-connect/desktop/target/release/bundle/msi/*.msi.zip*
- id: release-info
name: Prepare release info
shell: bash
run: |
ref=${{ github.ref_name }}
semver="${ref##nym-connect-}" && semver="${semver##v}"
echo "version=${semver}" >> "$GITHUB_OUTPUT"
echo "filename=nym-connect_${version}_x64_en-US.msi" >> "$GITHUB_OUTPUT"
echo "file_hash=${{ hashFiles('nym-connect/desktop/target/release/bundle/msi/nym-connect_*_x64_en-US.msi') }}" >> "$GITHUB_OUTPUT"
push-release-data:
if: ${{ (startsWith(github.ref, 'refs/tags/nym-connect-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
uses: ./.github/workflows/push-release-data.yml
needs: publish-tauri
with:
release_tag: ${{ github.ref_name }}
release_id: ${{ needs.publish-tauri.outputs.release_id }}
release_date: ${{ needs.publish-tauri.outputs.release_date }}
download_base_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}
changelog_url: https://github.com/nymtech/nym/blob/${{ github.ref_name }}/nym-connect/desktop/CHANGELOG.md
archive_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}/nym-connect_${{ needs.publish-tauri.outputs.version }}_x64_en-US.msi.zip
sig_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}/nym-connect_${{ needs.publish-tauri.outputs.version }}_x64_en-US.msi.zip.sig
version: ${{ needs.publish-tauri.outputs.version }}
filename: ${{ needs.publish-tauri.outputs.filename }}
file_hash: ${{ needs.publish-tauri.outputs.file_hash }}
name: NymConnect
category: connect
platform: Windows
secrets: inherit
+8 -174
View File
@@ -2,17 +2,17 @@ name: Publish Nym binaries
on: on:
workflow_dispatch: workflow_dispatch:
inputs: inputs:
add_tokio_unstable: add_tokio_unstable:
description: 'True to add RUSTFLAGS="--cfg tokio_unstable"' description: 'True to add RUSTFLAGS="--cfg tokio_unstable"'
required: true required: true
default: false default: false
type: boolean type: boolean
release: release:
types: [created] types: [created]
env: env:
NETWORK: mainnet NETWORK: mainnet
jobs: jobs:
publish-nym: publish-nym:
@@ -21,33 +21,15 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
platform: [custom-runner-linux] platform: [custom-runner-linux]
runs-on: ${{ matrix.platform }} runs-on: ${{ matrix.platform }}
outputs:
release_id: ${{ steps.create-release.outputs.id }}
release_date: ${{ fromJSON(steps.create-release.outputs.assets)[0].published_at }}
client_hash: ${{ steps.binary-hashes.outputs.client_hash }}
mixnode_hash: ${{ steps.binary-hashes.outputs.mixnode_hash }}
gateway_hash: ${{ steps.binary-hashes.outputs.gateway_hash }}
socks5_hash: ${{ steps.binary-hashes.outputs.socks5_hash }}
netreq_hash: ${{ steps.binary-hashes.outputs.netreq_hash }}
cli_hash: ${{ steps.binary-hashes.outputs.cli_hash }}
netstat_hash: ${{ steps.binary-hashes.outputs.netstat_hash }}
client_version: ${{ steps.binary-versions.outputs.client_version }}
mixnode_version: ${{ steps.binary-versions.outputs.mixnode_version }}
gateway_version: ${{ steps.binary-versions.outputs.gateway_version }}
socks5_version: ${{ steps.binary-versions.outputs.socks5_version }}
netreq_version: ${{ steps.binary-versions.outputs.netreq_version }}
cli_version: ${{ steps.binary-versions.outputs.cli_version }}
netstat_version: ${{ steps.binary-versions.outputs.netstat_version }}
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- name: Install Dependencies (Linux) - name: Install Dependencies (Linux)
run: sudo apt-get update && sudo apt-get -y install ripgrep libwebkit2gtk-4.0-dev build-essential curl wget libssl-dev libgtk-3-dev libudev-dev squashfs-tools 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 continue-on-error: true
- name: Sets env vars for tokio if set in manual dispatch inputs - name: Sets env vars for tokio if set in manual dispatch inputs
run: | run: |
echo 'RUSTFLAGS="--cfg tokio_unstable"' >> $GITHUB_ENV echo 'RUSTFLAGS="--cfg tokio_unstable"' >> $GITHUB_ENV
@@ -80,8 +62,7 @@ jobs:
target/release/nym-cli target/release/nym-cli
retention-days: 30 retention-days: 30
- id: create-release - 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' if: github.event_name == 'release'
with: with:
@@ -95,150 +76,3 @@ jobs:
target/release/nym-network-requester target/release/nym-network-requester
target/release/nym-network-statistics target/release/nym-network-statistics
target/release/nym-cli target/release/nym-cli
- id: release-info
name: Prepare release info
run: |
semver="${${{ github.ref_name }}##nym-binaries-}" && semver="${semver##v}"
echo "version=$semver" >> "$GITHUB_OUTPUT"
- id: binary-hashes
name: Generate binary hashes
run: |
echo "client_hash=${{ hashFiles('target/release/nym-client') }}" >> "$GITHUB_OUTPUT"
echo "mixnode_hash=${{ hashFiles('target/release/nym-mixnode') }}" >> "$GITHUB_OUTPUT"
echo "gateway_hash=${{ hashFiles('target/release/nym-gateway') }}" >> "$GITHUB_OUTPUT"
echo "socks5_hash=${{ hashFiles('target/release/nym-socks5-client') }}" >> "$GITHUB_OUTPUT"
echo "netreq_hash=${{ hashFiles('target/release/nym-network-requester') }}" >> "$GITHUB_OUTPUT"
echo "cli_hash=${{ hashFiles('target/release/nym-cli') }}" >> "$GITHUB_OUTPUT"
echo "netstat_hash=${{ hashFiles('target/release/nym-network-statistics') }}" >> "$GITHUB_OUTPUT"
- id: binary-versions
name: Get binary versions
run: |
v=$(rg '^version = "(.*)"' -or '$1' clients/native/Cargo.toml) && echo "client_version=$v" >> "$GITHUB_OUTPUT"
v=$(rg '^version = "(.*)"' -or '$1' mixnode/Cargo.toml) && echo "mixnode_version=$v" >> "$GITHUB_OUTPUT"
v=$(rg '^version = "(.*)"' -or '$1' gateway/Cargo.toml) && echo "gateway_version=$v" >> "$GITHUB_OUTPUT"
v=$(rg '^version = "(.*)"' -or '$1' clients/socks5/Cargo.toml) && echo "socks5_version=$v" >> "$GITHUB_OUTPUT"
v=$(rg '^version = "(.*)"' -or '$1' service-providers/network-requester/Cargo.toml) && echo "netreq_version=$v" >> "$GITHUB_OUTPUT"
v=$(rg '^version = "(.*)"' -or '$1' tools/nym-cli/Cargo.toml) && echo "cli_version=$v" >> "$GITHUB_OUTPUT"
v=$(rg '^version = "(.*)"' -or '$1' service-providers/network-statistics/Cargo.toml) && echo "netstat_version=$v" >> "$GITHUB_OUTPUT"
push-release-data-client:
if: ${{ (startsWith(github.ref, 'refs/tags/nym-binaries-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
uses: ./.github/workflows/push-release-data.yml
needs: publish-nym
with:
release_tag: ${{ github.ref_name }}
release_id: ${{ needs.publish-nym.outputs.release_id }}
release_date: ${{ needs.publish-nym.outputs.release_date }}
download_base_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}
changelog_url: https://github.com/nymtech/nym/blob/${{ github.ref_name }}/CHANGELOG.md
version: ${{ needs.publish-nym.outputs.client_version }}
filename: nym-client
file_hash: ${{ needs.publish-nym.outputs.client_hash }}
name: Client
category: binaries
secrets: inherit
push-release-data-mixnode:
if: ${{ (startsWith(github.ref, 'refs/tags/nym-binaries-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
uses: ./.github/workflows/push-release-data.yml
needs: publish-nym
with:
release_tag: ${{ github.ref_name }}
release_id: ${{ needs.publish-nym.outputs.release_id }}
release_date: ${{ needs.publish-nym.outputs.release_date }}
download_base_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}
changelog_url: https://github.com/nymtech/nym/blob/${{ github.ref_name }}/CHANGELOG.md
version: ${{ needs.publish-nym.outputs.mixnode_version }}
filename: nym-mixnode
file_hash: ${{ needs.publish-nym.outputs.mixnode_hash }}
name: Mixnode
category: binaries
secrets: inherit
push-release-data-gateway:
if: ${{ (startsWith(github.ref, 'refs/tags/nym-binaries-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
uses: ./.github/workflows/push-release-data.yml
needs: publish-nym
with:
release_tag: ${{ github.ref_name }}
release_id: ${{ needs.publish-nym.outputs.release_id }}
release_date: ${{ needs.publish-nym.outputs.release_date }}
download_base_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}
changelog_url: https://github.com/nymtech/nym/blob/${{ github.ref_name }}/CHANGELOG.md
version: ${{ needs.publish-nym.outputs.gateway_version }}
filename: nym-gateway
file_hash: ${{ needs.publish-nym.outputs.gateway_hash }}
name: Gateway
category: binaries
secrets: inherit
push-release-data-socks5:
if: ${{ (startsWith(github.ref, 'refs/tags/nym-binaries-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
uses: ./.github/workflows/push-release-data.yml
needs: publish-nym
with:
release_tag: ${{ github.ref_name }}
release_id: ${{ needs.publish-nym.outputs.release_id }}
release_date: ${{ needs.publish-nym.outputs.release_date }}
download_base_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}
changelog_url: https://github.com/nymtech/nym/blob/${{ github.ref_name }}/CHANGELOG.md
version: ${{ needs.publish-nym.outputs.socks5_version }}
filename: nym-socks5-client
file_hash: ${{ needs.publish-nym.outputs.socks5_hash }}
name: Socks5 Client
category: binaries
secrets: inherit
push-release-data-network-requester:
if: ${{ (startsWith(github.ref, 'refs/tags/nym-binaries-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
uses: ./.github/workflows/push-release-data.yml
needs: publish-nym
with:
release_tag: ${{ github.ref_name }}
release_id: ${{ needs.publish-nym.outputs.release_id }}
release_date: ${{ needs.publish-nym.outputs.release_date }}
download_base_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}
changelog_url: https://github.com/nymtech/nym/blob/${{ github.ref_name }}/CHANGELOG.md
version: ${{ needs.publish-nym.outputs.netreq_version }}
filename: nym-network-requester
file_hash: ${{ needs.publish-nym.outputs.netreq_hash }}
name: Network Requester
category: binaries
secrets: inherit
push-release-data-cli:
if: ${{ (startsWith(github.ref, 'refs/tags/nym-binaries-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
uses: ./.github/workflows/push-release-data.yml
needs: publish-nym
with:
release_tag: ${{ github.ref_name }}
release_id: ${{ needs.publish-nym.outputs.release_id }}
release_date: ${{ needs.publish-nym.outputs.release_date }}
download_base_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}
changelog_url: https://github.com/nymtech/nym/blob/${{ github.ref_name }}/CHANGELOG.md
version: ${{ needs.publish-nym.outputs.cli_version }}
filename: nym-cli
file_hash: ${{ needs.publish-nym.outputs.cli_hash }}
name: Cli
category: binaries
secrets: inherit
push-release-data-network-stat:
if: ${{ (startsWith(github.ref, 'refs/tags/nym-binaries-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
uses: ./.github/workflows/push-release-data.yml
needs: publish-nym
with:
release_tag: ${{ github.ref_name }}
release_id: ${{ needs.publish-nym.outputs.release_id }}
release_date: ${{ needs.publish-nym.outputs.release_date }}
download_base_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}
changelog_url: https://github.com/nymtech/nym/blob/${{ github.ref_name }}/CHANGELOG.md
version: ${{ needs.publish-nym.outputs.netstat_version }}
filename: nym-network-statistics
file_hash: ${{ needs.publish-nym.outputs.netstat_hash }}
name: Network Statistics
category: binaries
secrets: inherit
+6 -46
View File
@@ -15,22 +15,15 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
platform: [macos-latest] platform: [macos-latest]
runs-on: ${{ matrix.platform }} runs-on: ${{ matrix.platform }}
outputs:
release_id: ${{ steps.create-release.outputs.id }}
release_date: ${{ fromJSON(steps.create-release.outputs.assets)[0].created_at }}
version: ${{ steps.release-info.outputs.version }}
filename: ${{ steps.release-info.outputs.filename }}
file_hash: ${{ steps.release-info.outputs.file_hash }}
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- name: Node - name: Node v16
uses: actions/setup-node@v3 uses: actions/setup-node@v3
with: with:
node-version: 18 node-version: 16
- name: Install Rust stable - name: Install Rust stable
uses: actions-rs/toolchain@v1 uses: actions-rs/toolchain@v1
with: with:
@@ -58,15 +51,11 @@ jobs:
security list-keychain -d user -s $KEYCHAIN_PATH security list-keychain -d user -s $KEYCHAIN_PATH
- name: Create env file - name: Create env file
uses: timheuer/base64-to-file@v1.2 uses: timheuer/base64-to-file@v1.1
with: with:
fileName: '.env' fileName: '.env'
encodedString: ${{ secrets.WALLET_ADMIN_ADDRESS }} encodedString: ${{ secrets.WALLET_ADMIN_ADDRESS }}
- name: Install project dependencies
shell: bash
run: cd .. && yarn --network-timeout 100000
- name: Install app dependencies and build it - name: Install app dependencies and build it
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -91,40 +80,11 @@ jobs:
if: ${{ always() }} if: ${{ always() }}
run: | run: |
security delete-keychain $RUNNER_TEMP/app-signing.keychain-db security delete-keychain $RUNNER_TEMP/app-signing.keychain-db
- id: create-release
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' if: github.event_name == 'release'
with: with:
files: | files: |
nym-wallet/target/release/bundle/dmg/*.dmg nym-wallet/target/release/bundle/dmg/*.dmg
nym-wallet/target/release/bundle/macos/*.app.tar.gz* nym-wallet/target/release/bundle/macos/*.app.tar.gz*
- id: release-info
name: Prepare release info
run: |
ref=${{ github.ref_name }}
semver="${ref##nym-wallet-}" && semver="${semver##v}"
echo "version=${semver}" >> "$GITHUB_OUTPUT"
echo "filename=nym-wallet_${version}_x64.dmg" >> "$GITHUB_OUTPUT"
echo "file_hash=${{ hashFiles('nym-wallet/target/release/bundle/dmg/nym-wallet_*_x64.dmg') }}" >> "$GITHUB_OUTPUT"
push-release-data:
if: ${{ (startsWith(github.ref, 'refs/tags/nym-wallet-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
uses: ./.github/workflows/push-release-data.yml
needs: publish-tauri
with:
release_tag: ${{ github.ref_name }}
release_id: ${{ needs.publish-tauri.outputs.release_id }}
release_date: ${{ needs.publish-tauri.outputs.release_date }}
download_base_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}
changelog_url: https://github.com/nymtech/nym/blob/${{ github.ref_name }}/nym-wallet/CHANGELOG.md
archive_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}/nym-wallet.app.tar.gz
sig_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}/nym-wallet.app.tar.gz.sig
version: ${{ needs.publish-tauri.outputs.version }}
filename: ${{ needs.publish-tauri.outputs.filename }}
file_hash: ${{ needs.publish-tauri.outputs.file_hash }}
name: Wallet
category: wallet
platform: MacOS
secrets: inherit
@@ -1,6 +1,5 @@
name: Publish Nym Wallet (Ubuntu) name: Publish Nym Wallet (Ubuntu)
on: on:
workflow_dispatch:
release: release:
types: [created] types: [created]
@@ -15,15 +14,8 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
platform: [custom-runner-linux] platform: [custom-runner-linux]
runs-on: ${{ matrix.platform }} runs-on: ${{ matrix.platform }}
outputs:
release_id: ${{ steps.create-release.outputs.id }}
release_date: ${{ fromJSON(steps.create-release.outputs.assets)[0].created_at }}
version: ${{ steps.release-info.outputs.version }}
filename: ${{ steps.release-info.outputs.filename }}
file_hash: ${{ steps.release-info.outputs.file_hash }}
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
@@ -33,24 +25,19 @@ jobs:
sudo apt-get install -y webkit2gtk-4.0 sudo apt-get install -y webkit2gtk-4.0
continue-on-error: true continue-on-error: true
- name: Node - name: Node v16
uses: actions/setup-node@v3 uses: actions/setup-node@v3
with: with:
node-version: 18 node-version: 16
- name: Install Rust stable - name: Install Rust stable
uses: actions-rs/toolchain@v1 uses: actions-rs/toolchain@v1
with: with:
toolchain: stable toolchain: stable
- name: Install project dependencies
shell: bash
run: cd .. && yarn --network-timeout 100000
- name: Install app dependencies - name: Install app dependencies
run: yarn run: yarn
- name: Create env file - name: Create env file
uses: timheuer/base64-to-file@v1.2 uses: timheuer/base64-to-file@v1.1
with: with:
fileName: '.env' fileName: '.env'
encodedString: ${{ secrets.WALLET_ADMIN_ADDRESS }} encodedString: ${{ secrets.WALLET_ADMIN_ADDRESS }}
@@ -60,48 +47,9 @@ jobs:
env: env:
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }} TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }} TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
- name: Upload to release based on tag name
- name: Upload Artifact
uses: actions/upload-artifact@v3
with:
name: nym-wallet_1.0.0_amd64.AppImage.tar.gz
path: nym-wallet/target/release/bundle/appimage/nym-wallet*.AppImage.tar.gz
retention-days: 30
- id: create-release
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/appimage/*.AppImage nym-wallet/target/release/bundle/appimage/*.AppImage
nym-wallet/target/release/bundle/appimage/*.AppImage.tar.gz* nym-wallet/target/release/bundle/appimage/*.AppImage.tar.gz*
- id: release-info
name: Prepare release info
run: |
ref=${{ github.ref_name }}
semver="${ref##nym-wallet-}" && semver="${semver##v}"
echo "version=${semver}" >> "$GITHUB_OUTPUT"
echo "filename=nym-wallet_${version}_amd64.AppImage" >> "$GITHUB_OUTPUT"
echo "file_hash=${{ hashFiles('nym-wallet/target/release/bundle/appimage/nym-wallet_*_amd64.AppImage') }}" >> "$GITHUB_OUTPUT"
push-release-data:
if: ${{ (startsWith(github.ref, 'refs/tags/nym-wallet-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
uses: ./.github/workflows/push-release-data.yml
needs: publish-tauri
with:
release_tag: ${{ github.ref_name }}
release_id: ${{ needs.publish-tauri.outputs.release_id }}
release_date: ${{ needs.publish-tauri.outputs.release_date }}
download_base_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}
changelog_url: https://github.com/nymtech/nym/blob/${{ github.ref_name }}/nym-wallet/CHANGELOG.md
archive_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}/nym-wallet_${{ needs.publish-tauri.outputs.version }}_amd64.AppImage.tar.gz
sig_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}/nym-wallet_${{ needs.publish-tauri.outputs.version }}_amd64.AppImage.tar.gz.sig
version: ${{ needs.publish-tauri.outputs.version }}
filename: ${{ needs.publish-tauri.outputs.filename }}
file_hash: ${{ needs.publish-tauri.outputs.file_hash }}
name: Wallet
category: wallet
platform: Ubuntu
secrets: inherit
@@ -15,15 +15,8 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
platform: [windows10] platform: [windows10]
runs-on: ${{ matrix.platform }} runs-on: ${{ matrix.platform }}
outputs:
release_id: ${{ steps.create-release.outputs.id }}
release_date: ${{ fromJSON(steps.create-release.outputs.assets)[0].created_at }}
version: ${{ steps.release-info.outputs.version }}
filename: ${{ steps.release-info.outputs.filename }}
file_hash: ${{ steps.release-info.outputs.file_hash }}
steps: steps:
- name: Clean up first - name: Clean up first
continue-on-error: true continue-on-error: true
@@ -46,10 +39,10 @@ jobs:
Remove-Item -path certificate -include tempCert.txt Remove-Item -path certificate -include tempCert.txt
Import-PfxCertificate -FilePath certificate/certificate.pfx -CertStoreLocation Cert:\CurrentUser\My -Password (ConvertTo-SecureString -String $env:WINDOWS_CERTIFICATE_PASSWORD -Force -AsPlainText) Import-PfxCertificate -FilePath certificate/certificate.pfx -CertStoreLocation Cert:\CurrentUser\My -Password (ConvertTo-SecureString -String $env:WINDOWS_CERTIFICATE_PASSWORD -Force -AsPlainText)
- name: Node - name: Node v16
uses: actions/setup-node@v3 uses: actions/setup-node@v3
with: with:
node-version: 18 node-version: 16
- name: Install Rust stable - name: Install Rust stable
uses: actions-rs/toolchain@v1 uses: actions-rs/toolchain@v1
@@ -57,21 +50,15 @@ jobs:
toolchain: stable toolchain: stable
- name: Create env file - name: Create env file
uses: timheuer/base64-to-file@v1.2 uses: timheuer/base64-to-file@v1.1
with: with:
fileName: '.env' fileName: '.env'
encodedString: ${{ secrets.WALLET_ADMIN_ADDRESS }} encodedString: ${{ secrets.WALLET_ADMIN_ADDRESS }}
- name: Install project dependencies
shell: bash
run: cd .. && yarn --network-timeout 100000
- name: Install app dependencies - name: Install app dependencies
shell: bash
run: yarn --network-timeout 100000 run: yarn --network-timeout 100000
- name: Build and sign it - name: Build and sign it
shell: bash
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
ENABLE_CODE_SIGNING: ${{ secrets.WINDOWS_CERTIFICATE }} ENABLE_CODE_SIGNING: ${{ secrets.WINDOWS_CERTIFICATE }}
@@ -88,40 +75,10 @@ jobs:
path: nym-wallet/target/release/bundle/msi/nym-wallet_1.*.msi path: nym-wallet/target/release/bundle/msi/nym-wallet_1.*.msi
retention-days: 30 retention-days: 30
- id: create-release - 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' if: github.event_name == 'release'
with: with:
files: | files: |
nym-wallet/target/release/bundle/msi/*.msi nym-wallet/target/release/bundle/msi/*.msi
nym-wallet/target/release/bundle/msi/*.msi.zip* nym-wallet/target/release/bundle/msi/*.msi.zip*
- id: release-info
name: Prepare release info
run: |
ref=${{ github.ref_name }}
semver="${ref##nym-wallet-}" && semver="${semver##v}"
echo "version=${semver}" >> "$GITHUB_OUTPUT"
echo "filename=nym-wallet_${version}_x64_en-US.msi" >> "$GITHUB_OUTPUT"
echo "file_hash=${{ hashFiles('nym-wallet/target/release/bundle/msi/nym-wallet_*_x64_en-US.msi') }}" >> "$GITHUB_OUTPUT"
push-release-data:
if: ${{ (startsWith(github.ref, 'refs/tags/nym-wallet-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
uses: ./.github/workflows/push-release-data.yml
needs: publish-tauri
with:
release_tag: ${{ github.ref_name }}
release_id: ${{ needs.publish-tauri.outputs.release_id }}
release_date: ${{ needs.publish-tauri.outputs.release_date }}
download_base_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}
changelog_url: https://github.com/nymtech/nym/blob/${{ github.ref_name }}/nym-wallet/CHANGELOG.md
archive_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}/nym-wallet_${{ needs.publish-tauri.outputs.version }}_x64_en-US.msi.zip
sig_url: https://github.com/nymtech/nym/releases/download/${{ github.ref_name }}/nym-wallet_${{ needs.publish-tauri.outputs.version }}_x64_en-US.msi.zip.sig
version: ${{ needs.publish-tauri.outputs.version }}
filename: ${{ needs.publish-tauri.outputs.filename }}
file_hash: ${{ needs.publish-tauri.outputs.file_hash }}
name: Wallet
category: wallet
platform: Windows
secrets: inherit
+1 -7
View File
@@ -16,15 +16,9 @@ jobs:
- uses: rlespinasse/github-slug-action@v3.x - uses: rlespinasse/github-slug-action@v3.x
- uses: actions/setup-node@v3 - uses: actions/setup-node@v3
with: with:
node-version: 18 node-version: 16
- name: Setup yarn - name: Setup yarn
run: npm install -g yarn run: npm install -g yarn
- name: Install Rust stable
uses: actions-rs/toolchain@v1
with:
toolchain: stable
- name: Install wasm-pack
run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
- name: Build dependencies - name: Build dependencies
run: yarn && yarn build run: yarn && yarn build
- name: Build storybook - name: Build storybook
+2 -2
View File
@@ -34,10 +34,10 @@ jobs:
profile: minimal profile: minimal
toolchain: stable toolchain: stable
- name: Node - name: Node v16
uses: actions/setup-node@v3 uses: actions/setup-node@v3
with: with:
node-version: 18 node-version: 16
- name: Install yarn for building application - name: Install yarn for building application
run: yarn install run: yarn install
-111
View File
@@ -1,111 +0,0 @@
name: Nyms5 Android
# unsigned APKs only, supported archs:
# - arm64-v8a (arm64)
# - x86_64
on:
workflow_dispatch:
push:
tags:
- nyms5-android-v*
jobs:
build:
name: Build APK
runs-on: custom-runner-linux
env:
ANDROID_HOME: ${{ github.workspace }}/android-sdk
NDK_VERSION: 25.2.9519653
NDK_HOME: ${{ github.workspace }}/android-sdk/ndk/25.2.9519653
SDK_PLATFORM_VERSION: android-33
SDK_BUILDTOOLS_VERSION: 33.0.2
steps:
- 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@1.70.0
- name: Install rust android targets
run: |
rustup target add aarch64-linux-android \
x86_64-linux-android
- name: Build lib nym-socks5-listener
working-directory: sdk/lib/socks5-listener/
env:
RELEASE: true
RUSTFLAGS: "-C link-args=-Wl,--hash-style=gnu"
# build for arm64 and x86_64
run: ./build-android.sh aarch64 x86_64
- name: Build APKs (unsigned)
working-directory: nym-connect/native/android
env:
ANDROID_SDK_ROOT: ${{ env.ANDROID_HOME }}
SENTRY_AUTH_TOKEN: ${{ secrets.NYMS5_ANDROID_SENTRY_AUTH_TOKEN }}
# build for arm64 and x86_64
run: |
echo "auth.token=$SENTRY_AUTH_TOKEN" | tee -a sentry.properties
./gradlew :app:assembleArch64Debug
./gradlew :app:assembleArch64Release
- name: Prepare APKs
run: |
mkdir apk
mv nym-connect/native/android/app/build/outputs/apk/arch64/debug/app-arch64-debug.apk \
apk/nyms5-arch64-debug.apk
mv nym-connect/native/android/app/build/outputs/apk/arch64/release/app-arch64-release-unsigned.apk \
apk/nyms5-arch64-release.apk
- name: Upload APKs
uses: actions/upload-artifact@v3
with:
name: nyms5-apk-arch64
path: |
apk/nyms5-arch64-debug.apk
apk/nyms5-arch64-release.apk
gh-release:
name: Publish APK (GH release)
needs: build
runs-on: custom-runner-linux
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Download binary artifact
uses: actions/download-artifact@v3
with:
name: nyms5-apk-arch64
path: apk
- name: Release
uses: softprops/action-gh-release@v1
with:
files: |
apk/nyms5-arch64-debug.apk
apk/nyms5-arch64-release.apk
-212
View File
@@ -1,212 +0,0 @@
name: Push release data
env:
strapi_download_url: 'https://strapi.feat-nym-update-nym-web.websites.dev.nymte.ch/api/downloaders'
strapi_updater_url: 'https://strapi.feat-nym-update-nym-web.websites.dev.nymte.ch/api/updaters'
on:
workflow_call:
inputs:
release_tag:
required: true
description: Release tag
type: string
release_id:
required: true
description: Release ID
type: string
release_date:
required: true
description: Release date
type: string
download_base_url:
required: true
description: Download base URL
type: string
changelog_url:
required: true
description: Changelog URL
type: string
archive_url:
required: false
description: Binary archive URL
type: string
sig_url:
required: false
description: Archive signature URL
type: string
version:
required: true
description: Release version (semver)
type: string
filename:
required: true
description: Binary file name
type: string
file_hash:
required: true
description: Binary hash (sha256)
type: string
name:
required: true
description: Name
type: string
category:
required: true
description: Category
type: string
platform:
required: false
description: Platform
type: string
workflow_dispatch:
inputs:
# ⚠ since inputs are limited to 10 max for workflow_dispatch
# some properties were omitted
version:
required: true
description: Release version (semver)
type: string
default: '1.0.0'
release_id:
required: true
description: Release ID
type: string
default: '1234'
release_date:
required: true
description: Release date
type: string
default: '2023-06-26T10:09:16Z'
download_base_url:
required: true
description: Download base URL
type: string
default: 'https://github.com/nymtech/nym/releases/download/nym-wallet-v1.0.0'
changelog_url:
required: true
description: Changelog URL
type: string
default: 'https://github.com/nymtech/nym/blob/nym-wallet-v1.0.0/nym-wallet/CHANGELOG.md'
filename:
required: true
description: Binary file name
type: string
default: 'nym-wallet_1.0.0_amd64.AppImage'
file_hash:
required: true
description: Binary hash (sha256)
type: string
default: 'xxx'
name:
required: true
description: Name
type: string
default: 'Wallet'
category:
required: true
description: Category
default: 'wallet'
type: choice
options:
- wallet
- connect
- binaries
platform:
required: false
description: Platform
default: 'Ubuntu'
type: choice
options:
- Ubuntu
- Windows
- MacOS
jobs:
push-download-data:
name: Push download data to Strapi
runs-on: custom-runner-linux
steps:
- name: Release info
run: |
echo "version: ${{ inputs.version }}"
echo "tag: ${{ inputs.release_tag }}"
- id: get_sig
name: Get sig
if: ${{ inputs.sig_url != null }}
run: |
output=$(curl -LsSf ${{ inputs.sig_url }})
echo "sig=$output" >> "$GITHUB_OUTPUT"
- id: strapi-request
name: Strapi request
uses: fjogeleit/http-request-action@v1
with:
url: ${{ env.strapi_download_url }}
method: 'POST'
bearerToken: ${{ secrets.STRAPI_API_TOKEN_RELEASES }}
customHeaders: '{"Content-Type": "application/json"}'
data: |
{
"data": {
"releaseId": "${{ inputs.release_id }}",
"releaseDate": "${{ inputs.release_date }}",
"downloadBaseUrl": "${{ inputs.download_base_url }}",
"changelogUrl": "${{ inputs.changelog_url }}",
"version": "${{ inputs.version }}",
"filename": "${{ inputs.filename }}",
"name": "${{ inputs.name }}",
"category": "${{ inputs.category }}",
"platform": "${{ inputs.platform }}",
"sha256": "${{ inputs.file_hash }}",
"sig": "${{ steps.get_sig.outputs.sig }}"
}
}
- name: Strapi Response
run: |
echo ${{ steps.strapi-request.outputs.response }}
push-update-data:
name: Push update data to Strapi
runs-on: custom-runner-linux
# only push update data for tauri apps (desktop wallet and NC)
if: ${{ inputs.category == 'wallet' || inputs.category == 'connect' }}
steps:
- name: Release info
run: |
echo "version: ${{ inputs.version }}"
echo "tag: ${{ inputs.release_tag }}"
- id: get_sig
name: Get sig
if: ${{ inputs.sig_url != null }}
run: |
output=$(curl -LsSf ${{ inputs.sig_url }})
echo "sig=$output" >> "$GITHUB_OUTPUT"
- id: strapi-request
name: Strapi request
uses: fjogeleit/http-request-action@v1
with:
url: ${{ env.strapi_updater_url }}
method: 'POST'
bearerToken: ${{ secrets.STRAPI_API_TOKEN_RELEASES }}
customHeaders: '{"Content-Type": "application/json"}'
data: |
{
"data": {
"releaseId": "${{ inputs.release_id }}",
"releaseDate": "${{ inputs.release_date }}",
"downloadUrl": "${{ inputs.archive_url }}",
"changelog": "See ${{ inputs.changelog_url }} for the changelog",
"version": "${{ inputs.version }}",
"filename": "${{ inputs.filename }}",
"category": "${{ inputs.category }}",
"platform": "${{ inputs.platform }}",
"sha256": "${{ inputs.file_hash }}",
"sig": "${{ steps.get_sig.outputs.sig }}"
}
}
- name: Strapi Response
run: |
echo ${{ steps.strapi-request.outputs.response }}
-35
View File
@@ -1,35 +0,0 @@
name: Publish SDK to NPM
on:
workflow_dispatch:
jobs:
publish:
runs-on: [custom-runner-linux]
steps:
- uses: actions/checkout@v2
- name: Install Node
uses: actions/setup-node@v3
with:
node-version: 18
registry-url: 'https://registry.npmjs.org'
- name: Setup yarn
run: npm install -g yarn
- name: Install Rust stable
uses: actions-rs/toolchain@v1
with:
toolchain: stable
- name: Install wasm-pack
run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
- name: Install dependencies
run: yarn
- name: Build and publish
env:
NODE_AUTH_TOKEN: ${{ secrets.NODE_AUTH_TOKEN }}
working-directory: ./sdk/typescript/packages/sdk
run: scripts/publish.sh
+1 -1
View File
@@ -1 +1 @@
18 16
@@ -1,29 +0,0 @@
const Handlebars = require('handlebars');
const fs = require('fs');
const path = require('path');
async function addToContextAndValidate(context) {
if (!context.env.NYM_CI_WWW_LOCATION) {
throw new Error('Please ensure the env var NYM_CI_WWW_LOCATION is set');
}
if (!context.env.NYM_CI_WWW_BASE) {
throw new Error('Please ensure the env var NYM_CI_WWW_BASE is set');
}
}
async function getMessageBody(context) {
const source = fs
.readFileSync(
context.env.IS_SUCCESS === 'true'
? path.resolve(__dirname, 'templates', 'success')
: path.resolve(__dirname, 'templates', 'failure'),
)
.toString();
const template = Handlebars.compile(source);
return template(context);
}
module.exports = {
addToContextAndValidate,
getMessageBody,
};
@@ -1,17 +0,0 @@
🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥
> :rocket: {{ env.NYM_PROJECT_NAME }}
>
> 🔴 **FAILURE** :cry:
>
> `branch` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/tree/{{ env.GIT_BRANCH_NAME }}
>
> `commit` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/commit/{{ env.GITHUB_SHA }}
>
> `build ` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/actions/runs/{{ env.GITHUB_RUN_ID }}
>
Commit message:
```
{{ env.GIT_COMMIT_MESSAGE }}
```
@@ -1,17 +0,0 @@
🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩
> :rocket: {{ env.NYM_PROJECT_NAME }} ➡️➡️➡️➡️➡️ **View output:** https://{{ env.NYM_CI_WWW_BASE }}/developers/
>
> ✅ **SUCCESS**
>
> `branch` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/tree/{{ env.GIT_BRANCH_NAME }}
>
> `commit` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/commit/{{ env.GITHUB_SHA }}
>
> `build ` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/actions/runs/{{ env.GITHUB_RUN_ID }}
>
Commit message by `{{ env.GITHUB_ACTOR }}` at {{ timestamp }}:
```
{{ env.GIT_COMMIT_MESSAGE }}
```
@@ -1,29 +0,0 @@
const Handlebars = require('handlebars');
const fs = require('fs');
const path = require('path');
async function addToContextAndValidate(context) {
if (!context.env.NYM_CI_WWW_LOCATION) {
throw new Error('Please ensure the env var NYM_CI_WWW_LOCATION is set');
}
if (!context.env.NYM_CI_WWW_BASE) {
throw new Error('Please ensure the env var NYM_CI_WWW_BASE is set');
}
}
async function getMessageBody(context) {
const source = fs
.readFileSync(
context.env.IS_SUCCESS === 'true'
? path.resolve(__dirname, 'templates', 'success')
: path.resolve(__dirname, 'templates', 'failure'),
)
.toString();
const template = Handlebars.compile(source);
return template(context);
}
module.exports = {
addToContextAndValidate,
getMessageBody,
};
@@ -1,11 +0,0 @@
🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥
> :rocket: {{ env.NYM_PROJECT_NAME }}
> 🔴 **FAILURE** :cry:
> `branch` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/tree/{{ env.GIT_BRANCH_NAME }}
> `commit` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/commit/{{ env.GITHUB_SHA }}
> `build ` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/actions/runs/{{ env.GITHUB_RUN_ID }}
Commit message:
```
{{ env.GIT_COMMIT_MESSAGE }}
```
@@ -1,17 +0,0 @@
🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩
> :rocket: {{ env.NYM_PROJECT_NAME }} ➡️➡️➡️➡️➡️ **View output:** https://{{ env.NYM_CI_WWW_BASE }}/docs/
>
> ✅ **SUCCESS**
>
> `branch` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/tree/{{ env.GIT_BRANCH_NAME }}
>
> `commit` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/commit/{{ env.GITHUB_SHA }}
>
> `build ` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/actions/runs/{{ env.GITHUB_RUN_ID }}
>
Commit message by `{{ env.GITHUB_ACTOR }}` at {{ timestamp }}:
```
{{ env.GIT_COMMIT_MESSAGE }}
```
@@ -1,29 +0,0 @@
const Handlebars = require('handlebars');
const fs = require('fs');
const path = require('path');
async function addToContextAndValidate(context) {
if (!context.env.NYM_CI_WWW_LOCATION) {
throw new Error('Please ensure the env var NYM_CI_WWW_LOCATION is set');
}
if (!context.env.NYM_CI_WWW_BASE) {
throw new Error('Please ensure the env var NYM_CI_WWW_BASE is set');
}
}
async function getMessageBody(context) {
const source = fs
.readFileSync(
context.env.IS_SUCCESS === 'true'
? path.resolve(__dirname, 'templates', 'success')
: path.resolve(__dirname, 'templates', 'failure'),
)
.toString();
const template = Handlebars.compile(source);
return template(context);
}
module.exports = {
addToContextAndValidate,
getMessageBody,
};
@@ -1,17 +0,0 @@
🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥
> :rocket: {{ env.NYM_PROJECT_NAME }}
>
> 🔴 **FAILURE** :cry:
>
> `branch` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/tree/{{ env.GIT_BRANCH_NAME }}
>
> `commit` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/commit/{{ env.GITHUB_SHA }}
>
> `build ` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/actions/runs/{{ env.GITHUB_RUN_ID }}
>
Commit message:
```
{{ env.GIT_COMMIT_MESSAGE }}
```
@@ -1,17 +0,0 @@
🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩
> :rocket: {{ env.NYM_PROJECT_NAME }} ➡️➡️➡️➡️➡️ **View output:** https://{{ env.NYM_CI_WWW_LOCATION }}.{{ env.NYM_CI_WWW_BASE }}/
>
> ✅ **SUCCESS**
>
> `branch` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/tree/{{ env.GIT_BRANCH_NAME }}
>
> `commit` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/commit/{{ env.GITHUB_SHA }}
>
> `build ` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/actions/runs/{{ env.GITHUB_RUN_ID }}
>
Commit message by `{{ env.GITHUB_ACTOR }}` at {{ timestamp }}:
```
{{ env.GIT_COMMIT_MESSAGE }}
```
@@ -1,29 +0,0 @@
const Handlebars = require('handlebars');
const fs = require('fs');
const path = require('path');
async function addToContextAndValidate(context) {
if (!context.env.NYM_CI_WWW_LOCATION) {
throw new Error('Please ensure the env var NYM_CI_WWW_LOCATION is set');
}
if (!context.env.NYM_CI_WWW_BASE) {
throw new Error('Please ensure the env var NYM_CI_WWW_BASE is set');
}
}
async function getMessageBody(context) {
const source = fs
.readFileSync(
context.env.IS_SUCCESS === 'true'
? path.resolve(__dirname, 'templates', 'success')
: path.resolve(__dirname, 'templates', 'failure'),
)
.toString();
const template = Handlebars.compile(source);
return template(context);
}
module.exports = {
addToContextAndValidate,
getMessageBody,
};
@@ -1,17 +0,0 @@
🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥
> :rocket: {{ env.NYM_PROJECT_NAME }}
>
> 🔴 **FAILURE** :cry:
>
> `branch` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/tree/{{ env.GIT_BRANCH_NAME }}
>
> `commit` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/commit/{{ env.GITHUB_SHA }}
>
> `build ` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/actions/runs/{{ env.GITHUB_RUN_ID }}
>
Commit message:
```
{{ env.GIT_COMMIT_MESSAGE }}
```
@@ -1,17 +0,0 @@
🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩
> :rocket: {{ env.NYM_PROJECT_NAME }} ➡️➡️➡️➡️➡️ **View output:** https://{{ env.NYM_CI_WWW_LOCATION }}.{{ env.NYM_CI_WWW_BASE }}/
>
> ✅ **SUCCESS**
>
> `branch` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/tree/{{ env.GIT_BRANCH_NAME }}
>
> `commit` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/commit/{{ env.GITHUB_SHA }}
>
> `build ` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/actions/runs/{{ env.GITHUB_RUN_ID }}
>
Commit message by `{{ env.GITHUB_ACTOR }}` at {{ timestamp }}:
```
{{ env.GIT_COMMIT_MESSAGE }}
```
@@ -3,7 +3,7 @@ require('dotenv').config();
const { sendMatrixMessage } = require('./send_message_to_matrix'); const { sendMatrixMessage } = require('./send_message_to_matrix');
let context = { let context = {
kinds: ['nym-wallet', 'ts-packages', 'network-explorer', 'nightly', 'nym-connect','security','ci-docs','cd-docs','ci-dev','cd-dev'], kinds: ['nym-wallet', 'ts-packages', 'network-explorer', 'nightly', 'nym-connect','security'],
}; };
/** /**
+1 -1
View File
@@ -22,6 +22,6 @@
"unified": "^9.2.2" "unified": "^9.2.2"
}, },
"devDependencies": { "devDependencies": {
"prettier": "^2.8.7" "prettier": "2.3.2"
} }
} }
@@ -10,7 +10,7 @@ async function addToContextAndValidate(context) {
async function getMessageBody(context) { async function getMessageBody(context) {
try { try {
const source = fs const source = fs
.readFileSync("./notifications/deny.message").toString(); .readFileSync("deny.message").toString();
return source; return source;
} catch (error) { } catch (error) {
console.error(error); console.error(error);
+52 -60
View File
@@ -3,70 +3,62 @@ name: CI for linting Typescript
on: on:
push: push:
paths: paths:
- "ts-packages/**" - 'ts-packages/**'
- "sdk/typescript/**" - 'sdk/typescript/**'
- "nym-connect/desktop/src/**" - 'nym-connect/desktop/src/**'
- "nym-connect/desktop/package.json" - 'nym-connect/desktop/package.json'
- "nym-connect/mobile/src/**" - 'nym-connect/mobile/src/**'
- "nym-connect/mobile/package.json" - 'nym-connect/mobile/package.json'
- "nym-wallet/src/**" - 'nym-wallet/src/**'
- "nym-wallet/package.json" - 'nym-wallet/package.json'
- "explorer/**"
pull_request: pull_request:
paths: paths:
- "ts-packages/**" - 'ts-packages/**'
- "sdk/typescript/**" - 'sdk/typescript/**'
- "nym-connect/desktop/src/**" - 'nym-connect/desktop/src/**'
- "nym-connect/desktop/package.json" - 'nym-connect/desktop/package.json'
- "nym-connect/mobile/src/**" - 'nym-connect/mobile/src/**'
- "nym-connect/mobile/package.json" - 'nym-connect/mobile/package.json'
- "nym-wallet/src/**" - 'nym-wallet/src/**'
- "nym-wallet/package.json" - 'nym-wallet/package.json'
- "explorer/**"
jobs: jobs:
build: build:
runs-on: custom-runner-linux runs-on: custom-runner-linux
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- name: Install rsync - name: Install rsync
run: sudo apt-get install rsync run: sudo apt-get install rsync
continue-on-error: true continue-on-error: true
- uses: rlespinasse/github-slug-action@v3.x - uses: rlespinasse/github-slug-action@v3.x
- uses: actions/setup-node@v3 - uses: actions/setup-node@v3
with: with:
node-version: 18 node-version: 16
- name: Install Rust stable - name: Setup yarn
uses: actions-rs/toolchain@v1 run: npm install -g yarn
with: - name: Install
toolchain: stable run: yarn
- name: Install wasm-pack - name: Build packages
run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh run: yarn build
- name: Setup yarn - name: Lint
run: npm install -g yarn run: yarn lint && yarn tsc
- name: Install - name: Matrix - Node Install
run: yarn run: npm install
- name: Build packages working-directory: .github/workflows/support-files
run: yarn build - name: Matrix - Send Notification
- name: Lint env:
run: yarn lint && yarn tsc NYM_NOTIFICATION_KIND: ts-packages
- name: Matrix - Node Install NYM_PROJECT_NAME: "ts-packages"
run: npm install NYM_CI_WWW_BASE: "${{ secrets.NYM_CI_WWW_BASE }}"
working-directory: .github/workflows/support-files NYM_CI_WWW_LOCATION: "ts-${{ env.GITHUB_REF_SLUG }}"
- name: Matrix - Send Notification GIT_COMMIT_MESSAGE: "${{ github.event.head_commit.message }}"
env: GIT_BRANCH: "${GITHUB_REF##*/}"
NYM_NOTIFICATION_KIND: ts-packages IS_SUCCESS: "${{ job.status == 'success' }}"
NYM_PROJECT_NAME: "ts-packages" MATRIX_SERVER: "${{ secrets.MATRIX_SERVER }}"
NYM_CI_WWW_BASE: "${{ secrets.NYM_CI_WWW_BASE }}" MATRIX_ROOM: "${{ secrets.MATRIX_ROOM }}"
NYM_CI_WWW_LOCATION: "ts-${{ env.GITHUB_REF_SLUG }}" MATRIX_USER_ID: "${{ secrets.MATRIX_USER_ID }}"
GIT_COMMIT_MESSAGE: "${{ github.event.head_commit.message }}" MATRIX_TOKEN: "${{ secrets.MATRIX_TOKEN }}"
GIT_BRANCH: "${GITHUB_REF##*/}" MATRIX_DEVICE_ID: "${{ secrets.MATRIX_DEVICE_ID }}"
IS_SUCCESS: "${{ job.status == 'success' }}" uses: docker://keybaseio/client:stable-node
MATRIX_SERVER: "${{ secrets.MATRIX_SERVER }}" with:
MATRIX_ROOM: "${{ secrets.MATRIX_ROOM }}" args: .github/workflows/support-files/notifications/entry_point.sh
MATRIX_USER_ID: "${{ secrets.MATRIX_USER_ID }}"
MATRIX_TOKEN: "${{ secrets.MATRIX_TOKEN }}"
MATRIX_DEVICE_ID: "${{ secrets.MATRIX_DEVICE_ID }}"
uses: docker://keybaseio/client:stable-node
with:
args: .github/workflows/support-files/notifications/entry_point.sh
-79
View File
@@ -1,79 +0,0 @@
name: Upload nyxd to CI
on:
workflow_dispatch:
jobs:
publish-nyxd:
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/nyxd
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 build-essential curl wget libssl-dev libgtk-3-dev libudev-dev squashfs-tools git
continue-on-error: true
- name: Update env variables to include go
run: |
sudo rm -rf /usr/local/go
curl https://dl.google.com/go/go1.19.2.linux-amd64.tar.gz | sudo tar -C/usr/local -zxvf -
cat <<'EOF' >>$HOME/.profile
export GOROOT=/usr/local/go
export GOPATH=$HOME/go
export GO111MODULE=on
export PATH=$PATH:/usr/local/go/bin:$HOME/go/bin
EOF
source $HOME/.profile
- name: Verify Go is installed
run: go version
- name: Clone nyxd repo
run: |
git clone https://github.com/tommyv1987/nyxd
cd nyxd
git checkout release/v0.30.2
- name: Run nyxd
run: |
pwd
cd nyxd && make build
sleep 10
ls /home/runner/work/nym/nym/nyxd/build
- name: Prepare build output
shell: bash
env:
OUTPUT_DIR: ci-builds/nyxd
run: |
cp /home/runner/work/nym/nym/nyxd/build/nyxd $OUTPUT_DIR
WASMVM_SO=$(ldd /home/runner/work/nym/nym/nyxd/build/nyxd | grep "libwasm*" | awk '{ print $3 }')
ls $WASMVM_SO
sleep 3
cp $(echo $WASMVM_SO) $OUTPUT_DIR
- name: Deploy nyxd 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/"
+1 -1
View File
@@ -64,4 +64,4 @@ jobs:
uses: actions-rs/cargo@v1 uses: actions-rs/cargo@v1
with: with:
command: clippy command: clippy
args: --manifest-path nym-wallet/Cargo.toml --workspace --all-features --all-targets -- -D warnings args: --manifest-path nym-wallet/Cargo.toml --workspace --all-features -- -D warnings
-3
View File
@@ -8,7 +8,6 @@
.idea .idea
target target
.env .env
.env.dev
/.vscode/settings.json /.vscode/settings.json
validator/.vscode validator/.vscode
sample-configs/validator-config.toml sample-configs/validator-config.toml
@@ -42,5 +41,3 @@ storybook-static
envs/qwerty.env envs/qwerty.env
.parcel-cache .parcel-cache
**/.DS_Store **/.DS_Store
cpu-cycles/libcpucycles/build
foxyfox.env
+2 -178
View File
@@ -4,189 +4,12 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
## [Unreleased] ## [Unreleased]
## [v1.1.23] (2023-07-04)
- nym-cli: add client identity key signing support ([#3576])
- Feature/node tester package ([#3634])
- Add medium toggle to socks5 client ([#3615])
- Don't fully turn off background task when cover traffic is disabled ([#3596])
[#3576]: https://github.com/nymtech/nym/issues/3576
[#3634]: https://github.com/nymtech/nym/pull/3634
[#3615]: https://github.com/nymtech/nym/pull/3615
[#3596]: https://github.com/nymtech/nym/pull/3596
## [v1.1.22] (2023-06-20)
- CLI tool for querying network-requesters ([#3539])
- Statically link OpenSSL ([#3510])
- NymConnect - add sentry.io reporting ([#3421])
- init command does not change version number in config.toml ([#3336])
- [Bug] Config version does not correspond to binary version ([#3434])
[#3539]: https://github.com/nymtech/nym/issues/3539
[#3510]: https://github.com/nymtech/nym/issues/3510
[#3421]: https://github.com/nymtech/nym/issues/3421
[#3336]: https://github.com/nymtech/nym/issues/3336
[#3434]: https://github.com/nymtech/nym/issues/3434
## [v1.1.21] (2023-06-13)
- mixFetch: Change socks5 `SendRequest` to include OrderedMessage index as a field rather than making it serialized inside the `data` field
([#3534])
- Explorer - add more data columns to the Service Provider section: ([#3474])
- network-requester: support report if they run an open proxy using `ControlRequest` API ([#3461])
- Refactor client configs (London discussion) ([#3444])
- Increase `DEFAULT_MAXIMUM_CONNECTION_BUFFER_SIZE` to 2000 to improve reliability ([#3433])
- socks5: sender waits for lanes to clear even though the connection is closed ([#3366])
- version bump for variables ([#3545])
[#3534]: https://github.com/nymtech/nym/issues/3534
[#3474]: https://github.com/nymtech/nym/issues/3474
[#3461]: https://github.com/nymtech/nym/issues/3461
[#3444]: https://github.com/nymtech/nym/issues/3444
[#3433]: https://github.com/nymtech/nym/issues/3433
[#3366]: https://github.com/nymtech/nym/issues/3366
[#3545]: https://github.com/nymtech/nym/pull/3545
## [v1.1.20] (2023-06-06)
- Explorer - Fix SP supported apps list ([#3458])
- Investigate if we need to lower `SHUTDOWN_TIMEOUT` in socks5 to zero (or almost zero) ([#3438])
- Explorer - show all gateways in the default view regardless of the version number ([#3427])
- service-provider-directory: add signature check when announcing ([#3360])
- Support functionality for nym-name-service (nym-api, nym-cli, etc) ([#3355])
- Edit the nym-network-requester to support the enabled-credentials-mode flag ([#3101])
- [BUG] network requester documentation update ([#3493])
- removing hardcoded version numbers ([#3485])
- [BUG] network requester documentation update ([#3481])
- [BUG] network requester documentation update ([#3469])
- Sign when announcing service providers to the directory contract ([#3459])
- mixnode documentation update ([#3435])
- updated readme with new developer chat links + new docs links ([#3141])
[#3458]: https://github.com/nymtech/nym/issues/3458
[#3438]: https://github.com/nymtech/nym/issues/3438
[#3427]: https://github.com/nymtech/nym/issues/3427
[#3360]: https://github.com/nymtech/nym/issues/3360
[#3355]: https://github.com/nymtech/nym/issues/3355
[#3101]: https://github.com/nymtech/nym/issues/3101
[#3493]: https://github.com/nymtech/nym/pull/3493
[#3485]: https://github.com/nymtech/nym/pull/3485
[#3481]: https://github.com/nymtech/nym/pull/3481
[#3469]: https://github.com/nymtech/nym/pull/3469
[#3459]: https://github.com/nymtech/nym/pull/3459
[#3435]: https://github.com/nymtech/nym/pull/3435
[#3141]: https://github.com/nymtech/nym/pull/3141
## [v1.1.19] (2023-05-16)
- nym-name-service endpoint in nym-api ([#3403])
- Implement key storage for WASM client using IndexedDB (for browser) ([#3329])
- Initial version of nym-name-service contract providing name aliases for nym-addresses ([#3274])
- Update Cargo.lock ([#3410])
[#3403]: https://github.com/nymtech/nym/issues/3403
[#3329]: https://github.com/nymtech/nym/issues/3329
[#3274]: https://github.com/nymtech/nym/issues/3274
[#3410]: https://github.com/nymtech/nym/pull/3410
## [v1.1.18] (2023-05-09)
- Implement heartbeat messages between socks5 proxy and network requester ([#3215])
[#3215]: https://github.com/nymtech/nym/issues/3215
## [v1.1.17] (2023-05-02)
- Add service-provider-directory-contract support to nym-cli ([#3334])
- Start using the node-testing-utils (implemented in #3270) in nym-api Network monitor to simplify the logic there ([#3312])
- Add service-provider-directory support to validator-client ([#3296])
- Allow topology injection in our WASM client ('test my node' feature) ([#3270])
- Expose service-provider-directory contract data in nym-api endpoints ([#3242])
- Cache service provider contract in nym-api ([#3241])
- Feature/1 1 17 docs ([#3370])
- adding a test for SP endpoint ([#3367])
- Feature/store cipher ([#3350])
[#3334]: https://github.com/nymtech/nym/issues/3334
[#3312]: https://github.com/nymtech/nym/issues/3312
[#3296]: https://github.com/nymtech/nym/issues/3296
[#3270]: https://github.com/nymtech/nym/issues/3270
[#3242]: https://github.com/nymtech/nym/issues/3242
[#3241]: https://github.com/nymtech/nym/issues/3241
[#3370]: https://github.com/nymtech/nym/pull/3370
[#3367]: https://github.com/nymtech/nym/pull/3367
[#3350]: https://github.com/nymtech/nym/pull/3350
## [v1.1.16] (2023-04-25)
- Explorer - Fix sorting function on Stake Saturation. It is currently working per page and not globally ([#3320])
- Poisson process gets stuck at too slow rate. Rework to more aggressively up-regulate ([#3309])
- decrease the logging level of warnings associated with clients dropping packets due to gateway being overloaded (I'd say reduce it to debug/trace) - there are few sources of those, e.g. in real and cover traffic streams ([#3299])
- Make the buffer size in `AvailableReader` depend on packet sizes the client is using + introduce read timeouts ([#3213])
- Rust SDK - Support coconut, credential storage etc ([#2755])
- version bump for next release ([#3349])
- added coconut credential generation example ([#3339])
- update mix-node setup docs with node description ([#3325])
- exposed missing gateway commands in nym-cli ([#3324])
- make sure to clear inner 'ack_map' in 'GatewaysReader' ([#3300])
[#3320]: https://github.com/nymtech/nym/issues/3320
[#3309]: https://github.com/nymtech/nym/issues/3309
[#3299]: https://github.com/nymtech/nym/issues/3299
[#3213]: https://github.com/nymtech/nym/issues/3213
[#2755]: https://github.com/nymtech/nym/issues/2755
[#3349]: https://github.com/nymtech/nym/pull/3349
[#3339]: https://github.com/nymtech/nym/pull/3339
[#3325]: https://github.com/nymtech/nym/pull/3325
[#3324]: https://github.com/nymtech/nym/pull/3324
[#3300]: https://github.com/nymtech/nym/pull/3300
## [v1.1.15] (2023-04-18)
- Fix verloc being stuck waiting for shutdown signal ([#3250])
- Introduce `--output json` flag to `sign` command to allow to more easily capture the output ([#3249])
- Explorer - Dont fetch Service Provider list on Testnet ([#3245])
- When determining active set, rather than weighting the nodes by just the `stake`, use `stake * performance` ([#3234])
- Introduce dual packet sizes to our clients (as in use two packet sizes at the same time depending on message size) ([#3189])
- Experiment with offline signing in our validator client ([#3174])
- Modify network requester binary to reload `allowed.list` periodically to pull in any changes made upstream without having to restart the service ([#3149])
- Standardise all `--output json` on binary inits, we pass the output json at different points for different binaries. ([#3080])
- Service provider directory contract: initial version ([#2759])
- Fix issue where network-requester run failed on fresh init due to missing allow file ([#3316])
[#3250]: https://github.com/nymtech/nym/issues/3250
[#3249]: https://github.com/nymtech/nym/issues/3249
[#3245]: https://github.com/nymtech/nym/issues/3245
[#3234]: https://github.com/nymtech/nym/issues/3234
[#3189]: https://github.com/nymtech/nym/issues/3189
[#3174]: https://github.com/nymtech/nym/issues/3174
[#3149]: https://github.com/nymtech/nym/issues/3149
[#3080]: https://github.com/nymtech/nym/issues/3080
[#2759]: https://github.com/nymtech/nym/issues/2759
[#3316]: https://github.com/nymtech/nym/pull/3316
## [v1.1.14] (2023-04-04)
- Investigate cause of qwerty validator being in invalid rewarding state ([#3224])
- Fix NR config due to changes in #3199 ([#3223])
- [Issue] Mixnodes and gateway do not close connections properly ([#3187])
- disable sign-ext when using wasm-opt + update wasm-opt ([#3203])
- chore: tidy up client `Debug` config section ([#3199])
[#3224]: https://github.com/nymtech/nym/issues/3224
[#3223]: https://github.com/nymtech/nym/issues/3223
[#3187]: https://github.com/nymtech/nym/issues/3187
[#3203]: https://github.com/nymtech/nym/pull/3203
[#3199]: https://github.com/nymtech/nym/pull/3199
>>>>>>> master
## [v1.1.13] (2023-03-15) ## [v1.1.13] (2023-03-15)
- NE - instead of throwing a "Mixnode/Gateway not found" error for blacklisted nodes due to bad performance, show their history but tag them as "Having poor performance" ([#2979]) - NE - instead of throwing a "Mixnode/Gateway not found" error for blacklisted nodes due to bad performance, show their history but tag them as "Having poor performance" ([#2979])
- NE - Upgrade Sandbox and make below changes: ([#2332]) - NE - Upgrade Sandbox and make below changes: ([#2332])
- Explorer - Updates ([#3168]) - Explorer - Updates ([#3168])
- Fix contracts and nym-api audit findings ([#3026])
- Website v2 - deploy infrastructure for strapi and CI ([#2213]) - Website v2 - deploy infrastructure for strapi and CI ([#2213])
- add blockstream green to sp list ([#3180]) - add blockstream green to sp list ([#3180])
- mock-nym-api: fix .storybook lint error ([#3178]) - mock-nym-api: fix .storybook lint error ([#3178])
@@ -195,6 +18,7 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
[#2979]: https://github.com/nymtech/nym/issues/2979 [#2979]: https://github.com/nymtech/nym/issues/2979
[#2332]: https://github.com/nymtech/nym/issues/2332 [#2332]: https://github.com/nymtech/nym/issues/2332
[#3168]: https://github.com/nymtech/nym/issues/3168 [#3168]: https://github.com/nymtech/nym/issues/3168
[#3026]: https://github.com/nymtech/nym/issues/3026
[#2213]: https://github.com/nymtech/nym/issues/2213 [#2213]: https://github.com/nymtech/nym/issues/2213
[#3180]: https://github.com/nymtech/nym/pull/3180 [#3180]: https://github.com/nymtech/nym/pull/3180
[#3178]: https://github.com/nymtech/nym/pull/3178 [#3178]: https://github.com/nymtech/nym/pull/3178
Generated
+874 -1744
View File
File diff suppressed because it is too large Load Diff
+14 -30
View File
@@ -17,14 +17,13 @@ opt-level = 3
resolver = "2" resolver = "2"
members = [ members = [
"clients/client-core",
"clients/credential", "clients/credential",
"clients/native", "clients/native",
"clients/native/websocket-requests", "clients/native/websocket-requests",
"clients/socks5", "clients/socks5",
"common/async-file-watcher", "common/bandwidth-claim-contract",
"common/bandwidth-controller",
"common/bin-common", "common/bin-common",
"common/client-core",
"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",
@@ -37,9 +36,8 @@ members = [
"common/cosmwasm-smart-contracts/group-contract", "common/cosmwasm-smart-contracts/group-contract",
"common/cosmwasm-smart-contracts/mixnet-contract", "common/cosmwasm-smart-contracts/mixnet-contract",
"common/cosmwasm-smart-contracts/multisig-contract", "common/cosmwasm-smart-contracts/multisig-contract",
"common/cosmwasm-smart-contracts/name-service",
"common/cosmwasm-smart-contracts/service-provider-directory",
"common/cosmwasm-smart-contracts/vesting-contract", "common/cosmwasm-smart-contracts/vesting-contract",
"common/mobile-storage",
"common/credential-storage", "common/credential-storage",
"common/credentials", "common/credentials",
"common/crypto", "common/crypto",
@@ -49,7 +47,6 @@ members = [
"common/ledger", "common/ledger",
"common/mixnode-common", "common/mixnode-common",
"common/network-defaults", "common/network-defaults",
"common/node-tester-utils",
"common/nonexhaustive-delayqueue", "common/nonexhaustive-delayqueue",
"common/nymcoconut", "common/nymcoconut",
"common/nymsphinx", "common/nymsphinx",
@@ -61,14 +58,11 @@ members = [
"common/nymsphinx/forwarding", "common/nymsphinx/forwarding",
"common/nymsphinx/framing", "common/nymsphinx/framing",
"common/nymsphinx/params", "common/nymsphinx/params",
"common/nymsphinx/routing",
"common/nymsphinx/types", "common/nymsphinx/types",
"common/pemstore", "common/pemstore",
"common/socks5-client-core",
"common/socks5/proxy-helpers", "common/socks5/proxy-helpers",
"common/socks5/requests", "common/socks5/requests",
"common/statistics", "common/statistics",
"common/store-cipher",
"common/task", "common/task",
"common/topology", "common/topology",
"common/types", "common/types",
@@ -78,7 +72,6 @@ members = [
"gateway/gateway-requests", "gateway/gateway-requests",
"integrations/bity", "integrations/bity",
"mixnode", "mixnode",
"sdk/lib/socks5-listener",
"sdk/rust/nym-sdk", "sdk/rust/nym-sdk",
"service-providers/common", "service-providers/common",
"service-providers/network-requester", "service-providers/network-requester",
@@ -87,7 +80,6 @@ members = [
"nym-api/nym-api-requests", "nym-api/nym-api-requests",
"nym-outfox", "nym-outfox",
"tools/nym-cli", "tools/nym-cli",
"tools/nym-nr-query",
"tools/ts-rs-cli" "tools/ts-rs-cli"
] ]
@@ -102,7 +94,7 @@ default-members = [
"explorer-api", "explorer-api",
] ]
exclude = ["explorer", "contracts", "clients/webassembly", "nym-wallet", "nym-connect/mobile/src-tauri", "nym-connect/desktop", "nym-browser-extension/storage", "cpu-cycles"] 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"]
@@ -113,26 +105,19 @@ edition = "2021"
license = "Apache-2.0" license = "Apache-2.0"
[workspace.dependencies] [workspace.dependencies]
anyhow = "1.0.71"
async-trait = "0.1.64" async-trait = "0.1.64"
bip39 = { version = "2.0.0", features = ["zeroize"] }
cfg-if = "1.0.0" cfg-if = "1.0.0"
cosmwasm-derive = "=1.2.5" cosmwasm-derive = "=1.0.0"
cosmwasm-schema = "=1.2.5" cosmwasm-schema = "=1.0.0"
cosmwasm-std = "=1.2.5" cosmwasm-std = "=1.0.0"
cosmwasm-storage = "=1.2.5" cosmwasm-storage = "=1.0.0"
cosmrs = "=0.8.0" cw-utils = "=0.13.4"
cw-utils = "=1.0.1" cw-storage-plus = "=0.13.4"
cw-storage-plus = "=1.0.1" cw2 = { version = "=0.13.4" }
cw2 = { version = "=1.0.1" } cw3 = { version = "=0.13.4" }
cw3 = { version = "=1.0.1" } cw3-fixed-multisig = { version = "=0.13.4" }
cw3-fixed-multisig = { version = "=1.0.1" } cw4 = { version = "=0.13.4" }
cw4 = { version = "=1.0.1" }
cw-controllers = { version = "=1.0.1" }
dotenvy = "0.15.6" dotenvy = "0.15.6"
generic-array = "0.14.7"
k256 = "0.11"
getrandom = "0.2.10"
lazy_static = "1.4.0" lazy_static = "1.4.0"
log = "0.4" log = "0.4"
once_cell = "1.7.2" once_cell = "1.7.2"
@@ -143,4 +128,3 @@ tap = "1.0.1"
thiserror = "1.0.38" thiserror = "1.0.38"
tokio = "1.24.1" tokio = "1.24.1"
url = "2.2" url = "2.2"
zeroize = "1.6.0"
+107 -86
View File
@@ -1,122 +1,143 @@
# Default target
all: test
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
happy-no-mobile: fmt-no-mobile clippy-happy-no-mobile test-no-mobile
clippy-all: clippy-all-no-mobile clippy-all-connect-mobile
clippy-all-no-mobile: clippy-main clippy-main-examples clippy-all-contracts clippy-all-wallet clippy-all-connect clippy-all-wasm-client
clippy-happy: clippy-happy-no-mobile clippy-happy-connect-mobile
clippy-happy-no-mobile: clippy-happy-main clippy-happy-contracts clippy-happy-wallet clippy-happy-connect
cargo-test: cargo-test-no-mobile test-connect-mobile
cargo-test-no-mobile: test-main test-contracts test-wallet test-connect
cargo-test-expensive: test-main-expensive test-contracts-expensive test-wallet-expensive test-connect-expensive
build: build-no-mobile build-connect-mobile
build-no-mobile: build-contracts build-wallet build-main build-main-examples build-connect build-wasm-client
fmt: fmt-no-mobile fmt-connect-mobile
fmt-no-mobile: fmt-main fmt-contracts fmt-wallet fmt-connect fmt-wasm-client
# Building release binaries is a little manual as we can't just build --release clippy-happy-main:
# on all workspaces. cargo clippy
build-release: build-release-main wasm
# Deprecated clippy-happy-contracts:
# For backwards compatibility cargo clippy --manifest-path contracts/Cargo.toml --target wasm32-unknown-unknown
clippy-all: clippy
# ----------------------------------------------------------------------------- clippy-happy-wallet:
# Define targets for a given workspace cargo clippy --manifest-path nym-wallet/Cargo.toml
# $(1): name
# $(2): path to workspace
# $(3): extra arguments to cargo
# -----------------------------------------------------------------------------
define add_cargo_workspace
clippy-happy-$(1): clippy-happy-connect:
cargo clippy --manifest-path $(2)/Cargo.toml $(3) cargo clippy --manifest-path nym-connect/desktop/Cargo.toml
clippy-$(1): clippy-happy-connect-mobile:
cargo clippy --manifest-path $(2)/Cargo.toml --workspace $(3) -- -D warnings cargo clippy --manifest-path nym-connect/mobile/src-tauri/Cargo.toml
clippy-examples-$(1): clippy-main:
cargo clippy --manifest-path $(2)/Cargo.toml --workspace --examples -- -D warnings cargo clippy --workspace -- -D warnings
check-$(1): clippy-main-examples:
cargo check --manifest-path $(2)/Cargo.toml --workspace $(3) cargo clippy --workspace --examples -- -D warnings
test-$(1): clippy-wasm:
cargo test --manifest-path $(2)/Cargo.toml --workspace cargo clippy --manifest-path clients/webassembly/Cargo.toml --target wasm32-unknown-unknown --workspace -- -D warnings
test-expensive-$(1):
cargo test --manifest-path $(2)/Cargo.toml --workspace -- --ignored
build-$(1): clippy-all-contracts:
cargo build --manifest-path $(2)/Cargo.toml --workspace $(3) cargo clippy --workspace --manifest-path contracts/Cargo.toml --all-features --target wasm32-unknown-unknown -- -D warnings
build-examples-$(1): clippy-all-wallet:
cargo build --manifest-path $(2)/Cargo.toml --workspace --examples cargo clippy --workspace --manifest-path nym-wallet/Cargo.toml --all-features -- -D warnings
build-release-$(1): clippy-all-connect:
cargo build --manifest-path $(2)/Cargo.toml --workspace --release $(3) cargo clippy --workspace --manifest-path nym-connect/desktop/Cargo.toml --all-features -- -D warnings
fmt-$(1): clippy-all-connect-mobile:
cargo fmt --manifest-path $(2)/Cargo.toml --all cargo clippy --workspace --manifest-path nym-connect/mobile/src-tauri/Cargo.toml --all-features -- -D warnings
clippy-happy: clippy-happy-$(1) clippy-all-wasm-client:
clippy: clippy-$(1) clippy-examples-$(1) cargo clippy --workspace --manifest-path clients/webassembly/Cargo.toml --all-features --target wasm32-unknown-unknown -- -D warnings
check: check-$(1)
cargo-test: test-$(1)
cargo-test-expensive: test-expensive-$(1)
build: build-$(1) build-examples-$(1)
build-release-all: build-release-$(1)
fmt: fmt-$(1)
endef test-main:
cargo test --workspace
# ----------------------------------------------------------------------------- test-main-expensive:
# Rust workspaces cargo test --workspace -- --ignored
# -----------------------------------------------------------------------------
# Generate targets for the various cargo workspaces test-contracts:
cargo test --manifest-path contracts/Cargo.toml --all-features
$(eval $(call add_cargo_workspace,main,.)) test-contracts-expensive:
$(eval $(call add_cargo_workspace,contracts,contracts,--target wasm32-unknown-unknown)) cargo test --manifest-path contracts/Cargo.toml --all-features -- --ignored
$(eval $(call add_cargo_workspace,wasm-client,clients/webassembly,--target wasm32-unknown-unknown))
$(eval $(call add_cargo_workspace,wallet,nym-wallet,))
$(eval $(call add_cargo_workspace,connect,nym-connect/desktop))
ifdef NYM_MOBILE
$(eval $(call add_cargo_workspace,connect-mobile,nym-connect/mobile/src-tauri))
endif
# ----------------------------------------------------------------------------- test-wallet:
# Convenience targets for crates that are already part of the main workspace cargo test --manifest-path nym-wallet/Cargo.toml --all-features
# -----------------------------------------------------------------------------
test-wallet-expensive:
cargo test --manifest-path nym-wallet/Cargo.toml --all-features -- --ignored
test-connect:
cargo test --manifest-path nym-connect/desktop/Cargo.toml --all-features
test-connect-expensive:
cargo test --manifest-path nym-connect/desktop/Cargo.toml --all-features -- --ignored
test-connect-mobile:
cargo test --manifest-path nym-connect/mobile/src-tauri/Cargo.toml --all-features
test-connect-mobile-expensive:
cargo test --manifest-path nym-connect/mobile/src-tauri/Cargo.toml --all-features -- --ignored
build-main:
cargo build --workspace
build-main-examples:
cargo build --workspace --examples
build-contracts:
cargo build --manifest-path contracts/Cargo.toml --workspace
build-wallet:
cargo build --manifest-path nym-wallet/Cargo.toml --workspace
build-connect:
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 -p explorer-api cargo build --manifest-path explorer-api/Cargo.toml --workspace
build-wasm-client:
cargo build --manifest-path clients/webassembly/Cargo.toml --workspace --target wasm32-unknown-unknown
build-nym-cli: build-nym-cli:
cargo build -p nym-cli --release cargo build --release --manifest-path tools/nym-cli/Cargo.toml
# ----------------------------------------------------------------------------- fmt-main:
# Build contracts ready for deploy cargo fmt --all
# -----------------------------------------------------------------------------
CONTRACTS_OUT_DIR=contracts/target/wasm32-unknown-unknown/release fmt-contracts:
VESTING_CONTRACT=$(CONTRACTS_OUT_DIR)/vesting_contract.wasm cargo fmt --manifest-path contracts/Cargo.toml --all
MIXNET_CONTRACT=$(CONTRACTS_OUT_DIR)/mixnet_contract.wasm
SERVICE_PROVIDER_DIRECTORY_CONTRACT=$(CONTRACTS_OUT_DIR)/nym_service_provider_directory.wasm
NAME_SERVICE_CONTRACT=$(CONTRACTS_OUT_DIR)/nym_name_service.wasm
wasm: wasm-build wasm-opt fmt-wallet:
cargo fmt --manifest-path nym-wallet/Cargo.toml --all
wasm-build: fmt-connect:
cargo fmt --manifest-path nym-connect/desktop/Cargo.toml --all
fmt-connect-mobile:
cargo fmt --manifest-path nym-connect/mobile/src-tauri/Cargo.toml --all
fmt-wasm-client:
cargo fmt --manifest-path clients/webassembly/Cargo.toml --all
wasm:
RUSTFLAGS='-C link-arg=-s' cargo build --manifest-path contracts/Cargo.toml --release --target wasm32-unknown-unknown 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
wasm-opt:
wasm-opt --disable-sign-ext -Os $(VESTING_CONTRACT) -o $(VESTING_CONTRACT)
wasm-opt --disable-sign-ext -Os $(MIXNET_CONTRACT) -o $(MIXNET_CONTRACT)
wasm-opt --disable-sign-ext -Os $(SERVICE_PROVIDER_DIRECTORY_CONTRACT) -o $(SERVICE_PROVIDER_DIRECTORY_CONTRACT)
wasm-opt --disable-sign-ext -Os $(NAME_SERVICE_CONTRACT) -o $(NAME_SERVICE_CONTRACT)
# -----------------------------------------------------------------------------
# Misc
# -----------------------------------------------------------------------------
# NOTE: this seems deprecated an not needed anymore?
mixnet-opt: wasm mixnet-opt: wasm
cd contracts/mixnet && make opt cd contracts/mixnet && make opt
+7 -10
View File
@@ -13,7 +13,7 @@ The platform is composed of multiple Rust crates. Top-level executable binary cr
* nym-gateway - acts sort of like a mailbox for mixnet messages, which removes the need for direct delivery to potentially offline or firewalled devices. * nym-gateway - acts sort of like a mailbox for mixnet messages, which removes the need for direct delivery to potentially offline or firewalled devices.
* nym-network-monitor - sends packets through the full system to check that they are working as expected, and stores node uptime histories as the basis of a rewards system ("mixmining" or "proof-of-mixing"). * nym-network-monitor - sends packets through the full system to check that they are working as expected, and stores node uptime histories as the basis of a rewards system ("mixmining" or "proof-of-mixing").
* nym-explorer - a (projected) block explorer and (existing) mixnet viewer. * nym-explorer - a (projected) block explorer and (existing) mixnet viewer.
* nym-wallet - a desktop wallet implemented using the [Tauri](https://tauri.studio/en/docs/about/intro) framework. * nym-wallet - a desktop wallet implemented using the [Tauri](https://tauri.studio/en/docs/about/intro) framework.
[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg?style=for-the-badge)](https://opensource.org/licenses/Apache-2.0) [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg?style=for-the-badge)](https://opensource.org/licenses/Apache-2.0)
[![Build Status](https://img.shields.io/github/actions/workflow/status/nymtech/nym/build.yml?branch=develop&style=for-the-badge&logo=github-actions)](https://github.com/nymtech/nym/actions?query=branch%3Adevelop) [![Build Status](https://img.shields.io/github/actions/workflow/status/nymtech/nym/build.yml?branch=develop&style=for-the-badge&logo=github-actions)](https://github.com/nymtech/nym/actions?query=branch%3Adevelop)
@@ -21,8 +21,8 @@ The platform is composed of multiple Rust crates. Top-level executable binary cr
### Building ### Building
Platform build instructions are available on [our docs site](https://nymtech.net/docs/binaries/pre-built-binaries.html). Platform build instructions are available on [our docs site](https://nymtech.net/docs/stable/run-nym-nodes/build-nym).
Wallet build instructions are also available on [our docs site](https://nymtech.net/docs/wallet/desktop-wallet.html). Wallet build instructions are also available on [our docs site](https://nymtech.net/docs/stable/nym-apps/wallet#for-developers).
### Developing ### Developing
@@ -32,11 +32,7 @@ For Typescript components, please see [ts-packages](./ts-packages).
### Developer chat ### Developer chat
> We used to use Keybase for developer chats, but we have since migrated to Matrix and Discord. We no longer check the old **nymtech.friends** Keybase team. You can chat to us in [Keybase](https://keybase.io). Download their chat app, then click **Teams -> Join a team**. Type **nymtech.friends** into the team name and hit **continue**. For general chat, hang out in the **#general** channel. Our development takes places in the **#dev** channel. Node operators should be in the **#node-operators** channel.
You can chat to us in two places:
* The #dev channel on [Matrix](https://matrix.to/#/#dev:nymtech.chat)
* The various developer channels on [Discord](https://discord.gg/nym)
### Rewards ### Rewards
@@ -50,7 +46,7 @@ Node, node operator and delegator rewards are determined according to the princi
|<img src="https://render.githubusercontent.com/render/math?math=\lambda_{i}#gh-light-mode-only"><img src="https://render.githubusercontent.com/render/math?math=\color{white}\lambda_{i}#gh-dark-mode-only">|ratio of stake operator has pledged to their node to the token circulating supply. |<img src="https://render.githubusercontent.com/render/math?math=\lambda_{i}#gh-light-mode-only"><img src="https://render.githubusercontent.com/render/math?math=\color{white}\lambda_{i}#gh-dark-mode-only">|ratio of stake operator has pledged to their node to the token circulating supply.
|<img src="https://render.githubusercontent.com/render/math?math=\omega_{i}#gh-light-mode-only"><img src="https://render.githubusercontent.com/render/math?math=\color{white}\omega_{i}#gh-dark-mode-only">|fraction of total effort undertaken by node `i`, set to `1/k`. |<img src="https://render.githubusercontent.com/render/math?math=\omega_{i}#gh-light-mode-only"><img src="https://render.githubusercontent.com/render/math?math=\color{white}\omega_{i}#gh-dark-mode-only">|fraction of total effort undertaken by node `i`, set to `1/k`.
|<img src="https://render.githubusercontent.com/render/math?math=k#gh-light-mode-only"><img src="https://render.githubusercontent.com/render/math?math=\color{white}k#gh-dark-mode-only">|number of nodes stakeholders are incentivised to create, set by the validators, a matter of governance. Currently determined by the `reward set` size, and set to 720 in testnet Sandbox. |<img src="https://render.githubusercontent.com/render/math?math=k#gh-light-mode-only"><img src="https://render.githubusercontent.com/render/math?math=\color{white}k#gh-dark-mode-only">|number of nodes stakeholders are incentivised to create, set by the validators, a matter of governance. Currently determined by the `reward set` size, and set to 720 in testnet Sandbox.
|<img src="https://render.githubusercontent.com/render/math?math=\alpha#gh-light-mode-only"><img src="https://render.githubusercontent.com/render/math?math=\color{white}\alpha#gh-dark-mode-only">|Sybil attack resistance parameter - the higher this parameter is set the stronger the reduction in competitiveness gets for a Sybil attacker. |<img src="https://render.githubusercontent.com/render/math?math=\alpha#gh-light-mode-only"><img src="https://render.githubusercontent.com/render/math?math=\color{white}\alpha#gh-dark-mode-only">|Sybil attack resistance parameter - the higher this parameter is set the stronger the reduction in competitivness gets for a Sybil attacker.
|<img src="https://render.githubusercontent.com/render/math?math=PM_{i}#gh-light-mode-only"><img src="https://render.githubusercontent.com/render/math?math=\color{white}PM_{i}#gh-dark-mode-only">|declared profit margin of operator `i`, defaults to 10% in. |<img src="https://render.githubusercontent.com/render/math?math=PM_{i}#gh-light-mode-only"><img src="https://render.githubusercontent.com/render/math?math=\color{white}PM_{i}#gh-dark-mode-only">|declared profit margin of operator `i`, defaults to 10% in.
|<img src="https://render.githubusercontent.com/render/math?math=PF_{i}#gh-light-mode-only"><img src="https://render.githubusercontent.com/render/math?math=\color{white}PF_{i}#gh-dark-mode-only">|uptime of node `i`, scaled to 0 - 1, for the rewarding epoch |<img src="https://render.githubusercontent.com/render/math?math=PF_{i}#gh-light-mode-only"><img src="https://render.githubusercontent.com/render/math?math=\color{white}PF_{i}#gh-dark-mode-only">|uptime of node `i`, scaled to 0 - 1, for the rewarding epoch
|<img src="https://render.githubusercontent.com/render/math?math=PP_{i}#gh-light-mode-only"><img src="https://render.githubusercontent.com/render/math?math=\color{white}PP_{i}#gh-dark-mode-only">|cost of operating node `i` for the duration of the rewarding epoch, set to 40 NYMT. |<img src="https://render.githubusercontent.com/render/math?math=PP_{i}#gh-light-mode-only"><img src="https://render.githubusercontent.com/render/math?math=\color{white}PP_{i}#gh-dark-mode-only">|cost of operating node `i` for the duration of the rewarding epoch, set to 40 NYMT.
@@ -74,7 +70,7 @@ Operator of node `i` is credited with the following amount:
<img src="https://render.githubusercontent.com/render/math?math=min\{PP_{i},R_{i})\} %2b max\{0, (PM_{i} %2b (1 - PM_{i}) \cdot \lambda_{i}/\delta_{i}) \cdot (R_{i} - PP_{i})\}#gh-light-mode-only"> <img src="https://render.githubusercontent.com/render/math?math=min\{PP_{i},R_{i})\} %2b max\{0, (PM_{i} %2b (1 - PM_{i}) \cdot \lambda_{i}/\delta_{i}) \cdot (R_{i} - PP_{i})\}#gh-light-mode-only">
<img src="https://render.githubusercontent.com/render/math?math=\color{white}min\{PP_{i},R_{i})\} %2b max\{0, (PM_{i} %2b (1 - PM_{i}) \cdot \lambda_{i}/\delta_{i}) \cdot (R_{i} - PP_{i})\}#gh-dark-mode-only"> <img src="https://render.githubusercontent.com/render/math?math=\color{white}min\{PP_{i},R_{i})\} %2b max\{0, (PM_{i} %2b (1 - PM_{i}) \cdot \lambda_{i}/\delta_{i}) \cdot (R_{i} - PP_{i})\}#gh-dark-mode-only">
Delegate with stake `s` receives: Delegate with stake `s` recieves:
<img src="https://render.githubusercontent.com/render/math?math=max\{0, (1-PM_{i}) \cdot (s^'/\sigma_{i}) \cdot (R_{i} - PP_{i})\}#gh-light-mode-only"> <img src="https://render.githubusercontent.com/render/math?math=max\{0, (1-PM_{i}) \cdot (s^'/\sigma_{i}) \cdot (R_{i} - PP_{i})\}#gh-light-mode-only">
<img src="https://render.githubusercontent.com/render/math?math=\color{white}max\{0, (1-PM_{i}) \cdot (s^'/\sigma_{i}) \cdot (R_{i} - PP_{i})\}#gh-dark-mode-only"> <img src="https://render.githubusercontent.com/render/math?math=\color{white}max\{0, (1-PM_{i}) \cdot (s^'/\sigma_{i}) \cdot (R_{i} - PP_{i})\}#gh-dark-mode-only">
@@ -84,3 +80,4 @@ where `s'` is stake `s` scaled over total token circulating supply.
### Licensing and copyright information ### Licensing and copyright information
This program is available as open source under the terms of the Apache 2.0 license. However, some elements are being licensed under CC0-1.0 and MIT. For accurate information, please check individual files. This program is available as open source under the terms of the Apache 2.0 license. However, some elements are being licensed under CC0-1.0 and MIT. For accurate information, please check individual files.
+3 -3
View File
@@ -3,8 +3,8 @@ Critical bug or security issue 💥
If you're here because you're trying to figure out how to notify us of a security issue, go to Discord, and alert the core engineers: If you're here because you're trying to figure out how to notify us of a security issue, go to Discord, and alert the core engineers:
Dave Hrycyszyn futurechimp#5430 Dave Hrycyszyn futurechimp#5430
Drazen Urch drazen#4873
Jedrzej Stuczynski "Jedrzej | Nym#5666" Jedrzej Stuczynski "Jedrzej | Nym#5666"
Fran Arbanas | franarbanas#0995
Mark Sinclair | marknym#8088
Please avoid opening public issues on GitHub that contain information about a potential security vulnerability as this makes it difficult to reduce the impact and harm of valid security issues.
Please avoid opening public issues on GitHub that contain information about a potential security vulnerability as this makes it difficult to reduce the impact and harm of valid security issues.
-53
View File
@@ -1,53 +0,0 @@
<svg
width="100%"
height="100%"
viewBox="0 0 80 80"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<g clip-path="url(#clip0_421_13045)">
<path
d="M40 80C62.0914 80 80 62.0914 80 40C80 17.9086 62.0914 0 40 0C17.9086 0 0 17.9086 0 40C0 62.0914 17.9086 80 40 80Z"
fill="black"
/>
<path
d="M40 77.2636C60.5801 77.2636 77.2636 60.5801 77.2636 40C77.2636 19.4199 60.5801 2.73645 40 2.73645C19.4199 2.73645 2.73645 19.4199 2.73645 40C2.73645 60.5801 19.4199 77.2636 40 77.2636Z"
fill="white"
/>
<path
d="M24.0224 32.471H23.9776V32.5084V45.5775L18.4673 32.4934L18.4598 32.471H18.4299H15.3047H11.7981H11.7607V32.5084V47.4916V47.529H11.7981H15.3047H15.3421V47.4916V34.4L20.8748 47.5065L20.8822 47.529H20.9121H24.0224H27.5215H27.5589V47.4916V32.5084V32.471H27.5215H24.0224Z"
fill="black"
/>
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M23.8965 32.39H27.64V47.6101H20.8238L20.7989 47.5352L15.4232 34.8006V47.6101H11.6797V32.39H18.5183L18.5432 32.4649L23.8965 45.1761V32.39ZM23.9776 45.5776L18.4673 32.4935L18.4598 32.471H11.7608V47.529H15.3421V34.4L20.8748 47.5065L20.8823 47.529H27.5589V32.471H23.9776V45.5776Z"
fill="black"
/>
<path
d="M68.2019 32.471H61.5178H61.4804L61.4729 32.5009L58.0486 45.6374L54.6169 32.5009L54.6094 32.471H54.5795H47.8804H47.8355V32.5084V47.4916V47.529H47.8804H51.3795H51.4169V47.4916V34.5047L54.8038 47.499L54.8112 47.529H54.8486H61.2337H61.2636L61.2711 47.499L64.658 34.5047V47.4916V47.529H64.6954H68.2019H68.2393V47.4916V32.5084V32.471H68.2019Z"
fill="black"
/>
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M61.4171 32.39H68.3204V47.6101H64.5769V35.1372L61.3497 47.5187L61.3495 47.5195L61.3269 47.6101H54.7479L54.7253 47.5195L54.7251 47.5187L51.4979 35.1372V47.6101H47.7545V32.39H54.6727L54.6953 32.4804L54.6955 32.4813L58.0485 45.3163L61.3943 32.4813L61.3945 32.4805L61.4171 32.39ZM58.0486 45.6374L54.6168 32.5009L54.6094 32.471H47.8355V47.529H51.4168V34.5047L54.8038 47.4991L54.8112 47.529H61.2636L61.2711 47.4991L64.658 34.5047V47.529H68.2393V32.471H61.4804L61.4729 32.5009L58.0486 45.6374Z"
fill="black"
/>
<path
d="M42.0711 32.471H42.0486L42.0412 32.486L37.7869 39.8804L33.5103 32.486L33.5028 32.471H33.4804H29.4355H29.3608L29.3982 32.5308L35.9851 43.9402V47.4916V47.529H36.0225H39.529H39.5664V47.4916V43.9402L46.1533 32.5308L46.1907 32.471H46.1159H42.0711Z"
fill="black"
/>
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M41.9985 32.39H46.337L46.2228 32.5726L39.6475 43.9619V47.6101H35.904V43.9619L29.3286 32.5726L29.2145 32.39H33.5529L33.5817 32.4475L37.7868 39.7181L41.9697 32.4476L41.9985 32.39ZM42.0411 32.486L37.7869 39.8804L33.5103 32.486L33.5028 32.471H29.3608L29.3981 32.5308L35.9851 43.9402V47.529H39.5664V43.9402L46.1533 32.5308L46.1907 32.471H42.0486L42.0411 32.486Z"
fill="black"
/>
</g>
<defs>
<clipPath id="clip0_421_13045">
<rect width="80" height="80" fill="white" />
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 3.0 KiB

@@ -1,6 +1,6 @@
[package] [package]
name = "nym-client-core" name = "client-core"
version = "1.1.15" version = "1.1.13"
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"
@@ -9,42 +9,36 @@ rust-version = "1.66"
[dependencies] [dependencies]
async-trait = { workspace = true } async-trait = { workspace = true }
base64 = "0.21.2"
dirs = "4.0" dirs = "4.0"
dashmap = "5.4.0" dashmap = "5.4.0"
futures = "0.3" futures = "0.3"
humantime-serde = "1.0" humantime-serde = "1.0"
log = { workspace = true } log = { workspace = true }
rand = { version = "0.7.3", features = ["wasm-bindgen"] } rand = { version = "0.7.3", features = ["wasm-bindgen"] }
serde = { workspace = true, features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
serde_json = { workspace = true } serde_json = "1.0.89"
sha2 = "0.10.6"
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 } 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"
zeroize = { workspace = true }
# internal # internal
nym-bandwidth-controller = { path = "../bandwidth-controller" } nym-config = { path = "../../common/config" }
nym-config = { path = "../config" } nym-crypto = { path = "../../common/crypto" }
nym-crypto = { path = "../crypto" } gateway-client = { path = "../../common/client-libs/gateway-client" }
nym-gateway-client = { path = "../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"] }
nym-gateway-requests = { path = "../../gateway/gateway-requests" } gateway-requests = { path = "../../gateway/gateway-requests" }
nym-nonexhaustive-delayqueue = { path = "../nonexhaustive-delayqueue" } nym-nonexhaustive-delayqueue = { path = "../../common/nonexhaustive-delayqueue" }
nym-sphinx = { path = "../nymsphinx" } nym-sphinx = { path = "../../common/nymsphinx" }
nym-pemstore = { path = "../pemstore" } nym-pemstore = { path = "../../common/pemstore" }
nym-topology = { path = "../topology" } nym-topology = { path = "../../common/topology" }
nym-validator-client = { path = "../client-libs/validator-client", default-features = false } validator-client = { path = "../../common/client-libs/validator-client", default-features = false }
nym-task = { path = "../task" } nym-task = { path = "../../common/task" }
nym-credential-storage = { path = "../credential-storage" }
nym-network-defaults = { path = "../network-defaults" }
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.nym-validator-client] [target."cfg(not(target_arch = \"wasm32\"))".dependencies.validator-client]
path = "../client-libs/validator-client" path = "../../common/client-libs/validator-client"
features = ["nyxd-client"] features = ["nyxd-client"]
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.tokio-stream] [target."cfg(not(target_arch = \"wasm32\"))".dependencies.tokio-stream]
@@ -78,7 +72,7 @@ version = "0.2.4"
features = ["futures"] features = ["futures"]
[target."cfg(target_arch = \"wasm32\")".dependencies.wasm-utils] [target."cfg(target_arch = \"wasm32\")".dependencies.wasm-utils]
path = "../wasm-utils" path = "../../common/wasm-utils"
features = ["websocket"] features = ["websocket"]
[target."cfg(target_arch = \"wasm32\")".dependencies.time] [target."cfg(target_arch = \"wasm32\")".dependencies.time]
@@ -95,5 +89,5 @@ sqlx = { version = "0.6.2", features = ["runtime-tokio-rustls", "sqlite", "macro
[features] [features]
default = [] default = []
fs-surb-storage = ["sqlx"] fs-surb-storage = ["sqlx"]
wasm = ["nym-gateway-client/wasm"] wasm = ["gateway-client/wasm"]
@@ -1,15 +1,11 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net> // Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
//
use crate::{client::replies::reply_storage, config::DebugConfig}; use crate::{client::replies::reply_storage, config::DebugConfig};
pub fn setup_empty_reply_surb_backend(debug_config: &DebugConfig) -> reply_storage::Empty { pub fn setup_empty_reply_surb_backend(debug_config: &DebugConfig) -> reply_storage::Empty {
reply_storage::Empty { reply_storage::Empty {
min_surb_threshold: debug_config min_surb_threshold: debug_config.minimum_reply_surb_storage_threshold,
.reply_surbs max_surb_threshold: debug_config.maximum_reply_surb_storage_threshold,
.minimum_reply_surb_storage_threshold,
max_surb_threshold: debug_config
.reply_surbs
.maximum_reply_surb_storage_threshold,
} }
} }
@@ -1,12 +1,9 @@
// Copyright 2022-2023 - 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 super::received_buffer::ReceivedBufferMessage;
use crate::client::base_client::storage::MixnetClientStorage;
use crate::client::cover_traffic_stream::LoopCoverTrafficStream; use crate::client::cover_traffic_stream::LoopCoverTrafficStream;
use crate::client::inbound_messages::{InputMessage, InputMessageReceiver, InputMessageSender}; use crate::client::inbound_messages::{InputMessage, InputMessageReceiver, InputMessageSender};
use crate::client::key_manager::persistence::KeyStore; use crate::client::key_manager::KeyManager;
use crate::client::key_manager::ManagedKeys;
use crate::client::mix_traffic::{BatchMixMessageSender, MixTrafficController}; use crate::client::mix_traffic::{BatchMixMessageSender, MixTrafficController};
use crate::client::real_messages_control; use crate::client::real_messages_control;
use crate::client::real_messages_control::RealMessagesController; use crate::client::real_messages_control::RealMessagesController;
@@ -24,41 +21,38 @@ use crate::client::topology_control::{
}; };
use crate::config::{Config, DebugConfig, GatewayEndpointConfig}; use crate::config::{Config, DebugConfig, GatewayEndpointConfig};
use crate::error::ClientCoreError; use crate::error::ClientCoreError;
use crate::{config, spawn_future}; use crate::spawn_future;
use futures::channel::mpsc; use futures::channel::mpsc;
use log::{debug, info}; use gateway_client::bandwidth::BandwidthController;
use nym_bandwidth_controller::BandwidthController; #[cfg(target_arch = "wasm32")]
use nym_credential_storage::storage::Storage as CredentialStorage; use gateway_client::wasm_mockups::CosmWasmClient;
use nym_crypto::asymmetric::{encryption, identity}; use gateway_client::{
use nym_gateway_client::{
AcknowledgementReceiver, AcknowledgementSender, GatewayClient, MixnetMessageReceiver, AcknowledgementReceiver, AcknowledgementSender, GatewayClient, MixnetMessageReceiver,
MixnetMessageSender, MixnetMessageSender,
}; };
use log::{debug, info};
use nym_crypto::asymmetric::{encryption, identity};
use nym_sphinx::acknowledgements::AckKey; use nym_sphinx::acknowledgements::AckKey;
use nym_sphinx::addressing::clients::Recipient; use nym_sphinx::addressing::clients::Recipient;
use nym_sphinx::addressing::nodes::NodeIdentity; use nym_sphinx::addressing::nodes::NodeIdentity;
use nym_sphinx::params::PacketType; use nym_sphinx::receiver::ReconstructedMessage;
use nym_sphinx::receiver::{ReconstructedMessage, SphinxMessageReceiver};
use nym_task::connections::{ConnectionCommandReceiver, ConnectionCommandSender, LaneQueueLengths}; use nym_task::connections::{ConnectionCommandReceiver, ConnectionCommandSender, LaneQueueLengths};
use nym_task::{TaskClient, TaskManager}; use nym_task::{TaskClient, TaskManager};
use nym_topology::provider_trait::TopologyProvider; use nym_topology::provider_trait::TopologyProvider;
use std::sync::Arc; use std::sync::Arc;
use std::time::Duration;
use tap::TapFallible; use tap::TapFallible;
use url::Url; use url::Url;
#[cfg(target_arch = "wasm32")]
use nym_bandwidth_controller::wasm_mockups::DkgQueryClient;
use crate::client::base_client::storage::gateway_details::GatewayDetailsStore;
use crate::init::{setup_gateway, GatewaySetup, InitialisationDetails};
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
use nym_validator_client::nyxd::traits::DkgQueryClient; use validator_client::nyxd::CosmWasmClient;
use super::received_buffer::ReceivedBufferMessage;
#[cfg(all(not(target_arch = "wasm32"), feature = "fs-surb-storage"))] #[cfg(all(not(target_arch = "wasm32"), feature = "fs-surb-storage"))]
pub mod non_wasm_helpers; pub mod non_wasm_helpers;
pub mod helpers; pub mod helpers;
pub mod storage;
#[derive(Clone)] #[derive(Clone)]
pub struct ClientInput { pub struct ClientInput {
@@ -96,7 +90,6 @@ impl ClientOutput {
} }
} }
#[derive(Clone, Debug)]
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,
@@ -157,58 +150,75 @@ impl From<bool> for CredentialsToggle {
} }
} }
pub struct BaseClientBuilder<'a, C, S: MixnetClientStorage> { pub struct BaseClientBuilder<'a, B, C: Clone> {
config: &'a Config, // due to wasm limitations I had to split it like this : (
client_store: S, gateway_config: &'a GatewayEndpointConfig,
dkg_query_client: Option<C>, debug_config: &'a DebugConfig,
custom_topology_provider: Option<Box<dyn TopologyProvider + Send + Sync>>, disabled_credentials: bool,
setup_method: GatewaySetup, nym_api_endpoints: Vec<Url>,
reply_storage_backend: B,
custom_topology_provider: Option<Box<dyn TopologyProvider>>,
bandwidth_controller: Option<BandwidthController<C>>,
key_manager: KeyManager,
} }
impl<'a, C, S> BaseClientBuilder<'a, C, S> impl<'a, B, C> BaseClientBuilder<'a, B, C>
where where
S: MixnetClientStorage + 'static, B: ReplyStorageBackend + Send + Sync + 'static,
C: DkgQueryClient + Send + Sync + 'static, C: CosmWasmClient + Sync + Send + Clone + 'static,
{ {
pub fn new( pub fn new_from_base_config<T>(
base_config: &'a Config, base_config: &'a Config<T>,
client_store: S, key_manager: KeyManager,
dkg_query_client: Option<C>, bandwidth_controller: Option<BandwidthController<C>>,
) -> BaseClientBuilder<'a, C, S> { reply_storage_backend: B,
) -> BaseClientBuilder<'a, B, C> {
BaseClientBuilder { BaseClientBuilder {
config: base_config, gateway_config: base_config.get_gateway_endpoint_config(),
client_store, debug_config: base_config.get_debug_config(),
dkg_query_client, disabled_credentials: base_config.get_disabled_credentials_mode(),
nym_api_endpoints: base_config.get_nym_api_endpoints(),
bandwidth_controller,
reply_storage_backend,
key_manager,
custom_topology_provider: None, custom_topology_provider: None,
setup_method: GatewaySetup::MustLoad,
} }
} }
pub fn with_gateway_setup(mut self, setup: GatewaySetup) -> Self { pub fn new(
self.setup_method = setup; gateway_config: &'a GatewayEndpointConfig,
self debug_config: &'a DebugConfig,
key_manager: KeyManager,
bandwidth_controller: Option<BandwidthController<C>>,
reply_storage_backend: B,
credentials_toggle: CredentialsToggle,
nym_api_endpoints: Vec<Url>,
) -> BaseClientBuilder<'a, B, C> {
BaseClientBuilder {
gateway_config,
debug_config,
disabled_credentials: credentials_toggle.is_disabled(),
nym_api_endpoints,
reply_storage_backend,
custom_topology_provider: None,
bandwidth_controller,
key_manager,
}
} }
pub fn with_topology_provider( pub fn with_topology_provider(mut self, provider: Box<dyn TopologyProvider>) -> Self {
mut self,
provider: Box<dyn TopologyProvider + Send + Sync>,
) -> Self {
self.custom_topology_provider = Some(provider); self.custom_topology_provider = Some(provider);
self self
} }
// note: do **NOT** make this method public as its only valid usage is from within `start_base` pub fn as_mix_recipient(&self) -> Recipient {
// because it relies on the crypto keys being already loaded
fn mix_address(
managed_keys: &ManagedKeys,
gateway_config: &GatewayEndpointConfig,
) -> Recipient {
Recipient::new( Recipient::new(
*managed_keys.identity_public_key(), *self.key_manager.identity_keypair().public_key(),
*managed_keys.encryption_public_key(), *self.key_manager.encryption_keypair().public_key(),
// TODO: below only works under assumption that gateway address == gateway id // TODO: below only works under assumption that gateway address == gateway id
// (which currently is true) // (which currently is true)
NodeIdentity::from_base58_string(&gateway_config.gateway_id).unwrap(), NodeIdentity::from_base58_string(&self.gateway_config.gateway_id).unwrap(),
) )
} }
@@ -224,16 +234,21 @@ where
) { ) {
info!("Starting loop cover traffic stream..."); info!("Starting loop cover traffic stream...");
let stream = LoopCoverTrafficStream::new( let mut stream = LoopCoverTrafficStream::new(
ack_key, ack_key,
debug_config.acknowledgements.average_ack_delay, debug_config.average_ack_delay,
debug_config.average_packet_delay,
debug_config.loop_cover_traffic_average_delay,
mix_tx, mix_tx,
self_address, self_address,
topology_accessor, topology_accessor,
debug_config.traffic,
debug_config.cover_traffic,
); );
if let Some(size) = debug_config.use_extended_packet_size {
log::debug!("Setting extended packet size: {:?}", size);
stream.set_custom_packet_size(size.into());
}
stream.start_with_shutdown(shutdown); stream.start_with_shutdown(shutdown);
} }
@@ -250,7 +265,6 @@ where
lane_queue_lengths: LaneQueueLengths, lane_queue_lengths: LaneQueueLengths,
client_connection_rx: ConnectionCommandReceiver, client_connection_rx: ConnectionCommandReceiver,
shutdown: TaskClient, shutdown: TaskClient,
packet_type: PacketType,
) { ) {
info!("Starting real traffic stream..."); info!("Starting real traffic stream...");
@@ -266,7 +280,7 @@ where
lane_queue_lengths, lane_queue_lengths,
client_connection_rx, client_connection_rx,
) )
.start_with_shutdown(shutdown, packet_type); .start_with_shutdown(shutdown);
} }
// buffer controlling all messages fetched from provider // buffer controlling all messages fetched from provider
@@ -280,67 +294,69 @@ where
shutdown: TaskClient, shutdown: TaskClient,
) { ) {
info!("Starting received messages buffer controller..."); info!("Starting received messages buffer controller...");
let controller: ReceivedMessagesBufferController<SphinxMessageReceiver> = ReceivedMessagesBufferController::new(
ReceivedMessagesBufferController::new( local_encryption_keypair,
local_encryption_keypair, query_receiver,
query_receiver, mixnet_receiver,
mixnet_receiver, reply_key_storage,
reply_key_storage, reply_controller_sender,
reply_controller_sender, )
); .start_with_shutdown(shutdown)
controller.start_with_shutdown(shutdown)
} }
async fn start_gateway_client( async fn start_gateway_client(
config: &Config, &mut self,
gateway_config: GatewayEndpointConfig,
managed_keys: &ManagedKeys,
bandwidth_controller: Option<BandwidthController<C, S::CredentialStore>>,
mixnet_message_sender: MixnetMessageSender, mixnet_message_sender: MixnetMessageSender,
ack_sender: AcknowledgementSender, ack_sender: AcknowledgementSender,
shutdown: TaskClient, shutdown: TaskClient,
) -> Result<GatewayClient<C, S::CredentialStore>, ClientCoreError> ) -> Result<GatewayClient<C>, ClientCoreError> {
where let gateway_id = self.gateway_config.gateway_id.clone();
<S::KeyStore as KeyStore>::StorageError: Send + Sync + 'static, if gateway_id.is_empty() {
<S::CredentialStore as CredentialStorage>::StorageError: Send + Sync + 'static, return Err(ClientCoreError::GatewayIdUnknown);
{ }
let gateway_address = gateway_config.gateway_listener.clone(); let gateway_address = self.gateway_config.gateway_listener.clone();
let gateway_id = gateway_config.gateway_id; if gateway_address.is_empty() {
return Err(ClientCoreError::GatewayAddressUnknown);
}
// TODO: in theory, at this point, this should be infallible
let gateway_identity = identity::PublicKey::from_base58_string(gateway_id) let gateway_identity = identity::PublicKey::from_base58_string(gateway_id)
.map_err(ClientCoreError::UnableToCreatePublicKeyFromGatewayId)?; .map_err(ClientCoreError::UnableToCreatePublicKeyFromGatewayId)?;
// disgusting wasm workaround since there's no key persistence there (nor `client init`)
let shared_key = if self.key_manager.is_gateway_key_set() {
Some(self.key_manager.gateway_shared_key())
} else {
log::info!("Gateway key not set! Will proceed anyway.");
None
};
let mut gateway_client = GatewayClient::new( let mut gateway_client = GatewayClient::new(
gateway_address, gateway_address,
managed_keys.identity_keypair(), self.key_manager.identity_keypair(),
gateway_identity, gateway_identity,
Some(managed_keys.must_get_gateway_shared_key()), shared_key,
mixnet_message_sender, mixnet_message_sender,
ack_sender, ack_sender,
config.debug.gateway_connection.gateway_response_timeout, self.debug_config.gateway_response_timeout,
bandwidth_controller, self.bandwidth_controller.take(),
shutdown, shutdown,
); );
gateway_client.set_disabled_credentials_mode(config.client.disabled_credentials_mode); gateway_client.set_disabled_credentials_mode(self.disabled_credentials);
let shared_key = gateway_client gateway_client
.authenticate_and_start() .authenticate_and_start()
.await .await
.tap_err(|err| { .tap_err(|err| {
log::error!("Could not authenticate and start up the gateway connection - {err}") log::error!("Could not authenticate and start up the gateway connection - {err}")
})?; })?;
managed_keys.ensure_gateway_key(shared_key);
Ok(gateway_client) Ok(gateway_client)
} }
fn setup_topology_provider( fn setup_topology_provider(
custom_provider: Option<Box<dyn TopologyProvider + Send + Sync>>, custom_provider: Option<Box<dyn TopologyProvider>>,
nym_api_urls: Vec<Url>, nym_api_urls: Vec<Url>,
) -> Box<dyn TopologyProvider + Send + Sync> { ) -> Box<dyn TopologyProvider> {
// if no custom provider was ... provided ..., create one using nym-api // if no custom provider was ... provided ..., create one using nym-api
custom_provider.unwrap_or_else(|| { custom_provider.unwrap_or_else(|| {
Box::new(NymApiTopologyProvider::new( Box::new(NymApiTopologyProvider::new(
@@ -353,13 +369,12 @@ where
// 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(
topology_provider: Box<dyn TopologyProvider + Send + Sync>, topology_provider: Box<dyn TopologyProvider>,
topology_config: config::Topology, refresh_rate: Duration,
topology_accessor: TopologyAccessor, topology_accessor: TopologyAccessor,
mut shutdown: TaskClient, shutdown: TaskClient,
) -> Result<(), ClientCoreError> { ) -> Result<(), ClientCoreError> {
let topology_refresher_config = let topology_refresher_config = TopologyRefresherConfig::new(refresh_rate);
TopologyRefresherConfig::new(topology_config.topology_refresh_rate);
let mut topology_refresher = TopologyRefresher::new( let mut topology_refresher = TopologyRefresher::new(
topology_refresher_config, topology_refresher_config,
@@ -379,101 +394,65 @@ where
return Err(ClientCoreError::InsufficientNetworkTopology(err)); return Err(ClientCoreError::InsufficientNetworkTopology(err));
} }
if topology_config.disable_refreshing { info!("Starting topology refresher...");
// if we're not spawning the refresher, don't cause shutdown immediately topology_refresher.start_with_shutdown(shutdown);
info!("The topology refesher is not going to be started");
shutdown.mark_as_success();
} else {
// don't spawn the refresher if we don't want to be refreshing the topology.
// only use the initial values obtained
info!("Starting topology refresher...");
topology_refresher.start_with_shutdown(shutdown);
}
Ok(()) Ok(())
} }
// controller for sending packets to mixnet (either real traffic or cover traffic) // controller for sending sphinx packets to mixnet (either real traffic or cover traffic)
// TODO: if we want to send control messages to gateway_client, this CAN'T take the ownership // TODO: if we want to send control messages to gateway_client, this CAN'T take the ownership
// over it. Perhaps GatewayClient needs to be thread-shareable or have some channel for // over it. Perhaps GatewayClient needs to be thread-shareable or have some channel for
// requests? // requests?
fn start_mix_traffic_controller( fn start_mix_traffic_controller(
gateway_client: GatewayClient<C, S::CredentialStore>, gateway_client: GatewayClient<C>,
shutdown: TaskClient, shutdown: TaskClient,
) -> BatchMixMessageSender ) -> BatchMixMessageSender {
where
<S::CredentialStore as CredentialStorage>::StorageError: Send + Sync + 'static,
{
info!("Starting mix traffic controller..."); info!("Starting mix traffic controller...");
let (mix_traffic_controller, mix_tx) = MixTrafficController::new(gateway_client); let (mix_traffic_controller, mix_tx) = MixTrafficController::new(gateway_client);
mix_traffic_controller.start_with_shutdown(shutdown); mix_traffic_controller.start_with_shutdown(shutdown);
mix_tx mix_tx
} }
// TODO: rename it as it implies the data is persistent whilst one can use InMemBackend
async fn setup_persistent_reply_storage( async fn setup_persistent_reply_storage(
backend: S::ReplyStore, backend: B,
shutdown: TaskClient, shutdown: TaskClient,
) -> Result<CombinedReplyStorage, ClientCoreError> ) -> Result<CombinedReplyStorage, ClientCoreError>
where where
<S::ReplyStore as ReplyStorageBackend>::StorageError: Sync + Send, <B as ReplyStorageBackend>::StorageError: Sync + Send,
S::ReplyStore: Send + Sync,
{ {
log::trace!("Setup persistent reply storage"); if backend.is_active() {
let persistent_storage = PersistentReplyStorage::new(backend); log::trace!("Setup persistent reply storage");
let mem_store = persistent_storage let persistent_storage = PersistentReplyStorage::new(backend);
.load_state_from_backend() let mem_store = persistent_storage
.await .load_state_from_backend()
.map_err(|err| ClientCoreError::SurbStorageError {
source: Box::new(err),
})?;
let store_clone = mem_store.clone();
spawn_future(async move {
persistent_storage
.flush_on_shutdown(store_clone, shutdown)
.await .await
}); .map_err(|err| ClientCoreError::SurbStorageError {
source: Box::new(err),
})?;
Ok(mem_store) let store_clone = mem_store.clone();
} spawn_future(async move {
persistent_storage
.flush_on_shutdown(store_clone, shutdown)
.await
});
async fn initialise_keys_and_gateway(&self) -> Result<InitialisationDetails, ClientCoreError> Ok(mem_store)
where } else {
<S::KeyStore as KeyStore>::StorageError: Sync + Send, log::trace!("Setup inactive reply storage");
<S::GatewayDetailsStore as GatewayDetailsStore>::StorageError: Sync + Send, Ok(backend
{ .get_inactive_storage()
setup_gateway( .map_err(|err| ClientCoreError::SurbStorageError {
&self.setup_method, source: Box::new(err),
self.client_store.key_store(), })?)
self.client_store.gateway_details_store(), }
false,
Some(&self.config.client.nym_api_urls),
)
.await
} }
pub async fn start_base(mut self) -> Result<BaseClient, ClientCoreError> pub async fn start_base(mut self) -> Result<BaseClient, ClientCoreError>
where where
S::ReplyStore: Send + Sync, <B as ReplyStorageBackend>::StorageError: Sync + Send,
<S::KeyStore as KeyStore>::StorageError: Send + Sync,
<S::ReplyStore as ReplyStorageBackend>::StorageError: Sync + Send,
<S::CredentialStore as CredentialStorage>::StorageError: Send + Sync + 'static,
<S::GatewayDetailsStore as GatewayDetailsStore>::StorageError: Sync + Send,
{ {
info!("Starting nym client"); info!("Starting nym client");
// derive (or load) client keys and gateway configuration
let details = self.initialise_keys_and_gateway().await?;
let gateway_config = details.gateway_details;
let managed_keys = details.managed_keys;
let (reply_storage_backend, credential_store) = self.client_store.into_runtime_stores();
let bandwidth_controller = self
.dkg_query_client
.map(|client| BandwidthController::new(credential_store, client));
// channels for inter-component communication // channels for inter-component communication
// TODO: make the channels be internally created by the relevant components // TODO: make the channels be internally created by the relevant components
// rather than creating them here, so say for example the buffer controller would create the request channels // rather than creating them here, so say for example the buffer controller would create the request channels
@@ -500,39 +479,34 @@ where
let (reply_controller_sender, reply_controller_receiver) = let (reply_controller_sender, reply_controller_receiver) =
reply_controller::requests::new_control_channels(); reply_controller::requests::new_control_channels();
let self_address = Self::mix_address(&managed_keys, &gateway_config); let self_address = self.as_mix_recipient();
// the components are started in very specific order. Unless you know what you are doing, // the components are started in very specific order. Unless you know what you are doing,
// do not change that. // do not change that.
let gateway_client = Self::start_gateway_client( let gateway_client = self
self.config, .start_gateway_client(mixnet_messages_sender, ack_sender, task_manager.subscribe())
gateway_config, .await?;
&managed_keys,
bandwidth_controller, let reply_storage = Self::setup_persistent_reply_storage(
mixnet_messages_sender, self.reply_storage_backend,
ack_sender,
task_manager.subscribe(), task_manager.subscribe(),
) )
.await?; .await?;
let reply_storage =
Self::setup_persistent_reply_storage(reply_storage_backend, task_manager.subscribe())
.await?;
let topology_provider = Self::setup_topology_provider( let topology_provider = Self::setup_topology_provider(
self.custom_topology_provider.take(), self.custom_topology_provider.take(),
self.config.get_nym_api_endpoints(), self.nym_api_endpoints,
); );
Self::start_topology_refresher( Self::start_topology_refresher(
topology_provider, topology_provider,
self.config.debug.topology, self.debug_config.topology_refresh_rate,
shared_topology_accessor.clone(), shared_topology_accessor.clone(),
task_manager.subscribe(), task_manager.subscribe(),
) )
.await?; .await?;
Self::start_received_messages_buffer_controller( Self::start_received_messages_buffer_controller(
managed_keys.encryption_keypair(), self.key_manager.encryption_keypair(),
received_buffer_request_receiver, received_buffer_request_receiver,
mixnet_messages_receiver, mixnet_messages_receiver,
reply_storage.key_storage(), reply_storage.key_storage(),
@@ -540,11 +514,11 @@ where
task_manager.subscribe(), task_manager.subscribe(),
); );
// The message_sender is the transmitter for any component generating sphinx packets // The sphinx_message_sender is the transmitter for any component generating sphinx packets
// that are to be sent to the mixnet. They are used by cover traffic stream and real // that are to be sent to the mixnet. They are used by cover traffic stream and real
// traffic stream. // traffic stream.
// The MixTrafficController then sends the actual traffic // The MixTrafficController then sends the actual traffic
let message_sender = let sphinx_message_sender =
Self::start_mix_traffic_controller(gateway_client, task_manager.subscribe()); Self::start_mix_traffic_controller(gateway_client, task_manager.subscribe());
// Channels that the websocket listener can use to signal downstream to the real traffic // Channels that the websocket listener can use to signal downstream to the real traffic
@@ -555,39 +529,38 @@ where
// primarily to throttle incoming connections (e.g socks5 for attached network-requesters) // primarily to throttle incoming connections (e.g socks5 for attached network-requesters)
let shared_lane_queue_lengths = LaneQueueLengths::new(); let shared_lane_queue_lengths = LaneQueueLengths::new();
let controller_config = real_messages_control::Config::new( let mut controller_config = real_messages_control::Config::new(
&self.config.debug, self.debug_config,
managed_keys.ack_key(), self.key_manager.ack_key(),
self_address, self_address,
); );
if let Some(size) = self.debug_config.use_extended_packet_size {
log::debug!("Setting extended packet size: {:?}", size);
controller_config.set_custom_packet_size(size.into());
}
Self::start_real_traffic_controller( Self::start_real_traffic_controller(
controller_config, controller_config,
shared_topology_accessor.clone(), shared_topology_accessor.clone(),
ack_receiver, ack_receiver,
input_receiver, input_receiver,
message_sender.clone(), sphinx_message_sender.clone(),
reply_storage, reply_storage,
reply_controller_sender.clone(), reply_controller_sender.clone(),
reply_controller_receiver, reply_controller_receiver,
shared_lane_queue_lengths.clone(), shared_lane_queue_lengths.clone(),
client_connection_rx, client_connection_rx,
task_manager.subscribe(), task_manager.subscribe(),
self.config.debug.traffic.packet_type,
); );
if !self if !self.debug_config.disable_loop_cover_traffic_stream {
.config
.debug
.cover_traffic
.disable_loop_cover_traffic_stream
{
Self::start_cover_traffic_stream( Self::start_cover_traffic_stream(
&self.config.debug, self.debug_config,
managed_keys.ack_key(), self.key_manager.ack_key(),
self_address, self_address,
shared_topology_accessor.clone(), shared_topology_accessor.clone(),
message_sender, sphinx_message_sender,
task_manager.subscribe(), task_manager.subscribe(),
); );
} }
@@ -596,7 +569,6 @@ where
debug!("The address of this client is: {self_address}"); debug!("The address of this client is: {self_address}");
Ok(BaseClient { Ok(BaseClient {
address: self_address,
client_input: ClientInputStatus::AwaitingProducer { client_input: ClientInputStatus::AwaitingProducer {
client_input: ClientInput { client_input: ClientInput {
connection_command_sender: client_connection_tx, connection_command_sender: client_connection_tx,
@@ -619,7 +591,6 @@ where
} }
pub struct BaseClient { pub struct BaseClient {
pub address: Recipient,
pub client_input: ClientInputStatus, pub client_input: ClientInputStatus,
pub client_output: ClientOutputStatus, pub client_output: ClientOutputStatus,
pub client_state: ClientState, pub client_state: ClientState,
@@ -0,0 +1,100 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::client::replies::reply_storage::{
fs_backend, CombinedReplyStorage, ReplyStorageBackend,
};
use crate::config::DebugConfig;
use crate::error::ClientCoreError;
use log::{error, info};
use std::path::Path;
use std::{fs, io};
use time::OffsetDateTime;
async fn setup_fresh_backend<P: AsRef<Path>>(
db_path: P,
debug_config: &DebugConfig,
) -> Result<fs_backend::Backend, ClientCoreError> {
info!("creating fresh surb database");
let mut storage_backend = match fs_backend::Backend::init(db_path).await {
Ok(backend) => backend,
Err(err) => {
error!("failed to setup persistent storage backend for our reply needs: {err}");
return Err(ClientCoreError::SurbStorageError {
source: Box::new(err),
});
}
};
// while I kinda hate that we're going to be creating `CombinedReplyStorage` twice,
// it will only be happening on the very first run and in practice won't incur huge
// costs since the storage is going to be empty
let mem_store = CombinedReplyStorage::new(
debug_config.minimum_reply_surb_storage_threshold,
debug_config.maximum_reply_surb_storage_threshold,
);
storage_backend
.init_fresh(&mem_store)
.await
.map_err(|err| ClientCoreError::SurbStorageError {
source: Box::new(err),
})?;
Ok(storage_backend)
}
fn setup_inactive_backend(debug_config: &DebugConfig) -> fs_backend::Backend {
info!("creating inactive surb database");
fs_backend::Backend::new_inactive(
debug_config.minimum_reply_surb_storage_threshold,
debug_config.maximum_reply_surb_storage_threshold,
)
}
fn archive_corrupted_database<P: AsRef<Path>>(db_path: P) -> io::Result<()> {
let db_path = db_path.as_ref();
debug_assert!(db_path.exists());
let now = OffsetDateTime::now_utc().unix_timestamp();
let suffix = format!("_{now}.corrupted");
let new_extension =
if let Some(existing_extension) = db_path.extension().and_then(|ext| ext.to_str()) {
format!("{existing_extension}.{suffix}")
} else {
suffix
};
let mut renamed = db_path.to_owned();
renamed.set_extension(new_extension);
fs::rename(db_path, renamed)
}
pub async fn setup_fs_reply_surb_backend<P: AsRef<Path>>(
db_path: Option<P>,
debug_config: &DebugConfig,
) -> Result<fs_backend::Backend, ClientCoreError> {
if let Some(db_path) = db_path {
// if the database file doesnt exist, initialise fresh storage, otherwise attempt to load
// the existing one
let db_path = db_path.as_ref();
if db_path.exists() {
info!("loading existing surb database");
match fs_backend::Backend::try_load(db_path).await {
Ok(backend) => Ok(backend),
Err(err) => {
error!("failed to setup persistent storage backend for our reply needs: {err}. We're going to create a fresh database instead. This behaviour might change in the future");
archive_corrupted_database(db_path)?;
setup_fresh_backend(db_path, debug_config).await
}
}
} else {
setup_fresh_backend(db_path, debug_config).await
}
} else {
Ok(setup_inactive_backend(debug_config))
}
}
@@ -3,14 +3,14 @@
use crate::client::mix_traffic::BatchMixMessageSender; use crate::client::mix_traffic::BatchMixMessageSender;
use crate::client::topology_control::TopologyAccessor; use crate::client::topology_control::TopologyAccessor;
use crate::{config, spawn_future}; 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 nym_sphinx::acknowledgements::AckKey; use nym_sphinx::acknowledgements::AckKey;
use nym_sphinx::addressing::clients::Recipient; use nym_sphinx::addressing::clients::Recipient;
use nym_sphinx::cover::generate_loop_cover_packet; use nym_sphinx::cover::generate_loop_cover_packet;
use nym_sphinx::params::{PacketSize, PacketType}; use nym_sphinx::params::PacketSize;
use nym_sphinx::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;
@@ -34,8 +34,11 @@ where
/// Average delay an acknowledgement packet is going to get delay at a single mixnode. /// Average delay an acknowledgement packet is going to get delay at a single mixnode.
average_ack_delay: Duration, average_ack_delay: Duration,
/// Defines configuration options related to cover traffic. /// Average delay a data packet is going to get delay at a single mixnode.
cover_traffic: config::CoverTraffic, average_packet_delay: Duration,
/// Average delay between sending subsequent cover packets.
average_cover_message_sending_delay: Duration,
/// Internal state, determined by `average_message_sending_delay`, /// Internal state, determined by `average_message_sending_delay`,
/// used to keep track of when a next packet should be sent out. /// used to keep track of when a next packet should be sent out.
@@ -45,7 +48,7 @@ where
#[cfg(target_arch = "wasm32")] #[cfg(target_arch = "wasm32")]
next_delay: Pin<Box<wasm_timer::Delay>>, next_delay: Pin<Box<wasm_timer::Delay>>,
/// Channel used for sending prepared nym packets to `MixTrafficController` that sends them /// Channel used for sending prepared sphinx packets to `MixTrafficController` that sends them
/// out to the network without any further delays. /// out to the network without any further delays.
mix_tx: BatchMixMessageSender, mix_tx: BatchMixMessageSender,
@@ -58,13 +61,8 @@ where
/// Accessor to the common instance of network topology. /// Accessor to the common instance of network topology.
topology_access: TopologyAccessor, topology_access: TopologyAccessor,
/// Primary predefined packet size used for the loop cover messages. /// Predefined packet size used for the loop cover messages.
primary_packet_size: PacketSize, packet_size: PacketSize,
/// Optional secondary predefined packet size used for the loop cover messages.
secondary_packet_size: Option<PacketSize>,
packet_type: PacketType,
} }
impl<R> Stream for LoopCoverTrafficStream<R> impl<R> Stream for LoopCoverTrafficStream<R>
@@ -85,7 +83,7 @@ where
// we know it's time to send a message, so let's prepare delay for the next one // we know it's time to send a message, so let's prepare delay for the next one
// Get the `now` by looking at the current `delay` deadline // Get the `now` by looking at the current `delay` deadline
let avg_delay = self.cover_traffic.loop_cover_traffic_average_delay; let avg_delay = self.average_cover_message_sending_delay;
let next_poisson_delay = sample_poisson_duration(&mut self.rng, avg_delay); let next_poisson_delay = sample_poisson_duration(&mut self.rng, avg_delay);
// The next interval value is `next_poisson_delay` after the one that just // The next interval value is `next_poisson_delay` after the one that just
@@ -109,14 +107,15 @@ where
// obviously when we finally make shared rng that is on 'higher' level, this should become // obviously when we finally make shared rng that is on 'higher' level, this should become
// generic `R` // generic `R`
impl LoopCoverTrafficStream<OsRng> { impl LoopCoverTrafficStream<OsRng> {
#[allow(clippy::too_many_arguments)]
pub fn new( pub fn new(
ack_key: Arc<AckKey>, ack_key: Arc<AckKey>,
average_ack_delay: Duration, average_ack_delay: Duration,
average_packet_delay: Duration,
average_cover_message_sending_delay: Duration,
mix_tx: BatchMixMessageSender, mix_tx: BatchMixMessageSender,
our_full_destination: Recipient, our_full_destination: Recipient,
topology_access: TopologyAccessor, topology_access: TopologyAccessor,
traffic_config: config::Traffic,
cover_config: config::CoverTraffic,
) -> Self { ) -> Self {
let rng = OsRng; let rng = OsRng;
@@ -129,18 +128,21 @@ impl LoopCoverTrafficStream<OsRng> {
LoopCoverTrafficStream { LoopCoverTrafficStream {
ack_key, ack_key,
average_ack_delay, average_ack_delay,
cover_traffic: cover_config, average_packet_delay,
average_cover_message_sending_delay,
next_delay, next_delay,
mix_tx, mix_tx,
our_full_destination, our_full_destination,
rng, rng,
topology_access, topology_access,
primary_packet_size: traffic_config.primary_packet_size, packet_size: Default::default(),
secondary_packet_size: traffic_config.secondary_packet_size,
packet_type: traffic_config.packet_type,
} }
} }
pub fn set_custom_packet_size(&mut self, packet_size: PacketSize) {
self.packet_size = packet_size;
}
fn set_next_delay(&mut self, amount: Duration) { fn set_next_delay(&mut self, amount: Duration) {
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
let next_delay = Box::pin(time::sleep(amount)); let next_delay = Box::pin(time::sleep(amount));
@@ -151,28 +153,9 @@ impl LoopCoverTrafficStream<OsRng> {
self.next_delay = next_delay; self.next_delay = next_delay;
} }
fn loop_cover_message_size(&mut self) -> PacketSize {
let Some(secondary_packet_size) = self.secondary_packet_size else {
return self.primary_packet_size;
};
let use_primary = self
.rng
.gen_bool(self.cover_traffic.cover_traffic_primary_size_ratio);
if use_primary {
self.primary_packet_size
} else {
secondary_packet_size
}
}
async fn on_new_message(&mut self) { async fn on_new_message(&mut self) {
trace!("next cover message!"); trace!("next cover message!");
let cover_traffic_packet_size = self.loop_cover_message_size();
trace!("the next loop cover message will be put in a {cover_traffic_packet_size} packet");
// TODO for way down the line: in very rare cases (during topology update) we might have // TODO for way down the line: in very rare cases (during topology update) we might have
// to wait a really tiny bit before actually obtaining the permit hence messing with our // to wait a really tiny bit before actually obtaining the permit hence messing with our
// poisson delay, but is it really a problem? // poisson delay, but is it really a problem?
@@ -195,9 +178,8 @@ impl LoopCoverTrafficStream<OsRng> {
&self.ack_key, &self.ack_key,
&self.our_full_destination, &self.our_full_destination,
self.average_ack_delay, self.average_ack_delay,
self.cover_traffic.loop_cover_traffic_average_delay, self.average_packet_delay,
cover_traffic_packet_size, self.packet_size,
self.packet_type,
) )
.expect("Somehow failed to generate a loop cover message with a valid topology"); .expect("Somehow failed to generate a loop cover message with a valid topology");
@@ -207,6 +189,10 @@ impl LoopCoverTrafficStream<OsRng> {
// This isn't a problem, if the channel is full means we're already sending the // This isn't a problem, if the channel is full means we're already sending the
// max amount of messages downstream can handle. // max amount of messages downstream can handle.
log::debug!("Failed to send cover message - channel full"); log::debug!("Failed to send cover message - channel full");
// However it's still useful to alert the user that the gateway or the link to
// the gateway can't keep up. Either due to insufficient bandwidth on the
// client side, or that the gateway is overloaded.
log::warn!("Failed to send sphinx packet - gateway or connection to 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");
@@ -228,17 +214,9 @@ impl LoopCoverTrafficStream<OsRng> {
} }
pub fn start_with_shutdown(mut self, mut shutdown: nym_task::TaskClient) { pub fn start_with_shutdown(mut self, mut shutdown: nym_task::TaskClient) {
if self.cover_traffic.disable_loop_cover_traffic_stream {
// we should have never got here in the first place - the task should have never been created to begin with
// so panic and review the code that lead to this branch
panic!("attempted to start LoopCoverTrafficStream while config explicitly disabled it.")
}
// 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 = sample_poisson_duration( let sampled =
&mut self.rng, sample_poisson_duration(&mut self.rng, self.average_cover_message_sending_delay);
self.cover_traffic.loop_cover_traffic_average_delay,
);
self.set_next_delay(sampled); self.set_next_delay(sampled);
spawn_future(async move { spawn_future(async move {
@@ -1,10 +1,5 @@
// Copyright 2020-2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use nym_sphinx::addressing::clients::Recipient; use nym_sphinx::addressing::clients::Recipient;
use nym_sphinx::anonymous_replies::requests::AnonymousSenderTag; use nym_sphinx::anonymous_replies::requests::AnonymousSenderTag;
use nym_sphinx::forwarding::packet::MixPacket;
use nym_sphinx::params::PacketType;
use nym_task::connections::TransmissionLane; use nym_task::connections::TransmissionLane;
pub type InputMessageSender = tokio::sync::mpsc::Sender<InputMessage>; pub type InputMessageSender = tokio::sync::mpsc::Sender<InputMessage>;
@@ -12,14 +7,6 @@ pub type InputMessageReceiver = tokio::sync::mpsc::Receiver<InputMessage>;
#[derive(Debug)] #[derive(Debug)]
pub enum InputMessage { pub enum InputMessage {
/// Fire an already prepared mix packets into the network.
/// No guarantees are made about it. For example no retransmssion
/// will be attempted if it gets dropped.
Premade {
msgs: Vec<MixPacket>,
lane: TransmissionLane,
},
/// The simplest message variant where no additional information is attached. /// The simplest message variant where no additional information is attached.
/// You're simply sending your `data` to specified `recipient` without any tagging. /// You're simply sending your `data` to specified `recipient` without any tagging.
/// ///
@@ -54,49 +41,14 @@ pub enum InputMessage {
data: Vec<u8>, data: Vec<u8>,
lane: TransmissionLane, lane: TransmissionLane,
}, },
MessageWrapper {
message: Box<InputMessage>,
packet_type: PacketType,
},
} }
impl InputMessage { impl InputMessage {
pub fn new_premade( pub fn new_regular(recipient: Recipient, data: Vec<u8>, lane: TransmissionLane) -> Self {
msgs: Vec<MixPacket>, InputMessage::Regular {
lane: TransmissionLane,
packet_type: PacketType,
) -> Self {
let message = InputMessage::Premade { msgs, lane };
if packet_type == PacketType::Mix {
message
} else {
InputMessage::new_wrapper(message, packet_type)
}
}
pub fn new_wrapper(message: InputMessage, packet_type: PacketType) -> Self {
InputMessage::MessageWrapper {
message: Box::new(message),
packet_type,
}
}
pub fn new_regular(
recipient: Recipient,
data: Vec<u8>,
lane: TransmissionLane,
packet_type: Option<PacketType>,
) -> Self {
let message = InputMessage::Regular {
recipient, recipient,
data, data,
lane, lane,
};
if let Some(packet_type) = packet_type {
InputMessage::new_wrapper(message, packet_type)
} else {
message
} }
} }
@@ -105,18 +57,12 @@ impl InputMessage {
data: Vec<u8>, data: Vec<u8>,
reply_surbs: u32, reply_surbs: u32,
lane: TransmissionLane, lane: TransmissionLane,
packet_type: Option<PacketType>,
) -> Self { ) -> Self {
let message = InputMessage::Anonymous { InputMessage::Anonymous {
recipient, recipient,
data, data,
reply_surbs, reply_surbs,
lane, lane,
};
if let Some(packet_type) = packet_type {
InputMessage::new_wrapper(message, packet_type)
} else {
message
} }
} }
@@ -124,17 +70,11 @@ impl InputMessage {
recipient_tag: AnonymousSenderTag, recipient_tag: AnonymousSenderTag,
data: Vec<u8>, data: Vec<u8>,
lane: TransmissionLane, lane: TransmissionLane,
packet_type: Option<PacketType>,
) -> Self { ) -> Self {
let message = InputMessage::Reply { InputMessage::Reply {
recipient_tag, recipient_tag,
data, data,
lane, lane,
};
if let Some(packet_type) = packet_type {
InputMessage::new_wrapper(message, packet_type)
} else {
message
} }
} }
@@ -142,9 +82,7 @@ impl InputMessage {
match self { match self {
InputMessage::Regular { lane, .. } InputMessage::Regular { lane, .. }
| InputMessage::Anonymous { lane, .. } | InputMessage::Anonymous { lane, .. }
| InputMessage::Reply { lane, .. } | InputMessage::Reply { lane, .. } => lane,
| InputMessage::Premade { lane, .. } => lane,
InputMessage::MessageWrapper { message, .. } => message.lane(),
} }
} }
} }
@@ -0,0 +1,227 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::config::persistence::key_pathfinder::ClientKeyPathfinder;
use gateway_requests::registration::handshake::SharedKeys;
use log::*;
use nym_crypto::asymmetric::{encryption, identity};
use nym_sphinx::acknowledgements::AckKey;
use rand::{CryptoRng, RngCore};
use std::io;
use std::sync::Arc;
// Note: to support key rotation in the future, all keys will require adding an extra smart pointer,
// most likely an AtomicCell, or if it doesn't work as I think it does, a Mutex. Although I think
// AtomicCell includes a Mutex implicitly if the underlying type does not work atomically.
// And I guess there will need to be some mechanism for a grace period when you can still
// use the old key after new one was issued.
// Remember that Arc<T> has Deref implementation for T
#[derive(Clone)]
pub struct KeyManager {
/// identity key associated with the client instance.
identity_keypair: Arc<identity::KeyPair>,
/// encryption key associated with the client instance.
encryption_keypair: Arc<encryption::KeyPair>,
/// shared key derived with the gateway during "registration handshake"
gateway_shared_key: Option<Arc<SharedKeys>>,
/// key used for producing and processing acknowledgement packets.
ack_key: Arc<AckKey>,
}
// The expected flow of a KeyManager "lifetime" is as follows:
/*
1. ::new() is called during client-init
2. after gateway registration is completed [in init] ::insert_gateway_shared_key() is called
3. ::store_keys() is called before init finishes execution.
4. ::load_keys() is called at the beginning of each subsequent client-run
5. [not implemented] ::rotate_keys() is called periodically during client-run I presume?
*/
impl KeyManager {
/// Creates new instance of a [`KeyManager`]
pub fn new<R>(rng: &mut R) -> Self
where
R: RngCore + CryptoRng,
{
KeyManager {
identity_keypair: Arc::new(identity::KeyPair::new(rng)),
encryption_keypair: Arc::new(encryption::KeyPair::new(rng)),
gateway_shared_key: None,
ack_key: Arc::new(AckKey::new(rng)),
}
}
pub fn from_keys(
id_keypair: identity::KeyPair,
enc_keypair: encryption::KeyPair,
gateway_shared_key: SharedKeys,
ack_key: AckKey,
) -> Self {
Self {
identity_keypair: Arc::new(id_keypair),
encryption_keypair: Arc::new(enc_keypair),
gateway_shared_key: Some(Arc::new(gateway_shared_key)),
ack_key: Arc::new(ack_key),
}
}
/// Loads previously stored client keys from the disk.
fn load_client_keys(client_pathfinder: &ClientKeyPathfinder) -> io::Result<Self> {
let identity_keypair: identity::KeyPair =
nym_pemstore::load_keypair(&nym_pemstore::KeyPairPath::new(
client_pathfinder.private_identity_key().to_owned(),
client_pathfinder.public_identity_key().to_owned(),
))?;
let encryption_keypair: encryption::KeyPair =
nym_pemstore::load_keypair(&nym_pemstore::KeyPairPath::new(
client_pathfinder.private_encryption_key().to_owned(),
client_pathfinder.public_encryption_key().to_owned(),
))?;
let ack_key: AckKey = nym_pemstore::load_key(client_pathfinder.ack_key())?;
Ok(KeyManager {
identity_keypair: Arc::new(identity_keypair),
encryption_keypair: Arc::new(encryption_keypair),
gateway_shared_key: None,
ack_key: Arc::new(ack_key),
})
}
/// Loads previously stored keys from the disk. Fails if not all, including the shared gateway
/// key, is available.
pub fn load_keys(client_pathfinder: &ClientKeyPathfinder) -> io::Result<Self> {
let mut key_manager = Self::load_client_keys(client_pathfinder)?;
let gateway_shared_key: SharedKeys =
nym_pemstore::load_key(client_pathfinder.gateway_shared_key())?;
key_manager.gateway_shared_key = Some(Arc::new(gateway_shared_key));
Ok(key_manager)
}
/// Loads previously stored keys from the disk. Fails if client keys are not availabe, but the
/// shared gateway key is optional.
pub fn load_keys_but_gateway_is_optional(
client_pathfinder: &ClientKeyPathfinder,
) -> io::Result<Self> {
let mut key_manager = Self::load_client_keys(client_pathfinder)?;
let gateway_shared_key: Result<SharedKeys, io::Error> =
nym_pemstore::load_key(client_pathfinder.gateway_shared_key());
// It's ok if the gateway key was not found
let gateway_shared_key = match gateway_shared_key {
Err(err) if err.kind() == io::ErrorKind::NotFound => Ok(None),
Err(err) => Err(err),
Ok(key) => Ok(Some(key)),
}?;
key_manager.gateway_shared_key = gateway_shared_key.map(Arc::new);
Ok(key_manager)
}
/// Stores all available keys on the disk.
// While perhaps there is no much point in storing the `AckKey` on the disk,
// it is done so for the consistency sake so that you wouldn't require an rng instance
// during `load_keys` to generate the said key.
pub fn store_keys(&self, client_pathfinder: &ClientKeyPathfinder) -> io::Result<()> {
nym_pemstore::store_keypair(
self.identity_keypair.as_ref(),
&nym_pemstore::KeyPairPath::new(
client_pathfinder.private_identity_key().to_owned(),
client_pathfinder.public_identity_key().to_owned(),
),
)?;
nym_pemstore::store_keypair(
self.encryption_keypair.as_ref(),
&nym_pemstore::KeyPairPath::new(
client_pathfinder.private_encryption_key().to_owned(),
client_pathfinder.public_encryption_key().to_owned(),
),
)?;
nym_pemstore::store_key(self.ack_key.as_ref(), client_pathfinder.ack_key())?;
match self.gateway_shared_key.as_ref() {
None => debug!("No gateway shared key available to store!"),
Some(gate_key) => {
nym_pemstore::store_key(gate_key.as_ref(), client_pathfinder.gateway_shared_key())?
}
}
Ok(())
}
pub fn store_gateway_key(&self, client_pathfinder: &ClientKeyPathfinder) -> io::Result<()> {
match self.gateway_shared_key.as_ref() {
None => {
return Err(io::Error::new(
io::ErrorKind::Other,
"trying to store a non-existing key",
))
}
Some(gate_key) => {
nym_pemstore::store_key(gate_key.as_ref(), client_pathfinder.gateway_shared_key())?
}
}
Ok(())
}
/// Overwrite the existing identity keypair
pub fn set_identity_keypair(&mut self, id_keypair: identity::KeyPair) {
self.identity_keypair = Arc::new(id_keypair);
}
/// Gets an atomically reference counted pointer to [`identity::KeyPair`].
pub fn identity_keypair(&self) -> Arc<identity::KeyPair> {
Arc::clone(&self.identity_keypair)
}
/// Overwrite the existing encryption keypair
pub fn set_encryption_keypair(&mut self, enc_keypair: encryption::KeyPair) {
self.encryption_keypair = Arc::new(enc_keypair);
}
/// Gets an atomically reference counted pointer to [`encryption::KeyPair`].
pub fn encryption_keypair(&self) -> Arc<encryption::KeyPair> {
Arc::clone(&self.encryption_keypair)
}
/// Overwrite the existing ack key
pub fn set_ack_key(&mut self, ack_key: AckKey) {
self.ack_key = Arc::new(ack_key);
}
/// Gets an atomically reference counted pointer to [`AckKey`].
pub fn ack_key(&self) -> Arc<AckKey> {
Arc::clone(&self.ack_key)
}
/// After shared key with the gateway is derived, puts its ownership to this instance of a [`KeyManager`].
pub fn insert_gateway_shared_key(&mut self, gateway_shared_key: Arc<SharedKeys>) {
self.gateway_shared_key = Some(gateway_shared_key)
}
/// Gets an atomically reference counted pointer to [`SharedKey`].
// since this function is not fully public, it is not expected to be used externally and
// hence it's up to us to ensure it's called in correct context
pub fn gateway_shared_key(&self) -> Arc<SharedKeys> {
Arc::clone(
self.gateway_shared_key
.as_ref()
.expect("tried to unwrap empty gateway key!"),
)
}
pub fn is_gateway_key_set(&self) -> bool {
self.gateway_shared_key.is_some()
}
}
@@ -2,16 +2,13 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
use crate::spawn_future; use crate::spawn_future;
use log::*;
use nym_gateway_client::GatewayClient;
use nym_sphinx::forwarding::packet::MixPacket;
use nym_credential_storage::storage::Storage;
#[cfg(not(target_arch = "wasm32"))]
use nym_validator_client::nyxd::traits::DkgQueryClient;
#[cfg(target_arch = "wasm32")] #[cfg(target_arch = "wasm32")]
use nym_bandwidth_controller::wasm_mockups::DkgQueryClient; use gateway_client::wasm_mockups::CosmWasmClient;
use gateway_client::GatewayClient;
use log::*;
use nym_sphinx::forwarding::packet::MixPacket;
#[cfg(not(target_arch = "wasm32"))]
use validator_client::nyxd::CosmWasmClient;
pub type BatchMixMessageSender = tokio::sync::mpsc::Sender<Vec<MixPacket>>; pub type BatchMixMessageSender = tokio::sync::mpsc::Sender<Vec<MixPacket>>;
pub type BatchMixMessageReceiver = tokio::sync::mpsc::Receiver<Vec<MixPacket>>; pub type BatchMixMessageReceiver = tokio::sync::mpsc::Receiver<Vec<MixPacket>>;
@@ -20,10 +17,10 @@ pub type BatchMixMessageReceiver = tokio::sync::mpsc::Receiver<Vec<MixPacket>>;
pub const MIX_MESSAGE_RECEIVER_BUFFER_SIZE: usize = 32; pub const MIX_MESSAGE_RECEIVER_BUFFER_SIZE: usize = 32;
const MAX_FAILURE_COUNT: usize = 100; const MAX_FAILURE_COUNT: usize = 100;
pub struct MixTrafficController<C, St: Storage> { pub struct MixTrafficController<C: Clone> {
// TODO: most likely to be replaced by some higher level construct as // TODO: most likely to be replaced by some higher level construct as
// later on gateway_client will need to be accessible by other entities // later on gateway_client will need to be accessible by other entities
gateway_client: GatewayClient<C, St>, gateway_client: GatewayClient<C>,
mix_rx: BatchMixMessageReceiver, mix_rx: BatchMixMessageReceiver,
// TODO: this is temporary work-around. // TODO: this is temporary work-around.
@@ -31,24 +28,22 @@ pub struct MixTrafficController<C, St: Storage> {
consecutive_gateway_failure_count: usize, consecutive_gateway_failure_count: usize,
} }
impl<C, St> MixTrafficController<C, St> impl<C> MixTrafficController<C>
where where
C: DkgQueryClient + Sync + Send + 'static, C: CosmWasmClient + Sync + Send + Clone + 'static,
St: Storage + 'static,
<St as Storage>::StorageError: Send + Sync + 'static,
{ {
pub fn new( pub fn new(
gateway_client: GatewayClient<C, St>, gateway_client: GatewayClient<C>,
) -> (MixTrafficController<C, St>, BatchMixMessageSender) { ) -> (MixTrafficController<C>, BatchMixMessageSender) {
let (message_sender, message_receiver) = let (sphinx_message_sender, sphinx_message_receiver) =
tokio::sync::mpsc::channel(MIX_MESSAGE_RECEIVER_BUFFER_SIZE); tokio::sync::mpsc::channel(MIX_MESSAGE_RECEIVER_BUFFER_SIZE);
( (
MixTrafficController { MixTrafficController {
gateway_client, gateway_client,
mix_rx: message_receiver, mix_rx: sphinx_message_receiver,
consecutive_gateway_failure_count: 0, consecutive_gateway_failure_count: 0,
}, },
message_sender, sphinx_message_sender,
) )
} }
@@ -3,8 +3,8 @@
use super::action_controller::{AckActionSender, Action}; use super::action_controller::{AckActionSender, Action};
use futures::StreamExt; use futures::StreamExt;
use gateway_client::AcknowledgementReceiver;
use log::*; use log::*;
use nym_gateway_client::AcknowledgementReceiver;
use nym_sphinx::{ 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},
@@ -71,7 +71,7 @@ impl AcknowledgementListener {
while !shutdown.is_shutdown() { while !shutdown.is_shutdown() {
tokio::select! { tokio::select! {
acks = self.ack_receiver.next() => match acks { acks = self.ack_receiver.next() => match acks {
Some(acks) => {self.handle_ack_receiver_item(acks).await} Some(acks) => self.handle_ack_receiver_item(acks).await,
None => { None => {
log::trace!("AcknowledgementListener: Stopping since channel closed"); log::trace!("AcknowledgementListener: Stopping since channel closed");
break; break;
@@ -1,15 +1,12 @@
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net> // Copyright 2021-2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
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::real_messages_control::real_traffic_stream::RealMessage;
use crate::client::replies::reply_controller::ReplyControllerSender; use crate::client::replies::reply_controller::ReplyControllerSender;
use log::*; use log::*;
use nym_sphinx::addressing::clients::Recipient; use nym_sphinx::addressing::clients::Recipient;
use nym_sphinx::anonymous_replies::requests::AnonymousSenderTag; use nym_sphinx::anonymous_replies::requests::AnonymousSenderTag;
use nym_sphinx::forwarding::packet::MixPacket;
use nym_sphinx::params::PacketType;
use nym_task::connections::TransmissionLane; use nym_task::connections::TransmissionLane;
use rand::{CryptoRng, Rng}; use rand::{CryptoRng, Rng};
@@ -44,18 +41,6 @@ where
} }
} }
async fn handle_premade_packets(&mut self, packets: Vec<MixPacket>, lane: TransmissionLane) {
self.message_handler
.send_premade_mix_packets(
packets
.into_iter()
.map(|p| RealMessage::new(p, None))
.collect(),
lane,
)
.await
}
async fn handle_reply( async fn handle_reply(
&mut self, &mut self,
recipient_tag: AnonymousSenderTag, recipient_tag: AnonymousSenderTag,
@@ -72,11 +57,10 @@ where
recipient: Recipient, recipient: Recipient,
content: Vec<u8>, content: Vec<u8>,
lane: TransmissionLane, lane: TransmissionLane,
packet_type: PacketType,
) { ) {
if let Err(err) = self if let Err(err) = self
.message_handler .message_handler
.try_send_plain_message(recipient, content, lane, packet_type) .try_send_plain_message(recipient, content, lane)
.await .await
{ {
warn!("failed to send a plain message - {err}") warn!("failed to send a plain message - {err}")
@@ -89,11 +73,10 @@ where
content: Vec<u8>, content: Vec<u8>,
reply_surbs: u32, reply_surbs: u32,
lane: TransmissionLane, lane: TransmissionLane,
packet_type: PacketType,
) { ) {
if let Err(err) = self if let Err(err) = self
.message_handler .message_handler
.try_send_message_with_reply_surbs(recipient, content, reply_surbs, lane, packet_type) .try_send_message_with_reply_surbs(recipient, content, reply_surbs, lane)
.await .await
{ {
warn!("failed to send a repliable message - {err}") warn!("failed to send a repliable message - {err}")
@@ -106,17 +89,14 @@ where
recipient, recipient,
data, data,
lane, lane,
} => { } => self.handle_plain_message(recipient, data, lane).await,
self.handle_plain_message(recipient, data, lane, PacketType::Mix)
.await
}
InputMessage::Anonymous { InputMessage::Anonymous {
recipient, recipient,
data, data,
reply_surbs, reply_surbs,
lane, lane,
} => { } => {
self.handle_repliable_message(recipient, data, reply_surbs, lane, PacketType::Mix) self.handle_repliable_message(recipient, data, reply_surbs, lane)
.await .await
} }
InputMessage::Reply { InputMessage::Reply {
@@ -126,41 +106,6 @@ where
} => { } => {
self.handle_reply(recipient_tag, data, lane).await; self.handle_reply(recipient_tag, data, lane).await;
} }
InputMessage::Premade { msgs, lane } => self.handle_premade_packets(msgs, lane).await,
InputMessage::MessageWrapper {
message,
packet_type,
} => match *message {
InputMessage::Regular {
recipient,
data,
lane,
} => {
self.handle_plain_message(recipient, data, lane, packet_type)
.await
}
InputMessage::Anonymous {
recipient,
data,
reply_surbs,
lane,
} => {
self.handle_repliable_message(recipient, data, reply_surbs, lane, packet_type)
.await
}
InputMessage::Reply {
recipient_tag,
data,
lane,
} => {
self.handle_reply(recipient_tag, data, lane).await;
}
InputMessage::Premade { msgs, lane } => {
self.handle_premade_packets(msgs, lane).await
}
// MessageWrappers can't be nested
InputMessage::MessageWrapper { .. } => unimplemented!(),
},
}; };
} }
@@ -13,10 +13,10 @@ use crate::client::replies::reply_controller::ReplyControllerSender;
use crate::spawn_future; use crate::spawn_future;
use action_controller::AckActionReceiver; use action_controller::AckActionReceiver;
use futures::channel::mpsc; use futures::channel::mpsc;
use gateway_client::AcknowledgementReceiver;
use log::*; use log::*;
use nym_gateway_client::AcknowledgementReceiver;
use nym_sphinx::anonymous_replies::requests::AnonymousSenderTag; use nym_sphinx::anonymous_replies::requests::AnonymousSenderTag;
use nym_sphinx::params::{PacketSize, PacketType}; use nym_sphinx::params::PacketSize;
use nym_sphinx::{ use nym_sphinx::{
acknowledgements::AckKey, acknowledgements::AckKey,
addressing::clients::Recipient, addressing::clients::Recipient,
@@ -249,11 +249,7 @@ where
} }
} }
pub(super) fn start_with_shutdown( pub(super) fn start_with_shutdown(self, shutdown: nym_task::TaskClient) {
self,
shutdown: nym_task::TaskClient,
packet_type: PacketType,
) {
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;
@@ -279,7 +275,7 @@ where
let shutdown_handle = shutdown.clone(); let shutdown_handle = shutdown.clone();
spawn_future(async move { spawn_future(async move {
retransmission_request_listener retransmission_request_listener
.run_with_shutdown(shutdown_handle, packet_type) .run_with_shutdown(shutdown_handle)
.await; .await;
debug!("The retransmission request listener has finished execution!"); debug!("The retransmission request listener has finished execution!");
}); });
@@ -1,4 +1,4 @@
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net> // Copyright 2021-2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
use super::{ use super::{
@@ -11,9 +11,9 @@ 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 futures::StreamExt; use futures::StreamExt;
use log::*; use log::*;
use nym_sphinx::addressing::clients::Recipient;
use nym_sphinx::chunking::fragment::Fragment; use nym_sphinx::chunking::fragment::Fragment;
use nym_sphinx::preparer::PreparedFragment; use nym_sphinx::preparer::PreparedFragment;
use nym_sphinx::{addressing::clients::Recipient, params::PacketType};
use nym_task::connections::TransmissionLane; use nym_task::connections::TransmissionLane;
use rand::{CryptoRng, Rng}; use rand::{CryptoRng, Rng};
use std::sync::{Arc, Weak}; use std::sync::{Arc, Weak};
@@ -48,20 +48,17 @@ where
&mut self, &mut self,
packet_recipient: Recipient, packet_recipient: Recipient,
chunk_data: Fragment, chunk_data: Fragment,
packet_type: PacketType,
) -> Result<PreparedFragment, PreparationError> { ) -> Result<PreparedFragment, PreparationError> {
debug!("retransmitting normal packet..."); debug!("retransmitting normal packet...");
// TODO: Figure out retransmission packet type signaling
self.message_handler self.message_handler
.try_prepare_single_chunk_for_sending(packet_recipient, chunk_data, packet_type) .try_prepare_single_chunk_for_sending(packet_recipient, chunk_data)
.await .await
} }
async fn on_retransmission_request( async fn on_retransmission_request(
&mut self, &mut self,
weak_timed_out_ack: Weak<PendingAcknowledgement>, weak_timed_out_ack: Weak<PendingAcknowledgement>,
packet_type: PacketType,
) { ) {
let timed_out_ack = match weak_timed_out_ack.upgrade() { let timed_out_ack = match weak_timed_out_ack.upgrade() {
Some(timed_out_ack) => timed_out_ack, Some(timed_out_ack) => timed_out_ack,
@@ -88,7 +85,6 @@ where
self.prepare_normal_retransmission_chunk( self.prepare_normal_retransmission_chunk(
**recipient, **recipient,
timed_out_ack.message_chunk.clone(), timed_out_ack.message_chunk.clone(),
packet_type,
) )
.await .await
} }
@@ -135,26 +131,19 @@ where
// send to `OutQueueControl` to eventually send to the mix network // send to `OutQueueControl` to eventually send to the mix network
self.message_handler self.message_handler
.forward_messages( .forward_messages(
vec![RealMessage::new( vec![RealMessage::new(prepared_fragment.mix_packet, frag_id)],
prepared_fragment.mix_packet,
Some(frag_id),
)],
TransmissionLane::Retransmission, TransmissionLane::Retransmission,
) )
.await .await
} }
pub(super) async fn run_with_shutdown( pub(super) async fn run_with_shutdown(&mut self, mut shutdown: nym_task::TaskClient) {
&mut self,
mut shutdown: nym_task::TaskClient,
packet_type: PacketType,
) {
debug!("Started RetransmissionRequestListener with graceful shutdown support"); debug!("Started RetransmissionRequestListener with graceful shutdown support");
while !shutdown.is_shutdown() { while !shutdown.is_shutdown() {
tokio::select! { tokio::select! {
timed_out_ack = self.request_receiver.next() => match timed_out_ack { timed_out_ack = self.request_receiver.next() => match timed_out_ack {
Some(timed_out_ack) => self.on_retransmission_request(timed_out_ack, packet_type).await, Some(timed_out_ack) => self.on_retransmission_request(timed_out_ack).await,
None => { None => {
log::trace!("RetransmissionRequestListener: Stopping since channel closed"); log::trace!("RetransmissionRequestListener: Stopping since channel closed");
break; break;
@@ -15,7 +15,7 @@ use nym_sphinx::anonymous_replies::requests::{AnonymousSenderTag, RepliableMessa
use nym_sphinx::anonymous_replies::{ReplySurb, SurbEncryptionKey}; use nym_sphinx::anonymous_replies::{ReplySurb, SurbEncryptionKey};
use nym_sphinx::chunking::fragment::{Fragment, FragmentIdentifier}; use nym_sphinx::chunking::fragment::{Fragment, FragmentIdentifier};
use nym_sphinx::message::NymMessage; use nym_sphinx::message::NymMessage;
use nym_sphinx::params::{PacketSize, PacketType, DEFAULT_NUM_MIX_HOPS}; use nym_sphinx::params::{PacketSize, DEFAULT_NUM_MIX_HOPS};
use nym_sphinx::preparer::{MessagePreparer, PreparedFragment}; use nym_sphinx::preparer::{MessagePreparer, PreparedFragment};
use nym_sphinx::Delay; use nym_sphinx::Delay;
use nym_task::connections::TransmissionLane; use nym_task::connections::TransmissionLane;
@@ -27,7 +27,7 @@ use std::time::Duration;
use thiserror::Error; use thiserror::Error;
// 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, Error)] #[derive(Debug, Clone, Error)]
pub enum PreparationError { pub enum PreparationError {
#[error(transparent)] #[error(transparent)]
NymTopologyError(#[from] NymTopologyError), NymTopologyError(#[from] NymTopologyError),
@@ -101,11 +101,8 @@ pub(crate) struct Config {
/// Note that it does not include gateway hops. /// Note that it does not include gateway hops.
num_mix_hops: u8, num_mix_hops: u8,
/// Primary predefined packet size used for the encapsulated messages. /// Predefined packet size used for the encapsulated messages.
primary_packet_size: PacketSize, packet_size: PacketSize,
/// Optional secondary predefined packet size used for the encapsulated messages.
secondary_packet_size: Option<PacketSize>,
} }
impl Config { impl Config {
@@ -121,8 +118,7 @@ impl Config {
average_packet_delay, average_packet_delay,
average_ack_delay, average_ack_delay,
num_mix_hops: DEFAULT_NUM_MIX_HOPS, num_mix_hops: DEFAULT_NUM_MIX_HOPS,
primary_packet_size: PacketSize::default(), packet_size: PacketSize::default(),
secondary_packet_size: None,
} }
} }
@@ -134,14 +130,8 @@ impl Config {
} }
/// Allows setting non-default size of the sphinx packets sent out. /// Allows setting non-default size of the sphinx packets sent out.
pub fn with_custom_primary_packet_size(mut self, packet_size: PacketSize) -> Self { pub fn with_custom_packet_size(mut self, packet_size: PacketSize) -> Self {
self.primary_packet_size = packet_size; self.packet_size = packet_size;
self
}
/// Allows setting non-default size of the sphinx packets sent out.
pub fn with_custom_secondary_packet_size(mut self, packet_size: Option<PacketSize>) -> Self {
self.secondary_packet_size = packet_size;
self self
} }
} }
@@ -180,6 +170,7 @@ where
config.average_packet_delay, config.average_packet_delay,
config.average_ack_delay, config.average_ack_delay,
) )
.with_custom_real_message_packet_size(config.packet_size)
.with_mix_hops(config.num_mix_hops); .with_mix_hops(config.num_mix_hops);
MessageHandler { MessageHandler {
@@ -220,28 +211,6 @@ where
} }
} }
fn optimal_packet_size(&self, msg: &NymMessage) -> PacketSize {
// if secondary packet was never set, then it's obvious we have to use the primary packet
let Some(secondary_packet) = self.config.secondary_packet_size else {
trace!("only primary packet size is available");
return self.config.primary_packet_size;
};
let primary_count =
msg.required_packets(self.config.primary_packet_size, self.config.num_mix_hops);
let secondary_count = msg.required_packets(secondary_packet, self.config.num_mix_hops);
trace!("This message would require: {primary_count} primary packets or {secondary_count} secondary packets...");
// if there would be no benefit in using the secondary packet - use the primary (duh)
if primary_count <= secondary_count {
trace!("so choosing primary for this message");
self.config.primary_packet_size
} else {
trace!("so choosing secondary for this message");
secondary_packet
}
}
async fn generate_reply_surbs_with_keys( async fn generate_reply_surbs_with_keys(
&mut self, &mut self,
amount: usize, amount: usize,
@@ -268,13 +237,9 @@ where
reply_surb: ReplySurb, reply_surb: ReplySurb,
is_extra_surb_request: bool, is_extra_surb_request: bool,
) -> Result<(), SurbWrappedPreparationError> { ) -> Result<(), SurbWrappedPreparationError> {
let msg = NymMessage::new_reply(message);
let packet_size = self.optimal_packet_size(&msg);
debug!("Using {packet_size} packets for {msg}");
let mut fragment = self let mut fragment = self
.message_preparer .message_preparer
.pad_and_split_message(msg, packet_size); .pad_and_split_message(NymMessage::new_reply(message));
if fragment.len() > 1 { if fragment.len() > 1 {
// well, it's not a single surb message // well, it's not a single surb message
return Err(SurbWrappedPreparationError { return Err(SurbWrappedPreparationError {
@@ -291,10 +256,8 @@ where
.try_prepare_single_reply_chunk_for_sending(reply_surb, chunk_clone) .try_prepare_single_reply_chunk_for_sending(reply_surb, chunk_clone)
.await?; .await?;
let real_messages = RealMessage::new( let real_messages =
prepared_fragment.mix_packet, RealMessage::new(prepared_fragment.mix_packet, chunk.fragment_identifier());
Some(chunk.fragment_identifier()),
);
let delay = prepared_fragment.total_delay; let delay = prepared_fragment.total_delay;
let pending_ack = let pending_ack =
PendingAcknowledgement::new_anonymous(chunk, delay, target, is_extra_surb_request); PendingAcknowledgement::new_anonymous(chunk, delay, target, is_extra_surb_request);
@@ -326,12 +289,10 @@ where
// // TODO: this will require additional argument to make it use different variant of `ReplyMessage` // // TODO: this will require additional argument to make it use different variant of `ReplyMessage`
pub(crate) fn split_reply_message(&mut self, message: Vec<u8>) -> Vec<Fragment> { pub(crate) fn split_reply_message(&mut self, message: Vec<u8>) -> Vec<Fragment> {
let msg = NymMessage::new_reply(ReplyMessage::new_data_message(message));
let packet_size = self.optimal_packet_size(&msg);
debug!("Using {packet_size} packets for {msg}");
self.message_preparer self.message_preparer
.pad_and_split_message(msg, packet_size) .pad_and_split_message(NymMessage::new_reply(ReplyMessage::new_data_message(
message,
)))
} }
pub(crate) async fn send_retransmission_reply_chunks( pub(crate) async fn send_retransmission_reply_chunks(
@@ -386,8 +347,7 @@ where
let lane = raw.0; let lane = raw.0;
let fragment = raw.1; let fragment = raw.1;
let real_message = let real_message = RealMessage::new(prepared.mix_packet, prepared.fragment_identifier);
RealMessage::new(prepared.mix_packet, Some(prepared.fragment_identifier));
let delay = prepared.total_delay; let delay = prepared.total_delay;
let pending_ack = PendingAcknowledgement::new_anonymous(fragment, delay, target, false); let pending_ack = PendingAcknowledgement::new_anonymous(fragment, delay, target, false);
@@ -404,23 +364,14 @@ where
Ok(()) Ok(())
} }
pub(crate) async fn send_premade_mix_packets(
&mut self,
msgs: Vec<RealMessage>,
lane: TransmissionLane,
) {
self.forward_messages(msgs, lane).await;
}
pub(crate) async fn try_send_plain_message( pub(crate) async fn try_send_plain_message(
&mut self, &mut self,
recipient: Recipient, recipient: Recipient,
message: Vec<u8>, message: Vec<u8>,
lane: TransmissionLane, lane: TransmissionLane,
packet_type: PacketType,
) -> Result<(), PreparationError> { ) -> Result<(), PreparationError> {
let message = NymMessage::new_plain(message); let message = NymMessage::new_plain(message);
self.try_split_and_send_non_reply_message(message, recipient, lane, packet_type) self.try_split_and_send_non_reply_message(message, recipient, lane)
.await .await
} }
@@ -429,9 +380,7 @@ where
message: NymMessage, message: NymMessage,
recipient: Recipient, recipient: Recipient,
lane: TransmissionLane, lane: TransmissionLane,
packet_type: PacketType,
) -> Result<(), PreparationError> { ) -> Result<(), PreparationError> {
debug!("Sending non-reply message with packet type {packet_type}");
// TODO: I really dislike existence of this assertion, it implies code has to be re-organised // TODO: I really dislike existence of this assertion, it implies code has to be re-organised
debug_assert!(!matches!(message, NymMessage::Reply(_))); debug_assert!(!matches!(message, NymMessage::Reply(_)));
@@ -439,15 +388,7 @@ where
let topology_permit = self.topology_access.get_read_permit().await; let topology_permit = self.topology_access.get_read_permit().await;
let topology = self.get_topology(&topology_permit)?; let topology = self.get_topology(&topology_permit)?;
let packet_size = if packet_type == PacketType::Outfox { let fragments = self.message_preparer.pad_and_split_message(message);
PacketSize::OutfoxRegularPacket
} else {
self.optimal_packet_size(&message)
};
debug!("Using {packet_size} packets for {message}");
let fragments = self
.message_preparer
.pad_and_split_message(message, packet_size);
let mut pending_acks = Vec::with_capacity(fragments.len()); let mut pending_acks = Vec::with_capacity(fragments.len());
let mut real_messages = Vec::with_capacity(fragments.len()); let mut real_messages = Vec::with_capacity(fragments.len());
@@ -460,13 +401,10 @@ where
topology, topology,
&self.config.ack_key, &self.config.ack_key,
&recipient, &recipient,
packet_type,
)?; )?;
let real_message = RealMessage::new( let real_message =
prepared_fragment.mix_packet, RealMessage::new(prepared_fragment.mix_packet, fragment.fragment_identifier());
Some(fragment.fragment_identifier()),
);
let delay = prepared_fragment.total_delay; let delay = prepared_fragment.total_delay;
let pending_ack = PendingAcknowledgement::new_known(fragment, delay, recipient); let pending_ack = PendingAcknowledgement::new_known(fragment, delay, recipient);
@@ -484,9 +422,7 @@ where
&mut self, &mut self,
recipient: Recipient, recipient: Recipient,
amount: u32, amount: u32,
packet_type: PacketType,
) -> Result<(), PreparationError> { ) -> Result<(), PreparationError> {
debug!("Sending additional reply SURBs with packet type {packet_type}");
let sender_tag = self.get_or_create_sender_tag(&recipient); let sender_tag = self.get_or_create_sender_tag(&recipient);
let (reply_surbs, reply_keys) = let (reply_surbs, reply_keys) =
self.generate_reply_surbs_with_keys(amount as usize).await?; self.generate_reply_surbs_with_keys(amount as usize).await?;
@@ -500,7 +436,6 @@ where
message, message,
recipient, recipient,
TransmissionLane::AdditionalReplySurbs, TransmissionLane::AdditionalReplySurbs,
packet_type,
) )
.await?; .await?;
@@ -516,9 +451,7 @@ where
message: Vec<u8>, message: Vec<u8>,
num_reply_surbs: u32, num_reply_surbs: u32,
lane: TransmissionLane, lane: TransmissionLane,
packet_type: PacketType,
) -> Result<(), SurbWrappedPreparationError> { ) -> Result<(), SurbWrappedPreparationError> {
debug!("Sending message with reply SURBs with packet type {packet_type}");
let sender_tag = self.get_or_create_sender_tag(&recipient); let sender_tag = self.get_or_create_sender_tag(&recipient);
let (reply_surbs, reply_keys) = self let (reply_surbs, reply_keys) = self
.generate_reply_surbs_with_keys(num_reply_surbs as usize) .generate_reply_surbs_with_keys(num_reply_surbs as usize)
@@ -527,7 +460,7 @@ where
let message = let message =
NymMessage::new_repliable(RepliableMessage::new_data(message, sender_tag, reply_surbs)); NymMessage::new_repliable(RepliableMessage::new_data(message, sender_tag, reply_surbs));
self.try_split_and_send_non_reply_message(message, recipient, lane, packet_type) self.try_split_and_send_non_reply_message(message, recipient, lane)
.await?; .await?;
log::trace!("storing {} reply keys", reply_keys.len()); log::trace!("storing {} reply keys", reply_keys.len());
@@ -540,21 +473,13 @@ where
&mut self, &mut self,
recipient: Recipient, recipient: Recipient,
chunk: Fragment, chunk: Fragment,
packet_type: PacketType,
) -> Result<PreparedFragment, PreparationError> { ) -> Result<PreparedFragment, PreparationError> {
debug!("Sending single chunk with packet type {packet_type}");
let topology_permit = self.topology_access.get_read_permit().await; let topology_permit = self.topology_access.get_read_permit().await;
let topology = self.get_topology(&topology_permit)?; let topology = self.get_topology(&topology_permit)?;
let prepared_fragment = self let prepared_fragment = self
.message_preparer .message_preparer
.prepare_chunk_for_sending( .prepare_chunk_for_sending(chunk, topology, &self.config.ack_key, &recipient)
chunk,
topology,
&self.config.ack_key,
&recipient,
packet_type,
)
.unwrap(); .unwrap();
Ok(prepared_fragment) Ok(prepared_fragment)
@@ -565,7 +490,7 @@ where
fragments: Vec<Fragment>, fragments: Vec<Fragment>,
reply_surbs: Vec<ReplySurb>, reply_surbs: Vec<ReplySurb>,
) -> Result<Vec<PreparedFragment>, SurbWrappedPreparationError> { ) -> Result<Vec<PreparedFragment>, SurbWrappedPreparationError> {
debug_assert_eq!( debug_assert_ne!(
fragments.len(), fragments.len(),
reply_surbs.len(), reply_surbs.len(),
"attempted to send {} fragments with {} reply surbs", "attempted to send {} fragments with {} reply surbs",
@@ -590,7 +515,6 @@ where
topology, topology,
&self.config.ack_key, &self.config.ack_key,
reply_surb, reply_surb,
PacketType::Mix,
) )
.unwrap() .unwrap()
}) })
@@ -610,13 +534,7 @@ where
let prepared_fragment = self let prepared_fragment = self
.message_preparer .message_preparer
.prepare_reply_chunk_for_sending( .prepare_reply_chunk_for_sending(chunk, topology, &self.config.ack_key, reply_surb)
chunk,
topology,
&self.config.ack_key,
reply_surb,
PacketType::Mix,
)
.unwrap(); .unwrap();
Ok(prepared_fragment) Ok(prepared_fragment)
@@ -1,4 +1,4 @@
// Copyright 2021-2023 - 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
// INPUT: InputMessage from user // INPUT: InputMessage from user
@@ -22,14 +22,15 @@ use crate::{
spawn_future, spawn_future,
}; };
use futures::channel::mpsc; use futures::channel::mpsc;
use gateway_client::AcknowledgementReceiver;
use log::*; use log::*;
use nym_gateway_client::AcknowledgementReceiver;
use nym_sphinx::acknowledgements::AckKey; use nym_sphinx::acknowledgements::AckKey;
use nym_sphinx::addressing::clients::Recipient; use nym_sphinx::addressing::clients::Recipient;
use nym_sphinx::params::PacketType; use nym_sphinx::params::PacketSize;
use nym_task::connections::{ConnectionCommandReceiver, LaneQueueLengths}; 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 crate::client::replies::reply_controller; use crate::client::replies::reply_controller;
use crate::config; use crate::config;
@@ -44,29 +45,61 @@ pub struct Config {
/// Key used to decrypt contents of received SURBAcks /// Key used to decrypt contents of received SURBAcks
ack_key: Arc<AckKey>, ack_key: Arc<AckKey>,
/// Given ack timeout in the form a * BASE_DELAY + b, it specifies the additive part `b`
ack_wait_addition: Duration,
/// Given ack timeout in the form a * BASE_DELAY + b, it specifies the multiplier `a`
ack_wait_multiplier: f64,
/// Address of `this` client. /// Address of `this` client.
self_recipient: Recipient, self_recipient: Recipient,
/// Specifies all traffic related configuration options. /// Average delay between sending subsequent packets from this client.
traffic: config::Traffic, average_message_sending_delay: Duration,
/// Specifies all cover traffic related configuration options. /// Average delay a data packet is going to get delayed at a single mixnode.
cover_traffic: config::CoverTraffic, average_packet_delay_duration: Duration,
/// Specifies all acknowledgements related configuration options. /// Average delay an acknowledgement packet is going to get delayed at a single mixnode.
acks: config::Acknowledgements, average_ack_delay_duration: Duration,
/// Specifies all reply SURBs related configuration options. /// Controls whether the main packet stream constantly produces packets according to the predefined
reply_surbs: config::ReplySurbs, /// poisson distribution.
disable_main_poisson_packet_distribution: bool,
/// Predefined packet size used for the encapsulated messages.
packet_size: PacketSize,
/// Defines the minimum number of reply surbs the client would request.
minimum_reply_surb_request_size: u32,
/// Defines the maximum number of reply surbs the client would request.
maximum_reply_surb_request_size: u32,
/// Defines the maximum number of reply surbs a remote party is allowed to request from this client at once.
maximum_allowed_reply_surb_request_size: u32,
/// Defines maximum amount of time the client is going to wait for reply surbs before explicitly asking
/// for more even though in theory they wouldn't need to.
maximum_reply_surb_rerequest_waiting_period: Duration,
/// Defines maximum amount of time the client is going to wait for reply surbs before
/// deciding it's never going to get them and would drop all pending messages
maximum_reply_surb_drop_waiting_period: Duration,
/// Defines maximum amount of time given reply surb is going to be valid for.
/// This is going to be superseded by key rotation once implemented.
maximum_reply_surb_age: Duration,
/// Defines maximum amount of time given reply key is going to be valid for.
/// This is going to be superseded by key rotation once implemented.
maximum_reply_key_age: Duration,
} }
impl<'a> From<&'a Config> for acknowledgement_control::Config { impl<'a> From<&'a Config> for acknowledgement_control::Config {
fn from(cfg: &'a Config) -> Self { fn from(cfg: &'a Config) -> Self {
acknowledgement_control::Config::new( acknowledgement_control::Config::new(cfg.ack_wait_addition, cfg.ack_wait_multiplier)
cfg.acks.ack_wait_addition, .with_custom_packet_size(cfg.packet_size)
cfg.acks.ack_wait_multiplier,
)
.with_custom_packet_size(cfg.traffic.primary_packet_size)
} }
} }
@@ -75,16 +108,26 @@ impl<'a> From<&'a Config> for real_traffic_stream::Config {
real_traffic_stream::Config::new( real_traffic_stream::Config::new(
Arc::clone(&cfg.ack_key), Arc::clone(&cfg.ack_key),
cfg.self_recipient, cfg.self_recipient,
cfg.acks.average_ack_delay, cfg.average_ack_delay_duration,
cfg.traffic, cfg.average_packet_delay_duration,
cfg.cover_traffic.cover_traffic_primary_size_ratio, cfg.average_message_sending_delay,
cfg.disable_main_poisson_packet_distribution,
) )
.with_custom_cover_packet_size(cfg.packet_size)
} }
} }
impl<'a> From<&'a Config> for reply_controller::Config { impl<'a> From<&'a Config> for reply_controller::Config {
fn from(cfg: &'a Config) -> Self { fn from(cfg: &'a Config) -> Self {
reply_controller::Config::new(cfg.reply_surbs) reply_controller::Config::new(
cfg.minimum_reply_surb_request_size,
cfg.maximum_reply_surb_request_size,
cfg.maximum_allowed_reply_surb_request_size,
cfg.maximum_reply_surb_rerequest_waiting_period,
cfg.maximum_reply_surb_drop_waiting_period,
cfg.maximum_reply_surb_age,
cfg.maximum_reply_key_age,
)
} }
} }
@@ -93,11 +136,10 @@ impl<'a> From<&'a Config> for message_handler::Config {
message_handler::Config::new( message_handler::Config::new(
Arc::clone(&cfg.ack_key), Arc::clone(&cfg.ack_key),
cfg.self_recipient, cfg.self_recipient,
cfg.traffic.average_packet_delay, cfg.average_packet_delay_duration,
cfg.acks.average_ack_delay, cfg.average_ack_delay_duration,
) )
.with_custom_primary_packet_size(cfg.traffic.primary_packet_size) .with_custom_packet_size(cfg.packet_size)
.with_custom_secondary_packet_size(cfg.traffic.secondary_packet_size)
} }
} }
@@ -110,12 +152,32 @@ impl Config {
Config { Config {
ack_key, ack_key,
self_recipient, self_recipient,
traffic: base_client_debug_config.traffic, packet_size: Default::default(),
cover_traffic: base_client_debug_config.cover_traffic, ack_wait_addition: base_client_debug_config.ack_wait_addition,
acks: base_client_debug_config.acknowledgements, ack_wait_multiplier: base_client_debug_config.ack_wait_multiplier,
reply_surbs: base_client_debug_config.reply_surbs, average_message_sending_delay: base_client_debug_config.message_sending_average_delay,
average_packet_delay_duration: base_client_debug_config.average_packet_delay,
average_ack_delay_duration: base_client_debug_config.average_ack_delay,
disable_main_poisson_packet_distribution: base_client_debug_config
.disable_main_poisson_packet_distribution,
minimum_reply_surb_request_size: base_client_debug_config
.minimum_reply_surb_request_size,
maximum_reply_surb_request_size: base_client_debug_config
.maximum_reply_surb_request_size,
maximum_allowed_reply_surb_request_size: base_client_debug_config
.maximum_allowed_reply_surb_request_size,
maximum_reply_surb_rerequest_waiting_period: base_client_debug_config
.maximum_reply_surb_rerequest_waiting_period,
maximum_reply_surb_drop_waiting_period: base_client_debug_config
.maximum_reply_surb_drop_waiting_period,
maximum_reply_surb_age: base_client_debug_config.maximum_reply_surb_age,
maximum_reply_key_age: base_client_debug_config.maximum_reply_key_age,
} }
} }
pub fn set_custom_packet_size(&mut self, packet_size: PacketSize) {
self.packet_size = packet_size;
}
} }
pub(crate) struct RealMessagesController<R> pub(crate) struct RealMessagesController<R>
@@ -208,7 +270,7 @@ impl RealMessagesController<OsRng> {
} }
} }
pub fn start_with_shutdown(self, shutdown: nym_task::TaskClient, packet_type: PacketType) { 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;
@@ -224,6 +286,6 @@ impl RealMessagesController<OsRng> {
debug!("The reply controller has finished execution!"); debug!("The reply controller has finished execution!");
}); });
ack_control.start_with_shutdown(shutdown, packet_type); ack_control.start_with_shutdown(shutdown);
} }
} }
@@ -1,4 +1,4 @@
// Copyright 2021-2023 - 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 self::sending_delay_controller::SendingDelayController; use self::sending_delay_controller::SendingDelayController;
@@ -6,7 +6,6 @@ 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 crate::config;
use futures::task::{Context, Poll}; use futures::task::{Context, Poll};
use futures::{Future, Stream, StreamExt}; use futures::{Future, Stream, StreamExt};
use log::*; use log::*;
@@ -28,6 +27,7 @@ use std::time::Duration;
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
use tokio::time; use tokio::time;
#[cfg(target_arch = "wasm32")] #[cfg(target_arch = "wasm32")]
use wasm_timer; use wasm_timer;
@@ -44,12 +44,18 @@ pub(crate) struct Config {
/// Average delay an acknowledgement packet is going to get delay at a single mixnode. /// Average delay an acknowledgement packet is going to get delay at a single mixnode.
average_ack_delay: Duration, average_ack_delay: Duration,
/// Defines all configuration options related to this traffic stream. /// Average delay a data packet is going to get delay at a single mixnode.
traffic: config::Traffic, average_packet_delay: Duration,
/// Specifies the ratio of `primary_packet_size` to `secondary_packet_size` used in cover traffic. /// Average delay between sending subsequent packets.
/// Only applicable if `secondary_packet_size` is enabled. average_message_sending_delay: Duration,
cover_traffic_primary_size_ratio: f64,
/// Controls whether the stream constantly produces packets according to the predefined
/// poisson distribution.
disable_poisson_packet_distribution: bool,
/// Predefined packet size used for the loop cover messages.
cover_packet_size: PacketSize,
} }
impl Config { impl Config {
@@ -57,17 +63,25 @@ impl Config {
ack_key: Arc<AckKey>, ack_key: Arc<AckKey>,
our_full_destination: Recipient, our_full_destination: Recipient,
average_ack_delay: Duration, average_ack_delay: Duration,
traffic: config::Traffic, average_packet_delay: Duration,
cover_traffic_primary_size_ratio: f64, average_message_sending_delay: Duration,
disable_poisson_packet_distribution: bool,
) -> Self { ) -> Self {
Config { Config {
ack_key, ack_key,
our_full_destination, our_full_destination,
average_ack_delay, average_ack_delay,
traffic, average_packet_delay,
cover_traffic_primary_size_ratio, average_message_sending_delay,
disable_poisson_packet_distribution,
cover_packet_size: Default::default(),
} }
} }
pub fn with_custom_cover_packet_size(mut self, packet_size: PacketSize) -> Self {
self.cover_packet_size = packet_size;
self
}
} }
pub(crate) struct OutQueueControl<R> pub(crate) struct OutQueueControl<R>
@@ -92,7 +106,7 @@ where
// messages. // messages.
sending_delay_controller: SendingDelayController, sending_delay_controller: SendingDelayController,
/// Channel used for sending prepared packets to `MixTrafficController` that sends them /// Channel used for sending prepared sphinx packets to `MixTrafficController` that sends them
/// out to the network without any further delays. /// out to the network without any further delays.
mix_tx: BatchMixMessageSender, mix_tx: BatchMixMessageSender,
@@ -121,7 +135,7 @@ where
#[derive(Debug)] #[derive(Debug)]
pub(crate) struct RealMessage { pub(crate) struct RealMessage {
mix_packet: MixPacket, mix_packet: MixPacket,
fragment_id: Option<FragmentIdentifier>, fragment_id: FragmentIdentifier,
// TODO: add info about it being constructed with reply-surb // TODO: add info about it being constructed with reply-surb
} }
@@ -129,17 +143,17 @@ impl From<PreparedFragment> for RealMessage {
fn from(fragment: PreparedFragment) -> Self { fn from(fragment: PreparedFragment) -> Self {
RealMessage { RealMessage {
mix_packet: fragment.mix_packet, mix_packet: fragment.mix_packet,
fragment_id: Some(fragment.fragment_identifier), fragment_id: fragment.fragment_identifier,
} }
} }
} }
impl RealMessage { impl RealMessage {
pub(crate) fn packet_size(&self) -> usize { pub(crate) fn packet_size(&self) -> usize {
self.mix_packet.packet().len() self.mix_packet.sphinx_packet().len()
} }
pub(crate) fn new(mix_packet: MixPacket, fragment_id: Option<FragmentIdentifier>) -> Self { pub(crate) fn new(mix_packet: MixPacket, fragment_id: FragmentIdentifier) -> Self {
RealMessage { RealMessage {
mix_packet, mix_packet,
fragment_id, fragment_id,
@@ -198,30 +212,11 @@ where
self.sent_notifier.unbounded_send(frag_id).unwrap(); self.sent_notifier.unbounded_send(frag_id).unwrap();
} }
fn loop_cover_message_size(&mut self) -> PacketSize {
let Some(secondary_packet_size) = self.config.traffic.secondary_packet_size else {
return self.config.traffic.primary_packet_size;
};
let use_primary = self
.rng
.gen_bool(self.config.cover_traffic_primary_size_ratio);
if use_primary {
self.config.traffic.primary_packet_size
} else {
secondary_packet_size
}
}
async fn on_message(&mut self, next_message: StreamMessage) { async fn on_message(&mut self, next_message: StreamMessage) {
trace!("created new message"); trace!("created new message");
let (next_message, fragment_id) = match next_message { let (next_message, fragment_id) = match next_message {
StreamMessage::Cover => { StreamMessage::Cover => {
let cover_traffic_packet_size = self.loop_cover_message_size();
trace!("the next loop cover message will be put in a {cover_traffic_packet_size} packet");
// TODO for way down the line: in very rare cases (during topology update) we might have // TODO for way down the line: in very rare cases (during topology update) we might have
// to wait a really tiny bit before actually obtaining the permit hence messing with our // to wait a really tiny bit before actually obtaining the permit hence messing with our
// poisson delay, but is it really a problem? // poisson delay, but is it really a problem?
@@ -245,9 +240,8 @@ where
&self.config.ack_key, &self.config.ack_key,
&self.config.our_full_destination, &self.config.our_full_destination,
self.config.average_ack_delay, self.config.average_ack_delay,
self.config.traffic.average_packet_delay, self.config.average_packet_delay,
cover_traffic_packet_size, self.config.cover_packet_size,
self.config.traffic.packet_type,
) )
.expect( .expect(
"Somehow failed to generate a loop cover message with a valid topology", "Somehow failed to generate a loop cover message with a valid topology",
@@ -256,7 +250,7 @@ where
) )
} }
StreamMessage::Real(real_message) => { StreamMessage::Real(real_message) => {
(real_message.mix_packet, real_message.fragment_id) (real_message.mix_packet, Some(real_message.fragment_id))
} }
}; };
@@ -292,7 +286,7 @@ where
} }
fn current_average_message_sending_delay(&self) -> Duration { fn current_average_message_sending_delay(&self) -> Duration {
self.config.traffic.message_sending_average_delay self.config.average_message_sending_delay
* self.sending_delay_controller.current_multiplier() * self.sending_delay_controller.current_multiplier()
} }
@@ -303,34 +297,24 @@ where
self.sending_delay_controller.current_multiplier() self.sending_delay_controller.current_multiplier()
); );
if self // Even just a single used slot is enough to signal backpressure
.sending_delay_controller if used_slots > 0 {
.is_backpressure_currently_detected(used_slots)
{
log::trace!("Backpressure detected"); log::trace!("Backpressure detected");
self.sending_delay_controller.record_backpressure_detected(); self.sending_delay_controller.record_backpressure_detected();
} }
// If the buffer is running out, slow down the sending rate by increasing the delay // If the buffer is running out, slow down the sending rate
// multiplier.
if self.mix_tx.capacity() == 0 if self.mix_tx.capacity() == 0
&& self.sending_delay_controller.not_increased_delay_recently() && self.sending_delay_controller.not_increased_delay_recently()
{ {
self.sending_delay_controller.increase_delay_multiplier(); self.sending_delay_controller.increase_delay_multiplier();
} }
// If it looks like we are sending reliably, increase the sending rate by decreasing the // Very carefully step up the sending rate in case it seems like we can solidly handle the
// sending delay multiplier. // current rate.
if !self if self.sending_delay_controller.is_sending_reliable() {
.sending_delay_controller
.was_backpressure_detected_recently()
&& self.sending_delay_controller.not_decreased_delay_recently()
{
self.sending_delay_controller.decrease_delay_multiplier(); self.sending_delay_controller.decrease_delay_multiplier();
} }
// Keep track of multiplier changes, and log if necessary.
self.sending_delay_controller.record_delay_multiplier();
} }
fn pop_next_message(&mut self) -> Option<RealMessage> { fn pop_next_message(&mut self) -> Option<RealMessage> {
@@ -349,7 +333,7 @@ where
fn poll_poisson(&mut self, cx: &mut Context<'_>) -> Poll<Option<StreamMessage>> { fn poll_poisson(&mut self, cx: &mut Context<'_>) -> Poll<Option<StreamMessage>> {
// The average delay could change depending on if backpressure in the downstream channel // The average delay could change depending on if backpressure in the downstream channel
// (mix_tx) was detected. // (mix_tx) was detected.
self.adjust_current_average_message_sending_delay(); //self.adjust_current_average_message_sending_delay();
let avg_delay = self.current_average_message_sending_delay(); let avg_delay = self.current_average_message_sending_delay();
// Start by checking if we have any incoming messages about closed connections // Start by checking if we have any incoming messages about closed connections
@@ -387,7 +371,7 @@ where
// On every iteration we get new messages from upstream. Given that these come bunched // On every iteration we get new messages from upstream. Given that these come bunched
// in `Vec`, this ensures that on average we will fetch messages faster than we can // in `Vec`, this ensures that on average we will fetch messages faster than we can
// send, which is a condition for being able to multiplex packets from multiple // send, which is a condition for being able to multiplex sphinx packets from multiple
// data streams. // data streams.
match Pin::new(&mut self.real_receiver).poll_recv(cx) { match Pin::new(&mut self.real_receiver).poll_recv(cx) {
// in the case our real message channel stream was closed, we should also indicate we are closed // in the case our real message channel stream was closed, we should also indicate we are closed
@@ -416,10 +400,8 @@ where
// we never set an initial delay - let's do it now // we never set an initial delay - let's do it now
cx.waker().wake_by_ref(); cx.waker().wake_by_ref();
let sampled = sample_poisson_duration( let sampled =
&mut self.rng, sample_poisson_duration(&mut self.rng, self.config.average_message_sending_delay);
self.config.traffic.message_sending_average_delay,
);
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
let next_delay = Box::pin(time::sleep(sampled)); let next_delay = Box::pin(time::sleep(sampled));
@@ -470,7 +452,7 @@ where
mut self: Pin<&mut Self>, mut self: Pin<&mut Self>,
cx: &mut Context<'_>, cx: &mut Context<'_>,
) -> Poll<Option<StreamMessage>> { ) -> Poll<Option<StreamMessage>> {
if self.config.traffic.disable_main_poisson_packet_distribution { if self.config.disable_poisson_packet_distribution {
self.poll_immediate(cx) self.poll_immediate(cx)
} else { } else {
self.poll_poisson(cx) self.poll_poisson(cx)
@@ -486,7 +468,7 @@ where
let lanes = self.transmission_buffer.num_lanes(); let lanes = self.transmission_buffer.num_lanes();
let mult = self.sending_delay_controller.current_multiplier(); let mult = self.sending_delay_controller.current_multiplier();
let delay = self.current_average_message_sending_delay().as_millis(); let delay = self.current_average_message_sending_delay().as_millis();
let status_str = if self.config.traffic.disable_main_poisson_packet_distribution { let status_str = if self.config.disable_poisson_packet_distribution {
format!("Status: {lanes} lanes, backlog: {backlog:.2} kiB ({packets}), no delay") format!("Status: {lanes} lanes, backlog: {backlog:.2} kiB ({packets}), no delay")
} else { } else {
format!( format!(
@@ -509,12 +491,23 @@ where
} }
} }
#[cfg(not(target_arch = "wasm32"))]
fn log_status_infrequent(&self) {
if self.sending_delay_controller.current_multiplier() > 1 {
log::warn!(
"Unable to send packets at the default rate - rate reduced by setting the delay multiplier set to: {}",
self.sending_delay_controller.current_multiplier()
);
}
}
pub(super) async fn run_with_shutdown(&mut self, mut shutdown: nym_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"))]
{ {
let mut status_timer = tokio::time::interval(Duration::from_secs(5)); let mut status_timer = tokio::time::interval(Duration::from_secs(5));
let mut infrequent_status_timer = tokio::time::interval(Duration::from_secs(60));
while !shutdown.is_shutdown() { while !shutdown.is_shutdown() {
tokio::select! { tokio::select! {
@@ -525,6 +518,9 @@ where
_ = status_timer.tick() => { _ = status_timer.tick() => {
self.log_status(&mut shutdown); self.log_status(&mut shutdown);
} }
_ = infrequent_status_timer.tick() => {
self.log_status_infrequent();
}
next_message = self.next() => if let Some(next_message) = next_message { next_message = self.next() => if let Some(next_message) = next_message {
self.on_message(next_message).await; self.on_message(next_message).await;
} else { } else {
@@ -11,20 +11,15 @@ const INCREASE_DELAY_MIN_CHANGE_INTERVAL_SECS: u64 = 1;
// The minimum time between decreasing the average delay between packets. We don't want to change // The minimum time between decreasing the average delay between packets. We don't want to change
// to quickly to keep things somewhat stable. Also there are buffers downstreams meaning we need to // to quickly to keep things somewhat stable. Also there are buffers downstreams meaning we need to
// wait a little to see the effect before we decrease further. // wait a little to see the effect before we decrease further.
const DECREASE_DELAY_MIN_CHANGE_INTERVAL_SECS: u64 = 2; const DECREASE_DELAY_MIN_CHANGE_INTERVAL_SECS: u64 = 30;
// The queue length that is required for us to register that backpressure occured. If there are
// more than this many packets waiting to be sent, we consider the channel to be under
// backpressure.
const BACKPRESSURE_THRESHOLD: usize = 10;
// If we enough time passes without any sign of backpressure in the channel, we can consider // If we enough time passes without any sign of backpressure in the channel, we can consider
// lowering the average delay. // lowering the average delay. The goal is to keep somewhat stable, rather than maxing out
const ACCEPTABLE_TIME_WITHOUT_BACKPRESSURE_SECS: u64 = 2; // bandwidth at all times.
const ACCEPTABLE_TIME_WITHOUT_BACKPRESSURE_SECS: u64 = 30;
// The maximum multiplier we apply to the base average Poisson delay. // The maximum multiplier we apply to the base average Poisson delay.
const MAX_DELAY_MULTIPLIER: u32 = 6; const MAX_DELAY_MULTIPLIER: u32 = 6;
// The minium multiplier we apply to the base average Poisson delay. // The minium multiplier we apply to the base average Poisson delay.
const MIN_DELAY_MULTIPLIER: u32 = 1; const MIN_DELAY_MULTIPLIER: u32 = 1;
// If the multipler increases we log it, but we don't want to log about it too often.
const INTERVAL_BETWEEN_WARNING_ABOUT_ELEVATED_MULTIPLIER_SECS: u64 = 60;
pub(crate) struct SendingDelayController { pub(crate) struct SendingDelayController {
/// Multiply the average sending delay. /// Multiply the average sending delay.
@@ -38,14 +33,6 @@ pub(crate) struct SendingDelayController {
/// Minimum delay multiplier /// Minimum delay multiplier
lower_bound: u32, lower_bound: u32,
/// We counter the number of times the multiplier has been elevated. If it is elevated for long
/// enough we need to log about it.
multiplier_elevated_counter: u32,
/// We can't log about the elevated multiplier too often, so we keep track of the last time we
/// did,
time_when_logged_about_elevated_multiplier: Instant,
/// To make sure we don't change the multiplier to fast, we limit a change to some duration /// To make sure we don't change the multiplier to fast, we limit a change to some duration
time_when_changed: Instant, time_when_changed: Instant,
@@ -68,9 +55,6 @@ impl SendingDelayController {
current_multiplier: MIN_DELAY_MULTIPLIER, current_multiplier: MIN_DELAY_MULTIPLIER,
upper_bound, upper_bound,
lower_bound, lower_bound,
multiplier_elevated_counter: 0,
time_when_logged_about_elevated_multiplier: now
- Duration::from_secs(INTERVAL_BETWEEN_WARNING_ABOUT_ELEVATED_MULTIPLIER_SECS),
time_when_changed: now, time_when_changed: now,
time_when_backpressure_detected: now, time_when_backpressure_detected: now,
} }
@@ -95,7 +79,7 @@ impl SendingDelayController {
self.current_multiplier = self.current_multiplier =
(self.current_multiplier + 1).clamp(self.lower_bound, self.upper_bound); (self.current_multiplier + 1).clamp(self.lower_bound, self.upper_bound);
self.time_when_changed = get_time_now(); self.time_when_changed = get_time_now();
log::debug!( log::warn!(
"Increasing sending delay multiplier to: {}", "Increasing sending delay multiplier to: {}",
self.current_multiplier self.current_multiplier
); );
@@ -116,58 +100,22 @@ impl SendingDelayController {
} }
} }
pub(crate) fn record_backpressure_detected(&mut self) {
self.time_when_backpressure_detected = get_time_now();
}
pub(crate) fn not_increased_delay_recently(&self) -> bool { pub(crate) fn not_increased_delay_recently(&self) -> bool {
get_time_now() get_time_now()
> self.time_when_changed + Duration::from_secs(INCREASE_DELAY_MIN_CHANGE_INTERVAL_SECS) > self.time_when_changed + Duration::from_secs(INCREASE_DELAY_MIN_CHANGE_INTERVAL_SECS)
} }
pub(crate) fn not_decreased_delay_recently(&self) -> bool { pub(crate) fn is_sending_reliable(&self) -> bool {
get_time_now()
> self.time_when_changed + Duration::from_secs(DECREASE_DELAY_MIN_CHANGE_INTERVAL_SECS)
}
pub(crate) fn is_backpressure_currently_detected(&self, queue_length: usize) -> bool {
queue_length > BACKPRESSURE_THRESHOLD
}
pub(crate) fn record_backpressure_detected(&mut self) {
self.time_when_backpressure_detected = get_time_now();
}
pub(crate) fn was_backpressure_detected_recently(&self) -> bool {
get_time_now()
< self.time_when_backpressure_detected
+ Duration::from_secs(ACCEPTABLE_TIME_WITHOUT_BACKPRESSURE_SECS)
}
pub(crate) fn record_delay_multiplier(&mut self) {
// Count the number of times the multiplier has been elevated.
let multiplier_elevated = self.current_multiplier - self.lower_bound;
if multiplier_elevated == 0 {
self.multiplier_elevated_counter = 0;
} else {
self.multiplier_elevated_counter += 1;
}
// If needed, log about the elevated multiplier.
let now = get_time_now(); let now = get_time_now();
if self.multiplier_elevated_counter > 20 let delay_change_interval = Duration::from_secs(DECREASE_DELAY_MIN_CHANGE_INTERVAL_SECS);
&& now let acceptable_time_without_backpressure =
> self.time_when_logged_about_elevated_multiplier Duration::from_secs(ACCEPTABLE_TIME_WITHOUT_BACKPRESSURE_SECS);
+ Duration::from_secs(INTERVAL_BETWEEN_WARNING_ABOUT_ELEVATED_MULTIPLIER_SECS)
{ now > self.time_when_backpressure_detected + acceptable_time_without_backpressure
let status_str = format!( && now > self.time_when_changed + delay_change_interval
"Poisson delay currently scaled by: {}",
self.current_multiplier()
);
if self.current_multiplier() > 0 {
log::debug!("{}", status_str);
} else if self.current_multiplier() > 1 {
log::info!("{}", status_str);
} else if self.current_multiplier() > 2 {
log::warn!("{}", status_str);
}
self.time_when_logged_about_elevated_multiplier = now;
}
} }
} }
@@ -7,10 +7,10 @@ use crate::spawn_future;
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 log::*; use log::*;
use nym_crypto::asymmetric::encryption; use nym_crypto::asymmetric::encryption;
use nym_crypto::Digest; use nym_crypto::Digest;
use nym_gateway_client::MixnetMessageReceiver;
use nym_sphinx::anonymous_replies::requests::{ use nym_sphinx::anonymous_replies::requests::{
RepliableMessage, RepliableMessageContent, ReplyMessage, ReplyMessageContent, RepliableMessage, RepliableMessageContent, ReplyMessage, ReplyMessageContent,
}; };
@@ -30,13 +30,13 @@ pub type ReceivedBufferRequestReceiver = mpsc::UnboundedReceiver<ReceivedBufferM
pub type ReconstructedMessagesSender = mpsc::UnboundedSender<Vec<ReconstructedMessage>>; pub type ReconstructedMessagesSender = mpsc::UnboundedSender<Vec<ReconstructedMessage>>;
pub type ReconstructedMessagesReceiver = mpsc::UnboundedReceiver<Vec<ReconstructedMessage>>; pub type ReconstructedMessagesReceiver = mpsc::UnboundedReceiver<Vec<ReconstructedMessage>>;
struct ReceivedMessagesBufferInner<R: MessageReceiver> { struct ReceivedMessagesBufferInner {
messages: Vec<ReconstructedMessage>, messages: Vec<ReconstructedMessage>,
local_encryption_keypair: Arc<encryption::KeyPair>, local_encryption_keypair: Arc<encryption::KeyPair>,
// TODO: looking how it 'looks' here, perhaps `MessageReceiver` should be renamed to something // TODO: looking how it 'looks' here, perhaps `MessageReceiver` should be renamed to something
// else instead. // else instead.
message_receiver: R, message_receiver: MessageReceiver,
message_sender: Option<ReconstructedMessagesSender>, message_sender: Option<ReconstructedMessagesSender>,
// TODO: this will get cleared upon re-running the client // TODO: this will get cleared upon re-running the client
@@ -45,7 +45,7 @@ struct ReceivedMessagesBufferInner<R: MessageReceiver> {
recently_reconstructed: HashSet<i32>, recently_reconstructed: HashSet<i32>,
} }
impl<R: MessageReceiver> ReceivedMessagesBufferInner<R> { 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 nym_sphinx::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");
@@ -102,13 +102,13 @@ impl<R: MessageReceiver> ReceivedMessagesBufferInner<R> {
&mut self, &mut self,
reply_ciphertext: &mut [u8], reply_ciphertext: &mut [u8],
reply_key: SurbEncryptionKey, reply_key: SurbEncryptionKey,
) -> Result<Option<NymMessage>, MessageRecoveryError> { ) -> Option<NymMessage> {
// note: this performs decryption IN PLACE without extra allocation // note: this performs decryption IN PLACE without extra allocation
self.message_receiver self.message_receiver
.recover_plaintext_from_reply(reply_ciphertext, reply_key)?; .recover_plaintext_from_reply(reply_ciphertext, reply_key);
let fragment_data = reply_ciphertext; let fragment_data = reply_ciphertext;
Ok(self.recover_from_fragment(fragment_data)) self.recover_from_fragment(fragment_data)
} }
fn process_received_regular_packet(&mut self, mut raw_fragment: Vec<u8>) -> Option<NymMessage> { fn process_received_regular_packet(&mut self, mut raw_fragment: Vec<u8>) -> Option<NymMessage> {
@@ -130,13 +130,13 @@ impl<R: MessageReceiver> ReceivedMessagesBufferInner<R> {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
// Note: you should NEVER create more than a single instance of this using 'new()'. // Note: you should NEVER create more than a single instance of this using 'new()'.
// You should always use .clone() to create additional instances // You should always use .clone() to create additional instances
struct ReceivedMessagesBuffer<R: MessageReceiver> { struct ReceivedMessagesBuffer {
inner: Arc<Mutex<ReceivedMessagesBufferInner<R>>>, inner: Arc<Mutex<ReceivedMessagesBufferInner>>,
reply_key_storage: SentReplyKeys, reply_key_storage: SentReplyKeys,
reply_controller_sender: ReplyControllerSender, reply_controller_sender: ReplyControllerSender,
} }
impl<R: MessageReceiver> ReceivedMessagesBuffer<R> { impl ReceivedMessagesBuffer {
fn new( fn new(
local_encryption_keypair: Arc<encryption::KeyPair>, local_encryption_keypair: Arc<encryption::KeyPair>,
reply_key_storage: SentReplyKeys, reply_key_storage: SentReplyKeys,
@@ -146,7 +146,7 @@ impl<R: MessageReceiver> ReceivedMessagesBuffer<R> {
inner: Arc::new(Mutex::new(ReceivedMessagesBufferInner { inner: Arc::new(Mutex::new(ReceivedMessagesBufferInner {
messages: Vec::new(), messages: Vec::new(),
local_encryption_keypair, local_encryption_keypair,
message_receiver: R::new(), message_receiver: MessageReceiver::new(),
message_sender: None, message_sender: None,
recently_reconstructed: HashSet::new(), recently_reconstructed: HashSet::new(),
})), })),
@@ -328,10 +328,7 @@ impl<R: MessageReceiver> ReceivedMessagesBuffer<R> {
}) })
} }
async fn handle_new_received( async fn handle_new_received(&mut self, msgs: Vec<Vec<u8>>) {
&mut self,
msgs: Vec<Vec<u8>>,
) -> Result<(), MessageRecoveryError> {
trace!( trace!(
"Processing {:?} new message that might get added to the buffer!", "Processing {:?} new message that might get added to the buffer!",
msgs.len() msgs.len()
@@ -347,7 +344,7 @@ impl<R: MessageReceiver> ReceivedMessagesBuffer<R> {
// if yes - this is a reply message // if yes - this is a reply message
let completed_message = let completed_message =
if let Some((reply_key, reply_message)) = self.get_reply_key(&mut msg) { if let Some((reply_key, reply_message)) = self.get_reply_key(&mut msg) {
inner_guard.process_received_reply(reply_message, reply_key)? inner_guard.process_received_reply(reply_message, reply_key)
} else { } else {
inner_guard.process_received_regular_packet(msg) inner_guard.process_received_regular_packet(msg)
}; };
@@ -363,7 +360,6 @@ impl<R: MessageReceiver> ReceivedMessagesBuffer<R> {
if !completed_messages.is_empty() { if !completed_messages.is_empty() {
self.handle_reconstructed_messages(completed_messages).await self.handle_reconstructed_messages(completed_messages).await
} }
Ok(())
} }
} }
@@ -376,14 +372,14 @@ pub enum ReceivedBufferMessage {
ReceiverDisconnect, ReceiverDisconnect,
} }
struct RequestReceiver<R: MessageReceiver> { struct RequestReceiver {
received_buffer: ReceivedMessagesBuffer<R>, received_buffer: ReceivedMessagesBuffer,
query_receiver: ReceivedBufferRequestReceiver, query_receiver: ReceivedBufferRequestReceiver,
} }
impl<R: MessageReceiver> RequestReceiver<R> { impl RequestReceiver {
fn new( fn new(
received_buffer: ReceivedMessagesBuffer<R>, received_buffer: ReceivedMessagesBuffer,
query_receiver: ReceivedBufferRequestReceiver, query_receiver: ReceivedBufferRequestReceiver,
) -> Self { ) -> Self {
RequestReceiver { RequestReceiver {
@@ -426,14 +422,14 @@ impl<R: MessageReceiver> RequestReceiver<R> {
} }
} }
struct FragmentedMessageReceiver<R: MessageReceiver> { struct FragmentedMessageReceiver {
received_buffer: ReceivedMessagesBuffer<R>, received_buffer: ReceivedMessagesBuffer,
mixnet_packet_receiver: MixnetMessageReceiver, mixnet_packet_receiver: MixnetMessageReceiver,
} }
impl<R: MessageReceiver> FragmentedMessageReceiver<R> { impl FragmentedMessageReceiver {
fn new( fn new(
received_buffer: ReceivedMessagesBuffer<R>, received_buffer: ReceivedMessagesBuffer,
mixnet_packet_receiver: MixnetMessageReceiver, mixnet_packet_receiver: MixnetMessageReceiver,
) -> Self { ) -> Self {
FragmentedMessageReceiver { FragmentedMessageReceiver {
@@ -442,16 +438,13 @@ impl<R: MessageReceiver> FragmentedMessageReceiver<R> {
} }
} }
async fn run_with_shutdown( async fn run_with_shutdown(&mut self, mut shutdown: nym_task::TaskClient) {
&mut self,
mut shutdown: nym_task::TaskClient,
) -> Result<(), MessageRecoveryError> {
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! {
new_messages = self.mixnet_packet_receiver.next() => { new_messages = self.mixnet_packet_receiver.next() => {
if let Some(new_messages) = new_messages { if let Some(new_messages) = new_messages {
self.received_buffer.handle_new_received(new_messages).await?; self.received_buffer.handle_new_received(new_messages).await;
} else { } else {
log::trace!("FragmentedMessageReceiver: Stopping since channel closed"); log::trace!("FragmentedMessageReceiver: Stopping since channel closed");
break; break;
@@ -464,16 +457,15 @@ impl<R: MessageReceiver> FragmentedMessageReceiver<R> {
} }
shutdown.recv_timeout().await; shutdown.recv_timeout().await;
log::debug!("FragmentedMessageReceiver: Exiting"); log::debug!("FragmentedMessageReceiver: Exiting");
Ok(())
} }
} }
pub(crate) struct ReceivedMessagesBufferController<R: MessageReceiver> { pub(crate) struct ReceivedMessagesBufferController {
fragmented_message_receiver: FragmentedMessageReceiver<R>, fragmented_message_receiver: FragmentedMessageReceiver,
request_receiver: RequestReceiver<R>, request_receiver: RequestReceiver,
} }
impl<R: MessageReceiver + Clone + Send + 'static> ReceivedMessagesBufferController<R> { impl ReceivedMessagesBufferController {
pub(crate) fn new( pub(crate) fn new(
local_encryption_keypair: Arc<encryption::KeyPair>, local_encryption_keypair: Arc<encryption::KeyPair>,
query_receiver: ReceivedBufferRequestReceiver, query_receiver: ReceivedBufferRequestReceiver,
@@ -502,13 +494,9 @@ impl<R: MessageReceiver + Clone + Send + 'static> ReceivedMessagesBufferControll
let shutdown_handle = shutdown.clone(); let shutdown_handle = shutdown.clone();
spawn_future(async move { spawn_future(async move {
match fragmented_message_receiver fragmented_message_receiver
.run_with_shutdown(shutdown_handle) .run_with_shutdown(shutdown_handle)
.await .await;
{
Ok(_) => {}
Err(e) => error!("{e}"),
}
}); });
spawn_future(async move { spawn_future(async move {
request_receiver.run_with_shutdown(shutdown).await; request_receiver.run_with_shutdown(shutdown).await;
@@ -22,21 +22,38 @@ use time::OffsetDateTime;
use crate::client::helpers::new_interval_stream; use crate::client::helpers::new_interval_stream;
use crate::client::transmission_buffer::TransmissionBuffer; use crate::client::transmission_buffer::TransmissionBuffer;
use crate::config;
pub(crate) use requests::{ReplyControllerMessage, ReplyControllerReceiver, ReplyControllerSender}; pub(crate) use requests::{ReplyControllerMessage, ReplyControllerReceiver, ReplyControllerSender};
pub mod requests; pub mod requests;
// this is still left as a separate config so I wouldn't need to replace it everywhere
// plus its not unreasonable to think that we might need something outside config::ReplySurbs struct
pub struct Config { pub struct Config {
reply_surbs: config::ReplySurbs, min_surb_request_size: u32,
max_surb_request_size: u32,
maximum_allowed_reply_surb_request_size: u32,
max_surb_rerequest_waiting_period: Duration,
max_surb_drop_waiting_period: Duration,
max_reply_surb_age: Duration,
max_reply_key_age: Duration,
} }
impl Config { impl Config {
pub(crate) fn new(reply_surbs_cfg: config::ReplySurbs) -> Self { pub(crate) fn new(
min_surb_request_size: u32,
max_surb_request_size: u32,
maximum_allowed_reply_surb_request_size: u32,
max_surb_rerequest_waiting_period: Duration,
max_surb_drop_waiting_period: Duration,
max_reply_surb_age: Duration,
max_reply_key_age: Duration,
) -> Self {
Self { Self {
reply_surbs: reply_surbs_cfg, min_surb_request_size,
max_surb_request_size,
maximum_allowed_reply_surb_request_size,
max_surb_rerequest_waiting_period,
max_surb_drop_waiting_period,
max_reply_surb_age,
max_reply_key_age,
} }
} }
} }
@@ -492,17 +509,9 @@ where
} }
// 2. check whether the requested amount is within sane range // 2. check whether the requested amount is within sane range
if amount if amount > self.config.maximum_allowed_reply_surb_request_size {
> self warn!("The requested reply surb amount is larger than our maximum allowed ({amount} > {}). Lowering it to a more sane value...", self.config.maximum_allowed_reply_surb_request_size);
.config amount = self.config.maximum_allowed_reply_surb_request_size;
.reply_surbs
.maximum_allowed_reply_surb_request_size
{
warn!("The requested reply surb amount is larger than our maximum allowed ({amount} > {}). Lowering it to a more sane value...", self.config.reply_surbs.maximum_allowed_reply_surb_request_size);
amount = self
.config
.reply_surbs
.maximum_allowed_reply_surb_request_size;
} }
// 3. construct and send the surbs away // 3. construct and send the surbs away
@@ -512,11 +521,7 @@ where
let to_send = min(remaining, 100); let to_send = min(remaining, 100);
if let Err(err) = self if let Err(err) = self
.message_handler .message_handler
.try_send_additional_reply_surbs( .try_send_additional_reply_surbs(recipient, to_send)
recipient,
to_send,
nym_sphinx::params::PacketType::Mix,
)
.await .await
{ {
warn!("failed to send additional surbs to {recipient} - {err}"); warn!("failed to send additional surbs to {recipient} - {err}");
@@ -702,11 +707,8 @@ where
} }
let request_size = min( let request_size = min(
self.config.reply_surbs.maximum_reply_surb_request_size, self.config.max_surb_request_size,
max( max(total_queue, self.config.min_surb_request_size),
total_queue,
self.config.reply_surbs.minimum_reply_surb_request_size,
),
); );
if let Err(err) = self if let Err(err) = self
@@ -727,11 +729,7 @@ where
continue; continue;
} }
let Some(last_received) = self let Some(last_received) = self.full_reply_storage.surbs_storage_ref().surbs_last_received_at(pending_reply_target) else {
.full_reply_storage
.surbs_storage_ref()
.surbs_last_received_at(pending_reply_target)
else {
error!("we have {} pending replies for {pending_reply_target}, but we somehow never received any reply surbs from them!", vals.total_size()); error!("we have {} pending replies for {pending_reply_target}, but we somehow never received any reply surbs from them!", vals.total_size());
to_remove.push(*pending_reply_target); to_remove.push(*pending_reply_target);
continue; continue;
@@ -746,17 +744,9 @@ where
}; };
let diff = now - last_received_time; let diff = now - last_received_time;
let max_rerequest_wait = self
.config
.reply_surbs
.maximum_reply_surb_rerequest_waiting_period;
let max_drop_wait = self
.config
.reply_surbs
.maximum_reply_surb_drop_waiting_period;
if diff > max_rerequest_wait { if diff > self.config.max_surb_rerequest_waiting_period {
if diff > max_drop_wait { if diff > self.config.max_surb_drop_waiting_period {
to_remove.push(*pending_reply_target) to_remove.push(*pending_reply_target)
} else { } else {
debug!("We haven't received any surbs in {:?} from {pending_reply_target}. Going to explicitly ask for more", diff); debug!("We haven't received any surbs in {:?} from {pending_reply_target}. Going to explicitly ask for more", diff);
@@ -803,7 +793,7 @@ where
}; };
let diff = now - last_received_time; let diff = now - last_received_time;
if diff > self.config.reply_surbs.maximum_reply_surb_age { if diff > self.config.max_reply_surb_age {
info!("it's been {diff:?} since we last received any reply surb from {sender}. Going to remove all stored entries..."); info!("it's been {diff:?} since we last received any reply surb from {sender}. Going to remove all stored entries...");
to_remove_surbs.push(*sender); to_remove_surbs.push(*sender);
@@ -815,8 +805,7 @@ where
// this should never ever happen (famous last words, eh?), but in case it DOES happen eventually // this should never ever happen (famous last words, eh?), but in case it DOES happen eventually
// purge that malformed data // purge that malformed data
let Ok(sent_at) = OffsetDateTime::from_unix_timestamp(reply_key.sent_at_timestamp) let Ok(sent_at) = OffsetDateTime::from_unix_timestamp(reply_key.sent_at_timestamp) else {
else {
error!("somehow our stored timestamp ({}) for one of our reply key is corrupted!. Going to remove all the entry", reply_key.sent_at_timestamp); error!("somehow our stored timestamp ({}) for one of our reply key is corrupted!. Going to remove all the entry", reply_key.sent_at_timestamp);
to_remove_keys.push(*digest); to_remove_keys.push(*digest);
continue; continue;
@@ -824,7 +813,7 @@ where
let diff = now - sent_at; let diff = now - sent_at;
if diff > self.config.reply_surbs.maximum_reply_key_age { if diff > self.config.max_reply_key_age {
debug!("it's been {diff:?} since we created this reply key. it's probably never going to get used, so we're going to purge it..."); debug!("it's been {diff:?} since we created this reply key. it's probably never going to get used, so we're going to purge it...");
to_remove_keys.push(*digest); to_remove_keys.push(*digest);
} }
@@ -853,8 +842,7 @@ where
let mut stale_inspection = new_interval_stream(polling_rate); let mut stale_inspection = new_interval_stream(polling_rate);
// this is in the order of hours/days so we don't have to poll it that often // this is in the order of hours/days so we don't have to poll it that often
let polling_rate = let polling_rate = Duration::from_secs(self.config.max_reply_surb_age.as_secs() / 10);
Duration::from_secs(self.config.reply_surbs.maximum_reply_surb_age.as_secs() / 10);
let mut invalidation_inspection = new_interval_stream(polling_rate); let mut invalidation_inspection = new_interval_stream(polling_rate);
while !shutdown.is_shutdown() { while !shutdown.is_shutdown() {
@@ -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,
@@ -41,4 +55,8 @@ impl ReplyStorageBackend for Backend {
async fn load_surb_storage(&self) -> Result<CombinedReplyStorage, Self::StorageError> { async fn load_surb_storage(&self) -> Result<CombinedReplyStorage, Self::StorageError> {
self.empty.load_surb_storage().await self.empty.load_surb_storage().await
} }
fn get_inactive_storage(&self) -> Result<CombinedReplyStorage, Self::StorageError> {
self.empty.get_inactive_storage()
}
} }
@@ -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,
@@ -22,11 +23,49 @@ mod error;
mod manager; mod manager;
mod models; mod models;
#[derive(Debug)]
enum StorageManagerState {
Storage(StorageManager),
Inactive(InactiveMetadata),
}
// When the storage backaed is initialized as inactive, it will still contain metadata parameters
// that will be needed when the in-mem storage is fetched for use.
#[derive(Debug)]
struct InactiveMetadata {
pub minimum_reply_surb_storage_threshold: usize,
pub maximum_reply_surb_storage_threshold: usize,
}
impl StorageManagerState {
fn get(&self) -> &StorageManager {
match self {
StorageManagerState::Storage(manager) => manager,
StorageManagerState::Inactive(_) => {
panic!("tried to get storage of an inactive backend")
}
}
}
fn get_mut(&mut self) -> &mut StorageManager {
match self {
StorageManagerState::Storage(manager) => manager,
StorageManagerState::Inactive(_) => {
panic!("tried to get storage of an inactive backend")
}
}
}
fn is_active(&self) -> bool {
matches!(self, StorageManagerState::Storage(_))
}
}
#[derive(Debug)] #[derive(Debug)]
pub struct Backend { pub struct Backend {
temporary_old_path: Option<PathBuf>, temporary_old_path: Option<PathBuf>,
database_path: PathBuf, database_path: PathBuf,
manager: StorageManager, manager: StorageManagerState,
} }
impl Backend { impl Backend {
@@ -46,12 +85,26 @@ impl Backend {
let backend = Backend { let backend = Backend {
temporary_old_path: None, temporary_old_path: None,
database_path: owned_path, database_path: owned_path,
manager, manager: StorageManagerState::Storage(manager),
}; };
Ok(backend) Ok(backend)
} }
pub fn new_inactive(
minimum_reply_surb_storage_threshold: usize,
maximum_reply_surb_storage_threshold: usize,
) -> Self {
Backend {
temporary_old_path: None,
database_path: PathBuf::new(),
manager: StorageManagerState::Inactive(InactiveMetadata {
minimum_reply_surb_storage_threshold,
maximum_reply_surb_storage_threshold,
}),
}
}
pub async fn try_load<P: AsRef<Path>>(database_path: P) -> Result<Self, StorageError> { pub async fn try_load<P: AsRef<Path>>(database_path: P) -> Result<Self, StorageError> {
let owned_path: PathBuf = database_path.as_ref().into(); let owned_path: PathBuf = database_path.as_ref().into();
if owned_path.file_name().is_none() { if owned_path.file_name().is_none() {
@@ -123,13 +176,12 @@ impl Backend {
Ok(Backend { Ok(Backend {
temporary_old_path: None, temporary_old_path: None,
database_path: owned_path, database_path: owned_path,
// manager: StorageManagerState::Storage(manager), manager: StorageManagerState::Storage(manager),
manager,
}) })
} }
async fn close_pool(&mut self) { async fn close_pool(&mut self) {
self.manager.connection_pool.close().await; self.manager.get_mut().connection_pool.close().await;
} }
async fn rotate(&mut self) -> Result<(), StorageError> { async fn rotate(&mut self) -> Result<(), StorageError> {
@@ -148,8 +200,9 @@ impl Backend {
fs::rename(&self.database_path, &temp_old) fs::rename(&self.database_path, &temp_old)
.map_err(|err| StorageError::DatabaseRenameError { source: err })?; .map_err(|err| StorageError::DatabaseRenameError { source: err })?;
self.manager = StorageManager::init(&self.database_path, true).await?; self.manager =
self.manager.create_status_table().await?; StorageManagerState::Storage(StorageManager::init(&self.database_path, true).await?);
self.manager.get_mut().create_status_table().await?;
self.temporary_old_path = Some(temp_old); self.temporary_old_path = Some(temp_old);
Ok(()) Ok(())
@@ -166,26 +219,27 @@ impl Backend {
} }
async fn start_storage_flush(&self) -> Result<(), StorageError> { async fn start_storage_flush(&self) -> Result<(), StorageError> {
Ok(self.manager.set_flush_status(true).await?) Ok(self.manager.get().set_flush_status(true).await?)
} }
async fn end_storage_flush(&self) -> Result<(), StorageError> { async fn end_storage_flush(&self) -> Result<(), StorageError> {
self.manager self.manager
.get()
.set_previous_flush_timestamp(OffsetDateTime::now_utc().unix_timestamp()) .set_previous_flush_timestamp(OffsetDateTime::now_utc().unix_timestamp())
.await?; .await?;
Ok(self.manager.set_flush_status(false).await?) Ok(self.manager.get().set_flush_status(false).await?)
} }
async fn start_client_use(&self) -> Result<(), StorageError> { async fn start_client_use(&self) -> Result<(), StorageError> {
Ok(self.manager.set_client_in_use_status(true).await?) Ok(self.manager.get().set_client_in_use_status(true).await?)
} }
async fn stop_client_use(&self) -> Result<(), StorageError> { async fn stop_client_use(&self) -> Result<(), StorageError> {
Ok(self.manager.set_client_in_use_status(false).await?) Ok(self.manager.get().set_client_in_use_status(false).await?)
} }
async fn get_stored_tags(&self) -> Result<UsedSenderTags, StorageError> { async fn get_stored_tags(&self) -> Result<UsedSenderTags, StorageError> {
let stored = self.manager.get_tags().await?; let stored = self.manager.get().get_tags().await?;
// stop at the first instance of corruption. if even a single entry is malformed, // stop at the first instance of corruption. if even a single entry is malformed,
// something weird has happened and we can't trust the rest of the data // something weird has happened and we can't trust the rest of the data
@@ -201,6 +255,7 @@ impl Backend {
for map_ref in tags.as_raw_iter() { for map_ref in tags.as_raw_iter() {
let (recipient, tag) = map_ref.pair(); let (recipient, tag) = map_ref.pair();
self.manager self.manager
.get()
.insert_tag(StoredSenderTag::new(*recipient, *tag)) .insert_tag(StoredSenderTag::new(*recipient, *tag))
.await?; .await?;
} }
@@ -208,7 +263,7 @@ impl Backend {
} }
async fn get_stored_reply_keys(&self) -> Result<SentReplyKeys, StorageError> { async fn get_stored_reply_keys(&self) -> Result<SentReplyKeys, StorageError> {
let stored = self.manager.get_reply_keys().await?; let stored = self.manager.get().get_reply_keys().await?;
// stop at the first instance of corruption. if even a single entry is malformed, // stop at the first instance of corruption. if even a single entry is malformed,
// something weird has happened and we can't trust the rest of the data // something weird has happened and we can't trust the rest of the data
@@ -224,6 +279,7 @@ impl Backend {
for map_ref in reply_keys.as_raw_iter() { for map_ref in reply_keys.as_raw_iter() {
let (digest, key) = map_ref.pair(); let (digest, key) = map_ref.pair();
self.manager self.manager
.get()
.insert_reply_key(StoredReplyKey::new(*digest, *key)) .insert_reply_key(StoredReplyKey::new(*digest, *key))
.await?; .await?;
} }
@@ -231,7 +287,7 @@ impl Backend {
} }
async fn get_stored_reply_surbs(&self) -> Result<ReceivedReplySurbsMap, StorageError> { async fn get_stored_reply_surbs(&self) -> Result<ReceivedReplySurbsMap, StorageError> {
let surb_senders = self.manager.get_surb_senders().await?; let surb_senders = self.manager.get().get_surb_senders().await?;
let metadata = self.get_reply_surb_storage_metadata().await?; let metadata = self.get_reply_surb_storage_metadata().await?;
let mut received_surbs = Vec::with_capacity(surb_senders.len()); let mut received_surbs = Vec::with_capacity(surb_senders.len());
@@ -241,6 +297,7 @@ impl Backend {
sender.try_into()?; sender.try_into()?;
let stored_surbs = self let stored_surbs = self
.manager .manager
.get()
.get_reply_surbs(sender_id) .get_reply_surbs(sender_id)
.await? .await?
.into_iter() .into_iter()
@@ -268,6 +325,7 @@ impl Backend {
let (tag, received_surbs) = map_ref.pair(); let (tag, received_surbs) = map_ref.pair();
let sender_id = self let sender_id = self
.manager .manager
.get()
.insert_surb_sender(StoredSurbSender::new( .insert_surb_sender(StoredSurbSender::new(
*tag, *tag,
received_surbs.surbs_last_received_at(), received_surbs.surbs_last_received_at(),
@@ -276,6 +334,7 @@ impl Backend {
for reply_surb in received_surbs.surbs_ref() { for reply_surb in received_surbs.surbs_ref() {
self.manager self.manager
.get()
.insert_reply_surb(StoredReplySurb::new(sender_id, reply_surb)) .insert_reply_surb(StoredReplySurb::new(sender_id, reply_surb))
.await? .await?
} }
@@ -287,6 +346,7 @@ impl Backend {
&self, &self,
) -> Result<ReplySurbStorageMetadata, StorageError> { ) -> Result<ReplySurbStorageMetadata, StorageError> {
self.manager self.manager
.get()
.get_reply_surb_storage_metadata() .get_reply_surb_storage_metadata()
.await .await
.map_err(Into::into) .map_err(Into::into)
@@ -297,6 +357,7 @@ impl Backend {
reply_surbs: &ReceivedReplySurbsMap, reply_surbs: &ReceivedReplySurbsMap,
) -> Result<(), StorageError> { ) -> Result<(), StorageError> {
self.manager self.manager
.get()
.insert_reply_surb_storage_metadata(ReplySurbStorageMetadata::new( .insert_reply_surb_storage_metadata(ReplySurbStorageMetadata::new(
reply_surbs.min_surb_threshold(), reply_surbs.min_surb_threshold(),
reply_surbs.max_surb_threshold(), reply_surbs.max_surb_threshold(),
@@ -310,6 +371,24 @@ 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 {
self.manager.is_active()
}
async fn start_storage_session(&self) -> Result<(), Self::StorageError> { async fn start_storage_session(&self) -> Result<(), Self::StorageError> {
self.start_client_use().await self.start_client_use().await
} }
@@ -347,6 +426,18 @@ impl ReplyStorageBackend for Backend {
Ok(CombinedReplyStorage::load(reply_keys, reply_surbs, tags)) Ok(CombinedReplyStorage::load(reply_keys, reply_surbs, tags))
} }
fn get_inactive_storage(&self) -> Result<CombinedReplyStorage, Self::StorageError> {
match self.manager {
StorageManagerState::Storage(_) => {
panic!("tried to get inactive storage from an active storage backend")
}
StorageManagerState::Inactive(ref state) => Ok(CombinedReplyStorage::new(
state.minimum_reply_surb_storage_threshold,
state.maximum_reply_surb_storage_threshold,
)),
}
}
async fn stop_storage_session(self) -> Result<(), Self::StorageError> { async fn stop_storage_session(self) -> Result<(), Self::StorageError> {
self.stop_client_use().await self.stop_client_use().await
} }
@@ -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")]
@@ -26,19 +26,20 @@ pub struct Empty {
pub max_surb_threshold: usize, pub max_surb_threshold: usize,
} }
impl Default for Empty {
fn default() -> Self {
Empty {
min_surb_threshold: 20,
max_surb_threshold: 200,
}
}
}
#[async_trait] #[async_trait]
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,
@@ -59,12 +60,28 @@ impl ReplyStorageBackend for Empty {
self.max_surb_threshold, self.max_surb_threshold,
)) ))
} }
fn get_inactive_storage(&self) -> Result<CombinedReplyStorage, Self::StorageError> {
Ok(CombinedReplyStorage::new(
self.min_surb_threshold,
self.max_surb_threshold,
))
}
} }
#[async_trait] #[async_trait]
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 {
true
}
async fn start_storage_session(&self) -> Result<(), Self::StorageError> { async fn start_storage_session(&self) -> Result<(), Self::StorageError> {
Ok(()) Ok(())
} }
@@ -82,6 +99,11 @@ pub trait ReplyStorageBackend: Sized {
async fn load_surb_storage(&self) -> Result<CombinedReplyStorage, Self::StorageError>; async fn load_surb_storage(&self) -> Result<CombinedReplyStorage, Self::StorageError>;
/// In the case the storage backend is initialized in an inactive state (persisting data is
/// disabled), we might still need to fetch the (in-mem) storage and the parameters it was
/// created with.
fn get_inactive_storage(&self) -> Result<CombinedReplyStorage, Self::StorageError>;
async fn stop_storage_session(self) -> Result<(), Self::StorageError> { async fn stop_storage_session(self) -> Result<(), Self::StorageError> {
Ok(()) Ok(())
} }

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