Compare commits

..

1 Commits

Author SHA1 Message Date
serinko 7686c60333 DOC: smoosh-faq.md - quotation syntax fix 2023-09-19 16:46:43 +00:00
1094 changed files with 19356 additions and 52834 deletions
@@ -1,37 +0,0 @@
name: 'Install wasm-opt'
description: 'Installs wasm-opt from binaryen'
inputs:
version:
description: 'Version of wasm-opt to install'
default: '116'
runs:
using: 'composite'
steps:
- name: Check platform compatibility
run: |
if [[ "$(uname)" != "Linux" ]]; then
echo "Error: This action is only compatible with Linux."
exit 1
fi
shell: bash
- name: Download wasm-opt
run: |
set -e
SOURCE="https://github.com/WebAssembly/binaryen/releases/download/version_${{ inputs.version }}/binaryen-version_${{ inputs.version }}-x86_64-linux.tar.gz"
TEMP_ARCHIVE="$RUNNER_TEMP/binaryen-version_${{ inputs.version }}-x86_64-linux.tar.gz"
curl -L -o "$TEMP_ARCHIVE" "$SOURCE"
tar -xvzf $TEMP_ARCHIVE -C $RUNNER_TEMP
echo "$RUNNER_TEMP/binaryen-version_${{ inputs.version }}/bin" >> $GITHUB_PATH
shell: bash
id: install-binary
- name: Verify installation
run: |
if ! command -v wasm-opt &> /dev/null; then
echo "Error: wasm-opt binary was not installed successfully."
exit 1
fi
shell: bash
id: verify-installation
@@ -1,4 +1,4 @@
name: nightly-security-audit name: Daily security audit
on: on:
schedule: schedule:
@@ -26,7 +26,7 @@ jobs:
path: .github/workflows/support-files/notifications/deny.message path: .github/workflows/support-files/notifications/deny.message
notification: notification:
needs: cargo-deny needs: cargo-deny
runs-on: custom-linux runs-on: custom-runner-linux
steps: steps:
- name: Check out repository code - name: Check out repository code
uses: actions/checkout@v2 uses: actions/checkout@v2
@@ -1,11 +1,27 @@
name: ci-build-upload-binaries name: Build and upload binaries to CI
on: on:
workflow_dispatch: workflow_dispatch:
push:
paths:
- 'clients/**'
- 'common/**'
- 'contracts/**'
- 'explorer-api/**'
- 'gateway/**'
- 'integrations/**'
- 'mixnode/**'
- 'sdk/rust/nym-sdk/**'
- 'service-providers/**'
- 'nym-api/**'
- 'nym-outfox/**'
- 'tools/nym-cli/**'
- 'tools/ts-rs-cli/**'
pull_request: pull_request:
paths: paths:
- 'clients/**' - 'clients/**'
- 'common/**' - 'common/**'
- 'contracts/**'
- 'explorer-api/**' - 'explorer-api/**'
- 'gateway/**' - 'gateway/**'
- 'integrations/**' - 'integrations/**'
@@ -17,6 +33,9 @@ on:
- 'tools/nym-cli/**' - 'tools/nym-cli/**'
- 'tools/ts-rs-cli/**' - 'tools/ts-rs-cli/**'
env:
NETWORK: mainnet
jobs: jobs:
publish-nym: publish-nym:
strategy: strategy:
@@ -25,8 +44,6 @@ jobs:
platform: [ubuntu-20.04] platform: [ubuntu-20.04]
runs-on: ${{ matrix.platform }} runs-on: ${{ matrix.platform }}
env:
CARGO_TERM_COLOR: always
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
@@ -40,18 +57,33 @@ jobs:
echo $OUTPUT_DIR echo $OUTPUT_DIR
- name: Install Dependencies (Linux) - name: Install Dependencies (Linux)
run: sudo apt update && sudo apt install libudev-dev 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 protobuf-compiler
continue-on-error: true
- name: Install Rust stable - name: Install Rust stable
uses: actions-rs/toolchain@v1 uses: actions-rs/toolchain@v1
with: with:
toolchain: stable toolchain: 1.69.0
- name: Build all binaries - name: Build all binaries
uses: actions-rs/cargo@v1 uses: actions-rs/cargo@v1
with: with:
command: build command: build
args: --workspace --release args: --workspace --release --all
- name: Install Rust stable
uses: actions-rs/toolchain@v1
with:
toolchain: 1.69.0
target: wasm32-unknown-unknown
override: true
components: rustfmt, clippy
- name: Install wasm-opt
run: cargo install --version 0.112.0 wasm-opt
- name: Build release contracts
run: make contracts-wasm
- name: Prepare build output - name: Prepare build output
shell: bash shell: bash
@@ -67,6 +99,16 @@ jobs:
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/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/vesting_contract.wasm $OUTPUT_DIR
cp contracts/target/wasm32-unknown-unknown/release/nym_coconut_bandwidth.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/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
cp contracts/target/wasm32-unknown-unknown/release/nym_ephemera.wasm $OUTPUT_DIR
- name: Deploy branch to CI www - name: Deploy branch to CI www
continue-on-error: true continue-on-error: true
@@ -1,16 +1,16 @@
name: build-upload-binaries name: Build and upload binaries to artifact storage
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
env: env:
NETWORK: mainnet NETWORK: mainnet
jobs: jobs:
publish-nym: publish-nym:
@@ -20,8 +20,6 @@ jobs:
platform: [ubuntu-20.04] platform: [ubuntu-20.04]
runs-on: ${{ matrix.platform }} runs-on: ${{ matrix.platform }}
env:
CARGO_TERM_COLOR: always
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
@@ -1,14 +1,13 @@
name: ci-build-ts name: CI for ts-packages
on: on:
pull_request: push:
paths: paths:
- "ts-packages/**" - 'ts-packages/**'
- "sdk/typescript/**"
jobs: jobs:
build: build:
runs-on: ubuntu-20.04-16-core runs-on: custom-runner-linux
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- name: Install rsync - name: Install rsync
@@ -21,7 +20,7 @@ jobs:
- name: Setup yarn - name: Setup yarn
run: npm install -g yarn run: npm install -g yarn
- name: Build - name: Build
run: yarn && yarn build && yarn build:ci:storybook run: yarn && yarn build && yarn build:ci
- name: Deploy branch to CI www (storybook) - name: Deploy branch to CI www (storybook)
continue-on-error: true continue-on-error: true
uses: easingthemes/ssh-deploy@main uses: easingthemes/ssh-deploy@main
@@ -1,4 +1,4 @@
name: ci-build name: Continuous integration
on: on:
push: push:
@@ -37,22 +37,17 @@ on:
- 'tools/nym-nr-query/**' - 'tools/nym-nr-query/**'
- 'tools/ts-rs-cli/**' - 'tools/ts-rs-cli/**'
- 'Cargo.toml' - 'Cargo.toml'
workflow_dispatch:
jobs: jobs:
build: build:
strategy: runs-on: [ self-hosted, custom-linux ]
fail-fast: false # Enable sccache via environment variable
matrix:
os: [custom-linux, custom-runner-mac-m1]
runs-on: ${{ matrix.os }}
env: env:
CARGO_TERM_COLOR: always RUSTC_WRAPPER: /home/ubuntu/.cargo/bin/sccache
steps: steps:
- name: Install Dependencies (Linux) - name: Install Dependencies (Linux)
run: sudo apt-get update && sudo apt-get -y install libwebkit2gtk-4.0-dev build-essential curl wget libssl-dev libgtk-3-dev libudev-dev squashfs-tools protobuf-compiler 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 protobuf-compiler
continue-on-error: true continue-on-error: true
if: matrix.os == 'custom-linux'
- name: Check out repository code - name: Check out repository code
uses: actions/checkout@v2 uses: actions/checkout@v2
@@ -75,40 +70,36 @@ jobs:
uses: actions-rs/cargo@v1 uses: actions-rs/cargo@v1
with: with:
command: build command: build
# Enable wireguard by default on linux only args: --workspace
args: --workspace --features wireguard
- name: Build all examples - name: Build all examples
if: matrix.os == 'custom-linux'
uses: actions-rs/cargo@v1 uses: actions-rs/cargo@v1
with: with:
command: build command: build
args: --workspace --examples --features wireguard args: --workspace --examples
- name: Run all tests - name: Run all tests
if: matrix.os == 'custom-linux'
uses: actions-rs/cargo@v1 uses: actions-rs/cargo@v1
with: with:
command: test command: test
args: --workspace --features wireguard args: --workspace
- name: Run expensive tests - name: Run expensive tests
if: (github.ref == 'refs/heads/develop' || github.event.pull_request.base.ref == 'develop' || github.event.pull_request.base.ref == 'master') && matrix.os == 'custom-linux' if: github.ref == 'refs/heads/develop' || github.event.pull_request.base.ref == 'develop' || github.event.pull_request.base.ref == 'master'
uses: actions-rs/cargo@v1 uses: actions-rs/cargo@v1
with: with:
command: test command: test
args: --workspace --features wireguard -- --ignored args: --workspace -- --ignored
- name: Annotate with clippy checks - uses: actions-rs/clippy-check@v1
if: matrix.os == 'custom-linux' name: Clippy checks
uses: actions-rs/clippy-check@v1
continue-on-error: true continue-on-error: true
with: with:
token: ${{ secrets.GITHUB_TOKEN }} token: ${{ secrets.GITHUB_TOKEN }}
args: --workspace --features wireguard args: --workspace
- name: Clippy - name: Run clippy
uses: actions-rs/cargo@v1 uses: actions-rs/cargo@v1
with: with:
command: clippy command: clippy
args: --workspace --all-targets --features wireguard -- -D warnings args: --workspace --all-targets -- -D warnings
@@ -0,0 +1,19 @@
[
{
"os":"ubuntu-20.04",
"rust":"stable",
"runOnEvent":"always"
},
{
"os":"windows-latest",
"rust":"stable",
"runOnEvent":"pull_request"
},
{
"os":"macos-latest",
"rust":"stable",
"runOnEvent":"pull_request"
}
]
+28 -3
View File
@@ -1,14 +1,15 @@
name: cd-docs name: CD docs
on: on:
workflow_dispatch: workflow_dispatch:
push: push:
branches: master
paths: paths:
- 'documentation/docs/**' - 'documentation/docs/**'
jobs: jobs:
build: build:
runs-on: custom-linux runs-on: custom-runner-linux
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- name: Install rsync - name: Install rsync
@@ -25,7 +26,7 @@ jobs:
uses: actions-rs/cargo@v1 uses: actions-rs/cargo@v1
with: with:
command: build command: build
args: --workspace --release args: --workspace --release --all
- name: Install mdbook - name: Install mdbook
run: (test -x $HOME/.cargo/bin/mdbook || cargo install --vers "^0.4.33" mdbook) run: (test -x $HOME/.cargo/bin/mdbook || cargo install --vers "^0.4.33" mdbook)
- name: Install mdbook plugins - name: Install mdbook plugins
@@ -38,6 +39,30 @@ jobs:
run: cd documentation && ./build_all_to_dist.sh run: cd documentation && ./build_all_to_dist.sh
continue-on-error: false continue-on-error: false
- 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: "dist/docs/"
REMOTE_HOST: ${{ secrets.CD_WWW_REMOTE_HOST_DEV }}
REMOTE_USER: ${{ secrets.CD_WWW_REMOTE_USER }}
TARGET: ${{ secrets.CD_WWW_REMOTE_TARGET }}/
EXCLUDE: "/node_modules/"
- name: Deploy branch master to prod
if: github.ref == 'refs/heads/master'
uses: easingthemes/ssh-deploy@main
env:
SSH_PRIVATE_KEY: ${{ secrets.CD_WWW_SSH_PRIVATE_KEY }}
ARGS: "-rltgoDzvO --delete"
SOURCE: "dist/docs/"
REMOTE_HOST: ${{ secrets.CD_WWW_REMOTE_HOST_PROD }}
REMOTE_USER: ${{ secrets.CD_WWW_REMOTE_USER }}
TARGET: ${{ secrets.CD_WWW_REMOTE_TARGET }}/
EXCLUDE: "/node_modules/"
- name: Post process - name: Post process
run: cd documentation && ./post_process.sh run: cd documentation && ./post_process.sh
continue-on-error: false continue-on-error: false
@@ -1,7 +1,10 @@
name: ci-contracts-schema name: Check Contract Schema
on: on:
workflow_dispatch: push:
paths:
- 'contracts/**'
- 'common/**'
pull_request: pull_request:
paths: paths:
- 'contracts/**' - 'contracts/**'
@@ -10,9 +13,7 @@ on:
jobs: jobs:
check-schema: check-schema:
name: Generate and check schema name: Generate and check schema
runs-on: custom-linux runs-on: custom-runner-linux
env:
CARGO_TERM_COLOR: always
steps: steps:
- name: Check out repository code - name: Check out repository code
uses: actions/checkout@v2 uses: actions/checkout@v2
@@ -22,8 +23,9 @@ jobs:
with: with:
toolchain: stable toolchain: stable
- name: Generate the schema - name: Generate the schema
run: make contract-schema run: make contract-schema
- name: Check for diff - name: Check for diff
run: git diff --exit-code -- contracts/**/schema run: git diff --exit-code -- contracts/*/schema
@@ -1,4 +1,4 @@
name: nightly-check-merge-conflicts name: check-merge-conflicts
# Check that the latest release branch merges into master and develop without # Check that the latest release branch merges into master and develop without
# any conflicts that git is not able to resolve # any conflicts that git is not able to resolve
@@ -1,4 +1,4 @@
name: ci-binary-config-checker name: Run config checks on all binaries
on: on:
workflow_dispatch: workflow_dispatch:
@@ -31,8 +31,8 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
platform: [custom-linux] platform: [custom-runner-linux]
runs-on: ${{ matrix.platform }} runs-on: ${{ matrix.platform }}
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
@@ -45,12 +45,12 @@ jobs:
uses: actions-rs/toolchain@v1 uses: actions-rs/toolchain@v1
with: with:
toolchain: stable toolchain: stable
- name: Branch name - name: Branch name
run: echo running on branch ${GITHUB_REF##*/} run: echo running on branch ${GITHUB_REF##*/}
- name: Run tests against binaries - name: Run tests against binaries
run: ./build_and_run.sh ${{ github.head_ref || github.ref_name }} run: ./build_and_run.sh ${{ github.head_ref || github.ref_name }}
working-directory: tests/ working-directory: tests/
@@ -1,75 +0,0 @@
name: ci-contracts-upload-binaries
on:
workflow_dispatch:
pull_request:
paths:
- 'common/**'
- 'contracts/**'
env:
NETWORK: mainnet
jobs:
publish-nym-contracts:
strategy:
fail-fast: false
matrix:
platform: [ubuntu-20.04]
runs-on: ${{ matrix.platform }}
env:
CARGO_TERM_COLOR: always
steps:
- uses: actions/checkout@v3
- name: Prepare build output directory
shell: bash
env:
OUTPUT_DIR: ci-contract-builds/${{ github.ref_name }}
run: |
rm -rf ci-contract-builds || true
mkdir -p $OUTPUT_DIR
echo $OUTPUT_DIR
- name: Install Rust stable
uses: actions-rs/toolchain@v1
with:
toolchain: stable
target: wasm32-unknown-unknown
override: true
- name: Install wasm-opt
uses: ./.github/actions/install-wasm-opt
with:
version: '114'
- name: Build release contracts
run: make contracts
- name: Prepare build output
shell: bash
env:
OUTPUT_DIR: ci-contract-builds/${{ github.ref_name }}
run: |
cp contracts/target/wasm32-unknown-unknown/release/mixnet_contract.wasm $OUTPUT_DIR
cp contracts/target/wasm32-unknown-unknown/release/vesting_contract.wasm $OUTPUT_DIR
cp contracts/target/wasm32-unknown-unknown/release/nym_coconut_bandwidth.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/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
cp contracts/target/wasm32-unknown-unknown/release/nym_ephemera.wasm $OUTPUT_DIR
- name: Deploy branch to CI www
continue-on-error: true
uses: easingthemes/ssh-deploy@main
env:
SSH_PRIVATE_KEY: ${{ secrets.CI_WWW_SSH_PRIVATE_KEY }}
ARGS: "-avzr"
SOURCE: "ci-contract-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/"
+7 -12
View File
@@ -1,4 +1,4 @@
name: ci-docs name: CI docs
on: on:
workflow_dispatch: workflow_dispatch:
@@ -9,7 +9,7 @@ on:
jobs: jobs:
build: build:
runs-on: custom-linux runs-on: custom-runner-linux
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- name: Install rsync - name: Install rsync
@@ -26,22 +26,17 @@ jobs:
uses: actions-rs/cargo@v1 uses: actions-rs/cargo@v1
with: with:
command: build command: build
args: --workspace --release args: --workspace --release --all
- name: Install mdbook - name: Install mdbook
run: (test -x $HOME/.cargo/bin/mdbook || cargo install --vers "^0.4.35" mdbook) run: (test -x $HOME/.cargo/bin/mdbook || cargo install --vers "^0.4.33" mdbook)
- name: Install mdbook plugins - name: Install mdbook plugins
run: | run: |
cargo install --vers "=0.2.2" mdbook-variables && cargo install \ cargo install --vers "=0.2.2" mdbook-variables && cargo install \
--vers "^1.8.0" mdbook-admonish --force && cargo install --vers \ --vers "^1.8.0" mdbook-admonish && cargo install --vers \
"^0.1.2" mdbook-last-changed && cargo install --vers "^0.1.2" mdbook-theme \ "^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.7.7" mdbook-linkcheck
# && cd documentation \
# && mdbook-admonish install dev-portal \
# && mdbook-admonish install docs \
# && mdbook-admonish install operators
- name: Build all projects in documentation/ & move to ~/dist/docs/ - name: Build all projects in documentation/ & move to ~/dist/docs/
run: cd documentation && ./build_all_to_dist.sh run: cd documentation && ./build_all_to_dist.sh
continue-on-error: false continue-on-error: false
- name: Deploy branch to CI www - name: Deploy branch to CI www
continue-on-error: true continue-on-error: true
-40
View File
@@ -1,40 +0,0 @@
name: ci-nym-vpn-ui-js
on:
workflow_dispatch:
pull_request:
paths:
- 'nym-vpn/ui/src/**'
- 'nym-vpn/ui/package.json'
- 'nym-vpn/ui/index.html'
jobs:
check:
runs-on: custom-linux
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install Node
uses: actions/setup-node@v3
with:
node-version: 18
- name: Install Yarn
run: npm install -g yarn
- name: Install dependencies
working-directory: nym-vpn/ui
run: yarn
- name: Type-check
working-directory: nym-vpn/ui
run: yarn typecheck
- name: Check lint
working-directory: nym-vpn/ui
run: yarn lint
- name: Check formatting
working-directory: nym-vpn/ui
run: yarn fmt:check
# - name: Run tests
# working-directory: nym-vpn/ui
# run: yarn test
- name: Check build
working-directory: nym-vpn/ui
run: yarn build
-63
View File
@@ -1,63 +0,0 @@
name: ci-nym-vpn-ui-rust
on:
workflow_dispatch:
pull_request:
paths:
- 'nym-vpn/ui/src-tauri/**'
jobs:
build:
runs-on: custom-linux
env:
CARGO_TERM_COLOR: always
CARGOTOML_PATH: ./nym-vpn/ui/src-tauri/Cargo.toml
steps:
- name: Install Dependencies (Linux)
run: sudo apt-get update && sudo apt-get -y install libwebkit2gtk-4.0-dev build-essential curl wget libssl-dev libgtk-3-dev squashfs-tools libayatana-appindicator3-dev
continue-on-error: true
- name: Checkout
uses: actions/checkout@v4
- name: Install rust toolchain
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
override: true
components: rustfmt, clippy
- name: Prepare build
run: mkdir nym-vpn/ui/dist
- name: Build
uses: actions-rs/cargo@v1
with:
command: build
args: --manifest-path ${{ env.CARGOTOML_PATH }} --features custom-protocol
# - name: Run all tests
# uses: actions-rs/cargo@v1
# with:
# command: test
# args: --manifest-path ${{ env.CARGOTOML_PATH }}
- name: Check formatting
uses: actions-rs/cargo@v1
with:
command: fmt
args: --manifest-path ${{ env.CARGOTOML_PATH }} --all -- --check
- name: Annotate with clippy checks
uses: actions-rs/clippy-check@v1
continue-on-error: true
with:
token: ${{ secrets.GITHUB_TOKEN }}
args: --manifest-path ${{ env.CARGOTOML_PATH }} --all-features
- name: Clippy
uses: actions-rs/cargo@v1
with:
command: clippy
args: --manifest-path ${{ env.CARGOTOML_PATH }} --all-features --all-targets -- -D warnings
@@ -1,7 +1,7 @@
name: ci-nym-connect-desktop name: CI for nym-connect - Desktop
on: on:
pull_request: push:
paths: paths:
- 'nym-connect/desktop/**' - 'nym-connect/desktop/**'
@@ -11,7 +11,7 @@ defaults:
jobs: jobs:
build: build:
runs-on: custom-linux runs-on: custom-runner-linux
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- name: Install rsync - name: Install rsync
@@ -1,6 +1,16 @@
name: ci-nym-connect-desktop-rust name: Nym Connect - desktop (Rust)
on: on:
push:
paths:
- "nym-connect/desktop/src-tauri/**"
- "nym-connect/desktop/src-tauri/Cargo.toml"
- "clients/client-core/**"
- "clients/socks5/**"
- "common/**"
- "gateway/gateway-requests/**"
- "contracts/vesting/**"
- "nym-api/nym-api-requests/**"
pull_request: pull_request:
paths: paths:
- "nym-connect/desktop/src-tauri/**" - "nym-connect/desktop/src-tauri/**"
@@ -16,7 +26,7 @@ jobs:
build: build:
runs-on: [self-hosted, custom-linux] runs-on: [self-hosted, custom-linux]
env: env:
CARGO_TERM_COLOR: always RUSTC_WRAPPER: /home/ubuntu/.cargo/bin/sccache
steps: steps:
- name: Install Dependencies (Linux) - name: Install Dependencies (Linux)
run: sudo apt-get update && sudo apt-get -y install libwebkit2gtk-4.0-dev build-essential curl wget libssl-dev libgtk-3-dev squashfs-tools libayatana-appindicator3-dev run: sudo apt-get update && sudo apt-get -y install libwebkit2gtk-4.0-dev build-essential curl wget libssl-dev libgtk-3-dev squashfs-tools libayatana-appindicator3-dev
@@ -33,12 +43,6 @@ jobs:
override: true override: true
components: rustfmt, clippy components: rustfmt, clippy
- name: Check formatting
uses: actions-rs/cargo@v1
with:
command: fmt
args: --manifest-path nym-connect/desktop/Cargo.toml --all -- --check
- name: Build all binaries - name: Build all binaries
uses: actions-rs/cargo@v1 uses: actions-rs/cargo@v1
with: with:
@@ -51,6 +55,12 @@ jobs:
command: test command: test
args: --manifest-path nym-connect/desktop/Cargo.toml --workspace args: --manifest-path nym-connect/desktop/Cargo.toml --workspace
- name: Check formatting
uses: actions-rs/cargo@v1
with:
command: fmt
args: --manifest-path nym-connect/desktop/Cargo.toml --all -- --check
- uses: actions-rs/clippy-check@v1 - uses: actions-rs/clippy-check@v1
name: Clippy checks name: Clippy checks
continue-on-error: true continue-on-error: true
@@ -6,5 +6,9 @@
{ {
"rust":"beta", "rust":"beta",
"runOnEvent":"pull_request" "runOnEvent":"pull_request"
},
{
"rust":"nightly",
"runOnEvent":"pull_request"
} }
] ]
@@ -7,23 +7,23 @@ on:
jobs: jobs:
build: build:
if: ${{ (startsWith(github.ref, 'refs/tags/nym-contracts-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }} if: ${{ (startsWith(github.ref, 'refs/tags/nym-contracts-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
runs-on: [self-hosted, custom-ubuntu-20.04] runs-on: [self-hosted, custom-runner-linux]
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- name: Install Rust stable - name: Install Rust stable
uses: actions-rs/toolchain@v1 uses: actions-rs/toolchain@v1
with: with:
toolchain: stable toolchain: 1.69.0
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.114.0 wasm-opt run: cargo install --version 0.112.0 wasm-opt
- name: Build release contracts - name: Build release contracts
run: make contracts run: make contracts-wasm
- name: Upload Mixnet Contract Artifact - name: Upload Mixnet Contract Artifact
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v3
@@ -1,4 +1,4 @@
name: ci-contracts name: Contracts
on: on:
push: push:
@@ -6,7 +6,7 @@ on:
- 'contracts/**' - 'contracts/**'
- 'common/**' - 'common/**'
pull_request: pull_request:
paths: paths-ignore:
- 'contracts/**' - 'contracts/**'
- 'common/**' - 'common/**'
@@ -16,19 +16,18 @@ jobs:
outputs: outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }} matrix: ${{ steps.set-matrix.outputs.matrix }}
steps: steps:
# creates the matrix strategy from ci-contracts-matrix-includes.json # creates the matrix strategy from build_matrix_includes.json
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- id: set-matrix - id: set-matrix
uses: JoshuaTheMiller/conditional-build-matrix@main uses: JoshuaTheMiller/conditional-build-matrix@main
with: with:
inputFile: '.github/workflows/ci-contracts-matrix-includes.json' inputFile: '.github/workflows/contract_matrix_includes.json'
filter: '[?runOnEvent==`${{ github.event_name }}` || runOnEvent==`always`]' filter: '[?runOnEvent==`${{ github.event_name }}` || runOnEvent==`always`]'
build: contracts:
# since it's going to be compiled into wasm, there's absolutely # since it's going to be compiled into wasm, there's absolutely
# no point in running CI on different OS-es # no point in running CI on different OS-es
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
env: continue-on-error: ${{ matrix.rust == 'nightly' }}
CARGO_TERM_COLOR: always
needs: matrix_prep needs: matrix_prep
strategy: strategy:
fail-fast: false fail-fast: false
@@ -36,8 +35,7 @@ jobs:
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- name: Setup rust - uses: actions-rs/toolchain@v1
uses: actions-rs/toolchain@v1
with: with:
profile: minimal profile: minimal
toolchain: ${{ matrix.rust }} toolchain: ${{ matrix.rust }}
@@ -45,28 +43,25 @@ jobs:
override: true override: true
components: rustfmt, clippy components: rustfmt, clippy
- name: Build contracts - uses: actions-rs/cargo@v1
uses: actions-rs/cargo@v1
env: env:
RUSTFLAGS: '-C link-arg=-s' RUSTFLAGS: '-C link-arg=-s'
with: with:
command: build command: build
args: --manifest-path contracts/Cargo.toml --workspace --lib --target wasm32-unknown-unknown args: --manifest-path contracts/Cargo.toml --workspace --lib --target wasm32-unknown-unknown
- name: Run unit tests - uses: actions-rs/cargo@v1
uses: actions-rs/cargo@v1
with: with:
command: test command: test
args: --lib --manifest-path contracts/Cargo.toml args: --lib --manifest-path contracts/Cargo.toml
- name: Check formatting - uses: actions-rs/cargo@v1
uses: actions-rs/cargo@v1
with: with:
command: fmt command: fmt
args: --manifest-path contracts/Cargo.toml --all -- --check args: --manifest-path contracts/Cargo.toml --all -- --check
- name: Run clippy - uses: actions-rs/cargo@v1
uses: actions-rs/cargo@v1 if: ${{ matrix.rust != 'nightly' }}
with: with:
command: clippy command: clippy
args: --lib --manifest-path contracts/Cargo.toml --workspace --all-targets -- -D warnings args: --lib --manifest-path contracts/Cargo.toml --workspace --all-targets -- -D warnings
-43
View File
@@ -1,43 +0,0 @@
# Simple workflow for deploying static content to GitHub Pages
name: Deploy static content to Pages
on:
# Runs on pushes targeting the default branch
push:
branches: ["feature/ppa-repo"]
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
permissions:
contents: read
pages: write
id-token: write
# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.
concurrency:
group: "pages"
cancel-in-progress: false
jobs:
# Single deploy job since we're just deploying
deploy:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup Pages
uses: actions/configure-pages@v3
- name: Upload artifact
uses: actions/upload-pages-artifact@v2
with:
# Upload entire repository
path: './ppa'
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v2
+1 -1
View File
@@ -1,4 +1,4 @@
name: greetings name: Greetings
on: [pull_request_target, issues] on: [pull_request_target, issues]
@@ -1,4 +1,4 @@
name: ci-nym-network-explorer name: CI for Network Explorer
on: on:
workflow_dispatch: workflow_dispatch:
@@ -12,7 +12,7 @@ defaults:
jobs: jobs:
build: build:
runs-on: custom-linux runs-on: custom-runner-linux
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- name: Install rsync - name: Install rsync
-129
View File
@@ -1,129 +0,0 @@
name: nightly-build
on:
workflow_dispatch:
schedule:
- cron: '14 1 * * *'
jobs:
build:
strategy:
fail-fast: false
matrix:
rust: [stable, beta]
os: [ubuntu-20.04, windows-latest, macos-latest]
runs-on: ${{ matrix.os }}
env:
CARGO_TERM_COLOR: always
continue-on-error: true
steps:
- name: Check out repository code
uses: actions/checkout@v3
- name: Install Dependencies (Linux)
run: sudo apt-get update && sudo apt-get install -y build-essential curl wget libssl-dev libudev-dev squashfs-tools protobuf-compiler
if: matrix.os == 'ubuntu-20.04'
- name: Install Rust toolchain
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: ${{ matrix.rust }}
override: true
components: rustfmt, clippy
- name: Install Protoc
uses: arduino/setup-protoc@v2
if: matrix.os == 'macos-latest' || matrix.os == 'windows-latest'
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
- name: Check formatting
uses: actions-rs/cargo@v1
with:
command: fmt
args: --all -- --check
- name: Build binaries
uses: actions-rs/cargo@v1
with:
command: build
args: --release --workspace
- name: Build examples
uses: actions-rs/cargo@v1
with:
command: build
args: --release --workspace --examples
# To avoid running out of disk space, skip generating debug symbols
- name: Set debug to false (unix)
if: matrix.os == 'ubuntu-20.04' || matrix.os == 'macos-latest'
run: |
sed -i.bak 's/\[profile.dev\]/\[profile.dev\]\ndebug = false/' Cargo.toml
git diff
- name: Set debug to false (win)
if: matrix.os == 'windows-latest'
shell: pwsh
run: |
(Get-Content Cargo.toml) -replace '\[profile.dev\]', "`$&`ndebug = false" | Set-Content Cargo.toml
git diff
- name: Run unit tests
uses: actions-rs/cargo@v1
with:
command: test
args: --workspace
- name: Run slow unit tests
uses: actions-rs/cargo@v1
with:
command: test
args: --workspace -- --ignored
- name: Clean
uses: actions-rs/cargo@v1
with:
command: clean
- name: Clippy
uses: actions-rs/cargo@v1
with:
command: clippy
args: --workspace --all-targets -- -D warnings
notification:
needs: build
runs-on: custom-linux
steps:
- name: Collect jobs status
uses: technote-space/workflow-conclusion-action@v2
- name: Check out repository code
uses: actions/checkout@v3
- name: install npm
uses: actions/setup-node@v3
if: env.WORKFLOW_CONCLUSION == 'failure'
with:
node-version: 18
- name: Matrix - Node Install
if: env.WORKFLOW_CONCLUSION == 'failure'
run: npm install
working-directory: .github/workflows/support-files
- name: Matrix - Send Notification
if: env.WORKFLOW_CONCLUSION == 'failure'
env:
NYM_NOTIFICATION_KIND: nightly
NYM_PROJECT_NAME: "Nym nightly build"
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
GIT_COMMIT_MESSAGE: "${{ github.event.head_commit.message }}"
GIT_BRANCH: "${GITHUB_REF##*/}"
IS_SUCCESS: "${{ env.WORKFLOW_CONCLUSION == 'success' }}"
MATRIX_SERVER: "${{ secrets.MATRIX_SERVER }}"
MATRIX_ROOM: "${{ secrets.MATRIX_ROOM_NIGHTLY }}"
MATRIX_USER_ID: "${{ secrets.MATRIX_USER_ID }}"
MATRIX_TOKEN: "${{ secrets.MATRIX_TOKEN }}"
MATRIX_DEVICE_ID: "${{ secrets.MATRIX_DEVICE_ID }}"
uses: docker://keybaseio/client:stable-node
with:
args: .github/workflows/support-files/notifications/entry_point.sh
@@ -1,92 +0,0 @@
name: nightly-nym-connect-desktop-build
on:
workflow_dispatch:
schedule:
- cron: '14 1 * * *'
jobs:
build:
strategy:
fail-fast: false
matrix:
os: [ubuntu-20.04, macos-latest, windows-latest]
runs-on: ${{ matrix.os }}
env:
CARGO_TERM_COLOR: always
MANIFEST_PATH: --manifest-path nym-connect/desktop/Cargo.toml
continue-on-error: true
steps:
- name: Check out repository code
uses: actions/checkout@v3
- name: Install Dependencies (Linux)
run: sudo apt-get update && sudo apt-get install -y libwebkit2gtk-4.0-dev build-essential curl wget libssl-dev libgtk-3-dev squashfs-tools
if: matrix.os == 'ubuntu-20.04'
- name: Install rust toolchain
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
override: true
components: rustfmt, clippy
- name: Check formatting
uses: actions-rs/cargo@v1
with:
command: fmt
args: ${{ env.MANIFEST_PATH }} --all -- --check
- name: Build
uses: actions-rs/cargo@v1
with:
command: build
args: ${{ env.MANIFEST_PATH }} --release --workspace
- name: Unit tests
uses: actions-rs/cargo@v1
with:
command: test
args: ${{ env.MANIFEST_PATH }} --workspace
- name: Clippy
uses: actions-rs/cargo@v1
with:
command: clippy
args: ${{ env.MANIFEST_PATH }} --workspace --all-targets -- -D warnings
notification:
needs: build
runs-on: custom-linux
steps:
- name: Collect jobs status
uses: technote-space/workflow-conclusion-action@v2
- name: Check out repository code
uses: actions/checkout@v3
- name: install npm
uses: actions/setup-node@v3
if: env.WORKFLOW_CONCLUSION == 'failure'
with:
node-version: 18
- name: Matrix - Node Install
if: env.WORKFLOW_CONCLUSION == 'failure'
run: npm install
working-directory: .github/workflows/support-files
- name: Matrix - Send Notification
if: env.WORKFLOW_CONCLUSION == 'failure'
env:
NYM_NOTIFICATION_KIND: nightly
NYM_PROJECT_NAME: "nym-connect-desktop-nightly-build"
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
GIT_COMMIT_MESSAGE: "${{ github.event.head_commit.message }}"
GIT_BRANCH: "${GITHUB_REF##*/}"
IS_SUCCESS: "${{ env.WORKFLOW_CONCLUSION == 'success' }}"
MATRIX_SERVER: "${{ secrets.MATRIX_SERVER }}"
MATRIX_ROOM: "${{ secrets.MATRIX_ROOM_NIGHTLY }}"
MATRIX_USER_ID: "${{ secrets.MATRIX_USER_ID }}"
MATRIX_TOKEN: "${{ secrets.MATRIX_TOKEN }}"
MATRIX_DEVICE_ID: "${{ secrets.MATRIX_DEVICE_ID }}"
uses: docker://keybaseio/client:stable-node
with:
args: .github/workflows/support-files/notifications/entry_point.sh
@@ -1,92 +0,0 @@
name: nightly-nym-wallet-build
on:
workflow_dispatch:
schedule:
- cron: '14 1 * * *'
jobs:
build:
strategy:
fail-fast: false
matrix:
os: [ubuntu-20.04, macos-latest, windows-latest]
runs-on: ${{ matrix.os }}
env:
CARGO_TERM_COLOR: always
MANIFEST_PATH: --manifest-path nym-wallet/Cargo.toml
continue-on-error: true
steps:
- name: Check out repository code
uses: actions/checkout@v3
- name: Install Dependencies (Linux)
run: sudo apt-get update && sudo apt-get install -y libwebkit2gtk-4.0-dev build-essential curl wget libssl-dev libgtk-3-dev squashfs-tools
if: matrix.os == 'ubuntu-20.04'
- name: Install rust toolchain
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
override: true
components: rustfmt, clippy
- name: Check formatting
uses: actions-rs/cargo@v1
with:
command: fmt
args: ${{ env.MANIFEST_PATH }} --all -- --check
- name: Build
uses: actions-rs/cargo@v1
with:
command: build
args: ${{ env.MANIFEST_PATH }} --release --workspace
- name: Unit tests
uses: actions-rs/cargo@v1
with:
command: test
args: ${{ env.MANIFEST_PATH }} --workspace
- name: Clippy
uses: actions-rs/cargo@v1
with:
command: clippy
args: ${{ env.MANIFEST_PATH }} --workspace --all-targets -- -D warnings
notification:
needs: build
runs-on: custom-linux
steps:
- name: Collect jobs status
uses: technote-space/workflow-conclusion-action@v2
- name: Check out repository code
uses: actions/checkout@v3
- name: install npm
uses: actions/setup-node@v3
if: env.WORKFLOW_CONCLUSION == 'failure'
with:
node-version: 18
- name: Matrix - Node Install
if: env.WORKFLOW_CONCLUSION == 'failure'
run: npm install
working-directory: .github/workflows/support-files
- name: Matrix - Send Notification
if: env.WORKFLOW_CONCLUSION == 'failure'
env:
NYM_NOTIFICATION_KIND: nightly
NYM_PROJECT_NAME: "nym-wallet-nightly-build"
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
GIT_COMMIT_MESSAGE: "${{ github.event.head_commit.message }}"
GIT_BRANCH: "${GITHUB_REF##*/}"
IS_SUCCESS: "${{ env.WORKFLOW_CONCLUSION == 'success' }}"
MATRIX_SERVER: "${{ secrets.MATRIX_SERVER }}"
MATRIX_ROOM: "${{ secrets.MATRIX_ROOM_NIGHTLY }}"
MATRIX_USER_ID: "${{ secrets.MATRIX_USER_ID }}"
MATRIX_TOKEN: "${{ secrets.MATRIX_TOKEN }}"
MATRIX_DEVICE_ID: "${{ secrets.MATRIX_DEVICE_ID }}"
uses: docker://keybaseio/client:stable-node
with:
args: .github/workflows/support-files/notifications/entry_point.sh
+176
View File
@@ -0,0 +1,176 @@
name: Nightly builds
on:
schedule:
- cron: '14 1 * * *'
jobs:
matrix_prep:
runs-on: ubuntu-20.04
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
steps:
# creates the matrix strategy from nightly_build_matrix_includes.json
- uses: actions/checkout@v3
- id: set-matrix
uses: JoshuaTheMiller/conditional-build-matrix@main
with:
inputFile: '.github/workflows/nightly_build_matrix_includes.json'
filter: '[?runOnEvent==`${{ github.event_name }}` || runOnEvent==`always`]'
build:
needs: matrix_prep
strategy:
matrix: ${{fromJson(needs.matrix_prep.outputs.matrix)}}
runs-on: ${{ matrix.os }}
continue-on-error: ${{ matrix.rust == 'nightly' || matrix.rust == 'beta' || matrix.rust == 'stable' }}
steps:
- name: Install Dependencies (Linux)
run: sudo apt-get update && sudo apt-get install libwebkit2gtk-4.0-dev build-essential curl wget libssl-dev libgtk-3-dev libudev-dev squashfs-tools protobuf-compiler
continue-on-error: true
if: matrix.os == 'ubuntu-20.04'
- name: Check out repository code
uses: actions/checkout@v3
- name: Install rust toolchain
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: ${{ matrix.rust }}
override: true
components: rustfmt, clippy
- name: Check formatting
uses: actions-rs/cargo@v1
with:
command: fmt
args: --all -- --check
- name: Build all binaries
uses: actions-rs/cargo@v1
with:
command: build
args: --workspace
- name: Reclaim some disk space
uses: actions-rs/cargo@v1
if: ${{ matrix.os == 'windows-latest' || matrix.os == 'ubuntu-20.04' }}
with:
command: clean
- name: Build all examples
uses: actions-rs/cargo@v1
with:
command: build
args: --workspace --examples
- name: Reclaim some disk space
uses: actions-rs/cargo@v1
if: ${{ matrix.os == 'windows-latest' || matrix.os == 'ubuntu-20.04' }}
with:
command: clean
- name: Run all tests
uses: actions-rs/cargo@v1
with:
command: test
args: --workspace
- name: Reclaim some disk space
uses: actions-rs/cargo@v1
if: ${{ matrix.os == 'windows-latest' || matrix.os == 'ubuntu-20.04' }}
with:
command: clean
- name: Run expensive tests
if: github.ref == 'refs/heads/develop' || github.event.pull_request.base.ref == 'develop' || github.event.pull_request.base.ref == 'master'
uses: actions-rs/cargo@v1
with:
command: test
args: --workspace -- --ignored
- name: Reclaim some disk space
uses: actions-rs/cargo@v1
if: ${{ matrix.os == 'windows-latest' || matrix.os == 'ubuntu-20.04' }}
with:
command: clean
- uses: actions-rs/clippy-check@v1
name: Clippy checks
continue-on-error: true
with:
token: ${{ secrets.GITHUB_TOKEN }}
args: --workspace
- name: Run clippy
uses: actions-rs/cargo@v1
if: ${{ matrix.rust != 'nightly' }}
with:
command: clippy
args: --workspace --all-targets -- -D warnings
- name: Reclaim some disk space
uses: actions-rs/cargo@v1
if: ${{ matrix.os == 'windows-latest' || matrix.os == 'ubuntu-20.04' }}
with:
command: clean
# nym-wallet (the rust part)
- name: Build nym-wallet rust code
uses: actions-rs/cargo@v1
with:
command: build
args: --manifest-path nym-wallet/Cargo.toml --workspace
- name: Run nym-wallet tests
uses: actions-rs/cargo@v1
with:
command: test
args: --manifest-path nym-wallet/Cargo.toml --workspace
- name: Check nym-wallet formatting
uses: actions-rs/cargo@v1
with:
command: fmt
args: --manifest-path nym-wallet/Cargo.toml --all -- --check
- name: Run clippy for nym-wallet
uses: actions-rs/cargo@v1
if: ${{ matrix.rust != 'nightly' }}
with:
command: clippy
args: --manifest-path nym-wallet/Cargo.toml --workspace --all-targets -- -D warnings
notification:
needs: build
runs-on: custom-runner-linux
steps:
- name: Collect jobs status
uses: technote-space/workflow-conclusion-action@v2
- name: Check out repository code
uses: actions/checkout@v3
- name: install npm
uses: actions/setup-node@v3
if: env.WORKFLOW_CONCLUSION == 'failure'
with:
node-version: 18
- name: Matrix - Node Install
if: env.WORKFLOW_CONCLUSION == 'failure'
run: npm install
working-directory: .github/workflows/support-files
- name: Matrix - Send Notification
if: env.WORKFLOW_CONCLUSION == 'failure'
env:
NYM_NOTIFICATION_KIND: nightly
NYM_PROJECT_NAME: "Nym nightly build"
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
GIT_COMMIT_MESSAGE: "${{ github.event.head_commit.message }}"
GIT_BRANCH: "${GITHUB_REF##*/}"
IS_SUCCESS: "${{ env.WORKFLOW_CONCLUSION == 'success' }}"
MATRIX_SERVER: "${{ secrets.MATRIX_SERVER }}"
MATRIX_ROOM: "${{ secrets.MATRIX_ROOM_NIGHTLY }}"
MATRIX_USER_ID: "${{ secrets.MATRIX_USER_ID }}"
MATRIX_TOKEN: "${{ secrets.MATRIX_TOKEN }}"
MATRIX_DEVICE_ID: "${{ secrets.MATRIX_DEVICE_ID }}"
uses: docker://keybaseio/client:stable-node
with:
args: .github/workflows/support-files/notifications/entry_point.sh
@@ -0,0 +1,50 @@
[
{
"os":"ubuntu-20.04",
"rust":"stable",
"runOnEvent":"schedule"
},
{
"os":"windows10",
"rust":"stable",
"runOnEvent":"schedule"
},
{
"os":"macos-latest",
"rust":"stable",
"runOnEvent":"schedule"
},
{
"os":"ubuntu-20.04",
"rust":"beta",
"runOnEvent":"schedule"
},
{
"os":"windows10",
"rust":"beta",
"runOnEvent":"schedule"
},
{
"os":"macos-latest",
"rust":"beta",
"runOnEvent":"schedule"
},
{
"os":"ubuntu-20.04",
"rust":"nightly",
"runOnEvent":"schedule"
},
{
"os":"windows10",
"rust":"nightly",
"runOnEvent":"schedule"
},
{
"os":"macos-latest",
"rust":"nightly",
"runOnEvent":"schedule"
}
]
@@ -14,7 +14,7 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
platform: [macos-12-large] platform: [macos-latest]
runs-on: ${{ matrix.platform }} runs-on: ${{ matrix.platform }}
outputs: outputs:
@@ -14,7 +14,7 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
platform: [custom-ubuntu-20.04] platform: [custom-runner-linux]
runs-on: ${{ matrix.platform }} runs-on: ${{ matrix.platform }}
outputs: outputs:
@@ -20,7 +20,7 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
platform: [custom-ubuntu-20.04] platform: [custom-runner-linux]
runs-on: ${{ matrix.platform }} runs-on: ${{ matrix.platform }}
outputs: outputs:
@@ -14,7 +14,7 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
platform: [macos-12-large] platform: [macos-latest]
runs-on: ${{ matrix.platform }} runs-on: ${{ matrix.platform }}
outputs: outputs:
@@ -39,7 +39,6 @@ jobs:
env: env:
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }} APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }} KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
run: | run: |
# create variables # create variables
@@ -74,7 +73,6 @@ jobs:
ENABLE_CODE_SIGNING: ${{ secrets.APPLE_CERTIFICATE }} ENABLE_CODE_SIGNING: ${{ secrets.APPLE_CERTIFICATE }}
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }} APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_IDENTITY_ID }} APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_IDENTITY_ID }}
APPLE_ID: ${{ secrets.APPLE_ID }} APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }} APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
@@ -14,7 +14,7 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
platform: [custom-ubuntu-20.04] platform: [custom-runner-linux]
runs-on: ${{ matrix.platform }} runs-on: ${{ matrix.platform }}
outputs: outputs:
+32
View File
@@ -0,0 +1,32 @@
name: Release Nym Wallet
on:
workflow_dispatch:
inputs:
nym_wallet_version:
description: 'The version of the Nym Wallet to release'
default: '1.0.x'
required: true
type: string
jobs:
create-release:
strategy:
fail-fast: false
matrix:
platform: [ubuntu-20.04]
runs-on: ${{ matrix.platform }}
steps:
- uses: actions/checkout@v2
- name: Create release
uses: softprops/action-gh-release@v1
with:
body: >-
This is a pre-release
Download the wallet for your platform:
- [Linux](https://github.com/nymtech/nym/releases/download/nym-wallet-v${{ inputs.nym_wallet_version}}/nym-wallet_v${{ inputs.nym_wallet_version}}_amd64_ubuntu20.04.AppImage)
- [MacOS](https://github.com/nymtech/nym/releases/download/nym-wallet-v${{ inputs.nym_wallet_version}}/nym-wallet_v${{ inputs.nym_wallet_version}}_x64_macos_11.dmg)
- [Windows](https://github.com/nymtech/nym/releases/download/nym-wallet-v${{ inputs.nym_wallet_version}}/nym-wallet_v${{ inputs.nym_wallet_version}}_x64_windows.msi)
prerelease: true
name: Nym Wallet v${{ inputs.nym_wallet_version}}
tag_name: nym-wallet-v${{ inputs.nym_wallet_version}}
@@ -1,44 +1,35 @@
name: ci-nym-wallet-storybook name: Nym Wallet Storybook
on: on:
pull_request: push:
paths: paths:
- 'nym-wallet/**' - 'nym-wallet/**'
jobs: jobs:
build: build:
runs-on: custom-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: 18
- name: Setup yarn - name: Setup yarn
run: npm install -g yarn run: npm install -g yarn
- 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 wasm-pack - name: Install wasm-pack
run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh 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
run: yarn storybook:build run: yarn storybook:build
working-directory: ./nym-wallet working-directory: ./nym-wallet
- name: Deploy branch to CI www (storybook) - name: Deploy branch to CI www (storybook)
continue-on-error: true continue-on-error: true
uses: easingthemes/ssh-deploy@main uses: easingthemes/ssh-deploy@main
@@ -50,11 +41,9 @@ jobs:
REMOTE_USER: ${{ secrets.CI_WWW_REMOTE_USER }} REMOTE_USER: ${{ secrets.CI_WWW_REMOTE_USER }}
TARGET: ${{ secrets.CI_WWW_REMOTE_TARGET }}/wallet-${{ env.GITHUB_REF_SLUG }} TARGET: ${{ secrets.CI_WWW_REMOTE_TARGET }}/wallet-${{ env.GITHUB_REF_SLUG }}
EXCLUDE: "/dist/, /node_modules/" EXCLUDE: "/dist/, /node_modules/"
- name: 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
- name: Matrix - Send Notification - name: Matrix - Send Notification
env: env:
NYM_NOTIFICATION_KIND: nym-wallet NYM_NOTIFICATION_KIND: nym-wallet
+78
View File
@@ -0,0 +1,78 @@
name: Webdriverio tests for nym wallet
on:
push:
paths:
- "nym-wallet/**"
defaults:
run:
working-directory: nym-wallet
jobs:
test:
name: wallet tests
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v2
- name: Tauri dependencies
run: >
sudo apt-get update &&
sudo apt-get install -y
libgtk-3-dev
libgtksourceview-3.0-dev
webkit2gtk-4.0
libappindicator3-dev
webkit2gtk-driver
xvfb
continue-on-error: true
- name: Install minimal stable
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
- name: Node
uses: actions/setup-node@v3
with:
node-version: 18
- name: Install yarn for building application
run: yarn install
- name: Build application
run: yarn run webpack:build & yarn run tauri:build
- name: Check binary exists
run: |
cd target/release/
(test -f nym-wallet && echo nym binary exists) || echo wallet does not exist
- name: Install dependencies
run: yarn install
working-directory: nym-wallet/webdriver
- name: Remove existing user datafile
uses: JesseTG/rm@v1.0.2
with:
path: nym-wallet/webdriver/common/data/user-data.json
- name: Create user data json file
id: create-json
uses: jsdaniell/create-json@1.1.2
with:
name: "user-data.json"
json: ${{ secrets.WALLET_USERDATA }}
dir: "nym-wallet/webdriver/common/data/"
- name: Install tauri-driver
uses: actions-rs/cargo@v1
with:
command: install
args: tauri-driver
- name: Launch tests
run: xvfb-run yarn test:runall
working-directory: nym-wallet/webdriver
@@ -1,4 +1,4 @@
name: publish-nyms5-android-apk name: Nyms5 Android
# unsigned APKs only, supported archs: # unsigned APKs only, supported archs:
# - arm64-v8a (arm64) # - arm64-v8a (arm64)
# - x86_64 # - x86_64
@@ -12,7 +12,7 @@ on:
jobs: jobs:
build: build:
name: Build APK name: Build APK
runs-on: custom-ubuntu-20.04 runs-on: custom-runner-linux
env: env:
ANDROID_HOME: ${{ github.workspace }}/android-sdk ANDROID_HOME: ${{ github.workspace }}/android-sdk
NDK_VERSION: 25.2.9519653 NDK_VERSION: 25.2.9519653
@@ -94,7 +94,7 @@ jobs:
gh-release: gh-release:
name: Publish APK (GH release) name: Publish APK (GH release)
needs: build needs: build
runs-on: custom-linux runs-on: custom-runner-linux
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v3 uses: actions/checkout@v3
@@ -1,4 +1,4 @@
name: ci-nym-api-tests name: CI for Nym API Tests
on: on:
workflow_dispatch: workflow_dispatch:
@@ -16,10 +16,10 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- name: Install npm - name: Install npm
run: npm install run: npm install
- name: Node v18 - name: Node v18
uses: actions/setup-node@v3 uses: actions/setup-node@v3
with: with:
@@ -1,6 +1,10 @@
name: ci-sdk-docs-typescript name: Typescript SDK docs
on: on:
push:
paths:
- "sdk/typescript/**"
- "wasm/**"
pull_request: pull_request:
paths: paths:
- "sdk/typescript/**" - "sdk/typescript/**"
@@ -8,7 +12,7 @@ on:
jobs: jobs:
build: build:
runs-on: custom-linux runs-on: custom-runner-linux
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- name: Install rsync - name: Install rsync
@@ -30,14 +34,6 @@ jobs:
with: with:
go-version: '1.20' go-version: '1.20'
- name: Install wasm-pack
run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
- name: Install wasm-opt
uses: ./.github/actions/install-wasm-opt
with:
version: '116'
- name: Build branch WASM packages - name: Build branch WASM packages
run: make sdk-wasm-build run: make sdk-wasm-build
@@ -1,10 +1,10 @@
name: Publish Typescript SDK name: Publish SDK to NPM
on: on:
workflow_dispatch: workflow_dispatch:
jobs: jobs:
publish: publish:
runs-on: ubuntu-20.04-16-core runs-on: [custom-runner-linux]
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
@@ -12,7 +12,7 @@ jobs:
uses: actions/setup-node@v3 uses: actions/setup-node@v3
with: with:
node-version: 18 node-version: 18
registry-url: "https://registry.npmjs.org" registry-url: 'https://registry.npmjs.org'
- name: Setup yarn - name: Setup yarn
run: npm install -g yarn run: npm install -g yarn
@@ -25,26 +25,11 @@ jobs:
- name: Install wasm-pack - name: Install wasm-pack
run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
- name: Install wasm-opt
run: cargo install wasm-opt
- name: Set up Go
uses: actions/setup-go@v4
with:
go-version: "1.20"
- name: Install TinyGo
uses: acifani/setup-tinygo@v1
with:
tinygo-version: "0.27.0"
- name: Install dependencies - name: Install dependencies
run: yarn run: yarn
- name: Build WASM and Typescript SDK - name: Build and publish
run: yarn sdk:build
- name: Publish to NPM
env: env:
NODE_AUTH_TOKEN: ${{ secrets.NODE_AUTH_TOKEN }} NODE_AUTH_TOKEN: ${{ secrets.NODE_AUTH_TOKEN }}
run: ./sdk/typescript/scripts/publish.sh working-directory: ./sdk/typescript/packages/sdk
run: scripts/publish.sh
@@ -1,6 +1,15 @@
name: ci-lint-typescript name: CI for linting Typescript
on: on:
push:
paths:
- "ts-packages/**"
- "sdk/typescript/**"
- "nym-connect/desktop/src/**"
- "nym-connect/desktop/package.json"
- "nym-wallet/src/**"
- "nym-wallet/package.json"
- "explorer/**"
pull_request: pull_request:
paths: paths:
- "ts-packages/**" - "ts-packages/**"
@@ -13,7 +22,7 @@ on:
jobs: jobs:
build: build:
runs-on: ubuntu-20.04-16-core runs-on: custom-runner-linux
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- uses: rlespinasse/github-slug-action@v3.x - uses: rlespinasse/github-slug-action@v3.x
@@ -28,15 +37,9 @@ jobs:
uses: actions-rs/toolchain@v1 uses: actions-rs/toolchain@v1
with: with:
toolchain: stable toolchain: stable
- name: Install wasm-pack - name: Install wasm-pack
run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
- name: Install wasm-opt
uses: ./.github/actions/install-wasm-opt
with:
version: '116'
- name: Set up Go - name: Set up Go
uses: actions/setup-go@v4 uses: actions/setup-go@v4
with: with:
@@ -46,7 +49,7 @@ jobs:
run: yarn run: yarn
- name: Build packages - name: Build packages
run: yarn build:ci run: yarn build:ci:sdk
- name: Lint - name: Lint
run: yarn lint run: yarn lint
@@ -1,4 +1,4 @@
name: ci-nym-wallet-rust name: Nym Wallet (rust)
on: on:
push: push:
@@ -18,7 +18,7 @@ jobs:
build: build:
runs-on: [ self-hosted, custom-linux ] runs-on: [ self-hosted, custom-linux ]
env: env:
CARGO_TERM_COLOR: always RUSTC_WRAPPER: /home/ubuntu/.cargo/bin/sccache
steps: steps:
- name: Install Dependencies (Linux) - name: Install Dependencies (Linux)
run: sudo apt-get update && sudo apt-get -y install libwebkit2gtk-4.0-dev build-essential curl wget libssl-dev libgtk-3-dev squashfs-tools run: sudo apt-get update && sudo apt-get -y install libwebkit2gtk-4.0-dev build-essential curl wget libssl-dev libgtk-3-dev squashfs-tools
@@ -31,7 +31,7 @@ jobs:
uses: actions-rs/toolchain@v1 uses: actions-rs/toolchain@v1
with: with:
profile: minimal profile: minimal
toolchain: stable toolchain: 1.71.0
override: true override: true
components: rustfmt, clippy components: rustfmt, clippy
@@ -1,4 +1,4 @@
name: ci-sdk-wasm name: Wasm Client
on: on:
pull_request: pull_request:
@@ -9,16 +9,10 @@ on:
jobs: jobs:
wasm: wasm:
runs-on: [custom-linux] runs-on: ubuntu-20.04
env:
CARGO_TERM_COLOR: always
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- uses: actions/setup-node@v3
with:
node-version: 18
- uses: actions-rs/toolchain@v1 - uses: actions-rs/toolchain@v1
with: with:
profile: minimal profile: minimal
@@ -32,13 +26,12 @@ jobs:
with: with:
go-version: '1.20' go-version: '1.20'
- name: Install wasm-pack - name: Install wasm-pack
run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
- name: Install wasm-opt - name: Install wasm-opt
uses: ./.github/actions/install-wasm-opt run: cargo install wasm-opt
with:
version: '116'
- name: Install wasm-bindgen-cli - name: Install wasm-bindgen-cli
run: cargo install wasm-bindgen-cli run: cargo install wasm-bindgen-cli
+1 -3
View File
@@ -45,6 +45,4 @@ envs/qwerty.env
cpu-cycles/libcpucycles/build cpu-cycles/libcpucycles/build
foxyfox.env foxyfox.env
.next .next
ppa-private-key.b64
ppa-private-key.asc
-66
View File
@@ -4,72 +4,6 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
## [Unreleased] ## [Unreleased]
## [2023.nyxd-upgrade] (2023-11-22)
- Chore/nyxd 043 upgrade ([#3968])
[#3968]: https://github.com/nymtech/nym/pull/3968
## [2023.4-galaxy] (2023-11-07)
- DRY up client cli ([#4077])
- [mixnode] replace rocket with axum ([#4071])
- incorporate the nym node HTTP api into the mixnode ([#4070])
- replaced '--disable-sign-ext' with '--signext-lowering' when running wasm-opt ([#3896])
- Added PPA repo hosting support and nym-mixnode package with tooling for publishing ([#4165])
[#4077]: https://github.com/nymtech/nym/pull/4077
[#4071]: https://github.com/nymtech/nym/pull/4071
[#4070]: https://github.com/nymtech/nym/issues/4070
[#3896]: https://github.com/nymtech/nym/pull/3896
[#4165]: https://github.com/nymtech/nym/pull/4165
## [2023.3-kinder] (2023-10-31)
- suppress error output ([#4056])
- Update frontend type for current vesting period ([#4042])
- re-exported additional types for tx queries ([#4036])
- fixed fmt::Display impl for GatewayNetworkRequesterDetails ([#4033])
- Add exit node policy from TorNull and Tor Exit Node Policy ([#4024])
- basic self-described api for gateways to dynamically announce its details + nym-api aggregation ([#4017])
- use saturating sub in case outfox is not enabled ([#3986])
- Fix sorting for mixnodes and gateways ([#3985])
- Gateway client registry and api routes ([#3955])
- Feature/configurable socks5 bind address ([#3992])
[#4056]: https://github.com/nymtech/nym/pull/4056
[#4042]: https://github.com/nymtech/nym/pull/4042
[#4036]: https://github.com/nymtech/nym/pull/4036
[#4033]: https://github.com/nymtech/nym/pull/4033
[#4024]: https://github.com/nymtech/nym/issues/4024
[#4017]: https://github.com/nymtech/nym/issues/4017
[#3986]: https://github.com/nymtech/nym/pull/3986
[#3985]: https://github.com/nymtech/nym/pull/3985
[#3955]: https://github.com/nymtech/nym/pull/3955
[#3992]: https://github.com/nymtech/nym/pull/3992
## [2023.1-milka] (2023-09-24)
- custom Debug impl for mix::Node and gateway::Node ([#3930])
- added forceTls argument to 'MixFetchOptsSimple' ([#3907])
- Enable loop cover traffic by default in NR ([#3904])
- Fix all the cargo warnings ([#3899])
- [Issue] nym-socks5-client crash on UDP request ([#3898])
- Feature/gateway inbuilt nr ([#3877])
- removed queued mixnet migration that was already run ([#3872])
- [feat] Socks5 and Native client: run with hardcoded topology ([#3866])
- Introduce a local network requester directly inside a gateway ([#3838])
[#3930]: https://github.com/nymtech/nym/pull/3930
[#3907]: https://github.com/nymtech/nym/pull/3907
[#3904]: https://github.com/nymtech/nym/pull/3904
[#3899]: https://github.com/nymtech/nym/pull/3899
[#3898]: https://github.com/nymtech/nym/issues/3898
[#3877]: https://github.com/nymtech/nym/pull/3877
[#3872]: https://github.com/nymtech/nym/pull/3872
[#3866]: https://github.com/nymtech/nym/pull/3866
[#3838]: https://github.com/nymtech/nym/issues/3838
## [v1.1.31-kitkat] (2023-09-12) ## [v1.1.31-kitkat] (2023-09-12)
- feat: add name to `TaskClient` ([#3844]) - feat: add name to `TaskClient` ([#3844])
Generated
+1108 -1197
View File
File diff suppressed because it is too large Load Diff
+24 -72
View File
@@ -46,10 +46,8 @@ members = [
"common/crypto", "common/crypto",
"common/dkg", "common/dkg",
"common/execute", "common/execute",
"common/exit-policy", "common/http-requests",
"common/http-api-client",
"common/inclusion-probability", "common/inclusion-probability",
"common/ip-packet-requests",
"common/ledger", "common/ledger",
"common/mixnode-common", "common/mixnode-common",
"common/network-defaults", "common/network-defaults",
@@ -75,13 +73,11 @@ members = [
"common/store-cipher", "common/store-cipher",
"common/task", "common/task",
"common/topology", "common/topology",
"common/tun",
"common/types", "common/types",
"common/wasm/client-core", "common/wasm/client-core",
"common/wasm/storage", "common/wasm/storage",
"common/wasm/utils", "common/wasm/utils",
"common/wireguard", "common/wireguard",
"common/wireguard-types",
"explorer-api", "explorer-api",
"explorer-api/explorer-api-requests", "explorer-api/explorer-api-requests",
"explorer-api/explorer-client", "explorer-api/explorer-client",
@@ -92,14 +88,11 @@ members = [
"sdk/lib/socks5-listener", "sdk/lib/socks5-listener",
"sdk/rust/nym-sdk", "sdk/rust/nym-sdk",
"service-providers/common", "service-providers/common",
"service-providers/ip-packet-router",
"service-providers/network-requester", "service-providers/network-requester",
"service-providers/network-statistics", "service-providers/network-statistics",
"nym-api", "nym-api",
"nym-browser-extension/storage", "nym-browser-extension/storage",
"nym-api/nym-api-requests", "nym-api/nym-api-requests",
"nym-node",
"nym-node/nym-node-requests",
"nym-outfox", "nym-outfox",
"tools/internal/ssl-inject", "tools/internal/ssl-inject",
"tools/internal/sdk-version-bump", "tools/internal/sdk-version-bump",
@@ -107,7 +100,7 @@ members = [
"tools/nym-nr-query", "tools/nym-nr-query",
"tools/ts-rs-cli", "tools/ts-rs-cli",
"wasm/client", "wasm/client",
# "wasm/full-nym-wasm", "wasm/full-nym-wasm",
"wasm/mix-fetch", "wasm/mix-fetch",
"wasm/node-tester", "wasm/node-tester",
] ]
@@ -123,7 +116,7 @@ default-members = [
"explorer-api", "explorer-api",
] ]
exclude = ["explorer", "contracts", "nym-wallet", "nym-connect/mobile/src-tauri", "nym-connect/desktop", "nym-vpn/ui/src-tauri", "cpu-cycles"] exclude = ["explorer", "contracts", "nym-wallet", "nym-connect/mobile/src-tauri", "nym-connect/desktop", "cpu-cycles"]
[workspace.package] [workspace.package]
authors = ["Nym Technologies SA"] authors = ["Nym Technologies SA"]
@@ -136,41 +129,8 @@ license = "Apache-2.0"
[workspace.dependencies] [workspace.dependencies]
anyhow = "1.0.71" anyhow = "1.0.71"
async-trait = "0.1.68" async-trait = "0.1.68"
axum = "0.6.20"
base64 = "0.21.4"
bip39 = { version = "2.0.0", features = ["zeroize"] } bip39 = { version = "2.0.0", features = ["zeroize"] }
boringtun = { git = "https://github.com/cloudflare/boringtun", rev = "e1d6360d6ab4529fc942a078e4c54df107abe2ba" }
clap = "4.4.7"
cfg-if = "1.0.0" cfg-if = "1.0.0"
dashmap = "5.5.3"
dotenvy = "0.15.6"
futures = "0.3.28"
generic-array = "0.14.7"
getrandom = "0.2.10"
hyper = "0.14.27"
k256 = "0.13"
lazy_static = "1.4.0"
log = "0.4"
once_cell = "1.7.2"
parking_lot = "0.12.1"
rand = "0.8.5"
reqwest = "0.11.22"
schemars = "0.8.1"
serde = "1.0.152"
serde_json = "1.0.91"
tap = "1.0.1"
thiserror = "1.0.48"
tokio = "1.24.1"
tokio-tungstenite = "0.20.1"
tracing = "0.1.37"
tungstenite = { version = "0.20.1", default-features = false }
ts-rs = "7.0.0"
utoipa = "3.5.0"
utoipa-swagger-ui = "3.1.5"
url = "2.4"
zeroize = "1.6.0"
# cosmwasm-related
cosmwasm-derive = "=1.3.0" cosmwasm-derive = "=1.3.0"
cosmwasm-schema = "=1.3.0" cosmwasm-schema = "=1.3.0"
cosmwasm-std = "=1.3.0" cosmwasm-std = "=1.3.0"
@@ -178,19 +138,33 @@ cosmwasm-std = "=1.3.0"
# (and ideally we don't want to pull the same dependency twice) # (and ideally we don't want to pull the same dependency twice)
serde-json-wasm = "=0.5.0" serde-json-wasm = "=0.5.0"
cosmwasm-storage = "=1.3.0" cosmwasm-storage = "=1.3.0"
# same version as used by cosmwasm cosmrs = "=0.14.0"
# same version as used by cosmrs
cw-utils = "=1.0.1" cw-utils = "=1.0.1"
cw-storage-plus = "=1.1.0" cw-storage-plus = "=1.1.0"
cw2 = { version = "=1.1.0" } cw2 = { version = "=1.1.0" }
cw3 = { version = "=1.1.0" } cw3 = { version = "=1.1.0" }
cw4 = { version = "=1.1.0" } cw4 = { version = "=1.1.0" }
cw-controllers = { version = "=1.1.0" } cw-controllers = { version = "=1.1.0" }
dotenvy = "0.15.6"
# cosmrs-related futures = "0.3.28"
bip32 = "0.5.1" generic-array = "0.14.7"
cosmrs = "=0.15.0" getrandom = "0.2.10"
tendermint-rpc = "0.34" # same version as used by cosmrs k256 = "0.13"
prost = "0.12" lazy_static = "1.4.0"
log = "0.4"
once_cell = "1.7.2"
rand = "0.8.5"
reqwest = "0.11.18"
serde = "1.0.152"
serde_json = "1.0.91"
tap = "1.0.1"
tendermint-rpc = "0.32" # same version as used by cosmrs
thiserror = "1.0.38"
tokio = "1.24.1"
ts-rs = "7.0.0"
url = "2.4"
zeroize = "1.6.0"
# wasm-related dependencies # wasm-related dependencies
gloo-utils = "0.1.7" gloo-utils = "0.1.7"
@@ -201,25 +175,3 @@ wasm-bindgen = "0.2.86"
wasm-bindgen-futures = "0.4.37" wasm-bindgen-futures = "0.4.37"
wasmtimer = "0.2.0" wasmtimer = "0.2.0"
web-sys = "0.3.63" web-sys = "0.3.63"
# Profile settings for individual crates
[profile.release.package.nym-socks5-listener]
strip = true
codegen-units = 1
[profile.release.package.nym-client-wasm]
# lto = true
opt-level = 'z'
[profile.release.package.nym-node-tester-wasm]
# lto = true
opt-level = 'z'
[profile.release.package.nym-wasm-sdk]
# lto = true
opt-level = 'z'
[profile.release.package.mix-fetch-wasm]
# lto = true
opt-level = 'z'
+131 -109
View File
@@ -1,85 +1,76 @@
# Top-level Makefile for the nym monorepo # Default target
# Default target. Probably what you want to run in normal day-to-day usage when
# you want to check all backend code in one step.
all: test all: test
help: test: clippy-all cargo-test contracts-wasm sdk-wasm-test fmt
@echo "The main targets are"
@echo " all: the default target. Alias for test"
@echo " build: build all binaries"
@echo " build-release: build platform binaries and contracts in release mode"
@echo " clippy: run clippy for all workspaces"
@echo " test: run clippy, unit tests, and formatting."
@echo " test-all: like test, but also includes the expensive tests"
# -----------------------------------------------------------------------------
# Meta targets
# -----------------------------------------------------------------------------
# Run clippy for all workspaces, run all tests, format all Rust code
test: clippy cargo-test fmt
# Same as test, but also runs slow tests
test-all: test cargo-test-expensive test-all: test cargo-test-expensive
# Build release binaries for the main workspace (platform binaries) and the no-clippy: build cargo-test contracts-wasm fmt fmt-browser-extension-storage
# contracts, including running wasm-opt.
# Producing release versions of other components is deferred to their
# respective toolchains.
build-release: build-release-main contracts
# Not a meta target, more of a top-level target for building all binaries (in happy: fmt clippy-happy test
# debug mode). Listed here for visibility. The deps are appended successively
build:
# Not a meta target, more of a top-level target for clippy. Listed here for build: sdk-wasm-build build-browser-extension-storage
# visibility. The deps are appended successively.
clippy: # Building release binaries is a little manual as we can't just build --release
# on all workspaces.
build-release: build-release-main contracts-wasm
clippy: sdk-wasm-lint clippy-browser-extension-storage
# Deprecated
# For backwards compatibility
clippy-all: clippy
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
# Define targets for a given workspace # Define targets for a given workspace
# $(1): name # $(1): name
# $(2): path to workspace # $(2): path to workspace
# $(3): extra arguments to cargo # $(3): extra arguments to cargo
# $(4): RUSTFLAGS prefix env
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
define add_cargo_workspace define add_cargo_workspace
clippy-happy-$(1):
cargo clippy --manifest-path $(2)/Cargo.toml $(3)
clippy-$(1):
cargo clippy --manifest-path $(2)/Cargo.toml --workspace $(3) -- -D warnings
clippy-examples-$(1):
cargo clippy --manifest-path $(2)/Cargo.toml --workspace --examples -- -D warnings
check-$(1): check-$(1):
cargo check --manifest-path $(2)/Cargo.toml --workspace $(3) cargo check --manifest-path $(2)/Cargo.toml --workspace $(3)
build-$(1):
cargo build --manifest-path $(2)/Cargo.toml --workspace $(3)
build-extra-$(1):
cargo build --manifest-path $(2)/Cargo.toml --workspace --examples --tests
build-release-$(1):
$(4) cargo $$($(1)_BUILD_RELEASE_TOOLCHAIN) build --manifest-path $(2)/Cargo.toml --workspace --release $(3)
test-$(1): test-$(1):
cargo test --manifest-path $(2)/Cargo.toml --workspace cargo test --manifest-path $(2)/Cargo.toml --workspace
test-expensive-$(1): test-expensive-$(1):
cargo test --manifest-path $(2)/Cargo.toml --workspace -- --ignored cargo test --manifest-path $(2)/Cargo.toml --workspace -- --ignored
clippy-$(1): build-standalone-$(1):
cargo $$($(1)_CLIPPY_TOOLCHAIN) clippy --manifest-path $(2)/Cargo.toml --workspace $(3) -- -D warnings cargo build --manifest-path $(2)/Cargo.toml $(3)
clippy-extra-$(1): build-$(1):
cargo $$($(1)_CLIPPY_TOOLCHAIN) clippy --manifest-path $(2)/Cargo.toml --workspace --examples --tests -- -D warnings cargo build --manifest-path $(2)/Cargo.toml --workspace $(3)
build-examples-$(1):
cargo build --manifest-path $(2)/Cargo.toml --workspace --examples
build-release-$(1):
cargo build --manifest-path $(2)/Cargo.toml --workspace --release $(3)
fmt-$(1): fmt-$(1):
cargo fmt --manifest-path $(2)/Cargo.toml --all cargo fmt --manifest-path $(2)/Cargo.toml --all
clippy-happy: clippy-happy-$(1)
clippy: clippy-$(1) clippy-examples-$(1)
check: check-$(1) check: check-$(1)
build: build-$(1) build-extra-$(1)
build-release-all: build-release-$(1)
cargo-test: test-$(1) cargo-test: test-$(1)
cargo-test-expensive: test-expensive-$(1) cargo-test-expensive: test-expensive-$(1)
clippy: clippy-$(1) clippy-extra-$(1) build: build-$(1) build-examples-$(1)
build-release-all: build-release-$(1)
fmt: fmt-$(1) fmt: fmt-$(1)
endef endef
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
@@ -89,64 +80,11 @@ endef
# Generate targets for the various cargo workspaces # Generate targets for the various cargo workspaces
$(eval $(call add_cargo_workspace,main,.)) $(eval $(call add_cargo_workspace,main,.))
$(eval $(call add_cargo_workspace,contracts,contracts,--lib --target wasm32-unknown-unknown,RUSTFLAGS='-C link-arg=-s')) $(eval $(call add_cargo_workspace,contracts,contracts,--lib --target wasm32-unknown-unknown))
$(eval $(call add_cargo_workspace,wallet,nym-wallet)) #$(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)) $(eval $(call add_cargo_workspace,connect,nym-connect/desktop))
# -----------------------------------------------------------------------------
# SDK
# -----------------------------------------------------------------------------
sdk-wasm: sdk-wasm-build sdk-wasm-test sdk-wasm-lint
sdk-wasm-build:
$(MAKE) -C nym-browser-extension/storage wasm-pack
$(MAKE) -C wasm/client
$(MAKE) -C wasm/node-tester
$(MAKE) -C wasm/mix-fetch
#$(MAKE) -C wasm/full-nym-wasm
# run this from npm/yarn to ensure tools are in the path, e.g. yarn build:sdk from root of repo
sdk-typescript-build:
npx lerna run --scope @nymproject/sdk build --stream
npx lerna run --scope @nymproject/mix-fetch build --stream
npx lerna run --scope @nymproject/node-tester build --stream
yarn --cwd sdk/typescript/codegen/contract-clients build
# NOTE: These targets are part of the main workspace (but not as wasm32-unknown-unknown)
WASM_CRATES = extension-storage nym-client-wasm nym-node-tester-wasm
sdk-wasm-test:
#cargo test $(addprefix -p , $(WASM_CRATES)) --target wasm32-unknown-unknown -- -Dwarnings
sdk-wasm-lint:
cargo clippy $(addprefix -p , $(WASM_CRATES)) --target wasm32-unknown-unknown -- -Dwarnings
$(MAKE) -C wasm/mix-fetch check-fmt
# Add to top-level targets
build: sdk-wasm-build
cargo-test: sdk-wasm-test
clippy: sdk-wasm-lint
# -----------------------------------------------------------------------------
# Build contracts ready for deploy
# -----------------------------------------------------------------------------
CONTRACTS=vesting_contract mixnet_contract nym_service_provider_directory nym_name_service
CONTRACTS_WASM=$(addsuffix .wasm, $(CONTRACTS))
CONTRACTS_OUT_DIR=contracts/target/wasm32-unknown-unknown/release
contracts: build-release-contracts wasm-opt-contracts
wasm-opt-contracts:
for contract in $(CONTRACTS_WASM); do \
wasm-opt --signext-lowering -Os $(CONTRACTS_OUT_DIR)/$$contract -o $(CONTRACTS_OUT_DIR)/$$contract; \
done
# Consider adding 's' to make plural consistent (beware: used in github workflow)
contract-schema:
$(MAKE) -C contracts schema
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
# Convenience targets for crates that are already part of the main workspace # Convenience targets for crates that are already part of the main workspace
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
@@ -157,18 +95,102 @@ build-explorer-api:
build-nym-cli: build-nym-cli:
cargo build -p nym-cli --release cargo build -p nym-cli --release
build-browser-extension-storage:
cargo build -p extension-storage --target wasm32-unknown-unknown
fmt-browser-extension-storage:
cargo fmt -p extension-storage -- --check
clippy-browser-extension-storage:
cargo clippy -p extension-storage --target wasm32-unknown-unknown -- -Dwarnings
sdk-wasm: sdk-wasm-build sdk-wasm-test sdk-wasm-lint
sdk-wasm-build:
# browser storage
$(MAKE) -C nym-browser-extension/storage wasm-pack
# client
$(MAKE) -C wasm/client build
# node-tester
$(MAKE) -C wasm/node-tester build
# mix-fetch
$(MAKE) -C wasm/mix-fetch build
# full
$(MAKE) -C wasm/full-nym-wasm build-full
# run this from npm/yarn to ensure tools are in the path, e.g. yarn build:sdk from root of repo
sdk-typescript-build:
lerna run --scope @nymproject/sdk build --stream
lerna run --scope @nymproject/mix-fetch build --stream
lerna run --scope @nymproject/node-tester build --stream
sdk-wasm-test:
# # client
# cargo test -p nym-client-wasm --target wasm32-unknown-unknown
#
# # node-tester
# cargo test -p nym-node-tester-wasm --target wasm32-unknown-unknown
#
# # mix-fetch
# #cargo test -p nym-wasm-sdk --target wasm32-unknown-unknown
#
# # full
# cargo test -p nym-wasm-sdk --target wasm32-unknown-unknown
sdk-wasm-lint:
# client
cargo clippy -p nym-client-wasm --target wasm32-unknown-unknown -- -Dwarnings
# node-tester
cargo clippy -p nym-node-tester-wasm --target wasm32-unknown-unknown -- -Dwarnings
# mix-fetch
$(MAKE) -C wasm/mix-fetch check-fmt
# full
cargo clippy -p nym-wasm-sdk --target wasm32-unknown-unknown -- -Dwarnings
# -----------------------------------------------------------------------------
# Build contracts ready for deploy
# -----------------------------------------------------------------------------
CONTRACTS_OUT_DIR=contracts/target/wasm32-unknown-unknown/release
VESTING_CONTRACT=$(CONTRACTS_OUT_DIR)/vesting_contract.wasm
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
contracts-wasm: contracts-wasm-build contracts-wasm-opt
contracts-wasm-build:
RUSTFLAGS='-C link-arg=-s' cargo build --lib --manifest-path contracts/Cargo.toml --release --target wasm32-unknown-unknown
contracts-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)
contract-schema:
$(MAKE) -C contracts schema
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
# Misc # Misc
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
# NOTE: this seems deprecated an not needed anymore?
mixnet-opt: contracts-wasm
cd contracts/mixnet && make opt
generate-typescript: generate-typescript:
cd tools/ts-rs-cli && cargo run && cd ../.. cd tools/ts-rs-cli && cargo run && cd ../..
yarn types:lint:fix yarn types:lint:fix
run-api-tests: run-api-tests:
cd nym-api/tests/functional_test && yarn test:qa cd nym-api/tests/functional_test && yarn test:qa
# Build debian package, and update PPA
# Requires base64 encode GPG key to be set up in environment PPA_SIGNING_KEY
deb:
scripts/ppa.sh
+5 -11
View File
@@ -15,6 +15,7 @@ The platform is composed of multiple Rust crates. Top-level executable binary cr
* 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)
[![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)
@@ -49,10 +50,10 @@ 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">|A Sybil attack resistance parameter - the higher this parameter is set, the stronger the reduction in competitiveness 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 competitiveness 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%. |<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 NYMs. |<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.
Node reward for node `i` is determined as: Node reward for node `i` is determined as:
@@ -82,11 +83,4 @@ where `s'` is stake `s` scaled over total token circulating supply.
### Licensing and copyright information ### Licensing and copyright information
This is a monorepo and components that make up Nym as a system are licensed individually, so 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.
As a general approach, licensing is as follows this pattern:
- applications and binaries are GPLv3
- libraries and components are Apache 2.0 or MIT
- documentation is Apache 2.0 or CC0-1.0
Again, for accurate information, please check individual files.
+5 -85
View File
@@ -1,90 +1,10 @@
Critical bug or security issue 💥 Critical bug or security issue 💥
If you're here because you're trying to figure out how to notify us of a security issue, send us a PGP encrypted email to: 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
security@nymte.ch Jedrzej Stuczynski "Jedrzej | Nym#5666"
``` Fran Arbanas | franarbanas#0995
Mark Sinclair | marknym#8088
Encrypted with our public key which is available below in plain text and also on keyservers:
```
pub rsa4096 2023-10-30 [SC] [expire : 2026-10-29]
24B2592E801A5AAA8666C8BA7C3C727F05090550
uid [ ultime ] Security Nym Technologies <security@nymte.ch>
sub rsa4096 2023-10-30 [E] [expire : 2026-10-29]
```
The fingerprint of the key is on the second line above.
If you need to chat __urgently__ to our team for a __critical__ security issue:
go to Matrix, and alert the core engineers with a private direct message:
Jedrzej Stuczynski @jstuczyn:nymtech.chat
Mark Sinclair @mark:nymtech.chat
Raphaël Walther @raphael:nymtech.chat
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.
If you don't know what Matrix is, you can follow this documentation to create an account on this federation of instant messaging servers:
[Matrix for Instant Messaging](https://matrix.org/docs/chat_basics/matrix-for-im/)
```
-----BEGIN PGP PUBLIC KEY BLOCK-----
mQINBGU/XpcBEAC+ykz0yxn8FferjEBooptXlOH/v/28aa0Nv8DfImTgj9BNY5cR
UdLk+Wa3CSXQVE7PIsi0egEjAMfyxPEywbvPlgklW4XAKDVUCf3gxpQNN47VuVgV
VwrN0VBurhhIKoEw9daO6A0P44+6nmXGIfUulCr4fMxYq82SOooog/j5w0/LfITu
rQXxVABLkXHGN/NGf4BE52QI/ppeXWoshlNVU1wdZIIYWwte+9ukikWpN+LYfJUR
ybtyCjQ4Gdf8ap1GmkKHmAru24wbUuFsBWGVgHsXAwYlKxyiNGR9YwgAxmFk6vNf
1PqKGO3i4erx5X/+mzylzNbFlCqFuksZRyUSDZvQ8fxkm8ra1zWbO38eOTp8Vhgg
SKfRTzOKeZYURZicJPxmEIfA88U4tx+YWJ54YWT/gERZkjIJL5mzIuY9UulVvKUM
vMFUIzBMHOPXH16036zGyFMC1esRd2qqil4b9KtLgCOkrD1VgpjcveoA0VyMJCN6
LmKTrVjwjjDMxby+d49BolRWGnCofXozXwvNQx+CYv8M2WPErTpyYoofYFtpqr7A
fIufc/e0+um3zoGIbHejrhsbuH9Qf+MKsI+Ng93bdDtjeHz6MEgAlsTm0qeizYpj
IyKZIObPmfvrAm08hFZ8JnGk+XuooF36XWbJYjCCy0bOyMw1r7ZG99TcSwARAQAB
tC1TZWN1cml0eSBOeW0gVGVjaG5vbG9naWVzIDxzZWN1cml0eUBueW10ZS5jaD6J
AlQEEwEKAD4WIQQkslkugBpaqoZmyLp8PHJ/BQkFUAUCZT9elwIbAwUJBaOagAUL
CQgHAwUVCgkICwUWAgMBAAIeAQIXgAAKCRB8PHJ/BQkFUL7dD/9zO73uI5VR+SWx
PFmJW+9QsPiQbVRvGwNZurctmQ2s2Pe0vHRELFeqD5oYvSx2Lequ3Ir+zn/C3kDM
kNs40obSL6jCBiLPkxEY0JqzPM9jZr7EjvlibWV3f6DxooRIqEyfN57I3OBGlqZE
0Mx7sQuCcgau8C70DF952QhKUwXC2cmpmDKHVEEoio1xGSD4dQhGapCB32RQGtna
OGfAO9celNMvSq0Lp+aJxeACmWFY5T4/y79JPcT5vSs/yEIRmaH/fn2piwaFBsIq
gHJJMxO3740P1hF8j7KWUoUofuFaEALHBpEpjWTOj8ej1wmFlu+5F+jSVoc781Wb
ZZXu04cOBXnGTogzSxMpBe9TtLb28zd6WzFotC25KTI3pngMzXsQGLJLOwvoZKiS
LFjPRjg1rwobmB3Q3J2W5GYSveia0CDsZGP+g87GVVf/oD2Djpa68xyVYwIYeA6T
3DNdS77qHiRuGiS4kWXyVjDqOICboR4uCvt09zlkBuLDdTWqWYARUvZjtjs4w/Ol
rdrBI3A88ti8fRldYaNpu17ME1ilpN44yKoJtqiWc3Tisk8eYLfx6c7FQF3PrRva
mr7FZvhFsYML5CeNFHTEzN6Y3jjKN/60DvCfodWnWFK47Txkl8UAXGY2W9B0fWqQ
wUVr8uLuMyyMiKbeoufi7rGOj6AMErkCDQRlP16XARAA8FGmD5J3tM1BOM1niJxZ
JTdCauzEtxEoBL0RuqGBkR8U29sRM6DwuzjU7PwscFnBaGyU+eU73GwGkH3ozFfF
tllYhQrhP/kkN+0rEO5Xi+nR+4JCFRqrf3nJXAAPfiksURMp8er1dUOY2/e1ZSoL
tS+nzUivV8CfE+pgj/5YtGwPC+KYHLATkKkMELCrbW4UO06VWOqQsvr6kivXuJQQ
LdEAMpBlADmXFG45DmPKQzsBWUgvTwyGy3LX0nys8cgpex9BH8hhr01QmGyP469s
N3cNrtFuu8U6RAsiCD/8mlBuD3EQEU5SF0lc7kCICAZk+wElmXnimEi0TOYsbz6k
90lteicX70rA9GNeyI76H+VSOYvWpkRwaJAgUdzrAM1o9SHASq+cZ6nD85OZioQk
DWM6+Q+sf2oen0qJnnGmUr93kJIC0PIdgrXRrtiNfeRa1Z/H0LmREyyEMoFiVivn
z1vVk85Oq6Sf3ltUwvmDzuuJOtsp2Qp6+x6Snn/yKauI4uf4Cf/wKUch4r6Bwgg5
Dw49ky7lwlnALio4GIVoGLpLef93wWoDmp4Klyh3ZPf2nB0U91u3bHRUo7m+D7QJ
98cyKtqLLzjg7szGf60pIWNWRsadYQT3bSncynqknAjOV3BCvx6/ivsnpj//QjYR
HtviUAcQ1DBB6UC6q23FIs0AEQEAAYkCPAQYAQoAJhYhBCSyWS6AGlqqhmbIunw8
cn8FCQVQBQJlP16XAhsMBQkFo5qAAAoJEHw8cn8FCQVQzukP/iLxjOxT+UpPR//c
prDVSLkP4pF5bmw36U07jvqpS+/KTXsxiiQleffRabOpNLcd+K1ueavyt9nnIwHH
tHS9kM9A7DBw3LnpEbXki46QDCCI6niGijlLOEeAWqnocwMNTT05wVVgCtO3DQP2
MoSCcqHpXDChvOyr5d5xjYLVJhlctIMSomcVzGryjknPu0Yj/TkC/4c+m86ZWQUD
HqMHQIuiEenvb62/F4c5OJIRZPEn70wdddkgJuJU3eHdHrnuhCkjCC93GQGbGj03
Zqos6699y6hmPeD3U5IUv8ujwZYVCCuDm8gJfrp3R6WLfeZeK9WmTVBpCzsDg3fV
hSwmOk6pp8DAq1/Dev3yRkFggCEyGK6c9b+a0CRBncl8e5Q0QQIzNiS/uExQP3h+
ELJs3P0MLP+6FWhNUry09n3lnWkr1hY+v1M0GAxbfdv/tsCN1Pq/VQEz+CTqXqya
ftWldOHWw6Hh+gtwxcHjG4MBOrO5oICQ3lh2hGwQ58cDgZYSK/OGgJ9BggFl1CcM
0uGC0/TRCI1zt/4y+7efSZQMZkHo7VC/3MFbp2hcNejpW+BxVuwKTunFvWK3TLhq
sSlQ5yyhqchooepsFHq9bosKFjLJC01uprBv1rinoNduOy43FbyS7JPRRspANN0R
iC2pMbWdE0ZTQaFq6tPIg058pjqi
=nqgX
-----END PGP PUBLIC KEY BLOCK-----
```
+5 -5
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "nym-client" name = "nym-client"
version = "1.1.31" version = "1.1.29"
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"] authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"]
description = "Implementation of the Nym Client" description = "Implementation of the Nym Client"
edition = "2021" edition = "2021"
@@ -20,7 +20,7 @@ futures = { workspace = true } # bunch of futures stuff, however, now that I thi
# and the single instance of abortable we have should really be refactored anyway # and the single instance of abortable we have should really be refactored anyway
url = { workspace = true } url = { workspace = true }
clap = { workspace = true, features = ["cargo", "derive"] } clap = { version = "4.0", features = ["cargo", "derive"] }
dirs = "4.0" dirs = "4.0"
lazy_static = "1.4.0" lazy_static = "1.4.0"
log = { workspace = true } # self explanatory log = { workspace = true } # self explanatory
@@ -30,13 +30,13 @@ serde = { workspace = true, features = ["derive"] } # for config serialization/d
serde_json = { workspace = true } serde_json = { workspace = true }
thiserror = { workspace = true } thiserror = { workspace = true }
tap = "1.0.1" tap = "1.0.1"
tokio = { workspace = true, features = ["rt-multi-thread", "net", "signal"] } # async runtime tokio = { version = "1.24.1", features = ["rt-multi-thread", "net", "signal"] } # async runtime
tokio-tungstenite = { workspace = true } tokio-tungstenite = "0.14" # websocket
## internal ## internal
nym-bandwidth-controller = { path = "../../common/bandwidth-controller" } nym-bandwidth-controller = { path = "../../common/bandwidth-controller" }
nym-bin-common = { path = "../../common/bin-common", features = ["output_format"] } nym-bin-common = { path = "../../common/bin-common", features = ["output_format"] }
nym-client-core = { path = "../../common/client-core", features = ["fs-surb-storage", "cli"] } nym-client-core = { path = "../../common/client-core", features = ["fs-surb-storage"] }
nym-coconut-interface = { path = "../../common/coconut-interface" } nym-coconut-interface = { path = "../../common/coconut-interface" }
nym-config = { path = "../../common/config" } nym-config = { path = "../../common/config" }
nym-credential-storage = { path = "../../common/credential-storage" } nym-credential-storage = { path = "../../common/credential-storage" }
+1 -21
View File
@@ -4,8 +4,6 @@
use crate::client::config::persistence::ClientPaths; use crate::client::config::persistence::ClientPaths;
use crate::client::config::template::CONFIG_TEMPLATE; use crate::client::config::template::CONFIG_TEMPLATE;
use nym_bin_common::logging::LoggingSettings; use nym_bin_common::logging::LoggingSettings;
use nym_client_core::cli_helpers::client_init::ClientConfig;
use nym_client_core::config::disk_persistence::CommonClientPaths;
use nym_config::defaults::DEFAULT_WEBSOCKET_LISTENING_PORT; use nym_config::defaults::DEFAULT_WEBSOCKET_LISTENING_PORT;
use nym_config::{ use nym_config::{
must_get_home, read_config_from_toml_file, save_formatted_config_to_file, NymConfigTemplate, must_get_home, read_config_from_toml_file, save_formatted_config_to_file, NymConfigTemplate,
@@ -69,29 +67,11 @@ pub struct Config {
} }
impl NymConfigTemplate for Config { impl NymConfigTemplate for Config {
fn template(&self) -> &'static str { fn template() -> &'static str {
CONFIG_TEMPLATE CONFIG_TEMPLATE
} }
} }
impl ClientConfig for Config {
fn common_paths(&self) -> &CommonClientPaths {
&self.storage_paths.common_paths
}
fn core_config(&self) -> &BaseClientConfig {
&self.base
}
fn default_store_location(&self) -> PathBuf {
self.default_location()
}
fn save_to<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
save_formatted_config_to_file(self, path)
}
}
impl Config { impl Config {
pub fn new<S: AsRef<str>>(id: S) -> Self { pub fn new<S: AsRef<str>>(id: S) -> Self {
Config { Config {
@@ -11,7 +11,6 @@ use crate::{
use nym_bin_common::logging::LoggingSettings; use nym_bin_common::logging::LoggingSettings;
use nym_client_core::config::disk_persistence::old_v1_1_20_2::CommonClientPathsV1_1_20_2; use nym_client_core::config::disk_persistence::old_v1_1_20_2::CommonClientPathsV1_1_20_2;
use nym_client_core::config::old_config_v1_1_20_2::ConfigV1_1_20_2 as BaseConfigV1_1_20_2; use nym_client_core::config::old_config_v1_1_20_2::ConfigV1_1_20_2 as BaseConfigV1_1_20_2;
use nym_client_core::config::old_config_v1_1_30::ConfigV1_1_30 as BaseConfigV1_1_30;
use nym_client_core::config::GatewayEndpointConfig; use nym_client_core::config::GatewayEndpointConfig;
use nym_config::read_config_from_toml_file; use nym_config::read_config_from_toml_file;
use nym_network_defaults::DEFAULT_WEBSOCKET_LISTENING_PORT; use nym_network_defaults::DEFAULT_WEBSOCKET_LISTENING_PORT;
@@ -52,7 +51,7 @@ impl ConfigV1_1_20_2 {
pub fn upgrade(self) -> Result<(Config, GatewayEndpointConfig), ClientError> { pub fn upgrade(self) -> Result<(Config, GatewayEndpointConfig), ClientError> {
let gateway_details = self.base.client.gateway_endpoint.clone().into(); let gateway_details = self.base.client.gateway_endpoint.clone().into();
let config = Config { let config = Config {
base: BaseConfigV1_1_30::from(self.base).into(), base: self.base.into(),
socket: self.socket.into(), socket: self.socket.into(),
storage_paths: ClientPaths { storage_paths: ClientPaths {
common_paths: self.storage_paths.common_paths.upgrade_default()?, common_paths: self.storage_paths.common_paths.upgrade_default()?,
@@ -14,7 +14,7 @@ pub struct ClientPaths {
impl ClientPaths { impl ClientPaths {
pub fn new_default<P: AsRef<Path>>(base_data_directory: P) -> Self { pub fn new_default<P: AsRef<Path>>(base_data_directory: P) -> Self {
ClientPaths { ClientPaths {
common_paths: CommonClientPaths::new_base(base_data_directory), common_paths: CommonClientPaths::new_default(base_data_directory),
} }
} }
} }
+142 -5
View File
@@ -4,19 +4,28 @@
use crate::client::config::Config; use crate::client::config::Config;
use crate::error::ClientError; use crate::error::ClientError;
use crate::websocket; use crate::websocket;
use futures::channel::mpsc;
use log::*; use log::*;
use nym_client_core::client::base_client::non_wasm_helpers::default_query_dkg_client_from_config; use nym_client_core::client::base_client::non_wasm_helpers::default_query_dkg_client_from_config;
use nym_client_core::client::base_client::storage::OnDiskPersistent; use nym_client_core::client::base_client::storage::OnDiskPersistent;
use nym_client_core::client::base_client::{ use nym_client_core::client::base_client::{
BaseClientBuilder, ClientInput, ClientOutput, ClientState, BaseClientBuilder, ClientInput, ClientOutput, ClientState,
}; };
use nym_client_core::client::inbound_messages::InputMessage;
use nym_client_core::client::received_buffer::{
ReceivedBufferMessage, ReceivedBufferRequestSender, ReconstructedMessagesReceiver,
};
use nym_sphinx::anonymous_replies::requests::AnonymousSenderTag;
use nym_sphinx::params::PacketType; use nym_sphinx::params::PacketType;
use nym_task::TaskHandle; use nym_task::connections::TransmissionLane;
use nym_task::TaskManager;
use nym_validator_client::QueryHttpRpcNyxdClient; use nym_validator_client::QueryHttpRpcNyxdClient;
use std::error::Error; use std::error::Error;
use std::path::PathBuf; use std::path::PathBuf;
use tokio::sync::watch::error::SendError;
pub use nym_sphinx::addressing::clients::Recipient; pub use nym_sphinx::addressing::clients::Recipient;
pub use nym_sphinx::receiver::ReconstructedMessage;
pub mod config; pub mod config;
@@ -83,7 +92,7 @@ impl SocketClient {
pub async fn run_socket_forever(self) -> Result<(), Box<dyn Error + Send + Sync>> { pub async fn run_socket_forever(self) -> Result<(), Box<dyn Error + Send + Sync>> {
let shutdown = self.start_socket().await?; let shutdown = self.start_socket().await?;
let res = shutdown.wait_for_shutdown().await; let res = shutdown.catch_interrupt().await;
log::info!("Stopping nym-client"); log::info!("Stopping nym-client");
res res
} }
@@ -116,7 +125,7 @@ impl SocketClient {
Ok(base_client) Ok(base_client)
} }
pub async fn start_socket(self) -> Result<TaskHandle, ClientError> { pub async fn start_socket(self) -> Result<TaskManager, ClientError> {
if !self.config.socket.socket_type.is_websocket() { if !self.config.socket.socket_type.is_websocket() {
return Err(ClientError::InvalidSocketMode); return Err(ClientError::InvalidSocketMode);
} }
@@ -135,13 +144,141 @@ impl SocketClient {
client_output, client_output,
client_state, client_state,
&self_address, &self_address,
started_client.task_handle.get_handle(), started_client.task_manager.subscribe(),
packet_type, packet_type,
); );
info!("Client startup finished!"); info!("Client startup finished!");
info!("The address of this client is: {self_address}"); info!("The address of this client is: {self_address}");
Ok(started_client.task_handle) Ok(started_client.task_manager)
}
pub async fn start_direct(self) -> Result<DirectClient, ClientError> {
if self.config.socket.socket_type.is_websocket() {
return Err(ClientError::InvalidSocketMode);
}
let base_builder = self.create_base_client_builder().await?;
let packet_type = self.config.base.debug.traffic.packet_type;
let mut started_client = base_builder.start_base().await?;
let address = started_client.address;
let client_input = started_client.client_input.register_producer();
let client_output = started_client.client_output.register_consumer();
// register our receiver
let (reconstructed_sender, reconstructed_receiver) = mpsc::unbounded();
// tell the buffer to start sending stuff to us
client_output
.received_buffer_request_sender
.unbounded_send(ReceivedBufferMessage::ReceiverAnnounce(
reconstructed_sender,
))
.expect("the buffer request failed!");
Ok(DirectClient {
client_input,
_received_buffer_request_sender: client_output.received_buffer_request_sender,
reconstructed_receiver,
address,
shutdown_notifier: started_client.task_manager,
packet_type,
})
}
}
pub struct DirectClient {
client_input: ClientInput,
// make sure to not drop the channel
_received_buffer_request_sender: ReceivedBufferRequestSender,
reconstructed_receiver: ReconstructedMessagesReceiver,
address: Recipient,
// we need to keep reference to this guy otherwise things will start dropping
shutdown_notifier: TaskManager,
packet_type: PacketType,
}
impl DirectClient {
pub fn address(&self) -> &Recipient {
&self.address
}
pub fn signal_shutdown(&self) -> Result<(), SendError<()>> {
self.shutdown_notifier.signal_shutdown()
}
pub async fn wait_for_shutdown(&mut self) {
self.shutdown_notifier.wait_for_shutdown().await
}
/// EXPERIMENTAL DIRECT RUST API
/// It's untested and there are absolutely no guarantees about it (but seems to have worked
/// well enough in local tests)
pub async fn send_regular_message(&mut self, recipient: Recipient, message: Vec<u8>) {
let lane = TransmissionLane::General;
let input_msg = InputMessage::new_regular(recipient, message, lane, Some(self.packet_type));
self.client_input
.input_sender
.send(input_msg)
.await
.expect("InputMessageReceiver has stopped receiving!");
}
/// EXPERIMENTAL DIRECT RUST API
/// It's untested and there are absolutely no guarantees about it (but seems to have worked
/// well enough in local tests)
pub async fn send_anonymous_message(
&mut self,
recipient: Recipient,
message: Vec<u8>,
reply_surbs: u32,
) {
let lane = TransmissionLane::General;
let input_msg = InputMessage::new_anonymous(
recipient,
message,
reply_surbs,
lane,
Some(self.packet_type),
);
self.client_input
.input_sender
.send(input_msg)
.await
.expect("InputMessageReceiver has stopped receiving!");
}
/// EXPERIMENTAL DIRECT RUST API
/// It's untested and there are absolutely no guarantees about it (but seems to have worked
/// well enough in local tests)
pub async fn send_reply(&mut self, recipient_tag: AnonymousSenderTag, message: Vec<u8>) {
let lane = TransmissionLane::General;
let input_msg =
InputMessage::new_reply(recipient_tag, message, lane, Some(self.packet_type));
self.client_input
.input_sender
.send(input_msg)
.await
.expect("InputMessageReceiver has stopped receiving!");
}
/// EXPERIMENTAL DIRECT RUST API
/// It's untested and there are absolutely no guarantees about it (but seems to have worked
/// well enough in local tests)
/// Note: it waits for the first occurrence of messages being sent to ourselves. If you expect multiple
/// messages, you might have to call this function repeatedly.
// TODO: I guess this should really return something that `impl Stream<Item=ReconstructedMessage>`
pub async fn wait_for_messages(&mut self) -> Vec<ReconstructedMessage> {
use futures::StreamExt;
self.reconstructed_receiver
.next()
.await
.expect("buffer controller seems to have somehow died!")
} }
} }
+152 -56
View File
@@ -12,49 +12,54 @@ use crate::{
}; };
use clap::Args; use clap::Args;
use nym_bin_common::output_format::OutputFormat; use nym_bin_common::output_format::OutputFormat;
use nym_client_core::cli_helpers::client_init::{ use nym_client_core::client::base_client::storage::gateway_details::OnDiskGatewayDetails;
initialise_client, CommonClientInitArgs, InitResultsWithConfig, InitialisableClient, use nym_client_core::client::key_manager::persistence::OnDiskKeys;
}; use nym_client_core::config::GatewayEndpointConfig;
use nym_client_core::init::helpers::current_gateways;
use nym_client_core::init::GatewaySetup;
use nym_crypto::asymmetric::identity;
use nym_sphinx::addressing::clients::Recipient;
use nym_topology::NymTopology;
use serde::Serialize; use serde::Serialize;
use std::fmt::Display; use std::fmt::Display;
use std::fs;
use std::net::IpAddr; use std::net::IpAddr;
use std::path::PathBuf; use std::path::PathBuf;
use std::{fs, io};
struct NativeClientInit; use tap::TapFallible;
impl InitialisableClient for NativeClientInit {
const NAME: &'static str = "native";
type Error = ClientError;
type InitArgs = Init;
type Config = Config;
fn try_upgrade_outdated_config(id: &str) -> Result<(), Self::Error> {
try_upgrade_config(id)
}
fn initialise_storage_paths(id: &str) -> Result<(), Self::Error> {
fs::create_dir_all(default_data_directory(id))?;
fs::create_dir_all(default_config_directory(id))?;
Ok(())
}
fn default_config_path(id: &str) -> PathBuf {
default_config_filepath(id)
}
fn construct_config(init_args: &Self::InitArgs) -> Self::Config {
override_config(
Config::new(&init_args.common_args.id),
OverrideConfig::from(init_args.clone()),
)
}
}
#[derive(Args, Clone)] #[derive(Args, Clone)]
pub(crate) struct Init { pub(crate) struct Init {
#[command(flatten)] /// Id of the nym-mixnet-client we want to create config for.
common_args: CommonClientInitArgs, #[clap(long)]
id: String,
/// Id of the gateway we are going to connect to.
#[clap(long)]
gateway: Option<identity::PublicKey>,
/// Specifies whether the new gateway should be determined based by latency as opposed to being chosen
/// uniformly.
#[clap(long, conflicts_with = "gateway")]
latency_based_selection: bool,
/// Force register gateway. WARNING: this will overwrite any existing keys for the given id,
/// potentially causing loss of access.
#[clap(long)]
force_register_gateway: bool,
/// Comma separated list of rest endpoints of the nyxd validators
#[clap(long, alias = "nyxd_validators", value_delimiter = ',', hide = true)]
nyxd_urls: Option<Vec<url::Url>>,
/// Comma separated list of rest endpoints of the API validators
#[clap(
long,
alias = "api_validators",
value_delimiter = ',',
group = "network"
)]
// the alias here is included for backwards compatibility (1.1.4 and before)
nym_apis: Option<Vec<url::Url>>,
/// Whether to not start the websocket /// Whether to not start the websocket
#[clap(long)] #[clap(long)]
@@ -68,28 +73,40 @@ pub(crate) struct Init {
#[clap(long)] #[clap(long)]
host: Option<IpAddr>, host: Option<IpAddr>,
/// Path to .json file containing custom network specification.
#[clap(long, group = "network", hide = true)]
custom_mixnet: Option<PathBuf>,
/// Mostly debug-related option to increase default traffic rate so that you would not need to
/// modify config post init
#[clap(long, hide = true)]
fastmode: bool,
/// Disable loop cover traffic and the Poisson rate limiter (for debugging only)
#[clap(long, hide = true)]
no_cover: bool,
/// Set this client to work in a enabled credentials mode that would attempt to use gateway
/// with bandwidth credential requirement.
#[clap(long, hide = true)]
enabled_credentials_mode: Option<bool>,
#[clap(short, long, default_value_t = OutputFormat::default())] #[clap(short, long, default_value_t = OutputFormat::default())]
output: OutputFormat, output: OutputFormat,
} }
impl AsRef<CommonClientInitArgs> for Init {
fn as_ref(&self) -> &CommonClientInitArgs {
&self.common_args
}
}
impl From<Init> for OverrideConfig { impl From<Init> for OverrideConfig {
fn from(init_config: Init) -> Self { fn from(init_config: Init) -> Self {
OverrideConfig { OverrideConfig {
nym_apis: init_config.common_args.nym_apis, nym_apis: init_config.nym_apis,
disable_socket: init_config.disable_socket, disable_socket: init_config.disable_socket,
port: init_config.port, port: init_config.port,
host: init_config.host, host: init_config.host,
fastmode: init_config.common_args.fastmode, fastmode: init_config.fastmode,
no_cover: init_config.common_args.no_cover, no_cover: init_config.no_cover,
nyxd_urls: init_config.common_args.nyxd_urls, nyxd_urls: init_config.nyxd_urls,
enabled_credentials_mode: init_config.common_args.enabled_credentials_mode, enabled_credentials_mode: init_config.enabled_credentials_mode,
} }
} }
} }
@@ -97,17 +114,17 @@ impl From<Init> for OverrideConfig {
#[derive(Debug, Serialize)] #[derive(Debug, Serialize)]
pub struct InitResults { pub struct InitResults {
#[serde(flatten)] #[serde(flatten)]
client_core: nym_client_core::init::types::InitResults, client_core: nym_client_core::init::InitResults,
client_listening_port: u16, client_listening_port: u16,
client_address: String, client_address: String,
} }
impl InitResults { impl InitResults {
fn new(res: InitResultsWithConfig<Config>) -> Self { fn new(config: &Config, address: &Recipient, gateway: &GatewayEndpointConfig) -> Self {
Self { Self {
client_address: res.init_results.address.to_string(), client_core: nym_client_core::init::InitResults::new(&config.base, address, gateway),
client_core: res.init_results, client_listening_port: config.socket.listening_port,
client_listening_port: res.config.socket.listening_port, client_address: address.to_string(),
} }
} }
} }
@@ -120,14 +137,93 @@ impl Display for InitResults {
} }
} }
fn init_paths(id: &str) -> io::Result<()> {
fs::create_dir_all(default_data_directory(id))?;
fs::create_dir_all(default_config_directory(id))
}
pub(crate) async fn execute(args: Init) -> Result<(), ClientError> { pub(crate) async fn execute(args: Init) -> Result<(), ClientError> {
eprintln!("Initialising client..."); eprintln!("Initialising client...");
let output = args.output; let id = &args.id;
let res = initialise_client::<NativeClientInit>(args).await?;
let init_results = InitResults::new(res); let already_init = if default_config_filepath(id).exists() {
println!("{}", output.format(&init_results)); // in case we're using old config, try to upgrade it
// (if we're using the current version, it's a no-op)
try_upgrade_config(id)?;
eprintln!("Client \"{id}\" was already initialised before");
true
} else {
init_paths(id)?;
false
};
// Usually you only register with the gateway on the first init, however you can force
// re-registering if wanted.
let user_wants_force_register = args.force_register_gateway;
if user_wants_force_register {
eprintln!("Instructed to force registering gateway. This might overwrite keys!");
}
// If the client was already initialized, don't generate new keys and don't re-register with
// the gateway (because this would create a new shared key).
// Unless the user really wants to.
let register_gateway = !already_init || user_wants_force_register;
// Attempt to use a user-provided gateway, if possible
let user_chosen_gateway_id = args.gateway;
let gateway_setup = GatewaySetup::new_fresh(
user_chosen_gateway_id.map(|id| id.to_base58_string()),
Some(args.latency_based_selection),
);
// Load and potentially override config
let config = override_config(Config::new(id), OverrideConfig::from(args.clone()));
// Setup gateway by either registering a new one, or creating a new config from the selected
// one but with keys kept, or reusing the gateway configuration.
let key_store = OnDiskKeys::new(config.storage_paths.common_paths.keys.clone());
let details_store =
OnDiskGatewayDetails::new(&config.storage_paths.common_paths.gateway_details);
let network_gateways = if let Some(hardcoded_topology) = args
.custom_mixnet
.map(NymTopology::new_from_file)
.transpose()?
{
// hardcoded_topology
hardcoded_topology.get_gateways()
} else {
let mut rng = rand::thread_rng();
current_gateways(&mut rng, &config.base.client.nym_api_urls).await?
};
let init_details = nym_client_core::init::setup_gateway_from(
gateway_setup,
&key_store,
&details_store,
register_gateway,
Some(&network_gateways),
)
.await
.tap_err(|err| eprintln!("Failed to setup gateway\nError: {err}"))?
.details;
let config_save_location = config.default_location();
config.save_to_default_location().tap_err(|_| {
log::error!("Failed to save the config file");
})?;
eprintln!(
"Saved configuration file to {}",
config_save_location.display()
);
let address = init_details.client_address()?;
eprintln!("Client configuration completed.\n");
let init_results = InitResults::new(&config, &address, &init_details.gateway_details);
println!("{}", args.output.format(&init_results));
Ok(()) Ok(())
} }
+1 -1
View File
@@ -133,7 +133,7 @@ fn persist_gateway_details(
source: Box::new(source), source: Box::new(source),
}) })
})?; })?;
let persisted_details = PersistedGatewayDetails::new(details.into(), Some(&shared_keys))?; let persisted_details = PersistedGatewayDetails::new(details, &shared_keys);
details_store details_store
.store_to_disk(&persisted_details) .store_to_disk(&persisted_details)
.map_err(|source| { .map_err(|source| {
+50 -11
View File
@@ -10,14 +10,35 @@ use crate::{
use clap::Args; use clap::Args;
use log::*; use log::*;
use nym_bin_common::version_checker::is_minor_version_compatible; use nym_bin_common::version_checker::is_minor_version_compatible;
use nym_client_core::cli_helpers::client_run::CommonClientRunArgs; use nym_crypto::asymmetric::identity;
use std::error::Error; use std::error::Error;
use std::net::IpAddr; use std::net::IpAddr;
use std::path::PathBuf;
#[derive(Args, Clone)] #[derive(Args, Clone)]
pub(crate) struct Run { pub(crate) struct Run {
#[command(flatten)] /// Id of the nym-mixnet-client we want to run.
common_args: CommonClientRunArgs, #[clap(long)]
id: String,
/// Comma separated list of rest endpoints of the nyxd validators
#[clap(long, alias = "nyxd_validators", value_delimiter = ',', hide = true)]
nyxd_urls: Option<Vec<url::Url>>,
/// Comma separated list of rest endpoints of the API validators
#[clap(
long,
alias = "api_validators",
value_delimiter = ',',
group = "network"
)]
// the alias here is included for backwards compatibility (1.1.4 and before)
nym_apis: Option<Vec<url::Url>>,
/// Id of the gateway we want to connect to. If overridden, it is user's responsibility to
/// ensure prior registration happened
#[clap(long)]
gateway: Option<identity::PublicKey>,
/// Whether to not start the websocket /// Whether to not start the websocket
#[clap(long)] #[clap(long)]
@@ -30,19 +51,37 @@ pub(crate) struct Run {
/// Ip for the socket (if applicable) to listen for requests. /// Ip for the socket (if applicable) to listen for requests.
#[clap(long)] #[clap(long)]
host: Option<IpAddr>, host: Option<IpAddr>,
/// Path to .json file containing custom network specification.
#[clap(long, group = "network", hide = true)]
custom_mixnet: Option<PathBuf>,
/// Mostly debug-related option to increase default traffic rate so that you would not need to
/// modify config post init
#[clap(long, hide = true)]
fastmode: bool,
/// Disable loop cover traffic and the Poisson rate limiter (for debugging only)
#[clap(long, hide = true)]
no_cover: bool,
/// Set this client to work in a enabled credentials mode that would attempt to use gateway
/// with bandwidth credential requirement.
#[clap(long, hide = true)]
enabled_credentials_mode: Option<bool>,
} }
impl From<Run> for OverrideConfig { impl From<Run> for OverrideConfig {
fn from(run_config: Run) -> Self { fn from(run_config: Run) -> Self {
OverrideConfig { OverrideConfig {
nym_apis: run_config.common_args.nym_apis, nym_apis: run_config.nym_apis,
disable_socket: run_config.disable_socket, disable_socket: run_config.disable_socket,
port: run_config.port, port: run_config.port,
host: run_config.host, host: run_config.host,
fastmode: run_config.common_args.fastmode, fastmode: run_config.fastmode,
no_cover: run_config.common_args.no_cover, no_cover: run_config.no_cover,
nyxd_urls: run_config.common_args.nyxd_urls, nyxd_urls: run_config.nyxd_urls,
enabled_credentials_mode: run_config.common_args.enabled_credentials_mode, enabled_credentials_mode: run_config.enabled_credentials_mode,
} }
} }
} }
@@ -67,9 +106,9 @@ fn version_check(cfg: &Config) -> bool {
} }
pub(crate) async fn execute(args: Run) -> Result<(), Box<dyn Error + Send + Sync>> { pub(crate) async fn execute(args: Run) -> Result<(), Box<dyn Error + Send + Sync>> {
eprintln!("Starting client {}...", args.common_args.id); eprintln!("Starting client {}...", args.id);
let mut config = try_load_current_config(&args.common_args.id)?; let mut config = try_load_current_config(&args.id)?;
config = override_config(config, OverrideConfig::from(args.clone())); config = override_config(config, OverrideConfig::from(args.clone()));
if !version_check(&config) { if !version_check(&config) {
@@ -77,7 +116,7 @@ pub(crate) async fn execute(args: Run) -> Result<(), Box<dyn Error + Send + Sync
return Err(Box::new(ClientError::FailedLocalVersionCheck)); return Err(Box::new(ClientError::FailedLocalVersionCheck));
} }
SocketClient::new(config, args.common_args.custom_mixnet) SocketClient::new(config, args.custom_mixnet)
.run_socket_forever() .run_socket_forever()
.await .await
} }
+1 -6
View File
@@ -22,10 +22,5 @@ async fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
} }
setup_logging(); setup_logging();
if let Err(err) = commands::execute(args).await { commands::execute(args).await
log::error!("{err}");
println!("An error occurred: {err}");
std::process::exit(1);
}
Ok(())
} }
+3 -3
View File
@@ -1,13 +1,13 @@
[package] [package]
name = "nym-socks5-client" name = "nym-socks5-client"
version = "1.1.31" version = "1.1.29"
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"] authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
description = "A SOCKS5 localhost proxy that converts incoming messages to Sphinx and sends them to a Nym address" description = "A SOCKS5 localhost proxy that converts incoming messages to Sphinx and sends them to a Nym address"
edition = "2021" edition = "2021"
rust-version = "1.56" rust-version = "1.56"
[dependencies] [dependencies]
clap = { workspace = true, features = ["cargo", "derive"] } clap = { version = "4.0", features = ["cargo", "derive"] }
lazy_static = "1.4.0" lazy_static = "1.4.0"
log = { workspace = true } log = { workspace = true }
pretty_env_logger = "0.4" pretty_env_logger = "0.4"
@@ -21,7 +21,7 @@ url = { workspace = true }
# internal # internal
nym-bin-common = { path = "../../common/bin-common", features = ["output_format"] } nym-bin-common = { path = "../../common/bin-common", features = ["output_format"] }
nym-client-core = { path = "../../common/client-core", features = ["fs-surb-storage", "cli"] } nym-client-core = { path = "../../common/client-core", features = ["fs-surb-storage"] }
nym-coconut-interface = { path = "../../common/coconut-interface" } nym-coconut-interface = { path = "../../common/coconut-interface" }
nym-config = { path = "../../common/config" } nym-config = { path = "../../common/config" }
nym-credentials = { path = "../../common/credentials" } nym-credentials = { path = "../../common/credentials" }
+155 -67
View File
@@ -11,50 +11,25 @@ use crate::{
}; };
use clap::Args; use clap::Args;
use nym_bin_common::output_format::OutputFormat; use nym_bin_common::output_format::OutputFormat;
use nym_client_core::cli_helpers::client_init::{ use nym_client_core::client::base_client::storage::gateway_details::OnDiskGatewayDetails;
initialise_client, CommonClientInitArgs, InitResultsWithConfig, InitialisableClient, use nym_client_core::client::key_manager::persistence::OnDiskKeys;
}; use nym_client_core::config::GatewayEndpointConfig;
use nym_client_core::init::helpers::current_gateways;
use nym_client_core::init::GatewaySetup;
use nym_crypto::asymmetric::identity;
use nym_sphinx::addressing::clients::Recipient; use nym_sphinx::addressing::clients::Recipient;
use nym_topology::NymTopology;
use serde::Serialize; use serde::Serialize;
use std::fmt::Display; use std::fmt::Display;
use std::fs;
use std::net::{IpAddr, SocketAddr};
use std::path::PathBuf; use std::path::PathBuf;
use std::{fs, io};
struct Socks5ClientInit; use tap::TapFallible;
impl InitialisableClient for Socks5ClientInit {
const NAME: &'static str = "socks5";
type Error = Socks5ClientError;
type InitArgs = Init;
type Config = Config;
fn try_upgrade_outdated_config(id: &str) -> Result<(), Self::Error> {
try_upgrade_config(id)
}
fn initialise_storage_paths(id: &str) -> Result<(), Self::Error> {
fs::create_dir_all(default_data_directory(id))?;
fs::create_dir_all(default_config_directory(id))?;
Ok(())
}
fn default_config_path(id: &str) -> PathBuf {
default_config_filepath(id)
}
fn construct_config(init_args: &Self::InitArgs) -> Self::Config {
override_config(
Config::new(&init_args.common_args.id, &init_args.provider.to_string()),
OverrideConfig::from(init_args.clone()),
)
}
}
#[derive(Args, Clone)] #[derive(Args, Clone)]
pub(crate) struct Init { pub(crate) struct Init {
#[command(flatten)] /// Id of the nym-mixnet-client we want to create config for.
common_args: CommonClientInitArgs, #[clap(long)]
id: String,
/// Address of the socks5 provider to send messages to. /// Address of the socks5 provider to send messages to.
#[clap(long)] #[clap(long)]
@@ -69,37 +44,67 @@ pub(crate) struct Init {
#[clap(long, alias = "use_anonymous_sender_tag")] #[clap(long, alias = "use_anonymous_sender_tag")]
use_reply_surbs: Option<bool>, use_reply_surbs: Option<bool>,
/// Id of the gateway we are going to connect to.
#[clap(long)]
gateway: Option<identity::PublicKey>,
/// Specifies whether the new gateway should be determined based by latency as opposed to being chosen
/// uniformly.
#[clap(long, conflicts_with = "gateway")]
latency_based_selection: bool,
/// Force register gateway. WARNING: this will overwrite any existing keys for the given id,
/// potentially causing loss of access.
#[clap(long)]
force_register_gateway: bool,
/// Comma separated list of rest endpoints of the nyxd validators
#[clap(long, alias = "nyxd_validators", value_delimiter = ',', hide = true)]
nyxd_urls: Option<Vec<url::Url>>,
/// Comma separated list of rest endpoints of the API validators
#[clap(long, alias = "api_validators", value_delimiter = ',')]
// the alias here is included for backwards compatibility (1.1.4 and before)
nym_apis: Option<Vec<url::Url>>,
/// Port for the socket to listen on in all subsequent runs /// Port for the socket to listen on in all subsequent runs
#[clap(short, long)] #[clap(short, long)]
port: Option<u16>, port: Option<u16>,
/// The custom host on which the socks5 client will be listening for requests /// Path to .json file containing custom network specification.
#[clap(long)] #[clap(long, group = "network", hide = true)]
host: Option<IpAddr>, custom_mixnet: Option<PathBuf>,
/// Mostly debug-related option to increase default traffic rate so that you would not need to
/// modify config post init
#[clap(long, hide = true)]
fastmode: bool,
/// Disable loop cover traffic and the Poisson rate limiter (for debugging only)
#[clap(long, hide = true)]
no_cover: bool,
/// Set this client to work in a enabled credentials mode that would attempt to use gateway
/// with bandwidth credential requirement.
#[clap(long, hide = true)]
enabled_credentials_mode: Option<bool>,
#[clap(short, long, default_value_t = OutputFormat::default())] #[clap(short, long, default_value_t = OutputFormat::default())]
output: OutputFormat, output: OutputFormat,
} }
impl AsRef<CommonClientInitArgs> for Init {
fn as_ref(&self) -> &CommonClientInitArgs {
&self.common_args
}
}
impl From<Init> for OverrideConfig { impl From<Init> for OverrideConfig {
fn from(init_config: Init) -> Self { fn from(init_config: Init) -> Self {
OverrideConfig { OverrideConfig {
nym_apis: init_config.common_args.nym_apis, nym_apis: init_config.nym_apis,
ip: init_config.host,
port: init_config.port, port: init_config.port,
use_anonymous_replies: init_config.use_reply_surbs, use_anonymous_replies: init_config.use_reply_surbs,
fastmode: init_config.common_args.fastmode, fastmode: init_config.fastmode,
no_cover: init_config.common_args.no_cover, no_cover: init_config.no_cover,
geo_routing: None, geo_routing: None,
medium_toggle: false, medium_toggle: false,
nyxd_urls: init_config.common_args.nyxd_urls, nyxd_urls: init_config.nyxd_urls,
enabled_credentials_mode: init_config.common_args.enabled_credentials_mode, enabled_credentials_mode: init_config.enabled_credentials_mode,
outfox: false, outfox: false,
} }
} }
@@ -108,17 +113,21 @@ impl From<Init> for OverrideConfig {
#[derive(Debug, Serialize)] #[derive(Debug, Serialize)]
pub struct InitResults { pub struct InitResults {
#[serde(flatten)] #[serde(flatten)]
client_core: nym_client_core::init::types::InitResults, client_core: nym_client_core::init::InitResults,
socks5_listening_address: SocketAddr, socks5_listening_port: u16,
client_address: String, client_address: String,
} }
impl InitResults { impl InitResults {
fn new(res: InitResultsWithConfig<Config>) -> Self { fn new(config: &Config, address: &Recipient, gateway: &GatewayEndpointConfig) -> Self {
Self { Self {
client_address: res.init_results.address.to_string(), client_core: nym_client_core::init::InitResults::new(
client_core: res.init_results, &config.core.base,
socks5_listening_address: res.config.core.socks5.bind_adddress, address,
gateway,
),
socks5_listening_port: config.core.socks5.listening_port,
client_address: address.to_string(),
} }
} }
} }
@@ -126,23 +135,102 @@ impl InitResults {
impl Display for InitResults { impl Display for InitResults {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
writeln!(f, "{}", self.client_core)?; writeln!(f, "{}", self.client_core)?;
writeln!( writeln!(f, "SOCKS5 listening port: {}", self.socks5_listening_port)?;
f,
"SOCKS5 listening address: {}",
self.socks5_listening_address
)?;
write!(f, "Address of this client: {}", self.client_address) write!(f, "Address of this client: {}", self.client_address)
} }
} }
fn init_paths(id: &str) -> io::Result<()> {
fs::create_dir_all(default_data_directory(id))?;
fs::create_dir_all(default_config_directory(id))
}
pub(crate) async fn execute(args: Init) -> Result<(), Socks5ClientError> { pub(crate) async fn execute(args: Init) -> Result<(), Socks5ClientError> {
eprintln!("Initialising client..."); eprintln!("Initialising client...");
let output = args.output; let id = &args.id;
let res = initialise_client::<Socks5ClientInit>(args).await?; let provider_address = &args.provider;
let init_results = InitResults::new(res); let already_init = if default_config_filepath(id).exists() {
println!("{}", output.format(&init_results)); // in case we're using old config, try to upgrade it
// (if we're using the current version, it's a no-op)
try_upgrade_config(id)?;
eprintln!("SOCKS5 client \"{id}\" was already initialised before");
true
} else {
init_paths(id)?;
false
};
// Usually you only register with the gateway on the first init, however you can force
// re-registering if wanted.
let user_wants_force_register = args.force_register_gateway;
if user_wants_force_register {
eprintln!("Instructed to force registering gateway. This might overwrite keys!");
}
// If the client was already initialized, don't generate new keys and don't re-register with
// the gateway (because this would create a new shared key).
// Unless the user really wants to.
let register_gateway = !already_init || user_wants_force_register;
// Attempt to use a user-provided gateway, if possible
let user_chosen_gateway_id = args.gateway;
let gateway_setup = GatewaySetup::new_fresh(
user_chosen_gateway_id.map(|id| id.to_base58_string()),
Some(args.latency_based_selection),
);
// Load and potentially override config
let config = override_config(
Config::new(id, &provider_address.to_string()),
OverrideConfig::from(args.clone()),
);
// Setup gateway by either registering a new one, or creating a new config from the selected
// one but with keys kept, or reusing the gateway configuration.
let key_store = OnDiskKeys::new(config.storage_paths.common_paths.keys.clone());
let details_store =
OnDiskGatewayDetails::new(&config.storage_paths.common_paths.gateway_details);
let network_gateways = if let Some(hardcoded_topology) = args
.custom_mixnet
.map(NymTopology::new_from_file)
.transpose()?
{
// hardcoded_topology
hardcoded_topology.get_gateways()
} else {
let mut rng = rand::thread_rng();
current_gateways(&mut rng, &config.core.base.client.nym_api_urls).await?
};
let init_details = nym_client_core::init::setup_gateway_from(
gateway_setup,
&key_store,
&details_store,
register_gateway,
Some(&network_gateways),
)
.await
.tap_err(|err| eprintln!("Failed to setup gateway\nError: {err}"))?
.details;
// TODO: ask the service provider we specified for its interface version and set it in the config
let config_save_location = config.default_location();
config.save_to_default_location().tap_err(|_| {
log::error!("Failed to save the config file");
})?;
eprintln!(
"Saved configuration file to {}",
config_save_location.display()
);
let address = init_details.client_address()?;
let init_results = InitResults::new(&config, &address, &init_details.gateway_details);
println!("{}", args.output.format(&init_results));
Ok(()) Ok(())
} }
+12 -36
View File
@@ -4,8 +4,7 @@
use crate::config::old_config_v1_1_13::OldConfigV1_1_13; use crate::config::old_config_v1_1_13::OldConfigV1_1_13;
use crate::config::old_config_v1_1_20::ConfigV1_1_20; use crate::config::old_config_v1_1_20::ConfigV1_1_20;
use crate::config::old_config_v1_1_20_2::ConfigV1_1_20_2; use crate::config::old_config_v1_1_20_2::ConfigV1_1_20_2;
use crate::config::old_config_v1_1_30::ConfigV1_1_30; use crate::config::{BaseClientConfig, Config};
use crate::config::{BaseClientConfig, Config, SocksClientPaths};
use crate::error::Socks5ClientError; use crate::error::Socks5ClientError;
use clap::CommandFactory; use clap::CommandFactory;
use clap::{Parser, Subcommand}; use clap::{Parser, Subcommand};
@@ -23,7 +22,6 @@ use nym_client_core::error::ClientCoreError;
use nym_config::OptionalSet; use nym_config::OptionalSet;
use nym_sphinx::params::{PacketSize, PacketType}; use nym_sphinx::params::{PacketSize, PacketType};
use std::error::Error; use std::error::Error;
use std::net::IpAddr;
pub(crate) mod build_info; pub(crate) mod build_info;
pub mod init; pub mod init;
@@ -74,7 +72,6 @@ pub(crate) enum Commands {
// Configuration that can be overridden. // Configuration that can be overridden.
pub(crate) struct OverrideConfig { pub(crate) struct OverrideConfig {
nym_apis: Option<Vec<url::Url>>, nym_apis: Option<Vec<url::Url>>,
ip: Option<IpAddr>,
port: Option<u16>, port: Option<u16>,
use_anonymous_replies: Option<bool>, use_anonymous_replies: Option<bool>,
fastmode: bool, fastmode: bool,
@@ -148,7 +145,6 @@ pub(crate) fn override_config(config: Config, args: OverrideConfig) -> Config {
) )
.with_optional(Config::with_anonymous_replies, args.use_anonymous_replies) .with_optional(Config::with_anonymous_replies, args.use_anonymous_replies)
.with_optional(Config::with_port, args.port) .with_optional(Config::with_port, args.port)
.with_optional(Config::with_ip, args.ip)
.with_optional_base_custom_env( .with_optional_base_custom_env(
BaseClientConfig::with_custom_nym_apis, BaseClientConfig::with_custom_nym_apis,
args.nym_apis, args.nym_apis,
@@ -168,17 +164,18 @@ pub(crate) fn override_config(config: Config, args: OverrideConfig) -> Config {
} }
fn persist_gateway_details( fn persist_gateway_details(
storage_paths: &SocksClientPaths, config: &Config,
details: GatewayEndpointConfig, details: GatewayEndpointConfig,
) -> Result<(), Socks5ClientError> { ) -> Result<(), Socks5ClientError> {
let details_store = OnDiskGatewayDetails::new(&storage_paths.common_paths.gateway_details); let details_store =
let keys_store = OnDiskKeys::new(storage_paths.common_paths.keys.clone()); OnDiskGatewayDetails::new(&config.storage_paths.common_paths.gateway_details);
let keys_store = OnDiskKeys::new(config.storage_paths.common_paths.keys.clone());
let shared_keys = keys_store.ephemeral_load_gateway_keys().map_err(|source| { let shared_keys = keys_store.ephemeral_load_gateway_keys().map_err(|source| {
Socks5ClientError::ClientCoreError(ClientCoreError::KeyStoreError { Socks5ClientError::ClientCoreError(ClientCoreError::KeyStoreError {
source: Box::new(source), source: Box::new(source),
}) })
})?; })?;
let persisted_details = PersistedGatewayDetails::new(details.into(), Some(&shared_keys))?; let persisted_details = PersistedGatewayDetails::new(details, &shared_keys);
details_store details_store
.store_to_disk(&persisted_details) .store_to_disk(&persisted_details)
.map_err(|source| { .map_err(|source| {
@@ -202,10 +199,9 @@ fn try_upgrade_v1_1_13_config(id: &str) -> Result<bool, Socks5ClientError> {
let updated_step1: ConfigV1_1_20 = old_config.into(); let updated_step1: ConfigV1_1_20 = old_config.into();
let updated_step2: ConfigV1_1_20_2 = updated_step1.into(); let updated_step2: ConfigV1_1_20_2 = updated_step1.into();
let (updated_step3, gateway_config) = updated_step2.upgrade()?; let (updated, gateway_config) = updated_step2.upgrade()?;
persist_gateway_details(&updated_step3.storage_paths, gateway_config)?; persist_gateway_details(&updated, gateway_config)?;
let updated: Config = updated_step3.into();
updated.save_to_default_location()?; updated.save_to_default_location()?;
Ok(true) Ok(true)
} }
@@ -223,10 +219,9 @@ fn try_upgrade_v1_1_20_config(id: &str) -> Result<bool, Socks5ClientError> {
info!("It is going to get updated to the current specification."); info!("It is going to get updated to the current specification.");
let updated_step1: ConfigV1_1_20_2 = old_config.into(); let updated_step1: ConfigV1_1_20_2 = old_config.into();
let (updated_step2, gateway_config) = updated_step1.upgrade()?; let (updated, gateway_config) = updated_step1.upgrade()?;
persist_gateway_details(&updated_step2.storage_paths, gateway_config)?; persist_gateway_details(&updated, gateway_config)?;
let updated: Config = updated_step2.into();
updated.save_to_default_location()?; updated.save_to_default_location()?;
Ok(true) Ok(true)
} }
@@ -241,25 +236,9 @@ fn try_upgrade_v1_1_20_2_config(id: &str) -> Result<bool, Socks5ClientError> {
info!("It seems the client is using <= v1.1.20_2 config template."); info!("It seems the client is using <= v1.1.20_2 config template.");
info!("It is going to get updated to the current specification."); info!("It is going to get updated to the current specification.");
let (updated_step1, gateway_config) = old_config.upgrade()?; let (updated, gateway_config) = old_config.upgrade()?;
persist_gateway_details(&updated_step1.storage_paths, gateway_config)?; persist_gateway_details(&updated, gateway_config)?;
let updated: Config = updated_step1.into();
updated.save_to_default_location()?;
Ok(true)
}
fn try_upgrade_v1_1_30_config(id: &str) -> Result<bool, Socks5ClientError> {
// explicitly load it as v1.1.30 (which is incompatible with the current one, i.e. +1.1.31)
let Ok(old_config) = ConfigV1_1_30::read_from_default_path(id) else {
// if we failed to load it, there might have been nothing to upgrade
// or maybe it was an even older file. in either way. just ignore it and carry on with our day
return Ok(false);
};
info!("It seems the client is using <= v1.1.30 config template.");
info!("It is going to get updated to the current specification.");
let updated: Config = old_config.into();
updated.save_to_default_location()?; updated.save_to_default_location()?;
Ok(true) Ok(true)
} }
@@ -274,9 +253,6 @@ fn try_upgrade_config(id: &str) -> Result<(), Socks5ClientError> {
if try_upgrade_v1_1_20_2_config(id)? { if try_upgrade_v1_1_20_2_config(id)? {
return Ok(()); return Ok(());
} }
if try_upgrade_v1_1_30_config(id)? {
return Ok(());
}
Ok(()) Ok(())
} }
+43 -16
View File
@@ -10,17 +10,18 @@ use crate::{
use clap::Args; use clap::Args;
use log::*; use log::*;
use nym_bin_common::version_checker::is_minor_version_compatible; use nym_bin_common::version_checker::is_minor_version_compatible;
use nym_client_core::cli_helpers::client_run::CommonClientRunArgs;
use nym_client_core::client::base_client::storage::OnDiskPersistent; use nym_client_core::client::base_client::storage::OnDiskPersistent;
use nym_client_core::client::topology_control::geo_aware_provider::CountryGroup; use nym_client_core::client::topology_control::geo_aware_provider::CountryGroup;
use nym_crypto::asymmetric::identity;
use nym_socks5_client_core::NymClient; use nym_socks5_client_core::NymClient;
use nym_sphinx::addressing::clients::Recipient; use nym_sphinx::addressing::clients::Recipient;
use std::net::IpAddr; use std::path::PathBuf;
#[derive(Args, Clone)] #[derive(Args, Clone)]
pub(crate) struct Run { pub(crate) struct Run {
#[command(flatten)] /// Id of the nym-mixnet-client we want to run.
common_args: CommonClientRunArgs, #[clap(long)]
id: String,
/// Specifies whether this client is going to use an anonymous sender tag for communication with the service provider. /// Specifies whether this client is going to use an anonymous sender tag for communication with the service provider.
/// While this is going to hide its actual address information, it will make the actual communication /// While this is going to hide its actual address information, it will make the actual communication
@@ -35,13 +36,35 @@ pub(crate) struct Run {
#[clap(long)] #[clap(long)]
provider: Option<Recipient>, provider: Option<Recipient>,
/// Id of the gateway we want to connect to. If overridden, it is user's responsibility to
/// ensure prior registration happened
#[clap(long)]
gateway: Option<identity::PublicKey>,
/// Comma separated list of rest endpoints of the nyxd validators
#[clap(long, alias = "nyxd_validators", value_delimiter = ',', hide = true)]
nyxd_urls: Option<Vec<url::Url>>,
/// Comma separated list of rest endpoints of the Nym APIs
#[clap(long, value_delimiter = ',', group = "network")]
nym_apis: Option<Vec<url::Url>>,
/// Port for the socket to listen on /// Port for the socket to listen on
#[clap(short, long)] #[clap(short, long)]
port: Option<u16>, port: Option<u16>,
/// The custom host on which the socks5 client will be listening for requests /// Path to .json file containing custom network specification.
#[clap(long)] #[clap(long, group = "network", group = "routing", hide = true)]
host: Option<IpAddr>, custom_mixnet: Option<PathBuf>,
/// Mostly debug-related option to increase default traffic rate so that you would not need to
/// modify config post init
#[clap(long, hide = true)]
fastmode: bool,
/// Disable loop cover traffic and the Poisson rate limiter (for debugging only)
#[clap(long, hide = true)]
no_cover: bool,
/// Set geo-aware mixnode selection when sending mixnet traffic, for experiments only. /// Set geo-aware mixnode selection when sending mixnet traffic, for experiments only.
#[clap(long, hide = true, value_parser = validate_country_group, group="routing")] #[clap(long, hide = true, value_parser = validate_country_group, group="routing")]
@@ -52,6 +75,11 @@ pub(crate) struct Run {
#[clap(long, hide = true)] #[clap(long, hide = true)]
medium_toggle: bool, medium_toggle: bool,
/// Set this client to work in a enabled credentials mode that would attempt to use gateway
/// with bandwidth credential requirement.
#[clap(long, hide = true)]
enabled_credentials_mode: Option<bool>,
#[clap(long, hide = true, action)] #[clap(long, hide = true, action)]
outfox: bool, outfox: bool,
} }
@@ -59,16 +87,15 @@ pub(crate) struct Run {
impl From<Run> for OverrideConfig { impl From<Run> for OverrideConfig {
fn from(run_config: Run) -> Self { fn from(run_config: Run) -> Self {
OverrideConfig { OverrideConfig {
nym_apis: run_config.common_args.nym_apis, nym_apis: run_config.nym_apis,
ip: run_config.host,
port: run_config.port, port: run_config.port,
use_anonymous_replies: run_config.use_anonymous_replies, use_anonymous_replies: run_config.use_anonymous_replies,
fastmode: run_config.common_args.fastmode, fastmode: run_config.fastmode,
no_cover: run_config.common_args.no_cover, no_cover: run_config.no_cover,
geo_routing: run_config.geo_routing, geo_routing: run_config.geo_routing,
medium_toggle: run_config.medium_toggle, medium_toggle: run_config.medium_toggle,
nyxd_urls: run_config.common_args.nyxd_urls, nyxd_urls: run_config.nyxd_urls,
enabled_credentials_mode: run_config.common_args.enabled_credentials_mode, enabled_credentials_mode: run_config.enabled_credentials_mode,
outfox: run_config.outfox, outfox: run_config.outfox,
} }
} }
@@ -103,9 +130,9 @@ fn version_check(cfg: &Config) -> bool {
} }
pub(crate) async fn execute(args: Run) -> Result<(), Box<dyn std::error::Error + Send + Sync>> { pub(crate) async fn execute(args: Run) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
eprintln!("Starting client {}...", args.common_args.id); eprintln!("Starting client {}...", args.id);
let mut config = try_load_current_config(&args.common_args.id)?; let mut config = try_load_current_config(&args.id)?;
config = override_config(config, OverrideConfig::from(args.clone())); config = override_config(config, OverrideConfig::from(args.clone()));
if !version_check(&config) { if !version_check(&config) {
@@ -116,7 +143,7 @@ pub(crate) async fn execute(args: Run) -> Result<(), Box<dyn std::error::Error +
let storage = let storage =
OnDiskPersistent::from_paths(config.storage_paths.common_paths, &config.core.base.debug) OnDiskPersistent::from_paths(config.storage_paths.common_paths, &config.core.base.debug)
.await?; .await?;
NymClient::new(config.core, storage, args.common_args.custom_mixnet) NymClient::new(config.core, storage, args.custom_mixnet)
.run_forever() .run_forever()
.await .await
} }
+3 -32
View File
@@ -1,10 +1,9 @@
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net> // Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
use crate::config::persistence::SocksClientPaths;
use crate::config::template::CONFIG_TEMPLATE; use crate::config::template::CONFIG_TEMPLATE;
use nym_bin_common::logging::LoggingSettings; use nym_bin_common::logging::LoggingSettings;
use nym_client_core::cli_helpers::client_init::ClientConfig;
use nym_client_core::config::disk_persistence::CommonClientPaths;
use nym_config::{ use nym_config::{
must_get_home, read_config_from_toml_file, save_formatted_config_to_file, NymConfigTemplate, must_get_home, read_config_from_toml_file, save_formatted_config_to_file, NymConfigTemplate,
DEFAULT_CONFIG_DIR, DEFAULT_CONFIG_FILENAME, DEFAULT_DATA_DIR, NYM_DIR, DEFAULT_CONFIG_DIR, DEFAULT_CONFIG_FILENAME, DEFAULT_DATA_DIR, NYM_DIR,
@@ -12,18 +11,15 @@ use nym_config::{
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::fmt::Debug; use std::fmt::Debug;
use std::io; use std::io;
use std::net::IpAddr;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::str::FromStr; use std::str::FromStr;
pub use crate::config::persistence::SocksClientPaths;
pub use nym_client_core::config::Config as BaseClientConfig; pub use nym_client_core::config::Config as BaseClientConfig;
pub use nym_socks5_client_core::config::Config as CoreConfig; pub use nym_socks5_client_core::config::Config as CoreConfig;
pub mod old_config_v1_1_13; pub mod old_config_v1_1_13;
pub mod old_config_v1_1_20; pub mod old_config_v1_1_20;
pub mod old_config_v1_1_20_2; pub mod old_config_v1_1_20_2;
pub mod old_config_v1_1_30;
mod persistence; mod persistence;
mod template; mod template;
@@ -66,29 +62,11 @@ pub struct Config {
} }
impl NymConfigTemplate for Config { impl NymConfigTemplate for Config {
fn template(&self) -> &'static str { fn template() -> &'static str {
CONFIG_TEMPLATE CONFIG_TEMPLATE
} }
} }
impl ClientConfig for Config {
fn common_paths(&self) -> &CommonClientPaths {
&self.storage_paths.common_paths
}
fn core_config(&self) -> &BaseClientConfig {
&self.core.base
}
fn default_store_location(&self) -> PathBuf {
self.default_location()
}
fn save_to<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
save_formatted_config_to_file(self, path)
}
}
impl Config { impl Config {
pub fn new<S: AsRef<str>>(id: S, provider_mix_address: S) -> Self { pub fn new<S: AsRef<str>>(id: S, provider_mix_address: S) -> Self {
Config { Config {
@@ -124,15 +102,8 @@ impl Config {
self.core.validate() self.core.validate()
} }
#[must_use]
pub fn with_port(mut self, port: u16) -> Self { pub fn with_port(mut self, port: u16) -> Self {
self.core = self.core.with_port(port); self.core.socks5.listening_port = port;
self
}
#[must_use]
pub fn with_ip(mut self, ip: IpAddr) -> Self {
self.core = self.core.with_ip(ip);
self self
} }
@@ -1,11 +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::config::old_config_v1_1_30::ConfigV1_1_30;
use crate::{ use crate::{
config::{default_config_filepath, persistence::SocksClientPaths}, config::{default_config_filepath, persistence::SocksClientPaths, Config},
error::Socks5ClientError, error::Socks5ClientError,
}; };
use nym_bin_common::logging::LoggingSettings; use nym_bin_common::logging::LoggingSettings;
use nym_client_core::config::disk_persistence::old_v1_1_20_2::CommonClientPathsV1_1_20_2; use nym_client_core::config::disk_persistence::old_v1_1_20_2::CommonClientPathsV1_1_20_2;
use nym_client_core::config::GatewayEndpointConfig; use nym_client_core::config::GatewayEndpointConfig;
@@ -43,9 +43,9 @@ impl ConfigV1_1_20_2 {
// in this upgrade, gateway endpoint configuration was moved out of the config file, // in this upgrade, gateway endpoint configuration was moved out of the config file,
// so its returned to be stored elsewhere. // so its returned to be stored elsewhere.
pub fn upgrade(self) -> Result<(ConfigV1_1_30, GatewayEndpointConfig), Socks5ClientError> { pub fn upgrade(self) -> Result<(Config, GatewayEndpointConfig), Socks5ClientError> {
let gateway_details = self.core.base.client.gateway_endpoint.clone().into(); let gateway_details = self.core.base.client.gateway_endpoint.clone().into();
let config = ConfigV1_1_30 { let config = Config {
core: self.core.into(), core: self.core.into(),
storage_paths: SocksClientPaths { storage_paths: SocksClientPaths {
common_paths: self.storage_paths.common_paths.upgrade_default()?, common_paths: self.storage_paths.common_paths.upgrade_default()?,
@@ -1,44 +0,0 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::config::persistence::SocksClientPaths;
use crate::config::{default_config_filepath, Config};
use nym_bin_common::logging::LoggingSettings;
use nym_config::read_config_from_toml_file;
use nym_socks5_client_core::config::old_config_v1_1_30::ConfigV1_1_30 as CoreConfigV1_1_30;
use serde::{Deserialize, Serialize};
use std::io;
use std::path::Path;
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct ConfigV1_1_30 {
pub core: CoreConfigV1_1_30,
// I'm leaving a landmine here for when the paths actually do change the next time,
// but propagating the change right now (in ALL clients) would be such a hassle...,
// so sorry for the next person looking at it : )
pub storage_paths: SocksClientPaths,
pub logging: LoggingSettings,
}
impl From<ConfigV1_1_30> for Config {
fn from(value: ConfigV1_1_30) -> Self {
Config {
core: value.core.into(),
storage_paths: value.storage_paths,
logging: LoggingSettings::default(),
}
}
}
impl ConfigV1_1_30 {
pub fn read_from_toml_file<P: AsRef<Path>>(path: P) -> io::Result<Self> {
read_config_from_toml_file(path)
}
pub fn read_from_default_path<P: AsRef<Path>>(id: P) -> io::Result<Self> {
Self::read_from_toml_file(default_config_filepath(id))
}
}
+1 -1
View File
@@ -14,7 +14,7 @@ pub struct SocksClientPaths {
impl SocksClientPaths { impl SocksClientPaths {
pub fn new_default<P: AsRef<Path>>(base_data_directory: P) -> Self { pub fn new_default<P: AsRef<Path>>(base_data_directory: P) -> Self {
SocksClientPaths { SocksClientPaths {
common_paths: CommonClientPaths::new_base(base_data_directory), common_paths: CommonClientPaths::new_default(base_data_directory),
} }
} }
} }
+2 -3
View File
@@ -75,9 +75,8 @@ gateway_details = '{{ storage_paths.gateway_details }}'
# The mix address of the provider to which all requests are going to be sent. # The mix address of the provider to which all requests are going to be sent.
provider_mix_address = '{{ core.socks5.provider_mix_address }}' provider_mix_address = '{{ core.socks5.provider_mix_address }}'
# The address on which the client will be listening for incoming requests # The port on which the client will be listening for incoming requests
# (default: 127.0.0.1:1080) listening_port = {{ core.socks5.listening_port }}
bind_adddress = '{{ core.socks5.bind_adddress }}'
# Specifies whether this client is going to use an anonymous sender tag for communication with the service provider. # Specifies whether this client is going to use an anonymous sender tag for communication with the service provider.
# While this is going to hide its actual address information, it will make the actual communication # While this is going to hide its actual address information, it will make the actual communication
+1 -6
View File
@@ -21,10 +21,5 @@ async fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
} }
setup_logging(); setup_logging();
if let Err(err) = commands::execute(args).await { commands::execute(args).await
log::error!("{err}");
println!("An error occurred: {err}");
std::process::exit(1);
}
Ok(())
} }
+1 -1
View File
@@ -8,7 +8,7 @@ edition = "2021"
[dependencies] [dependencies]
bip39 = { workspace = true } bip39 = { workspace = true }
rand = "0.7.3" rand = "0.7.3"
thiserror = { workspace = true } thiserror = "1.0"
url = { workspace = true } url = { workspace = true }
nym-coconut-interface = { path = "../coconut-interface" } nym-coconut-interface = { path = "../coconut-interface" }
+1 -5
View File
@@ -9,13 +9,12 @@ repository = { workspace = true }
[dependencies] [dependencies]
atty = "0.2" atty = "0.2"
clap = { workspace = true, features = ["derive"] } clap = { version = "4.0", features = ["derive"] }
clap_complete = "4.0" clap_complete = "4.0"
clap_complete_fig = "4.0" clap_complete_fig = "4.0"
log = { workspace = true } log = { workspace = true }
pretty_env_logger = "0.4.0" pretty_env_logger = "0.4.0"
semver = "0.11" semver = "0.11"
schemars = { workspace = true, features = ["preserve_order"], optional = true }
serde = { workspace = true, features = ["derive"] } serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true, optional = true } serde_json = { workspace = true, optional = true }
@@ -30,7 +29,6 @@ opentelemetry-jaeger = { version = "0.18.0", optional = true, features = [
"isahc_collector_client", "isahc_collector_client",
] } ] }
tracing-opentelemetry = { version = "0.19.0", optional = true } tracing-opentelemetry = { version = "0.19.0", optional = true }
utoipa = { workspace = true, optional = true }
opentelemetry = { version = "0.19.0", optional = true, features = ["rt-tokio"] } opentelemetry = { version = "0.19.0", optional = true, features = ["rt-tokio"] }
@@ -44,9 +42,7 @@ vergen = { version = "=7.4.3", default-features = false, features = [
[features] [features]
default = [] default = []
openapi = ["utoipa"]
output_format = ["serde_json"] output_format = ["serde_json"]
bin_info_schema = ["schemars"]
tracing = [ tracing = [
"tracing-subscriber", "tracing-subscriber",
"tracing-tree", "tracing-tree",
@@ -81,8 +81,6 @@ impl BinaryBuildInformation {
} }
#[derive(Clone, Debug, Serialize, Deserialize)] #[derive(Clone, Debug, Serialize, Deserialize)]
#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "bin_info_schema", derive(schemars::JsonSchema))]
pub struct BinaryBuildInformationOwned { pub struct BinaryBuildInformationOwned {
/// Provides the name of the binary, i.e. the content of `CARGO_PKG_NAME` environmental variable. /// Provides the name of the binary, i.e. the content of `CARGO_PKG_NAME` environmental variable.
pub binary_name: String, pub binary_name: String,
@@ -32,14 +32,4 @@ impl OutputFormat {
OutputFormat::Json => serde_json::to_string(data).unwrap(), OutputFormat::Json => serde_json::to_string(data).unwrap(),
} }
} }
#[cfg(feature = "output_format")]
pub fn to_stdout<T: serde::Serialize + ToString>(&self, data: &T) {
println!("{}", self.format(data))
}
#[cfg(feature = "output_format")]
pub fn to_stderr<T: serde::Serialize + ToString>(&self, data: &T) {
eprintln!("{}", self.format(data))
}
} }
+4 -5
View File
@@ -11,8 +11,7 @@ rust-version = "1.66"
async-trait = { workspace = true } async-trait = { workspace = true }
base64 = "0.21.2" base64 = "0.21.2"
cfg-if = "1.0.0" cfg-if = "1.0.0"
clap = { workspace = true, optional = true } dashmap = "5.4.0"
dashmap = { workspace = true }
dirs = "4.0" dirs = "4.0"
futures = { workspace = true } futures = { workspace = true }
humantime-serde = "1.0" humantime-serde = "1.0"
@@ -25,7 +24,7 @@ sha2 = "0.10.6"
tap = "1.0.1" tap = "1.0.1"
thiserror = { workspace = true } thiserror = { workspace = true }
url = { workspace = true, features = ["serde"] } url = { workspace = true, features = ["serde"] }
tungstenite = { workspace = true, default-features = false } tungstenite = { version = "0.13.0", default-features = false }
tokio = { workspace = true, features = ["macros"]} tokio = { workspace = true, features = ["macros"]}
time = "0.3.17" time = "0.3.17"
zeroize = { workspace = true } zeroize = { workspace = true }
@@ -36,6 +35,7 @@ nym-config = { path = "../config" }
nym-crypto = { path = "../crypto" } nym-crypto = { path = "../crypto" }
nym-explorer-client = { path = "../../explorer-api/explorer-client" } nym-explorer-client = { path = "../../explorer-api/explorer-client" }
nym-gateway-client = { path = "../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"] }
nym-gateway-requests = { path = "../../gateway/gateway-requests" } nym-gateway-requests = { path = "../../gateway/gateway-requests" }
nym-nonexhaustive-delayqueue = { path = "../nonexhaustive-delayqueue" } nym-nonexhaustive-delayqueue = { path = "../nonexhaustive-delayqueue" }
nym-sphinx = { path = "../nymsphinx" } nym-sphinx = { path = "../nymsphinx" }
@@ -55,7 +55,7 @@ workspace = true
features = ["time"] features = ["time"]
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.tokio-tungstenite] [target."cfg(not(target_arch = \"wasm32\"))".dependencies.tokio-tungstenite]
version = "0.20.1" version = "0.14"
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.sqlx] [target."cfg(not(target_arch = \"wasm32\"))".dependencies.sqlx]
version = "0.6.2" version = "0.6.2"
@@ -93,7 +93,6 @@ sqlx = { version = "0.6.2", features = ["runtime-tokio-rustls", "sqlite", "macro
[features] [features]
default = [] default = []
cli = ["clap"]
fs-surb-storage = ["sqlx"] fs-surb-storage = ["sqlx"]
wasm = ["nym-gateway-client/wasm"] wasm = ["nym-gateway-client/wasm"]
@@ -1,210 +0,0 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::config::disk_persistence::CommonClientPaths;
use crate::error::ClientCoreError;
use crate::{
client::{
base_client::storage::gateway_details::OnDiskGatewayDetails,
key_manager::persistence::OnDiskKeys,
},
init::types::{GatewayDetails, GatewaySelectionSpecification, GatewaySetup, InitResults},
};
use log::info;
use nym_crypto::asymmetric::identity;
use nym_topology::NymTopology;
use std::path::{Path, PathBuf};
pub trait InitialisableClient {
const NAME: &'static str;
type Error: From<ClientCoreError>;
type InitArgs: AsRef<CommonClientInitArgs>;
type Config: ClientConfig;
fn try_upgrade_outdated_config(id: &str) -> Result<(), Self::Error>;
fn initialise_storage_paths(id: &str) -> Result<(), Self::Error>;
fn default_config_path(id: &str) -> PathBuf;
fn construct_config(init_args: &Self::InitArgs) -> Self::Config;
}
pub trait ClientConfig {
fn common_paths(&self) -> &CommonClientPaths;
fn core_config(&self) -> &crate::config::Config;
fn default_store_location(&self) -> PathBuf;
fn save_to<P: AsRef<Path>>(&self, path: P) -> std::io::Result<()>;
}
#[cfg_attr(feature = "cli", derive(clap::Args))]
#[derive(Debug, Clone)]
pub struct CommonClientInitArgs {
/// Id of client we want to create config for.
#[cfg_attr(feature = "cli", clap(long))]
pub id: String,
/// Id of the gateway we are going to connect to.
#[cfg_attr(feature = "cli", clap(long))]
pub gateway: Option<identity::PublicKey>,
/// Specifies whether the new gateway should be determined based by latency as opposed to being chosen
/// uniformly.
#[cfg_attr(feature = "cli", clap(long, conflicts_with = "gateway"))]
pub latency_based_selection: bool,
/// Force register gateway. WARNING: this will overwrite any existing keys for the given id,
/// potentially causing loss of access.
#[cfg_attr(feature = "cli", clap(long))]
pub force_register_gateway: bool,
/// Comma separated list of rest endpoints of the nyxd validators
#[cfg_attr(
feature = "cli",
clap(long, alias = "nyxd_validators", value_delimiter = ',', hide = true)
)]
pub nyxd_urls: Option<Vec<url::Url>>,
/// Comma separated list of rest endpoints of the API validators
#[cfg_attr(
feature = "cli",
clap(
long,
alias = "api_validators",
value_delimiter = ',',
group = "network"
)
)]
pub nym_apis: Option<Vec<url::Url>>,
/// Path to .json file containing custom network specification.
#[cfg_attr(feature = "cli", clap(long, group = "network", hide = true))]
pub custom_mixnet: Option<PathBuf>,
/// Set this client to work in a enabled credentials mode that would attempt to use gateway
/// with bandwidth credential requirement.
#[cfg_attr(feature = "cli", clap(long, hide = true))]
pub enabled_credentials_mode: Option<bool>,
/// Mostly debug-related option to increase default traffic rate so that you would not need to
/// modify config post init
#[cfg_attr(feature = "cli", clap(long, hide = true))]
pub fastmode: bool,
/// Disable loop cover traffic and the Poisson rate limiter (for debugging only)
#[cfg_attr(feature = "cli", clap(long, hide = true))]
pub no_cover: bool,
}
pub struct InitResultsWithConfig<T> {
pub config: T,
pub init_results: InitResults,
}
pub async fn initialise_client<C>(
init_args: C::InitArgs,
) -> Result<InitResultsWithConfig<C::Config>, C::Error>
where
C: InitialisableClient,
{
info!("initialising {} client", C::NAME);
let common_args = init_args.as_ref();
let id = &common_args.id;
let already_init = if C::default_config_path(id).exists() {
// in case we're using old config, try to upgrade it
// (if we're using the current version, it's a no-op)
C::try_upgrade_outdated_config(id)?;
eprintln!("{} client \"{id}\" was already initialised before", C::NAME);
true
} else {
C::initialise_storage_paths(id)?;
false
};
// Usually you only register with the gateway on the first init, however you can force
// re-registering if wanted.
let user_wants_force_register = common_args.force_register_gateway;
if user_wants_force_register {
eprintln!("Instructed to force registering gateway. This might overwrite keys!");
}
// If the client was already initialized, don't generate new keys and don't re-register with
// the gateway (because this would create a new shared key).
// Unless the user really wants to.
let register_gateway = !already_init || user_wants_force_register;
// Attempt to use a user-provided gateway, if possible
let user_chosen_gateway_id = common_args.gateway;
let selection_spec = GatewaySelectionSpecification::new(
user_chosen_gateway_id.map(|id| id.to_base58_string()),
Some(common_args.latency_based_selection),
false,
);
// Load and potentially override config
let config = C::construct_config(&init_args);
let paths = config.common_paths();
let core = config.core_config();
// Setup gateway by either registering a new one, or creating a new config from the selected
// one but with keys kept, or reusing the gateway configuration.
let key_store = OnDiskKeys::new(paths.keys.clone());
let details_store = OnDiskGatewayDetails::new(&paths.gateway_details);
let available_gateways = if let Some(custom_mixnet) = common_args.custom_mixnet.as_ref() {
let hardcoded_topology = NymTopology::new_from_file(custom_mixnet).map_err(|source| {
ClientCoreError::CustomTopologyLoadFailure {
file_path: custom_mixnet.clone(),
source,
}
})?;
hardcoded_topology.get_gateways()
} else {
let mut rng = rand::thread_rng();
crate::init::helpers::current_gateways(&mut rng, &core.client.nym_api_urls).await?
};
let gateway_setup = GatewaySetup::New {
specification: selection_spec,
available_gateways,
overwrite_data: register_gateway,
};
let init_details =
crate::init::setup_gateway(gateway_setup, &key_store, &details_store).await?;
// TODO: ask the service provider we specified for its interface version and set it in the config
let config_save_location = config.default_store_location();
if let Err(err) = config.save_to(&config_save_location) {
return Err(ClientCoreError::ConfigSaveFailure {
typ: C::NAME.to_string(),
id: id.to_string(),
path: config_save_location,
source: err,
}
.into());
}
eprintln!(
"Saved configuration file to {}",
config_save_location.display()
);
let address = init_details.client_address()?;
let GatewayDetails::Configured(gateway_details) = init_details.gateway_details else {
return Err(ClientCoreError::UnexpectedPersistedCustomGatewayDetails)?;
};
let init_results = InitResults::new(config.core_config(), address, &gateway_details);
Ok(InitResultsWithConfig {
config,
init_results,
})
}
@@ -1,59 +0,0 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use nym_crypto::asymmetric::identity;
use std::path::PathBuf;
#[cfg_attr(feature = "cli", derive(clap::Args))]
#[derive(Debug, Clone)]
pub struct CommonClientRunArgs {
/// Id of client we want to create config for.
#[cfg_attr(feature = "cli", clap(long))]
pub id: String,
/// Id of the gateway we want to connect to. If overridden, it is user's responsibility to
/// ensure prior registration happened
#[cfg_attr(feature = "cli", clap(long))]
pub gateway: Option<identity::PublicKey>,
/// Comma separated list of rest endpoints of the nyxd validators
#[cfg_attr(
feature = "cli",
clap(long, alias = "nyxd_validators", value_delimiter = ',', hide = true)
)]
pub nyxd_urls: Option<Vec<url::Url>>,
/// Comma separated list of rest endpoints of the API validators
#[cfg_attr(
feature = "cli",
clap(
long,
alias = "api_validators",
value_delimiter = ',',
group = "network"
)
)]
pub nym_apis: Option<Vec<url::Url>>,
/// Path to .json file containing custom network specification.
#[cfg_attr(feature = "cli", clap(long, group = "network", hide = true))]
pub custom_mixnet: Option<PathBuf>,
/// Set this client to work in a enabled credentials mode that would attempt to use gateway
/// with bandwidth credential requirement.
#[cfg_attr(feature = "cli", clap(long, hide = true))]
pub enabled_credentials_mode: Option<bool>,
/// Mostly debug-related option to increase default traffic rate so that you would not need to
/// modify config post init
// note: we removed the 'conflicts_with = medium_toggle', but that's fine since NR
// has defined the conflict on that field itself
#[cfg_attr(feature = "cli", clap(long, hide = true))]
pub fastmode: bool,
/// Disable loop cover traffic and the Poisson rate limiter (for debugging only)
// note: we removed the 'conflicts_with = medium_toggle', but that's fine since NR
// has defined the conflict on that field itself
#[cfg_attr(feature = "cli", clap(long, hide = true))]
pub no_cover: bool,
}
@@ -1,5 +0,0 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
pub mod client_init;
pub mod client_run;
+89 -170
View File
@@ -8,7 +8,6 @@ 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::persistence::KeyStore;
use crate::client::mix_traffic::transceiver::{GatewayReceiver, GatewayTransceiver, RemoteGateway};
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;
@@ -26,18 +25,16 @@ use crate::client::topology_control::{
}; };
use crate::config::{Config, DebugConfig}; use crate::config::{Config, DebugConfig};
use crate::error::ClientCoreError; use crate::error::ClientCoreError;
use crate::init::{ use crate::init::{setup_gateway, GatewaySetup, InitialisationDetails, InitialisationResult};
setup_gateway,
types::{GatewayDetails, GatewaySetup, InitialisationResult},
};
use crate::{config, spawn_future}; use crate::{config, spawn_future};
use futures::channel::mpsc; use futures::channel::mpsc;
use log::{debug, error, info}; use log::{debug, info};
use nym_bandwidth_controller::BandwidthController; use nym_bandwidth_controller::BandwidthController;
use nym_credential_storage::storage::Storage as CredentialStorage; use nym_credential_storage::storage::Storage as CredentialStorage;
use nym_crypto::asymmetric::encryption; use nym_crypto::asymmetric::{encryption, identity};
use nym_gateway_client::{ use nym_gateway_client::{
AcknowledgementReceiver, GatewayClient, MixnetMessageReceiver, PacketRouter, AcknowledgementReceiver, AcknowledgementSender, GatewayClient, MixnetMessageReceiver,
MixnetMessageSender,
}; };
use nym_sphinx::acknowledgements::AckKey; use nym_sphinx::acknowledgements::AckKey;
use nym_sphinx::addressing::clients::Recipient; use nym_sphinx::addressing::clients::Recipient;
@@ -45,11 +42,10 @@ use nym_sphinx::addressing::nodes::NodeIdentity;
use nym_sphinx::params::PacketType; use nym_sphinx::params::PacketType;
use nym_sphinx::receiver::{ReconstructedMessage, SphinxMessageReceiver}; use nym_sphinx::receiver::{ReconstructedMessage, SphinxMessageReceiver};
use nym_task::connections::{ConnectionCommandReceiver, ConnectionCommandSender, LaneQueueLengths}; use nym_task::connections::{ConnectionCommandReceiver, ConnectionCommandSender, LaneQueueLengths};
use nym_task::{TaskClient, TaskHandle}; use nym_task::{TaskClient, TaskManager};
use nym_topology::provider_trait::TopologyProvider; use nym_topology::provider_trait::TopologyProvider;
use nym_topology::HardcodedTopologyProvider; use nym_topology::HardcodedTopologyProvider;
use nym_validator_client::nyxd::contract_traits::DkgQueryClient; use nym_validator_client::nyxd::contract_traits::DkgQueryClient;
use std::fmt::Debug;
use std::path::Path; use std::path::Path;
use std::sync::Arc; use std::sync::Arc;
use url::Url; use url::Url;
@@ -161,12 +157,7 @@ pub struct BaseClientBuilder<'a, C, S: MixnetClientStorage> {
config: &'a Config, config: &'a Config,
client_store: S, client_store: S,
dkg_query_client: Option<C>, dkg_query_client: Option<C>,
wait_for_gateway: bool,
custom_topology_provider: Option<Box<dyn TopologyProvider + Send + Sync>>, custom_topology_provider: Option<Box<dyn TopologyProvider + Send + Sync>>,
custom_gateway_transceiver: Option<Box<dyn GatewayTransceiver + Send>>,
shutdown: Option<TaskClient>,
setup_method: GatewaySetup, setup_method: GatewaySetup,
} }
@@ -184,10 +175,7 @@ where
config: base_config, config: base_config,
client_store, client_store,
dkg_query_client, dkg_query_client,
wait_for_gateway: false,
custom_topology_provider: None, custom_topology_provider: None,
custom_gateway_transceiver: None,
shutdown: None,
setup_method: GatewaySetup::MustLoad, setup_method: GatewaySetup::MustLoad,
} }
} }
@@ -198,12 +186,6 @@ where
self self
} }
#[must_use]
pub fn with_wait_for_gateway(mut self, wait_for_gateway: bool) -> Self {
self.wait_for_gateway = wait_for_gateway;
self
}
#[must_use] #[must_use]
pub fn with_topology_provider( pub fn with_topology_provider(
mut self, mut self,
@@ -213,18 +195,6 @@ where
self self
} }
#[must_use]
pub fn with_gateway_transceiver(mut self, sender: Box<dyn GatewayTransceiver + Send>) -> Self {
self.custom_gateway_transceiver = Some(sender);
self
}
#[must_use]
pub fn with_shutdown(mut self, shutdown: TaskClient) -> Self {
self.shutdown = Some(shutdown);
self
}
pub fn with_stored_topology<P: AsRef<Path>>( pub fn with_stored_topology<P: AsRef<Path>>(
mut self, mut self,
file: P, file: P,
@@ -236,13 +206,13 @@ where
// note: do **NOT** make this method public as its only valid usage is from within `start_base` // note: do **NOT** make this method public as its only valid usage is from within `start_base`
// because it relies on the crypto keys being already loaded // because it relies on the crypto keys being already loaded
fn mix_address(details: &InitialisationResult) -> Recipient { fn mix_address(details: &InitialisationDetails) -> Recipient {
Recipient::new( Recipient::new(
*details.managed_keys.identity_public_key(), *details.managed_keys.identity_public_key(),
*details.managed_keys.encryption_public_key(), *details.managed_keys.encryption_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(details.gateway_details.gateway_id()).unwrap(), NodeIdentity::from_base58_string(&details.gateway_details.gateway_id).unwrap(),
) )
} }
@@ -329,37 +299,50 @@ where
config: &Config, config: &Config,
initialisation_result: InitialisationResult, initialisation_result: InitialisationResult,
bandwidth_controller: Option<BandwidthController<C, S::CredentialStore>>, bandwidth_controller: Option<BandwidthController<C, S::CredentialStore>>,
packet_router: PacketRouter, mixnet_message_sender: MixnetMessageSender,
ack_sender: AcknowledgementSender,
shutdown: TaskClient, shutdown: TaskClient,
) -> Result<GatewayClient<C, S::CredentialStore>, ClientCoreError> ) -> Result<GatewayClient<C, S::CredentialStore>, ClientCoreError>
where where
<S::KeyStore as KeyStore>::StorageError: Send + Sync + 'static, <S::KeyStore as KeyStore>::StorageError: Send + Sync + 'static,
<S::CredentialStore as CredentialStorage>::StorageError: Send + Sync + 'static, <S::CredentialStore as CredentialStorage>::StorageError: Send + Sync + 'static,
{ {
let managed_keys = initialisation_result.managed_keys; let managed_keys = initialisation_result.details.managed_keys;
let GatewayDetails::Configured(gateway_config) = initialisation_result.gateway_details
else {
return Err(ClientCoreError::UnexpectedPersistedCustomGatewayDetails);
};
let mut gateway_client = let mut gateway_client =
if let Some(existing_client) = initialisation_result.authenticated_ephemeral_client { if let Some(existing_client) = initialisation_result.authenticated_ephemeral_client {
existing_client.upgrade(packet_router, bandwidth_controller, shutdown) existing_client.upgrade(
} else { mixnet_message_sender,
let cfg = gateway_config.try_into()?; ack_sender,
GatewayClient::new( config.debug.gateway_connection.gateway_response_timeout,
cfg, bandwidth_controller,
managed_keys.identity_keypair(), shutdown,
Some(managed_keys.must_get_gateway_shared_key()), )
packet_router, } else {
let gateway_config = initialisation_result.details.gateway_details;
let gateway_address = gateway_config.gateway_listener.clone();
let gateway_id = gateway_config.gateway_id;
// TODO: in theory, at this point, this should be infallible
let gateway_identity = identity::PublicKey::from_base58_string(gateway_id)
.map_err(ClientCoreError::UnableToCreatePublicKeyFromGatewayId)?;
GatewayClient::new(
gateway_address,
managed_keys.identity_keypair(),
gateway_identity,
Some(managed_keys.must_get_gateway_shared_key()),
mixnet_message_sender,
ack_sender,
config.debug.gateway_connection.gateway_response_timeout,
bandwidth_controller, bandwidth_controller,
shutdown, shutdown,
) )
.with_disabled_credentials_mode(config.client.disabled_credentials_mode)
.with_response_timeout(config.debug.gateway_connection.gateway_response_timeout)
}; };
let gateway_id = gateway_client.gateway_identity(); let gateway_id = gateway_client.gateway_identity();
gateway_client.set_disabled_credentials_mode(config.client.disabled_credentials_mode);
let shared_key = gateway_client let shared_key = gateway_client
.authenticate_and_start() .authenticate_and_start()
@@ -372,48 +355,11 @@ where
} }
})?; })?;
managed_keys.ensure_gateway_key(Some(shared_key)); managed_keys.ensure_gateway_key(shared_key);
Ok(gateway_client) Ok(gateway_client)
} }
async fn setup_gateway_transceiver(
custom_gateway_transceiver: Option<Box<dyn GatewayTransceiver + Send>>,
config: &Config,
initialisation_result: InitialisationResult,
bandwidth_controller: Option<BandwidthController<C, S::CredentialStore>>,
packet_router: PacketRouter,
mut shutdown: TaskClient,
) -> Result<Box<dyn GatewayTransceiver + Send>, ClientCoreError>
where
<S::KeyStore as KeyStore>::StorageError: Send + Sync + 'static,
<S::CredentialStore as CredentialStorage>::StorageError: Send + Sync + 'static,
{
// if we have setup custom gateway sender and persisted details agree with it, return it
if let Some(mut custom_gateway_transceiver) = custom_gateway_transceiver {
return if !initialisation_result.gateway_details.is_custom() {
Err(ClientCoreError::CustomGatewaySelectionExpected)
} else {
// and make sure to invalidate the task client so we wouldn't cause premature shutdown
shutdown.mark_as_success();
custom_gateway_transceiver.set_packet_router(packet_router)?;
Ok(custom_gateway_transceiver)
};
}
// otherwise, setup normal gateway client, etc
let gateway_client = Self::start_gateway_client(
config,
initialisation_result,
bandwidth_controller,
packet_router,
shutdown,
)
.await?;
Ok(Box::new(RemoteGateway::new(gateway_client)))
}
fn setup_topology_provider( fn setup_topology_provider(
custom_provider: Option<Box<dyn TopologyProvider + Send + Sync>>, custom_provider: Option<Box<dyn TopologyProvider + Send + Sync>>,
provider_from_config: config::TopologyStructure, provider_from_config: config::TopologyStructure,
@@ -441,8 +387,6 @@ where
topology_provider: Box<dyn TopologyProvider + Send + Sync>, topology_provider: Box<dyn TopologyProvider + Send + Sync>,
topology_config: config::Topology, topology_config: config::Topology,
topology_accessor: TopologyAccessor, topology_accessor: TopologyAccessor,
local_gateway: &NodeIdentity,
wait_for_gateway: bool,
mut shutdown: TaskClient, mut shutdown: TaskClient,
) -> Result<(), ClientCoreError> { ) -> Result<(), ClientCoreError> {
let topology_refresher_config = let topology_refresher_config =
@@ -466,32 +410,6 @@ where
return Err(ClientCoreError::InsufficientNetworkTopology(err)); return Err(ClientCoreError::InsufficientNetworkTopology(err));
} }
let gateway_wait_timeout = if wait_for_gateway {
Some(topology_config.max_startup_gateway_waiting_period)
} else {
None
};
if let Err(err) = topology_refresher
.ensure_contains_gateway(local_gateway)
.await
{
if let Some(waiting_timeout) = gateway_wait_timeout {
if let Err(err) = topology_refresher
.wait_for_gateway(local_gateway, waiting_timeout)
.await
{
error!(
"the gateway did not come back online within the specified timeout: {err}"
);
return Err(err.into());
}
} else {
error!("the gateway we're supposedly connected to does not exist. We'll not be able to send any packets to ourselves: {err}");
return Err(err.into());
}
}
if topology_config.disable_refreshing { if topology_config.disable_refreshing {
// if we're not spawning the refresher, don't cause shutdown immediately // if we're not spawning the refresher, don't cause shutdown immediately
info!("The topology refesher is not going to be started"); info!("The topology refesher is not going to be started");
@@ -506,12 +424,19 @@ where
Ok(()) Ok(())
} }
// controller for sending 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
// over it. Perhaps GatewayClient needs to be thread-shareable or have some channel for
// requests?
fn start_mix_traffic_controller( fn start_mix_traffic_controller(
gateway_transceiver: Box<dyn GatewayTransceiver + Send>, gateway_client: GatewayClient<C, S::CredentialStore>,
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_transceiver); 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
} }
@@ -548,12 +473,21 @@ where
setup_method: GatewaySetup, setup_method: GatewaySetup,
key_store: &S::KeyStore, key_store: &S::KeyStore,
details_store: &S::GatewayDetailsStore, details_store: &S::GatewayDetailsStore,
overwrite_data: bool,
validator_servers: Option<&[Url]>,
) -> Result<InitialisationResult, ClientCoreError> ) -> Result<InitialisationResult, ClientCoreError>
where where
<S::KeyStore as KeyStore>::StorageError: Sync + Send, <S::KeyStore as KeyStore>::StorageError: Sync + Send,
<S::GatewayDetailsStore as GatewayDetailsStore>::StorageError: Sync + Send, <S::GatewayDetailsStore as GatewayDetailsStore>::StorageError: Sync + Send,
{ {
setup_gateway(setup_method, key_store, details_store).await setup_gateway(
setup_method,
key_store,
details_store,
overwrite_data,
validator_servers,
)
.await
} }
pub async fn start_base(mut self) -> Result<BaseClient, ClientCoreError> pub async fn start_base(mut self) -> Result<BaseClient, ClientCoreError>
@@ -571,11 +505,17 @@ where
self.setup_method, self.setup_method,
self.client_store.key_store(), self.client_store.key_store(),
self.client_store.gateway_details_store(), self.client_store.gateway_details_store(),
false,
Some(&self.config.client.nym_api_urls),
) )
.await?; .await?;
let (reply_storage_backend, credential_store) = self.client_store.into_runtime_stores(); 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
@@ -596,25 +536,31 @@ where
let shared_topology_accessor = TopologyAccessor::new(); let shared_topology_accessor = TopologyAccessor::new();
// Shutdown notifier for signalling tasks to stop // Shutdown notifier for signalling tasks to stop
let shutdown = self let task_manager = TaskManager::default();
.shutdown
.map(Into::<TaskHandle>::into)
.unwrap_or_default()
.name_if_unnamed("BaseNymClient");
// channels responsible for dealing with reply-related fun // channels responsible for dealing with reply-related fun
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(&init_res); let self_address = Self::mix_address(&init_res.details);
let ack_key = init_res.managed_keys.ack_key(); let ack_key = init_res.details.managed_keys.ack_key();
let encryption_keys = init_res.managed_keys.encryption_keypair(); let encryption_keys = init_res.details.managed_keys.encryption_keypair();
// 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 bandwidth_controller = self let gateway_client = Self::start_gateway_client(
.dkg_query_client self.config,
.map(|client| BandwidthController::new(credential_store, client)); init_res,
bandwidth_controller,
mixnet_messages_sender,
ack_sender,
task_manager.subscribe(),
)
.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(),
@@ -622,36 +568,11 @@ where
self.config.get_nym_api_endpoints(), self.config.get_nym_api_endpoints(),
); );
// needs to be started as the first thing to block if required waiting for the gateway
Self::start_topology_refresher( Self::start_topology_refresher(
topology_provider, topology_provider,
self.config.debug.topology, self.config.debug.topology,
shared_topology_accessor.clone(), shared_topology_accessor.clone(),
self_address.gateway(), task_manager.subscribe(),
self.wait_for_gateway,
shutdown.fork("topology_refresher"),
)
.await?;
let gateway_packet_router = PacketRouter::new(
ack_sender,
mixnet_messages_sender,
shutdown.get_handle().named("gateway-packet-router"),
);
let gateway_transceiver = Self::setup_gateway_transceiver(
self.custom_gateway_transceiver,
self.config,
init_res,
bandwidth_controller,
gateway_packet_router,
shutdown.fork("gateway_transceiver"),
)
.await?;
let reply_storage = Self::setup_persistent_reply_storage(
reply_storage_backend,
shutdown.fork("persistent_reply_storage"),
) )
.await?; .await?;
@@ -661,17 +582,15 @@ where
mixnet_messages_receiver, mixnet_messages_receiver,
reply_storage.key_storage(), reply_storage.key_storage(),
reply_controller_sender.clone(), reply_controller_sender.clone(),
shutdown.fork("received_messages_buffer"), task_manager.subscribe(),
); );
// The message_sender is the transmitter for any component generating sphinx packets // The 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 = Self::start_mix_traffic_controller( let message_sender =
gateway_transceiver, Self::start_mix_traffic_controller(gateway_client, task_manager.subscribe());
shutdown.fork("mix_traffic_controller"),
);
// 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
// controller that connections are closed. // controller that connections are closed.
@@ -698,7 +617,7 @@ where
reply_controller_receiver, reply_controller_receiver,
shared_lane_queue_lengths.clone(), shared_lane_queue_lengths.clone(),
client_connection_rx, client_connection_rx,
shutdown.fork("real_traffic_controller"), task_manager.subscribe(),
self.config.debug.traffic.packet_type, self.config.debug.traffic.packet_type,
); );
@@ -714,7 +633,7 @@ where
self_address, self_address,
shared_topology_accessor.clone(), shared_topology_accessor.clone(),
message_sender, message_sender,
shutdown.fork("cover_traffic_stream"), task_manager.subscribe(),
); );
} }
@@ -739,7 +658,7 @@ where
reply_controller_sender, reply_controller_sender,
topology_accessor: shared_topology_accessor, topology_accessor: shared_topology_accessor,
}, },
task_handle: shutdown, task_manager,
}) })
} }
} }
@@ -750,5 +669,5 @@ pub struct BaseClient {
pub client_output: ClientOutputStatus, pub client_output: ClientOutputStatus,
pub client_state: ClientState, pub client_state: ClientState,
pub task_handle: TaskHandle, pub task_manager: TaskManager,
} }
@@ -2,12 +2,8 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
use crate::config::GatewayEndpointConfig; use crate::config::GatewayEndpointConfig;
use crate::error::ClientCoreError;
use crate::init::types::{EmptyCustomDetails, GatewayDetails};
use async_trait::async_trait; use async_trait::async_trait;
use log::error;
use nym_gateway_requests::registration::handshake::SharedKeys; use nym_gateway_requests::registration::handshake::SharedKeys;
use serde::de::DeserializeOwned;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use sha2::{Digest, Sha256}; use sha2::{Digest, Sha256};
use std::error::Error; use std::error::Error;
@@ -17,57 +13,19 @@ use zeroize::Zeroizing;
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))] #[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)] #[cfg_attr(not(target_arch = "wasm32"), async_trait)]
pub trait GatewayDetailsStore<T = EmptyCustomDetails> { pub trait GatewayDetailsStore {
type StorageError: Error; type StorageError: Error;
async fn load_gateway_details(&self) -> Result<PersistedGatewayDetails<T>, Self::StorageError> async fn load_gateway_details(&self) -> Result<PersistedGatewayDetails, Self::StorageError>;
where
T: DeserializeOwned + Send + Sync;
async fn store_gateway_details( async fn store_gateway_details(
&self, &self,
details: &PersistedGatewayDetails<T>, details: &PersistedGatewayDetails,
) -> Result<(), Self::StorageError> ) -> Result<(), Self::StorageError>;
where
T: Serialize + Send + Sync;
} }
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)] pub struct PersistedGatewayDetails {
pub enum PersistedGatewayDetails<T = EmptyCustomDetails> {
/// Standard details of a remote gateway
Default(PersistedGatewayConfig),
/// Custom gateway setup, such as for a client embedded inside gateway itself
Custom(PersistedCustomGatewayDetails<T>),
}
impl<T> PersistedGatewayDetails<T> {
// TODO: this should probably allow for custom verification over T
pub fn validate(&self, shared_key: Option<&SharedKeys>) -> Result<(), ClientCoreError> {
match self {
PersistedGatewayDetails::Default(details) => {
if !details.verify(shared_key.ok_or(ClientCoreError::UnavailableSharedKey)?) {
Err(ClientCoreError::MismatchedGatewayDetails {
gateway_id: details.details.gateway_id.clone(),
})
} else {
Ok(())
}
}
PersistedGatewayDetails::Custom(_) => {
if shared_key.is_some() {
error!("using custom persisted gateway setup with shared key present - are you sure that's what you want?");
// but technically we could still continue. just ignore the key
}
Ok(())
}
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct PersistedGatewayConfig {
// TODO: should we also verify correctness of the details themselves? // TODO: should we also verify correctness of the details themselves?
// i.e. we could include a checksum or tag (via the shared keys) // i.e. we could include a checksum or tag (via the shared keys)
// counterargument: if we wanted to modify, say, the host information in the stored file on disk, // counterargument: if we wanted to modify, say, the host information in the stored file on disk,
@@ -77,19 +35,16 @@ pub struct PersistedGatewayConfig {
key_hash: Vec<u8>, key_hash: Vec<u8>,
/// Actual gateway details being persisted. /// Actual gateway details being persisted.
pub details: GatewayEndpointConfig, pub(crate) details: GatewayEndpointConfig,
} }
#[derive(Debug, Clone, Serialize, Deserialize)] impl From<PersistedGatewayDetails> for GatewayEndpointConfig {
pub struct PersistedCustomGatewayDetails<T> { fn from(value: PersistedGatewayDetails) -> Self {
// whatever custom method is used, gateway's identity must be known value.details
pub gateway_id: String, }
#[serde(flatten)]
pub additional_data: T,
} }
impl PersistedGatewayConfig { impl PersistedGatewayDetails {
pub fn new(details: GatewayEndpointConfig, shared_key: &SharedKeys) -> Self { pub fn new(details: GatewayEndpointConfig, shared_key: &SharedKeys) -> Self {
let key_bytes = Zeroizing::new(shared_key.to_bytes()); let key_bytes = Zeroizing::new(shared_key.to_bytes());
@@ -97,7 +52,7 @@ impl PersistedGatewayConfig {
key_hasher.update(&key_bytes); key_hasher.update(&key_bytes);
let key_hash = key_hasher.finalize().to_vec(); let key_hash = key_hasher.finalize().to_vec();
PersistedGatewayConfig { key_hash, details } PersistedGatewayDetails { key_hash, details }
} }
pub fn verify(&self, shared_key: &SharedKeys) -> bool { pub fn verify(&self, shared_key: &SharedKeys) -> bool {
@@ -111,50 +66,6 @@ impl PersistedGatewayConfig {
} }
} }
impl<T> PersistedGatewayDetails<T> {
pub fn new(
details: GatewayDetails<T>,
shared_key: Option<&SharedKeys>,
) -> Result<Self, ClientCoreError> {
match details {
GatewayDetails::Configured(cfg) => {
let shared_key = shared_key.ok_or(ClientCoreError::UnavailableSharedKey)?;
Ok(PersistedGatewayDetails::Default(
PersistedGatewayConfig::new(cfg, shared_key),
))
}
GatewayDetails::Custom(custom) => Ok(PersistedGatewayDetails::Custom(custom.into())),
}
}
pub fn is_custom(&self) -> bool {
matches!(self, PersistedGatewayDetails::Custom(..))
}
pub fn matches(&self, other: &GatewayDetails<T>) -> bool
where
T: PartialEq,
{
match self {
PersistedGatewayDetails::Default(default) => {
if let GatewayDetails::Configured(other_configured) = other {
&default.details == other_configured
} else {
false
}
}
PersistedGatewayDetails::Custom(custom) => {
if let GatewayDetails::Custom(other_custom) = other {
custom.gateway_id == other_custom.gateway_id
&& custom.additional_data == other_custom.additional_data
} else {
false
}
}
}
}
}
// helper to make Vec<u8> serialization use base64 representation to make it human readable // helper to make Vec<u8> serialization use base64 representation to make it human readable
// so that it would be easier for users to copy contents from the disk if they wanted to use it elsewhere // so that it would be easier for users to copy contents from the disk if they wanted to use it elsewhere
mod base64 { mod base64 {
@@ -205,10 +116,7 @@ impl OnDiskGatewayDetails {
} }
} }
pub fn load_from_disk<T>(&self) -> Result<PersistedGatewayDetails<T>, OnDiskGatewayDetailsError> pub fn load_from_disk(&self) -> Result<PersistedGatewayDetails, OnDiskGatewayDetailsError> {
where
T: DeserializeOwned,
{
let file = std::fs::File::open(&self.file_location).map_err(|err| { let file = std::fs::File::open(&self.file_location).map_err(|err| {
OnDiskGatewayDetailsError::LoadFailure { OnDiskGatewayDetailsError::LoadFailure {
path: self.file_location.display().to_string(), path: self.file_location.display().to_string(),
@@ -219,13 +127,10 @@ impl OnDiskGatewayDetails {
Ok(serde_json::from_reader(file)?) Ok(serde_json::from_reader(file)?)
} }
pub fn store_to_disk<T>( pub fn store_to_disk(
&self, &self,
details: &PersistedGatewayDetails<T>, details: &PersistedGatewayDetails,
) -> Result<(), OnDiskGatewayDetailsError> ) -> Result<(), OnDiskGatewayDetailsError> {
where
T: Serialize,
{
// ensure the whole directory structure exists // ensure the whole directory structure exists
if let Some(parent_dir) = &self.file_location.parent() { if let Some(parent_dir) = &self.file_location.parent() {
std::fs::create_dir_all(parent_dir).map_err(|err| { std::fs::create_dir_all(parent_dir).map_err(|err| {
@@ -265,8 +170,8 @@ impl GatewayDetailsStore for OnDiskGatewayDetails {
} }
#[derive(Default)] #[derive(Default)]
pub struct InMemGatewayDetails<T = EmptyCustomDetails> { pub struct InMemGatewayDetails {
details: Mutex<Option<PersistedGatewayDetails<T>>>, details: Mutex<Option<PersistedGatewayDetails>>,
} }
#[derive(Debug, thiserror::Error)] #[derive(Debug, thiserror::Error)]
@@ -38,6 +38,9 @@ pub trait MixnetClientStorage {
type CredentialStore: CredentialStorage; type CredentialStore: CredentialStorage;
type GatewayDetailsStore: GatewayDetailsStore; type GatewayDetailsStore: GatewayDetailsStore;
// this is a TERRIBLE name...
// fn into_split(self) -> (Self::KeyStore, Self::ReplyStore, Self::CredentialStore, Self::GatewayDetailsStore);
fn into_runtime_stores(self) -> (Self::ReplyStore, Self::CredentialStore); fn into_runtime_stores(self) -> (Self::ReplyStore, Self::CredentialStore);
fn key_store(&self) -> &Self::KeyStore; fn key_store(&self) -> &Self::KeyStore;
@@ -103,7 +103,7 @@ impl ManagedKeys {
pub fn gateway_shared_key(&self) -> Option<Arc<SharedKeys>> { pub fn gateway_shared_key(&self) -> Option<Arc<SharedKeys>> {
match self { match self {
ManagedKeys::Initial(_) => None, ManagedKeys::Initial(_) => None,
ManagedKeys::FullyDerived(keys) => keys.gateway_shared_key(), ManagedKeys::FullyDerived(keys) => Some(keys.gateway_shared_key()),
ManagedKeys::Invalidated => unreachable!("the managed keys got invalidated"), ManagedKeys::Invalidated => unreachable!("the managed keys got invalidated"),
} }
} }
@@ -124,26 +124,10 @@ impl ManagedKeys {
} }
} }
pub fn ensure_gateway_key(&self, gateway_shared_key: Option<Arc<SharedKeys>>) { pub fn ensure_gateway_key(&self, gateway_shared_key: Arc<SharedKeys>) {
if let ManagedKeys::FullyDerived(key_manager) = &self { if let ManagedKeys::FullyDerived(key_manager) = &self {
if self.gateway_shared_key().is_none() && gateway_shared_key.is_none() { if !Arc::ptr_eq(&key_manager.gateway_shared_key, &gateway_shared_key)
// the key doesn't exist in either state || key_manager.gateway_shared_key != gateway_shared_key
return;
}
if gateway_shared_key.is_some() && self.gateway_shared_key().is_none()
|| gateway_shared_key.is_none() && self.gateway_shared_key().is_some()
{
// if one is provided whilst the other is not...
// TODO: should this actually panic or return an error? would this branch be possible
// under normal operation?
panic!("inconsistent re-derived gateway key")
}
// here we know both keys MUST exist
let provided = gateway_shared_key.unwrap();
if !Arc::ptr_eq(key_manager.must_get_gateway_shared_key(), &provided)
|| *key_manager.must_get_gateway_shared_key() != provided
{ {
// this should NEVER happen thus panic here // this should NEVER happen thus panic here
panic!("derived fresh gateway shared key whilst already holding one!") panic!("derived fresh gateway shared key whilst already holding one!")
@@ -153,12 +137,12 @@ impl ManagedKeys {
pub async fn deal_with_gateway_key<S: KeyStore>( pub async fn deal_with_gateway_key<S: KeyStore>(
&mut self, &mut self,
gateway_shared_key: Option<Arc<SharedKeys>>, gateway_shared_key: Arc<SharedKeys>,
key_store: &S, key_store: &S,
) -> Result<(), S::StorageError> { ) -> Result<(), S::StorageError> {
let key_manager = match std::mem::replace(self, ManagedKeys::Invalidated) { let key_manager = match std::mem::replace(self, ManagedKeys::Invalidated) {
ManagedKeys::Initial(keys) => { ManagedKeys::Initial(keys) => {
let key_manager = keys.insert_maybe_gateway_shared_key(gateway_shared_key); let key_manager = keys.insert_gateway_shared_key(gateway_shared_key);
key_manager.persist_keys(key_store).await?; key_manager.persist_keys(key_store).await?;
key_manager key_manager
} }
@@ -200,10 +184,7 @@ impl KeyManagerBuilder {
} }
} }
pub fn insert_maybe_gateway_shared_key( pub fn insert_gateway_shared_key(self, gateway_shared_key: Arc<SharedKeys>) -> KeyManager {
self,
gateway_shared_key: Option<Arc<SharedKeys>>,
) -> KeyManager {
KeyManager { KeyManager {
identity_keypair: self.identity_keypair, identity_keypair: self.identity_keypair,
encryption_keypair: self.encryption_keypair, encryption_keypair: self.encryption_keypair,
@@ -241,11 +222,7 @@ pub struct KeyManager {
encryption_keypair: Arc<encryption::KeyPair>, encryption_keypair: Arc<encryption::KeyPair>,
/// shared key derived with the gateway during "registration handshake" /// shared key derived with the gateway during "registration handshake"
// I'm not a fan of how we broke the nice transition of `KeyManagerBuilder` -> `KeyManager` gateway_shared_key: Arc<SharedKeys>,
// by making this field optional.
// However, it has to be optional for when we use embedded NR inside a gateway,
// since it won't have a shared key (because why would it?)
gateway_shared_key: Option<Arc<SharedKeys>>,
/// key used for producing and processing acknowledgement packets. /// key used for producing and processing acknowledgement packets.
ack_key: Arc<AckKey>, ack_key: Arc<AckKey>,
@@ -255,13 +232,13 @@ impl KeyManager {
pub fn from_keys( pub fn from_keys(
id_keypair: identity::KeyPair, id_keypair: identity::KeyPair,
enc_keypair: encryption::KeyPair, enc_keypair: encryption::KeyPair,
gateway_shared_key: Option<SharedKeys>, gateway_shared_key: SharedKeys,
ack_key: AckKey, ack_key: AckKey,
) -> Self { ) -> Self {
Self { Self {
identity_keypair: Arc::new(id_keypair), identity_keypair: Arc::new(id_keypair),
encryption_keypair: Arc::new(enc_keypair), encryption_keypair: Arc::new(enc_keypair),
gateway_shared_key: gateway_shared_key.map(Arc::new), gateway_shared_key: Arc::new(gateway_shared_key),
ack_key: Arc::new(ack_key), ack_key: Arc::new(ack_key),
} }
} }
@@ -288,23 +265,13 @@ impl KeyManager {
Arc::clone(&self.ack_key) Arc::clone(&self.ack_key)
} }
fn must_get_gateway_shared_key(&self) -> &Arc<SharedKeys> {
self.gateway_shared_key
.as_ref()
.expect("gateway shared key is unavailable")
}
pub fn uses_custom_gateway(&self) -> bool {
self.gateway_shared_key.is_none()
}
/// Gets an atomically reference counted pointer to [`SharedKey`]. /// Gets an atomically reference counted pointer to [`SharedKey`].
pub fn gateway_shared_key(&self) -> Option<Arc<SharedKeys>> { pub fn gateway_shared_key(&self) -> Arc<SharedKeys> {
self.gateway_shared_key.as_ref().map(Arc::clone) Arc::clone(&self.gateway_shared_key)
} }
pub fn remove_gateway_key(self) -> KeyManagerBuilder { pub fn remove_gateway_key(self) -> KeyManagerBuilder {
if Arc::strong_count(self.must_get_gateway_shared_key()) > 1 { if Arc::strong_count(&self.gateway_shared_key) > 1 {
panic!("attempted to remove gateway key whilst still holding multiple references!") panic!("attempted to remove gateway key whilst still holding multiple references!")
} }
KeyManagerBuilder { KeyManagerBuilder {
@@ -88,20 +88,20 @@ impl OnDiskKeys {
pub fn ephemeral_load_gateway_keys( pub fn ephemeral_load_gateway_keys(
&self, &self,
) -> Result<zeroize::Zeroizing<SharedKeys>, OnDiskKeysError> { ) -> Result<zeroize::Zeroizing<SharedKeys>, OnDiskKeysError> {
self.load_key(self.paths.gateway_shared_key(), "gateway shared") self.load_key(self.paths.gateway_shared_key(), "gateway shared keys")
.map(zeroize::Zeroizing::new) .map(zeroize::Zeroizing::new)
} }
#[doc(hidden)] #[doc(hidden)]
pub fn load_encryption_keypair(&self) -> Result<encryption::KeyPair, OnDiskKeysError> { pub fn load_encryption_keypair(&self) -> Result<encryption::KeyPair, OnDiskKeysError> {
let encryption_paths = self.paths.encryption_key_pair_path(); let encryption_paths = self.paths.encryption_key_pair_path();
self.load_keypair(encryption_paths, "encryption") self.load_keypair(encryption_paths, "encryption keys")
} }
#[doc(hidden)] #[doc(hidden)]
pub fn load_identity_keypair(&self) -> Result<identity::KeyPair, OnDiskKeysError> { pub fn load_identity_keypair(&self) -> Result<identity::KeyPair, OnDiskKeysError> {
let identity_paths = self.paths.identity_key_pair_path(); let identity_paths = self.paths.identity_key_pair_path();
self.load_keypair(identity_paths, "identity") self.load_keypair(identity_paths, "identity keys")
} }
fn load_key<T: PemStorableKey>( fn load_key<T: PemStorableKey>(
@@ -161,9 +161,8 @@ impl OnDiskKeys {
let encryption_keypair = self.load_encryption_keypair()?; let encryption_keypair = self.load_encryption_keypair()?;
let ack_key: AckKey = self.load_key(self.paths.ack_key(), "ack key")?; let ack_key: AckKey = self.load_key(self.paths.ack_key(), "ack key")?;
let gateway_shared_key: Option<SharedKeys> = self let gateway_shared_key: SharedKeys =
.load_key(self.paths.gateway_shared_key(), "gateway shared keys") self.load_key(self.paths.gateway_shared_key(), "gateway shared keys")?;
.ok();
Ok(KeyManager::from_keys( Ok(KeyManager::from_keys(
identity_keypair, identity_keypair,
@@ -174,8 +173,6 @@ impl OnDiskKeys {
} }
fn store_keys(&self, keys: &KeyManager) -> Result<(), OnDiskKeysError> { fn store_keys(&self, keys: &KeyManager) -> Result<(), OnDiskKeysError> {
use std::ops::Deref;
let identity_paths = self.paths.identity_key_pair_path(); let identity_paths = self.paths.identity_key_pair_path();
let encryption_paths = self.paths.encryption_key_pair_path(); let encryption_paths = self.paths.encryption_key_pair_path();
@@ -191,14 +188,11 @@ impl OnDiskKeys {
)?; )?;
self.store_key(keys.ack_key.as_ref(), self.paths.ack_key(), "ack key")?; self.store_key(keys.ack_key.as_ref(), self.paths.ack_key(), "ack key")?;
self.store_key(
if let Some(shared_keys) = &keys.gateway_shared_key { keys.gateway_shared_key.as_ref(),
self.store_key( self.paths.gateway_shared_key(),
shared_keys.deref(), "gateway shared keys",
self.paths.gateway_shared_key(), )?;
"gateway shared keys",
)?;
}
Ok(()) Ok(())
} }
@@ -1,26 +1,24 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net> // Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
use crate::client::mix_traffic::transceiver::GatewayTransceiver;
use crate::spawn_future; use crate::spawn_future;
use log::*; use log::*;
use nym_credential_storage::storage::Storage;
use nym_gateway_client::GatewayClient;
use nym_sphinx::forwarding::packet::MixPacket; use nym_sphinx::forwarding::packet::MixPacket;
use nym_validator_client::nyxd::contract_traits::DkgQueryClient;
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>>;
pub mod transceiver;
// We remind ourselves that 32 x 32kb = 1024kb, a reasonable size for a network buffer. // We remind ourselves that 32 x 32kb = 1024kb, a reasonable size for a network buffer.
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;
// that's also disgusting. pub struct MixTrafficController<C, St: Storage> {
pub struct Empty; // TODO: most likely to be replaced by some higher level construct as
// later on gateway_client will need to be accessible by other entities
pub struct MixTrafficController { gateway_client: GatewayClient<C, St>,
gateway_transceiver: Box<dyn GatewayTransceiver + Send>,
mix_rx: BatchMixMessageReceiver, mix_rx: BatchMixMessageReceiver,
// TODO: this is temporary work-around. // TODO: this is temporary work-around.
@@ -28,31 +26,20 @@ pub struct MixTrafficController {
consecutive_gateway_failure_count: usize, consecutive_gateway_failure_count: usize,
} }
impl MixTrafficController { impl<C, St> MixTrafficController<C, St>
pub fn new<T>(gateway_transceiver: T) -> (MixTrafficController, BatchMixMessageSender) where
where C: DkgQueryClient + Sync + Send + 'static,
T: GatewayTransceiver + Send + 'static, St: Storage + 'static,
{ <St as Storage>::StorageError: Send + Sync + 'static,
{
pub fn new(
gateway_client: GatewayClient<C, St>,
) -> (MixTrafficController<C, St>, BatchMixMessageSender) {
let (message_sender, message_receiver) = let (message_sender, message_receiver) =
tokio::sync::mpsc::channel(MIX_MESSAGE_RECEIVER_BUFFER_SIZE); tokio::sync::mpsc::channel(MIX_MESSAGE_RECEIVER_BUFFER_SIZE);
( (
MixTrafficController { MixTrafficController {
gateway_transceiver: Box::new(gateway_transceiver), gateway_client,
mix_rx: message_receiver,
consecutive_gateway_failure_count: 0,
},
message_sender,
)
}
pub fn new_dynamic(
gateway_transceiver: Box<dyn GatewayTransceiver + Send>,
) -> (MixTrafficController, BatchMixMessageSender) {
let (message_sender, message_receiver) =
tokio::sync::mpsc::channel(MIX_MESSAGE_RECEIVER_BUFFER_SIZE);
(
MixTrafficController {
gateway_transceiver,
mix_rx: message_receiver, mix_rx: message_receiver,
consecutive_gateway_failure_count: 0, consecutive_gateway_failure_count: 0,
}, },
@@ -65,16 +52,16 @@ impl MixTrafficController {
let result = if mix_packets.len() == 1 { let result = if mix_packets.len() == 1 {
let mix_packet = mix_packets.pop().unwrap(); let mix_packet = mix_packets.pop().unwrap();
self.gateway_transceiver.send_mix_packet(mix_packet).await self.gateway_client.send_mix_packet(mix_packet).await
} else { } else {
self.gateway_transceiver self.gateway_client
.batch_send_mix_packets(mix_packets) .batch_send_mix_packets(mix_packets)
.await .await
}; };
match result { match result {
Err(err) => { Err(err) => {
error!("Failed to send sphinx packet(s) to the gateway: {err}"); error!("Failed to send sphinx packet(s) to the gateway! - {err}");
self.consecutive_gateway_failure_count += 1; self.consecutive_gateway_failure_count += 1;
if self.consecutive_gateway_failure_count == MAX_FAILURE_COUNT { if self.consecutive_gateway_failure_count == MAX_FAILURE_COUNT {
// todo: in the future this should initiate a 'graceful' shutdown or try // todo: in the future this should initiate a 'graceful' shutdown or try
@@ -1,262 +0,0 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use async_trait::async_trait;
use log::{debug, error};
use nym_crypto::asymmetric::identity;
use nym_gateway_client::GatewayClient;
pub use nym_gateway_client::{GatewayPacketRouter, PacketRouter};
use nym_sphinx::forwarding::packet::MixPacket;
use std::fmt::Debug;
use thiserror::Error;
#[cfg(not(target_arch = "wasm32"))]
use futures::channel::{mpsc, oneshot};
// we need to type erase the error type since we can't have dynamic associated types alongside dynamic dispatch
#[derive(Debug, Error)]
#[error(transparent)]
pub struct ErasedGatewayError(Box<dyn std::error::Error + Send + Sync>);
fn erase_err<E: std::error::Error + Send + Sync + 'static>(err: E) -> ErasedGatewayError {
ErasedGatewayError(Box::new(err))
}
/// This combines combines the functionalities of being able to send and receive mix packets.
pub trait GatewayTransceiver: GatewaySender + GatewayReceiver {
fn gateway_identity(&self) -> identity::PublicKey;
}
/// This trait defines the functionality of sending `MixPacket` into the mixnet,
/// usually through a gateway.
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
pub trait GatewaySender {
async fn send_mix_packet(&mut self, packet: MixPacket) -> Result<(), ErasedGatewayError>;
async fn batch_send_mix_packets(
&mut self,
packets: Vec<MixPacket>,
) -> Result<(), ErasedGatewayError> {
// allow for optimisation when sending multiple packets
for packet in packets {
self.send_mix_packet(packet).await?;
}
Ok(())
}
}
/// this trait defines the functionality of being able to correctly route
/// packets received from the mixnet, i.e. acks and 'proper' messages.
pub trait GatewayReceiver {
// ughhhh I really dislike this method, but couldn't come up wih anything better
// ideally this would have been an associated type, but heh. we can't.
fn set_packet_router(
&mut self,
_packet_router: PacketRouter,
) -> Result<(), ErasedGatewayError> {
debug!("no-op packet router setup");
Ok(())
}
}
// to allow for dynamic dispatch
impl<G: GatewayTransceiver + ?Sized + Send> GatewayTransceiver for Box<G> {
#[inline]
fn gateway_identity(&self) -> identity::PublicKey {
(**self).gateway_identity()
}
}
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
impl<G: GatewaySender + ?Sized + Send> GatewaySender for Box<G> {
#[inline]
async fn send_mix_packet(&mut self, packet: MixPacket) -> Result<(), ErasedGatewayError> {
(**self).send_mix_packet(packet).await
}
#[inline]
async fn batch_send_mix_packets(
&mut self,
packets: Vec<MixPacket>,
) -> Result<(), ErasedGatewayError> {
(**self).batch_send_mix_packets(packets).await
}
}
impl<G: GatewayReceiver + ?Sized> GatewayReceiver for Box<G> {
#[inline]
fn set_packet_router(&mut self, packet_router: PacketRouter) -> Result<(), ErasedGatewayError> {
(**self).set_packet_router(packet_router)
}
}
/// Gateway to which the client is connected through a socket.
/// Most likely through a websocket.
pub struct RemoteGateway<C, St> {
gateway_client: GatewayClient<C, St>,
}
impl<C, St> RemoteGateway<C, St> {
pub fn new(gateway_client: GatewayClient<C, St>) -> Self {
Self { gateway_client }
}
}
impl<C, St> GatewayTransceiver for RemoteGateway<C, St>
where
C: Send,
St: Send,
{
fn gateway_identity(&self) -> identity::PublicKey {
self.gateway_client.gateway_identity()
}
}
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
impl<C, St> GatewaySender for RemoteGateway<C, St>
where
C: Send,
St: Send,
{
async fn send_mix_packet(&mut self, packet: MixPacket) -> Result<(), ErasedGatewayError> {
self.gateway_client
.send_mix_packet(packet)
.await
.map_err(erase_err)
}
async fn batch_send_mix_packets(
&mut self,
packets: Vec<MixPacket>,
) -> Result<(), ErasedGatewayError> {
self.gateway_client
.batch_send_mix_packets(packets)
.await
.map_err(erase_err)
}
}
impl<C, St> GatewayReceiver for RemoteGateway<C, St> {}
#[derive(Debug, Error)]
pub enum LocalGatewayError {
#[error("attempted to set the packet router for the second time")]
PacketRouterAlreadySet,
#[error("failed to setup packet router - has the receiver been dropped?")]
FailedPacketRouterSetup,
}
/// Gateway running within the same process.
#[cfg(not(target_arch = "wasm32"))]
pub struct LocalGateway {
/// Identity of the locally managed gateway
local_identity: identity::PublicKey,
// 'sender' part
/// Channel responsible for taking mix packets and forwarding them further into the further mixnet layers.
packet_forwarder: mpsc::UnboundedSender<MixPacket>,
// 'receiver' part
packet_router_tx: Option<oneshot::Sender<PacketRouter>>,
}
#[cfg(not(target_arch = "wasm32"))]
impl LocalGateway {
pub fn new(
local_identity: identity::PublicKey,
packet_forwarder: mpsc::UnboundedSender<MixPacket>,
packet_router_tx: oneshot::Sender<PacketRouter>,
) -> Self {
LocalGateway {
local_identity,
packet_forwarder,
packet_router_tx: Some(packet_router_tx),
}
}
}
#[cfg(not(target_arch = "wasm32"))]
mod nonwasm_sealed {
use super::*;
impl GatewayTransceiver for LocalGateway {
fn gateway_identity(&self) -> identity::PublicKey {
self.local_identity
}
}
#[async_trait]
impl GatewaySender for LocalGateway {
async fn send_mix_packet(&mut self, packet: MixPacket) -> Result<(), ErasedGatewayError> {
self.packet_forwarder
.unbounded_send(packet)
.map_err(|err| err.into_send_error())
.map_err(erase_err)
}
}
impl GatewayReceiver for LocalGateway {
fn set_packet_router(
&mut self,
packet_router: PacketRouter,
) -> Result<(), ErasedGatewayError> {
let Some(packet_routex_tx) = self.packet_router_tx.take() else {
return Err(erase_err(LocalGatewayError::PacketRouterAlreadySet));
};
packet_routex_tx
.send(packet_router)
.map_err(|_| erase_err(LocalGatewayError::FailedPacketRouterSetup))
}
}
}
// if we ever decided to start writing unit tests... : )
pub struct MockGateway {
dummy_identity: identity::PublicKey,
packet_router: Option<PacketRouter>,
sent: Vec<MixPacket>,
}
impl Default for MockGateway {
fn default() -> Self {
MockGateway {
dummy_identity: "3ebjp1Fb9hdcS1AR6AZihgeJiMHkB5jjJUsvqNnfQwU7"
.parse()
.unwrap(),
packet_router: None,
sent: vec![],
}
}
}
#[derive(Debug, Error)]
#[error("mock gateway error")]
pub struct MockGatewayError;
impl GatewayReceiver for MockGateway {
// TODO: that's frustrating. can't do anything about the behaviour here since all the routing is in the `PacketRouter`...
fn set_packet_router(&mut self, packet_router: PacketRouter) -> Result<(), ErasedGatewayError> {
self.packet_router = Some(packet_router);
Ok(())
}
}
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
impl GatewaySender for MockGateway {
async fn send_mix_packet(&mut self, packet: MixPacket) -> Result<(), ErasedGatewayError> {
self.sent.push(packet);
Ok(())
}
}
impl GatewayTransceiver for MockGateway {
fn gateway_identity(&self) -> identity::PublicKey {
self.dummy_identity
}
}
@@ -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;
@@ -263,7 +263,7 @@ impl ActionController {
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 ActionController with graceful shutdown support"); debug!("Started ActionController with graceful shutdown support");
loop { while !shutdown.is_shutdown() {
tokio::select! { tokio::select! {
action = self.incoming_actions.next() => match action { action = self.incoming_actions.next() => match action {
Some(action) => self.process_action(action), Some(action) => self.process_action(action),
@@ -283,7 +283,6 @@ impl ActionController {
}, },
_ = shutdown.recv_with_delay() => { _ = shutdown.recv_with_delay() => {
log::trace!("ActionController: Received shutdown"); log::trace!("ActionController: Received shutdown");
break;
} }
} }
} }
@@ -260,7 +260,7 @@ where
let mut sent_notification_listener = self.sent_notification_listener; let mut sent_notification_listener = self.sent_notification_listener;
let mut action_controller = self.action_controller; let mut action_controller = self.action_controller;
let shutdown_handle = shutdown.fork("acknowledgement_listener"); let shutdown_handle = shutdown.clone();
spawn_future(async move { spawn_future(async move {
acknowledgement_listener acknowledgement_listener
.run_with_shutdown(shutdown_handle) .run_with_shutdown(shutdown_handle)
@@ -268,7 +268,7 @@ where
debug!("The acknowledgement listener has finished execution!"); debug!("The acknowledgement listener has finished execution!");
}); });
let shutdown_handle = shutdown.fork("input_message_listener"); let shutdown_handle = shutdown.clone();
spawn_future(async move { spawn_future(async move {
input_message_listener input_message_listener
.run_with_shutdown(shutdown_handle) .run_with_shutdown(shutdown_handle)
@@ -276,7 +276,7 @@ where
debug!("The input listener has finished execution!"); debug!("The input listener has finished execution!");
}); });
let shutdown_handle = shutdown.fork("retransmission_request_listener"); 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, packet_type)
@@ -284,7 +284,7 @@ where
debug!("The retransmission request listener has finished execution!"); debug!("The retransmission request listener has finished execution!");
}); });
let shutdown_handle = shutdown.fork("sent_notification_listener"); let shutdown_handle = shutdown.clone();
spawn_future(async move { spawn_future(async move {
sent_notification_listener sent_notification_listener
.run_with_shutdown(shutdown_handle) .run_with_shutdown(shutdown_handle)
@@ -293,9 +293,7 @@ where
}); });
spawn_future(async move { spawn_future(async move {
action_controller action_controller.run_with_shutdown(shutdown).await;
.run_with_shutdown(shutdown.with_suffix("action_controller"))
.await;
debug!("The controller has finished execution!"); debug!("The controller has finished execution!");
}); });
} }
@@ -40,7 +40,7 @@ impl SentNotificationListener {
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 SentNotificationListener with graceful shutdown support"); debug!("Started SentNotificationListener with graceful shutdown support");
loop { while !shutdown.is_shutdown() {
tokio::select! { tokio::select! {
frag_id = self.sent_notifier.next() => match frag_id { frag_id = self.sent_notifier.next() => match frag_id {
Some(frag_id) => { Some(frag_id) => {
@@ -53,7 +53,6 @@ impl SentNotificationListener {
}, },
_ = shutdown.recv_with_delay() => { _ = shutdown.recv_with_delay() => {
log::trace!("SentNotificationListener: Received shutdown"); log::trace!("SentNotificationListener: Received shutdown");
break;
} }
} }
} }
@@ -213,17 +213,17 @@ impl RealMessagesController<OsRng> {
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;
let shutdown_handle = shutdown.fork("out_queue_control"); let shutdown_handle = shutdown.clone();
spawn_future(async move { spawn_future(async move {
out_queue_control.run_with_shutdown(shutdown_handle).await; out_queue_control.run_with_shutdown(shutdown_handle).await;
debug!("The out queue controller has finished execution!"); debug!("The out queue controller has finished execution!");
}); });
let shutdown_handle = shutdown.fork("reply_control"); let shutdown_handle = shutdown.clone();
spawn_future(async move { spawn_future(async move {
reply_control.run_with_shutdown(shutdown_handle).await; reply_control.run_with_shutdown(shutdown_handle).await;
debug!("The reply controller has finished execution!"); debug!("The reply controller has finished execution!");
}); });
ack_control.start_with_shutdown(shutdown.with_suffix("ack_control"), packet_type); ack_control.start_with_shutdown(shutdown, packet_type);
} }
} }
@@ -500,12 +500,11 @@ where
{ {
let mut status_timer = tokio::time::interval(Duration::from_secs(5)); let mut status_timer = tokio::time::interval(Duration::from_secs(5));
loop { while !shutdown.is_shutdown() {
tokio::select! { tokio::select! {
biased; biased;
_ = shutdown.recv_with_delay() => { _ = shutdown.recv_with_delay() => {
log::trace!("OutQueueControl: Received shutdown"); log::trace!("OutQueueControl: Received shutdown");
break;
} }
_ = status_timer.tick() => { _ = status_timer.tick() => {
self.log_status(&mut shutdown); self.log_status(&mut shutdown);
@@ -500,7 +500,7 @@ impl<R: MessageReceiver + Clone + Send + 'static> ReceivedMessagesBufferControll
let mut fragmented_message_receiver = self.fragmented_message_receiver; let mut fragmented_message_receiver = self.fragmented_message_receiver;
let mut request_receiver = self.request_receiver; let mut request_receiver = self.request_receiver;
let shutdown_handle = shutdown.fork("fragmented_message_receiver"); let shutdown_handle = shutdown.clone();
spawn_future(async move { spawn_future(async move {
match fragmented_message_receiver match fragmented_message_receiver
.run_with_shutdown(shutdown_handle) .run_with_shutdown(shutdown_handle)
@@ -511,9 +511,7 @@ impl<R: MessageReceiver + Clone + Send + 'static> ReceivedMessagesBufferControll
} }
}); });
spawn_future(async move { spawn_future(async move {
request_receiver request_receiver.run_with_shutdown(shutdown).await;
.run_with_shutdown(shutdown.with_suffix("request_receiver"))
.await;
}); });
} }
} }
@@ -39,7 +39,7 @@ where
mem_state: CombinedReplyStorage, mem_state: CombinedReplyStorage,
mut shutdown: nym_task::TaskClient, mut shutdown: nym_task::TaskClient,
) { ) {
use log::{debug, error, info}; use log::{debug, error, info, warn};
debug!("Started PersistentReplyStorage"); debug!("Started PersistentReplyStorage");
if let Err(err) = self.backend.start_storage_session().await { if let Err(err) = self.backend.start_storage_session().await {
@@ -50,7 +50,7 @@ where
shutdown.recv().await; shutdown.recv().await;
info!("PersistentReplyStorage is flushing all reply-related data to underlying storage"); info!("PersistentReplyStorage is flushing all reply-related data to underlying storage");
info!("you MUST NOT forcefully shutdown now or you risk data corruption!"); warn!("you MUST NOT forcefully shutdown now or you risk data corruption!");
if let Err(err) = self.backend.flush_surb_storage(&mem_state).await { if let Err(err) = self.backend.flush_surb_storage(&mem_state).await {
error!("failed to flush our reply-related data to the persistent storage: {err}") error!("failed to flush our reply-related data to the persistent storage: {err}")
} else { } else {
@@ -199,7 +199,7 @@ fn group_mixnodes_by_country_code(
if let Some(ref location) = m.location { if let Some(ref location) = m.location {
let country_code = location.two_letter_iso_country_code.clone(); let country_code = location.two_letter_iso_country_code.clone();
let group_code = CountryGroup::new(country_code.as_str()); let group_code = CountryGroup::new(country_code.as_str());
let mixnodes = acc.entry(group_code).or_default(); let mixnodes = acc.entry(group_code).or_insert_with(Vec::new);
mixnodes.push(m.mix_id); mixnodes.push(m.mix_id);
} }
acc acc
@@ -5,17 +5,10 @@ use crate::spawn_future;
pub(crate) use accessor::{TopologyAccessor, TopologyReadPermit}; pub(crate) use accessor::{TopologyAccessor, TopologyReadPermit};
use futures::StreamExt; use futures::StreamExt;
use log::*; use log::*;
use nym_sphinx::addressing::nodes::NodeIdentity;
use nym_topology::provider_trait::TopologyProvider; use nym_topology::provider_trait::TopologyProvider;
use nym_topology::NymTopologyError; use nym_topology::NymTopologyError;
use std::time::Duration; use std::time::Duration;
#[cfg(not(target_arch = "wasm32"))]
use tokio::time::sleep;
#[cfg(target_arch = "wasm32")]
use wasmtimer::tokio::sleep;
mod accessor; mod accessor;
pub mod geo_aware_provider; pub mod geo_aware_provider;
pub(crate) mod nym_api_provider; pub(crate) mod nym_api_provider;
@@ -93,54 +86,6 @@ impl TopologyRefresher {
self.topology_accessor.ensure_is_routable().await self.topology_accessor.ensure_is_routable().await
} }
pub async fn ensure_contains_gateway(
&self,
gateway: &NodeIdentity,
) -> Result<(), NymTopologyError> {
let topology = self
.topology_accessor
.current_topology()
.await
.ok_or(NymTopologyError::EmptyNetworkTopology)?;
if !topology.gateway_exists(gateway) {
return Err(NymTopologyError::NonExistentGatewayError {
identity_key: gateway.to_base58_string(),
});
}
Ok(())
}
pub async fn wait_for_gateway(
&mut self,
gateway: &NodeIdentity,
timeout_duration: Duration,
) -> Result<(), NymTopologyError> {
info!(
"going to wait for at most {timeout_duration:?} for gateway '{gateway}' to come online"
);
let deadline = sleep(timeout_duration);
tokio::pin!(deadline);
loop {
tokio::select! {
_ = &mut deadline => {
return Err(NymTopologyError::TimedOutWaitingForGateway {
identity_key: gateway.to_base58_string()
})
}
_ = self.try_refresh() => {
if self.ensure_contains_gateway(gateway).await.is_ok() {
return Ok(())
}
info!("gateway '{gateway}' is still not online...");
sleep(self.refresh_rate).await
}
}
}
}
pub fn start_with_shutdown(mut self, mut shutdown: nym_task::TaskClient) { pub fn start_with_shutdown(mut self, mut shutdown: nym_task::TaskClient) {
spawn_future(async move { spawn_future(async move {
debug!("Started TopologyRefresher with graceful shutdown support"); debug!("Started TopologyRefresher with graceful shutdown support");
@@ -69,7 +69,7 @@ impl NymApiTopologyProvider {
Ok(mixes) => mixes, Ok(mixes) => mixes,
}; };
let gateways = match self.validator_client.get_cached_described_gateways().await { let gateways = match self.validator_client.get_cached_gateways().await {
Err(err) => { Err(err) => {
error!("failed to get network gateways - {err}"); error!("failed to get network gateways - {err}");
return None; return None;
@@ -35,7 +35,7 @@ pub struct ClientKeysPaths {
} }
impl ClientKeysPaths { impl ClientKeysPaths {
pub fn new_base<P: AsRef<Path>>(base_data_directory: P) -> Self { pub fn new_default<P: AsRef<Path>>(base_data_directory: P) -> Self {
let base_dir = base_data_directory.as_ref(); let base_dir = base_data_directory.as_ref();
ClientKeysPaths { ClientKeysPaths {

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