Compare commits

..

6 Commits

Author SHA1 Message Date
Tommy Verrall 4dc75d3a44 attempt to fix unwrap 2024-03-28 15:26:32 +01:00
Jędrzej Stuczyński de214e9121 fixed NR template 2024-03-28 12:34:30 +00:00
Jędrzej Stuczyński 8a1c537e35 remove explicit deref 2024-03-28 10:15:49 +00:00
Jędrzej Stuczyński 14b2a29083 config migration for removing allow.list 2024-03-28 10:15:49 +00:00
Jędrzej Stuczyński 1c5ae7d8bd moved and renamed NR old config structs 2024-03-28 10:15:49 +00:00
Jędrzej Stuczyński f1737c2bb3 removed the usage of allow.list 2024-03-28 10:15:48 +00:00
1483 changed files with 66183 additions and 89195 deletions
+9
View File
@@ -0,0 +1,9 @@
# Description
Closes: #XXXX
<!-- If appropriate, insert relevant description here -->
# Checklist:
- [ ] added a changelog entry to `CHANGELOG.md`
+3 -22
View File
@@ -9,11 +9,7 @@ jobs:
steps:
- 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 git python3 && sudo apt-get update --fix-missing
- name: Install pip3
run: sudo apt install -y python3-pip
- name: Install Python3 modules
run: sudo pip3 install pandas tabulate
run: sudo apt-get update && sudo apt-get install -y build-essential curl wget libssl-dev libudev-dev squashfs-tools protobuf-compiler
- name: Install rsync
run: sudo apt-get install rsync
- uses: rlespinasse/github-slug-action@v3.x
@@ -34,24 +30,9 @@ jobs:
- name: Remove existing Nym config directory (`~/.nym/`)
run: cd documentation && ./remove_existing_config.sh
continue-on-error: false
# This is the original flow
# - name: Build all projects in documentation/ & move to ~/dist/docs/
# run: cd documentation && ./build_all_to_dist.sh
# This is a workaround replacement which builds on the last working commit b332a6b55668f60988e36961f3f62a794ba82ddb and then on current branch
- name: Save current branch to ~/current_branch
run: git rev-parse --abbrev-ref HEAD > ~/current_branch
- name: Git pull, reset & switch to b332a6b55668f60988e36961f3f62a794ba82ddb
run: git pull && git reset --hard && git checkout b332a6b55668f60988e36961f3f62a794ba82ddb
- name: Build all projects in documentation/ & move to ~/dist/docs/ from b332a6b55668f60988e36961f3f62a794ba82ddb
- name: Build all projects in documentation/ & move to ~/dist/docs/
run: cd documentation && ./build_all_to_dist.sh
- name: Switch to current branch
run: git checkout $echo "$(cat ~/current_branch)"
- name: Build all projects in documentation/ & move to ~/dist/docs/ on current branch
run: cd documentation && ./build_all_to_dist.sh && rm ~/current_branch
# End of replacemet
continue-on-error: false
- name: Post process
run: cd documentation && ./post_process.sh
@@ -104,12 +104,14 @@ jobs:
name: nym-binaries-artifacts
path: |
target/release/nym-client
target/release/nym-gateway
target/release/nym-mixnode
target/release/nym-socks5-client
target/release/nym-api
target/release/nym-network-requester
target/release/nym-network-statistics
target/release/nym-cli
target/release/nymvisor
target/release/nym-node
retention-days: 30
# If this was a pull_request or nightly, upload to build server
@@ -121,11 +123,13 @@ jobs:
OUTPUT_DIR: ci-builds/${{ github.ref_name }}
run: |
cp target/release/nym-client $OUTPUT_DIR
cp target/release/nym-gateway $OUTPUT_DIR
cp target/release/nym-mixnode $OUTPUT_DIR
cp target/release/nym-socks5-client $OUTPUT_DIR
cp target/release/nym-api $OUTPUT_DIR
cp target/release/nym-network-requester $OUTPUT_DIR
cp target/release/nym-network-statistics $OUTPUT_DIR
cp target/release/nymvisor $OUTPUT_DIR
cp target/release/nym-node $OUTPUT_DIR
cp target/release/nym-cli $OUTPUT_DIR
cp target/release/explorer-api $OUTPUT_DIR
if [ ${{ github.event_name == 'workflow_dispatch' && inputs.enable_deb == true }} = true ]; then
+2
View File
@@ -6,6 +6,7 @@ on:
- 'clients/**'
- 'common/**'
- 'explorer-api/**'
- 'ephemera/**'
- 'gateway/**'
- 'integrations/**'
- 'mixnode/**'
@@ -23,6 +24,7 @@ on:
- 'clients/**'
- 'common/**'
- 'explorer-api/**'
- 'ephemera/**'
- 'gateway/**'
- 'integrations/**'
- 'mixnode/**'
@@ -35,7 +35,7 @@ jobs:
- name: Install Rust stable
uses: actions-rs/toolchain@v1
with:
toolchain: 1.77
toolchain: stable
target: wasm32-unknown-unknown
override: true
@@ -58,6 +58,8 @@ jobs:
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
- name: Deploy branch to CI www
continue-on-error: true
+3 -23
View File
@@ -13,11 +13,7 @@ jobs:
steps:
- 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 git python3 && sudo apt-get update --fix-missing
- name: Install pip3
run: sudo apt install -y python3-pip
- name: Install Python3 modules
run: sudo pip3 install pandas tabulate
run: sudo apt-get update && sudo apt-get install -y build-essential curl wget libssl-dev libudev-dev squashfs-tools protobuf-compiler
- name: Install rsync
run: sudo apt-get install rsync
- uses: rlespinasse/github-slug-action@v3.x
@@ -38,25 +34,9 @@ jobs:
- name: Remove existing Nym config directory (`~/.nym/`)
run: cd documentation && ./remove_existing_config.sh
continue-on-error: false
# This is the original flow
# - name: Build all projects in documentation/ & move to ~/dist/docs/
# run: cd documentation && ./build_all_to_dist.sh
# This is a workaround replacement which builds on the last working commit b332a6b55668f60988e36961f3f62a794ba82ddb and then on current branch
- name: Save current branch to ~/current_branch
run: git rev-parse --abbrev-ref HEAD > ~/current_branch
- name: Git pull, reset & switch to b332a6b55668f60988e36961f3f62a794ba82ddb
run: git pull && git reset --hard && git checkout b332a6b55668f60988e36961f3f62a794ba82ddb
- name: Build all projects in documentation/ & move to ~/dist/docs/ from b332a6b55668f60988e36961f3f62a794ba82ddb
- name: Build all projects in documentation/ & move to ~/dist/docs/
run: cd documentation && ./build_all_to_dist.sh
- name: Switch to current branch
run: git checkout $echo "$(cat ~/current_branch)"
- name: Build all projects in documentation/ & move to ~/dist/docs/ on current branch
run: cd documentation && ./build_all_to_dist.sh && rm ~/current_branch
# End of replacemet
continue-on-error: false
- name: Deploy branch to CI www
continue-on-error: true
@@ -0,0 +1,65 @@
name: ci-nym-connect-desktop-rust
on:
pull_request:
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/**"
jobs:
build:
runs-on: [self-hosted, custom-linux]
env:
CARGO_TERM_COLOR: always
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: Check out repository code
uses: actions/checkout@v2
- 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: --manifest-path nym-connect/desktop/Cargo.toml --all -- --check
- name: Build all binaries
uses: actions-rs/cargo@v1
with:
command: build
args: --manifest-path nym-connect/desktop/Cargo.toml --workspace
- name: Run all tests
uses: actions-rs/cargo@v1
with:
command: test
args: --manifest-path nym-connect/desktop/Cargo.toml --workspace
- uses: actions-rs/clippy-check@v1
name: Clippy checks
continue-on-error: true
with:
token: ${{ secrets.GITHUB_TOKEN }}
args: --manifest-path nym-connect/desktop/Cargo.toml --workspace --all-features
- name: Run clippy
uses: actions-rs/cargo@v1
with:
command: clippy
args: --manifest-path nym-connect/desktop/Cargo.toml --workspace --all-features -- -D warnings
@@ -0,0 +1,72 @@
name: ci-nym-connect-desktop
on:
pull_request:
paths:
- 'nym-connect/desktop/**'
defaults:
run:
working-directory: nym-connect/desktop
jobs:
build:
runs-on: custom-linux
steps:
- uses: actions/checkout@v2
- name: Install rsync
run: sudo apt-get install rsync
continue-on-error: true
- uses: rlespinasse/github-slug-action@v3.x
- uses: actions/setup-node@v3
with:
node-version: 18
- name: Install Yarn
run: npm install -g yarn
- name: Install Rust stable
uses: actions-rs/toolchain@v1
with:
toolchain: stable
- name: Install wasm-pack
run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
- name: Install project dependencies
run: cd ../.. && yarn --network-timeout 100000
- name: Install app dependencies
run: yarn
continue-on-error: true
- name: Set environment from the example
run: cp .env.sample .env
- run: yarn storybook:build
- name: Deploy branch to CI www
continue-on-error: true
uses: easingthemes/ssh-deploy@main
env:
SSH_PRIVATE_KEY: ${{ secrets.CI_WWW_SSH_PRIVATE_KEY }}
ARGS: "-rltgoDzvO --delete"
SOURCE: "nym-connect/desktop/storybook-static/"
REMOTE_HOST: ${{ secrets.CI_WWW_REMOTE_HOST }}
REMOTE_USER: ${{ secrets.CI_WWW_REMOTE_USER }}
TARGET: ${{ secrets.CI_WWW_REMOTE_TARGET }}/nym-connect-${{ env.GITHUB_REF_SLUG }}
EXCLUDE: "/dist/, /node_modules/"
- name: Matrix - Node Install
run: npm install
working-directory: .github/workflows/support-files
- name: Matrix - Send Notification
env:
NYM_NOTIFICATION_KIND: nym-connect
NYM_PROJECT_NAME: "nym-connect"
NYM_CI_WWW_BASE: "${{ secrets.NYM_CI_WWW_BASE }}"
NYM_CI_WWW_LOCATION: "nym-connect-${{ env.GITHUB_REF_SLUG }}"
GIT_COMMIT_MESSAGE: "${{ github.event.head_commit.message }}"
GIT_BRANCH: "${GITHUB_REF##*/}"
IS_SUCCESS: "${{ job.status == 'success' }}"
MATRIX_SERVER: "${{ secrets.MATRIX_SERVER }}"
MATRIX_ROOM: "${{ secrets.MATRIX_ROOM }}"
MATRIX_USER_ID: "${{ secrets.MATRIX_USER_ID }}"
MATRIX_TOKEN: "${{ secrets.MATRIX_TOKEN }}"
MATRIX_DEVICE_ID: "${{ secrets.MATRIX_DEVICE_ID }}"
uses: docker://keybaseio/client:stable-node
with:
args: .github/workflows/support-files/notifications/entry_point.sh
+1 -1
View File
@@ -17,7 +17,7 @@ jobs:
- uses: rlespinasse/github-slug-action@v3.x
- uses: actions/setup-node@v3
with:
node-version: 18.17
node-version: 18
- name: Install Rust stable
uses: actions-rs/toolchain@v1
with:
@@ -0,0 +1,92 @@
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
-27
View File
@@ -1,27 +0,0 @@
name: pr-validation
on:
pull_request:
branches:
- develop
- 'release/**'
types:
- labeled
- unlabeled
- opened
- reopened
- synchronize
- edited
- milestoned
- demilestoned
env:
LABELS: ${{ join( github.event.pull_request.labels.*.name, ' ' ) }}
jobs:
check-milestone:
name: Check Milestone
runs-on: ubuntu-latest
steps:
- if: github.event.pull_request.milestone == null && contains( env.LABELS, 'no-milestone' ) == false
run: exit 1
+12 -4
View File
@@ -27,17 +27,21 @@ jobs:
release_id: ${{ steps.create-release.outputs.id }}
release_date: ${{ fromJSON(steps.create-release.outputs.assets)[0].published_at }}
client_hash: ${{ steps.binary-hashes.outputs.client_hash }}
mixnode_hash: ${{ steps.binary-hashes.outputs.mixnode_hash }}
gateway_hash: ${{ steps.binary-hashes.outputs.gateway_hash }}
nymvisor_hash: ${{ steps.binary-hashes.outputs.nymvisor_hash }}
nymnode_hash: ${{ steps.binary-hashes.outputs.nymnode_hash }}
socks5_hash: ${{ steps.binary-hashes.outputs.socks5_hash }}
netreq_hash: ${{ steps.binary-hashes.outputs.netreq_hash }}
cli_hash: ${{ steps.binary-hashes.outputs.cli_hash }}
netstat_hash: ${{ steps.binary-hashes.outputs.netstat_hash }}
client_version: ${{ steps.binary-versions.outputs.client_version }}
mixnode_version: ${{ steps.binary-versions.outputs.mixnode_version }}
gateway_version: ${{ steps.binary-versions.outputs.gateway_version }}
nymvisor_version: ${{ steps.binary-versions.outputs.nymvisor_version }}
nymnode_version: ${{ steps.binary-versions.outputs.nymnode_version }}
socks5_version: ${{ steps.binary-versions.outputs.socks5_version }}
netreq_version: ${{ steps.binary-versions.outputs.netreq_version }}
cli_version: ${{ steps.binary-versions.outputs.cli_version }}
netstat_version: ${{ steps.binary-versions.outputs.netstat_version }}
steps:
- uses: actions/checkout@v3
@@ -69,12 +73,14 @@ jobs:
path: |
target/release/explorer-api
target/release/nym-client
target/release/nym-gateway
target/release/nym-mixnode
target/release/nym-socks5-client
target/release/nym-api
target/release/nym-network-requester
target/release/nym-network-statistics
target/release/nym-cli
target/release/nymvisor
target/release/nym-node
retention-days: 30
- id: create-release
@@ -85,12 +91,14 @@ jobs:
files: |
target/release/explorer-api
target/release/nym-client
target/release/nym-gateway
target/release/nym-mixnode
target/release/nym-socks5-client
target/release/nym-api
target/release/nym-network-requester
target/release/nym-network-statistics
target/release/nym-cli
target/release/nymvisor
target/release/nym-node
push-release-data-client:
if: ${{ (startsWith(github.ref, 'refs/tags/nym-binaries-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
@@ -0,0 +1,122 @@
name: publish-nym-connect-macos
on:
workflow_dispatch:
release:
types: [created]
defaults:
run:
working-directory: nym-connect/desktop
jobs:
publish-tauri:
if: ${{ (startsWith(github.ref, 'refs/tags/nym-connect-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
strategy:
fail-fast: false
matrix:
platform: [macos-12-large]
runs-on: ${{ matrix.platform }}
outputs:
release_id: ${{ steps.create-release.outputs.id }}
release_date: ${{ fromJSON(steps.create-release.outputs.assets)[0].created_at }}
version: ${{ steps.release-info.outputs.version }}
filename: ${{ steps.release-info.outputs.filename }}
file_hash: ${{ steps.release-info.outputs.file_hash }}
steps:
- uses: actions/checkout@v2
- name: Node
uses: actions/setup-node@v3
with:
node-version: 18
- name: Install Rust stable
uses: actions-rs/toolchain@v1
with:
toolchain: stable
target: wasm32-unknown-unknown
- name: Install wasm-pack
run: |
export WASM_PACK_VERSION="v0.12.1"
curl -LO https://github.com/rustwasm/wasm-pack/releases/download/${WASM_PACK_VERSION}/wasm-pack-${WASM_PACK_VERSION}-x86_64-apple-darwin.tar.gz
tar xvzf wasm-pack-${WASM_PACK_VERSION}-x86_64-apple-darwin.tar.gz -C $HOME/.cargo/bin --strip-components=1
rm wasm-pack-${WASM_PACK_VERSION}-x86_64-apple-darwin.tar.gz
- name: Install the Apple developer certificate for code signing
env:
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
run: |
# create variables
CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12
KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db
# import certificate and provisioning profile from secrets
echo -n "$APPLE_CERTIFICATE" | base64 --decode --output $CERTIFICATE_PATH
# create temporary keychain
security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
security set-keychain-settings -lut 21600 $KEYCHAIN_PATH
security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
# import certificate to keychain
security import $CERTIFICATE_PATH -P "$APPLE_CERTIFICATE_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
security list-keychain -d user -s $KEYCHAIN_PATH
- name: Create env file
uses: timheuer/base64-to-file@v1.2
with:
fileName: '.env'
encodedString: ${{ secrets.WALLET_ADMIN_ADDRESS }}
- name: Install project dependencies
shell: bash
run: cd .. && yarn --network-timeout 100000
- name: Install app dependencies and build it
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
ENABLE_CODE_SIGNING: ${{ secrets.APPLE_CERTIFICATE }}
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_IDENTITY_ID }}
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
SENTRY_DSN_RUST: ${{ secrets.SENTRY_DSN_RUST }}
SENTRY_DSN_JS: ${{ secrets.SENTRY_DSN_JS }}
run: yarn && yarn build
- name: Upload Artifact
uses: actions/upload-artifact@v3
with:
name: nym-connect_1.0.0_x64.dmg
path: nym-connect/desktop/target/release/bundle/dmg/nym-connect_1*_x64.dmg
retention-days: 30
- name: Clean up keychain
if: ${{ always() }}
run: |
security delete-keychain $RUNNER_TEMP/app-signing.keychain-db
- id: create-release
name: Upload to release based on tag name
uses: softprops/action-gh-release@v1
if: github.event_name == 'release'
with:
files: |
nym-connect/desktop/target/release/bundle/dmg/*.dmg
nym-connect/desktop/target/release/bundle/macos/*.app.tar.gz*
push-release-data:
if: ${{ (startsWith(github.ref, 'refs/tags/nym-connect-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
uses: ./.github/workflows/release-calculate-hash.yml
needs: publish-tauri
with:
release_tag: ${{ github.ref_name }}
secrets: inherit
@@ -0,0 +1,89 @@
name: publish-nym-connect-ubuntu
on:
workflow_dispatch:
release:
types: [created]
defaults:
run:
working-directory: nym-connect/desktop
jobs:
publish-tauri:
if: ${{ (startsWith(github.ref, 'refs/tags/nym-connect-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
strategy:
fail-fast: false
matrix:
platform: [custom-ubuntu-20.04]
runs-on: ${{ matrix.platform }}
outputs:
release_id: ${{ steps.create-release.outputs.id }}
release_date: ${{ fromJSON(steps.create-release.outputs.assets)[0].created_at }}
version: ${{ steps.release-info.outputs.version }}
filename: ${{ steps.release-info.outputs.filename }}
file_hash: ${{ steps.release-info.outputs.file_hash }}
steps:
- uses: actions/checkout@v2
- name: Tauri dependencies
run: >
sudo apt-get update &&
sudo apt-get install -y webkit2gtk-4.0 libayatana-appindicator3-dev
continue-on-error: true
- name: Node
uses: actions/setup-node@v3
with:
node-version: 18
- name: Install Rust stable
uses: actions-rs/toolchain@v1
with:
toolchain: stable
- name: Install project dependencies
shell: bash
run: cd .. && yarn --network-timeout 100000
- name: Install app dependencies
run: yarn
- name: Create env file
uses: timheuer/base64-to-file@v1.2
with:
fileName: '.env'
encodedString: ${{ secrets.WALLET_ADMIN_ADDRESS }}
- name: Build app
run: yarn build
env:
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
SENTRY_DSN_RUST: ${{ secrets.SENTRY_DSN_RUST }}
SENTRY_DSN_JS: ${{ secrets.SENTRY_DSN_JS }}
- name: Upload Artifact
uses: actions/upload-artifact@v3
with:
name: nym-connect.AppImage.tar.gz
path: nym-connect/desktop/target/release/bundle/appimage/nym-connect_1*_amd64.AppImage
retention-days: 30
- id: create-release
name: Upload to release based on tag name
uses: softprops/action-gh-release@v1
if: github.event_name == 'release'
with:
files: |
nym-connect/desktop/target/release/bundle/appimage/*.AppImage
nym-connect/desktop/target/release/bundle/appimage/*.AppImage.tar.gz*
push-release-data:
if: ${{ (startsWith(github.ref, 'refs/tags/nym-connect-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
uses: ./.github/workflows/release-calculate-hash.yml
needs: publish-tauri
with:
release_tag: ${{ github.ref_name }}
secrets: inherit
@@ -0,0 +1,108 @@
name: publish-nym-connect-win10
on:
workflow_dispatch:
release:
types: [created]
defaults:
run:
working-directory: nym-connect/desktop
jobs:
publish-tauri:
if: ${{ (startsWith(github.ref, 'refs/tags/nym-connect-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
strategy:
fail-fast: false
matrix:
platform: [windows10]
runs-on: ${{ matrix.platform }}
outputs:
release_id: ${{ steps.create-release.outputs.id }}
release_date: ${{ fromJSON(steps.create-release.outputs.assets)[0].created_at }}
version: ${{ steps.release-info.outputs.version }}
filename: ${{ steps.release-info.outputs.filename }}
file_hash: ${{ steps.release-info.outputs.file_hash }}
steps:
- name: Clean up first
continue-on-error: true
working-directory: .
run: |
cd ..
del /s /q /A:H nym
rmdir /s /q nym
- uses: actions/checkout@v3
- name: Import signing certificate
env:
WINDOWS_CERTIFICATE: ${{ secrets.WINDOWS_CERTIFICATE }}
WINDOWS_CERTIFICATE_PASSWORD: ${{ secrets.WINDOWS_CERTIFICATE_PASSWORD }}
run: |
New-Item -ItemType directory -Path certificate
Set-Content -Path certificate/tempCert.txt -Value $env:WINDOWS_CERTIFICATE
certutil -decode certificate/tempCert.txt certificate/certificate.pfx
Remove-Item -path certificate -include tempCert.txt
Import-PfxCertificate -FilePath certificate/certificate.pfx -CertStoreLocation Cert:\CurrentUser\My -Password (ConvertTo-SecureString -String $env:WINDOWS_CERTIFICATE_PASSWORD -Force -AsPlainText)
- name: Node
uses: actions/setup-node@v3
with:
node-version: 18
- name: Install Rust stable
uses: actions-rs/toolchain@v1
with:
toolchain: stable
- name: Create env file
uses: timheuer/base64-to-file@v1.2
with:
fileName: '.env'
encodedString: ${{ secrets.WALLET_ADMIN_ADDRESS }}
- name: Install project dependencies
shell: bash
run: cd .. && yarn --network-timeout 100000
- name: Install app dependencies
shell: bash
run: yarn --network-timeout 100000
- name: Build and sign it
shell: bash
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
ENABLE_CODE_SIGNING: ${{ secrets.WINDOWS_CERTIFICATE }}
WINDOWS_CERTIFICATE: ${{ secrets.WINDOWS_CERTIFICATE }}
WINDOWS_CERTIFICATE_PASSWORD: ${{ secrets.WINDOWS_CERTIFICATE_PASSWORD }}
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
SENTRY_DSN_RUST: ${{ secrets.SENTRY_DSN_RUST }}
SENTRY_DSN_JS: ${{ secrets.SENTRY_DSN_JS }}
run: yarn build
- name: Upload Artifact
uses: actions/upload-artifact@v3
with:
name: nym-connect_1.0.0_x64_en-US.msi
path: nym-connect/desktop/target/release/bundle/msi/nym-connect_1*_x64_en-US.msi
retention-days: 30
- id: create-release
name: Upload to release based on tag name
uses: softprops/action-gh-release@v1
if: github.event_name == 'release'
with:
files: |
nym-connect/desktop/target/release/bundle/msi/*.msi
nym-connect/desktop/target/release/bundle/msi/*.msi.zip*
push-release-data:
if: ${{ (startsWith(github.ref, 'refs/tags/nym-connect-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
uses: ./.github/workflows/release-calculate-hash.yml
needs: publish-tauri
with:
release_tag: ${{ github.ref_name }}
secrets: inherit
@@ -102,18 +102,6 @@ jobs:
nym-wallet/target/release/bundle/dmg/*.dmg
nym-wallet/target/release/bundle/macos/*.app.tar.gz*
- name: Deploy artifacts 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: "nym-wallet/target/release/bundle/macos/nym-wallet.app.tar.gz"
REMOTE_HOST: ${{ secrets.CI_WWW_REMOTE_HOST }}
REMOTE_USER: ${{ secrets.CI_WWW_REMOTE_USER }}
TARGET: ${{ secrets.CI_WWW_REMOTE_TARGET }}/builds/${{ github.ref_name }}/nym-wallet
EXCLUDE: "/dist/, /node_modules/"
push-release-data:
if: ${{ (startsWith(github.ref, 'refs/tags/nym-wallet-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
uses: ./.github/workflows/release-calculate-hash.yml
@@ -77,18 +77,6 @@ jobs:
nym-wallet/target/release/bundle/appimage/*.AppImage
nym-wallet/target/release/bundle/appimage/*.AppImage.tar.gz*
- name: Deploy artifacts 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: "nym-wallet/target/release/bundle/appimage/nym-wallet*.AppImage.tar.gz"
REMOTE_HOST: ${{ secrets.CI_WWW_REMOTE_HOST }}
REMOTE_USER: ${{ secrets.CI_WWW_REMOTE_USER }}
TARGET: ${{ secrets.CI_WWW_REMOTE_TARGET }}/builds/${{ github.ref_name }}/nym-wallet
EXCLUDE: "/dist/, /node_modules/"
push-release-data:
if: ${{ (startsWith(github.ref, 'refs/tags/nym-wallet-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
uses: ./.github/workflows/release-calculate-hash.yml
@@ -97,18 +97,6 @@ jobs:
nym-wallet/target/release/bundle/msi/*.msi
nym-wallet/target/release/bundle/msi/*.msi.zip*
- name: Deploy artifacts 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: "nym-wallet/target/release/bundle/msi/nym-wallet_1.*.msi"
REMOTE_HOST: ${{ secrets.CI_WWW_REMOTE_HOST }}
REMOTE_USER: ${{ secrets.CI_WWW_REMOTE_USER }}
TARGET: ${{ secrets.CI_WWW_REMOTE_TARGET }}/builds/${{ github.ref_name }}/nym-wallet
EXCLUDE: "/dist/, /node_modules/"
push-release-data:
if: ${{ (startsWith(github.ref, 'refs/tags/nym-wallet-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
uses: ./.github/workflows/release-calculate-hash.yml
@@ -0,0 +1,29 @@
const Handlebars = require('handlebars');
const fs = require('fs');
const path = require('path');
async function addToContextAndValidate(context) {
if (!context.env.NYM_CI_WWW_LOCATION) {
throw new Error('Please ensure the env var NYM_CI_WWW_LOCATION is set');
}
if (!context.env.NYM_CI_WWW_BASE) {
throw new Error('Please ensure the env var NYM_CI_WWW_BASE is set');
}
}
async function getMessageBody(context) {
const source = fs
.readFileSync(
context.env.IS_SUCCESS === 'true'
? path.resolve(__dirname, 'templates', 'success')
: path.resolve(__dirname, 'templates', 'failure'),
)
.toString();
const template = Handlebars.compile(source);
return template(context);
}
module.exports = {
addToContextAndValidate,
getMessageBody,
};
@@ -0,0 +1,16 @@
🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥
> :rocket: {{ env.NYM_PROJECT_NAME }}
>
> 🔴 **FAILURE** :cry:
>
> `branch` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/tree/{{ env.GIT_BRANCH_NAME }}
>
> `commit` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/commit/{{ env.GITHUB_SHA }}
>
> `build ` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/actions/runs/{{ env.GITHUB_RUN_ID }}
>
Commit message:
```
{{ env.GIT_COMMIT_MESSAGE }}
```
@@ -0,0 +1,16 @@
🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩
> :rocket: {{ env.NYM_PROJECT_NAME }} ➡️➡️➡️➡️➡️ **View storybook:** https://{{ env.NYM_CI_WWW_LOCATION }}.{{ env.NYM_CI_WWW_BASE }}/
>
> ✅ **SUCCESS**
>
> `branch` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/tree/{{ env.GIT_BRANCH_NAME }}
>
> `commit` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/commit/{{ env.GITHUB_SHA }}
>
> `build ` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/actions/runs/{{ env.GITHUB_RUN_ID }}
>
Commit message by `{{ env.GITHUB_ACTOR }}` at {{ timestamp }}:
```
{{ env.GIT_COMMIT_MESSAGE }}
```
-135
View File
@@ -4,141 +4,6 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
## [Unreleased]
## [2024.7-doubledecker] (2024-07-04)
- Add an early return in `parse_raw_str_logs` for empty raw log strings. ([#4686])
- Bump braces from 3.0.2 to 3.0.3 in /wasm/mix-fetch/internal-dev ([#4672])
- add expiry returned on import ([#4670])
- [bugfix] missing rustls feature ([#4666])
- Bump ws from 8.13.0 to 8.17.1 in /wasm/client/internal-dev-node ([#4665])
- Bump braces from 3.0.2 to 3.0.3 in /clients/native/examples/js-examples/websocket ([#4663])
- Bump ws from 8.14.2 to 8.17.1 in /sdk/typescript/packages/nodejs-client ([#4662])
- Update setup.md ([#4661])
- New clippy lints ([#4660])
- Bump braces from 3.0.2 to 3.0.3 in /nym-api/tests ([#4659])
- Bump braces from 3.0.2 to 3.0.3 in /docker/typescript_client/upload_contract ([#4658])
- Update vps-setup.md ([#4656])
- Update configuration.md ([#4655])
- Remove old PR template ([#4639])
[#4686]: https://github.com/nymtech/nym/pull/4686
[#4672]: https://github.com/nymtech/nym/pull/4672
[#4670]: https://github.com/nymtech/nym/pull/4670
[#4666]: https://github.com/nymtech/nym/pull/4666
[#4665]: https://github.com/nymtech/nym/pull/4665
[#4663]: https://github.com/nymtech/nym/pull/4663
[#4662]: https://github.com/nymtech/nym/pull/4662
[#4661]: https://github.com/nymtech/nym/pull/4661
[#4660]: https://github.com/nymtech/nym/pull/4660
[#4659]: https://github.com/nymtech/nym/pull/4659
[#4658]: https://github.com/nymtech/nym/pull/4658
[#4656]: https://github.com/nymtech/nym/pull/4656
[#4655]: https://github.com/nymtech/nym/pull/4655
[#4639]: https://github.com/nymtech/nym/pull/4639
## [2024.6-chomp] (2024-06-25)
- Remove additional code as part of Ephemera Purge and SP and contracts ([#4650])
- bugfix: make sure nym-api can handle non-cw2 (or without detailed build info) compliant contracts ([#4648])
- introduced a flag to accept toc and exposed it via self-described API ([#4647])
- bugfix: make sure to return an error on invalid public ip ([#4646])
- Add ci check for PR having an assigned milestone ([#4644])
- Removed ephemera code ([#4642])
- Remove stale peers ([#4640])
- Add generic wg private network routing ([#4636])
- Feature/new node endpoints ([#4635])
- standarised ContractBuildInformation and added it to all contracts ([#4631])
- validate nym-node public ips on startup ([#4630])
- Bump defguard wg ([#4625])
- Fix cargo warnings ([#4624])
- Update kernel peers on peer modification ([#4622])
- Handle v6 and v7 requests in the IPR, but reply with v6 ([#4620])
- fix typo ([#4619])
- Update crypto and rand crates ([#4607])
- Purge name service and service provider directory contracts ([#4603])
[#4650]: https://github.com/nymtech/nym/pull/4650
[#4648]: https://github.com/nymtech/nym/pull/4648
[#4647]: https://github.com/nymtech/nym/pull/4647
[#4646]: https://github.com/nymtech/nym/pull/4646
[#4644]: https://github.com/nymtech/nym/pull/4644
[#4642]: https://github.com/nymtech/nym/pull/4642
[#4640]: https://github.com/nymtech/nym/pull/4640
[#4636]: https://github.com/nymtech/nym/pull/4636
[#4635]: https://github.com/nymtech/nym/pull/4635
[#4631]: https://github.com/nymtech/nym/pull/4631
[#4630]: https://github.com/nymtech/nym/pull/4630
[#4625]: https://github.com/nymtech/nym/pull/4625
[#4624]: https://github.com/nymtech/nym/pull/4624
[#4622]: https://github.com/nymtech/nym/pull/4622
[#4620]: https://github.com/nymtech/nym/pull/4620
[#4619]: https://github.com/nymtech/nym/pull/4619
[#4607]: https://github.com/nymtech/nym/pull/4607
[#4603]: https://github.com/nymtech/nym/pull/4603
## [2024.5-ragusa] (2024-05-22)
- Feature/nym node api location ([#4605])
- Add optional signature to IPR request/response ([#4604])
- Feature/unstable tested nodes endpoint ([#4601])
- nym-api: make report/avg_uptime endpoints ignore blacklist ([#4599])
- removed blocking for coconut in the final epoch state ([#4598])
- allow using explicit admin address for issuing freepasses ([#4595])
- Use rfc3339 for last_polled in described nym-api endpoint ([#4591])
- Explicitly handle constraint unique violation when importing credential ([#4588])
- [bugfix] noop flag for nym-api for nymvisor compatibility ([#4586])
- Chore/additional helpers ([#4585])
- Feature/wasm coconut ([#4584])
- upgraded axum and related deps to the most recent version ([#4573])
- Feature/nyxd scraper pruning ([#4564])
- Run cargo autoinherit on the main workspace ([#4553])
- Add rustls-tls to reqwest in validator-client ([#4552])
- Feature/rewarder voucher issuance ([#4548])
- make sure 'OffsetDateTimeJsonSchemaWrapper' is serialised with legacy format ([#4613])
[#4613]: https://github.com/nymtech/nym/pull/4613
[#4605]: https://github.com/nymtech/nym/pull/4605
[#4604]: https://github.com/nymtech/nym/pull/4604
[#4601]: https://github.com/nymtech/nym/pull/4601
[#4599]: https://github.com/nymtech/nym/pull/4599
[#4598]: https://github.com/nymtech/nym/pull/4598
[#4595]: https://github.com/nymtech/nym/pull/4595
[#4591]: https://github.com/nymtech/nym/pull/4591
[#4588]: https://github.com/nymtech/nym/pull/4588
[#4586]: https://github.com/nymtech/nym/pull/4586
[#4585]: https://github.com/nymtech/nym/pull/4585
[#4584]: https://github.com/nymtech/nym/pull/4584
[#4573]: https://github.com/nymtech/nym/pull/4573
[#4564]: https://github.com/nymtech/nym/pull/4564
[#4553]: https://github.com/nymtech/nym/pull/4553
[#4552]: https://github.com/nymtech/nym/pull/4552
[#4548]: https://github.com/nymtech/nym/pull/4548
## [2024.4-nutella] (2024-05-08)
- [fix] apply disable_poisson_rate from internal NR/IPR cfgs ([#4579])
- updating sign commands to include nym-node ([#4578])
- changed nym-node redirects from 308 'Permanent Redirect' to 303: 'See Other' ([#4572])
[#4579]: https://github.com/nymtech/nym/pull/4579
[#4578]: https://github.com/nymtech/nym/pull/4578
[#4572]: https://github.com/nymtech/nym/pull/4572
## [2024.3-eclipse] (2024-04-22)
- Initial release of the first iteration of the Nym Node
- Improvements to gateway functionality
- IPR development
- Removal of allow list in favour of implementing an exit policy
- Explorer delegation: enables direct delegation to nodes via the Nym Explorer
## [2024.2-fast-and-furious] (2024-03-25)
- Internal testing pre-release
## [2024.1-marabou] (2024-02-15)
**New Features:**
Generated
+3355 -1724
View File
File diff suppressed because it is too large Load Diff
+36 -148
View File
@@ -20,12 +20,10 @@ members = [
"clients/native",
"clients/native/websocket-requests",
"clients/socks5",
"common/authenticator-requests",
"common/async-file-watcher",
"common/bandwidth-controller",
"common/bin-common",
"common/client-core",
"common/client-core/config-types",
"common/client-core/surb-storage",
"common/client-core/gateways-storage",
"common/client-libs/gateway-client",
@@ -36,11 +34,13 @@ members = [
"common/cosmwasm-smart-contracts/coconut-bandwidth-contract",
"common/cosmwasm-smart-contracts/coconut-dkg",
"common/cosmwasm-smart-contracts/contracts-common",
# "common/cosmwasm-smart-contracts/ephemera",
"common/cosmwasm-smart-contracts/group-contract",
"common/cosmwasm-smart-contracts/mixnet-contract",
"common/cosmwasm-smart-contracts/multisig-contract",
"common/cosmwasm-smart-contracts/name-service",
"common/cosmwasm-smart-contracts/service-provider-directory",
"common/cosmwasm-smart-contracts/vesting-contract",
"common/country-group",
"common/credential-storage",
"common/credentials",
"common/credential-utils",
@@ -50,7 +50,6 @@ members = [
"common/execute",
"common/exit-policy",
"common/http-api-client",
"common/http-api-common",
"common/inclusion-probability",
"common/ip-packet-requests",
"common/ledger",
@@ -77,6 +76,7 @@ members = [
"common/socks5-client-core",
"common/socks5/proxy-helpers",
"common/socks5/requests",
"common/statistics",
"common/store-cipher",
"common/task",
"common/topology",
@@ -96,15 +96,14 @@ members = [
"mixnode",
"sdk/lib/socks5-listener",
"sdk/rust/nym-sdk",
"service-providers/authenticator",
"service-providers/common",
"service-providers/ip-packet-router",
"service-providers/network-requester",
"service-providers/network-statistics",
"nym-api",
"nym-browser-extension/storage",
"nym-api/nym-api-requests",
"nym-node",
"nym-node/nym-node-http-api",
"nym-node/nym-node-requests",
"nym-outfox",
"nym-validator-rewarder",
@@ -116,10 +115,10 @@ members = [
"tools/nymvisor",
"tools/ts-rs-cli",
"wasm/client",
# "wasm/full-nym-wasm", # If we uncomment this again, remember to also uncomment the profile settings below
# "wasm/full-nym-wasm",
"wasm/mix-fetch",
"wasm/node-tester",
"wasm/zknym-lib",
"common/nym-metrics",
]
default-members = [
@@ -127,18 +126,21 @@ default-members = [
"clients/socks5",
"gateway",
"service-providers/network-requester",
"service-providers/network-statistics",
"mixnode",
"nym-api",
"tools/nymvisor",
"explorer-api",
"nym-validator-rewarder",
"nym-node"
]
exclude = [
"explorer",
"contracts",
"nym-wallet",
"nym-connect/mobile/src-tauri",
"nym-connect/desktop",
"nym-vpn/ui/src-tauri",
"cpu-cycles",
"sdk/ffi/cpp",
]
@@ -152,152 +154,43 @@ edition = "2021"
license = "Apache-2.0"
[workspace.dependencies]
addr = "0.15.6"
aes = "0.8.1"
aes-gcm = "0.10.1"
anyhow = "1.0.71"
argon2 = "0.5.0"
async-trait = "0.1.68"
axum = "0.7.5"
axum-extra = "0.9.3"
axum = "0.6.20"
base64 = "0.21.4"
bincode = "1.3.3"
bs58 = "0.5.0"
bip39 = { version = "2.0.0", features = ["zeroize"] }
bitvec = "1.0.0"
blake3 = "1.3.1"
bs58 = "0.5.1"
bytecodec = "0.4.15"
bytes = "1.5.0"
cargo_metadata = "0.18.1"
celes = "2.4.0"
cfg-if = "1.0.0"
chacha20 = "0.9.0"
chacha20poly1305 = "0.10.1"
chrono = "0.4.31"
cipher = "0.4.3"
clap = "4.4.7"
clap_complete = "4.0"
clap_complete_fig = "4.0"
colored = "2.0"
comfy-table = "6.0.0"
console-subscriber = "0.1.1"
console_error_panic_hook = "0.1"
const-str = "0.5.6"
const_format = "0.2.32"
criterion = "0.4"
csv = "1.3.0"
ctr = "0.9.1"
cupid = "0.6.1"
curve25519-dalek = "4.1"
cfg-if = "1.0.0"
dashmap = "5.5.3"
defguard_wireguard_rs = "0.4.2"
digest = "0.10.7"
dirs = "4.0"
doc-comment = "0.3"
dotenvy = "0.15.6"
ecdsa = "0.16"
ed25519-dalek = "2.1"
etherparse = "0.13.0"
eyre = "0.6.9"
fastrand = "2.1.0"
flate2 = "1.0.28"
futures = "0.3.28"
generic-array = "0.14.7"
getrandom = "0.2.10"
getset = "0.1.1"
handlebars = "3.5.5"
headers = "0.4.0"
hex = "0.4.3"
hex-literal = "0.3.3"
hkdf = "0.12.3"
hmac = "0.12.1"
http = "1"
httpcodec = "0.2.3"
humantime = "2.1.0"
humantime-serde = "1.1.1"
hyper = "1.3.1"
indexed_db_futures = "0.3.0"
inquire = "0.6.2"
ip_network = "0.4.1"
ipnetwork = "0.16"
isocountry = "0.3.2"
hyper = "0.14.27"
k256 = "0.13"
lazy_static = "1.4.0"
ledger-transport = "0.10.0"
ledger-transport-hid = "0.10.0"
log = "0.4"
maxminddb = "0.23.0"
mime = "0.3.17"
nix = "0.27.1"
notify = "5.1.0"
okapi = "0.7.0"
once_cell = "1.7.2"
opentelemetry = "0.19.0"
opentelemetry-jaeger = "0.18.0"
parking_lot = "0.12.1"
pem = "0.8"
pin-project = "1.0"
pretty_env_logger = "0.4.0"
publicsuffix = "2.2.3"
quote = "1"
rand = "0.8.5"
rand-07 = "0.7.3"
rand_chacha = "0.3"
rand_chacha_02 = "0.2"
rand_core = "0.6.3"
rand_distr = "0.4"
rand_pcg = "0.3.1"
rand_seeder = "0.2.3"
rayon = "1.5.1"
regex = "1.8.4"
reqwest = { version = "0.12.4", default-features = false }
rocket = "0.5.0"
rocket_cors = "0.6.0"
rocket_okapi = "0.8.0"
safer-ffi = "0.1.4"
reqwest = { version = "0.11.22", default-features = false }
schemars = "0.8.1"
semver = "1.0.23"
serde = "1.0.152"
serde_bytes = "0.11.6"
serde_derive = "1.0"
serde_json = "1.0.91"
serde_repr = "0.1"
serde_with = "3.4.0"
serde_yaml = "0.9.25"
sha2 = "0.10.8"
si-scale = "0.2.2"
sphinx-packet = "0.1.1"
sqlx = "0.6.3"
strum = "0.25"
subtle-encoding = "0.5"
syn = "1"
sysinfo = "0.30.12"
tap = "1.0.1"
tar = "0.4.40"
tempfile = "3.5.0"
thiserror = "1.0.48"
time = "0.3.30"
thiserror = "1.0.48"
tokio = "1.33.0"
tokio-stream = "0.1.14"
tokio-test = "0.4.2"
tokio-tungstenite = { version = "0.20.1" }
tokio-util = "0.7.10"
toml = "0.8.14"
tower = "0.4.13"
tower-http = "0.5.2"
tokio-tungstenite = { version = "0.20.1" }
tracing = "0.1.37"
tracing-opentelemetry = "0.19.0"
tracing-subscriber = "0.3.16"
tracing-tree = "0.2.2"
ts-rs = "7.0.0"
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"
utoipa = "4.2.0"
utoipa-swagger-ui = "6.0.0"
vergen = { version = "=8.3.1", default-features = false }
walkdir = "2"
wasm-bindgen-test = "0.3.36"
x25519-dalek = "2.0.0"
zeroize = "1.6.0"
prometheus = { version = "0.13.0" }
@@ -305,9 +198,10 @@ prometheus = { version = "0.13.0" }
# coconut/DKG related
# unfortunately until https://github.com/zkcrypto/bls12_381/issues/10 is resolved, we have to rely on the fork
# as we need to be able to serialize Gt so that we could create the lookup table for baby-step-giant-step algorithm
bls12_381 = { git = "https://github.com/jstuczyn/bls12_381", default-features = false, branch = "feature/gt-serialization-0.8.0" }
group = { version = "0.13.0", default-features = false }
ff = { version = "0.13.0", default-features = false }
bls12_381 = { git = "https://github.com/jstuczyn/bls12_381", branch = "feature/gt-serialization-0.8.0" }
group = "0.13.0"
ff = "0.13.0"
# cosmwasm-related
cosmwasm-derive = "=1.4.3"
@@ -326,27 +220,24 @@ cw4 = { version = "=1.1.2" }
cw-controllers = { version = "=1.1.0" }
# cosmrs-related
bip32 = { version = "0.5.1", default-features = false }
bip32 = "0.5.1"
# temporarily using a fork again (yay.) because we need staking and slashing support
cosmrs = { git = "https://github.com/jstuczyn/cosmos-rust", branch = "nym-temp/all-validator-features" }
#cosmrs = { git = "https://github.com/jstuczyn/cosmos-rust", branch = "nym-temp/all-validator-features" } # unfortuntely we need a fork by yours truly to get the staking support
tendermint = "0.34" # same version as used by cosmrs
tendermint-rpc = "0.34" # same version as used by cosmrs
prost = { version = "0.12", default-features = false }
prost = "0.12"
# wasm-related dependencies
gloo-utils = "0.2.0"
gloo-net = "0.5.0"
js-sys = "0.3.69"
serde-wasm-bindgen = "0.6.5"
gloo-utils = "0.1.7"
js-sys = "0.3.63"
serde-wasm-bindgen = "0.5.0"
tsify = "0.4.5"
wasm-bindgen = "0.2.92"
wasm-bindgen-futures = "0.4.39"
wasm-bindgen = "0.2.86"
wasm-bindgen-futures = "0.4.37"
wasmtimer = "0.2.0"
web-sys = "0.3.69"
itertools = "0.12.0"
web-sys = "0.3.63"
# Profile settings for individual crates
@@ -362,12 +253,9 @@ opt-level = 'z'
# lto = true
opt-level = 'z'
# Commented out since the crate is also commented out from the inclusion in the
# workspace above. We should uncomment this if we re-include it in the
# workspace
#[profile.release.package.nym-wasm-sdk]
## lto = true
#opt-level = 'z'
[profile.release.package.nym-wasm-sdk]
# lto = true
opt-level = 'z'
[profile.release.package.mix-fetch-wasm]
# lto = true
+4 -4
View File
@@ -92,6 +92,7 @@ endef
$(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,wallet,nym-wallet))
$(eval $(call add_cargo_workspace,connect,nym-connect/desktop))
# -----------------------------------------------------------------------------
# SDK
@@ -104,7 +105,6 @@ sdk-wasm-build:
$(MAKE) -C wasm/client
$(MAKE) -C wasm/node-tester
$(MAKE) -C wasm/mix-fetch
$(MAKE) -C wasm/zknym-lib
#$(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
@@ -115,7 +115,7 @@ sdk-typescript-build:
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 zknym-lib
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
@@ -133,7 +133,7 @@ clippy: sdk-wasm-lint
# Build contracts ready for deploy
# -----------------------------------------------------------------------------
CONTRACTS=vesting_contract mixnet_contract
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
@@ -185,4 +185,4 @@ deb-gateway: build-nym-gateway
deb-cli: build-nym-cli
cargo deb -p nym-cli
deb: deb-mixnode deb-gateway deb-cli
deb: deb-mixnode deb-gateway deb-cli
+56 -36
View File
@@ -7,66 +7,86 @@ SPDX-License-Identifier: Apache-2.0
The platform is composed of multiple Rust crates. Top-level executable binary crates include:
* `nym-node` - a tool for running a node within the Nym network. Nym Nodes containing functionality such as `mixnode`, `entry-gateway` and `exit-gateway` are fundamental components of Nym Mixnet architecture. Nym Nodes are ran by decentralised node operators. Read more about `nym-node` in [Operators Guide documentation](https://nymtech.net/operators/nodes/nym-node.html). Network functionality of `nym-node` (labeled with `--mode` flag) can be:
- `mixnode` - shuffles [Sphinx](https://github.com/nymtech/sphinx) packets together to provide privacy against network-level attackers.
- `gateway` - acts sort of like a mailbox for mixnet messages, which removes the need for direct delivery to potentially offline or firewalled devices. Gateways can be further categorized as `entry-gateway` and `exit-gateway`. The latter has an extra embedded IP packet router and Network requester to route data to the internet.
* `nym-client` - an executable which you can build into your own applications. Use it for interacting with Nym nodes.
* `nym-socks5-client` - a Socks5 proxy you can run on your machine and use with existing applications.
* `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.
<!-- coming soon
* `nym-network-monitor` - sends packets through the full system to check that they are working as expected, and stores node uptime histories as the basis of a rewards system ("mixmining" or "proof-of-mixing").
-->
```ascii
┌─►mix──┐ mix mix
│ │
Entry │ │ Exit
client ───► Gateway ──┘ mix │ mix ┌─►mix ───► Gateway ───► internet
│ │
│ │
mix └─►mix──┘ mix
```
* nym-mixnode - shuffles [Sphinx](https://github.com/nymtech/sphinx) packets together to provide privacy against network-level attackers.
* nym-client - an executable which you can build into your own applications. Use it for interacting with Nym nodes.
* nym-socks5-client - a Socks5 proxy you can run on your machine and use with existing applications.
* nym-gateway - acts sort of like a mailbox for mixnet messages, which removes the need for direct delivery to potentially offline or firewalled devices.
* nym-network-monitor - sends packets through the full system to check that they are working as expected, and stores node uptime histories as the basis of a rewards system ("mixmining" or "proof-of-mixing").
* nym-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.
[![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)
### Building
* Platform build instructions are available on Nym [Operators Guide documentation](https://nymtech.net/operators/binaries/building-nym.html).
* Wallet build instructions are available on Nym [Technical docs](https://nymtech.net/docs/wallet/desktop-wallet.html).
Platform build instructions are available on [our docs site](https://nymtech.net/docs/binaries/pre-built-binaries.html).
Wallet build instructions are also available on [our docs site](https://nymtech.net/docs/wallet/desktop-wallet.html).
### Developing
There's a [`sandbox.env`](https://github.com/nymtech/nym/envs/sandbox.env) file provided which you can rename to `.env` if you want convenient testing environment. Read more about sandbox environment in our [Operators Guide page](https://nymtech.net/operators/sandbox.html).
There's a `.env.sample-dev` file provided which you can rename to `.env` if you want convenient logging, backtrace, or other environment variables pre-set. The `.env` file is ignored so you don't need to worry about checking it in.
References for developers:
* [Developers Portal](https://nymtech.net/developers)
* [Typescript SDKs](https://sdk.nymtech.net/)
* [Technical Documentation - Nym network overview](https://nymtech.net/docs/)
* [Release Cycle - git flow](https://nymtech.net/operators/release-cycle.html)
For Typescript components, please see [ts-packages](./ts-packages).
### Developer chat
> We used to use Keybase for developer chats, but we have since migrated to Matrix and Discord. We no longer check the old **nymtech.friends** Keybase team.
You can chat to us in two places:
* The #dev channel on [Matrix](https://matrix.to/#/#dev:nymtech.chat)
* The various developer channels on [Discord](https://discord.gg/FaTJb8q8)
* The various developer channels on [Discord](https://discord.gg/nym)
### Tokenomics & Rewards
### Rewards
Nym network economic incentives, operator and validator rewards, and scalability of the network are determined according to the principles laid out in the section 6 of [Nym Whitepaper](https://nymtech.net/nym-whitepaper.pdf).
Initial reward pool is set to 250 million Nym, making the circulating supply 750 million Nym.
Node, node operator and delegator rewards are determined according to the principles laid out in the section 6 of [Nym Whitepaper](https://nymtech.net/nym-whitepaper.pdf). Below is a TLDR of the variables and formulas involved in calculating the epoch rewards. Initial reward pool is set to 250 million Nym, making the circulating supply 750 million Nym.
|Symbol|Definition|
|---|---|
|<img src="https://render.githubusercontent.com/render/math?math=R#gh-light-mode-only"><img src="https://render.githubusercontent.com/render/math?math=\color{white}R#gh-dark-mode-only">|global share of rewards available, starts at 2% of the reward pool.
|<img src="https://render.githubusercontent.com/render/math?math=R_{i}#gh-light-mode-only"><img src="https://render.githubusercontent.com/render/math?math=\color{white}R_{i}#gh-dark-mode-only">|node reward for mixnode `i`.
|<img src="https://render.githubusercontent.com/render/math?math=\sigma_{i}#gh-light-mode-only"><img src="https://render.githubusercontent.com/render/math?math=\color{white}\sigma_{i}#gh-dark-mode-only">|ratio of total node stake (node bond + all delegations) to the token circulating supply.
|<img src="https://render.githubusercontent.com/render/math?math=\lambda_{i}#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=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=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=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.
Node reward for node `i` is determined as:
<img src="https://render.githubusercontent.com/render/math?math=R_{i}=PF_{i} \cdot R \cdot (\sigma^'_{i} \cdot \omega_{i} \cdot k %2b \alpha \cdot \lambda^'_{i} \cdot \sigma^'_{i} \cdot k)/(1 %2b \alpha)#gh-light-mode-only">
<img src="https://render.githubusercontent.com/render/math?math=\color{white}R_{i}=PF_{i} \cdot R \cdot (\sigma^'_{i} \cdot \omega_{i} \cdot k %2b \alpha \cdot \lambda^'_{i} \cdot \sigma^'_{i} \cdot k)/(1 %2b \alpha)#gh-dark-mode-only">
where:
<img src="https://render.githubusercontent.com/render/math?math=\sigma^'_{i} = min\{\sigma_{i}, 1/k\}#gh-light-mode-only">
<img src="https://render.githubusercontent.com/render/math?math=\color{white}\sigma^'_{i} = min\{\sigma_{i}, 1/k\}#gh-dark-mode-only">
and
<img src="https://render.githubusercontent.com/render/math?math=\lambda^'_{i} = min\{\lambda_{i}, 1/k\}#gh-light-mode-only">
<img src="https://render.githubusercontent.com/render/math?math=\color{white}\lambda^'_{i} = min\{\lambda_{i}, 1/k\}#gh-dark-mode-only">
Operator of node `i` is credited with the following amount:
<img src="https://render.githubusercontent.com/render/math?math=min\{PP_{i},R_{i})\} %2b max\{0, (PM_{i} %2b (1 - PM_{i}) \cdot \lambda_{i}/\delta_{i}) \cdot (R_{i} - PP_{i})\}#gh-light-mode-only">
<img src="https://render.githubusercontent.com/render/math?math=\color{white}min\{PP_{i},R_{i})\} %2b max\{0, (PM_{i} %2b (1 - PM_{i}) \cdot \lambda_{i}/\delta_{i}) \cdot (R_{i} - PP_{i})\}#gh-dark-mode-only">
Delegate with stake `s` receives:
<img src="https://render.githubusercontent.com/render/math?math=max\{0, (1-PM_{i}) \cdot (s^'/\sigma_{i}) \cdot (R_{i} - PP_{i})\}#gh-light-mode-only">
<img src="https://render.githubusercontent.com/render/math?math=\color{white}max\{0, (1-PM_{i}) \cdot (s^'/\sigma_{i}) \cdot (R_{i} - PP_{i})\}#gh-dark-mode-only">
where `s'` is stake `s` scaled over total token circulating supply.
### 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.
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
Nym Node Operators and Validators Temrs and Conditions can be found [here](https://nymtech.net/terms-and-conditions/operators/v1.0.0).
Again, for accurate information, please check individual files.
+5 -5
View File
@@ -1,6 +1,6 @@
[package]
name = "nym-client"
version = "1.1.37"
version = "1.1.33"
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"]
description = "Implementation of the Nym Client"
edition = "2021"
@@ -23,13 +23,13 @@ url = { workspace = true }
bs58 = { workspace = true }
clap = { workspace = true, features = ["cargo", "derive"] }
dirs = { workspace = true }
dirs = "4.0"
log = { workspace = true } # self explanatory
rand = { workspace = true }
rand = { version = "0.7.3", features = ["wasm-bindgen"] } # rng-related traits + some rng implementation to use
serde = { workspace = true, features = ["derive"] } # for config serialization/deserialization
serde_json = { workspace = true }
thiserror = { workspace = true }
tap = { workspace = true }
tap = "1.0.1"
time = { workspace = true }
tokio = { workspace = true, features = ["rt-multi-thread", "net", "signal"] } # async runtime
tokio-tungstenite = { workspace = true }
@@ -37,7 +37,7 @@ zeroize = { workspace = true }
## internal
nym-bandwidth-controller = { path = "../../common/bandwidth-controller" }
nym-bin-common = { path = "../../common/bin-common", features = ["output_format", "clap"] }
nym-bin-common = { path = "../../common/bin-common", features = ["output_format"] }
nym-client-core = { path = "../../common/client-core", features = ["fs-surb-storage", "fs-gateways-storage", "cli"] }
nym-config = { path = "../../common/config" }
nym-credential-storage = { path = "../../common/credential-storage" }
File diff suppressed because it is too large Load Diff
+1 -3
View File
@@ -106,10 +106,8 @@ impl SocketClient {
};
let storage = self.initialise_storage().await?;
let user_agent = nym_bin_common::bin_info!().into();
let mut base_client = BaseClientBuilder::new(&self.config.base, storage, dkg_query_client)
.with_user_agent(user_agent);
let mut base_client = BaseClientBuilder::new(&self.config.base, storage, dkg_query_client);
if let Some(custom_mixnet) = &self.custom_mixnet {
base_client = base_client.with_stored_topology(custom_mixnet)?;
+1 -2
View File
@@ -22,9 +22,8 @@ impl AsRef<CommonClientAddGatewayArgs> for Args {
}
pub(crate) async fn execute(args: Args) -> Result<(), ClientError> {
let user_agent = nym_bin_common::bin_info!().into();
let output = args.output;
let res = add_gateway::<CliNativeClient, _>(args, Some(user_agent)).await?;
let res = add_gateway::<CliNativeClient, _>(args).await?;
println!("{}", output.format(&res));
Ok(())
@@ -8,7 +8,5 @@ use nym_client_core::cli_helpers::client_import_credential::{
};
pub(crate) async fn execute(args: CommonClientImportCredentialArgs) -> Result<(), ClientError> {
import_credential::<CliNativeClient, _>(args).await?;
println!("successfully imported credential!");
Ok(())
import_credential::<CliNativeClient, _>(args).await
}
+1 -2
View File
@@ -114,9 +114,8 @@ impl Display for InitResults {
pub(crate) async fn execute(args: Init) -> Result<(), ClientError> {
eprintln!("Initialising client...");
let user_agent = nym_bin_common::bin_info!().into();
let output = args.output;
let res = initialise_client::<CliNativeClient>(args, Some(user_agent)).await?;
let res = initialise_client::<CliNativeClient>(args).await?;
let init_results = InitResults::new(res);
println!("{}", output.format(&init_results));
-3
View File
@@ -23,9 +23,6 @@ pub enum ClientError {
#[error("Attempted to start the client in invalid socket mode")]
InvalidSocketMode,
#[error(transparent)]
ConfigUpgradeFailure(#[from] nym_client_core::config::ConfigUpgradeFailure),
#[error(transparent)]
NymIdError(#[from] NymIdError),
}
+8 -9
View File
@@ -1,6 +1,6 @@
[package]
name = "nym-socks5-client"
version = "1.1.37"
version = "1.1.33"
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"
edition = "2021"
@@ -13,10 +13,10 @@ clap = { workspace = true, features = ["cargo", "derive"] }
log = { workspace = true }
serde = { workspace = true, features = ["derive"] } # for config serialization/deserialization
serde_json = { workspace = true }
tap = { workspace = true }
tap = "1.0.1"
thiserror = { workspace = true }
tokio = { workspace = true, features = ["rt-multi-thread", "net", "signal"] }
rand = { workspace = true }
tokio = { version = "1.24.1", features = ["rt-multi-thread", "net", "signal"] }
rand = "0.7.3"
time = { workspace = true }
url = { workspace = true }
zeroize = { workspace = true }
@@ -25,18 +25,17 @@ zeroize = { workspace = true }
nym-bin-common = { path = "../../common/bin-common", features = ["output_format"] }
nym-client-core = { path = "../../common/client-core", features = ["fs-surb-storage", "fs-gateways-storage", "cli"] }
nym-config = { path = "../../common/config" }
nym-credential-storage = { path = "../../common/credential-storage" }
nym-credentials = { path = "../../common/credentials" }
nym-crypto = { path = "../../common/crypto" }
nym-gateway-requests = { path = "../../gateway/gateway-requests" }
nym-id = { path = "../../common/nym-id" }
nym-credential-storage = { path = "../../common/credential-storage" }
nym-network-defaults = { path = "../../common/network-defaults" }
nym-sphinx = { path = "../../common/nymsphinx" }
nym-ordered-buffer = { path = "../../common/socks5/ordered-buffer" }
nym-pemstore = { path = "../../common/pemstore" }
nym-socks5-client-core = { path = "../../common/socks5-client-core" }
nym-sphinx = { path = "../../common/nymsphinx" }
nym-topology = { path = "../../common/topology" }
nym-validator-client = { path = "../../common/client-libs/validator-client", features = ["http-client"] }
nym-socks5-client-core = { path = "../../common/socks5-client-core" }
nym-id = { path = "../../common/nym-id" }
[features]
default = []
+1 -2
View File
@@ -22,9 +22,8 @@ impl AsRef<CommonClientAddGatewayArgs> for Args {
}
pub(crate) async fn execute(args: Args) -> Result<(), Socks5ClientError> {
let user_agent = nym_bin_common::bin_info!().into();
let output = args.output;
let res = add_gateway::<CliSocks5Client, _>(args, Some(user_agent)).await?;
let res = add_gateway::<CliSocks5Client, _>(args).await?;
println!("{}", output.format(&res));
Ok(())
@@ -10,7 +10,5 @@ use nym_client_core::cli_helpers::client_import_credential::{
pub(crate) async fn execute(
args: CommonClientImportCredentialArgs,
) -> Result<(), Socks5ClientError> {
import_credential::<CliSocks5Client, _>(args).await?;
println!("successfully imported credential!");
Ok(())
import_credential::<CliSocks5Client, _>(args).await
}
+1 -2
View File
@@ -129,9 +129,8 @@ impl Display for InitResults {
pub(crate) async fn execute(args: Init) -> Result<(), Socks5ClientError> {
eprintln!("Initialising client...");
let user_agent = nym_bin_common::bin_info!().into();
let output = args.output;
let res = initialise_client::<CliSocks5Client>(args, Some(user_agent)).await?;
let res = initialise_client::<CliSocks5Client>(args).await?;
let init_results = InitResults::new(res);
println!("{}", output.format(&init_results));
+3 -9
View File
@@ -116,13 +116,7 @@ pub(crate) async fn execute(args: Run) -> Result<(), Box<dyn std::error::Error +
let storage =
OnDiskPersistent::from_paths(config.storage_paths.common_paths, &config.core.base.debug)
.await?;
let user_agent = nym_bin_common::bin_info!().into();
NymClient::new(
config.core,
storage,
user_agent,
args.common_args.custom_mixnet,
)
.run_forever()
.await
NymClient::new(config.core, storage, args.common_args.custom_mixnet)
.run_forever()
.await
}
-3
View File
@@ -23,9 +23,6 @@ pub enum Socks5ClientError {
#[error(transparent)]
ClientCoreError(#[from] ClientCoreError),
#[error(transparent)]
ConfigUpgradeFailure(#[from] nym_client_core::config::ConfigUpgradeFailure),
#[error(transparent)]
NymIdError(#[from] NymIdError),
}
+2 -2
View File
@@ -8,6 +8,6 @@ license.workspace = true
[dependencies]
futures = { workspace = true }
log = { workspace = true }
notify = { workspace = true }
log = "0.4"
notify = "5.1.0"
tokio = { workspace = true, features = ["time"] }
-17
View File
@@ -1,17 +0,0 @@
[package]
name = "nym-authenticator-requests"
version = "0.1.0"
authors.workspace = true
repository.workspace = true
homepage.workspace = true
documentation.workspace = true
edition.workspace = true
license.workspace = true
[dependencies]
bincode = { workspace = true }
rand = { workspace = true }
serde = { workspace = true, features = ["derive"] }
nym-sphinx = { path = "../nymsphinx" }
nym-wireguard-types = { path = "../wireguard-types" }
-13
View File
@@ -1,13 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
pub mod v1;
pub const CURRENT_VERSION: u8 = 1;
fn make_bincode_serializer() -> impl bincode::Options {
use bincode::Options;
bincode::DefaultOptions::new()
.with_big_endian()
.with_varint_encoding()
}
@@ -1,7 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
pub mod request;
pub mod response;
const VERSION: u8 = 1;
@@ -1,70 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use nym_sphinx::addressing::Recipient;
use nym_wireguard_types::{GatewayClient, InitMessage};
use serde::{Deserialize, Serialize};
use crate::make_bincode_serializer;
use super::VERSION;
fn generate_random() -> u64 {
use rand::RngCore;
let mut rng = rand::rngs::OsRng;
rng.next_u64()
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct AuthenticatorRequest {
pub version: u8,
pub data: AuthenticatorRequestData,
pub reply_to: Recipient,
pub request_id: u64,
}
impl AuthenticatorRequest {
pub fn from_reconstructed_message(
message: &nym_sphinx::receiver::ReconstructedMessage,
) -> Result<Self, bincode::Error> {
use bincode::Options;
make_bincode_serializer().deserialize(&message.message)
}
pub fn new_initial_request(init_message: InitMessage, reply_to: Recipient) -> (Self, u64) {
let request_id = generate_random();
(
Self {
version: VERSION,
data: AuthenticatorRequestData::Initial(init_message),
reply_to,
request_id,
},
request_id,
)
}
pub fn new_final_request(gateway_client: GatewayClient, reply_to: Recipient) -> (Self, u64) {
let request_id = generate_random();
(
Self {
version: VERSION,
data: AuthenticatorRequestData::Final(gateway_client),
reply_to,
request_id,
},
request_id,
)
}
pub fn to_bytes(&self) -> Result<Vec<u8>, bincode::Error> {
use bincode::Options;
make_bincode_serializer().serialize(self)
}
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub enum AuthenticatorRequestData {
Initial(InitMessage),
Final(GatewayClient),
}
@@ -1,88 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use nym_sphinx::addressing::Recipient;
use nym_wireguard_types::registration::RegistrationData;
use serde::{Deserialize, Serialize};
use crate::make_bincode_serializer;
use super::VERSION;
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct AuthenticatorResponse {
pub version: u8,
pub data: AuthenticatorResponseData,
pub reply_to: Recipient,
}
impl AuthenticatorResponse {
pub fn new_pending_registration_success(
registration_data: RegistrationData,
request_id: u64,
reply_to: Recipient,
) -> Self {
Self {
version: VERSION,
data: AuthenticatorResponseData::PendingRegistration(PendingRegistrationResponse {
reply: registration_data,
reply_to,
request_id,
}),
reply_to,
}
}
pub fn new_registered(reply_to: Recipient, request_id: u64) -> Self {
Self {
version: VERSION,
data: AuthenticatorResponseData::Registered(RegisteredResponse {
reply_to,
request_id,
}),
reply_to,
}
}
pub fn recipient(&self) -> Recipient {
self.reply_to
}
pub fn to_bytes(&self) -> Result<Vec<u8>, bincode::Error> {
use bincode::Options;
make_bincode_serializer().serialize(self)
}
pub fn from_reconstructed_message(
message: &nym_sphinx::receiver::ReconstructedMessage,
) -> Result<Self, bincode::Error> {
use bincode::Options;
make_bincode_serializer().deserialize(&message.message)
}
pub fn id(&self) -> Option<u64> {
match &self.data {
AuthenticatorResponseData::PendingRegistration(response) => Some(response.request_id),
AuthenticatorResponseData::Registered(response) => Some(response.request_id),
}
}
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub enum AuthenticatorResponseData {
PendingRegistration(PendingRegistrationResponse),
Registered(RegisteredResponse),
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct PendingRegistrationResponse {
pub request_id: u64,
pub reply_to: Recipient,
pub reply: RegistrationData,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct RegisteredResponse {
pub request_id: u64,
pub reply_to: Recipient,
}
+1 -1
View File
@@ -9,7 +9,7 @@ license.workspace = true
[dependencies]
bip39 = { workspace = true }
log = { workspace = true }
rand = { workspace = true }
rand = "0.7.3"
thiserror = { workspace = true }
url = { workspace = true }
zeroize = { workspace = true }
-13
View File
@@ -1,13 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
// See other comments for other TaskStatus message enumds about abusing the Error trait when we
// should have a new trait for TaskStatus messages
#[derive(Debug, thiserror::Error)]
pub enum BandwidthStatusMessage {
#[error("remaining bandwidth: {0}")]
RemainingBandwidth(i64),
#[error("no bandwidth left")]
NoBandwidth,
}
-4
View File
@@ -14,14 +14,10 @@ use nym_validator_client::coconut::all_coconut_api_clients;
use nym_validator_client::nym_api::EpochId;
use nym_validator_client::nyxd::contract_traits::DkgQueryClient;
pub use event::BandwidthStatusMessage;
pub mod acquire;
pub mod error;
mod event;
mod utils;
#[derive(Debug)]
pub struct BandwidthController<C, St> {
storage: St,
client: C,
+25 -13
View File
@@ -8,33 +8,46 @@ license = { workspace = true }
repository = { workspace = true }
[dependencies]
const-str = { workspace = true }
clap = { workspace = true, features = ["derive"], optional = true }
clap_complete = { workspace = true, optional = true }
clap_complete_fig = { workspace = true, optional = true }
atty = "0.2"
const-str = "0.5.6"
clap = { workspace = true, features = ["derive"] }
clap_complete = "4.0"
clap_complete_fig = "4.0"
log = { workspace = true }
pretty_env_logger = { workspace = true }
pretty_env_logger = "0.4.0"
semver = "0.11"
schemars = { workspace = true, features = ["preserve_order"], optional = true }
serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true, optional = true }
## tracing
tracing-subscriber = { workspace = true, features = ["env-filter"], optional = true }
tracing-tree = { workspace = true, optional = true }
opentelemetry-jaeger = { workspace = true, features = ["rt-tokio", "collector_client", "isahc_collector_client"], optional = true }
tracing-opentelemetry = { workspace = true, optional = true }
tracing-subscriber = { version = "0.3.16", features = [
"env-filter",
], optional = true }
tracing-tree = { version = "0.2.2", optional = true }
opentelemetry-jaeger = { version = "0.18.0", optional = true, features = [
"rt-tokio",
"collector_client",
"isahc_collector_client",
] }
tracing-opentelemetry = { version = "0.19.0", optional = true }
utoipa = { workspace = true, optional = true }
opentelemetry = { workspace = true, features = ["rt-tokio"], optional = true }
opentelemetry = { version = "0.19.0", optional = true, features = ["rt-tokio"] }
[build-dependencies]
vergen = { workspace = true, features = ["build", "git", "gitcl", "rustc", "cargo"] }
vergen = { version = "=8.2.6", default-features = false, features = [
"build",
"git",
"gitcl",
"rustc",
"cargo",
] }
[features]
default = []
openapi = ["utoipa"]
output_format = ["serde_json", "dep:clap"]
output_format = ["serde_json"]
bin_info_schema = ["schemars"]
basic_tracing = ["tracing-subscriber"]
tracing = [
@@ -44,4 +57,3 @@ tracing = [
"tracing-opentelemetry",
"opentelemetry",
]
clap = [ "dep:clap", "dep:clap_complete", "dep:clap_complete_fig" ]
@@ -44,10 +44,6 @@ pub struct BinaryBuildInformation {
/// Provides the cargo debug mode that was used for the build.
// NOTE: keep the old name cargo_profile instead of cargo_debug for backwards compatibility
pub cargo_profile: &'static str,
// VERGEN_CARGO_TARGET_TRIPLE
/// Provides the cargo target triple that was used for the build.
pub cargo_triple: &'static str,
}
impl BinaryBuildInformation {
@@ -70,7 +66,6 @@ impl BinaryBuildInformation {
rustc_version: env!("VERGEN_RUSTC_SEMVER"),
rustc_channel: env!("VERGEN_RUSTC_CHANNEL"),
cargo_profile,
cargo_triple: env!("VERGEN_CARGO_TARGET_TRIPLE"),
}
}
@@ -100,7 +95,6 @@ impl BinaryBuildInformation {
rustc_version: env!("VERGEN_RUSTC_SEMVER"),
rustc_channel: env!("VERGEN_RUSTC_CHANNEL"),
cargo_profile,
cargo_triple: env!("VERGEN_CARGO_TARGET_TRIPLE"),
}
}
@@ -115,7 +109,6 @@ impl BinaryBuildInformation {
rustc_version: self.rustc_version.to_owned(),
rustc_channel: self.rustc_channel.to_owned(),
cargo_profile: self.cargo_profile.to_owned(),
cargo_triple: self.cargo_triple.to_owned(),
}
}
@@ -163,15 +156,6 @@ pub struct BinaryBuildInformationOwned {
/// Provides the cargo debug mode that was used for the build.
// NOTE: keep the old name cargo_profile instead of cargo_debug for backwards compatibility
pub cargo_profile: String,
// VERGEN_CARGO_TARGET_TRIPLE
/// Provides the cargo target triple that was used for the build.
#[serde(default = "unknown")]
pub cargo_triple: String,
}
fn unknown() -> String {
"unknown".to_string()
}
impl Display for BinaryBuildInformationOwned {
+1 -3
View File
@@ -2,11 +2,9 @@
// SPDX-License-Identifier: Apache-2.0
pub mod build_information;
pub mod completions;
pub mod logging;
pub mod version_checker;
#[cfg(feature = "clap")]
pub mod completions;
#[cfg(feature = "output_format")]
pub mod output_format;
+2 -3
View File
@@ -2,7 +2,6 @@
// SPDX-License-Identifier: Apache-2.0
use serde::{Deserialize, Serialize};
use std::io::IsTerminal;
#[cfg(feature = "tracing")]
pub use opentelemetry;
@@ -15,7 +14,7 @@ pub use tracing_subscriber;
#[cfg(feature = "tracing")]
pub use tracing_tree;
#[derive(Debug, Default, Copy, Clone, Deserialize, PartialEq, Eq, Serialize)]
#[derive(Debug, Default, Clone, Deserialize, PartialEq, Eq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct LoggingSettings {
// well, we need to implement something here at some point...
@@ -121,7 +120,7 @@ pub fn banner(crate_name: &str, crate_version: &str) -> String {
}
pub fn maybe_print_banner(crate_name: &str, crate_version: &str) {
if std::io::stdout().is_terminal() {
if atty::is(atty::Stream::Stdout) {
println!("{}", banner(crate_name, crate_version))
}
}
+12 -22
View File
@@ -3,28 +3,29 @@ name = "nym-client-core"
version = "1.1.15"
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
edition = "2021"
rust-version = "1.70"
rust-version = "1.66"
license.workspace = true
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
async-trait = { workspace = true }
base64 = { workspace = true }
base64 = "0.21.2"
bs58 = { workspace = true }
cfg-if = { workspace = true }
cfg-if = "1.0.0"
clap = { workspace = true, optional = true }
futures = { workspace = true }
humantime-serde = { workspace = true }
humantime-serde = "1.0"
log = { workspace = true }
rand = { workspace = true }
rand = { version = "0.7.3", features = ["wasm-bindgen"] }
serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true }
sha2 = { workspace = true }
si-scale = { workspace = true }
tap = { workspace = true }
sha2 = "0.10.6"
si-scale = "0.2.2"
tap = "1.0.1"
thiserror = { workspace = true }
url = { workspace = true, features = ["serde"] }
tungstenite = { workspace = true, default-features = false }
tokio = { workspace = true, features = ["macros"] }
time = { workspace = true }
zeroize = { workspace = true }
@@ -33,7 +34,6 @@ zeroize = { workspace = true }
nym-id = { path = "../nym-id" }
nym-bandwidth-controller = { path = "../bandwidth-controller" }
nym-config = { path = "../config" }
nym-country-group = { path = "../country-group" }
nym-crypto = { path = "../crypto" }
nym-explorer-client = { path = "../../explorer-api/explorer-client" }
nym-gateway-client = { path = "../client-libs/gateway-client" }
@@ -47,7 +47,6 @@ nym-validator-client = { path = "../client-libs/validator-client", default-featu
nym-task = { path = "../task" }
nym-credential-storage = { path = "../credential-storage" }
nym-network-defaults = { path = "../network-defaults" }
nym-client-core-config-types = { path = "./config-types", features = ["disk-persistence"] }
nym-client-core-surb-storage = { path = "./surb-storage" }
nym-client-core-gateways-storage = { path = "./gateways-storage" }
@@ -73,17 +72,8 @@ workspace = true
features = ["time"]
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.tokio-tungstenite]
workspace = true
features = ["rustls-tls-webpki-roots"]
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.tungstenite]
workspace = true
default-features = true
features = ["rustls-tls-webpki-roots"]
[target."cfg(target_arch = \"wasm32\")".dependencies.tungstenite]
workspace = true
default-features = false
version = "0.20.1"
features = ["rustls-tls-native-roots"]
[target."cfg(target_arch = \"wasm32\")".dependencies.wasm-bindgen-futures]
workspace = true
@@ -108,7 +98,7 @@ version = "0.3.17"
features = ["wasm-bindgen"]
[dev-dependencies]
tempfile = { workspace = true }
tempfile = "3.1.0"
[features]
default = []
@@ -1,26 +0,0 @@
[package]
name = "nym-client-core-config-types"
version = "0.1.0"
edition = "2021"
license.workspace = true
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
humantime-serde = { workspace = true }
serde = { workspace = true, features = ["derive"] }
thiserror.workspace = true
url = { workspace = true, features = ["serde"] }
nym-config = { path = "../../config" }
nym-country-group = { path = "../../country-group" }
nym-pemstore = { path = "../../pemstore", optional = true }
# those are pulling so many deps T.T
nym-sphinx-params = { path = "../../nymsphinx/params" }
nym-sphinx-addressing = { path = "../../nymsphinx/addressing" }
[features]
disk-persistence = ["nym-pemstore"]
@@ -1,9 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
pub mod v1;
pub mod v2;
// aliases for backwards compatibility
pub use v1 as old_v1_1_20_2;
pub use v2 as old_v1_1_33;
@@ -1,37 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::disk_persistence::old::v2::{
ClientKeysPathsV2, CommonClientPathsV2, DEFAULT_GATEWAY_DETAILS_FILENAME,
};
use crate::error::ConfigUpgradeFailure;
use serde::{Deserialize, Serialize};
use std::path::PathBuf;
// aliases for backwards compatibility
pub type CommonClientPathsV1_1_20_2 = CommonClientPathsV1;
#[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct CommonClientPathsV1 {
pub keys: ClientKeysPathsV2,
pub credentials_database: PathBuf,
pub reply_surb_database: PathBuf,
}
impl CommonClientPathsV1 {
pub fn upgrade_default(self) -> Result<CommonClientPathsV2, ConfigUpgradeFailure> {
let data_dir = self
.reply_surb_database
.parent()
.ok_or_else(|| ConfigUpgradeFailure {
current_version: "1.1.20-2".to_string(),
})?;
Ok(CommonClientPathsV2 {
keys: self.keys,
gateway_details: data_dir.join(DEFAULT_GATEWAY_DETAILS_FILENAME),
credentials_database: self.credentials_database,
reply_surb_database: self.reply_surb_database,
})
}
}
@@ -1,19 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use thiserror::Error;
#[derive(Debug, Error)]
#[error("unable to upgrade config file from `{current_version}`")]
pub struct ConfigUpgradeFailure {
pub current_version: String,
}
#[derive(Error, Debug)]
pub enum InvalidTrafficModeFailure {
#[error("attempted to set medium toggle traffic mode with fast mode flag")]
MediumToggleWithFastMode,
#[error("attempted to set medium toggle traffic mode with no cover flag")]
MediumToggleWithNoCover,
}
-677
View File
@@ -1,677 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use nym_config::defaults::NymNetworkDetails;
use nym_sphinx_addressing::Recipient;
use nym_sphinx_params::{PacketSize, PacketType};
use serde::{Deserialize, Serialize};
use std::time::Duration;
use url::Url;
#[cfg(feature = "disk-persistence")]
pub mod disk_persistence;
pub mod error;
pub mod old;
pub use error::ConfigUpgradeFailure;
// 'DEBUG'
const DEFAULT_ACK_WAIT_MULTIPLIER: f64 = 1.5;
const DEFAULT_ACK_WAIT_ADDITION: Duration = Duration::from_millis(1_500);
const DEFAULT_LOOP_COVER_STREAM_AVERAGE_DELAY: Duration = Duration::from_millis(200);
const DEFAULT_MESSAGE_STREAM_AVERAGE_DELAY: Duration = Duration::from_millis(20);
const DEFAULT_AVERAGE_PACKET_DELAY: Duration = Duration::from_millis(50);
const DEFAULT_TOPOLOGY_REFRESH_RATE: Duration = Duration::from_secs(5 * 60); // every 5min
const DEFAULT_TOPOLOGY_RESOLUTION_TIMEOUT: Duration = Duration::from_millis(5_000);
// the same values as our current (10.06.24) blacklist
const DEFAULT_MIN_MIXNODE_PERFORMANCE: u8 = 50;
const DEFAULT_MIN_GATEWAY_PERFORMANCE: u8 = 50;
const DEFAULT_MAX_STARTUP_GATEWAY_WAITING_PERIOD: Duration = Duration::from_secs(70 * 60); // 70min -> full epoch (1h) + a bit of overhead
// Set this to a high value for now, so that we don't risk sporadic timeouts that might cause
// bought bandwidth tokens to not have time to be spent; Once we remove the gateway from the
// bandwidth bridging protocol, we can come back to a smaller timeout value
const DEFAULT_GATEWAY_RESPONSE_TIMEOUT: Duration = Duration::from_secs(5 * 60);
const DEFAULT_COVER_TRAFFIC_PRIMARY_SIZE_RATIO: f64 = 0.70;
// reply-surbs related:
// define when to request
// clients/client-core/src/client/replies/reply_storage/surb_storage.rs
const DEFAULT_MINIMUM_REPLY_SURB_STORAGE_THRESHOLD: usize = 10;
const DEFAULT_MAXIMUM_REPLY_SURB_STORAGE_THRESHOLD: usize = 200;
// define how much to request at once
// clients/client-core/src/client/replies/reply_controller.rs
const DEFAULT_MINIMUM_REPLY_SURB_REQUEST_SIZE: u32 = 10;
const DEFAULT_MAXIMUM_REPLY_SURB_REQUEST_SIZE: u32 = 100;
const DEFAULT_MAXIMUM_ALLOWED_SURB_REQUEST_SIZE: u32 = 500;
const DEFAULT_MAXIMUM_REPLY_SURB_REREQUEST_WAITING_PERIOD: Duration = Duration::from_secs(10);
const DEFAULT_MAXIMUM_REPLY_SURB_DROP_WAITING_PERIOD: Duration = Duration::from_secs(5 * 60);
// 12 hours
const DEFAULT_MAXIMUM_REPLY_SURB_AGE: Duration = Duration::from_secs(12 * 60 * 60);
// 24 hours
const DEFAULT_MAXIMUM_REPLY_KEY_AGE: Duration = Duration::from_secs(24 * 60 * 60);
use crate::error::InvalidTrafficModeFailure;
pub use nym_country_group::CountryGroup;
#[derive(Debug, Clone, Deserialize, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct Config {
pub client: Client,
#[serde(default)]
pub debug: DebugConfig,
}
impl Config {
pub fn new<S1, S2>(id: S1, version: S2) -> Self
where
S1: Into<String>,
S2: Into<String>,
{
Config {
client: Client::new_default(id, version),
debug: Default::default(),
}
}
pub fn from_client_config(client: Client, debug: DebugConfig) -> Self {
Config { client, debug }
}
pub fn validate(&self) -> bool {
self.debug.validate()
}
pub fn with_debug_config(mut self, debug: DebugConfig) -> Self {
self.debug = debug;
self
}
pub fn with_disabled_credentials(mut self, disabled_credentials_mode: bool) -> Self {
self.client.disabled_credentials_mode = disabled_credentials_mode;
self
}
pub fn with_custom_nyxd(mut self, urls: Vec<Url>) -> Self {
self.client.nyxd_urls = urls;
self
}
pub fn set_custom_nyxd(&mut self, nyxd_urls: Vec<Url>) {
self.client.nyxd_urls = nyxd_urls;
}
pub fn with_custom_nym_apis(mut self, nym_api_urls: Vec<Url>) -> Self {
self.client.nym_api_urls = nym_api_urls;
self
}
pub fn set_custom_nym_apis(&mut self, nym_api_urls: Vec<Url>) {
self.client.nym_api_urls = nym_api_urls;
}
pub fn with_high_default_traffic_volume(mut self, enabled: bool) -> Self {
if enabled {
self.set_high_default_traffic_volume();
}
self
}
pub fn with_packet_type(mut self, packet_type: PacketType) -> Self {
self.debug.traffic.packet_type = packet_type;
self
}
// TODO: this should be refactored properly
// as of 12.09.23 the below is true (not sure how this comment will rot in the future)
// medium_toggle:
// - sets secondary packet size to 16kb
// - disables poisson distribution of the main traffic stream
// - sets the cover traffic stream to 1 packet / 5s (on average)
// - disables per hop delay
//
// fastmode (to be renamed to `fast-poisson`):
// - sets average per hop delay to 10ms
// - sets the cover traffic stream to 1 packet / 2000s (on average); for all intents and purposes it disables the stream
// - sets the poisson distribution of the main traffic stream to 4ms, i.e. 250 packets / s on average
//
// no_cover:
// - disables poisson distribution of the main traffic stream
// - disables the secondary cover traffic stream
#[doc(hidden)]
pub fn try_apply_traffic_modes(
&mut self,
disable_poisson_process: bool,
medium_toggle: bool,
fast_mode: bool,
no_cover: bool,
) -> Result<(), InvalidTrafficModeFailure> {
if disable_poisson_process {
self.set_no_poisson_process()
}
if medium_toggle {
if fast_mode {
return Err(InvalidTrafficModeFailure::MediumToggleWithFastMode);
}
if no_cover {
return Err(InvalidTrafficModeFailure::MediumToggleWithNoCover);
}
self.set_experimental_medium_toggle();
}
if fast_mode {
self.set_high_default_traffic_volume()
}
if no_cover {
self.set_no_cover_traffic();
}
Ok(())
}
pub fn set_high_default_traffic_volume(&mut self) {
self.debug.traffic.average_packet_delay = Duration::from_millis(10);
// basically don't really send cover messages
self.debug.cover_traffic.loop_cover_traffic_average_delay =
Duration::from_millis(2_000_000);
// 250 "real" messages / s
self.debug.traffic.message_sending_average_delay = Duration::from_millis(4);
}
/// Enable medium mixnet traffic, for experiments only.
/// This includes things like disabling cover traffic, no per hop delays, etc.
#[doc(hidden)]
pub fn set_experimental_medium_toggle(&mut self) {
self.set_no_cover_traffic_with_keepalive();
self.set_no_per_hop_delays();
self.debug.traffic.secondary_packet_size = Some(PacketSize::ExtendedPacket16);
}
pub fn with_disabled_poisson_process(mut self, disabled: bool) -> Self {
if disabled {
self.set_no_poisson_process()
}
self
}
pub fn set_no_poisson_process(&mut self) {
self.debug.traffic.disable_main_poisson_packet_distribution = true;
}
pub fn with_disabled_cover_traffic(mut self, disabled: bool) -> Self {
if disabled {
self.set_no_cover_traffic()
}
self
}
pub fn set_no_cover_traffic(&mut self) {
self.debug.cover_traffic.disable_loop_cover_traffic_stream = true;
self.debug.traffic.disable_main_poisson_packet_distribution = true;
}
pub fn with_disabled_cover_traffic_with_keepalive(mut self, disabled: bool) -> Self {
if disabled {
self.set_no_cover_traffic_with_keepalive()
}
self
}
pub fn set_no_cover_traffic_with_keepalive(&mut self) {
self.debug.traffic.disable_main_poisson_packet_distribution = true;
self.debug.cover_traffic.loop_cover_traffic_average_delay = Duration::from_secs(5);
}
pub fn with_disabled_topology_refresh(mut self, disable_topology_refresh: bool) -> Self {
self.debug.topology.disable_refreshing = disable_topology_refresh;
self
}
pub fn with_topology_structure(mut self, topology_structure: TopologyStructure) -> Self {
self.set_topology_structure(topology_structure);
self
}
pub fn set_topology_structure(&mut self, topology_structure: TopologyStructure) {
self.debug.topology.topology_structure = topology_structure;
}
pub fn with_no_per_hop_delays(mut self, no_per_hop_delays: bool) -> Self {
if no_per_hop_delays {
self.set_no_per_hop_delays()
}
self
}
pub fn set_no_per_hop_delays(&mut self) {
self.debug.traffic.average_packet_delay = Duration::ZERO;
self.debug.acknowledgements.average_ack_delay = Duration::ZERO;
}
pub fn with_secondary_packet_size(mut self, secondary_packet_size: Option<PacketSize>) -> Self {
self.set_secondary_packet_size(secondary_packet_size);
self
}
pub fn set_secondary_packet_size(&mut self, secondary_packet_size: Option<PacketSize>) {
self.debug.traffic.secondary_packet_size = secondary_packet_size;
}
pub fn set_custom_version(&mut self, version: &str) {
self.client.version = version.to_string();
}
pub fn get_id(&self) -> String {
self.client.id.clone()
}
pub fn get_disabled_credentials_mode(&self) -> bool {
self.client.disabled_credentials_mode
}
pub fn get_validator_endpoints(&self) -> Vec<Url> {
self.client.nyxd_urls.clone()
}
pub fn get_nym_api_endpoints(&self) -> Vec<Url> {
self.client.nym_api_urls.clone()
}
}
#[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)]
// note: the deny_unknown_fields is VITAL here to allow upgrades from v1.1.20_2
#[serde(deny_unknown_fields)]
pub struct Client {
/// Version of the client for which this configuration was created.
pub version: String,
/// ID specifies the human readable ID of this particular client.
pub id: String,
/// Indicates whether this client is running in a disabled credentials mode, thus attempting
/// to claim bandwidth without presenting bandwidth credentials.
// TODO: this should be moved to `debug.gateway_connection`
#[serde(default)]
pub disabled_credentials_mode: bool,
/// Addresses to nyxd validators via which the client can communicate with the chain.
#[serde(alias = "validator_urls")]
pub nyxd_urls: Vec<Url>,
/// Addresses to APIs running on validator from which the client gets the view of the network.
#[serde(alias = "validator_api_urls")]
pub nym_api_urls: Vec<Url>,
}
impl Client {
pub fn new_default<S1, S2>(id: S1, version: S2) -> Self
where
S1: Into<String>,
S2: Into<String>,
{
let network = NymNetworkDetails::new_mainnet();
let nyxd_urls = network
.endpoints
.iter()
.map(|validator| validator.nyxd_url())
.collect();
let nym_api_urls = network
.endpoints
.iter()
.filter_map(|validator| validator.api_url())
.collect::<Vec<_>>();
Client {
version: version.into(),
id: id.into(),
disabled_credentials_mode: true,
nyxd_urls,
nym_api_urls,
}
}
pub fn new<S: Into<String>>(
id: S,
version: S,
disabled_credentials_mode: bool,
nyxd_urls: Vec<Url>,
nym_api_urls: Vec<Url>,
) -> Self {
Client {
version: version.into(),
id: id.into(),
disabled_credentials_mode,
nyxd_urls,
nym_api_urls,
}
}
}
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
#[serde(default, deny_unknown_fields)]
pub struct Traffic {
/// The parameter of Poisson distribution determining how long, on average,
/// sent packet is going to be delayed at any given mix node.
/// So for a packet going through three mix nodes, on average, it will take three times this value
/// until the packet reaches its destination.
#[serde(with = "humantime_serde")]
pub average_packet_delay: Duration,
/// The parameter of Poisson distribution determining how long, on average,
/// it is going to take another 'real traffic stream' message to be sent.
/// If no real packets are available and cover traffic is enabled,
/// a loop cover message is sent instead in order to preserve the rate.
#[serde(with = "humantime_serde")]
pub message_sending_average_delay: Duration,
/// Controls whether the main packet stream constantly produces packets according to the predefined
/// poisson distribution.
pub disable_main_poisson_packet_distribution: bool,
/// Specifies the packet size used for sent messages.
/// Do not override it unless you understand the consequences of that change.
pub primary_packet_size: PacketSize,
/// Specifies the optional auxiliary packet size for optimizing message streams.
/// Note that its use decreases overall anonymity.
/// Do not set it it unless you understand the consequences of that change.
pub secondary_packet_size: Option<PacketSize>,
pub packet_type: PacketType,
}
impl Traffic {
pub fn validate(&self) -> bool {
if let Some(secondary_packet_size) = self.secondary_packet_size {
if secondary_packet_size == PacketSize::AckPacket
|| secondary_packet_size == self.primary_packet_size
{
return false;
}
}
true
}
}
impl Default for Traffic {
fn default() -> Self {
Traffic {
average_packet_delay: DEFAULT_AVERAGE_PACKET_DELAY,
message_sending_average_delay: DEFAULT_MESSAGE_STREAM_AVERAGE_DELAY,
disable_main_poisson_packet_distribution: false,
primary_packet_size: PacketSize::RegularPacket,
secondary_packet_size: None,
packet_type: PacketType::Mix,
}
}
}
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
#[serde(default, deny_unknown_fields)]
pub struct CoverTraffic {
/// The parameter of Poisson distribution determining how long, on average,
/// it is going to take for another loop cover traffic message to be sent.
#[serde(with = "humantime_serde")]
pub loop_cover_traffic_average_delay: Duration,
/// Specifies the ratio of `primary_packet_size` to `secondary_packet_size` used in cover traffic.
/// Only applicable if `secondary_packet_size` is enabled.
pub cover_traffic_primary_size_ratio: f64,
/// Controls whether the dedicated loop cover traffic stream should be enabled.
/// (and sending packets, on average, every [Self::loop_cover_traffic_average_delay])
pub disable_loop_cover_traffic_stream: bool,
}
impl Default for CoverTraffic {
fn default() -> Self {
CoverTraffic {
loop_cover_traffic_average_delay: DEFAULT_LOOP_COVER_STREAM_AVERAGE_DELAY,
cover_traffic_primary_size_ratio: DEFAULT_COVER_TRAFFIC_PRIMARY_SIZE_RATIO,
disable_loop_cover_traffic_stream: false,
}
}
}
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
#[serde(default, deny_unknown_fields)]
pub struct GatewayConnection {
/// How long we're willing to wait for a response to a message sent to the gateway,
/// before giving up on it.
#[serde(with = "humantime_serde")]
pub gateway_response_timeout: Duration,
}
impl Default for GatewayConnection {
fn default() -> Self {
GatewayConnection {
gateway_response_timeout: DEFAULT_GATEWAY_RESPONSE_TIMEOUT,
}
}
}
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
#[serde(default, deny_unknown_fields)]
pub struct Acknowledgements {
/// The parameter of Poisson distribution determining how long, on average,
/// sent acknowledgement is going to be delayed at any given mix node.
/// So for an ack going through three mix nodes, on average, it will take three times this value
/// until the packet reaches its destination.
#[serde(with = "humantime_serde")]
pub average_ack_delay: Duration,
/// Value multiplied with the expected round trip time of an acknowledgement packet before
/// it is assumed it was lost and retransmission of the data packet happens.
/// In an ideal network with 0 latency, this value would have been 1.
pub ack_wait_multiplier: f64,
/// Value added to the expected round trip time of an acknowledgement packet before
/// it is assumed it was lost and retransmission of the data packet happens.
/// In an ideal network with 0 latency, this value would have been 0.
#[serde(with = "humantime_serde")]
pub ack_wait_addition: Duration,
}
impl Default for Acknowledgements {
fn default() -> Self {
Acknowledgements {
average_ack_delay: DEFAULT_AVERAGE_PACKET_DELAY,
ack_wait_multiplier: DEFAULT_ACK_WAIT_MULTIPLIER,
ack_wait_addition: DEFAULT_ACK_WAIT_ADDITION,
}
}
}
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
#[serde(default, deny_unknown_fields)]
pub struct Topology {
/// The uniform delay every which clients are querying the directory server
/// to try to obtain a compatible network topology to send sphinx packets through.
#[serde(with = "humantime_serde")]
pub topology_refresh_rate: Duration,
/// During topology refresh, test packets are sent through every single possible network
/// path. This timeout determines waiting period until it is decided that the packet
/// did not reach its destination.
#[serde(with = "humantime_serde")]
pub topology_resolution_timeout: Duration,
/// Specifies whether the client should not refresh the network topology after obtaining
/// the first valid instance.
/// Supersedes `topology_refresh_rate_ms`.
pub disable_refreshing: bool,
/// Defines how long the client is going to wait on startup for its gateway to come online,
/// before abandoning the procedure.
#[serde(with = "humantime_serde")]
pub max_startup_gateway_waiting_period: Duration,
/// Specifies the mixnode topology to be used for sending packets.
pub topology_structure: TopologyStructure,
/// Specifies a minimum performance of a mixnode that is used on route construction.
/// This setting is only applicable when `NymApi` topology is used.
pub minimum_mixnode_performance: u8,
/// Specifies a minimum performance of a gateway that is used on route construction.
/// This setting is only applicable when `NymApi` topology is used.
pub minimum_gateway_performance: u8,
}
#[allow(clippy::large_enum_variant)]
#[derive(Default, Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum TopologyStructure {
#[default]
NymApi,
GeoAware(GroupBy),
}
#[allow(clippy::large_enum_variant)]
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum GroupBy {
CountryGroup(CountryGroup),
NymAddress(Recipient),
}
impl std::fmt::Display for GroupBy {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
GroupBy::CountryGroup(group) => write!(f, "group: {group}"),
GroupBy::NymAddress(address) => write!(f, "address: {address}"),
}
}
}
impl Default for Topology {
fn default() -> Self {
Topology {
topology_refresh_rate: DEFAULT_TOPOLOGY_REFRESH_RATE,
topology_resolution_timeout: DEFAULT_TOPOLOGY_RESOLUTION_TIMEOUT,
disable_refreshing: false,
max_startup_gateway_waiting_period: DEFAULT_MAX_STARTUP_GATEWAY_WAITING_PERIOD,
topology_structure: TopologyStructure::default(),
minimum_mixnode_performance: DEFAULT_MIN_MIXNODE_PERFORMANCE,
minimum_gateway_performance: DEFAULT_MIN_GATEWAY_PERFORMANCE,
}
}
}
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
#[serde(default, deny_unknown_fields)]
pub struct ReplySurbs {
/// Defines the minimum number of reply surbs the client wants to keep in its storage at all times.
/// It can only allow to go below that value if its to request additional reply surbs.
pub minimum_reply_surb_storage_threshold: usize,
/// Defines the maximum number of reply surbs the client wants to keep in its storage at any times.
pub maximum_reply_surb_storage_threshold: usize,
/// Defines the minimum number of reply surbs the client would request.
pub minimum_reply_surb_request_size: u32,
/// Defines the maximum number of reply surbs the client would request.
pub maximum_reply_surb_request_size: u32,
/// Defines the maximum number of reply surbs a remote party is allowed to request from this client at once.
pub maximum_allowed_reply_surb_request_size: u32,
/// Defines maximum amount of time the client is going to wait for reply surbs before explicitly asking
/// for more even though in theory they wouldn't need to.
#[serde(with = "humantime_serde")]
pub maximum_reply_surb_rerequest_waiting_period: Duration,
/// Defines maximum amount of time the client is going to wait for reply surbs before
/// deciding it's never going to get them and would drop all pending messages
#[serde(with = "humantime_serde")]
pub maximum_reply_surb_drop_waiting_period: Duration,
/// Defines maximum amount of time given reply surb is going to be valid for.
/// This is going to be superseded by key rotation once implemented.
#[serde(with = "humantime_serde")]
pub maximum_reply_surb_age: Duration,
/// Defines maximum amount of time given reply key is going to be valid for.
/// This is going to be superseded by key rotation once implemented.
#[serde(with = "humantime_serde")]
pub maximum_reply_key_age: Duration,
/// Specifies the number of mixnet hops the packet should go through. If not specified, then
/// the default value is used.
pub surb_mix_hops: Option<u8>,
}
impl Default for ReplySurbs {
fn default() -> Self {
ReplySurbs {
minimum_reply_surb_storage_threshold: DEFAULT_MINIMUM_REPLY_SURB_STORAGE_THRESHOLD,
maximum_reply_surb_storage_threshold: DEFAULT_MAXIMUM_REPLY_SURB_STORAGE_THRESHOLD,
minimum_reply_surb_request_size: DEFAULT_MINIMUM_REPLY_SURB_REQUEST_SIZE,
maximum_reply_surb_request_size: DEFAULT_MAXIMUM_REPLY_SURB_REQUEST_SIZE,
maximum_allowed_reply_surb_request_size: DEFAULT_MAXIMUM_ALLOWED_SURB_REQUEST_SIZE,
maximum_reply_surb_rerequest_waiting_period:
DEFAULT_MAXIMUM_REPLY_SURB_REREQUEST_WAITING_PERIOD,
maximum_reply_surb_drop_waiting_period: DEFAULT_MAXIMUM_REPLY_SURB_DROP_WAITING_PERIOD,
maximum_reply_surb_age: DEFAULT_MAXIMUM_REPLY_SURB_AGE,
maximum_reply_key_age: DEFAULT_MAXIMUM_REPLY_KEY_AGE,
surb_mix_hops: None,
}
}
}
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
#[serde(default, deny_unknown_fields)]
pub struct DebugConfig {
/// Defines all configuration options related to traffic streams.
pub traffic: Traffic,
/// Defines all configuration options related to cover traffic stream(s).
pub cover_traffic: CoverTraffic,
/// Defines all configuration options related to the gateway connection.
pub gateway_connection: GatewayConnection,
/// Defines all configuration options related to acknowledgements, such as delays or wait timeouts.
pub acknowledgements: Acknowledgements,
/// Defines all configuration options related topology, such as refresh rates or timeouts.
pub topology: Topology,
/// Defines all configuration options related to reply SURBs.
pub reply_surbs: ReplySurbs,
}
impl DebugConfig {
pub fn validate(&self) -> bool {
// no other sections have explicit requirements (yet)
self.traffic.validate()
}
}
// it could be derived, sure, but I'd rather have an explicit implementation in case we had to change
// something manually at some point
#[allow(clippy::derivable_impls)]
impl Default for DebugConfig {
fn default() -> Self {
DebugConfig {
traffic: Default::default(),
cover_traffic: Default::default(),
gateway_connection: Default::default(),
acknowledgements: Default::default(),
topology: Default::default(),
reply_surbs: Default::default(),
}
}
}
@@ -1,15 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
pub mod v1;
pub mod v2;
pub mod v3;
pub mod v4;
pub mod v5;
// aliases for backwards compatibility
pub use v1 as old_config_v1_1_13;
pub use v2 as old_config_v1_1_20;
pub use v3 as old_config_v1_1_20_2;
pub use v4 as old_config_v1_1_30;
pub use v5 as old_config_v1_1_33;
@@ -1,18 +0,0 @@
/*
* Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
* SPDX-License-Identifier: Apache-2.0
*/
CREATE TABLE remote_gateway_details_temp
(
gateway_id_bs58 TEXT NOT NULL UNIQUE PRIMARY KEY REFERENCES registered_gateway (gateway_id_bs58),
derived_aes128_ctr_blake3_hmac_keys_bs58 TEXT NOT NULL,
gateway_owner_address TEXT,
gateway_listener TEXT NOT NULL,
wg_tun_address TEXT
);
INSERT INTO remote_gateway_details_temp SELECT * FROM remote_gateway_details;
DROP TABLE remote_gateway_details;
ALTER TABLE remote_gateway_details_temp RENAME TO remote_gateway_details;
@@ -27,12 +27,6 @@ pub struct GatewayRegistration {
pub registration_timestamp: OffsetDateTime,
}
impl GatewayRegistration {
pub fn gateway_id(&self) -> identity::PublicKey {
self.details.gateway_id()
}
}
impl<'a> From<&'a GatewayRegistration> for RawRegisteredGateway {
fn from(value: &'a GatewayRegistration) -> Self {
RawRegisteredGateway {
@@ -65,7 +59,7 @@ impl GatewayDetails {
pub fn new_remote(
gateway_id: identity::PublicKey,
derived_aes128_ctr_blake3_hmac_keys: Arc<SharedKeys>,
gateway_owner_address: Option<AccountId>,
gateway_owner_address: AccountId,
gateway_listener: Url,
wg_tun_address: Option<Url>,
) -> Self {
@@ -170,7 +164,7 @@ pub struct RegisteredGateway {
pub struct RawRemoteGatewayDetails {
pub gateway_id_bs58: String,
pub derived_aes128_ctr_blake3_hmac_keys_bs58: String,
pub gateway_owner_address: Option<String>,
pub gateway_owner_address: String,
pub gateway_listener: String,
pub wg_tun_address: Option<String>,
}
@@ -195,19 +189,14 @@ impl TryFrom<RawRemoteGatewayDetails> for RemoteGatewayDetails {
})?,
);
let gateway_owner_address = value
.gateway_owner_address
.as_ref()
.map(|raw_owner| {
AccountId::from_str(raw_owner).map_err(|source| {
BadGateway::MalformedGatewayOwnerAccountAddress {
gateway_id: value.gateway_id_bs58.clone(),
raw_owner: raw_owner.clone(),
source,
}
})
})
.transpose()?;
let gateway_owner_address =
AccountId::from_str(&value.gateway_owner_address).map_err(|source| {
BadGateway::MalformedGatewayOwnerAccountAddress {
gateway_id: value.gateway_id_bs58.clone(),
raw_owner: value.gateway_owner_address.clone(),
source,
}
})?;
let gateway_listener = Url::parse(&value.gateway_listener).map_err(|source| {
BadGateway::MalformedListener {
@@ -246,7 +235,7 @@ impl<'a> From<&'a RemoteGatewayDetails> for RawRemoteGatewayDetails {
derived_aes128_ctr_blake3_hmac_keys_bs58: value
.derived_aes128_ctr_blake3_hmac_keys
.to_base58_string(),
gateway_owner_address: value.gateway_owner_address.as_ref().map(|o| o.to_string()),
gateway_owner_address: value.gateway_owner_address.to_string(),
gateway_listener: value.gateway_listener.to_string(),
wg_tun_address: value.wg_tun_address.as_ref().map(|addr| addr.to_string()),
}
@@ -261,7 +250,7 @@ pub struct RemoteGatewayDetails {
// the keys will be zeroized
pub derived_aes128_ctr_blake3_hmac_keys: Arc<SharedKeys>,
pub gateway_owner_address: Option<AccountId>,
pub gateway_owner_address: AccountId,
pub gateway_listener: Url,
@@ -309,12 +298,3 @@ pub struct CustomGatewayDetails {
pub gateway_id: identity::PublicKey,
pub data: Option<Vec<u8>>,
}
impl CustomGatewayDetails {
pub fn new(gateway_id: identity::PublicKey) -> CustomGatewayDetails {
Self {
gateway_id,
data: None,
}
}
}
@@ -16,7 +16,6 @@ use log::info;
use nym_client_core_gateways_storage::GatewayDetails;
use nym_crypto::asymmetric::identity;
use nym_topology::NymTopology;
use nym_validator_client::UserAgent;
use std::path::PathBuf;
#[cfg_attr(feature = "cli", derive(clap::Args))]
@@ -61,10 +60,7 @@ pub struct CommonClientAddGatewayArgs {
pub custom_mixnet: Option<PathBuf>,
}
pub async fn add_gateway<C, A>(
args: A,
user_agent: Option<UserAgent>,
) -> Result<GatewayInfo, C::Error>
pub async fn add_gateway<C, A>(args: A) -> Result<GatewayInfo, C::Error>
where
A: AsRef<CommonClientAddGatewayArgs>,
C: CliClient,
@@ -115,8 +111,7 @@ where
hardcoded_topology.get_gateways()
} else {
let mut rng = rand::thread_rng();
crate::init::helpers::current_gateways(&mut rng, &core.client.nym_api_urls, user_agent)
.await?
crate::init::helpers::current_gateways(&mut rng, &core.client.nym_api_urls).await?
};
// since we're registering with a brand new gateway,
@@ -16,7 +16,6 @@ use log::info;
use nym_client_core_gateways_storage::GatewayDetails;
use nym_crypto::asymmetric::identity;
use nym_topology::NymTopology;
use nym_validator_client::UserAgent;
use rand::rngs::OsRng;
use std::path::PathBuf;
@@ -97,7 +96,6 @@ pub struct InitResultsWithConfig<T> {
pub async fn initialise_client<C>(
init_args: C::InitArgs,
user_agent: Option<UserAgent>,
) -> Result<InitResultsWithConfig<C::Config>, C::Error>
where
C: InitialisableClient,
@@ -165,8 +163,7 @@ where
hardcoded_topology.get_gateways()
} else {
let mut rng = rand::thread_rng();
crate::init::helpers::current_gateways(&mut rng, &core.client.nym_api_urls, user_agent)
.await?
crate::init::helpers::current_gateways(&mut rng, &core.client.nym_api_urls).await?
};
let gateway_setup = GatewaySetup::New {
@@ -25,7 +25,7 @@ use crate::client::replies::reply_storage::{
};
use crate::client::topology_control::nym_api_provider::NymApiTopologyProvider;
use crate::client::topology_control::{
nym_api_provider, TopologyAccessor, TopologyRefresher, TopologyRefresherConfig,
TopologyAccessor, TopologyRefresher, TopologyRefresherConfig,
};
use crate::config::{Config, DebugConfig};
use crate::error::ClientCoreError;
@@ -39,7 +39,7 @@ use log::{debug, error, info, warn};
use nym_bandwidth_controller::BandwidthController;
use nym_client_core_gateways_storage::{GatewayDetails, GatewaysDetailsStore};
use nym_credential_storage::storage::Storage as CredentialStorage;
use nym_crypto::asymmetric::{encryption, identity};
use nym_crypto::asymmetric::encryption;
use nym_gateway_client::{
AcknowledgementReceiver, GatewayClient, GatewayConfig, MixnetMessageReceiver, PacketRouter,
};
@@ -53,7 +53,7 @@ use nym_task::connections::{ConnectionCommandReceiver, ConnectionCommandSender,
use nym_task::{TaskClient, TaskHandle};
use nym_topology::provider_trait::TopologyProvider;
use nym_topology::HardcodedTopologyProvider;
use nym_validator_client::{nyxd::contract_traits::DkgQueryClient, UserAgent};
use nym_validator_client::nyxd::contract_traits::DkgQueryClient;
use rand::rngs::OsRng;
use std::fmt::Debug;
use std::os::raw::c_int as RawFd;
@@ -184,7 +184,6 @@ pub struct BaseClientBuilder<'a, C, S: MixnetClientStorage> {
custom_topology_provider: Option<Box<dyn TopologyProvider + Send + Sync>>,
custom_gateway_transceiver: Option<Box<dyn GatewayTransceiver + Send>>,
shutdown: Option<TaskClient>,
user_agent: Option<UserAgent>,
setup_method: GatewaySetup,
}
@@ -208,7 +207,6 @@ where
custom_topology_provider: None,
custom_gateway_transceiver: None,
shutdown: None,
user_agent: None,
setup_method: GatewaySetup::MustLoad { gateway_id: None },
}
}
@@ -252,12 +250,6 @@ where
self
}
#[must_use]
pub fn with_user_agent(mut self, user_agent: UserAgent) -> Self {
self.user_agent = Some(user_agent);
self
}
pub fn with_stored_topology<P: AsRef<Path>>(
mut self,
file: P,
@@ -396,10 +388,7 @@ where
let cfg = GatewayConfig::new(
details.gateway_id,
details
.gateway_owner_address
.as_ref()
.map(|o| o.to_string()),
Some(details.gateway_owner_address.to_string()),
gateway_listener,
);
GatewayClient::new(
@@ -473,20 +462,14 @@ where
fn setup_topology_provider(
custom_provider: Option<Box<dyn TopologyProvider + Send + Sync>>,
config_topology: config::Topology,
provider_from_config: config::TopologyStructure,
nym_api_urls: Vec<Url>,
user_agent: Option<UserAgent>,
) -> Box<dyn TopologyProvider + Send + Sync> {
// if no custom provider was ... provided ..., create one using nym-api
custom_provider.unwrap_or_else(|| match config_topology.topology_structure {
custom_provider.unwrap_or_else(|| match provider_from_config {
config::TopologyStructure::NymApi => Box::new(NymApiTopologyProvider::new(
nym_api_provider::Config {
min_mixnode_performance: config_topology.minimum_mixnode_performance,
min_gateway_performance: config_topology.minimum_gateway_performance,
},
nym_api_urls,
env!("CARGO_PKG_VERSION").to_string(),
user_agent,
)),
config::TopologyStructure::GeoAware(group_by) => {
Box::new(GeoAwareTopologyProvider::new(
@@ -687,7 +670,6 @@ where
let self_address = Self::mix_address(&init_res);
let ack_key = init_res.client_keys.ack_key();
let encryption_keys = init_res.client_keys.encryption_keypair();
let identity_keys = init_res.client_keys.identity_keypair();
// the components are started in very specific order. Unless you know what you are doing,
// do not change that.
@@ -697,9 +679,8 @@ where
let topology_provider = Self::setup_topology_provider(
self.custom_topology_provider.take(),
self.config.debug.topology,
self.config.debug.topology.topology_structure,
self.config.get_nym_api_endpoints(),
self.user_agent.clone(),
);
// needs to be started as the first thing to block if required waiting for the gateway
@@ -811,7 +792,6 @@ where
Ok(BaseClient {
address: self_address,
identity_keys,
client_input: ClientInputStatus::AwaitingProducer {
client_input: ClientInput {
connection_command_sender: client_connection_tx,
@@ -836,7 +816,6 @@ where
pub struct BaseClient {
pub address: Recipient,
pub identity_keys: Arc<identity::KeyPair>,
pub client_input: ClientInputStatus,
pub client_output: ClientOutputStatus,
pub client_state: ClientState,
@@ -92,11 +92,11 @@ pub mod v1_1_33 {
message: format!("the stored gateway id was malformed: {err}"),
})?,
derived_aes128_ctr_blake3_hmac_keys: Arc::new(gateway_shared_key),
gateway_owner_address: Some(gateway_owner.parse().map_err(|err| {
gateway_owner_address: gateway_owner.parse().map_err(|err| {
ClientCoreError::UpgradeFailure {
message: format!("the stored gateway owner address was malformed: {err}"),
}
})?),
})?,
gateway_listener: gateway_listener.parse().map_err(|err| {
ClientCoreError::UpgradeFailure {
message: format!("the stored gateway listener address was malformed: {err}"),
@@ -7,7 +7,7 @@ use std::error::Error;
use tokio::sync::Mutex;
#[cfg(not(target_arch = "wasm32"))]
use crate::config::disk_persistence::ClientKeysPaths;
use crate::config::disk_persistence::keys_paths::ClientKeysPaths;
#[cfg(not(target_arch = "wasm32"))]
use nym_crypto::asymmetric::{encryption, identity};
#[cfg(not(target_arch = "wasm32"))]
@@ -7,8 +7,6 @@ use nym_metrics::{inc, inc_by};
use si_scale::helpers::bibytes2;
// Metrics server
use futures::future::{FusedFuture, OptionFuture};
use futures::FutureExt;
#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
use http_body_util::Full;
#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
@@ -537,14 +535,6 @@ impl PacketStatisticsControl {
}
loop {
// it seems at some point tokio changed its select precondition evaluation,
// and it's no longer checked before the future is evaluated.
let accept_future: OptionFuture<_> = listener
.as_ref()
.map(|l| l.accept())
.map(FutureExt::fuse)
.into();
tokio::select! {
stats_event = self.stats_rx.recv() => match stats_event {
Some(stats_event) => {
@@ -556,37 +546,37 @@ impl PacketStatisticsControl {
break;
}
},
// conditional will disable the branch if we're in wasm32-unknown-unknown
// use `_` to calm down clippy when running for wasm
_result = accept_future, if !accept_future.is_terminated() => {
cfg_if::cfg_if! {
if #[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))] {
if let Some(Ok((stream, _))) = _result {
let io = TokioIo::new(stream);
tokio::task::spawn(async move {
if let Err(err) = http1::Builder::new()
.serve_connection(io, service_fn(serve_metrics))
.await
{
log::warn!("Error serving connection: {:?}", err);
}
});
} else {
log::warn!("Error accepting connection");
_ = async {
if let Some(ref listener) = listener {
if let Ok((stream, _)) = listener.accept().await {
cfg_if::cfg_if! {
if #[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))] {
let io = TokioIo::new(stream);
tokio::task::spawn(async move {
if let Err(err) = http1::Builder::new()
.serve_connection(io, service_fn(serve_metrics))
.await
{
log::warn!("Error serving connection: {:?}", err);
}
});
}
}
}
} else {
let _ = futures::future::pending::<()>().await;
}
}
}, if listener.is_some() => {
},
_ = snapshot_interval.tick() => {
self.update_history();
self.update_rates();
}
},
_ = report_interval.tick() => {
self.report_rates();
self.check_for_notable_events();
self.report_counters();
}
},
_ = shutdown.recv_with_delay() => {
log::trace!("PacketStatisticsControl: Received shutdown");
break;
@@ -1,5 +1,6 @@
use crate::config::GroupBy;
use log::{debug, error};
use std::{collections::HashMap, fmt};
use log::{debug, error, info};
use nym_explorer_client::{ExplorerClient, PrettyDetailedMixNodeBond};
use nym_network_defaults::var_names::EXPLORER_API;
use nym_topology::{
@@ -9,11 +10,11 @@ use nym_topology::{
};
use nym_validator_client::client::MixId;
use rand::{prelude::SliceRandom, thread_rng};
use std::collections::HashMap;
use serde::{Deserialize, Serialize};
use tap::TapOptional;
use url::Url;
pub use nym_country_group::CountryGroup;
use crate::config::GroupBy;
const MIN_NODES_PER_LAYER: usize = 1;
@@ -37,6 +38,158 @@ fn create_explorer_client() -> Option<ExplorerClient> {
Some(client)
}
#[derive(Copy, Clone, Hash, PartialEq, Eq, Serialize, Deserialize, Debug)]
pub enum CountryGroup {
Europe,
NorthAmerica,
SouthAmerica,
Oceania,
Asia,
Africa,
Unknown,
}
impl CountryGroup {
// We map contry codes into group, which initially are continent codes to a first approximation,
// but we do it manually to reserve the right to tweak this distribution for our purposes.
// NOTE: I did this quickly and it's not a complete list of all countries, but only those that
// were present in the network at the time. Please add more as needed.
fn new(country_code: &str) -> Self {
let country_code = country_code.to_uppercase();
use CountryGroup::*;
match country_code.as_ref() {
// Europe
"AT" => Europe,
"BG" => Europe,
"CH" => Europe,
"CY" => Europe,
"CZ" => Europe,
"DE" => Europe,
"DK" => Europe,
"ES" => Europe,
"FI" => Europe,
"FR" => Europe,
"GB" => Europe,
"GR" => Europe,
"IE" => Europe,
"IT" => Europe,
"LT" => Europe,
"LU" => Europe,
"LV" => Europe,
"MD" => Europe,
"MT" => Europe,
"NL" => Europe,
"NO" => Europe,
"PL" => Europe,
"RO" => Europe,
"SE" => Europe,
"SK" => Europe,
"TR" => Europe,
"UA" => Europe,
// North America
"CA" => NorthAmerica,
"MX" => NorthAmerica,
"US" => NorthAmerica,
// South America
"AR" => SouthAmerica,
"BR" => SouthAmerica,
"CL" => SouthAmerica,
"CO" => SouthAmerica,
"CR" => SouthAmerica,
"GT" => SouthAmerica,
// Oceania
"AU" => Oceania,
// Asia
"AM" => Asia,
"BH" => Asia,
"CN" => Asia,
"GE" => Asia,
"HK" => Asia,
"ID" => Asia,
"IL" => Asia,
"IN" => Asia,
"JP" => Asia,
"KH" => Asia,
"KR" => Asia,
"KZ" => Asia,
"MY" => Asia,
"RU" => Asia,
"SG" => Asia,
"TH" => Asia,
"VN" => Asia,
// Africa
"SC" => Africa,
"UG" => Africa,
"ZA" => Africa,
// And group level codes work too
"EU" => Europe,
"NA" => NorthAmerica,
"SA" => SouthAmerica,
"OC" => Oceania,
"AS" => Asia,
"AF" => Africa,
// And some aliases
"EUROPE" => Europe,
"NORTHAMERICA" => NorthAmerica,
"SOUTHAMERICA" => SouthAmerica,
"OCEANIA" => Oceania,
"ASIA" => Asia,
"AFRICA" => Africa,
_ => {
info!("Unknown country code: {}", country_code);
Unknown
}
}
}
}
impl fmt::Display for CountryGroup {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use CountryGroup::*;
match self {
Europe => write!(f, "EU"),
NorthAmerica => write!(f, "NA"),
SouthAmerica => write!(f, "SA"),
Oceania => write!(f, "OC"),
Asia => write!(f, "AS"),
Africa => write!(f, "AF"),
Unknown => write!(f, "Unknown"),
}
}
}
impl std::str::FromStr for CountryGroup {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
let group = CountryGroup::new(s);
if group == CountryGroup::Unknown {
Err(())
} else {
Ok(group)
}
}
}
impl CountryGroup {
#[allow(unused)]
fn known(self) -> Option<CountryGroup> {
use CountryGroup::*;
match self {
Europe | NorthAmerica | SouthAmerica | Oceania | Asia | Africa => Some(self),
Unknown => None,
}
}
}
fn group_mixnodes_by_country_code(
mixnodes: Vec<PrettyDetailedMixNodeBond>,
) -> HashMap<CountryGroup, Vec<MixId>> {
@@ -2,36 +2,14 @@
// SPDX-License-Identifier: Apache-2.0
use async_trait::async_trait;
use log::{debug, error, warn};
use log::{error, warn};
use nym_topology::provider_trait::TopologyProvider;
use nym_topology::{NymTopology, NymTopologyError};
use nym_validator_client::UserAgent;
use nym_topology::{nym_topology_from_detailed, NymTopology, NymTopologyError};
use rand::prelude::SliceRandom;
use rand::thread_rng;
use url::Url;
// the same values as our current (10.06.24) blacklist
pub const DEFAULT_MIN_MIXNODE_PERFORMANCE: u8 = 50;
pub const DEFAULT_MIN_GATEWAY_PERFORMANCE: u8 = 50;
pub(crate) struct Config {
pub(crate) min_mixnode_performance: u8,
pub(crate) min_gateway_performance: u8,
}
impl Default for Config {
fn default() -> Self {
// old values that decided on blacklist membership
Config {
min_mixnode_performance: DEFAULT_MIN_MIXNODE_PERFORMANCE,
min_gateway_performance: DEFAULT_MIN_GATEWAY_PERFORMANCE,
}
}
}
pub(crate) struct NymApiTopologyProvider {
config: Config,
validator_client: nym_validator_client::client::NymApiClient,
nym_api_urls: Vec<Url>,
@@ -40,26 +18,13 @@ pub(crate) struct NymApiTopologyProvider {
}
impl NymApiTopologyProvider {
pub(crate) fn new(
config: Config,
mut nym_api_urls: Vec<Url>,
client_version: String,
user_agent: Option<UserAgent>,
) -> Self {
pub(crate) fn new(mut nym_api_urls: Vec<Url>, client_version: String) -> Self {
nym_api_urls.shuffle(&mut thread_rng());
let validator_client = if let Some(user_agent) = user_agent {
nym_validator_client::client::NymApiClient::new_with_user_agent(
nym_api_urls[0].clone(),
user_agent,
)
} else {
nym_validator_client::client::NymApiClient::new(nym_api_urls[0].clone())
};
NymApiTopologyProvider {
config,
validator_client,
validator_client: nym_validator_client::client::NymApiClient::new(
nym_api_urls[0].clone(),
),
nym_api_urls,
client_version,
currently_used_api: 0,
@@ -96,11 +61,7 @@ impl NymApiTopologyProvider {
}
async fn get_current_compatible_topology(&mut self) -> Option<NymTopology> {
let mixnodes = match self
.validator_client
.get_basic_mixnodes(Some(self.client_version.clone()))
.await
{
let mixnodes = match self.validator_client.get_cached_active_mixnodes().await {
Err(err) => {
error!("failed to get network mixnodes - {err}");
return None;
@@ -108,11 +69,7 @@ impl NymApiTopologyProvider {
Ok(mixes) => mixes,
};
let gateways = match self
.validator_client
.get_basic_gateways(Some(self.client_version.clone()))
.await
{
let gateways = match self.validator_client.get_cached_described_gateways().await {
Err(err) => {
error!("failed to get network gateways - {err}");
return None;
@@ -120,20 +77,8 @@ impl NymApiTopologyProvider {
Ok(gateways) => gateways,
};
debug!(
"there are {} mixnodes and {} gateways in total (before performance filtering)",
mixnodes.len(),
gateways.len()
);
let topology = NymTopology::from_unordered(
mixnodes.iter().filter(|m| {
m.performance.round_to_integer() >= self.config.min_mixnode_performance
}),
gateways.iter().filter(|g| {
g.performance.round_to_integer() >= self.config.min_gateway_performance
}),
);
let topology = nym_topology_from_detailed(mixnodes, gateways)
.filter_system_version(&self.client_version);
if let Err(err) = self.check_layer_distribution(&topology) {
warn!("The current filtered active topology has extremely skewed layer distribution. It cannot be used: {err}");
@@ -1,53 +1,15 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use serde::{Deserialize, Serialize};
use std::path::{Path, PathBuf};
pub mod old;
// preserve old structure for easier migration
pub use old::{old_v1_1_20_2, old_v1_1_33};
pub const DEFAULT_REPLY_SURB_DB_FILENAME: &str = "persistent_reply_store.sqlite";
pub const DEFAULT_CREDENTIALS_DB_FILENAME: &str = "credentials_database.db";
pub const DEFAULT_GATEWAYS_DETAILS_DB_FILENAME: &str = "gateways_registrations.sqlite";
pub const DEFAULT_PRIVATE_IDENTITY_KEY_FILENAME: &str = "private_identity.pem";
pub const DEFAULT_PUBLIC_IDENTITY_KEY_FILENAME: &str = "public_identity.pem";
pub const DEFAULT_PRIVATE_ENCRYPTION_KEY_FILENAME: &str = "private_encryption.pem";
pub const DEFAULT_PUBLIC_ENCRYPTION_KEY_FILENAME: &str = "public_encryption.pem";
pub const DEFAULT_ACK_KEY_FILENAME: &str = "ack_key.pem";
#[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct CommonClientPaths {
pub keys: ClientKeysPaths,
/// Path to the file containing information about gateways used by this client,
/// i.e. details such as their public keys, owner addresses or the network information.
pub gateway_registrations: PathBuf,
/// Path to the database containing bandwidth credentials of this client.
pub credentials_database: PathBuf,
/// Path to the persistent store for received reply surbs, unused encryption keys and used sender tags.
pub reply_surb_database: PathBuf,
}
impl CommonClientPaths {
pub fn new_base<P: AsRef<Path>>(base_data_directory: P) -> Self {
let base_dir = base_data_directory.as_ref();
CommonClientPaths {
credentials_database: base_dir.join(DEFAULT_CREDENTIALS_DB_FILENAME),
reply_surb_database: base_dir.join(DEFAULT_REPLY_SURB_DB_FILENAME),
gateway_registrations: base_dir.join(DEFAULT_GATEWAYS_DETAILS_DB_FILENAME),
keys: ClientKeysPaths::new_base(base_data_directory),
}
}
}
#[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)]
pub struct ClientKeysPaths {
/// Path to file containing private identity key.
@@ -0,0 +1,43 @@
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::config::disk_persistence::keys_paths::ClientKeysPaths;
use serde::{Deserialize, Serialize};
use std::path::{Path, PathBuf};
pub mod keys_paths;
pub mod old_v1_1_20_2;
pub mod old_v1_1_33;
pub const DEFAULT_REPLY_SURB_DB_FILENAME: &str = "persistent_reply_store.sqlite";
pub const DEFAULT_CREDENTIALS_DB_FILENAME: &str = "credentials_database.db";
pub const DEFAULT_GATEWAYS_DETAILS_DB_FILENAME: &str = "gateways_registrations.sqlite";
#[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct CommonClientPaths {
pub keys: ClientKeysPaths,
/// Path to the file containing information about gateways used by this client,
/// i.e. details such as their public keys, owner addresses or the network information.
pub gateway_registrations: PathBuf,
/// Path to the database containing bandwidth credentials of this client.
pub credentials_database: PathBuf,
/// Path to the persistent store for received reply surbs, unused encryption keys and used sender tags.
pub reply_surb_database: PathBuf,
}
impl CommonClientPaths {
pub fn new_base<P: AsRef<Path>>(base_data_directory: P) -> Self {
let base_dir = base_data_directory.as_ref();
CommonClientPaths {
credentials_database: base_dir.join(DEFAULT_CREDENTIALS_DB_FILENAME),
reply_surb_database: base_dir.join(DEFAULT_REPLY_SURB_DB_FILENAME),
gateway_registrations: base_dir.join(DEFAULT_GATEWAYS_DETAILS_DB_FILENAME),
keys: ClientKeysPaths::new_base(base_data_directory),
}
}
}
@@ -0,0 +1,33 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::config::disk_persistence::old_v1_1_33::{
ClientKeysPathsV1_1_33, CommonClientPathsV1_1_33, DEFAULT_GATEWAY_DETAILS_FILENAME,
};
use crate::error::ClientCoreError;
use serde::{Deserialize, Serialize};
use std::path::PathBuf;
#[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct CommonClientPathsV1_1_20_2 {
pub keys: ClientKeysPathsV1_1_33,
pub credentials_database: PathBuf,
pub reply_surb_database: PathBuf,
}
impl CommonClientPathsV1_1_20_2 {
pub fn upgrade_default(self) -> Result<CommonClientPathsV1_1_33, ClientCoreError> {
let data_dir = self.reply_surb_database.parent().ok_or_else(|| {
ClientCoreError::ConfigFileUpgradeFailure {
current_version: "1.1.20-2".to_string(),
}
})?;
Ok(CommonClientPathsV1_1_33 {
keys: self.keys,
gateway_details: data_dir.join(DEFAULT_GATEWAY_DETAILS_FILENAME),
credentials_database: self.credentials_database,
reply_surb_database: self.reply_surb_database,
})
}
}
@@ -1,20 +1,16 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::disk_persistence::ClientKeysPaths;
use crate::disk_persistence::{CommonClientPaths, DEFAULT_GATEWAYS_DETAILS_DB_FILENAME};
use crate::error::ConfigUpgradeFailure;
use crate::config::disk_persistence::keys_paths::ClientKeysPaths;
use crate::config::disk_persistence::{CommonClientPaths, DEFAULT_GATEWAYS_DETAILS_DB_FILENAME};
use crate::error::ClientCoreError;
use serde::{Deserialize, Serialize};
use std::path::PathBuf;
pub const DEFAULT_GATEWAY_DETAILS_FILENAME: &str = "gateway_details.json";
// aliases for backwards compatibility
pub type CommonClientPathsV1_1_33 = CommonClientPathsV2;
pub type ClientKeysPathsV1_1_33 = ClientKeysPathsV2;
#[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)]
pub struct ClientKeysPathsV2 {
pub struct ClientKeysPathsV1_1_33 {
/// Path to file containing private identity key.
pub private_identity_key_file: PathBuf,
@@ -36,7 +32,7 @@ pub struct ClientKeysPathsV2 {
pub ack_key_file: PathBuf,
}
impl ClientKeysPathsV2 {
impl ClientKeysPathsV1_1_33 {
pub fn upgrade(self) -> ClientKeysPaths {
ClientKeysPaths {
private_identity_key_file: self.private_identity_key_file,
@@ -50,8 +46,8 @@ impl ClientKeysPathsV2 {
#[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct CommonClientPathsV2 {
pub keys: ClientKeysPathsV2,
pub struct CommonClientPathsV1_1_33 {
pub keys: ClientKeysPathsV1_1_33,
/// Path to the file containing information about gateway used by this client,
/// i.e. details such as its public key, owner address or the network information.
@@ -64,16 +60,15 @@ pub struct CommonClientPathsV2 {
pub reply_surb_database: PathBuf,
}
impl CommonClientPathsV2 {
impl CommonClientPathsV1_1_33 {
// note that during the upgrade process, the caller will need to extract the key and gateway details
// manually and resave them in the new database
pub fn upgrade_default(self) -> Result<CommonClientPaths, ConfigUpgradeFailure> {
let data_dir = self
.gateway_details
.parent()
.ok_or_else(|| ConfigUpgradeFailure {
pub fn upgrade_default(self) -> Result<CommonClientPaths, ClientCoreError> {
let data_dir = self.gateway_details.parent().ok_or_else(|| {
ClientCoreError::ConfigFileUpgradeFailure {
current_version: "1.1.33".to_string(),
})?;
}
})?;
Ok(CommonClientPaths {
keys: self.keys.upgrade(),
+599 -6
View File
@@ -1,9 +1,602 @@
// Copyright 2021-2024 - Nym Technologies SA <contact@nymtech.net>
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
pub use nym_client_core_config_types::disk_persistence;
pub use nym_client_core_config_types::old::{
old_config_v1_1_13, old_config_v1_1_20, old_config_v1_1_20_2, old_config_v1_1_30,
old_config_v1_1_33,
use crate::client::topology_control::geo_aware_provider::CountryGroup;
use nym_config::defaults::NymNetworkDetails;
use nym_sphinx::{
addressing::clients::Recipient,
params::{PacketSize, PacketType},
};
pub use nym_client_core_config_types::*;
use serde::{Deserialize, Serialize};
use std::time::Duration;
use url::Url;
pub mod disk_persistence;
pub mod old_config_v1_1_13;
pub mod old_config_v1_1_20;
pub mod old_config_v1_1_20_2;
pub mod old_config_v1_1_30;
pub mod old_config_v1_1_33;
// 'DEBUG'
const DEFAULT_ACK_WAIT_MULTIPLIER: f64 = 1.5;
const DEFAULT_ACK_WAIT_ADDITION: Duration = Duration::from_millis(1_500);
const DEFAULT_LOOP_COVER_STREAM_AVERAGE_DELAY: Duration = Duration::from_millis(200);
const DEFAULT_MESSAGE_STREAM_AVERAGE_DELAY: Duration = Duration::from_millis(20);
const DEFAULT_AVERAGE_PACKET_DELAY: Duration = Duration::from_millis(50);
const DEFAULT_TOPOLOGY_REFRESH_RATE: Duration = Duration::from_secs(5 * 60); // every 5min
const DEFAULT_TOPOLOGY_RESOLUTION_TIMEOUT: Duration = Duration::from_millis(5_000);
const DEFAULT_MAX_STARTUP_GATEWAY_WAITING_PERIOD: Duration = Duration::from_secs(70 * 60); // 70min -> full epoch (1h) + a bit of overhead
// Set this to a high value for now, so that we don't risk sporadic timeouts that might cause
// bought bandwidth tokens to not have time to be spent; Once we remove the gateway from the
// bandwidth bridging protocol, we can come back to a smaller timeout value
const DEFAULT_GATEWAY_RESPONSE_TIMEOUT: Duration = Duration::from_secs(5 * 60);
const DEFAULT_COVER_TRAFFIC_PRIMARY_SIZE_RATIO: f64 = 0.70;
// reply-surbs related:
// define when to request
// clients/client-core/src/client/replies/reply_storage/surb_storage.rs
const DEFAULT_MINIMUM_REPLY_SURB_STORAGE_THRESHOLD: usize = 10;
const DEFAULT_MAXIMUM_REPLY_SURB_STORAGE_THRESHOLD: usize = 200;
// define how much to request at once
// clients/client-core/src/client/replies/reply_controller.rs
const DEFAULT_MINIMUM_REPLY_SURB_REQUEST_SIZE: u32 = 10;
const DEFAULT_MAXIMUM_REPLY_SURB_REQUEST_SIZE: u32 = 100;
const DEFAULT_MAXIMUM_ALLOWED_SURB_REQUEST_SIZE: u32 = 500;
const DEFAULT_MAXIMUM_REPLY_SURB_REREQUEST_WAITING_PERIOD: Duration = Duration::from_secs(10);
const DEFAULT_MAXIMUM_REPLY_SURB_DROP_WAITING_PERIOD: Duration = Duration::from_secs(5 * 60);
// 12 hours
const DEFAULT_MAXIMUM_REPLY_SURB_AGE: Duration = Duration::from_secs(12 * 60 * 60);
// 24 hours
const DEFAULT_MAXIMUM_REPLY_KEY_AGE: Duration = Duration::from_secs(24 * 60 * 60);
#[derive(Debug, Clone, Deserialize, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct Config {
pub client: Client,
#[serde(default)]
pub debug: DebugConfig,
}
impl Config {
pub fn new<S1, S2>(id: S1, version: S2) -> Self
where
S1: Into<String>,
S2: Into<String>,
{
Config {
client: Client::new_default(id, version),
debug: Default::default(),
}
}
pub fn from_client_config(client: Client, debug: DebugConfig) -> Self {
Config { client, debug }
}
pub fn validate(&self) -> bool {
self.debug.validate()
}
pub fn with_debug_config(mut self, debug: DebugConfig) -> Self {
self.debug = debug;
self
}
pub fn with_disabled_credentials(mut self, disabled_credentials_mode: bool) -> Self {
self.client.disabled_credentials_mode = disabled_credentials_mode;
self
}
pub fn with_custom_nyxd(mut self, urls: Vec<Url>) -> Self {
self.client.nyxd_urls = urls;
self
}
pub fn set_custom_nyxd(&mut self, nyxd_urls: Vec<Url>) {
self.client.nyxd_urls = nyxd_urls;
}
pub fn with_custom_nym_apis(mut self, nym_api_urls: Vec<Url>) -> Self {
self.client.nym_api_urls = nym_api_urls;
self
}
pub fn set_custom_nym_apis(&mut self, nym_api_urls: Vec<Url>) {
self.client.nym_api_urls = nym_api_urls;
}
pub fn with_high_default_traffic_volume(mut self, enabled: bool) -> Self {
if enabled {
self.set_high_default_traffic_volume();
}
self
}
pub fn with_packet_type(mut self, packet_type: PacketType) -> Self {
self.debug.traffic.packet_type = packet_type;
self
}
pub fn set_high_default_traffic_volume(&mut self) {
self.debug.traffic.average_packet_delay = Duration::from_millis(10);
// basically don't really send cover messages
self.debug.cover_traffic.loop_cover_traffic_average_delay =
Duration::from_millis(2_000_000);
// 250 "real" messages / s
self.debug.traffic.message_sending_average_delay = Duration::from_millis(4);
}
pub fn with_disabled_poisson_process(mut self, disabled: bool) -> Self {
if disabled {
self.set_no_poisson_process()
}
self
}
pub fn set_no_poisson_process(&mut self) {
self.debug.traffic.disable_main_poisson_packet_distribution = true;
}
pub fn with_disabled_cover_traffic(mut self, disabled: bool) -> Self {
if disabled {
self.set_no_cover_traffic()
}
self
}
pub fn set_no_cover_traffic(&mut self) {
self.debug.cover_traffic.disable_loop_cover_traffic_stream = true;
self.debug.traffic.disable_main_poisson_packet_distribution = true;
}
pub fn with_disabled_cover_traffic_with_keepalive(mut self, disabled: bool) -> Self {
if disabled {
self.set_no_cover_traffic_with_keepalive()
}
self
}
pub fn set_no_cover_traffic_with_keepalive(&mut self) {
self.debug.traffic.disable_main_poisson_packet_distribution = true;
self.debug.cover_traffic.loop_cover_traffic_average_delay = Duration::from_secs(5);
}
pub fn with_disabled_topology_refresh(mut self, disable_topology_refresh: bool) -> Self {
self.debug.topology.disable_refreshing = disable_topology_refresh;
self
}
pub fn with_topology_structure(mut self, topology_structure: TopologyStructure) -> Self {
self.set_topology_structure(topology_structure);
self
}
pub fn set_topology_structure(&mut self, topology_structure: TopologyStructure) {
self.debug.topology.topology_structure = topology_structure;
}
pub fn with_no_per_hop_delays(mut self, no_per_hop_delays: bool) -> Self {
if no_per_hop_delays {
self.set_no_per_hop_delays()
}
self
}
pub fn set_no_per_hop_delays(&mut self) {
self.debug.traffic.average_packet_delay = Duration::ZERO;
self.debug.acknowledgements.average_ack_delay = Duration::ZERO;
}
pub fn with_secondary_packet_size(mut self, secondary_packet_size: Option<PacketSize>) -> Self {
self.set_secondary_packet_size(secondary_packet_size);
self
}
pub fn set_secondary_packet_size(&mut self, secondary_packet_size: Option<PacketSize>) {
self.debug.traffic.secondary_packet_size = secondary_packet_size;
}
pub fn set_custom_version(&mut self, version: &str) {
self.client.version = version.to_string();
}
pub fn get_id(&self) -> String {
self.client.id.clone()
}
pub fn get_disabled_credentials_mode(&self) -> bool {
self.client.disabled_credentials_mode
}
pub fn get_validator_endpoints(&self) -> Vec<Url> {
self.client.nyxd_urls.clone()
}
pub fn get_nym_api_endpoints(&self) -> Vec<Url> {
self.client.nym_api_urls.clone()
}
}
#[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)]
// note: the deny_unknown_fields is VITAL here to allow upgrades from v1.1.20_2
#[serde(deny_unknown_fields)]
pub struct Client {
/// Version of the client for which this configuration was created.
pub version: String,
/// ID specifies the human readable ID of this particular client.
pub id: String,
/// Indicates whether this client is running in a disabled credentials mode, thus attempting
/// to claim bandwidth without presenting bandwidth credentials.
// TODO: this should be moved to `debug.gateway_connection`
#[serde(default)]
pub disabled_credentials_mode: bool,
/// Addresses to nyxd validators via which the client can communicate with the chain.
#[serde(alias = "validator_urls")]
pub nyxd_urls: Vec<Url>,
/// Addresses to APIs running on validator from which the client gets the view of the network.
#[serde(alias = "validator_api_urls")]
pub nym_api_urls: Vec<Url>,
}
impl Client {
pub fn new_default<S1, S2>(id: S1, version: S2) -> Self
where
S1: Into<String>,
S2: Into<String>,
{
let network = NymNetworkDetails::new_mainnet();
let nyxd_urls = network
.endpoints
.iter()
.map(|validator| validator.nyxd_url())
.collect();
let nym_api_urls = network
.endpoints
.iter()
.filter_map(|validator| validator.api_url())
.collect::<Vec<_>>();
Client {
version: version.into(),
id: id.into(),
disabled_credentials_mode: true,
nyxd_urls,
nym_api_urls,
}
}
pub fn new<S: Into<String>>(
id: S,
disabled_credentials_mode: bool,
nyxd_urls: Vec<Url>,
nym_api_urls: Vec<Url>,
) -> Self {
Client {
version: env!("CARGO_PKG_VERSION").to_string(),
id: id.into(),
disabled_credentials_mode,
nyxd_urls,
nym_api_urls,
}
}
}
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
#[serde(default, deny_unknown_fields)]
pub struct Traffic {
/// The parameter of Poisson distribution determining how long, on average,
/// sent packet is going to be delayed at any given mix node.
/// So for a packet going through three mix nodes, on average, it will take three times this value
/// until the packet reaches its destination.
#[serde(with = "humantime_serde")]
pub average_packet_delay: Duration,
/// The parameter of Poisson distribution determining how long, on average,
/// it is going to take another 'real traffic stream' message to be sent.
/// If no real packets are available and cover traffic is enabled,
/// a loop cover message is sent instead in order to preserve the rate.
#[serde(with = "humantime_serde")]
pub message_sending_average_delay: Duration,
/// Controls whether the main packet stream constantly produces packets according to the predefined
/// poisson distribution.
pub disable_main_poisson_packet_distribution: bool,
/// Specifies the packet size used for sent messages.
/// Do not override it unless you understand the consequences of that change.
pub primary_packet_size: PacketSize,
/// Specifies the optional auxiliary packet size for optimizing message streams.
/// Note that its use decreases overall anonymity.
/// Do not set it it unless you understand the consequences of that change.
pub secondary_packet_size: Option<PacketSize>,
pub packet_type: PacketType,
}
impl Traffic {
pub fn validate(&self) -> bool {
if let Some(secondary_packet_size) = self.secondary_packet_size {
if secondary_packet_size == PacketSize::AckPacket
|| secondary_packet_size == self.primary_packet_size
{
return false;
}
}
true
}
}
impl Default for Traffic {
fn default() -> Self {
Traffic {
average_packet_delay: DEFAULT_AVERAGE_PACKET_DELAY,
message_sending_average_delay: DEFAULT_MESSAGE_STREAM_AVERAGE_DELAY,
disable_main_poisson_packet_distribution: false,
primary_packet_size: PacketSize::RegularPacket,
secondary_packet_size: None,
packet_type: PacketType::Mix,
}
}
}
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
#[serde(default, deny_unknown_fields)]
pub struct CoverTraffic {
/// The parameter of Poisson distribution determining how long, on average,
/// it is going to take for another loop cover traffic message to be sent.
#[serde(with = "humantime_serde")]
pub loop_cover_traffic_average_delay: Duration,
/// Specifies the ratio of `primary_packet_size` to `secondary_packet_size` used in cover traffic.
/// Only applicable if `secondary_packet_size` is enabled.
pub cover_traffic_primary_size_ratio: f64,
/// Controls whether the dedicated loop cover traffic stream should be enabled.
/// (and sending packets, on average, every [Self::loop_cover_traffic_average_delay])
pub disable_loop_cover_traffic_stream: bool,
}
impl Default for CoverTraffic {
fn default() -> Self {
CoverTraffic {
loop_cover_traffic_average_delay: DEFAULT_LOOP_COVER_STREAM_AVERAGE_DELAY,
cover_traffic_primary_size_ratio: DEFAULT_COVER_TRAFFIC_PRIMARY_SIZE_RATIO,
disable_loop_cover_traffic_stream: false,
}
}
}
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
#[serde(default, deny_unknown_fields)]
pub struct GatewayConnection {
/// How long we're willing to wait for a response to a message sent to the gateway,
/// before giving up on it.
#[serde(with = "humantime_serde")]
pub gateway_response_timeout: Duration,
}
impl Default for GatewayConnection {
fn default() -> Self {
GatewayConnection {
gateway_response_timeout: DEFAULT_GATEWAY_RESPONSE_TIMEOUT,
}
}
}
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
#[serde(default, deny_unknown_fields)]
pub struct Acknowledgements {
/// The parameter of Poisson distribution determining how long, on average,
/// sent acknowledgement is going to be delayed at any given mix node.
/// So for an ack going through three mix nodes, on average, it will take three times this value
/// until the packet reaches its destination.
#[serde(with = "humantime_serde")]
pub average_ack_delay: Duration,
/// Value multiplied with the expected round trip time of an acknowledgement packet before
/// it is assumed it was lost and retransmission of the data packet happens.
/// In an ideal network with 0 latency, this value would have been 1.
pub ack_wait_multiplier: f64,
/// Value added to the expected round trip time of an acknowledgement packet before
/// it is assumed it was lost and retransmission of the data packet happens.
/// In an ideal network with 0 latency, this value would have been 0.
#[serde(with = "humantime_serde")]
pub ack_wait_addition: Duration,
}
impl Default for Acknowledgements {
fn default() -> Self {
Acknowledgements {
average_ack_delay: DEFAULT_AVERAGE_PACKET_DELAY,
ack_wait_multiplier: DEFAULT_ACK_WAIT_MULTIPLIER,
ack_wait_addition: DEFAULT_ACK_WAIT_ADDITION,
}
}
}
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
#[serde(default, deny_unknown_fields)]
pub struct Topology {
/// The uniform delay every which clients are querying the directory server
/// to try to obtain a compatible network topology to send sphinx packets through.
#[serde(with = "humantime_serde")]
pub topology_refresh_rate: Duration,
/// During topology refresh, test packets are sent through every single possible network
/// path. This timeout determines waiting period until it is decided that the packet
/// did not reach its destination.
#[serde(with = "humantime_serde")]
pub topology_resolution_timeout: Duration,
/// Specifies whether the client should not refresh the network topology after obtaining
/// the first valid instance.
/// Supersedes `topology_refresh_rate_ms`.
pub disable_refreshing: bool,
/// Defines how long the client is going to wait on startup for its gateway to come online,
/// before abandoning the procedure.
#[serde(with = "humantime_serde")]
pub max_startup_gateway_waiting_period: Duration,
/// Specifies the mixnode topology to be used for sending packets.
pub topology_structure: TopologyStructure,
}
#[allow(clippy::large_enum_variant)]
#[derive(Default, Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum TopologyStructure {
#[default]
NymApi,
GeoAware(GroupBy),
}
#[allow(clippy::large_enum_variant)]
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum GroupBy {
CountryGroup(CountryGroup),
NymAddress(Recipient),
}
impl std::fmt::Display for GroupBy {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
GroupBy::CountryGroup(group) => write!(f, "group: {}", group),
GroupBy::NymAddress(address) => write!(f, "address: {}", address),
}
}
}
impl Default for Topology {
fn default() -> Self {
Topology {
topology_refresh_rate: DEFAULT_TOPOLOGY_REFRESH_RATE,
topology_resolution_timeout: DEFAULT_TOPOLOGY_RESOLUTION_TIMEOUT,
disable_refreshing: false,
max_startup_gateway_waiting_period: DEFAULT_MAX_STARTUP_GATEWAY_WAITING_PERIOD,
topology_structure: TopologyStructure::default(),
}
}
}
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
#[serde(default, deny_unknown_fields)]
pub struct ReplySurbs {
/// Defines the minimum number of reply surbs the client wants to keep in its storage at all times.
/// It can only allow to go below that value if its to request additional reply surbs.
pub minimum_reply_surb_storage_threshold: usize,
/// Defines the maximum number of reply surbs the client wants to keep in its storage at any times.
pub maximum_reply_surb_storage_threshold: usize,
/// Defines the minimum number of reply surbs the client would request.
pub minimum_reply_surb_request_size: u32,
/// Defines the maximum number of reply surbs the client would request.
pub maximum_reply_surb_request_size: u32,
/// Defines the maximum number of reply surbs a remote party is allowed to request from this client at once.
pub maximum_allowed_reply_surb_request_size: u32,
/// Defines maximum amount of time the client is going to wait for reply surbs before explicitly asking
/// for more even though in theory they wouldn't need to.
#[serde(with = "humantime_serde")]
pub maximum_reply_surb_rerequest_waiting_period: Duration,
/// Defines maximum amount of time the client is going to wait for reply surbs before
/// deciding it's never going to get them and would drop all pending messages
#[serde(with = "humantime_serde")]
pub maximum_reply_surb_drop_waiting_period: Duration,
/// Defines maximum amount of time given reply surb is going to be valid for.
/// This is going to be superseded by key rotation once implemented.
#[serde(with = "humantime_serde")]
pub maximum_reply_surb_age: Duration,
/// Defines maximum amount of time given reply key is going to be valid for.
/// This is going to be superseded by key rotation once implemented.
#[serde(with = "humantime_serde")]
pub maximum_reply_key_age: Duration,
/// Specifies the number of mixnet hops the packet should go through. If not specified, then
/// the default value is used.
pub surb_mix_hops: Option<u8>,
}
impl Default for ReplySurbs {
fn default() -> Self {
ReplySurbs {
minimum_reply_surb_storage_threshold: DEFAULT_MINIMUM_REPLY_SURB_STORAGE_THRESHOLD,
maximum_reply_surb_storage_threshold: DEFAULT_MAXIMUM_REPLY_SURB_STORAGE_THRESHOLD,
minimum_reply_surb_request_size: DEFAULT_MINIMUM_REPLY_SURB_REQUEST_SIZE,
maximum_reply_surb_request_size: DEFAULT_MAXIMUM_REPLY_SURB_REQUEST_SIZE,
maximum_allowed_reply_surb_request_size: DEFAULT_MAXIMUM_ALLOWED_SURB_REQUEST_SIZE,
maximum_reply_surb_rerequest_waiting_period:
DEFAULT_MAXIMUM_REPLY_SURB_REREQUEST_WAITING_PERIOD,
maximum_reply_surb_drop_waiting_period: DEFAULT_MAXIMUM_REPLY_SURB_DROP_WAITING_PERIOD,
maximum_reply_surb_age: DEFAULT_MAXIMUM_REPLY_SURB_AGE,
maximum_reply_key_age: DEFAULT_MAXIMUM_REPLY_KEY_AGE,
surb_mix_hops: None,
}
}
}
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
#[serde(default, deny_unknown_fields)]
pub struct DebugConfig {
/// Defines all configuration options related to traffic streams.
pub traffic: Traffic,
/// Defines all configuration options related to cover traffic stream(s).
pub cover_traffic: CoverTraffic,
/// Defines all configuration options related to the gateway connection.
pub gateway_connection: GatewayConnection,
/// Defines all configuration options related to acknowledgements, such as delays or wait timeouts.
pub acknowledgements: Acknowledgements,
/// Defines all configuration options related topology, such as refresh rates or timeouts.
pub topology: Topology,
/// Defines all configuration options related to reply SURBs.
pub reply_surbs: ReplySurbs,
}
impl DebugConfig {
pub fn validate(&self) -> bool {
// no other sections have explicit requirements (yet)
self.traffic.validate()
}
}
// it could be derived, sure, but I'd rather have an explicit implementation in case we had to change
// something manually at some point
#[allow(clippy::derivable_impls)]
impl Default for DebugConfig {
fn default() -> Self {
DebugConfig {
traffic: Default::default(),
cover_traffic: Default::default(),
gateway_connection: Default::default(),
acknowledgements: Default::default(),
topology: Default::default(),
reply_surbs: Default::default(),
}
}
}
@@ -1,28 +1,23 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::old::v2::{
AcknowledgementsV2, ClientV2, ConfigV2, CoverTrafficV2, DebugConfigV2, GatewayConnectionV2,
LoggingV2, ReplySurbsV2, TopologyV2, TrafficV2, DEFAULT_ACK_WAIT_ADDITION,
DEFAULT_ACK_WAIT_MULTIPLIER, DEFAULT_AVERAGE_PACKET_DELAY, DEFAULT_GATEWAY_RESPONSE_TIMEOUT,
DEFAULT_LOOP_COVER_STREAM_AVERAGE_DELAY, DEFAULT_MAXIMUM_ALLOWED_SURB_REQUEST_SIZE,
DEFAULT_MAXIMUM_REPLY_KEY_AGE, DEFAULT_MAXIMUM_REPLY_SURB_AGE,
DEFAULT_MAXIMUM_REPLY_SURB_DROP_WAITING_PERIOD, DEFAULT_MAXIMUM_REPLY_SURB_REQUEST_SIZE,
DEFAULT_MAXIMUM_REPLY_SURB_REREQUEST_WAITING_PERIOD,
use crate::config::old_config_v1_1_20::{
AcknowledgementsV1_1_20, ClientV1_1_20, ConfigV1_1_20, CoverTrafficV1_1_20, DebugConfigV1_1_20,
GatewayConnectionV1_1_20, LoggingV1_1_20, ReplySurbsV1_1_20, TopologyV1_1_20, TrafficV1_1_20,
DEFAULT_ACK_WAIT_ADDITION, DEFAULT_ACK_WAIT_MULTIPLIER, DEFAULT_AVERAGE_PACKET_DELAY,
DEFAULT_GATEWAY_RESPONSE_TIMEOUT, DEFAULT_LOOP_COVER_STREAM_AVERAGE_DELAY,
DEFAULT_MAXIMUM_ALLOWED_SURB_REQUEST_SIZE, DEFAULT_MAXIMUM_REPLY_KEY_AGE,
DEFAULT_MAXIMUM_REPLY_SURB_AGE, DEFAULT_MAXIMUM_REPLY_SURB_DROP_WAITING_PERIOD,
DEFAULT_MAXIMUM_REPLY_SURB_REQUEST_SIZE, DEFAULT_MAXIMUM_REPLY_SURB_REREQUEST_WAITING_PERIOD,
DEFAULT_MAXIMUM_REPLY_SURB_STORAGE_THRESHOLD, DEFAULT_MESSAGE_STREAM_AVERAGE_DELAY,
DEFAULT_MINIMUM_REPLY_SURB_REQUEST_SIZE, DEFAULT_MINIMUM_REPLY_SURB_STORAGE_THRESHOLD,
DEFAULT_TOPOLOGY_REFRESH_RATE, DEFAULT_TOPOLOGY_RESOLUTION_TIMEOUT,
};
use nym_sphinx_params::PacketSize;
use nym_sphinx::params::PacketSize;
use serde::{Deserialize, Serialize};
use std::marker::PhantomData;
use std::time::Duration;
// aliases for backwards compatibility
pub type OldConfigV1_1_13<T> = ConfigV1<T>;
pub type OldLoggingV1_1_13 = LoggingV1;
pub type OldDebugConfigV1_1_13 = DebugConfigV1;
#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "lowercase")]
pub enum ExtendedPacketSize {
@@ -43,28 +38,28 @@ impl From<ExtendedPacketSize> for PacketSize {
#[derive(Debug, Clone, Deserialize, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct ConfigV1<T> {
pub client: ClientV2<T>,
pub struct OldConfigV1_1_13<T> {
pub client: ClientV1_1_20<T>,
#[serde(default)]
pub logging: LoggingV1,
pub logging: OldLoggingV1_1_13,
#[serde(default)]
pub debug: DebugConfigV1,
pub debug: OldDebugConfigV1_1_13,
}
#[derive(Debug, Clone, Default, Deserialize, PartialEq, Eq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct LoggingV1 {}
pub struct OldLoggingV1_1_13 {}
impl From<LoggingV1> for LoggingV2 {
fn from(_value: LoggingV1) -> Self {
LoggingV2 {}
impl From<OldLoggingV1_1_13> for LoggingV1_1_20 {
fn from(_value: OldLoggingV1_1_13) -> Self {
LoggingV1_1_20 {}
}
}
#[derive(Debug, Clone, Deserialize, PartialEq, Serialize)]
#[serde(default, deny_unknown_fields)]
pub struct DebugConfigV1 {
pub struct OldDebugConfigV1_1_13 {
#[serde(with = "humantime_serde")]
pub average_packet_delay: Duration,
@@ -119,10 +114,10 @@ pub struct DebugConfigV1 {
pub maximum_reply_key_age: Duration,
}
impl From<DebugConfigV1> for DebugConfigV2 {
fn from(value: DebugConfigV1) -> Self {
DebugConfigV2 {
traffic: TrafficV2 {
impl From<OldDebugConfigV1_1_13> for DebugConfigV1_1_20 {
fn from(value: OldDebugConfigV1_1_13) -> Self {
DebugConfigV1_1_20 {
traffic: TrafficV1_1_20 {
average_packet_delay: value.average_packet_delay,
message_sending_average_delay: value.message_sending_average_delay,
disable_main_poisson_packet_distribution: value
@@ -130,25 +125,25 @@ impl From<DebugConfigV1> for DebugConfigV2 {
primary_packet_size: PacketSize::RegularPacket,
secondary_packet_size: value.use_extended_packet_size.map(Into::into),
},
cover_traffic: CoverTrafficV2 {
cover_traffic: CoverTrafficV1_1_20 {
loop_cover_traffic_average_delay: value.loop_cover_traffic_average_delay,
disable_loop_cover_traffic_stream: value.disable_loop_cover_traffic_stream,
..CoverTrafficV2::default()
..CoverTrafficV1_1_20::default()
},
gateway_connection: GatewayConnectionV2 {
gateway_connection: GatewayConnectionV1_1_20 {
gateway_response_timeout: value.gateway_response_timeout,
},
acknowledgements: AcknowledgementsV2 {
acknowledgements: AcknowledgementsV1_1_20 {
average_ack_delay: value.average_ack_delay,
ack_wait_multiplier: value.ack_wait_multiplier,
ack_wait_addition: value.ack_wait_addition,
},
topology: TopologyV2 {
topology: TopologyV1_1_20 {
topology_refresh_rate: value.topology_refresh_rate,
topology_resolution_timeout: value.topology_resolution_timeout,
disable_refreshing: false,
},
reply_surbs: ReplySurbsV2 {
reply_surbs: ReplySurbsV1_1_20 {
minimum_reply_surb_storage_threshold: value.minimum_reply_surb_storage_threshold,
maximum_reply_surb_storage_threshold: value.maximum_reply_surb_storage_threshold,
minimum_reply_surb_request_size: value.minimum_reply_surb_request_size,
@@ -166,9 +161,9 @@ impl From<DebugConfigV1> for DebugConfigV2 {
}
}
impl Default for DebugConfigV1 {
impl Default for OldDebugConfigV1_1_13 {
fn default() -> Self {
DebugConfigV1 {
OldDebugConfigV1_1_13 {
average_packet_delay: DEFAULT_AVERAGE_PACKET_DELAY,
average_ack_delay: DEFAULT_AVERAGE_PACKET_DELAY,
ack_wait_multiplier: DEFAULT_ACK_WAIT_MULTIPLIER,
@@ -195,10 +190,10 @@ impl Default for DebugConfigV1 {
}
}
impl<T, U> From<ConfigV1<T>> for ConfigV2<U> {
fn from(value: ConfigV1<T>) -> Self {
ConfigV2 {
client: ClientV2 {
impl<T, U> From<OldConfigV1_1_13<T>> for ConfigV1_1_20<U> {
fn from(value: OldConfigV1_1_13<T>) -> Self {
ConfigV1_1_20 {
client: ClientV1_1_20 {
version: value.client.version,
id: value.client.id,
disabled_credentials_mode: value.client.disabled_credentials_mode,
@@ -1,11 +1,12 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::old::v3::{
AcknowledgementsV3, CoverTrafficV3, DebugConfigV3, GatewayConnectionV3,
GatewayEndpointConfigV3, ReplySurbsV3, TopologyV3, TrafficV3,
use crate::config::old_config_v1_1_20_2::{
AcknowledgementsV1_1_20_2, CoverTrafficV1_1_20_2, DebugConfigV1_1_20_2,
GatewayConnectionV1_1_20_2, GatewayEndpointConfigV1_1_20_2, ReplySurbsV1_1_20_2,
TopologyV1_1_20_2, TrafficV1_1_20_2,
};
use nym_sphinx_params::{PacketSize, PacketType};
use nym_sphinx::params::{PacketSize, PacketType};
use serde::{Deserialize, Serialize};
use std::marker::PhantomData;
use std::path::PathBuf;
@@ -53,41 +54,27 @@ pub(crate) const DEFAULT_MAXIMUM_REPLY_SURB_AGE: Duration = Duration::from_secs(
// 24 hours
pub(crate) const DEFAULT_MAXIMUM_REPLY_KEY_AGE: Duration = Duration::from_secs(24 * 60 * 60);
// aliases for backwards compatibility
pub type ConfigV1_1_20<T> = ConfigV2<T>;
pub type ClientV1_1_20<T> = ClientV2<T>;
pub type LoggingV1_1_20 = LoggingV2;
pub type DebugConfigV1_1_20 = DebugConfigV2;
pub type GatewayEndpointConfigV1_1_20 = GatewayEndpointConfigV2;
pub type TrafficV1_1_20 = TrafficV2;
pub type CoverTrafficV1_1_20 = CoverTrafficV2;
pub type GatewayConnectionV1_1_20 = GatewayConnectionV2;
pub type AcknowledgementsV1_1_20 = AcknowledgementsV2;
pub type TopologyV1_1_20 = TopologyV2;
pub type ReplySurbsV1_1_20 = ReplySurbsV2;
#[derive(Debug, Clone, Deserialize, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct ConfigV2<T> {
pub client: ClientV2<T>,
pub struct ConfigV1_1_20<T> {
pub client: ClientV1_1_20<T>,
#[serde(default)]
pub logging: LoggingV2,
pub logging: LoggingV1_1_20,
#[serde(default)]
pub debug: DebugConfigV2,
pub debug: DebugConfigV1_1_20,
}
#[derive(Clone, Debug, Default, Deserialize, PartialEq, Eq, Serialize)]
pub struct GatewayEndpointConfigV2 {
pub struct GatewayEndpointConfigV1_1_20 {
pub gateway_id: String,
pub gateway_owner: String,
pub gateway_listener: String,
}
impl From<GatewayEndpointConfigV2> for GatewayEndpointConfigV3 {
fn from(value: GatewayEndpointConfigV2) -> Self {
GatewayEndpointConfigV3 {
impl From<GatewayEndpointConfigV1_1_20> for GatewayEndpointConfigV1_1_20_2 {
fn from(value: GatewayEndpointConfigV1_1_20) -> Self {
GatewayEndpointConfigV1_1_20_2 {
gateway_id: value.gateway_id,
gateway_owner: value.gateway_owner,
gateway_listener: value.gateway_listener,
@@ -96,7 +83,7 @@ impl From<GatewayEndpointConfigV2> for GatewayEndpointConfigV3 {
}
#[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)]
pub struct ClientV2<T> {
pub struct ClientV1_1_20<T> {
pub version: String,
pub id: String,
#[serde(default)]
@@ -111,7 +98,7 @@ pub struct ClientV2<T> {
pub public_encryption_key_file: PathBuf,
pub gateway_shared_key_file: PathBuf,
pub ack_key_file: PathBuf,
pub gateway_endpoint: GatewayEndpointConfigV2,
pub gateway_endpoint: GatewayEndpointConfigV1_1_20,
pub database_path: PathBuf,
#[serde(default)]
pub reply_surb_database_path: PathBuf,
@@ -123,11 +110,11 @@ pub struct ClientV2<T> {
#[derive(Debug, Clone, Default, Deserialize, PartialEq, Eq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct LoggingV2 {}
pub struct LoggingV1_1_20 {}
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
#[serde(default)]
pub struct TrafficV2 {
pub struct TrafficV1_1_20 {
#[serde(with = "humantime_serde")]
pub average_packet_delay: Duration,
#[serde(with = "humantime_serde")]
@@ -137,9 +124,9 @@ pub struct TrafficV2 {
pub secondary_packet_size: Option<PacketSize>,
}
impl From<TrafficV2> for TrafficV3 {
fn from(value: TrafficV2) -> Self {
TrafficV3 {
impl From<TrafficV1_1_20> for TrafficV1_1_20_2 {
fn from(value: TrafficV1_1_20) -> Self {
TrafficV1_1_20_2 {
average_packet_delay: value.average_packet_delay,
message_sending_average_delay: value.message_sending_average_delay,
disable_main_poisson_packet_distribution: value
@@ -151,9 +138,9 @@ impl From<TrafficV2> for TrafficV3 {
}
}
impl Default for TrafficV2 {
impl Default for TrafficV1_1_20 {
fn default() -> Self {
TrafficV2 {
TrafficV1_1_20 {
average_packet_delay: DEFAULT_AVERAGE_PACKET_DELAY,
message_sending_average_delay: DEFAULT_MESSAGE_STREAM_AVERAGE_DELAY,
disable_main_poisson_packet_distribution: false,
@@ -165,16 +152,16 @@ impl Default for TrafficV2 {
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
#[serde(default, deny_unknown_fields)]
pub struct CoverTrafficV2 {
pub struct CoverTrafficV1_1_20 {
#[serde(with = "humantime_serde")]
pub loop_cover_traffic_average_delay: Duration,
pub cover_traffic_primary_size_ratio: f64,
pub disable_loop_cover_traffic_stream: bool,
}
impl From<CoverTrafficV2> for CoverTrafficV3 {
fn from(value: CoverTrafficV2) -> Self {
CoverTrafficV3 {
impl From<CoverTrafficV1_1_20> for CoverTrafficV1_1_20_2 {
fn from(value: CoverTrafficV1_1_20) -> Self {
CoverTrafficV1_1_20_2 {
loop_cover_traffic_average_delay: value.loop_cover_traffic_average_delay,
cover_traffic_primary_size_ratio: value.cover_traffic_primary_size_ratio,
disable_loop_cover_traffic_stream: value.disable_loop_cover_traffic_stream,
@@ -182,9 +169,9 @@ impl From<CoverTrafficV2> for CoverTrafficV3 {
}
}
impl Default for CoverTrafficV2 {
impl Default for CoverTrafficV1_1_20 {
fn default() -> Self {
CoverTrafficV2 {
CoverTrafficV1_1_20 {
loop_cover_traffic_average_delay: DEFAULT_LOOP_COVER_STREAM_AVERAGE_DELAY,
cover_traffic_primary_size_ratio: DEFAULT_COVER_TRAFFIC_PRIMARY_SIZE_RATIO,
disable_loop_cover_traffic_stream: false,
@@ -194,22 +181,22 @@ impl Default for CoverTrafficV2 {
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
#[serde(default, deny_unknown_fields)]
pub struct GatewayConnectionV2 {
pub struct GatewayConnectionV1_1_20 {
#[serde(with = "humantime_serde")]
pub gateway_response_timeout: Duration,
}
impl From<GatewayConnectionV2> for GatewayConnectionV3 {
fn from(value: GatewayConnectionV2) -> Self {
GatewayConnectionV3 {
impl From<GatewayConnectionV1_1_20> for GatewayConnectionV1_1_20_2 {
fn from(value: GatewayConnectionV1_1_20) -> Self {
GatewayConnectionV1_1_20_2 {
gateway_response_timeout: value.gateway_response_timeout,
}
}
}
impl Default for GatewayConnectionV2 {
impl Default for GatewayConnectionV1_1_20 {
fn default() -> Self {
GatewayConnectionV2 {
GatewayConnectionV1_1_20 {
gateway_response_timeout: DEFAULT_GATEWAY_RESPONSE_TIMEOUT,
}
}
@@ -217,7 +204,7 @@ impl Default for GatewayConnectionV2 {
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
#[serde(default, deny_unknown_fields)]
pub struct AcknowledgementsV2 {
pub struct AcknowledgementsV1_1_20 {
#[serde(with = "humantime_serde")]
pub average_ack_delay: Duration,
pub ack_wait_multiplier: f64,
@@ -225,9 +212,9 @@ pub struct AcknowledgementsV2 {
pub ack_wait_addition: Duration,
}
impl From<AcknowledgementsV2> for AcknowledgementsV3 {
fn from(value: AcknowledgementsV2) -> Self {
AcknowledgementsV3 {
impl From<AcknowledgementsV1_1_20> for AcknowledgementsV1_1_20_2 {
fn from(value: AcknowledgementsV1_1_20) -> Self {
AcknowledgementsV1_1_20_2 {
average_ack_delay: value.average_ack_delay,
ack_wait_multiplier: value.ack_wait_multiplier,
ack_wait_addition: value.ack_wait_addition,
@@ -235,9 +222,9 @@ impl From<AcknowledgementsV2> for AcknowledgementsV3 {
}
}
impl Default for AcknowledgementsV2 {
impl Default for AcknowledgementsV1_1_20 {
fn default() -> Self {
AcknowledgementsV2 {
AcknowledgementsV1_1_20 {
average_ack_delay: DEFAULT_AVERAGE_PACKET_DELAY,
ack_wait_multiplier: DEFAULT_ACK_WAIT_MULTIPLIER,
ack_wait_addition: DEFAULT_ACK_WAIT_ADDITION,
@@ -247,7 +234,7 @@ impl Default for AcknowledgementsV2 {
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
#[serde(default, deny_unknown_fields)]
pub struct TopologyV2 {
pub struct TopologyV1_1_20 {
#[serde(with = "humantime_serde")]
pub topology_refresh_rate: Duration,
#[serde(with = "humantime_serde")]
@@ -255,9 +242,9 @@ pub struct TopologyV2 {
pub disable_refreshing: bool,
}
impl From<TopologyV2> for TopologyV3 {
fn from(value: TopologyV2) -> Self {
TopologyV3 {
impl From<TopologyV1_1_20> for TopologyV1_1_20_2 {
fn from(value: TopologyV1_1_20) -> Self {
TopologyV1_1_20_2 {
topology_refresh_rate: value.topology_refresh_rate,
topology_resolution_timeout: value.topology_resolution_timeout,
disable_refreshing: value.disable_refreshing,
@@ -265,9 +252,9 @@ impl From<TopologyV2> for TopologyV3 {
}
}
impl Default for TopologyV2 {
impl Default for TopologyV1_1_20 {
fn default() -> Self {
TopologyV2 {
TopologyV1_1_20 {
topology_refresh_rate: DEFAULT_TOPOLOGY_REFRESH_RATE,
topology_resolution_timeout: DEFAULT_TOPOLOGY_RESOLUTION_TIMEOUT,
disable_refreshing: false,
@@ -277,7 +264,7 @@ impl Default for TopologyV2 {
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
#[serde(default, deny_unknown_fields)]
pub struct ReplySurbsV2 {
pub struct ReplySurbsV1_1_20 {
pub minimum_reply_surb_storage_threshold: usize,
pub maximum_reply_surb_storage_threshold: usize,
pub minimum_reply_surb_request_size: u32,
@@ -293,9 +280,9 @@ pub struct ReplySurbsV2 {
pub maximum_reply_key_age: Duration,
}
impl From<ReplySurbsV2> for ReplySurbsV3 {
fn from(value: ReplySurbsV2) -> Self {
ReplySurbsV3 {
impl From<ReplySurbsV1_1_20> for ReplySurbsV1_1_20_2 {
fn from(value: ReplySurbsV1_1_20) -> Self {
ReplySurbsV1_1_20_2 {
minimum_reply_surb_storage_threshold: value.minimum_reply_surb_storage_threshold,
maximum_reply_surb_storage_threshold: value.maximum_reply_surb_storage_threshold,
minimum_reply_surb_request_size: value.minimum_reply_surb_request_size,
@@ -310,9 +297,9 @@ impl From<ReplySurbsV2> for ReplySurbsV3 {
}
}
impl Default for ReplySurbsV2 {
impl Default for ReplySurbsV1_1_20 {
fn default() -> Self {
ReplySurbsV2 {
ReplySurbsV1_1_20 {
minimum_reply_surb_storage_threshold: DEFAULT_MINIMUM_REPLY_SURB_STORAGE_THRESHOLD,
maximum_reply_surb_storage_threshold: DEFAULT_MAXIMUM_REPLY_SURB_STORAGE_THRESHOLD,
minimum_reply_surb_request_size: DEFAULT_MINIMUM_REPLY_SURB_REQUEST_SIZE,
@@ -329,18 +316,18 @@ impl Default for ReplySurbsV2 {
#[derive(Debug, Default, Clone, Copy, Deserialize, PartialEq, Serialize)]
#[serde(default, deny_unknown_fields)]
pub struct DebugConfigV2 {
pub traffic: TrafficV2,
pub cover_traffic: CoverTrafficV2,
pub gateway_connection: GatewayConnectionV2,
pub acknowledgements: AcknowledgementsV2,
pub topology: TopologyV2,
pub reply_surbs: ReplySurbsV2,
pub struct DebugConfigV1_1_20 {
pub traffic: TrafficV1_1_20,
pub cover_traffic: CoverTrafficV1_1_20,
pub gateway_connection: GatewayConnectionV1_1_20,
pub acknowledgements: AcknowledgementsV1_1_20,
pub topology: TopologyV1_1_20,
pub reply_surbs: ReplySurbsV1_1_20,
}
impl From<DebugConfigV2> for DebugConfigV3 {
fn from(value: DebugConfigV2) -> Self {
DebugConfigV3 {
impl From<DebugConfigV1_1_20> for DebugConfigV1_1_20_2 {
fn from(value: DebugConfigV1_1_20) -> Self {
DebugConfigV1_1_20_2 {
traffic: value.traffic.into(),
cover_traffic: value.cover_traffic.into(),
gateway_connection: value.gateway_connection.into(),
@@ -1,12 +1,12 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::old::v4::{
AcknowledgementsV4, ClientV4, ConfigV4, CoverTrafficV4, DebugConfigV4, GatewayConnectionV4,
ReplySurbsV4, TopologyV4, TrafficV4,
use crate::config::old_config_v1_1_30::{
AcknowledgementsV1_1_30, ClientV1_1_30, ConfigV1_1_30, CoverTrafficV1_1_30, DebugConfigV1_1_30,
GatewayConnectionV1_1_30, ReplySurbsV1_1_30, TopologyV1_1_30, TrafficV1_1_30,
};
use crate::old::v5::GatewayEndpointConfigV5;
use nym_sphinx_params::{PacketSize, PacketType};
use crate::config::old_config_v1_1_33::OldGatewayEndpointConfigV1_1_33;
use nym_sphinx::params::{PacketSize, PacketType};
use serde::{Deserialize, Serialize};
use std::time::Duration;
use url::Url;
@@ -50,31 +50,18 @@ const DEFAULT_MAXIMUM_REPLY_SURB_AGE: Duration = Duration::from_secs(12 * 60 * 6
// 24 hours
const DEFAULT_MAXIMUM_REPLY_KEY_AGE: Duration = Duration::from_secs(24 * 60 * 60);
// aliases for backwards compatibility
pub type ConfigV1_1_20_2 = ConfigV3;
pub type ClientV1_1_20_2 = ClientV3;
pub type DebugConfigV1_1_20_2 = DebugConfigV3;
pub type GatewayEndpointConfigV1_1_20_2 = GatewayEndpointConfigV3;
pub type TrafficV1_1_20_2 = TrafficV3;
pub type CoverTrafficV1_1_20_2 = CoverTrafficV3;
pub type GatewayConnectionV1_1_20_2 = GatewayConnectionV3;
pub type AcknowledgementsV1_1_20_2 = AcknowledgementsV3;
pub type TopologyV1_1_20_2 = TopologyV3;
pub type ReplySurbsV1_1_20_2 = ReplySurbsV3;
#[derive(Debug, Clone, Deserialize, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct ConfigV3 {
pub client: ClientV3,
pub struct ConfigV1_1_20_2 {
pub client: ClientV1_1_20_2,
#[serde(default)]
pub debug: DebugConfigV3,
pub debug: DebugConfigV1_1_20_2,
}
impl From<ConfigV3> for ConfigV4 {
fn from(value: ConfigV3) -> Self {
ConfigV4 {
impl From<ConfigV1_1_20_2> for ConfigV1_1_30 {
fn from(value: ConfigV1_1_20_2) -> Self {
ConfigV1_1_30 {
client: value.client.into(),
debug: value.debug.into(),
}
@@ -82,7 +69,7 @@ impl From<ConfigV3> for ConfigV4 {
}
#[derive(Clone, Debug, Default, Deserialize, PartialEq, Eq, Serialize)]
pub struct GatewayEndpointConfigV3 {
pub struct GatewayEndpointConfigV1_1_20_2 {
/// gateway_id specifies ID of the gateway to which the client should send messages.
/// If initially omitted, a random gateway will be chosen from the available topology.
pub gateway_id: String,
@@ -94,9 +81,9 @@ pub struct GatewayEndpointConfigV3 {
pub gateway_listener: String,
}
impl From<GatewayEndpointConfigV3> for GatewayEndpointConfigV5 {
fn from(value: GatewayEndpointConfigV3) -> Self {
GatewayEndpointConfigV5 {
impl From<GatewayEndpointConfigV1_1_20_2> for OldGatewayEndpointConfigV1_1_33 {
fn from(value: GatewayEndpointConfigV1_1_20_2) -> Self {
OldGatewayEndpointConfigV1_1_33 {
gateway_id: value.gateway_id,
gateway_owner: value.gateway_owner,
gateway_listener: value.gateway_listener,
@@ -105,7 +92,7 @@ impl From<GatewayEndpointConfigV3> for GatewayEndpointConfigV5 {
}
#[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)]
pub struct ClientV3 {
pub struct ClientV1_1_20_2 {
pub version: String,
pub id: String,
@@ -118,12 +105,12 @@ pub struct ClientV3 {
#[serde(alias = "validator_api_urls")]
pub nym_api_urls: Vec<Url>,
pub gateway_endpoint: GatewayEndpointConfigV3,
pub gateway_endpoint: GatewayEndpointConfigV1_1_20_2,
}
impl From<ClientV3> for ClientV4 {
fn from(value: ClientV3) -> Self {
ClientV4 {
impl From<ClientV1_1_20_2> for ClientV1_1_30 {
fn from(value: ClientV1_1_20_2) -> Self {
ClientV1_1_30 {
version: value.version,
id: value.id,
disabled_credentials_mode: value.disabled_credentials_mode,
@@ -135,7 +122,7 @@ impl From<ClientV3> for ClientV4 {
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
#[serde(default)]
pub struct TrafficV3 {
pub struct TrafficV1_1_20_2 {
#[serde(with = "humantime_serde")]
pub average_packet_delay: Duration,
#[serde(with = "humantime_serde")]
@@ -146,9 +133,9 @@ pub struct TrafficV3 {
pub packet_type: PacketType,
}
impl From<TrafficV3> for TrafficV4 {
fn from(value: TrafficV3) -> Self {
TrafficV4 {
impl From<TrafficV1_1_20_2> for TrafficV1_1_30 {
fn from(value: TrafficV1_1_20_2) -> Self {
TrafficV1_1_30 {
average_packet_delay: value.average_packet_delay,
message_sending_average_delay: value.message_sending_average_delay,
disable_main_poisson_packet_distribution: value
@@ -160,9 +147,9 @@ impl From<TrafficV3> for TrafficV4 {
}
}
impl Default for TrafficV3 {
impl Default for TrafficV1_1_20_2 {
fn default() -> Self {
TrafficV3 {
TrafficV1_1_20_2 {
average_packet_delay: DEFAULT_AVERAGE_PACKET_DELAY,
message_sending_average_delay: DEFAULT_MESSAGE_STREAM_AVERAGE_DELAY,
disable_main_poisson_packet_distribution: false,
@@ -175,16 +162,16 @@ impl Default for TrafficV3 {
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
#[serde(default, deny_unknown_fields)]
pub struct CoverTrafficV3 {
pub struct CoverTrafficV1_1_20_2 {
#[serde(with = "humantime_serde")]
pub loop_cover_traffic_average_delay: Duration,
pub cover_traffic_primary_size_ratio: f64,
pub disable_loop_cover_traffic_stream: bool,
}
impl From<CoverTrafficV3> for CoverTrafficV4 {
fn from(value: CoverTrafficV3) -> Self {
CoverTrafficV4 {
impl From<CoverTrafficV1_1_20_2> for CoverTrafficV1_1_30 {
fn from(value: CoverTrafficV1_1_20_2) -> Self {
CoverTrafficV1_1_30 {
loop_cover_traffic_average_delay: value.loop_cover_traffic_average_delay,
cover_traffic_primary_size_ratio: value.cover_traffic_primary_size_ratio,
disable_loop_cover_traffic_stream: value.disable_loop_cover_traffic_stream,
@@ -192,9 +179,9 @@ impl From<CoverTrafficV3> for CoverTrafficV4 {
}
}
impl Default for CoverTrafficV3 {
impl Default for CoverTrafficV1_1_20_2 {
fn default() -> Self {
CoverTrafficV3 {
CoverTrafficV1_1_20_2 {
loop_cover_traffic_average_delay: DEFAULT_LOOP_COVER_STREAM_AVERAGE_DELAY,
cover_traffic_primary_size_ratio: DEFAULT_COVER_TRAFFIC_PRIMARY_SIZE_RATIO,
disable_loop_cover_traffic_stream: false,
@@ -204,22 +191,22 @@ impl Default for CoverTrafficV3 {
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
#[serde(default, deny_unknown_fields)]
pub struct GatewayConnectionV3 {
pub struct GatewayConnectionV1_1_20_2 {
#[serde(with = "humantime_serde")]
pub gateway_response_timeout: Duration,
}
impl From<GatewayConnectionV3> for GatewayConnectionV4 {
fn from(value: GatewayConnectionV3) -> Self {
GatewayConnectionV4 {
impl From<GatewayConnectionV1_1_20_2> for GatewayConnectionV1_1_30 {
fn from(value: GatewayConnectionV1_1_20_2) -> Self {
GatewayConnectionV1_1_30 {
gateway_response_timeout: value.gateway_response_timeout,
}
}
}
impl Default for GatewayConnectionV3 {
impl Default for GatewayConnectionV1_1_20_2 {
fn default() -> Self {
GatewayConnectionV3 {
GatewayConnectionV1_1_20_2 {
gateway_response_timeout: DEFAULT_GATEWAY_RESPONSE_TIMEOUT,
}
}
@@ -227,7 +214,7 @@ impl Default for GatewayConnectionV3 {
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
#[serde(default, deny_unknown_fields)]
pub struct AcknowledgementsV3 {
pub struct AcknowledgementsV1_1_20_2 {
#[serde(with = "humantime_serde")]
pub average_ack_delay: Duration,
pub ack_wait_multiplier: f64,
@@ -235,9 +222,9 @@ pub struct AcknowledgementsV3 {
pub ack_wait_addition: Duration,
}
impl From<AcknowledgementsV3> for AcknowledgementsV4 {
fn from(value: AcknowledgementsV3) -> Self {
AcknowledgementsV4 {
impl From<AcknowledgementsV1_1_20_2> for AcknowledgementsV1_1_30 {
fn from(value: AcknowledgementsV1_1_20_2) -> Self {
AcknowledgementsV1_1_30 {
average_ack_delay: value.average_ack_delay,
ack_wait_multiplier: value.ack_wait_multiplier,
ack_wait_addition: value.ack_wait_addition,
@@ -245,9 +232,9 @@ impl From<AcknowledgementsV3> for AcknowledgementsV4 {
}
}
impl Default for AcknowledgementsV3 {
impl Default for AcknowledgementsV1_1_20_2 {
fn default() -> Self {
AcknowledgementsV3 {
AcknowledgementsV1_1_20_2 {
average_ack_delay: DEFAULT_AVERAGE_PACKET_DELAY,
ack_wait_multiplier: DEFAULT_ACK_WAIT_MULTIPLIER,
ack_wait_addition: DEFAULT_ACK_WAIT_ADDITION,
@@ -257,7 +244,7 @@ impl Default for AcknowledgementsV3 {
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
#[serde(default, deny_unknown_fields)]
pub struct TopologyV3 {
pub struct TopologyV1_1_20_2 {
#[serde(with = "humantime_serde")]
pub topology_refresh_rate: Duration,
#[serde(with = "humantime_serde")]
@@ -265,9 +252,9 @@ pub struct TopologyV3 {
pub disable_refreshing: bool,
}
impl Default for TopologyV3 {
impl Default for TopologyV1_1_20_2 {
fn default() -> Self {
TopologyV3 {
TopologyV1_1_20_2 {
topology_refresh_rate: DEFAULT_TOPOLOGY_REFRESH_RATE,
topology_resolution_timeout: DEFAULT_TOPOLOGY_RESOLUTION_TIMEOUT,
disable_refreshing: false,
@@ -275,9 +262,9 @@ impl Default for TopologyV3 {
}
}
impl From<TopologyV3> for TopologyV4 {
fn from(value: TopologyV3) -> Self {
TopologyV4 {
impl From<TopologyV1_1_20_2> for TopologyV1_1_30 {
fn from(value: TopologyV1_1_20_2) -> Self {
TopologyV1_1_30 {
topology_refresh_rate: value.topology_refresh_rate,
topology_resolution_timeout: value.topology_resolution_timeout,
disable_refreshing: value.disable_refreshing,
@@ -288,7 +275,7 @@ impl From<TopologyV3> for TopologyV4 {
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
#[serde(default, deny_unknown_fields)]
pub struct ReplySurbsV3 {
pub struct ReplySurbsV1_1_20_2 {
pub minimum_reply_surb_storage_threshold: usize,
pub maximum_reply_surb_storage_threshold: usize,
pub minimum_reply_surb_request_size: u32,
@@ -304,9 +291,9 @@ pub struct ReplySurbsV3 {
pub maximum_reply_key_age: Duration,
}
impl Default for ReplySurbsV3 {
impl Default for ReplySurbsV1_1_20_2 {
fn default() -> Self {
ReplySurbsV3 {
ReplySurbsV1_1_20_2 {
minimum_reply_surb_storage_threshold: DEFAULT_MINIMUM_REPLY_SURB_STORAGE_THRESHOLD,
maximum_reply_surb_storage_threshold: DEFAULT_MAXIMUM_REPLY_SURB_STORAGE_THRESHOLD,
minimum_reply_surb_request_size: DEFAULT_MINIMUM_REPLY_SURB_REQUEST_SIZE,
@@ -321,9 +308,9 @@ impl Default for ReplySurbsV3 {
}
}
impl From<ReplySurbsV3> for ReplySurbsV4 {
fn from(value: ReplySurbsV3) -> Self {
ReplySurbsV4 {
impl From<ReplySurbsV1_1_20_2> for ReplySurbsV1_1_30 {
fn from(value: ReplySurbsV1_1_20_2) -> Self {
ReplySurbsV1_1_30 {
minimum_reply_surb_storage_threshold: value.minimum_reply_surb_storage_threshold,
maximum_reply_surb_storage_threshold: value.maximum_reply_surb_storage_threshold,
minimum_reply_surb_request_size: value.minimum_reply_surb_request_size,
@@ -340,18 +327,18 @@ impl From<ReplySurbsV3> for ReplySurbsV4 {
#[derive(Debug, Default, Clone, Copy, Deserialize, PartialEq, Serialize)]
#[serde(default, deny_unknown_fields)]
pub struct DebugConfigV3 {
pub traffic: TrafficV3,
pub cover_traffic: CoverTrafficV3,
pub gateway_connection: GatewayConnectionV3,
pub acknowledgements: AcknowledgementsV3,
pub topology: TopologyV3,
pub reply_surbs: ReplySurbsV3,
pub struct DebugConfigV1_1_20_2 {
pub traffic: TrafficV1_1_20_2,
pub cover_traffic: CoverTrafficV1_1_20_2,
pub gateway_connection: GatewayConnectionV1_1_20_2,
pub acknowledgements: AcknowledgementsV1_1_20_2,
pub topology: TopologyV1_1_20_2,
pub reply_surbs: ReplySurbsV1_1_20_2,
}
impl From<DebugConfigV3> for DebugConfigV4 {
fn from(value: DebugConfigV3) -> Self {
DebugConfigV4 {
impl From<DebugConfigV1_1_20_2> for DebugConfigV1_1_30 {
fn from(value: DebugConfigV1_1_20_2) -> Self {
DebugConfigV1_1_30 {
traffic: value.traffic.into(),
cover_traffic: value.cover_traffic.into(),
gateway_connection: value.gateway_connection.into(),
@@ -1,13 +1,16 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::old::v5::{
AcknowledgementsV5, ClientV5, ConfigV5, CoverTrafficV5, DebugConfigV5, GatewayConnectionV5,
GroupByV5, ReplySurbsV5, TopologyStructureV5, TopologyV5, TrafficV5,
use crate::client::topology_control::geo_aware_provider::CountryGroup;
use crate::config::old_config_v1_1_33::{
AcknowledgementsV1_1_33, ClientV1_1_33, ConfigV1_1_33, CoverTrafficV1_1_33, DebugConfigV1_1_33,
GatewayConnectionV1_1_33, GroupByV1_1_33, ReplySurbsV1_1_33, TopologyStructureV1_1_33,
TopologyV1_1_33, TrafficV1_1_33,
};
use nym_sphinx::{
addressing::clients::Recipient,
params::{PacketSize, PacketType},
};
use crate::CountryGroup;
use nym_sphinx_addressing::Recipient;
use nym_sphinx_params::{PacketSize, PacketType};
use serde::{Deserialize, Serialize};
use std::time::Duration;
use url::Url;
@@ -53,39 +56,27 @@ const DEFAULT_MAXIMUM_REPLY_SURB_AGE: Duration = Duration::from_secs(12 * 60 * 6
// 24 hours
const DEFAULT_MAXIMUM_REPLY_KEY_AGE: Duration = Duration::from_secs(24 * 60 * 60);
// aliases for backwards compatibility
pub type ConfigV1_1_30 = ConfigV4;
pub type ClientV1_1_30 = ClientV4;
pub type DebugConfigV1_1_30 = DebugConfigV4;
pub type TrafficV1_1_30 = TrafficV4;
pub type CoverTrafficV1_1_30 = CoverTrafficV4;
pub type GatewayConnectionV1_1_30 = GatewayConnectionV4;
pub type AcknowledgementsV1_1_30 = AcknowledgementsV4;
pub type TopologyV1_1_30 = TopologyV4;
pub type ReplySurbsV1_1_30 = ReplySurbsV4;
#[derive(Debug, Clone, Deserialize, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct ConfigV4 {
pub client: ClientV4,
pub struct ConfigV1_1_30 {
pub client: ClientV1_1_30,
#[serde(default)]
pub debug: DebugConfigV4,
pub debug: DebugConfigV1_1_30,
}
impl From<ConfigV4> for ConfigV5 {
fn from(value: ConfigV4) -> Self {
ConfigV5 {
client: ClientV5 {
impl From<ConfigV1_1_30> for ConfigV1_1_33 {
fn from(value: ConfigV1_1_30) -> Self {
ConfigV1_1_33 {
client: ClientV1_1_33 {
version: value.client.version,
id: value.client.id,
disabled_credentials_mode: value.client.disabled_credentials_mode,
nyxd_urls: value.client.nyxd_urls,
nym_api_urls: value.client.nym_api_urls,
},
debug: DebugConfigV5 {
traffic: TrafficV5 {
debug: DebugConfigV1_1_33 {
traffic: TrafficV1_1_33 {
average_packet_delay: value.debug.traffic.average_packet_delay,
message_sending_average_delay: value
.debug
@@ -99,7 +90,7 @@ impl From<ConfigV4> for ConfigV5 {
secondary_packet_size: value.debug.traffic.secondary_packet_size,
packet_type: value.debug.traffic.packet_type,
},
cover_traffic: CoverTrafficV5 {
cover_traffic: CoverTrafficV1_1_33 {
loop_cover_traffic_average_delay: value
.debug
.cover_traffic
@@ -113,18 +104,18 @@ impl From<ConfigV4> for ConfigV5 {
.cover_traffic
.disable_loop_cover_traffic_stream,
},
gateway_connection: GatewayConnectionV5 {
gateway_connection: GatewayConnectionV1_1_33 {
gateway_response_timeout: value
.debug
.gateway_connection
.gateway_response_timeout,
},
acknowledgements: AcknowledgementsV5 {
acknowledgements: AcknowledgementsV1_1_33 {
average_ack_delay: value.debug.acknowledgements.average_ack_delay,
ack_wait_multiplier: value.debug.acknowledgements.ack_wait_multiplier,
ack_wait_addition: value.debug.acknowledgements.ack_wait_addition,
},
topology: TopologyV5 {
topology: TopologyV1_1_33 {
topology_refresh_rate: value.debug.topology.topology_refresh_rate,
topology_resolution_timeout: value.debug.topology.topology_resolution_timeout,
disable_refreshing: value.debug.topology.disable_refreshing,
@@ -134,7 +125,7 @@ impl From<ConfigV4> for ConfigV5 {
.max_startup_gateway_waiting_period,
topology_structure: value.debug.topology.topology_structure.into(),
},
reply_surbs: ReplySurbsV5 {
reply_surbs: ReplySurbsV1_1_33 {
minimum_reply_surb_storage_threshold: value
.debug
.reply_surbs
@@ -178,7 +169,7 @@ impl From<ConfigV4> for ConfigV5 {
#[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)]
// note: the deny_unknown_fields is VITAL here to allow upgrades from v1.1.20_2
#[serde(deny_unknown_fields)]
pub struct ClientV4 {
pub struct ClientV1_1_30 {
/// Version of the client for which this configuration was created.
pub version: String,
@@ -202,7 +193,7 @@ pub struct ClientV4 {
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
#[serde(default, deny_unknown_fields)]
pub struct TrafficV4 {
pub struct TrafficV1_1_30 {
/// The parameter of Poisson distribution determining how long, on average,
/// sent packet is going to be delayed at any given mix node.
/// So for a packet going through three mix nodes, on average, it will take three times this value
@@ -233,9 +224,9 @@ pub struct TrafficV4 {
pub packet_type: PacketType,
}
impl Default for TrafficV4 {
impl Default for TrafficV1_1_30 {
fn default() -> Self {
TrafficV4 {
TrafficV1_1_30 {
average_packet_delay: DEFAULT_AVERAGE_PACKET_DELAY,
message_sending_average_delay: DEFAULT_MESSAGE_STREAM_AVERAGE_DELAY,
disable_main_poisson_packet_distribution: false,
@@ -248,7 +239,7 @@ impl Default for TrafficV4 {
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
#[serde(default, deny_unknown_fields)]
pub struct CoverTrafficV4 {
pub struct CoverTrafficV1_1_30 {
/// The parameter of Poisson distribution determining how long, on average,
/// it is going to take for another loop cover traffic message to be sent.
#[serde(with = "humantime_serde")]
@@ -263,9 +254,9 @@ pub struct CoverTrafficV4 {
pub disable_loop_cover_traffic_stream: bool,
}
impl Default for CoverTrafficV4 {
impl Default for CoverTrafficV1_1_30 {
fn default() -> Self {
CoverTrafficV4 {
CoverTrafficV1_1_30 {
loop_cover_traffic_average_delay: DEFAULT_LOOP_COVER_STREAM_AVERAGE_DELAY,
cover_traffic_primary_size_ratio: DEFAULT_COVER_TRAFFIC_PRIMARY_SIZE_RATIO,
disable_loop_cover_traffic_stream: false,
@@ -275,16 +266,16 @@ impl Default for CoverTrafficV4 {
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
#[serde(default, deny_unknown_fields)]
pub struct GatewayConnectionV4 {
pub struct GatewayConnectionV1_1_30 {
/// How long we're willing to wait for a response to a message sent to the gateway,
/// before giving up on it.
#[serde(with = "humantime_serde")]
pub gateway_response_timeout: Duration,
}
impl Default for GatewayConnectionV4 {
impl Default for GatewayConnectionV1_1_30 {
fn default() -> Self {
GatewayConnectionV4 {
GatewayConnectionV1_1_30 {
gateway_response_timeout: DEFAULT_GATEWAY_RESPONSE_TIMEOUT,
}
}
@@ -292,7 +283,7 @@ impl Default for GatewayConnectionV4 {
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
#[serde(default, deny_unknown_fields)]
pub struct AcknowledgementsV4 {
pub struct AcknowledgementsV1_1_30 {
/// The parameter of Poisson distribution determining how long, on average,
/// sent acknowledgement is going to be delayed at any given mix node.
/// So for an ack going through three mix nodes, on average, it will take three times this value
@@ -312,9 +303,9 @@ pub struct AcknowledgementsV4 {
pub ack_wait_addition: Duration,
}
impl Default for AcknowledgementsV4 {
impl Default for AcknowledgementsV1_1_30 {
fn default() -> Self {
AcknowledgementsV4 {
AcknowledgementsV1_1_30 {
average_ack_delay: DEFAULT_AVERAGE_PACKET_DELAY,
ack_wait_multiplier: DEFAULT_ACK_WAIT_MULTIPLIER,
ack_wait_addition: DEFAULT_ACK_WAIT_ADDITION,
@@ -324,7 +315,7 @@ impl Default for AcknowledgementsV4 {
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
#[serde(default, deny_unknown_fields)]
pub struct TopologyV4 {
pub struct TopologyV1_1_30 {
/// The uniform delay every which clients are querying the directory server
/// to try to obtain a compatible network topology to send sphinx packets through.
#[serde(with = "humantime_serde")]
@@ -347,23 +338,23 @@ pub struct TopologyV4 {
pub max_startup_gateway_waiting_period: Duration,
/// Specifies the mixnode topology to be used for sending packets.
pub topology_structure: TopologyStructureV4,
pub topology_structure: TopologyStructureV1_1_30,
}
#[allow(clippy::large_enum_variant)]
#[derive(Default, Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum TopologyStructureV4 {
pub enum TopologyStructureV1_1_30 {
#[default]
NymApi,
GeoAware(GroupByV4),
GeoAware(GroupByV1_1_30),
}
impl From<TopologyStructureV4> for TopologyStructureV5 {
fn from(value: TopologyStructureV4) -> Self {
impl From<TopologyStructureV1_1_30> for TopologyStructureV1_1_33 {
fn from(value: TopologyStructureV1_1_30) -> Self {
match value {
TopologyStructureV4::NymApi => TopologyStructureV5::NymApi,
TopologyStructureV4::GeoAware(group_by) => {
TopologyStructureV5::GeoAware(group_by.into())
TopologyStructureV1_1_30::NymApi => TopologyStructureV1_1_33::NymApi,
TopologyStructureV1_1_30::GeoAware(group_by) => {
TopologyStructureV1_1_33::GeoAware(group_by.into())
}
}
}
@@ -371,44 +362,44 @@ impl From<TopologyStructureV4> for TopologyStructureV5 {
#[allow(clippy::large_enum_variant)]
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum GroupByV4 {
pub enum GroupByV1_1_30 {
CountryGroup(CountryGroup),
NymAddress(Recipient),
}
impl From<GroupByV4> for GroupByV5 {
fn from(value: GroupByV4) -> Self {
impl From<GroupByV1_1_30> for GroupByV1_1_33 {
fn from(value: GroupByV1_1_30) -> Self {
match value {
GroupByV4::CountryGroup(country) => GroupByV5::CountryGroup(country),
GroupByV4::NymAddress(addr) => GroupByV5::NymAddress(addr),
GroupByV1_1_30::CountryGroup(country) => GroupByV1_1_33::CountryGroup(country),
GroupByV1_1_30::NymAddress(addr) => GroupByV1_1_33::NymAddress(addr),
}
}
}
impl std::fmt::Display for GroupByV4 {
impl std::fmt::Display for GroupByV1_1_30 {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
GroupByV4::CountryGroup(group) => write!(f, "group: {}", group),
GroupByV4::NymAddress(address) => write!(f, "address: {}", address),
GroupByV1_1_30::CountryGroup(group) => write!(f, "group: {}", group),
GroupByV1_1_30::NymAddress(address) => write!(f, "address: {}", address),
}
}
}
impl Default for TopologyV4 {
impl Default for TopologyV1_1_30 {
fn default() -> Self {
TopologyV4 {
TopologyV1_1_30 {
topology_refresh_rate: DEFAULT_TOPOLOGY_REFRESH_RATE,
topology_resolution_timeout: DEFAULT_TOPOLOGY_RESOLUTION_TIMEOUT,
disable_refreshing: false,
max_startup_gateway_waiting_period: DEFAULT_MAX_STARTUP_GATEWAY_WAITING_PERIOD,
topology_structure: TopologyStructureV4::default(),
topology_structure: TopologyStructureV1_1_30::default(),
}
}
}
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
#[serde(default, deny_unknown_fields)]
pub struct ReplySurbsV4 {
pub struct ReplySurbsV1_1_30 {
/// Defines the minimum number of reply surbs the client wants to keep in its storage at all times.
/// It can only allow to go below that value if its to request additional reply surbs.
pub minimum_reply_surb_storage_threshold: usize,
@@ -446,9 +437,9 @@ pub struct ReplySurbsV4 {
pub maximum_reply_key_age: Duration,
}
impl Default for ReplySurbsV4 {
impl Default for ReplySurbsV1_1_30 {
fn default() -> Self {
ReplySurbsV4 {
ReplySurbsV1_1_30 {
minimum_reply_surb_storage_threshold: DEFAULT_MINIMUM_REPLY_SURB_STORAGE_THRESHOLD,
maximum_reply_surb_storage_threshold: DEFAULT_MAXIMUM_REPLY_SURB_STORAGE_THRESHOLD,
minimum_reply_surb_request_size: DEFAULT_MINIMUM_REPLY_SURB_REQUEST_SIZE,
@@ -465,22 +456,22 @@ impl Default for ReplySurbsV4 {
#[derive(Debug, Default, Clone, Copy, Deserialize, PartialEq, Serialize)]
#[serde(default, deny_unknown_fields)]
pub struct DebugConfigV4 {
pub struct DebugConfigV1_1_30 {
/// Defines all configuration options related to traffic streams.
pub traffic: TrafficV4,
pub traffic: TrafficV1_1_30,
/// Defines all configuration options related to cover traffic stream(s).
pub cover_traffic: CoverTrafficV4,
pub cover_traffic: CoverTrafficV1_1_30,
/// Defines all configuration options related to the gateway connection.
pub gateway_connection: GatewayConnectionV4,
pub gateway_connection: GatewayConnectionV1_1_30,
/// Defines all configuration options related to acknowledgements, such as delays or wait timeouts.
pub acknowledgements: AcknowledgementsV4,
pub acknowledgements: AcknowledgementsV1_1_30,
/// Defines all configuration options related topology, such as refresh rates or timeouts.
pub topology: TopologyV4,
pub topology: TopologyV1_1_30,
/// Defines all configuration options related to reply SURBs.
pub reply_surbs: ReplySurbsV4,
pub reply_surbs: ReplySurbsV1_1_30,
}
@@ -1,12 +1,15 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::{
Acknowledgements, Client, Config, CountryGroup, CoverTraffic, DebugConfig, GatewayConnection,
GroupBy, ReplySurbs, Topology, TopologyStructure, Traffic,
use crate::client::topology_control::geo_aware_provider::CountryGroup;
use crate::config::{
Acknowledgements, Client, Config, CoverTraffic, DebugConfig, GatewayConnection, GroupBy,
ReplySurbs, Topology, TopologyStructure, Traffic,
};
use nym_sphinx::{
addressing::clients::Recipient,
params::{PacketSize, PacketType},
};
use nym_sphinx_addressing::Recipient;
use nym_sphinx_params::{PacketSize, PacketType};
use serde::{Deserialize, Serialize};
use std::time::Duration;
use url::Url;
@@ -52,21 +55,8 @@ const DEFAULT_MAXIMUM_REPLY_SURB_AGE: Duration = Duration::from_secs(12 * 60 * 6
// 24 hours
const DEFAULT_MAXIMUM_REPLY_KEY_AGE: Duration = Duration::from_secs(24 * 60 * 60);
// aliases for backwards compatibility
pub type ConfigV1_1_33 = ConfigV5;
pub type ClientV1_1_33 = ClientV5;
pub type DebugConfigV1_1_33 = DebugConfigV5;
pub type OldGatewayEndpointConfigV1_1_33 = GatewayEndpointConfigV5;
pub type TrafficV1_1_33 = TrafficV5;
pub type CoverTrafficV1_1_33 = CoverTrafficV5;
pub type GatewayConnectionV1_1_33 = GatewayConnectionV5;
pub type AcknowledgementsV1_1_33 = AcknowledgementsV5;
pub type TopologyV1_1_33 = TopologyV5;
pub type ReplySurbsV1_1_33 = ReplySurbsV5;
#[derive(Clone, Debug, Default, Deserialize, PartialEq, Eq, Serialize)]
pub struct GatewayEndpointConfigV5 {
pub struct OldGatewayEndpointConfigV1_1_33 {
/// gateway_id specifies ID of the gateway to which the client should send messages.
/// If initially omitted, a random gateway will be chosen from the available topology.
pub gateway_id: String,
@@ -80,15 +70,15 @@ pub struct GatewayEndpointConfigV5 {
#[derive(Debug, Clone, Deserialize, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct ConfigV5 {
pub client: ClientV5,
pub struct ConfigV1_1_33 {
pub client: ClientV1_1_33,
#[serde(default)]
pub debug: DebugConfigV5,
pub debug: DebugConfigV1_1_33,
}
impl From<ConfigV5> for Config {
fn from(value: ConfigV5) -> Self {
impl From<ConfigV1_1_33> for Config {
fn from(value: ConfigV1_1_33) -> Self {
Config {
client: Client {
version: value.client.version,
@@ -146,7 +136,6 @@ impl From<ConfigV5> for Config {
.topology
.max_startup_gateway_waiting_period,
topology_structure: value.debug.topology.topology_structure.into(),
..Default::default()
},
reply_surbs: ReplySurbs {
minimum_reply_surb_storage_threshold: value
@@ -189,7 +178,7 @@ impl From<ConfigV5> for Config {
#[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)]
// note: the deny_unknown_fields is VITAL here to allow upgrades from v1.1.20_2
#[serde(deny_unknown_fields)]
pub struct ClientV5 {
pub struct ClientV1_1_33 {
/// Version of the client for which this configuration was created.
pub version: String,
@@ -213,7 +202,7 @@ pub struct ClientV5 {
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
#[serde(default, deny_unknown_fields)]
pub struct TrafficV5 {
pub struct TrafficV1_1_33 {
/// The parameter of Poisson distribution determining how long, on average,
/// sent packet is going to be delayed at any given mix node.
/// So for a packet going through three mix nodes, on average, it will take three times this value
@@ -244,9 +233,9 @@ pub struct TrafficV5 {
pub packet_type: PacketType,
}
impl Default for TrafficV5 {
impl Default for TrafficV1_1_33 {
fn default() -> Self {
TrafficV5 {
TrafficV1_1_33 {
average_packet_delay: DEFAULT_AVERAGE_PACKET_DELAY,
message_sending_average_delay: DEFAULT_MESSAGE_STREAM_AVERAGE_DELAY,
disable_main_poisson_packet_distribution: false,
@@ -259,7 +248,7 @@ impl Default for TrafficV5 {
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
#[serde(default, deny_unknown_fields)]
pub struct CoverTrafficV5 {
pub struct CoverTrafficV1_1_33 {
/// The parameter of Poisson distribution determining how long, on average,
/// it is going to take for another loop cover traffic message to be sent.
#[serde(with = "humantime_serde")]
@@ -274,9 +263,9 @@ pub struct CoverTrafficV5 {
pub disable_loop_cover_traffic_stream: bool,
}
impl Default for CoverTrafficV5 {
impl Default for CoverTrafficV1_1_33 {
fn default() -> Self {
CoverTrafficV5 {
CoverTrafficV1_1_33 {
loop_cover_traffic_average_delay: DEFAULT_LOOP_COVER_STREAM_AVERAGE_DELAY,
cover_traffic_primary_size_ratio: DEFAULT_COVER_TRAFFIC_PRIMARY_SIZE_RATIO,
disable_loop_cover_traffic_stream: false,
@@ -286,16 +275,16 @@ impl Default for CoverTrafficV5 {
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
#[serde(default, deny_unknown_fields)]
pub struct GatewayConnectionV5 {
pub struct GatewayConnectionV1_1_33 {
/// How long we're willing to wait for a response to a message sent to the gateway,
/// before giving up on it.
#[serde(with = "humantime_serde")]
pub gateway_response_timeout: Duration,
}
impl Default for GatewayConnectionV5 {
impl Default for GatewayConnectionV1_1_33 {
fn default() -> Self {
GatewayConnectionV5 {
GatewayConnectionV1_1_33 {
gateway_response_timeout: DEFAULT_GATEWAY_RESPONSE_TIMEOUT,
}
}
@@ -303,7 +292,7 @@ impl Default for GatewayConnectionV5 {
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
#[serde(default, deny_unknown_fields)]
pub struct AcknowledgementsV5 {
pub struct AcknowledgementsV1_1_33 {
/// The parameter of Poisson distribution determining how long, on average,
/// sent acknowledgement is going to be delayed at any given mix node.
/// So for an ack going through three mix nodes, on average, it will take three times this value
@@ -323,9 +312,9 @@ pub struct AcknowledgementsV5 {
pub ack_wait_addition: Duration,
}
impl Default for AcknowledgementsV5 {
impl Default for AcknowledgementsV1_1_33 {
fn default() -> Self {
AcknowledgementsV5 {
AcknowledgementsV1_1_33 {
average_ack_delay: DEFAULT_AVERAGE_PACKET_DELAY,
ack_wait_multiplier: DEFAULT_ACK_WAIT_MULTIPLIER,
ack_wait_addition: DEFAULT_ACK_WAIT_ADDITION,
@@ -335,7 +324,7 @@ impl Default for AcknowledgementsV5 {
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
#[serde(default, deny_unknown_fields)]
pub struct TopologyV5 {
pub struct TopologyV1_1_33 {
/// The uniform delay every which clients are querying the directory server
/// to try to obtain a compatible network topology to send sphinx packets through.
#[serde(with = "humantime_serde")]
@@ -358,66 +347,68 @@ pub struct TopologyV5 {
pub max_startup_gateway_waiting_period: Duration,
/// Specifies the mixnode topology to be used for sending packets.
pub topology_structure: TopologyStructureV5,
pub topology_structure: TopologyStructureV1_1_33,
}
#[allow(clippy::large_enum_variant)]
#[derive(Default, Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum TopologyStructureV5 {
pub enum TopologyStructureV1_1_33 {
#[default]
NymApi,
GeoAware(GroupByV5),
GeoAware(GroupByV1_1_33),
}
impl From<TopologyStructureV5> for TopologyStructure {
fn from(value: TopologyStructureV5) -> Self {
impl From<TopologyStructureV1_1_33> for TopologyStructure {
fn from(value: TopologyStructureV1_1_33) -> Self {
match value {
TopologyStructureV5::NymApi => TopologyStructure::NymApi,
TopologyStructureV5::GeoAware(group_by) => TopologyStructure::GeoAware(group_by.into()),
TopologyStructureV1_1_33::NymApi => TopologyStructure::NymApi,
TopologyStructureV1_1_33::GeoAware(group_by) => {
TopologyStructure::GeoAware(group_by.into())
}
}
}
}
#[allow(clippy::large_enum_variant)]
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum GroupByV5 {
pub enum GroupByV1_1_33 {
CountryGroup(CountryGroup),
NymAddress(Recipient),
}
impl From<GroupByV5> for GroupBy {
fn from(value: GroupByV5) -> Self {
impl From<GroupByV1_1_33> for GroupBy {
fn from(value: GroupByV1_1_33) -> Self {
match value {
GroupByV5::CountryGroup(country) => GroupBy::CountryGroup(country),
GroupByV5::NymAddress(addr) => GroupBy::NymAddress(addr),
GroupByV1_1_33::CountryGroup(country) => GroupBy::CountryGroup(country),
GroupByV1_1_33::NymAddress(addr) => GroupBy::NymAddress(addr),
}
}
}
impl std::fmt::Display for GroupByV5 {
impl std::fmt::Display for GroupByV1_1_33 {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
GroupByV5::CountryGroup(group) => write!(f, "group: {}", group),
GroupByV5::NymAddress(address) => write!(f, "address: {}", address),
GroupByV1_1_33::CountryGroup(group) => write!(f, "group: {}", group),
GroupByV1_1_33::NymAddress(address) => write!(f, "address: {}", address),
}
}
}
impl Default for TopologyV5 {
impl Default for TopologyV1_1_33 {
fn default() -> Self {
TopologyV5 {
TopologyV1_1_33 {
topology_refresh_rate: DEFAULT_TOPOLOGY_REFRESH_RATE,
topology_resolution_timeout: DEFAULT_TOPOLOGY_RESOLUTION_TIMEOUT,
disable_refreshing: false,
max_startup_gateway_waiting_period: DEFAULT_MAX_STARTUP_GATEWAY_WAITING_PERIOD,
topology_structure: TopologyStructureV5::default(),
topology_structure: TopologyStructureV1_1_33::default(),
}
}
}
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
#[serde(default, deny_unknown_fields)]
pub struct ReplySurbsV5 {
pub struct ReplySurbsV1_1_33 {
/// Defines the minimum number of reply surbs the client wants to keep in its storage at all times.
/// It can only allow to go below that value if its to request additional reply surbs.
pub minimum_reply_surb_storage_threshold: usize,
@@ -459,9 +450,9 @@ pub struct ReplySurbsV5 {
pub surb_mix_hops: Option<u8>,
}
impl Default for ReplySurbsV5 {
impl Default for ReplySurbsV1_1_33 {
fn default() -> Self {
ReplySurbsV5 {
ReplySurbsV1_1_33 {
minimum_reply_surb_storage_threshold: DEFAULT_MINIMUM_REPLY_SURB_STORAGE_THRESHOLD,
maximum_reply_surb_storage_threshold: DEFAULT_MAXIMUM_REPLY_SURB_STORAGE_THRESHOLD,
minimum_reply_surb_request_size: DEFAULT_MINIMUM_REPLY_SURB_REQUEST_SIZE,
@@ -479,22 +470,22 @@ impl Default for ReplySurbsV5 {
#[derive(Debug, Default, Clone, Copy, Deserialize, PartialEq, Serialize)]
#[serde(default, deny_unknown_fields)]
pub struct DebugConfigV5 {
pub struct DebugConfigV1_1_33 {
/// Defines all configuration options related to traffic streams.
pub traffic: TrafficV5,
pub traffic: TrafficV1_1_33,
/// Defines all configuration options related to cover traffic stream(s).
pub cover_traffic: CoverTrafficV5,
pub cover_traffic: CoverTrafficV1_1_33,
/// Defines all configuration options related to the gateway connection.
pub gateway_connection: GatewayConnectionV5,
pub gateway_connection: GatewayConnectionV1_1_33,
/// Defines all configuration options related to acknowledgements, such as delays or wait timeouts.
pub acknowledgements: AcknowledgementsV5,
pub acknowledgements: AcknowledgementsV1_1_33,
/// Defines all configuration options related topology, such as refresh rates or timeouts.
pub topology: TopologyV5,
pub topology: TopologyV1_1_33,
/// Defines all configuration options related to reply SURBs.
pub reply_surbs: ReplySurbsV5,
pub reply_surbs: ReplySurbsV1_1_33,
}
+1 -7
View File
@@ -9,7 +9,6 @@ use nym_crypto::asymmetric::identity;
use nym_gateway_client::GatewayClient;
use nym_topology::{filter::VersionFilterable, gateway, mix};
use nym_validator_client::client::IdentityKeyRef;
use nym_validator_client::UserAgent;
use rand::{seq::SliceRandom, Rng};
use std::{sync::Arc, time::Duration};
use tungstenite::Message;
@@ -60,16 +59,11 @@ impl<'a> GatewayWithLatency<'a> {
pub async fn current_gateways<R: Rng>(
rng: &mut R,
nym_apis: &[Url],
user_agent: Option<UserAgent>,
) -> Result<Vec<gateway::Node>, ClientCoreError> {
let nym_api = nym_apis
.choose(rng)
.ok_or(ClientCoreError::ListOfNymApisIsEmpty)?;
let client = if let Some(user_agent) = user_agent {
nym_validator_client::client::NymApiClient::new_with_user_agent(nym_api.clone(), user_agent)
} else {
nym_validator_client::client::NymApiClient::new(nym_api.clone())
};
let client = nym_validator_client::client::NymApiClient::new(nym_api.clone());
log::debug!("Fetching list of gateways from: {nym_api}");
+3 -3
View File
@@ -201,7 +201,7 @@ where
log::debug!("Setting up gateway");
match setup {
GatewaySetup::MustLoad { gateway_id } => {
log::debug!("GatewaySetup::MustLoad with id: {gateway_id:?}");
log::trace!("GatewaySetup::MustLoad with id: {gateway_id:?}");
use_loaded_gateway_details(key_store, details_store, gateway_id).await
}
GatewaySetup::New {
@@ -209,7 +209,7 @@ where
available_gateways,
wg_tun_address,
} => {
log::debug!("GatewaySetup::New with spec: {specification:?}");
log::trace!("GatewaySetup::New with spec: {specification:?}");
setup_new_gateway(
key_store,
details_store,
@@ -224,7 +224,7 @@ where
gateway_details,
client_keys: managed_keys,
} => {
log::debug!("GatewaySetup::ReuseConnection");
log::trace!("GatewaySetup::ReuseConnection");
Ok(reuse_gateway_connection(
authenticated_ephemeral_client,
*gateway_details,
+8 -14
View File
@@ -29,7 +29,7 @@ pub enum SelectedGateway {
Remote {
gateway_id: identity::PublicKey,
gateway_owner_address: Option<AccountId>,
gateway_owner_address: AccountId,
gateway_listener: Url,
@@ -84,19 +84,13 @@ impl SelectedGateway {
let wg_tun_address = wg_tun_address(wg_tun_ip_address, &node)?;
let gateway_owner_address = node
.owner
.as_ref()
.map(|raw_owner| {
AccountId::from_str(raw_owner).map_err(|source| {
ClientCoreError::MalformedGatewayOwnerAccountAddress {
gateway_id: node.identity_key.to_base58_string(),
raw_owner: raw_owner.clone(),
err: source.to_string(),
}
})
})
.transpose()?;
let gateway_owner_address = AccountId::from_str(&node.owner).map_err(|source| {
ClientCoreError::MalformedGatewayOwnerAccountAddress {
gateway_id: node.identity_key.to_base58_string(),
raw_owner: node.owner,
err: source.to_string(),
}
})?;
let gateway_listener =
Url::parse(&gateway_listener).map_err(|source| ClientCoreError::MalformedListener {
+6 -5
View File
@@ -14,10 +14,8 @@ futures = { workspace = true }
log = { workspace = true }
thiserror = { workspace = true }
url = { workspace = true }
rand = { workspace = true }
tokio = { workspace = true, features = ["macros"] }
si-scale = { workspace = true }
time.workspace = true
rand = { version = "0.7.3", features = ["wasm-bindgen"] }
tokio = { version = "1.24.1", features = ["macros"] }
# internal
nym-bandwidth-controller = { path = "../../bandwidth-controller" }
@@ -48,7 +46,10 @@ features = ["net", "sync", "time"]
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.tokio-tungstenite]
workspace = true
features = ["rustls-tls-webpki-roots"]
# the choice of this particular tls feature was arbitrary;
# if you reckon a different one would be more appropriate, feel free to change it
# features = ["native-tls"]
features = ["rustls-tls-native-roots"]
# wasm-only dependencies
[target."cfg(target_arch = \"wasm32\")".dependencies.wasm-bindgen]
+15 -32
View File
@@ -11,7 +11,7 @@ use crate::traits::GatewayPacketRouter;
use crate::{cleanup_socket_message, try_decrypt_binary_message};
use futures::{SinkExt, StreamExt};
use log::*;
use nym_bandwidth_controller::{BandwidthController, BandwidthStatusMessage};
use nym_bandwidth_controller::BandwidthController;
use nym_credential_storage::ephemeral_storage::EphemeralStorage as EphemeralCredentialStorage;
use nym_credential_storage::storage::Storage as CredentialStorage;
use nym_credentials::CredentialSpendingData;
@@ -79,7 +79,6 @@ impl GatewayConfig {
}
// TODO: this should be refactored into a state machine that keeps track of its authentication state
#[derive(Debug)]
pub struct GatewayClient<C, St = EphemeralCredentialStorage> {
authenticated: bool,
disabled_credentials_mode: bool,
@@ -105,8 +104,8 @@ pub struct GatewayClient<C, St = EphemeralCredentialStorage> {
// currently unused (but populated)
negotiated_protocol: Option<u8>,
/// Listen to shutdown messages and send notifications back to the task manager
task_client: TaskClient,
/// Listen to shutdown messages.
shutdown: TaskClient,
}
impl<C, St> GatewayClient<C, St> {
@@ -117,7 +116,7 @@ impl<C, St> GatewayClient<C, St> {
shared_key: Option<Arc<SharedKeys>>,
packet_router: PacketRouter,
bandwidth_controller: Option<BandwidthController<C, St>>,
task_client: TaskClient,
shutdown: TaskClient,
) -> Self {
GatewayClient {
authenticated: false,
@@ -135,7 +134,7 @@ impl<C, St> GatewayClient<C, St> {
reconnection_attempts: DEFAULT_RECONNECTION_ATTEMPTS,
reconnection_backoff: DEFAULT_RECONNECTION_BACKOFF,
negotiated_protocol: None,
task_client,
shutdown,
}
}
@@ -220,18 +219,9 @@ impl<C, St> GatewayClient<C, St> {
#[cfg(not(target_arch = "wasm32"))]
pub async fn establish_connection(&mut self) -> Result<(), GatewayClientError> {
debug!(
"Attemting to establish connection to gateway at: {}",
self.gateway_address
);
let ws_stream = match connect_async(&self.gateway_address).await {
Ok((ws_stream, _)) => ws_stream,
Err(error) => {
return Err(GatewayClientError::NetworkConnectionFailed {
address: self.gateway_address.clone(),
source: error,
})
}
Err(e) => return Err(GatewayClientError::NetworkError(e)),
};
self.connection = SocketState::Available(Box::new(ws_stream));
@@ -299,7 +289,7 @@ impl<C, St> GatewayClient<C, St> {
loop {
tokio::select! {
_ = self.task_client.recv() => {
_ = self.shutdown.recv() => {
log::trace!("GatewayClient control response: Received shutdown");
log::debug!("GatewayClient control response: Exiting");
break Err(GatewayClientError::ConnectionClosedGatewayShutdown);
@@ -451,7 +441,7 @@ impl<C, St> GatewayClient<C, St> {
}
debug_assert!(self.connection.is_available());
log::debug!("Registering gateway");
log::trace!("Registering gateway");
// it's fine to instantiate it here as it's only used once (during authentication or registration)
// and putting it into the GatewayClient struct would be a hassle
@@ -503,7 +493,6 @@ impl<C, St> GatewayClient<C, St> {
if !self.connection.is_established() {
return Err(GatewayClientError::ConnectionNotEstablished);
}
log::debug!("Authenticating with gateway");
// it's fine to instantiate it here as it's only used once (during authentication or registration)
// and putting it into the GatewayClient struct would be a hassle
@@ -539,10 +528,6 @@ impl<C, St> GatewayClient<C, St> {
self.authenticated = status;
self.bandwidth_remaining = bandwidth_remaining;
self.negotiated_protocol = protocol_version;
log::debug!("authenticated: {status}, bandwidth remaining: {bandwidth_remaining}");
self.task_client.send_status_msg(Box::new(
BandwidthStatusMessage::RemainingBandwidth(bandwidth_remaining),
));
Ok(())
}
ServerResponse::Error { message } => Err(GatewayClientError::GatewayError(message)),
@@ -555,11 +540,10 @@ impl<C, St> GatewayClient<C, St> {
&mut self,
) -> Result<Arc<SharedKeys>, GatewayClientError> {
if self.authenticated {
debug!("Already authenticated");
return if let Some(shared_key) = &self.shared_key {
Ok(Arc::clone(shared_key))
} else {
Err(GatewayClientError::AuthenticationFailureWithPreexistingSharedKey)
Err(GatewayClientError::AuthenticationFailure)
};
}
@@ -808,7 +792,7 @@ impl<C, St> GatewayClient<C, St> {
.as_ref()
.expect("no shared key present even though we're authenticated!"),
),
self.task_client.clone(),
self.shutdown.clone(),
)
}
_ => unreachable!(),
@@ -865,7 +849,6 @@ impl<C, St> GatewayClient<C, St> {
// type alias for an ease of use
pub type InitGatewayClient = GatewayClient<InitOnly>;
#[derive(Debug)]
pub struct InitOnly;
impl GatewayClient<InitOnly, EphemeralCredentialStorage> {
@@ -882,8 +865,8 @@ impl GatewayClient<InitOnly, EphemeralCredentialStorage> {
// perfectly fine here, because it's not meant to be used
let (ack_tx, _) = mpsc::unbounded();
let (mix_tx, _) = mpsc::unbounded();
let task_client = TaskClient::dummy();
let packet_router = PacketRouter::new(ack_tx, mix_tx, task_client.clone());
let shutdown = TaskClient::dummy();
let packet_router = PacketRouter::new(ack_tx, mix_tx, shutdown.clone());
GatewayClient {
authenticated: false,
@@ -901,7 +884,7 @@ impl GatewayClient<InitOnly, EphemeralCredentialStorage> {
reconnection_attempts: DEFAULT_RECONNECTION_ATTEMPTS,
reconnection_backoff: DEFAULT_RECONNECTION_BACKOFF,
negotiated_protocol: None,
task_client,
shutdown,
}
}
@@ -909,7 +892,7 @@ impl GatewayClient<InitOnly, EphemeralCredentialStorage> {
self,
packet_router: PacketRouter,
bandwidth_controller: Option<BandwidthController<C, St>>,
task_client: TaskClient,
shutdown: TaskClient,
) -> GatewayClient<C, St> {
// invariants that can't be broken
// (unless somebody decided to expose some field that wasn't meant to be exposed)
@@ -933,7 +916,7 @@ impl GatewayClient<InitOnly, EphemeralCredentialStorage> {
reconnection_attempts: self.reconnection_attempts,
reconnection_backoff: self.reconnection_backoff,
negotiated_protocol: self.negotiated_protocol,
task_client,
shutdown,
}
}
}
@@ -23,9 +23,6 @@ pub enum GatewayClientError {
#[error("There was a network error: {0}")]
NetworkErrorWasm(#[from] JsError),
#[error("connection failed: {address}: {source}")]
NetworkConnectionFailed { address: String, source: WsError },
#[error("Invalid URL: {0}")]
InvalidURL(String),
@@ -74,9 +71,6 @@ pub enum GatewayClientError {
#[error("Authentication failure")]
AuthenticationFailure,
#[error("Authentication failure with preexisting shared key")]
AuthenticationFailureWithPreexistingSharedKey,
#[error("Timed out")]
Timeout,
@@ -10,14 +10,9 @@ use futures::stream::{SplitSink, SplitStream};
use futures::{SinkExt, StreamExt};
use log::*;
use nym_gateway_requests::registration::handshake::SharedKeys;
use nym_gateway_requests::ServerResponse;
use nym_task::TaskClient;
use si_scale::helpers::bibytes2;
use std::os::raw::c_int as RawFd;
use std::sync::atomic::{AtomicI64, Ordering};
use std::sync::Arc;
use std::time::Duration;
use time::OffsetDateTime;
use tungstenite::Message;
#[cfg(unix)]
@@ -53,22 +48,6 @@ pub(crate) fn ws_fd(_conn: &WsConn) -> Option<RawFd> {
None
}
// disgusting? absolutely, but does the trick for now
static LAST_LOGGED_BANDWIDTH_TS: AtomicI64 = AtomicI64::new(0);
fn maybe_log_bandwidth(remaining: i64) {
// SAFETY: this value is always populated with valid timestamps
let last =
OffsetDateTime::from_unix_timestamp(LAST_LOGGED_BANDWIDTH_TS.load(Ordering::Relaxed))
.unwrap();
let now = OffsetDateTime::now_utc();
if last + Duration::from_secs(10) < now {
log::info!("remaining bandwidth: {}", bibytes2(remaining as f64));
LAST_LOGGED_BANDWIDTH_TS.store(now.unix_timestamp(), Ordering::Relaxed)
}
}
#[derive(Debug)]
pub(crate) struct PartiallyDelegated {
sink_half: SplitSink<WsConn, Message>,
delegated_stream: (SplitStreamReceiver, oneshot::Sender<()>),
@@ -76,10 +55,7 @@ pub(crate) struct PartiallyDelegated {
}
impl PartiallyDelegated {
fn recover_received_plaintexts(
ws_msgs: Vec<Message>,
shared_key: &SharedKeys,
) -> Result<Vec<Vec<u8>>, GatewayClientError> {
fn recover_received_plaintexts(ws_msgs: Vec<Message>, shared_key: &SharedKeys) -> Vec<Vec<u8>> {
let mut plaintexts = Vec::with_capacity(ws_msgs.len());
for ws_msg in ws_msgs {
match ws_msg {
@@ -97,32 +73,15 @@ impl PartiallyDelegated {
// TODO: those can return the "send confirmations" - perhaps it should be somehow worked around?
Message::Text(text) => {
trace!(
"received a text message - probably a response to some previous query! - {text}",
"received a text message - probably a response to some previous query! - {}",
text
);
match ServerResponse::try_from(text)
.map_err(|_| GatewayClientError::MalformedResponse)?
{
ServerResponse::Send {
remaining_bandwidth,
} => maybe_log_bandwidth(remaining_bandwidth),
ServerResponse::Error { message } => {
error!("gateway failure: {message}");
return Err(GatewayClientError::GatewayError(message));
}
other => {
warn!(
"received illegal message of type {} in an authenticated client",
other.name()
)
}
}
continue;
}
_ => continue,
}
}
Ok(plaintexts)
plaintexts
}
fn route_socket_messages(
@@ -130,7 +89,7 @@ impl PartiallyDelegated {
packet_router: &PacketRouter,
shared_key: &SharedKeys,
) -> Result<(), GatewayClientError> {
let plaintexts = Self::recover_received_plaintexts(ws_msgs, shared_key)?;
let plaintexts = Self::recover_received_plaintexts(ws_msgs, shared_key);
packet_router.route_received(plaintexts)
}
@@ -170,8 +129,7 @@ impl PartiallyDelegated {
};
if let Err(err) = Self::route_socket_messages(ws_msgs, &packet_router, shared_key.as_ref()) {
log::error!("Route socket messages failed: {err}");
break Err(err)
log::warn!("Route socket messages failed: {err}");
}
}
};
@@ -263,7 +221,6 @@ impl PartiallyDelegated {
// we can either have the stream itself or an option to re-obtain it
// by notifying the future owning it to finish the execution and awaiting the result
// which should be almost immediate (or an invalid state which should never, ever happen)
#[derive(Debug)]
pub(crate) enum SocketState {
Available(Box<WsConn>),
PartiallyDelegated(PartiallyDelegated),
+17 -13
View File
@@ -10,18 +10,22 @@ license.workspace = true
[dependencies]
base64 = "0.13"
colored = { workspace = true }
colored = "2.0"
nym-coconut-dkg-common = { path = "../../cosmwasm-smart-contracts/coconut-dkg" }
nym-contracts-common = { path = "../../cosmwasm-smart-contracts/contracts-common" }
nym-ephemera-common = { path = "../../cosmwasm-smart-contracts/ephemera" }
nym-mixnet-contract-common = { path = "../../cosmwasm-smart-contracts/mixnet-contract" }
nym-vesting-contract-common = { path = "../../cosmwasm-smart-contracts/vesting-contract" }
nym-coconut-bandwidth-contract-common = { path = "../../cosmwasm-smart-contracts/coconut-bandwidth-contract" }
nym-multisig-contract-common = { path = "../../cosmwasm-smart-contracts/multisig-contract" }
nym-name-service-common = { path = "../../cosmwasm-smart-contracts/name-service" }
nym-group-contract-common = { path = "../../cosmwasm-smart-contracts/group-contract" }
nym-service-provider-directory-common = { path = "../../cosmwasm-smart-contracts/service-provider-directory" }
serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true }
nym-http-api-client = { path = "../../../common/http-api-client" }
reqwest = { workspace = true, features = ["json"] }
nym-http-api-client = { path = "../../../common/http-api-client"}
thiserror = { workspace = true }
log = { workspace = true }
url = { workspace = true, features = ["serde"] }
@@ -45,16 +49,16 @@ tendermint-rpc = { workspace = true }
# of cargo's feature unification we'd get `bip32/std` meaning we'd get `std::error::Error` for the re-exported (via cosmrs) bip32::Error type
bip32 = { workspace = true, default-features = false, features = ["std"] }
eyre = { workspace = true }
eyre = { version = "0.6" }
cw-utils = { workspace = true }
cw2 = { workspace = true }
cw3 = { workspace = true }
cw4 = { workspace = true }
cw-controllers = { workspace = true }
prost = { workspace = true, default-features = false }
flate2 = { workspace = true }
flate2 = { version = "1.0.20" }
sha2 = { version = "0.9.5" }
itertools = { workspace = true }
itertools = { version = "0.10" }
zeroize = { workspace = true, features = ["zeroize_derive"] }
cosmwasm-std = { workspace = true }
@@ -63,14 +67,6 @@ cosmwasm-std = { workspace = true }
workspace = true
features = ["tokio"]
[target."cfg(target_arch = \"wasm32\")".dependencies.reqwest]
workspace = true
features = ["json"]
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.reqwest]
workspace = true
features = ["json", "rustls-tls"]
[dev-dependencies]
bip39 = { workspace = true }
cosmrs = { workspace = true, features = ["bip32"] }
@@ -83,6 +79,14 @@ name = "offline_signing"
# (traits would need to be moved around and refactored themselves)
required-features = ["http-client"]
[[example]]
name = "query_service_provider_directory"
required-features = ["http-client"]
[[example]]
name = "query_name_service"
required-features = ["http-client"]
[features]
default = ["http-client"]
http-client = ["cosmrs/rpc"]
@@ -0,0 +1,37 @@
use std::str::FromStr;
use cosmrs::AccountId;
use nym_name_service_common::Address;
use nym_network_defaults::{setup_env, NymNetworkDetails};
use nym_validator_client::nyxd::contract_traits::{
NameServiceQueryClient, PagedNameServiceQueryClient,
};
#[tokio::main]
async fn main() {
setup_env(Some("../../../envs/qa.env"));
let network_details = NymNetworkDetails::new_from_env();
let config =
nym_validator_client::Config::try_from_nym_network_details(&network_details).unwrap();
let client = nym_validator_client::Client::new_query(config).unwrap();
let config = client.nyxd.get_name_service_config().await.unwrap();
println!("config: {config:?}");
let names_paged = client.nyxd.get_names_paged(None, None).await.unwrap();
println!("names (paged): {names_paged:#?}");
let names = client.nyxd.get_all_names().await.unwrap();
println!("names: {names:#?}");
let owner = AccountId::from_str("n1hmf957kc7arcd39rl7xq8l0a4zyg7kxnv7su87").unwrap();
let names_by_owner = client.nyxd.get_names_by_owner(owner).await.unwrap();
println!("names (by owner): {names_by_owner:#?}");
let nym_address = Address::new("client_id.client_key@gateway_id").unwrap();
let names_by_address = client.nyxd.get_names_by_address(nym_address).await.unwrap();
println!("names (by address): {names_by_address:#?}");
let service_info = client.nyxd.get_name_entry(1).await;
println!("service info: {service_info:#?}");
}
@@ -0,0 +1,45 @@
use std::str::FromStr;
use cosmrs::AccountId;
use nym_network_defaults::{setup_env, NymNetworkDetails};
use nym_service_provider_directory_common::NymAddress;
use nym_validator_client::nyxd::contract_traits::{
PagedSpDirectoryQueryClient, SpDirectoryQueryClient,
};
#[tokio::main]
async fn main() {
setup_env(Some("../../../envs/qa.env"));
let network_details = NymNetworkDetails::new_from_env();
let config =
nym_validator_client::Config::try_from_nym_network_details(&network_details).unwrap();
let client = nym_validator_client::Client::new_query(config).unwrap();
let config = client.nyxd.get_service_config().await.unwrap();
println!("config: {config:?}");
let services_paged = client.nyxd.get_services_paged(None, None).await.unwrap();
println!("services (paged): {services_paged:#?}");
let services = client.nyxd.get_all_services().await.unwrap();
println!("services: {services:#?}");
let announcer = AccountId::from_str("n1hmf957kc7arcd39rl7xq8l0a4zyg7kxnv7su87").unwrap();
let services_by_announcer = client
.nyxd
.get_services_by_announcer(announcer)
.await
.unwrap();
println!("services (by announcer): {services_by_announcer:#?}");
let nym_address = NymAddress::new("foo.bar@gateway");
let services_by_nym_address = client
.nyxd
.get_services_by_nym_address(nym_address)
.await
.unwrap();
assert_eq!(services_by_announcer, services_by_nym_address);
let service_info = client.nyxd.get_service_info(1).await;
println!("service info: {service_info:#?}");
}
@@ -18,8 +18,6 @@ use nym_api_requests::models::{
GatewayCoreStatusResponse, MixnodeCoreStatusResponse, MixnodeStatusResponse,
RewardEstimationResponse, StakeSaturationResponse,
};
use nym_api_requests::nym_nodes::SkimmedNode;
use nym_http_api_client::UserAgent;
use nym_network_defaults::NymNetworkDetails;
use url::Url;
@@ -259,16 +257,6 @@ impl NymApiClient {
NymApiClient { nym_api }
}
pub fn new_with_user_agent(api_url: Url, user_agent: UserAgent) -> Self {
let nym_api = nym_api::Client::builder::<_, ValidatorClientError>(api_url)
.expect("invalid api url")
.with_user_agent(user_agent)
.build::<ValidatorClientError>()
.expect("failed to build nym api client");
NymApiClient { nym_api }
}
pub fn api_url(&self) -> &Url {
self.nym_api.current_url()
}
@@ -277,28 +265,6 @@ impl NymApiClient {
self.nym_api.change_base_url(new_endpoint);
}
pub async fn get_basic_mixnodes(
&self,
semver_compatibility: Option<String>,
) -> Result<Vec<SkimmedNode>, ValidatorClientError> {
Ok(self
.nym_api
.get_basic_mixnodes(semver_compatibility)
.await?
.nodes)
}
pub async fn get_basic_gateways(
&self,
semver_compatibility: Option<String>,
) -> Result<Vec<SkimmedNode>, ValidatorClientError> {
Ok(self
.nym_api
.get_basic_gateways(semver_compatibility)
.await?
.nodes)
}
pub async fn get_cached_active_mixnodes(
&self,
) -> Result<Vec<MixNodeDetails>, ValidatorClientError> {
@@ -17,7 +17,6 @@ pub use crate::signing::direct_wallet::DirectSecp256k1HdWallet;
pub use client::NymApiClient;
pub use client::{Client, CoconutApiClient, Config};
pub use nym_api_requests::*;
pub use nym_http_api_client::UserAgent;
#[cfg(feature = "http-client")]
pub use cosmrs::rpc::HttpClient as HttpRpcClient;
@@ -25,13 +25,14 @@ pub use nym_coconut_dkg_common::types::EpochId;
use nym_http_api_client::{ApiClient, NO_PARAMS};
use nym_mixnet_contract_common::mixnode::MixNodeDetails;
use nym_mixnet_contract_common::{GatewayBond, IdentityKeyRef, MixId};
use nym_name_service_common::response::NamesListResponse;
use nym_service_provider_directory_common::response::ServicesListResponse;
pub mod error;
pub mod routes;
use nym_api_requests::coconut::models::FreePassNonceResponse;
use nym_api_requests::coconut::FreePassRequest;
use nym_api_requests::nym_nodes::{CachedNodesResponse, SkimmedNode};
pub use nym_http_api_client::Client;
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
@@ -96,52 +97,6 @@ pub trait NymApiClientExt: ApiClient {
.await
}
async fn get_basic_mixnodes(
&self,
semver_compatibility: Option<String>,
) -> Result<CachedNodesResponse<SkimmedNode>, NymAPIError> {
let params = if let Some(semver_compatibility) = &semver_compatibility {
vec![("semver_compatibility", semver_compatibility.as_str())]
} else {
vec![]
};
self.get_json(
&[
routes::API_VERSION,
"unstable",
"nym-nodes",
"mixnodes",
"skimmed",
],
&params,
)
.await
}
async fn get_basic_gateways(
&self,
semver_compatibility: Option<String>,
) -> Result<CachedNodesResponse<SkimmedNode>, NymAPIError> {
let params = if let Some(semver_compatibility) = &semver_compatibility {
vec![("semver_compatibility", semver_compatibility.as_str())]
} else {
vec![]
};
self.get_json(
&[
routes::API_VERSION,
"unstable",
"nym-nodes",
"gateways",
"skimmed",
],
&params,
)
.await
}
async fn get_active_mixnodes(&self) -> Result<Vec<MixNodeDetails>, NymAPIError> {
self.get_json(
&[routes::API_VERSION, routes::MIXNODES, routes::ACTIVE],
@@ -537,6 +492,19 @@ pub trait NymApiClientExt: ApiClient {
)
.await
}
async fn get_service_providers(&self) -> Result<ServicesListResponse, NymAPIError> {
log::trace!("Getting service providers");
self.get_json(&[routes::API_VERSION, routes::SERVICE_PROVIDERS], NO_PARAMS)
.await
}
//async fn get_registered_names(&self) -> Result<Vec<NameEntry>, NymAPIError> {
async fn get_registered_names(&self) -> Result<NamesListResponse, NymAPIError> {
log::trace!("Getting registered names");
self.get_json(&[routes::API_VERSION, routes::REGISTERED_NAMES], NO_PARAMS)
.await
}
}
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
@@ -40,3 +40,4 @@ pub const STAKE_SATURATION: &str = "stake-saturation";
pub const INCLUSION_CHANCE: &str = "inclusion-probability";
pub const SERVICE_PROVIDERS: &str = "services";
pub const REGISTERED_NAMES: &str = "names";
@@ -0,0 +1,79 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::collect_paged;
use crate::nyxd::contract_traits::NymContractsProvider;
use crate::nyxd::error::NyxdError;
use crate::nyxd::CosmWasmClient;
use async_trait::async_trait;
use nym_ephemera_common::msg::QueryMsg as EphemeraQueryMsg;
use nym_ephemera_common::peers::PagedPeerResponse;
use nym_ephemera_common::types::JsonPeerInfo;
use serde::Deserialize;
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
pub trait EphemeraQueryClient {
async fn query_ephemera_contract<T>(&self, query: EphemeraQueryMsg) -> Result<T, NyxdError>
where
for<'a> T: Deserialize<'a>;
async fn get_peers_paged(
&self,
start_after: Option<String>,
limit: Option<u32>,
) -> Result<PagedPeerResponse, NyxdError> {
let request = EphemeraQueryMsg::GetPeers { start_after, limit };
self.query_ephemera_contract(request).await
}
}
// extension trait to the query client to deal with the paged queries
// (it didn't feel appropriate to combine it with the existing trait
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
pub trait PagedEphemeraQueryClient: EphemeraQueryClient {
async fn get_all_ephemera_peers(&self) -> Result<Vec<JsonPeerInfo>, NyxdError> {
collect_paged!(self, get_peers_paged, peers)
}
}
#[async_trait]
impl<T> PagedEphemeraQueryClient for T where T: EphemeraQueryClient {}
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
impl<C> EphemeraQueryClient for C
where
C: CosmWasmClient + NymContractsProvider + Send + Sync,
{
async fn query_ephemera_contract<T>(&self, query: EphemeraQueryMsg) -> Result<T, NyxdError>
where
for<'a> T: Deserialize<'a>,
{
let ephemera_contract_address = &self
.ephemera_contract_address()
.ok_or_else(|| NyxdError::unavailable_contract_address("ephemera contract"))?;
self.query_contract_smart(ephemera_contract_address, &query)
.await
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::nyxd::contract_traits::tests::IgnoreValue;
// it's enough that this compiles and clippy is happy about it
#[allow(dead_code)]
fn all_query_variants_are_covered<C: EphemeraQueryClient + Send + Sync>(
client: C,
msg: EphemeraQueryMsg,
) {
match msg {
EphemeraQueryMsg::GetPeers { limit, start_after } => {
client.get_peers_paged(start_after, limit).ignore()
}
};
}
}
@@ -0,0 +1,86 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::nyxd::contract_traits::NymContractsProvider;
use crate::nyxd::cosmwasm_client::types::ExecuteResult;
use crate::nyxd::error::NyxdError;
use crate::nyxd::{Coin, Fee, SigningCosmWasmClient};
use crate::signing::signer::OfflineSigner;
use async_trait::async_trait;
use nym_ephemera_common::msg::ExecuteMsg as EphemeraExecuteMsg;
use nym_ephemera_common::types::JsonPeerInfo;
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
pub trait EphemeraSigningClient {
async fn execute_ephemera_contract(
&self,
fee: Option<Fee>,
msg: EphemeraExecuteMsg,
memo: String,
funds: Vec<Coin>,
) -> Result<ExecuteResult, NyxdError>;
async fn register_as_peer(
&self,
peer_info: JsonPeerInfo,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
let req = EphemeraExecuteMsg::RegisterPeer { peer_info };
self.execute_ephemera_contract(fee, req, "registering as peer".to_string(), vec![])
.await
}
}
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
impl<C> EphemeraSigningClient for C
where
C: SigningCosmWasmClient + NymContractsProvider + Sync,
NyxdError: From<<Self as OfflineSigner>::Error>,
{
async fn execute_ephemera_contract(
&self,
fee: Option<Fee>,
msg: EphemeraExecuteMsg,
memo: String,
funds: Vec<Coin>,
) -> Result<ExecuteResult, NyxdError> {
let ephemera_contract_address = self
.ephemera_contract_address()
.ok_or_else(|| NyxdError::unavailable_contract_address("ephemera contract"))?;
let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier())));
let signer_address = &self.signer_addresses()?[0];
self.execute(
signer_address,
ephemera_contract_address,
&msg,
fee,
memo,
funds,
)
.await
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::nyxd::contract_traits::tests::IgnoreValue;
// it's enough that this compiles and clippy is happy about it
#[allow(dead_code)]
fn all_execute_variants_are_covered<C: EphemeraSigningClient + Send + Sync>(
client: C,
msg: EphemeraExecuteMsg,
) {
match msg {
EphemeraExecuteMsg::RegisterPeer { peer_info } => {
client.register_as_peer(peer_info, None).ignore()
}
};
}
}
@@ -10,17 +10,23 @@ use std::str::FromStr;
// query clients
pub mod coconut_bandwidth_query_client;
pub mod dkg_query_client;
pub mod ephemera_query_client;
pub mod group_query_client;
pub mod mixnet_query_client;
pub mod multisig_query_client;
pub mod name_service_query_client;
pub mod sp_directory_query_client;
pub mod vesting_query_client;
// signing clients
pub mod coconut_bandwidth_signing_client;
pub mod dkg_signing_client;
pub mod ephemera_signing_client;
pub mod group_signing_client;
pub mod mixnet_signing_client;
pub mod multisig_signing_client;
pub mod name_service_signing_client;
pub mod sp_directory_signing_client;
pub mod vesting_signing_client;
// re-export query traits
@@ -28,17 +34,23 @@ pub use coconut_bandwidth_query_client::{
CoconutBandwidthQueryClient, PagedCoconutBandwidthQueryClient,
};
pub use dkg_query_client::{DkgQueryClient, PagedDkgQueryClient};
pub use ephemera_query_client::{EphemeraQueryClient, PagedEphemeraQueryClient};
pub use group_query_client::{GroupQueryClient, PagedGroupQueryClient};
pub use mixnet_query_client::{MixnetQueryClient, PagedMixnetQueryClient};
pub use multisig_query_client::{MultisigQueryClient, PagedMultisigQueryClient};
pub use name_service_query_client::{NameServiceQueryClient, PagedNameServiceQueryClient};
pub use sp_directory_query_client::{PagedSpDirectoryQueryClient, SpDirectoryQueryClient};
pub use vesting_query_client::{PagedVestingQueryClient, VestingQueryClient};
// re-export signing traits
pub use coconut_bandwidth_signing_client::CoconutBandwidthSigningClient;
pub use dkg_signing_client::DkgSigningClient;
pub use ephemera_signing_client::EphemeraSigningClient;
pub use group_signing_client::GroupSigningClient;
pub use mixnet_signing_client::MixnetSigningClient;
pub use multisig_signing_client::MultisigSigningClient;
pub use name_service_signing_client::NameServiceSigningClient;
pub use sp_directory_signing_client::SpDirectorySigningClient;
pub use vesting_signing_client::VestingSigningClient;
// helper for providing blanket implementation for query clients
@@ -52,6 +64,13 @@ pub trait NymContractsProvider {
fn dkg_contract_address(&self) -> Option<&AccountId>;
fn group_contract_address(&self) -> Option<&AccountId>;
fn multisig_contract_address(&self) -> Option<&AccountId>;
// ephemera-related
fn ephemera_contract_address(&self) -> Option<&AccountId>;
// SPs
fn name_service_contract_address(&self) -> Option<&AccountId>;
fn service_provider_contract_address(&self) -> Option<&AccountId>;
}
#[derive(Debug, Clone)]
@@ -63,6 +82,11 @@ pub struct TypedNymContracts {
pub group_contract_address: Option<AccountId>,
pub multisig_contract_address: Option<AccountId>,
pub coconut_dkg_contract_address: Option<AccountId>,
pub ephemera_contract_address: Option<AccountId>,
pub service_provider_directory_contract_address: Option<AccountId>,
pub name_service_contract_address: Option<AccountId>,
}
impl TryFrom<NymContracts> for TypedNymContracts {
@@ -94,6 +118,18 @@ impl TryFrom<NymContracts> for TypedNymContracts {
.coconut_dkg_contract_address
.map(|addr| addr.parse())
.transpose()?,
ephemera_contract_address: value
.ephemera_contract_address
.map(|addr| addr.parse())
.transpose()?,
service_provider_directory_contract_address: value
.service_provider_directory_contract_address
.map(|addr| addr.parse())
.transpose()?,
name_service_contract_address: value
.name_service_contract_address
.map(|addr| addr.parse())
.transpose()?,
})
}
}
@@ -0,0 +1,144 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::collect_paged;
use crate::nyxd::contract_traits::NymContractsProvider;
use crate::nyxd::{error::NyxdError, CosmWasmClient};
use async_trait::async_trait;
use cosmrs::AccountId;
use nym_contracts_common::{signing::Nonce, ContractBuildInformation};
use nym_name_service_common::{
msg::QueryMsg as NameQueryMsg,
response::{ConfigResponse, NamesListResponse, PagedNamesListResponse},
Address, NameId, NymName, RegisteredName,
};
use serde::Deserialize;
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
pub trait NameServiceQueryClient {
async fn query_name_service_contract<T>(&self, query: NameQueryMsg) -> Result<T, NyxdError>
where
for<'a> T: Deserialize<'a>;
async fn get_name_service_config(&self) -> Result<ConfigResponse, NyxdError> {
self.query_name_service_contract(NameQueryMsg::Config {})
.await
}
async fn get_name_entry(&self, name_id: NameId) -> Result<RegisteredName, NyxdError> {
self.query_name_service_contract(NameQueryMsg::NameId { name_id })
.await
}
async fn get_names_paged(
&self,
start_after: Option<NameId>,
limit: Option<u32>,
) -> Result<PagedNamesListResponse, NyxdError> {
self.query_name_service_contract(NameQueryMsg::All { limit, start_after })
.await
}
async fn get_name_signing_nonce(&self, address: &AccountId) -> Result<Nonce, NyxdError> {
self.query_name_service_contract(NameQueryMsg::SigningNonce {
address: address.to_string(),
})
.await
}
async fn get_names_by_owner(&self, owner: AccountId) -> Result<NamesListResponse, NyxdError> {
self.query_name_service_contract(NameQueryMsg::ByOwner {
owner: owner.to_string(),
})
.await
}
async fn get_names_by_nym_name(&self, name: NymName) -> Result<NamesListResponse, NyxdError> {
self.query_name_service_contract(NameQueryMsg::ByName { name })
.await
}
async fn get_names_by_address(&self, address: Address) -> Result<NamesListResponse, NyxdError> {
self.query_name_service_contract(NameQueryMsg::ByAddress { address })
.await
}
async fn get_name_service_contract_version(
&self,
) -> Result<ContractBuildInformation, NyxdError> {
self.query_name_service_contract(NameQueryMsg::GetContractVersion {})
.await
}
async fn get_name_service_contract_cw2_version(
&self,
) -> Result<cw2::ContractVersion, NyxdError> {
self.query_name_service_contract(NameQueryMsg::GetCW2ContractVersion {})
.await
}
}
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
pub trait PagedNameServiceQueryClient: NameServiceQueryClient {
async fn get_all_names(&self) -> Result<Vec<RegisteredName>, NyxdError> {
collect_paged!(self, get_names_paged, names)
}
}
#[async_trait]
impl<T> PagedNameServiceQueryClient for T where T: NameServiceQueryClient {}
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
impl<C> NameServiceQueryClient for C
where
C: CosmWasmClient + NymContractsProvider + Send + Sync,
{
async fn query_name_service_contract<T>(&self, query: NameQueryMsg) -> Result<T, NyxdError>
where
for<'a> T: Deserialize<'a>,
{
let name_service_contract_address = &self
.name_service_contract_address()
.ok_or_else(|| NyxdError::unavailable_contract_address("name service contract"))?;
self.query_contract_smart(name_service_contract_address, &query)
.await
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::nyxd::contract_traits::tests::IgnoreValue;
// it's enough that this compiles and clippy is happy about it
#[allow(dead_code)]
fn all_query_variants_are_covered<C: NameServiceQueryClient + Send + Sync>(
client: C,
msg: NameQueryMsg,
) {
match msg {
NameQueryMsg::NameId { name_id } => client.get_name_entry(name_id).ignore(),
NameQueryMsg::ByOwner { owner } => {
client.get_names_by_owner(owner.parse().unwrap()).ignore()
}
NameQueryMsg::ByName { name } => client.get_names_by_nym_name(name).ignore(),
NameQueryMsg::ByAddress { address } => client.get_names_by_address(address).ignore(),
NameQueryMsg::All { limit, start_after } => {
client.get_names_paged(limit, start_after).ignore()
}
NameQueryMsg::SigningNonce { address } => client
.get_name_signing_nonce(&address.parse().unwrap())
.ignore(),
NameQueryMsg::Config {} => client.get_name_service_config().ignore(),
NameQueryMsg::GetContractVersion {} => {
client.get_name_service_contract_version().ignore()
}
NameQueryMsg::GetCW2ContractVersion {} => {
client.get_name_service_contract_cw2_version().ignore()
}
};
}
}
@@ -0,0 +1,138 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use async_trait::async_trait;
use nym_contracts_common::signing::MessageSignature;
use nym_name_service_common::{msg::ExecuteMsg as NameExecuteMsg, NameDetails, NameId, NymName};
use crate::nyxd::contract_traits::NymContractsProvider;
use crate::nyxd::{
coin::Coin, cosmwasm_client::types::ExecuteResult, error::NyxdError, Fee, SigningCosmWasmClient,
};
use crate::signing::signer::OfflineSigner;
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
pub trait NameServiceSigningClient {
async fn execute_name_service_contract(
&self,
fee: Option<Fee>,
msg: NameExecuteMsg,
funds: Vec<Coin>,
) -> Result<ExecuteResult, NyxdError>;
async fn register_name(
&self,
name: NameDetails,
owner_signature: MessageSignature,
deposit: Coin,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_name_service_contract(
fee,
NameExecuteMsg::Register {
name,
owner_signature,
},
vec![deposit],
)
.await
}
async fn delete_name_by_id(
&self,
name_id: NameId,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_name_service_contract(fee, NameExecuteMsg::DeleteId { name_id }, vec![])
.await
}
async fn delete_service_provider_by_name(
&self,
name: NymName,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_name_service_contract(fee, NameExecuteMsg::DeleteName { name }, vec![])
.await
}
async fn update_deposit_required(
&self,
deposit_required: Coin,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_name_service_contract(
fee,
NameExecuteMsg::UpdateDepositRequired {
deposit_required: deposit_required.into(),
},
vec![],
)
.await
}
}
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
impl<C> NameServiceSigningClient for C
where
C: SigningCosmWasmClient + NymContractsProvider + Sync,
NyxdError: From<<Self as OfflineSigner>::Error>,
{
async fn execute_name_service_contract(
&self,
fee: Option<Fee>,
msg: NameExecuteMsg,
funds: Vec<Coin>,
) -> Result<ExecuteResult, NyxdError> {
let name_service_contract_address = &self
.name_service_contract_address()
.ok_or_else(|| NyxdError::unavailable_contract_address("name service contract"))?;
let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier())));
let memo = msg.default_memo();
let signer_address = &self.signer_addresses()?[0];
self.execute(
signer_address,
name_service_contract_address,
&msg,
fee,
memo,
funds,
)
.await
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::nyxd::contract_traits::tests::{mock_coin, IgnoreValue};
// it's enough that this compiles and clippy is happy about it
#[allow(dead_code)]
fn all_execute_variants_are_covered<C: NameServiceSigningClient + Send + Sync>(
client: C,
msg: NameExecuteMsg,
) {
match msg {
NameExecuteMsg::Register {
name,
owner_signature,
} => client
.register_name(name, owner_signature, mock_coin(), None)
.ignore(),
NameExecuteMsg::DeleteId { name_id } => {
client.delete_name_by_id(name_id, None).ignore()
}
NameExecuteMsg::DeleteName { name } => {
client.delete_service_provider_by_name(name, None).ignore()
}
NameExecuteMsg::UpdateDepositRequired { deposit_required } => client
.update_deposit_required(deposit_required.into(), None)
.ignore(),
};
}
}
@@ -0,0 +1,142 @@
use crate::collect_paged;
use async_trait::async_trait;
use cosmrs::AccountId;
use nym_contracts_common::{signing::Nonce, ContractBuildInformation};
use nym_service_provider_directory_common::{
msg::QueryMsg as SpQueryMsg,
response::{
ConfigResponse, PagedServicesListResponse, ServiceInfoResponse, ServicesListResponse,
},
NymAddress, Service, ServiceId,
};
use serde::Deserialize;
use crate::nyxd::contract_traits::NymContractsProvider;
use crate::nyxd::{error::NyxdError, CosmWasmClient};
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
pub trait SpDirectoryQueryClient {
async fn query_service_provider_contract<T>(&self, query: SpQueryMsg) -> Result<T, NyxdError>
where
for<'a> T: Deserialize<'a>;
async fn get_service_config(&self) -> Result<ConfigResponse, NyxdError> {
self.query_service_provider_contract(SpQueryMsg::Config {})
.await
}
async fn get_service_info(
&self,
service_id: ServiceId,
) -> Result<ServiceInfoResponse, NyxdError> {
self.query_service_provider_contract(SpQueryMsg::ServiceId { service_id })
.await
}
async fn get_services_paged(
&self,
start_after: Option<ServiceId>,
limit: Option<u32>,
) -> Result<PagedServicesListResponse, NyxdError> {
self.query_service_provider_contract(SpQueryMsg::All { limit, start_after })
.await
}
async fn get_services_by_announcer(
&self,
announcer: AccountId,
) -> Result<ServicesListResponse, NyxdError> {
self.query_service_provider_contract(SpQueryMsg::ByAnnouncer {
announcer: announcer.to_string(),
})
.await
}
async fn get_services_by_nym_address(
&self,
nym_address: NymAddress,
) -> Result<ServicesListResponse, NyxdError> {
self.query_service_provider_contract(SpQueryMsg::ByNymAddress { nym_address })
.await
}
async fn get_sp_contract_version(&self) -> Result<ContractBuildInformation, NyxdError> {
self.query_service_provider_contract(SpQueryMsg::GetContractVersion {})
.await
}
async fn get_sp_contract_cw2_version(&self) -> Result<cw2::ContractVersion, NyxdError> {
self.query_service_provider_contract(SpQueryMsg::GetCW2ContractVersion {})
.await
}
async fn get_service_signing_nonce(&self, address: &AccountId) -> Result<Nonce, NyxdError> {
self.query_service_provider_contract(SpQueryMsg::SigningNonce {
address: address.to_string(),
})
.await
}
}
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
pub trait PagedSpDirectoryQueryClient: SpDirectoryQueryClient {
async fn get_all_services(&self) -> Result<Vec<Service>, NyxdError> {
collect_paged!(self, get_services_paged, services)
}
}
#[async_trait]
impl<T> PagedSpDirectoryQueryClient for T where T: SpDirectoryQueryClient {}
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
impl<C> SpDirectoryQueryClient for C
where
C: CosmWasmClient + NymContractsProvider + Send + Sync,
{
async fn query_service_provider_contract<T>(&self, query: SpQueryMsg) -> Result<T, NyxdError>
where
for<'a> T: Deserialize<'a>,
{
let sp_directory_contract_address =
&self.service_provider_contract_address().ok_or_else(|| {
NyxdError::unavailable_contract_address("service provider directory contract")
})?;
self.query_contract_smart(sp_directory_contract_address, &query)
.await
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::nyxd::contract_traits::tests::IgnoreValue;
// it's enough that this compiles and clippy is happy about it
#[allow(dead_code)]
fn all_query_variants_are_covered<C: SpDirectoryQueryClient + Send + Sync>(
client: C,
msg: SpQueryMsg,
) {
match msg {
SpQueryMsg::ServiceId { service_id } => client.get_service_info(service_id).ignore(),
SpQueryMsg::ByAnnouncer { announcer } => client
.get_services_by_announcer(announcer.parse().unwrap())
.ignore(),
SpQueryMsg::ByNymAddress { nym_address } => {
client.get_services_by_nym_address(nym_address).ignore()
}
SpQueryMsg::All { limit, start_after } => {
client.get_services_paged(start_after, limit).ignore()
}
SpQueryMsg::SigningNonce { address } => client
.get_service_signing_nonce(&address.parse().unwrap())
.ignore(),
SpQueryMsg::Config {} => client.get_service_config().ignore(),
SpQueryMsg::GetContractVersion {} => client.get_sp_contract_version().ignore(),
SpQueryMsg::GetCW2ContractVersion {} => client.get_sp_contract_cw2_version().ignore(),
};
}
}
@@ -0,0 +1,148 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::nyxd::contract_traits::NymContractsProvider;
use crate::nyxd::{
coin::Coin, cosmwasm_client::types::ExecuteResult, error::NyxdError, Fee, SigningCosmWasmClient,
};
use crate::signing::signer::OfflineSigner;
use async_trait::async_trait;
use nym_contracts_common::signing::MessageSignature;
use nym_service_provider_directory_common::{
msg::ExecuteMsg as SpExecuteMsg, NymAddress, ServiceDetails, ServiceId,
};
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
pub trait SpDirectorySigningClient {
async fn execute_service_provider_directory_contract(
&self,
fee: Option<Fee>,
msg: SpExecuteMsg,
funds: Vec<Coin>,
) -> Result<ExecuteResult, NyxdError>;
async fn announce_service_provider(
&self,
service: ServiceDetails,
owner_signature: MessageSignature,
deposit: Coin,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_service_provider_directory_contract(
fee,
SpExecuteMsg::Announce {
service,
owner_signature,
},
vec![deposit],
)
.await
}
async fn delete_service_provider_by_id(
&self,
service_id: ServiceId,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_service_provider_directory_contract(
fee,
SpExecuteMsg::DeleteId { service_id },
vec![],
)
.await
}
async fn delete_service_provider_by_nym_address(
&self,
nym_address: NymAddress,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_service_provider_directory_contract(
fee,
SpExecuteMsg::DeleteNymAddress { nym_address },
vec![],
)
.await
}
async fn update_deposit_required(
&self,
deposit_required: Coin,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_service_provider_directory_contract(
fee,
SpExecuteMsg::UpdateDepositRequired {
deposit_required: deposit_required.into(),
},
vec![],
)
.await
}
}
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
impl<C> SpDirectorySigningClient for C
where
C: SigningCosmWasmClient + NymContractsProvider + Sync,
NyxdError: From<<Self as OfflineSigner>::Error>,
{
async fn execute_service_provider_directory_contract(
&self,
fee: Option<Fee>,
msg: SpExecuteMsg,
funds: Vec<Coin>,
) -> Result<ExecuteResult, NyxdError> {
let sp_directory_contract_address =
&self.service_provider_contract_address().ok_or_else(|| {
NyxdError::unavailable_contract_address("service provider directory contract")
})?;
let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier())));
let memo = msg.default_memo();
let signer_address = &self.signer_addresses()?[0];
self.execute(
signer_address,
sp_directory_contract_address,
&msg,
fee,
memo,
funds,
)
.await
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::nyxd::contract_traits::tests::{mock_coin, IgnoreValue};
// it's enough that this compiles and clippy is happy about it
#[allow(dead_code)]
fn all_execute_variants_are_covered<C: SpDirectorySigningClient + Send + Sync>(
client: C,
msg: SpExecuteMsg,
) {
match msg {
SpExecuteMsg::Announce {
service,
owner_signature,
} => client
.announce_service_provider(service, owner_signature, mock_coin(), None)
.ignore(),
SpExecuteMsg::DeleteId { service_id } => client
.delete_service_provider_by_id(service_id, None)
.ignore(),
SpExecuteMsg::DeleteNymAddress { nym_address } => client
.delete_service_provider_by_nym_address(nym_address, None)
.ignore(),
SpExecuteMsg::UpdateDepositRequired { deposit_required } => client
.update_deposit_required(deposit_required.into(), None)
.ignore(),
};
}
}

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