Compare commits

..

2 Commits

Author SHA1 Message Date
Simon Wicky 1e74de2d67 domain fronting on the run part 2024-07-18 14:37:12 +02:00
Simon Wicky a886715948 ugly first try at domain fronting 2024-07-16 15:11:48 +02:00
1026 changed files with 24144 additions and 51374 deletions
-7
View File
@@ -1,7 +0,0 @@
.git
.github
.gitignore
**/node_modules
**/target
dist
documentation
-17
View File
@@ -14,20 +14,3 @@ updates:
prefix: build
prefix-development: chore
include: scope
# Update the root workspace (only). For now we don't include
# the contracts workspcae.
- package-ecosystem: cargo
directory: /
schedule:
interval: weekly
time: "09:00"
ignore:
- dependency-name: "cosmwasm-*"
- dependency-name: "cw*"
groups:
patch-updates:
patterns:
- "*"
update-types:
- "patch"
open-pull-requests-limit: 10
-9
View File
@@ -1,9 +0,0 @@
name: build-deb-meta
on:
workflow_dispatch:
jobs:
build:
steps:
run: "echo hello"
+4 -4
View File
@@ -7,7 +7,7 @@ jobs:
build:
runs-on: ubuntu-20.04-16-core
steps:
- uses: actions/checkout@v4
- 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
@@ -17,7 +17,7 @@ jobs:
- name: Install rsync
run: sudo apt-get install rsync
- uses: rlespinasse/github-slug-action@v3.x
- uses: actions/setup-node@v4
- uses: actions/setup-node@v3
with:
node-version: 18
- name: Install Rust stable
@@ -41,8 +41,8 @@ jobs:
# 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: Git pull & switch to b332a6b55668f60988e36961f3f62a794ba82ddb
run: git pull && git checkout b332a6b55668f60988e36961f3f62a794ba82ddb
- name: Build all projects in documentation/ & move to ~/dist/docs/ from b332a6b55668f60988e36961f3f62a794ba82ddb
run: cd documentation && ./build_all_to_dist.sh
@@ -35,7 +35,7 @@ jobs:
runs-on: ${{ matrix.platform }}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- name: Install Dependencies (Linux)
run: sudo apt-get update && sudo apt-get -y install jq vim libwebkit2gtk-4.0-dev build-essential curl wget libssl-dev libgtk-3-dev libudev-dev squashfs-tools
+2 -2
View File
@@ -10,12 +10,12 @@ jobs:
build:
runs-on: ubuntu-20.04-16-core
steps:
- uses: actions/checkout@v4
- 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@v4
- uses: actions/setup-node@v3
with:
node-version: 18
- name: Setup yarn
+11 -3
View File
@@ -8,6 +8,11 @@ on:
required: true
default: false
type: boolean
enable_wireguard:
description: "Add --features wireguard"
required: true
default: false
type: boolean
enable_deb:
description: "True to enable cargo-deb installation and .deb package building"
required: false
@@ -37,13 +42,13 @@ jobs:
strategy:
fail-fast: false
matrix:
platform: [ ubuntu-20.04 ]
platform: [ubuntu-20.04]
runs-on: ${{ matrix.platform }}
env:
CARGO_TERM_COLOR: always
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- name: Prepare build output directory
shell: bash
@@ -65,6 +70,9 @@ jobs:
- name: Set CARGO_FEATURES
run: |
echo 'CARGO_FEATURES=--features wireguard' >> $GITHUB_ENV
if: >
github.event_name == 'schedule' ||
(github.event_name == 'workflow_dispatch' && inputs.enable_wireguard == true)
- name: Install Rust stable
uses: actions-rs/toolchain@v1
@@ -91,7 +99,7 @@ jobs:
- name: Upload Artifact
if: github.event_name == 'workflow_dispatch'
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v3
with:
name: nym-binaries-artifacts
path: |
+2 -10
View File
@@ -53,7 +53,7 @@ jobs:
if: matrix.os == 'custom-linux'
- name: Check out repository code
uses: actions/checkout@v4
uses: actions/checkout@v2
- name: Install rust toolchain
uses: actions-rs/toolchain@v1
@@ -76,14 +76,6 @@ jobs:
# Enable wireguard by default on linux only
args: --workspace --features wireguard
# while disabled by default, this build ensures nothing is broken within
# `axum` feature
- name: Build with `axum` feature
uses: actions-rs/cargo@v1
with:
command: build
args: --features axum
- name: Build all examples
if: matrix.os == 'custom-linux'
uses: actions-rs/cargo@v1
@@ -117,4 +109,4 @@ jobs:
uses: actions-rs/cargo@v1
with:
command: clippy
args: --workspace --all-targets --features wireguard,axum -- -D warnings
args: --workspace --all-targets --features wireguard -- -D warnings
+1 -1
View File
@@ -13,7 +13,7 @@ jobs:
- licenses bans sources
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- uses: EmbarkStudios/cargo-deny-action@v1
with:
log-level: warn
+1 -1
View File
@@ -15,7 +15,7 @@ jobs:
CARGO_TERM_COLOR: always
steps:
- name: Check out repository code
uses: actions/checkout@v4
uses: actions/checkout@v2
- name: Install Rust toolchain
uses: actions-rs/toolchain@v1
@@ -15,13 +15,13 @@ jobs:
strategy:
fail-fast: false
matrix:
platform: [ ubuntu-20.04 ]
platform: [ubuntu-20.04]
runs-on: ${{ matrix.platform }}
env:
CARGO_TERM_COLOR: always
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- name: Prepare build output directory
shell: bash
@@ -58,7 +58,6 @@ 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_ecash.wasm $OUTPUT_DIR
- name: Deploy branch to CI www
continue-on-error: true
+2 -2
View File
@@ -17,7 +17,7 @@ jobs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
steps:
# creates the matrix strategy from ci-contracts-matrix-includes.json
- uses: actions/checkout@v4
- uses: actions/checkout@v2
- id: set-matrix
uses: JoshuaTheMiller/conditional-build-matrix@main
with:
@@ -34,7 +34,7 @@ jobs:
fail-fast: false
matrix: ${{fromJson(needs.matrix_prep.outputs.matrix)}}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v2
- name: Setup rust
uses: actions-rs/toolchain@v1
+4 -4
View File
@@ -11,7 +11,7 @@ jobs:
build:
runs-on: ubuntu-20.04-16-core
steps:
- uses: actions/checkout@v4
- 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
@@ -21,7 +21,7 @@ jobs:
- name: Install rsync
run: sudo apt-get install rsync
- uses: rlespinasse/github-slug-action@v3.x
- uses: actions/setup-node@v4
- uses: actions/setup-node@v3
with:
node-version: 18
- name: Install Rust stable
@@ -46,8 +46,8 @@ jobs:
# 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: Git pull & switch to b332a6b55668f60988e36961f3f62a794ba82ddb
run: git pull && git checkout b332a6b55668f60988e36961f3f62a794ba82ddb
- name: Build all projects in documentation/ & move to ~/dist/docs/ from b332a6b55668f60988e36961f3f62a794ba82ddb
run: cd documentation && ./build_all_to_dist.sh
+3 -3
View File
@@ -15,10 +15,10 @@ jobs:
build:
runs-on: ubuntu-20.04-16-core
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v2
- uses: rlespinasse/github-slug-action@v3.x
- uses: actions/setup-node@v4
- uses: actions/setup-node@v3
with:
node-version: 18
- name: Setup yarn
@@ -38,7 +38,7 @@ jobs:
version: '116'
- name: Set up Go
uses: actions/setup-go@v5
uses: actions/setup-go@v4
with:
go-version: '1.20'
+2 -2
View File
@@ -15,7 +15,7 @@ jobs:
name: nym-api tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v2
- name: install yarn in root
run: cd ../.. && yarn install
@@ -24,7 +24,7 @@ jobs:
run: npm install
- name: Node v18
uses: actions/setup-node@v4
uses: actions/setup-node@v3
with:
node-version: 18.1.0
@@ -14,12 +14,12 @@ jobs:
build:
runs-on: custom-linux
steps:
- uses: actions/checkout@v4
- 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@v4
- uses: actions/setup-node@v3
with:
node-version: 18
- name: Setup yarn
+1 -1
View File
@@ -25,7 +25,7 @@ jobs:
continue-on-error: true
- name: Check out repository code
uses: actions/checkout@v4
uses: actions/checkout@v2
- name: Install rust toolchain
uses: actions-rs/toolchain@v1
@@ -9,7 +9,7 @@ jobs:
build:
runs-on: custom-linux
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v2
- name: Install rsync
run: sudo apt-get install rsync
@@ -17,7 +17,7 @@ jobs:
- uses: rlespinasse/github-slug-action@v3.x
- uses: actions/setup-node@v4
- uses: actions/setup-node@v3
with:
node-version: 18
+3 -3
View File
@@ -10,12 +10,12 @@ jobs:
build:
runs-on: custom-linux
steps:
- uses: actions/checkout@v4
- 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@v4
- uses: actions/setup-node@v3
with:
node-version: 18.17
- name: Install Rust stable
@@ -26,7 +26,7 @@ jobs:
run: npm install -g yarn
- name: Set up Go
uses: actions/setup-go@v5
uses: actions/setup-go@v4
with:
go-version: '1.20'
+3 -3
View File
@@ -13,9 +13,9 @@ jobs:
env:
CARGO_TERM_COLOR: always
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v2
- uses: actions/setup-node@v4
- uses: actions/setup-node@v3
with:
node-version: 18
@@ -28,7 +28,7 @@ jobs:
components: rustfmt, clippy
- name: Set up Go
uses: actions/setup-go@v5
uses: actions/setup-go@v4
with:
go-version: '1.20'
+4 -4
View File
@@ -30,14 +30,14 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v3
- name: Setup Pages
uses: actions/configure-pages@v5
uses: actions/configure-pages@v3
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
uses: actions/upload-pages-artifact@v2
with:
# Upload entire repository
path: './ppa'
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
uses: actions/deploy-pages@v2
+5 -5
View File
@@ -18,7 +18,7 @@ jobs:
continue-on-error: true
steps:
- name: Check out repository code
uses: actions/checkout@v4
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
@@ -33,7 +33,7 @@ jobs:
components: rustfmt, clippy
- name: Install Protoc
uses: arduino/setup-protoc@v3
uses: arduino/setup-protoc@v2
if: matrix.os == 'macos-latest' || matrix.os == 'windows-latest'
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
@@ -98,11 +98,11 @@ jobs:
runs-on: custom-linux
steps:
- name: Collect jobs status
uses: technote-space/workflow-conclusion-action@v3
uses: technote-space/workflow-conclusion-action@v2
- name: Check out repository code
uses: actions/checkout@v4
uses: actions/checkout@v3
- name: install npm
uses: actions/setup-node@v4
uses: actions/setup-node@v3
if: env.WORKFLOW_CONCLUSION == 'failure'
with:
node-version: 18
@@ -15,7 +15,7 @@ jobs:
output1: ${{ steps.step2.outputs.latest_release }}
steps:
- name: Check out repository code
uses: actions/checkout@v4
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Set output variable to latest release branch
@@ -28,7 +28,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout repo
uses: actions/checkout@v4
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Setup git user
@@ -47,7 +47,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout repo
uses: actions/checkout@v4
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Setup git user
@@ -18,7 +18,7 @@ jobs:
continue-on-error: true
steps:
- name: Check out repository code
uses: actions/checkout@v4
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
@@ -61,11 +61,11 @@ jobs:
runs-on: custom-linux
steps:
- name: Collect jobs status
uses: technote-space/workflow-conclusion-action@v3
uses: technote-space/workflow-conclusion-action@v2
- name: Check out repository code
uses: actions/checkout@v4
uses: actions/checkout@v3
- name: install npm
uses: actions/setup-node@v4
uses: actions/setup-node@v3
if: env.WORKFLOW_CONCLUSION == 'failure'
with:
node-version: 18
+5 -5
View File
@@ -8,7 +8,7 @@ jobs:
runs-on: ubuntu-20.04
steps:
- name: Checkout repository code
uses: actions/checkout@v4
uses: actions/checkout@v2
- name: Install rust toolchain
uses: actions-rs/toolchain@v1
with:
@@ -20,7 +20,7 @@ jobs:
find . -name Cargo.toml -exec cargo deny --manifest-path {} check \
advisories -A advisory-not-detected --hide-inclusion-graph \; &> \
>(uniq &> .github/workflows/support-files/notifications/deny.message )
- uses: actions/upload-artifact@v4
- uses: actions/upload-artifact@v3
with:
name: report
path: .github/workflows/support-files/notifications/deny.message
@@ -29,14 +29,14 @@ jobs:
runs-on: custom-linux
steps:
- name: Check out repository code
uses: actions/checkout@v4
uses: actions/checkout@v2
- name: Download report from previous job
uses: actions/download-artifact@v4
uses: actions/download-artifact@v3
with:
name: report
path: .github/workflows/support-files/notifications
- name: install npm
uses: actions/setup-node@v4
uses: actions/setup-node@v3
with:
node-version: 18
- name: Matrix - Node Install
+5 -9
View File
@@ -40,7 +40,7 @@ jobs:
cli_version: ${{ steps.binary-versions.outputs.cli_version }}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- name: Install Dependencies (Linux)
run: sudo apt-get update && sudo apt-get -y install ripgrep libwebkit2gtk-4.0-dev build-essential curl wget libssl-dev libgtk-3-dev libudev-dev squashfs-tools
@@ -51,10 +51,6 @@ jobs:
echo 'RUSTFLAGS="--cfg tokio_unstable"' >> $GITHUB_ENV
if: github.event_name == 'workflow_dispatch' && inputs.add_tokio_unstable == true
- name: Set CARGO_FEATURES
run: |
echo 'CARGO_FEATURES=--features wireguard' >> $GITHUB_ENV
- name: Install Rust stable
uses: actions-rs/toolchain@v1
with:
@@ -64,10 +60,10 @@ jobs:
uses: actions-rs/cargo@v1
with:
command: build
args: --workspace --release ${{ env.CARGO_FEATURES }}
args: --workspace --release
- name: Upload Artifact
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v3
with:
name: my-artifact
path: |
@@ -83,7 +79,7 @@ jobs:
- id: create-release
name: Upload to release based on tag name
uses: softprops/action-gh-release@v2
uses: softprops/action-gh-release@v1
if: github.event_name == 'release'
with:
files: |
+4 -4
View File
@@ -9,7 +9,7 @@ jobs:
if: ${{ (startsWith(github.ref, 'refs/tags/nym-contracts-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
runs-on: [self-hosted, custom-ubuntu-20.04]
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v2
- name: Install Rust stable
uses: actions-rs/toolchain@v1
@@ -26,21 +26,21 @@ jobs:
run: make contracts
- name: Upload Mixnet Contract Artifact
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v3
with:
name: mixnet_contract.wasm
path: contracts/target/wasm32-unknown-unknown/release/mixnet_contract.wasm
retention-days: 5
- name: Upload Vesting Contract Artifact
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v3
with:
name: vesting_contract.wasm
path: contracts/target/wasm32-unknown-unknown/release/vesting_contract.wasm
retention-days: 5
- name: Upload to release based on tag name
uses: softprops/action-gh-release@v2
uses: softprops/action-gh-release@v1
if: github.event_name == 'release'
with:
files: |
@@ -25,10 +25,10 @@ jobs:
file_hash: ${{ steps.release-info.outputs.file_hash }}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v2
- name: Node
uses: actions/setup-node@v4
uses: actions/setup-node@v3
with:
node-version: 18
- name: Install Rust stable
@@ -83,7 +83,7 @@ jobs:
run: yarn && yarn build
- name: Upload Artifact
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v3
with:
name: nym-wallet.app.tar.gz
path: nym-wallet/target/release/bundle/macos/nym-wallet.app.tar.gz
@@ -95,7 +95,7 @@ jobs:
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@v2
uses: softprops/action-gh-release@v1
if: github.event_name == 'release'
with:
files: |
@@ -25,7 +25,7 @@ jobs:
file_hash: ${{ steps.release-info.outputs.file_hash }}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v2
- name: Tauri dependencies
run: >
@@ -34,7 +34,7 @@ jobs:
continue-on-error: true
- name: Node
uses: actions/setup-node@v4
uses: actions/setup-node@v3
with:
node-version: 18
@@ -62,7 +62,7 @@ jobs:
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
- name: Upload Artifact
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v3
with:
name: nym-wallet_1.0.0_amd64.AppImage.tar.gz
path: nym-wallet/target/release/bundle/appimage/nym-wallet*.AppImage.tar.gz
@@ -70,7 +70,7 @@ jobs:
- id: create-release
name: Upload to release based on tag name
uses: softprops/action-gh-release@v2
uses: softprops/action-gh-release@v1
if: github.event_name == 'release'
with:
files: |
@@ -33,7 +33,7 @@ jobs:
del /s /q /A:H nym
rmdir /s /q nym
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- name: Import signing certificate
env:
@@ -47,7 +47,7 @@ jobs:
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@v4
uses: actions/setup-node@v3
with:
node-version: 18
@@ -82,7 +82,7 @@ jobs:
run: yarn build
- name: Upload Artifact
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v3
with:
name: nym-wallet_1.0.0_x64_en-US.msi
path: nym-wallet/target/release/bundle/msi/nym-wallet_1.*.msi
@@ -90,7 +90,7 @@ jobs:
- id: create-release
name: Upload to release based on tag name
uses: softprops/action-gh-release@v2
uses: softprops/action-gh-release@v1
if: github.event_name == 'release'
with:
files: |
@@ -22,10 +22,10 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v3
- name: Install Java
uses: actions/setup-java@v4
uses: actions/setup-java@v3
with:
distribution: "temurin"
java-version: "17"
@@ -49,7 +49,7 @@ jobs:
"build-tools;$SDK_BUILDTOOLS_VERSION"
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@1.90.0
uses: dtolnay/rust-toolchain@1.70.0
- name: Install rust android targets
run: |
@@ -84,7 +84,7 @@ jobs:
apk/nyms5-arch64-release.apk
- name: Upload APKs
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v3
with:
name: nyms5-apk-arch64
path: |
@@ -97,14 +97,14 @@ jobs:
runs-on: custom-linux
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v3
- name: Download binary artifact
uses: actions/download-artifact@v4
uses: actions/download-artifact@v3
with:
name: nyms5-apk-arch64
path: apk
- name: Release
uses: softprops/action-gh-release@v2
uses: softprops/action-gh-release@v1
with:
files: |
apk/nyms5-arch64-debug.apk
+4 -4
View File
@@ -6,10 +6,10 @@ jobs:
publish:
runs-on: ubuntu-20.04-16-core
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v2
- name: Install Node
uses: actions/setup-node@v4
uses: actions/setup-node@v3
with:
node-version: 18
registry-url: "https://registry.npmjs.org"
@@ -29,12 +29,12 @@ jobs:
run: cargo install wasm-opt
- name: Set up Go
uses: actions/setup-go@v5
uses: actions/setup-go@v4
with:
go-version: "1.20"
- name: Install TinyGo
uses: acifani/setup-tinygo@v2
uses: acifani/setup-tinygo@v1
with:
tinygo-version: "0.27.0"
+3 -3
View File
@@ -20,8 +20,8 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Check out repository code
uses: actions/checkout@v4
- uses: actions/setup-node@v4
uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 18
- uses: nymtech/nym/.github/actions/nym-hash-releases@develop
@@ -30,7 +30,7 @@ jobs:
with:
release-tag-or-name-or-id: ${{ inputs.release_tag }}
- uses: actions/upload-artifact@v4
- uses: actions/upload-artifact@v2
with:
name: Asset Hashes
path: hashes.json
+1 -4
View File
@@ -48,7 +48,4 @@ foxyfox.env
.next
ppa-private-key.b64
ppa-private-key.asc
nym-network-monitor/topology.json
nym-network-monitor/__pycache__
nym-network-monitor/*.key
ppa-private-key.asc
+1 -38
View File
@@ -4,44 +4,6 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
## [Unreleased]
## [2024.9-topdeck] (2024-07-26)
- chore: fix 1.80 lint issues ([#4731])
- Handle clients with different versions in IPR ([#4723])
- Add 1GB/day/user bandwidth cap ([#4717])
- Feature/merge back ([#4710])
- removed mixnode/gateway config migration code and disabled cli without explicit flag ([#4706])
[#4731]: https://github.com/nymtech/nym/pull/4731
[#4723]: https://github.com/nymtech/nym/pull/4723
[#4717]: https://github.com/nymtech/nym/pull/4717
[#4710]: https://github.com/nymtech/nym/pull/4710
[#4706]: https://github.com/nymtech/nym/pull/4706
## [2024.8-wispa] (2024-07-10)
- add event parsing to support cosmos_sdk > 0.50 ([#4697])
- Fix NR config compatibility ([#4690])
- Remove UserAgent constructor since it's weakly typed ([#4689])
- [bugfix]: Node_api_check CLI looked over roles on blacklisted nodes ([#4687])
- Add mixnodes to self describing api cache ([#4684])
- Move and whole bump of crates to workspace and upgrade some ([#4680])
- Remove code that refers to removed nym-network-statistics ([#4679])
- Remove nym-network-statistics ([#4678])
- Create UserAgent that can be passed from the binary to the nym api client ([#4677])
- Add authenticator ([#4667])
[#4697]: https://github.com/nymtech/nym/pull/4697
[#4690]: https://github.com/nymtech/nym/pull/4690
[#4689]: https://github.com/nymtech/nym/pull/4689
[#4687]: https://github.com/nymtech/nym/pull/4687
[#4684]: https://github.com/nymtech/nym/pull/4684
[#4680]: https://github.com/nymtech/nym/pull/4680
[#4679]: https://github.com/nymtech/nym/pull/4679
[#4678]: https://github.com/nymtech/nym/pull/4678
[#4677]: https://github.com/nymtech/nym/pull/4677
[#4667]: https://github.com/nymtech/nym/pull/4667
## [2024.7-doubledecker] (2024-07-04)
- Add an early return in `parse_raw_str_logs` for empty raw log strings. ([#4686])
@@ -551,6 +513,7 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
[#3187]: https://github.com/nymtech/nym/issues/3187
[#3203]: https://github.com/nymtech/nym/pull/3203
[#3199]: https://github.com/nymtech/nym/pull/3199
>>>>>>> master
## [v1.1.13] (2023-03-15)
Generated
+597 -1154
View File
File diff suppressed because it is too large Load Diff
+42 -80
View File
@@ -14,12 +14,12 @@ panic = "abort"
opt-level = 3
[workspace]
resolver = "2"
members = [
"clients/native",
"clients/native/websocket-requests",
"clients/socks5",
"common/authenticator-requests",
"common/async-file-watcher",
"common/bandwidth-controller",
"common/bin-common",
@@ -33,7 +33,6 @@ members = [
"common/commands",
"common/config",
"common/cosmwasm-smart-contracts/coconut-bandwidth-contract",
"common/cosmwasm-smart-contracts/ecash-contract",
"common/cosmwasm-smart-contracts/coconut-dkg",
"common/cosmwasm-smart-contracts/contracts-common",
"common/cosmwasm-smart-contracts/group-contract",
@@ -47,12 +46,8 @@ members = [
"common/credentials-interface",
"common/crypto",
"common/dkg",
"common/ecash-double-spending",
"common/ecash-time",
"common/execute",
"common/exit-policy",
"common/gateway-requests",
"common/gateway-storage",
"common/http-api-client",
"common/http-api-common",
"common/inclusion-probability",
@@ -63,7 +58,6 @@ members = [
"common/node-tester-utils",
"common/nonexhaustive-delayqueue",
"common/nymcoconut",
"common/nym_offline_compact_ecash",
"common/nym-id",
"common/nym-metrics",
"common/nymsphinx",
@@ -79,10 +73,10 @@ members = [
"common/nymsphinx/types",
"common/nyxd-scraper",
"common/pemstore",
"common/serde-helpers",
"common/socks5-client-core",
"common/socks5/proxy-helpers",
"common/socks5/requests",
"common/statistics",
"common/store-cipher",
"common/task",
"common/topology",
@@ -97,15 +91,15 @@ members = [
"explorer-api/explorer-api-requests",
"explorer-api/explorer-client",
"gateway",
"gateway/gateway-requests",
"integrations/bity",
"mixnode",
"sdk/lib/socks5-listener",
"sdk/rust/nym-sdk",
"service-providers/authenticator",
"service-providers/common",
"service-providers/ip-packet-router",
"service-providers/network-requester",
"nym-network-monitor",
"service-providers/network-statistics",
"nym-api",
"nym-browser-extension/storage",
"nym-api/nym-api-requests",
@@ -126,8 +120,6 @@ members = [
"wasm/mix-fetch",
"wasm/node-tester",
"wasm/zknym-lib",
"tools/internal/testnet-manager",
"tools/internal/testnet-manager/dkg-bypass-contract",
]
default-members = [
@@ -135,19 +127,19 @@ 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",
"nym-node"
]
exclude = [
"explorer",
"contracts",
"nym-wallet",
"nym-vpn/ui/src-tauri",
"cpu-cycles",
"sdk/ffi/cpp",
]
@@ -159,8 +151,6 @@ homepage = "https://nymtech.net"
documentation = "https://nymtech.net"
edition = "2021"
license = "Apache-2.0"
rust-version = "1.80"
readme = "README.md"
[workspace.dependencies]
addr = "0.15.6"
@@ -168,22 +158,17 @@ aes = "0.8.1"
aes-gcm = "0.10.1"
anyhow = "1.0.71"
argon2 = "0.5.0"
async-trait = "0.1.81"
async-trait = "0.1.68"
axum = "0.7.5"
axum-extra = "0.9.3"
base64 = "0.22.1"
base64 = "0.21.4"
bincode = "1.3.3"
bip39 = { version = "2.0.0", features = ["zeroize"] }
# can we unify those?
bit-vec = "0.7.0"
bitvec = "1.0.0"
blake3 = "1.5.4"
bloomfilter = "1.0.14"
blake3 = "1.3.1"
bs58 = "0.5.1"
bytecodec = "0.4.15"
bytes = "1.7.1"
bytes = "1.5.0"
cargo_metadata = "0.18.1"
celes = "2.4.0"
cfg-if = "1.0.0"
@@ -191,12 +176,11 @@ chacha20 = "0.9.0"
chacha20poly1305 = "0.10.1"
chrono = "0.4.31"
cipher = "0.4.3"
clap = "4.5.16"
clap_complete = "4.5"
clap_complete_fig = "4.5"
clap = "4.4.7"
clap_complete = "4.0"
clap_complete_fig = "4.0"
colored = "2.0"
comfy-table = "6.0.0"
console = "0.15.8"
console-subscriber = "0.1.1"
console_error_panic_hook = "0.1"
const-str = "0.5.6"
@@ -208,16 +192,13 @@ cupid = "0.6.1"
curve25519-dalek = "4.1"
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.1"
flate2 = "1.0.33"
flate2 = "1.0.28"
futures = "0.3.28"
generic-array = "0.14.7"
getrandom = "0.2.10"
@@ -228,17 +209,15 @@ 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"
http = "1"
hyper = "1.3.1"
indicatif = "0.17.8"
indexed_db_futures = "0.3.0"
inquire = "0.6.2"
ip_network = "0.4.1"
ipnetwork = "0.20"
isocountry = "0.3.2"
itertools = "0.13.0"
k256 = "0.13"
lazy_static = "1.4.0"
ledger-transport = "0.10.0"
@@ -254,54 +233,48 @@ opentelemetry = "0.19.0"
opentelemetry-jaeger = "0.18.0"
parking_lot = "0.12.1"
pem = "0.8"
petgraph = "0.6.5"
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.10.6"
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.12"
safer-ffi = "0.1.4"
schemars = "0.8.1"
semver = "1.0.23"
serde = "1.0.209"
serde_bytes = "0.11.15"
serde = "1.0.152"
serde_bytes = "0.11.6"
serde_derive = "1.0"
serde_json = "1.0.127"
serde_json = "1.0.91"
serde_repr = "0.1"
serde_with = "3.9.0"
serde_with = "3.4.0"
serde_yaml = "0.9.25"
sha2 = "0.10.8"
si-scale = "0.2.3"
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.63"
thiserror = "1.0.48"
time = "0.3.30"
tokio = "1.39"
tokio-stream = "0.1.15"
tokio-test = "0.4.4"
tokio = "1.33.0"
tokio-stream = "0.1.14"
tokio-test = "0.4.2"
tokio-tungstenite = { version = "0.20.1" }
tokio-util = "0.7.11"
toml = "0.8.14"
tokio-util = "0.7.10"
tower = "0.4.13"
tower-http = "0.5.2"
tracing = "0.1.37"
@@ -310,16 +283,12 @@ tracing-subscriber = "0.3.16"
tracing-tree = "0.2.2"
ts-rs = "7.0.0"
tungstenite = { version = "0.20.1", default-features = false }
url = "2.5"
utoipa = "4.2"
utoipa-rapidoc = "4.0"
utoipa-swagger-ui = "7.1"
utoipauto = "0.1"
uuid = "*"
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" }
@@ -327,8 +296,7 @@ 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
# plus to make our live easier we need serde support from https://github.com/zkcrypto/bls12_381/pull/125
bls12_381 = { git = "https://github.com/jstuczyn/bls12_381", default-features = false, branch = "temp/experimental-serdect" }
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 }
@@ -349,31 +317,25 @@ cw4 = { version = "=1.1.2" }
cw-controllers = { version = "=1.1.0" }
# cosmrs-related
bip32 = { version = "0.5.2", default-features = false }
bip32 = { version = "0.5.1", default-features = false }
# temporarily using a fork again (yay.) because we need staking and slashing support (which are already on main but not released)
# plus response message parsing (which is, as of the time of writing this message, waiting to get merged)
#cosmrs = { path = "../cosmos-rust-fork/cosmos-rust/cosmrs" }
cosmrs = { git = "https://github.com/cosmos/cosmos-rust", rev = "4b1332e6d8258ac845cef71589c8d362a669675a" } # unfortuntely we need a fork by yours truly to get the staking support
tendermint = "0.37.0" # same version as used by cosmrs
tendermint-rpc = "0.37.0" # same version as used by cosmrs
# 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 }
# wasm-related dependencies
gloo-utils = "0.2.0"
gloo-net = "0.5.0"
# use a separate branch due to feature unification failures
# this is blocked until the upstream removes outdates `wasm_bindgen` feature usage
# indexed_db_futures = "0.4.1"
indexed_db_futures = { git = "https://github.com/TiemenSch/rust-indexed-db", branch = "update-uuid" }
js-sys = "0.3.70"
js-sys = "0.3.69"
serde-wasm-bindgen = "0.6.5"
tsify = "0.4.5"
wasm-bindgen = "0.2.93"
wasm-bindgen-futures = "0.4.43"
wasm-bindgen = "0.2.92"
wasm-bindgen-futures = "0.4.39"
wasmtimer = "0.2.0"
web-sys = "0.3.70"
web-sys = "0.3.69"
# Profile settings for individual crates
+1 -1
View File
@@ -133,7 +133,7 @@ clippy: sdk-wasm-lint
# Build contracts ready for deploy
# -----------------------------------------------------------------------------
CONTRACTS=vesting_contract mixnet_contract nym_ecash
CONTRACTS=vesting_contract mixnet_contract
CONTRACTS_WASM=$(addsuffix .wasm, $(CONTRACTS))
CONTRACTS_OUT_DIR=contracts/target/wasm32-unknown-unknown/release
+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://nymtech.net/go/discord)
* 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.
+8 -24
View File
@@ -1,6 +1,6 @@
[package]
name = "nym-client"
version = "1.1.39"
version = "1.1.37"
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"]
description = "Implementation of the Nym Client"
edition = "2021"
@@ -23,49 +23,33 @@ 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 }
serde = { workspace = true, features = [
"derive",
] } # for config serialization/deserialization
serde = { workspace = true, features = ["derive"] } # for config serialization/deserialization
serde_json = { workspace = true }
thiserror = { workspace = true }
tap = { workspace = true }
time = { workspace = true }
tokio = { workspace = true, features = [
"rt-multi-thread",
"net",
"signal",
] } # async runtime
tokio = { workspace = true, features = ["rt-multi-thread", "net", "signal"] } # async runtime
tokio-tungstenite = { workspace = true }
zeroize = { workspace = true }
## internal
nym-bandwidth-controller = { path = "../../common/bandwidth-controller" }
nym-bin-common = { path = "../../common/bin-common", features = [
"output_format",
"clap",
] }
nym-client-core = { path = "../../common/client-core", features = [
"fs-credentials-storage",
"fs-surb-storage",
"fs-gateways-storage",
"cli",
] }
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 = "../../common/gateway-requests" }
nym-gateway-requests = { path = "../../gateway/gateway-requests" }
nym-network-defaults = { path = "../../common/network-defaults" }
nym-sphinx = { path = "../../common/nymsphinx" }
nym-pemstore = { path = "../../common/pemstore" }
nym-task = { path = "../../common/task" }
nym-topology = { path = "../../common/topology" }
nym-validator-client = { path = "../../common/client-libs/validator-client", features = [
"http-client",
] }
nym-validator-client = { path = "../../common/client-libs/validator-client", features = ["http-client"] }
nym-client-websocket-requests = { path = "websocket-requests" }
nym-id = { path = "../../common/nym-id" }
+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(())
+2 -2
View File
@@ -73,6 +73,7 @@ impl From<Init> for OverrideConfig {
fn from(init_config: Init) -> Self {
OverrideConfig {
nym_apis: init_config.common_args.nym_apis,
fronting_domains: init_config.common_args.fronting_domains,
disable_socket: init_config.disable_socket,
port: init_config.port,
host: init_config.host,
@@ -114,9 +115,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));
+5 -5
View File
@@ -26,7 +26,6 @@ pub(crate) mod import_credential;
pub(crate) mod init;
mod list_gateways;
pub(crate) mod run;
mod show_ticketbooks;
mod switch_gateway;
pub(crate) struct CliNativeClient;
@@ -85,9 +84,6 @@ pub(crate) enum Commands {
/// Change the currently active gateway. Note that you must have already registered with the new gateway!
SwitchGateway(switch_gateway::Args),
/// Display information associated with the imported ticketbooks,
ShowTicketbooks(show_ticketbooks::Args),
/// Show build information of this binary
BuildInfo(build_info::BuildInfo),
@@ -101,6 +97,7 @@ pub(crate) enum Commands {
// Configuration that can be overridden.
pub(crate) struct OverrideConfig {
nym_apis: Option<Vec<url::Url>>,
fronting_domains: Option<Vec<url::Url>>,
disable_socket: Option<bool>,
port: Option<u16>,
host: Option<IpAddr>,
@@ -120,7 +117,6 @@ pub(crate) async fn execute(args: Cli) -> Result<(), Box<dyn Error + Send + Sync
Commands::ListGateways(args) => list_gateways::execute(args).await?,
Commands::AddGateway(args) => add_gateway::execute(args).await?,
Commands::SwitchGateway(args) => switch_gateway::execute(args).await?,
Commands::ShowTicketbooks(args) => show_ticketbooks::execute(args).await?,
Commands::BuildInfo(m) => build_info::execute(m),
Commands::Completions(s) => s.generate(&mut Cli::command(), bin_name),
Commands::GenerateFigSpec => fig_generate(&mut Cli::command(), bin_name),
@@ -138,6 +134,10 @@ pub(crate) fn override_config(config: Config, args: OverrideConfig) -> Config {
.with_base(BaseClientConfig::with_disabled_cover_traffic, args.no_cover)
.with_optional(Config::with_port, args.port)
.with_optional(Config::with_host, args.host)
.with_optional_ext(
BaseClientConfig::with_fronting_domains,
args.fronting_domains,
)
.with_optional_custom_env_ext(
BaseClientConfig::with_custom_nym_apis,
args.nym_apis,
+1
View File
@@ -36,6 +36,7 @@ impl From<Run> for OverrideConfig {
fn from(run_config: Run) -> Self {
OverrideConfig {
nym_apis: run_config.common_args.nym_apis,
fronting_domains: run_config.common_args.fronting_domains,
disable_socket: run_config.disable_socket,
port: run_config.port,
host: run_config.host,
@@ -1,32 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::commands::CliNativeClient;
use crate::error::ClientError;
use nym_bin_common::output_format::OutputFormat;
use nym_client_core::cli_helpers::client_show_ticketbooks::{
show_ticketbooks, CommonShowTicketbooksArgs,
};
#[derive(clap::Args)]
pub(crate) struct Args {
#[command(flatten)]
common_args: CommonShowTicketbooksArgs,
#[arg(short, long, default_value_t = OutputFormat::default())]
output: OutputFormat,
}
impl AsRef<CommonShowTicketbooksArgs> for Args {
fn as_ref(&self) -> &CommonShowTicketbooksArgs {
&self.common_args
}
}
pub(crate) async fn execute(args: Args) -> Result<(), ClientError> {
let output = args.output;
let res = show_ticketbooks::<CliNativeClient, _>(args).await?;
println!("{}", output.format(&res));
Ok(())
}
+1 -1
View File
@@ -422,7 +422,7 @@ impl Handler {
) {
// We don't want a crash in the connection handler to trigger a shutdown of the whole
// process.
task_client.disarm();
task_client.mark_as_success();
let ws_stream = match accept_async(socket).await {
Ok(ws_stream) => ws_stream,
+9 -22
View File
@@ -1,6 +1,6 @@
[package]
name = "nym-socks5-client"
version = "1.1.39"
version = "1.1.37"
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"
@@ -11,9 +11,7 @@ license.workspace = true
bs58 = { workspace = true }
clap = { workspace = true, features = ["cargo", "derive"] }
log = { workspace = true }
serde = { workspace = true, features = [
"derive",
] } # for config serialization/deserialization
serde = { workspace = true, features = ["derive"] } # for config serialization/deserialization
serde_json = { workspace = true }
tap = { workspace = true }
thiserror = { workspace = true }
@@ -24,31 +22,20 @@ url = { workspace = true }
zeroize = { workspace = true }
# internal
nym-bin-common = { path = "../../common/bin-common", features = [
"output_format",
"clap",
] }
nym-client-core = { path = "../../common/client-core", features = [
"fs-credentials-storage",
"fs-surb-storage",
"fs-gateways-storage",
"cli",
] }
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 = "../../common/gateway-requests" }
nym-id = { path = "../../common/nym-id" }
nym-gateway-requests = { path = "../../gateway/gateway-requests" }
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(())
+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));
-5
View File
@@ -30,7 +30,6 @@ mod import_credential;
pub mod init;
mod list_gateways;
pub(crate) mod run;
mod show_ticketbooks;
mod switch_gateway;
pub(crate) struct CliSocks5Client;
@@ -89,9 +88,6 @@ pub(crate) enum Commands {
/// Change the currently active gateway. Note that you must have already registered with the new gateway!
SwitchGateway(switch_gateway::Args),
/// Display information associated with the imported ticketbooks,
ShowTicketbooks(show_ticketbooks::Args),
/// Show build information of this binary
BuildInfo(build_info::BuildInfo),
@@ -127,7 +123,6 @@ pub(crate) async fn execute(args: Cli) -> Result<(), Box<dyn Error + Send + Sync
Commands::ListGateways(args) => list_gateways::execute(args).await?,
Commands::AddGateway(args) => add_gateway::execute(args).await?,
Commands::SwitchGateway(args) => switch_gateway::execute(args).await?,
Commands::ShowTicketbooks(args) => show_ticketbooks::execute(args).await?,
Commands::BuildInfo(m) => build_info::execute(m),
Commands::Completions(s) => s.generate(&mut Cli::command(), bin_name),
Commands::GenerateFigSpec => fig_generate(&mut Cli::command(), bin_name),
+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
}
@@ -1,32 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::commands::CliSocks5Client;
use crate::error::Socks5ClientError;
use nym_bin_common::output_format::OutputFormat;
use nym_client_core::cli_helpers::client_show_ticketbooks::{
show_ticketbooks, CommonShowTicketbooksArgs,
};
#[derive(clap::Args)]
pub(crate) struct Args {
#[command(flatten)]
common_args: CommonShowTicketbooksArgs,
#[arg(short, long, default_value_t = OutputFormat::default())]
output: OutputFormat,
}
impl AsRef<CommonShowTicketbooksArgs> for Args {
fn as_ref(&self) -> &CommonShowTicketbooksArgs {
&self.common_args
}
}
pub(crate) async fn execute(args: Args) -> Result<(), Socks5ClientError> {
let output = args.output;
let res = show_ticketbooks::<CliSocks5Client, _>(args).await?;
println!("{}", output.format(&res));
Ok(())
}
-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,84 +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, PeerPublicKey};
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 new_query_request(peer_public_key: PeerPublicKey, reply_to: Recipient) -> (Self, u64) {
let request_id = generate_random();
(
Self {
version: VERSION,
data: AuthenticatorRequestData::QueryBandwidth(peer_public_key),
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),
QueryBandwidth(PeerPublicKey),
}
@@ -1,119 +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, RegistredData, RemainingBandwidthData};
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(
registred_data: RegistredData,
reply_to: Recipient,
request_id: u64,
) -> Self {
Self {
version: VERSION,
data: AuthenticatorResponseData::Registered(RegisteredResponse {
reply: registred_data,
reply_to,
request_id,
}),
reply_to,
}
}
pub fn new_remaining_bandwidth(
remaining_bandwidth_data: Option<RemainingBandwidthData>,
reply_to: Recipient,
request_id: u64,
) -> Self {
Self {
version: VERSION,
data: AuthenticatorResponseData::RemainingBandwidth(RemainingBandwidthResponse {
reply: remaining_bandwidth_data,
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),
AuthenticatorResponseData::RemainingBandwidth(response) => Some(response.request_id),
}
}
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub enum AuthenticatorResponseData {
PendingRegistration(PendingRegistrationResponse),
Registered(RegisteredResponse),
RemainingBandwidth(RemainingBandwidthResponse),
}
#[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,
pub reply: RegistredData,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct RemainingBandwidthResponse {
pub request_id: u64,
pub reply_to: Recipient,
pub reply: Option<RemainingBandwidthData>,
}
+1 -2
View File
@@ -14,14 +14,13 @@ thiserror = { workspace = true }
url = { workspace = true }
zeroize = { workspace = true }
nym-ecash-time = { path = "../ecash-time" }
nym-coconut = { path = "../nymcoconut" }
nym-credential-storage = { path = "../credential-storage" }
nym-credentials = { path = "../credentials" }
nym-credentials-interface = { path = "../credentials-interface" }
nym-crypto = { path = "../crypto", features = ["rand", "asymmetric", "symmetric", "aes", "hashing"] }
nym-network-defaults = { path = "../network-defaults" }
nym-validator-client = { path = "../client-libs/validator-client", default-features = false }
nym-ecash-contract-common = { path = "../cosmwasm-smart-contracts/ecash-contract" }
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.nym-validator-client]
path = "../client-libs/validator-client"
+50 -89
View File
@@ -1,126 +1,87 @@
// Copyright 2023-2024 - Nym Technologies SA <contact@nymtech.net>
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::error::BandwidthControllerError;
use crate::utils::{get_coin_index_signatures, get_expiration_date_signatures};
use log::info;
use nym_credential_storage::models::StorableIssuedCredential;
use nym_credential_storage::storage::Storage;
use nym_credentials::ecash::bandwidth::IssuanceTicketBook;
use nym_credentials::ecash::utils::obtain_aggregate_wallet;
use nym_credentials::IssuedTicketBook;
use nym_credentials_interface::TicketType;
use nym_crypto::asymmetric::identity;
use nym_ecash_time::{ecash_default_expiration_date, Date};
use nym_validator_client::coconut::all_ecash_api_clients;
use nym_validator_client::nym_api::EpochId;
use nym_validator_client::nyxd::contract_traits::EcashSigningClient;
use nym_validator_client::nyxd::contract_traits::{DkgQueryClient, EcashQueryClient};
use nym_validator_client::nyxd::cosmwasm_client::ToSingletonContractData;
use nym_validator_client::EcashApiClient;
use nym_credentials::coconut::bandwidth::{CredentialType, IssuanceBandwidthCredential};
use nym_credentials::coconut::utils::obtain_aggregate_signature;
use nym_crypto::asymmetric::{encryption, identity};
use nym_validator_client::coconut::all_coconut_api_clients;
use nym_validator_client::nyxd::contract_traits::CoconutBandwidthSigningClient;
use nym_validator_client::nyxd::contract_traits::DkgQueryClient;
use nym_validator_client::nyxd::Coin;
use rand::rngs::OsRng;
use state::State;
use zeroize::Zeroizing;
pub async fn make_deposit<C>(
client: &C,
client_id: &[u8],
expiration: Option<Date>,
ticketbook_type: TicketType,
) -> Result<IssuanceTicketBook, BandwidthControllerError>
pub mod state;
pub async fn deposit<C>(client: &C, amount: Coin) -> Result<State, BandwidthControllerError>
where
C: EcashSigningClient + EcashQueryClient + Sync,
C: CoconutBandwidthSigningClient + Sync,
{
let mut rng = OsRng;
let signing_key = identity::PrivateKey::new(&mut rng);
let expiration = expiration.unwrap_or_else(ecash_default_expiration_date);
let encryption_key = encryption::PrivateKey::new(&mut rng);
let deposit_amount = client.get_required_deposit_amount().await?;
info!("we'll need to deposit {deposit_amount} to obtain the ticketbook");
let result = client
.make_ticketbook_deposit(
let tx_hash = client
.deposit(
amount.clone(),
CredentialType::Voucher.to_string(),
signing_key.public_key().to_base58_string(),
deposit_amount.into(),
encryption_key.public_key().to_base58_string(),
None,
)
.await?;
.await?
.transaction_hash;
let deposit_id = result.parse_singleton_u32_contract_data()?;
let voucher =
IssuanceBandwidthCredential::new_voucher(amount, tx_hash, signing_key, encryption_key);
info!("our ticketbook deposit has been stored under id {deposit_id}");
let state = State { voucher };
Ok(IssuanceTicketBook::new_with_expiration(
deposit_id,
client_id,
signing_key,
ticketbook_type,
expiration,
))
Ok(state)
}
pub async fn query_and_persist_required_global_signatures<S>(
storage: &S,
epoch_id: EpochId,
expiration_date: Date,
apis: Vec<EcashApiClient>,
) -> Result<(), BandwidthControllerError>
where
S: Storage,
<S as Storage>::StorageError: Send + Sync + 'static,
{
log::info!("Getting expiration date signatures");
// this will also persist the signatures in the storage if they were not there already
get_expiration_date_signatures(storage, epoch_id, expiration_date, apis.clone()).await?;
log::info!("Getting coin indices signatures");
// this will also persist the signatures in the storage if they were not there already
get_coin_index_signatures(storage, epoch_id, apis).await?;
Ok(())
}
pub async fn get_ticket_book<C, St>(
issuance_data: &IssuanceTicketBook,
pub async fn get_bandwidth_voucher<C, St>(
state: &State,
client: &C,
storage: &St,
apis: Option<Vec<EcashApiClient>>,
) -> Result<IssuedTicketBook, BandwidthControllerError>
) -> Result<(), BandwidthControllerError>
where
C: DkgQueryClient + Send + Sync,
St: Storage,
<St as Storage>::StorageError: Send + Sync + 'static,
{
// temporary
assert!(state.voucher.typ().is_voucher());
let epoch_id = client.get_current_epoch().await?.epoch_id;
let threshold = client
.get_current_epoch_threshold()
.await?
.ok_or(BandwidthControllerError::NoThreshold)?;
let apis = match apis {
Some(apis) => apis,
None => all_ecash_api_clients(client, epoch_id).await?,
let coconut_api_clients = all_coconut_api_clients(client, epoch_id).await?;
let signature =
obtain_aggregate_signature(&state.voucher, &coconut_api_clients, threshold).await?;
let issued = state.voucher.to_issued_credential(signature, epoch_id);
// make sure the data gets zeroized after persisting it
let credential_data = Zeroizing::new(issued.pack_v1());
let storable = StorableIssuedCredential {
serialization_revision: issued.current_serialization_revision(),
credential_data: credential_data.as_ref(),
credential_type: issued.typ().to_string(),
epoch_id: epoch_id
.try_into()
.expect("our epoch is has run over u32::MAX!"),
};
log::info!("Querying wallet signatures");
let wallet = obtain_aggregate_wallet(issuance_data, &apis, threshold).await?;
info!("managed to obtain sufficient number of partial signatures!");
log::info!("Getting expiration date signatures");
// this will also persist the signatures in the storage if they were not there already
get_expiration_date_signatures(
storage,
epoch_id,
issuance_data.expiration_date(),
apis.clone(),
)
.await?;
log::info!("Getting coin indices signatures");
// this will also persist the signatures in the storage if they were not there already
get_coin_index_signatures(storage, epoch_id, apis).await?;
let issued = issuance_data.to_issued_ticketbook(wallet, epoch_id);
info!("persisting the ticketbook into the storage...");
storage
.insert_issued_ticketbook(&issued)
.insert_issued_credential(storable)
.await
.map_err(|err| BandwidthControllerError::CredentialStorageError(Box::new(err)))?;
Ok(issued)
.map_err(|err| BandwidthControllerError::CredentialStorageError(Box::new(err)))
}
@@ -0,0 +1,14 @@
// Copyright 2022-2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use nym_credentials::coconut::bandwidth::IssuanceBandwidthCredential;
pub struct State {
pub voucher: IssuanceBandwidthCredential,
}
impl State {
pub fn new(voucher: IssuanceBandwidthCredential) -> Self {
State { voucher }
}
}
+5 -16
View File
@@ -1,12 +1,12 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use nym_coconut::CoconutError;
use nym_credential_storage::error::StorageError;
use nym_credentials::error::Error as CredentialsError;
use nym_credentials_interface::CompactEcashError;
use nym_crypto::asymmetric::encryption::KeyRecoveryError;
use nym_crypto::asymmetric::identity::Ed25519RecoveryError;
use nym_validator_client::coconut::EcashApiError;
use nym_validator_client::coconut::CoconutApiError;
use nym_validator_client::error::ValidatorClientError;
use thiserror::Error;
@@ -16,7 +16,7 @@ pub enum BandwidthControllerError {
Nyxd(#[from] nym_validator_client::nyxd::error::NyxdError),
#[error("coconut api query failure: {0}")]
CoconutApiError(#[from] EcashApiError),
CoconutApiError(#[from] CoconutApiError),
#[error("There was a credential storage error - {0}")]
CredentialStorageError(Box<dyn std::error::Error + Send + Sync>),
@@ -28,8 +28,8 @@ pub enum BandwidthControllerError {
#[error(transparent)]
StorageError(#[from] StorageError),
#[error("Ecash error - {0}")]
EcashError(#[from] CompactEcashError),
#[error("Coconut error - {0}")]
CoconutError(#[from] CoconutError),
#[error("Validator client error - {0}")]
ValidatorError(#[from] ValidatorClientError),
@@ -51,15 +51,4 @@ pub enum BandwidthControllerError {
#[error("can't handle recovering storage with revision {stored}. {expected} was expected")]
UnsupportedCredentialStorageRevision { stored: u8, expected: u8 },
#[error("did not receive a valid response for aggregated data ({typ}) from ANY nym-api")]
ExhaustedApiQueries { typ: String },
}
impl BandwidthControllerError {
pub fn credential_storage_error(
source: impl std::error::Error + Send + Sync + 'static,
) -> Self {
BandwidthControllerError::CredentialStorageError(Box::new(source))
}
}
-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,
}
+90 -152
View File
@@ -1,32 +1,21 @@
// Copyright 2021-2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
#![warn(clippy::expect_used)]
#![warn(clippy::unwrap_used)]
#![warn(clippy::todo)]
#![warn(clippy::dbg_macro)]
use crate::error::BandwidthControllerError;
use crate::utils::{
get_aggregate_verification_key, get_coin_index_signatures, get_expiration_date_signatures,
ApiClientsWrapper,
};
use log::error;
use nym_credential_storage::models::RetrievedTicketbook;
use crate::utils::stored_credential_to_issued_bandwidth;
use log::{debug, error, warn};
use nym_credential_storage::storage::Storage;
use nym_credentials::ecash::bandwidth::CredentialSpendingData;
use nym_credentials_interface::{
AnnotatedCoinIndexSignature, AnnotatedExpirationDateSignature, NymPayInfo, VerificationKeyAuth,
};
use nym_ecash_time::Date;
use nym_credentials::coconut::bandwidth::issued::BandwidthCredentialIssuedDataVariant;
use nym_credentials::coconut::bandwidth::CredentialSpendingData;
use nym_credentials::coconut::utils::obtain_aggregate_verification_key;
use nym_credentials::IssuedBandwidthCredential;
use nym_credentials_interface::VerificationKey;
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)]
@@ -43,20 +32,13 @@ pub struct PreparedCredential {
/// could use correct verification key for validation.
pub epoch_id: EpochId,
/// Auxiliary metadata associated with the withdrawn credential
pub metadata: PreparedCredentialMetadata,
/// The database id of the stored credential.
pub credential_id: i64,
}
#[derive(Copy, Clone)]
pub struct PreparedCredentialMetadata {
/// The database id of the stored credential.
pub ticketbook_id: i64,
/// The number of tickets withdrawn in this credential
pub tickets_withdrawn: u32,
/// The amount of tickets used INCLUDING those tickets that JUST got withdrawn
pub used_tickets: u32,
pub struct RetrievedCredential {
pub credential: IssuedBandwidthCredential,
pub credential_id: i64,
}
impl<C, St: Storage> BandwidthController<C, St> {
@@ -65,155 +47,111 @@ impl<C, St: Storage> BandwidthController<C, St> {
}
/// Tries to retrieve one of the stored, unused credentials that hasn't yet expired.
pub async fn get_next_usable_ticketbook(
/// It marks any retrieved intermediate credentials as expired.
pub async fn get_next_usable_credential(
&self,
tickets: u32,
) -> Result<RetrievedTicketbook, BandwidthControllerError>
gateway_id: &str,
) -> Result<RetrievedCredential, BandwidthControllerError>
where
<St as Storage>::StorageError: Send + Sync + 'static,
{
let Some(ticketbook) = self
.storage
.get_next_unspent_usable_ticketbook(tickets)
.await
.map_err(BandwidthControllerError::credential_storage_error)?
else {
return Err(BandwidthControllerError::NoCredentialsAvailable);
};
loop {
let Some(maybe_next) = self
.storage
.get_next_unspent_credential(gateway_id)
.await
.map_err(|err| BandwidthControllerError::CredentialStorageError(Box::new(err)))?
else {
return Err(BandwidthControllerError::NoCredentialsAvailable);
};
let id = maybe_next.id;
Ok(ticketbook)
// try to deserialize it
let valid_credential = match stored_credential_to_issued_bandwidth(maybe_next) {
// check if it has already expired
Ok(credential) => match credential.variant_data() {
BandwidthCredentialIssuedDataVariant::Voucher(_) => {
debug!("credential {id} is a bandwidth voucher");
credential
}
BandwidthCredentialIssuedDataVariant::FreePass(freepass_info) => {
debug!("credential {id} is a free pass");
if freepass_info.expired() {
warn!("the free pass (id: {id}) has already expired! The expiration was set to {}", freepass_info.expiry_date());
self.storage.mark_expired(id).await.map_err(|err| {
BandwidthControllerError::CredentialStorageError(Box::new(err))
})?;
continue;
}
credential
}
},
Err(err) => {
error!("failed to deserialize credential with id {id}: {err}. it may need to be manually removed from the storage");
return Err(err);
}
};
return Ok(RetrievedCredential {
credential: valid_credential,
credential_id: id,
});
}
}
pub async fn attempt_revert_ticket_usage(
&self,
info: PreparedCredentialMetadata,
) -> Result<bool, BandwidthControllerError>
where
<St as Storage>::StorageError: Send + Sync + 'static,
{
self.storage
.attempt_revert_ticketbook_withdrawal(
info.ticketbook_id,
info.used_tickets,
info.tickets_withdrawn,
)
.await
.map_err(BandwidthControllerError::credential_storage_error)
pub fn storage(&self) -> &St {
&self.storage
}
async fn get_aggregate_verification_key(
&self,
epoch_id: EpochId,
apis: &mut ApiClientsWrapper,
) -> Result<VerificationKeyAuth, BandwidthControllerError>
) -> Result<VerificationKey, BandwidthControllerError>
where
C: DkgQueryClient + Sync + Send,
<St as Storage>::StorageError: Send + Sync + 'static,
{
let ecash_apis = apis.get_or_init(epoch_id, &self.client).await?;
get_aggregate_verification_key(&self.storage, epoch_id, ecash_apis).await
let coconut_api_clients = all_coconut_api_clients(&self.client, epoch_id).await?;
Ok(obtain_aggregate_verification_key(&coconut_api_clients)?)
}
async fn get_coin_index_signatures(
pub async fn prepare_bandwidth_credential(
&self,
epoch_id: EpochId,
apis: &mut ApiClientsWrapper,
) -> Result<Vec<AnnotatedCoinIndexSignature>, BandwidthControllerError>
where
C: DkgQueryClient + Sync + Send,
<St as Storage>::StorageError: Send + Sync + 'static,
{
let ecash_apis = apis.get_or_init(epoch_id, &self.client).await?;
get_coin_index_signatures(&self.storage, epoch_id, ecash_apis).await
}
async fn get_expiration_date_signatures(
&self,
epoch_id: EpochId,
expiration_date: Date,
apis: &mut ApiClientsWrapper,
) -> Result<Vec<AnnotatedExpirationDateSignature>, BandwidthControllerError>
where
C: DkgQueryClient + Sync + Send,
<St as Storage>::StorageError: Send + Sync + 'static,
{
let ecash_apis = apis.get_or_init(epoch_id, &self.client).await?;
get_expiration_date_signatures(&self.storage, epoch_id, expiration_date, ecash_apis).await
}
async fn prepare_ecash_ticket_inner(
&self,
provider_pk: [u8; 32],
tickets_to_spend: u32,
mut retrieved_ticketbook: RetrievedTicketbook,
) -> Result<CredentialSpendingData, BandwidthControllerError>
where
C: DkgQueryClient + Sync + Send,
<St as Storage>::StorageError: Send + Sync + 'static,
{
let epoch_id = retrieved_ticketbook.ticketbook.epoch_id();
let expiration_date = retrieved_ticketbook.ticketbook.expiration_date();
let mut api_clients = Default::default();
let verification_key = self
.get_aggregate_verification_key(epoch_id, &mut api_clients)
.await?;
let expiration_signatures = self
.get_expiration_date_signatures(epoch_id, expiration_date, &mut api_clients)
.await?;
let coin_indices_signatures = self
.get_coin_index_signatures(epoch_id, &mut api_clients)
.await?;
let pay_info = NymPayInfo::generate(provider_pk);
let spend_request = retrieved_ticketbook.ticketbook.prepare_for_spending(
&verification_key,
pay_info.into(),
&coin_indices_signatures,
&expiration_signatures,
tickets_to_spend as u64,
)?;
Ok(spend_request)
}
pub async fn prepare_ecash_ticket(
&self,
provider_pk: [u8; 32],
tickets_to_spend: u32,
gateway_id: &str,
) -> Result<PreparedCredential, BandwidthControllerError>
where
C: DkgQueryClient + Sync + Send,
<St as Storage>::StorageError: Send + Sync + 'static,
{
let retrieved_ticketbook = self.get_next_usable_ticketbook(tickets_to_spend).await?;
let retrieved_credential = self.get_next_usable_credential(gateway_id).await?;
let ticketbook_id = retrieved_ticketbook.ticketbook_id;
let epoch_id = retrieved_ticketbook.ticketbook.epoch_id();
let epoch_id = retrieved_credential.credential.epoch_id();
let credential_id = retrieved_credential.credential_id;
let used_tickets =
retrieved_ticketbook.ticketbook.spent_tickets() as u32 + tickets_to_spend;
let metadata = PreparedCredentialMetadata {
ticketbook_id,
tickets_withdrawn: tickets_to_spend,
used_tickets,
};
let verification_key = self.get_aggregate_verification_key(epoch_id).await?;
match self
.prepare_ecash_ticket_inner(provider_pk, tickets_to_spend, retrieved_ticketbook)
let spend_request = retrieved_credential
.credential
.prepare_for_spending(&verification_key)?;
Ok(PreparedCredential {
data: spend_request,
epoch_id,
credential_id,
})
}
pub async fn consume_credential(
&self,
id: i64,
gateway_id: &str,
) -> Result<(), BandwidthControllerError>
where
<St as Storage>::StorageError: Send + Sync + 'static,
{
self.storage
.consume_coconut_credential(id, gateway_id)
.await
{
Ok(data) => Ok(PreparedCredential {
data,
epoch_id,
metadata,
}),
Err(err) => {
error!("failed to prepare credential spending request. attempting to revert withdrawal...");
self.attempt_revert_ticket_usage(metadata).await?;
Err(err)
}
}
.map_err(|err| BandwidthControllerError::CredentialStorageError(Box::new(err)))
}
}
+15 -174
View File
@@ -2,180 +2,21 @@
// SPDX-License-Identifier: Apache-2.0
use crate::error::BandwidthControllerError;
use log::warn;
use nym_credential_storage::storage::Storage;
use nym_credentials_interface::{
AnnotatedCoinIndexSignature, AnnotatedExpirationDateSignature, VerificationKeyAuth,
};
use nym_ecash_time::Date;
use nym_validator_client::coconut::all_ecash_api_clients;
use nym_validator_client::nym_api::EpochId;
use nym_validator_client::nyxd::contract_traits::DkgQueryClient;
use nym_validator_client::EcashApiClient;
use rand::prelude::SliceRandom;
use rand::thread_rng;
use std::fmt::Display;
use std::future::Future;
use nym_credential_storage::models::StoredIssuedCredential;
use nym_credentials::coconut::bandwidth::issued::CURRENT_SERIALIZATION_REVISION;
use nym_credentials::coconut::bandwidth::IssuedBandwidthCredential;
// it really doesn't need the RwLock because it's never moved across tasks,
// but we need all the Send/Sync action
#[derive(Default)]
pub(crate) struct ApiClientsWrapper(Option<Vec<EcashApiClient>>);
impl ApiClientsWrapper {
pub(crate) async fn get_or_init<C>(
&mut self,
epoch_id: EpochId,
dkg_client: &C,
) -> Result<Vec<EcashApiClient>, BandwidthControllerError>
where
C: DkgQueryClient + Sync + Send,
{
if let Some(cached) = &self.0 {
return Ok(cached.clone());
}
let clients = all_ecash_api_clients(dkg_client, epoch_id).await?;
// technically we don't have to be cloning all the clients here, but it's way simpler than
// dealing with locking and whatnot given the performance penalty is negligible
self.0 = Some(clients.clone());
Ok(clients)
pub fn stored_credential_to_issued_bandwidth(
cred: StoredIssuedCredential,
) -> Result<IssuedBandwidthCredential, BandwidthControllerError> {
if cred.serialization_revision != CURRENT_SERIALIZATION_REVISION {
return Err(
BandwidthControllerError::UnsupportedCredentialStorageRevision {
stored: cred.serialization_revision,
expected: CURRENT_SERIALIZATION_REVISION,
},
);
}
}
pub(crate) async fn query_random_apis_until_success<F, T, U, E>(
mut apis: Vec<EcashApiClient>,
f: F,
typ: impl Into<String>,
) -> Result<T, BandwidthControllerError>
where
F: Fn(EcashApiClient) -> U,
U: Future<Output = Result<T, E>>,
E: Display,
{
// try apis in pseudorandom way to remove any bias towards the first registered dealer
apis.shuffle(&mut thread_rng());
for api in apis {
let disp = api.to_string();
match f(api).await {
Ok(res) => return Ok(res),
Err(err) => {
warn!("failed to obtain valid response from API {disp}: {err}")
}
}
}
Err(BandwidthControllerError::ExhaustedApiQueries { typ: typ.into() })
}
pub(crate) async fn get_aggregate_verification_key<St>(
storage: &St,
epoch_id: EpochId,
ecash_apis: Vec<EcashApiClient>,
) -> Result<VerificationKeyAuth, BandwidthControllerError>
where
St: Storage,
<St as Storage>::StorageError: Send + Sync + 'static,
{
if let Some(stored) = storage
.get_master_verification_key(epoch_id)
.await
.map_err(BandwidthControllerError::credential_storage_error)?
{
return Ok(stored);
};
let master_vk = query_random_apis_until_success(
ecash_apis,
|api| async move { api.api_client.master_verification_key(Some(epoch_id)).await },
format!("aggregated verification key for epoch {epoch_id}"),
)
.await?
.key;
// store the retrieved key
storage
.insert_master_verification_key(epoch_id, &master_vk)
.await
.map_err(BandwidthControllerError::credential_storage_error)?;
Ok(master_vk)
}
pub(crate) async fn get_coin_index_signatures<St>(
storage: &St,
epoch_id: EpochId,
ecash_apis: Vec<EcashApiClient>,
) -> Result<Vec<AnnotatedCoinIndexSignature>, BandwidthControllerError>
where
St: Storage,
<St as Storage>::StorageError: Send + Sync + 'static,
{
if let Some(stored) = storage
.get_coin_index_signatures(epoch_id)
.await
.map_err(BandwidthControllerError::credential_storage_error)?
{
return Ok(stored);
};
let index_sigs = query_random_apis_until_success(
ecash_apis,
|api| async move {
api.api_client
.global_coin_indices_signatures(Some(epoch_id))
.await
},
format!("aggregated coin index signatures for epoch {epoch_id}"),
)
.await?
.signatures;
// store the retrieved key
storage
.insert_coin_index_signatures(epoch_id, &index_sigs)
.await
.map_err(BandwidthControllerError::credential_storage_error)?;
Ok(index_sigs)
}
pub(crate) async fn get_expiration_date_signatures<St>(
storage: &St,
epoch_id: EpochId,
expiration_date: Date,
ecash_apis: Vec<EcashApiClient>,
) -> Result<Vec<AnnotatedExpirationDateSignature>, BandwidthControllerError>
where
St: Storage,
<St as Storage>::StorageError: Send + Sync + 'static,
{
if let Some(stored) = storage
.get_expiration_date_signatures(expiration_date)
.await
.map_err(BandwidthControllerError::credential_storage_error)?
{
return Ok(stored);
};
let expiration_sigs = query_random_apis_until_success(
ecash_apis,
|api| async move {
api.api_client
.global_expiration_date_signatures(Some(expiration_date))
.await
},
format!("aggregated coin index signatures for date {expiration_date}"),
)
.await?
.signatures;
// store the retrieved key
storage
.insert_expiration_date_signatures(epoch_id, expiration_date, &expiration_sigs)
.await
.map_err(BandwidthControllerError::credential_storage_error)?;
Ok(expiration_sigs)
Ok(IssuedBandwidthCredential::unpack_v1(&cred.credential_data)?)
}
+4 -5
View File
@@ -9,9 +9,9 @@ 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 }
clap = { workspace = true, features = ["derive"] }
clap_complete = { workspace = true }
clap_complete_fig = { workspace = true }
log = { workspace = true }
pretty_env_logger = { workspace = true }
semver = "0.11"
@@ -34,7 +34,7 @@ vergen = { workspace = true, features = ["build", "git", "gitcl", "rustc", "carg
[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 +44,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;
+5 -12
View File
@@ -10,19 +10,17 @@ license.workspace = true
[dependencies]
async-trait = { workspace = true }
base64 = { workspace = true }
base64 = "0.21.2"
bs58 = { workspace = true }
cfg-if = { workspace = true }
clap = { workspace = true, optional = true }
comfy-table = { version = "7.1.1", optional = true }
futures = { workspace = true }
humantime-serde = { workspace = true }
log = { workspace = true }
rand = { workspace = true }
rand_chacha = { workspace = true }
serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true }
sha2 = { workspace = true }
sha2 = "0.10.6"
si-scale = { workspace = true }
tap = { workspace = true }
thiserror = { workspace = true }
@@ -39,7 +37,7 @@ 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" }
nym-gateway-requests = { path = "../gateway-requests" }
nym-gateway-requests = { path = "../../gateway/gateway-requests" }
nym-metrics = { path = "../nym-metrics" }
nym-nonexhaustive-delayqueue = { path = "../nonexhaustive-delayqueue" }
nym-sphinx = { path = "../nymsphinx" }
@@ -47,15 +45,11 @@ nym-pemstore = { path = "../pemstore" }
nym-topology = { path = "../topology", features = ["serializable"] }
nym-validator-client = { path = "../client-libs/validator-client", default-features = false }
nym-task = { path = "../task" }
nym-credentials-interface = { path = "../credentials-interface" }
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-config-types = { path = "./config-types", features = ["disk-persistence"] }
nym-client-core-surb-storage = { path = "./surb-storage" }
nym-client-core-gateways-storage = { path = "./gateways-storage" }
nym-ecash-time = { path = "../ecash-time" }
### For serving prometheus metrics
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.hyper]
@@ -118,8 +112,7 @@ tempfile = { workspace = true }
[features]
default = []
cli = ["clap", "comfy-table"]
fs-credentials-storage = ["nym-credential-storage/persistent-storage"]
cli = ["clap"]
fs-surb-storage = ["nym-client-core-surb-storage/fs-surb-storage"]
fs-gateways-storage = ["nym-client-core-gateways-storage/fs-gateways-storage"]
wasm = ["nym-gateway-client/wasm"]
@@ -117,6 +117,11 @@ impl Config {
self
}
pub fn with_fronting_domains(mut self, fronting_domains: Vec<Url>) -> Self {
self.client.fronting_domains = Some(fronting_domains);
self
}
pub fn set_custom_nym_apis(&mut self, nym_api_urls: Vec<Url>) {
self.client.nym_api_urls = nym_api_urls;
}
@@ -289,6 +294,10 @@ impl Config {
pub fn get_nym_api_endpoints(&self) -> Vec<Url> {
self.client.nym_api_urls.clone()
}
pub fn get_fronting_domains(&self) -> Option<Vec<Url>> {
self.client.fronting_domains.clone()
}
}
#[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)]
@@ -314,6 +323,9 @@ pub struct Client {
/// 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>,
/// Domain to use for domain fronting censorship circumvention
pub fronting_domains: Option<Vec<Url>>,
}
impl Client {
@@ -340,6 +352,7 @@ impl Client {
disabled_credentials_mode: true,
nyxd_urls,
nym_api_urls,
fronting_domains: None,
}
}
@@ -349,6 +362,7 @@ impl Client {
disabled_credentials_mode: bool,
nyxd_urls: Vec<Url>,
nym_api_urls: Vec<Url>,
fronting_domains: Option<Vec<Url>>,
) -> Self {
Client {
version: version.into(),
@@ -356,6 +370,7 @@ impl Client {
disabled_credentials_mode,
nyxd_urls,
nym_api_urls,
fronting_domains,
}
}
}
@@ -95,6 +95,7 @@ impl From<ConfigV5> for Config {
id: value.client.id,
disabled_credentials_mode: value.client.disabled_credentials_mode,
nyxd_urls: value.client.nyxd_urls,
fronting_domains: None, //SW need proper migrations if it gets applied
nym_api_urls: value.client.nym_api_urls,
},
debug: DebugConfig {
@@ -18,7 +18,7 @@ url.workspace = true
zeroize = { workspace = true, features = ["zeroize_derive"] }
nym-crypto = { path = "../../crypto", features = ["asymmetric"] }
nym-gateway-requests = { path = "../../gateway-requests" }
nym-gateway-requests = { path = "../../../gateway/gateway-requests" }
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.sqlx]
workspace = true
@@ -27,12 +27,7 @@ optional = true
[build-dependencies]
tokio = { workspace = true, features = ["rt-multi-thread", "macros"] }
sqlx = { workspace = true, features = [
"runtime-tokio-rustls",
"sqlite",
"macros",
"migrate",
] }
sqlx = { workspace = true, features = ["runtime-tokio-rustls", "sqlite", "macros", "migrate"] }
[features]
fs-gateways-storage = ["sqlx"]
fs-gateways-storage = ["sqlx"]
@@ -1,17 +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
);
INSERT INTO remote_gateway_details_temp SELECT gateway_id_bs58, derived_aes128_ctr_blake3_hmac_keys_bs58, gateway_owner_address, gateway_listener FROM remote_gateway_details;
DROP TABLE remote_gateway_details;
ALTER TABLE remote_gateway_details_temp RENAME TO remote_gateway_details;
@@ -155,13 +155,14 @@ impl StorageManager {
) -> Result<(), sqlx::Error> {
sqlx::query!(
r#"
INSERT INTO remote_gateway_details(gateway_id_bs58, derived_aes128_ctr_blake3_hmac_keys_bs58, gateway_owner_address, gateway_listener)
VALUES (?, ?, ?, ?)
INSERT INTO remote_gateway_details(gateway_id_bs58, derived_aes128_ctr_blake3_hmac_keys_bs58, gateway_owner_address, gateway_listener, wg_tun_address)
VALUES (?, ?, ?, ?, ?)
"#,
remote.gateway_id_bs58,
remote.derived_aes128_ctr_blake3_hmac_keys_bs58,
remote.gateway_owner_address,
remote.gateway_listener,
remote.wg_tun_address,
)
.execute(&self.connection_pool)
.await?;
@@ -67,12 +67,14 @@ impl GatewayDetails {
derived_aes128_ctr_blake3_hmac_keys: Arc<SharedKeys>,
gateway_owner_address: Option<AccountId>,
gateway_listener: Url,
wg_tun_address: Option<Url>,
) -> Self {
GatewayDetails::Remote(RemoteGatewayDetails {
gateway_id,
derived_aes128_ctr_blake3_hmac_keys,
gateway_owner_address,
gateway_listener,
wg_tun_address,
})
}
@@ -170,6 +172,7 @@ pub struct RawRemoteGatewayDetails {
pub derived_aes128_ctr_blake3_hmac_keys_bs58: String,
pub gateway_owner_address: Option<String>,
pub gateway_listener: String,
pub wg_tun_address: Option<String>,
}
impl TryFrom<RawRemoteGatewayDetails> for RemoteGatewayDetails {
@@ -214,11 +217,24 @@ impl TryFrom<RawRemoteGatewayDetails> for RemoteGatewayDetails {
}
})?;
let wg_tun_address = value
.wg_tun_address
.as_ref()
.map(|addr| {
Url::parse(addr).map_err(|source| BadGateway::MalformedListener {
gateway_id: value.gateway_id_bs58.clone(),
raw_listener: addr.clone(),
source,
})
})
.transpose()?;
Ok(RemoteGatewayDetails {
gateway_id,
derived_aes128_ctr_blake3_hmac_keys,
gateway_owner_address,
gateway_listener,
wg_tun_address,
})
}
}
@@ -232,6 +248,7 @@ impl<'a> From<&'a RemoteGatewayDetails> for RawRemoteGatewayDetails {
.to_base58_string(),
gateway_owner_address: value.gateway_owner_address.as_ref().map(|o| o.to_string()),
gateway_listener: value.gateway_listener.to_string(),
wg_tun_address: value.wg_tun_address.as_ref().map(|addr| addr.to_string()),
}
}
}
@@ -247,6 +264,8 @@ pub struct RemoteGatewayDetails {
pub gateway_owner_address: Option<AccountId>,
pub gateway_listener: Url,
pub wg_tun_address: Option<Url>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
@@ -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, None).await?
};
// since we're registering with a brand new gateway,
@@ -133,6 +128,7 @@ where
let gateway_setup = GatewaySetup::New {
specification: selection_spec,
available_gateways,
wg_tun_address: None,
};
let init_details =
@@ -161,5 +157,6 @@ where
active: common_args.set_active,
typ: gateway_registration.details.typ().to_string(),
endpoint: Some(gateway_details.gateway_listener.clone()),
wg_tun_address: gateway_details.wg_tun_address.clone(),
})
}
@@ -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;
@@ -71,6 +70,13 @@ pub struct CommonClientInitArgs {
)]
pub nym_apis: Option<Vec<url::Url>>,
///Comma separated list of urls to use for domain fronting
#[cfg_attr(
feature = "cli",
clap(long, value_delimiter = ',', requires = "nym_apis", hide = true)
)]
pub fronting_domains: Option<Vec<url::Url>>,
/// Path to .json file containing custom network specification.
#[cfg_attr(feature = "cli", clap(long, group = "network", hide = true))]
pub custom_mixnet: Option<PathBuf>,
@@ -97,7 +103,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,
@@ -146,6 +151,16 @@ where
.collect::<Vec<&str>>()
.join(",")
);
if let Some(fronting_domains) = &core.client.fronting_domains {
log::info!(
"fronted by : {}",
fronting_domains
.iter()
.map(|url| url.host_str().unwrap_or_default())
.collect::<Vec<&str>>()
.join(",")
);
}
let key_store = OnDiskKeys::new(paths.keys.clone());
let details_store = setup_fs_gateways_storage(&paths.gateway_registrations).await?;
@@ -165,13 +180,18 @@ 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,
core.client.fronting_domains.as_ref(),
)
.await?
};
let gateway_setup = GatewaySetup::New {
specification: selection_spec,
available_gateways,
wg_tun_address: None,
};
let init_details =
@@ -57,6 +57,7 @@ where
active: active_gateway == Some(remote_details.gateway_id),
typ: GatewayType::Remote.to_string(),
endpoint: Some(remote_details.gateway_listener),
wg_tun_address: remote_details.wg_tun_address,
}),
GatewayDetails::Custom(_) => info.push(GatewayInfo {
registration: gateway.registration_timestamp,
@@ -64,6 +65,7 @@ where
active: active_gateway == Some(gateway.details.gateway_id()),
typ: gateway.details.typ().to_string(),
endpoint: None,
wg_tun_address: None,
}),
};
}
@@ -35,6 +35,13 @@ pub struct CommonClientRunArgs {
)]
pub nym_apis: Option<Vec<url::Url>>,
///Comma separated list of urls to use for domain fronting
#[cfg_attr(
feature = "cli",
clap(long, value_delimiter = ',', requires = "nym_apis", hide = true)
)]
pub fronting_domains: Option<Vec<url::Url>>,
/// Path to .json file containing custom network specification.
#[cfg_attr(feature = "cli", clap(long, group = "network", hide = true))]
pub custom_mixnet: Option<PathBuf>,
@@ -1,140 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::cli_helpers::{CliClient, CliClientConfig};
use crate::error::ClientCoreError;
use nym_credential_storage::models::BasicTicketbookInformation;
use nym_credential_storage::storage::Storage;
use nym_credentials_interface::TicketType;
use nym_ecash_time::ecash_today;
use serde::{Deserialize, Serialize};
use time::Date;
#[derive(Serialize, Deserialize)]
pub struct AvailableTicketbook {
pub id: i64,
pub typ: TicketType,
pub expiration: Date,
pub issued_tickets: u32,
pub claimed_tickets: u32,
pub ticket_size: u64,
}
impl AvailableTicketbook {
#[cfg(feature = "cli")]
fn table_row(&self) -> comfy_table::Row {
let ecash_today = ecash_today().date();
let issued = self.issued_tickets;
let si_issued = si_scale::helpers::bibytes2((issued as u64 * self.ticket_size) as f64);
let claimed = self.claimed_tickets;
let si_claimed = si_scale::helpers::bibytes2((claimed as u64 * self.ticket_size) as f64);
let remaining = issued - claimed;
let si_remaining =
si_scale::helpers::bibytes2((remaining as u64 * self.ticket_size) as f64);
let si_size = si_scale::helpers::bibytes2(self.ticket_size as f64);
let expiration = if self.expiration <= ecash_today {
comfy_table::Cell::new(format!("EXPIRED ON {}", self.expiration))
.fg(comfy_table::Color::Red)
.add_attribute(comfy_table::Attribute::Bold)
} else {
comfy_table::Cell::new(self.expiration.to_string())
};
vec![
comfy_table::Cell::new(self.id.to_string()),
comfy_table::Cell::new(self.typ),
expiration,
comfy_table::Cell::new(format!("{issued} ({si_issued})")),
comfy_table::Cell::new(format!("{claimed} ({si_claimed})")),
comfy_table::Cell::new(format!("{remaining} ({si_remaining})")),
comfy_table::Cell::new(si_size),
]
.into()
}
}
impl TryFrom<BasicTicketbookInformation> for AvailableTicketbook {
type Error = ClientCoreError;
fn try_from(value: BasicTicketbookInformation) -> Result<Self, Self::Error> {
let typ = value
.ticketbook_type
.parse()
.map_err(|_| ClientCoreError::UnknownTicketType)?;
Ok(AvailableTicketbook {
id: value.id,
typ,
expiration: value.expiration_date,
issued_tickets: value.total_tickets,
claimed_tickets: value.used_tickets,
ticket_size: typ.to_repr().bandwidth_value(),
})
}
}
#[derive(Serialize, Deserialize)]
#[serde(transparent)]
pub struct AvailableTicketbooks(Vec<AvailableTicketbook>);
#[cfg(feature = "cli")]
impl std::fmt::Display for AvailableTicketbooks {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut table = comfy_table::Table::new();
table.set_header(vec![
"id",
"type",
"expiration",
"issued tickets (bandwidth)",
"claimed tickets (bandwidth)",
"remaining tickets (bandwidth)",
"ticket size",
]);
for ticketbook in &self.0 {
table.add_row(ticketbook.table_row());
}
writeln!(f, "{table}")?;
Ok(())
}
}
#[cfg_attr(feature = "cli", derive(clap::Args))]
#[derive(Debug, Clone)]
pub struct CommonShowTicketbooksArgs {
/// Id of client that is going to display the ticketbook information
#[cfg_attr(feature = "cli", clap(long))]
pub id: String,
}
pub async fn show_ticketbooks<C, A>(args: A) -> Result<AvailableTicketbooks, C::Error>
where
A: AsRef<CommonShowTicketbooksArgs>,
C: CliClient,
{
let common_args = args.as_ref();
let id = &common_args.id;
let config = C::try_load_current_config(id).await?;
let paths = config.common_paths();
let credentials_store =
nym_credential_storage::initialise_persistent_storage(&paths.credentials_database).await;
let ticketbooks = credentials_store
.get_ticketbooks_info()
.await
.map_err(|err| ClientCoreError::CredentialStoreError {
source: Box::new(err),
})?;
Ok(AvailableTicketbooks(
ticketbooks
.into_iter()
.map(TryInto::<AvailableTicketbook>::try_into)
.collect::<Result<_, _>>()?,
))
}
@@ -6,7 +6,6 @@ pub mod client_import_credential;
pub mod client_init;
pub mod client_list_gateways;
pub mod client_run;
pub mod client_show_ticketbooks;
pub mod client_switch_gateway;
pub mod traits;
mod types;
@@ -15,6 +15,7 @@ pub struct GatewayInfo {
pub typ: String,
pub endpoint: Option<Url>,
pub wg_tun_address: Option<Url>,
}
impl Display for GatewayInfo {
@@ -30,6 +31,10 @@ impl Display for GatewayInfo {
if let Some(endpoint) = &self.endpoint {
write!(f, " endpoint: {endpoint}")?;
}
if let Some(wg_tun_address) = &self.wg_tun_address {
write!(f, " wg tun address: {wg_tun_address}")?;
}
Ok(())
}
}
@@ -3,6 +3,7 @@
use super::packet_statistics_control::PacketStatisticsReporter;
use super::received_buffer::ReceivedBufferMessage;
use super::topology_control::fronted_api_provider::FrontedApiTopologyProvider;
use super::topology_control::geo_aware_provider::GeoAwareTopologyProvider;
use crate::client::base_client::storage::helpers::store_client_keys;
use crate::client::base_client::storage::MixnetClientStorage;
@@ -35,15 +36,15 @@ use crate::init::{
};
use crate::{config, spawn_future};
use futures::channel::mpsc;
use log::*;
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_gateway_client::client::config::GatewayClientConfig;
use nym_gateway_client::{
AcknowledgementReceiver, GatewayClient, GatewayConfig, MixnetMessageReceiver, PacketRouter,
};
use nym_network_defaults::{DEFAULT_CLIENT_LISTENING_PORT, WG_TUN_DEVICE_ADDRESS};
use nym_sphinx::acknowledgements::AckKey;
use nym_sphinx::addressing::clients::Recipient;
use nym_sphinx::addressing::nodes::NodeIdentity;
@@ -53,7 +54,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;
@@ -180,10 +181,10 @@ pub struct BaseClientBuilder<'a, C, S: MixnetClientStorage> {
dkg_query_client: Option<C>,
wait_for_gateway: bool,
wireguard_connection: bool,
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,
}
@@ -203,10 +204,10 @@ where
client_store,
dkg_query_client,
wait_for_gateway: false,
wireguard_connection: false,
custom_topology_provider: None,
custom_gateway_transceiver: None,
shutdown: None,
user_agent: None,
setup_method: GatewaySetup::MustLoad { gateway_id: None },
}
}
@@ -223,6 +224,12 @@ where
self
}
#[must_use]
pub fn with_wireguard_connection(mut self, wireguard_connection: bool) -> Self {
self.wireguard_connection = wireguard_connection;
self
}
#[must_use]
pub fn with_topology_provider(
mut self,
@@ -244,12 +251,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,
@@ -352,6 +353,7 @@ where
async fn start_gateway_client(
config: &Config,
wireguard_connection: bool,
initialisation_result: InitialisationResult,
bandwidth_controller: Option<BandwidthController<C, S::CredentialStore>>,
packet_router: PacketRouter,
@@ -367,33 +369,44 @@ where
return Err(ClientCoreError::UnexpectedPersistedCustomGatewayDetails);
};
let mut gateway_client =
if let Some(existing_client) = initialisation_result.authenticated_ephemeral_client {
existing_client.upgrade(packet_router, bandwidth_controller, shutdown)
let mut gateway_client = if let Some(existing_client) =
initialisation_result.authenticated_ephemeral_client
{
existing_client.upgrade(packet_router, bandwidth_controller, shutdown)
} else {
let gateway_listener = if wireguard_connection {
if let Some(tun_address) = details.wg_tun_address {
tun_address.to_string()
} else {
let default =
format!("ws://{WG_TUN_DEVICE_ADDRESS}:{DEFAULT_CLIENT_LISTENING_PORT}");
warn!("gateway {} does not have tun device address set. defaulting to '{default}'", details.gateway_id);
default
}
} else {
let cfg = GatewayConfig::new(
details.gateway_id,
details
.gateway_owner_address
.as_ref()
.map(|o| o.to_string()),
details.gateway_listener.to_string(),
);
GatewayClient::new(
GatewayClientConfig::new_default()
.with_disabled_credentials_mode(config.client.disabled_credentials_mode)
.with_response_timeout(
config.debug.gateway_connection.gateway_response_timeout,
),
cfg,
managed_keys.identity_keypair(),
Some(details.derived_aes128_ctr_blake3_hmac_keys),
packet_router,
bandwidth_controller,
shutdown,
)
details.gateway_listener.to_string()
};
let cfg = GatewayConfig::new(
details.gateway_id,
details
.gateway_owner_address
.as_ref()
.map(|o| o.to_string()),
gateway_listener,
);
GatewayClient::new(
cfg,
managed_keys.identity_keypair(),
Some(details.derived_aes128_ctr_blake3_hmac_keys),
packet_router,
bandwidth_controller,
shutdown,
)
.with_disabled_credentials_mode(config.client.disabled_credentials_mode)
.with_response_timeout(config.debug.gateway_connection.gateway_response_timeout)
};
gateway_client
.authenticate_and_start()
.await
@@ -411,6 +424,7 @@ where
async fn setup_gateway_transceiver(
custom_gateway_transceiver: Option<Box<dyn GatewayTransceiver + Send>>,
config: &Config,
wireguard_connection: bool,
initialisation_result: InitialisationResult,
bandwidth_controller: Option<BandwidthController<C, S::CredentialStore>>,
packet_router: PacketRouter,
@@ -430,7 +444,7 @@ where
Err(ClientCoreError::CustomGatewaySelectionExpected)
} else {
// and make sure to invalidate the task client so we wouldn't cause premature shutdown
shutdown.disarm();
shutdown.mark_as_success();
custom_gateway_transceiver.set_packet_router(packet_router)?;
Ok(custom_gateway_transceiver)
};
@@ -439,6 +453,7 @@ where
// otherwise, setup normal gateway client, etc
let gateway_client = Self::start_gateway_client(
config,
wireguard_connection,
initialisation_result,
bandwidth_controller,
packet_router,
@@ -453,19 +468,29 @@ where
custom_provider: Option<Box<dyn TopologyProvider + Send + Sync>>,
config_topology: config::Topology,
nym_api_urls: Vec<Url>,
user_agent: Option<UserAgent>,
fronting_domains: Option<Vec<Url>>,
) -> 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 {
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::NymApi => match fronting_domains {
Some(domains) => Box::new(FrontedApiTopologyProvider::new(
nym_api_provider::Config {
min_mixnode_performance: config_topology.minimum_mixnode_performance,
min_gateway_performance: config_topology.minimum_gateway_performance,
},
nym_api_urls,
domains,
env!("CARGO_PKG_VERSION").to_string(),
)),
None => 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(),
)),
},
config::TopologyStructure::GeoAware(group_by) => {
Box::new(GeoAwareTopologyProvider::new(
nym_api_urls,
@@ -536,7 +561,7 @@ where
if topology_config.disable_refreshing {
// if we're not spawning the refresher, don't cause shutdown immediately
info!("The topology refesher is not going to be started");
shutdown.disarm();
shutdown.mark_as_success();
} else {
// don't spawn the refresher if we don't want to be refreshing the topology.
// only use the initial values obtained
@@ -677,7 +702,7 @@ where
self.custom_topology_provider.take(),
self.config.debug.topology,
self.config.get_nym_api_endpoints(),
self.user_agent.clone(),
self.config.get_fronting_domains(),
);
// needs to be started as the first thing to block if required waiting for the gateway
@@ -703,6 +728,7 @@ where
let gateway_transceiver = Self::setup_gateway_transceiver(
self.custom_gateway_transceiver,
self.config,
self.wireguard_connection,
init_res,
bandwidth_controller,
gateway_packet_router,
@@ -102,6 +102,7 @@ pub mod v1_1_33 {
message: format!("the stored gateway listener address was malformed: {err}"),
}
})?,
wg_tun_address: None,
}))
}
@@ -23,7 +23,7 @@ use crate::{
config::{self, disk_persistence::CommonClientPaths},
error::ClientCoreError,
};
#[cfg(all(not(target_arch = "wasm32"), feature = "fs-credentials-storage"))]
#[cfg(all(not(target_arch = "wasm32"), feature = "fs-surb-storage"))]
use nym_credential_storage::persistent_storage::PersistentStorage as PersistentCredentialStorage;
pub use nym_client_core_gateways_storage as gateways_storage;
@@ -3,12 +3,10 @@
use async_trait::async_trait;
use log::{debug, error};
use nym_credential_storage::storage::Storage as CredentialStorage;
use nym_crypto::asymmetric::identity;
use nym_gateway_client::GatewayClient;
pub use nym_gateway_client::{GatewayPacketRouter, PacketRouter};
use nym_sphinx::forwarding::packet::MixPacket;
use nym_validator_client::nyxd::contract_traits::DkgQueryClient;
use std::fmt::Debug;
use std::os::raw::c_int as RawFd;
use thiserror::Error;
@@ -113,9 +111,8 @@ impl<C, St> RemoteGateway<C, St> {
impl<C, St> GatewayTransceiver for RemoteGateway<C, St>
where
C: DkgQueryClient + Send + Sync,
St: CredentialStorage,
<St as CredentialStorage>::StorageError: Send + Sync + 'static,
C: Send,
St: Send,
{
fn gateway_identity(&self) -> identity::PublicKey {
self.gateway_client.gateway_identity()
@@ -129,9 +126,8 @@ where
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
impl<C, St> GatewaySender for RemoteGateway<C, St>
where
C: DkgQueryClient + Send + Sync,
St: CredentialStorage,
<St as CredentialStorage>::StorageError: Send + Sync + 'static,
C: Send,
St: Send,
{
async fn send_mix_packet(&mut self, packet: MixPacket) -> Result<(), ErasedGatewayError> {
self.gateway_client
@@ -458,7 +458,7 @@ impl PacketStatisticsControl {
fn report_rates(&self) {
if let Some((_, rates)) = self.rates.back() {
log::debug!("{}", rates.summary());
log::info!("{}", rates.summary());
log::debug!("{}", rates.detailed_summary());
}
}
@@ -486,7 +486,7 @@ impl PacketStatisticsControl {
// Check what the number of retransmissions was during the recording window
if let Some((_, start_stats)) = self.history.front() {
let delta = self.stats.clone() - start_stats.clone();
log::debug!(
log::info!(
"mix packet retransmissions/real mix packets: {}/{}",
delta.retransmissions_queued,
delta.real_packets_queued,
@@ -453,7 +453,6 @@ where
let mut pending_acks = Vec::with_capacity(fragments.len());
let mut real_messages = Vec::with_capacity(fragments.len());
debug!("Splitting message into {} fragments", fragments.len());
for fragment in fragments {
// we need to clone it because we need to keep it in memory in case we had to retransmit
// it. And then we'd need to recreate entire ACK again.
@@ -474,6 +474,13 @@ where
Poll::Ready(Some((real_messages, conn_id))) => {
log::trace!("handling real_messages: size: {}", real_messages.len());
// This is the last step in the pipeline where we know the type of the message, so
// lets count the number of retransmissions here.
if conn_id == TransmissionLane::Retransmission {
self.stats_tx
.report(PacketStatisticsEvent::RetransmissionQueued);
}
// First store what we got for the given connection id
self.transmission_buffer.store(&conn_id, real_messages);
let real_next = self.pop_next_message().expect("we just added one");
@@ -0,0 +1,147 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use async_trait::async_trait;
use log::{debug, error, warn};
use nym_topology::provider_trait::TopologyProvider;
use nym_topology::{NymTopology, NymTopologyError};
use rand::prelude::SliceRandom;
use rand::thread_rng;
use url::Url;
use super::nym_api_provider::Config;
pub(crate) struct FrontedApiTopologyProvider {
config: Config,
validator_client: nym_validator_client::client::NymApiClient,
nym_api_urls: Vec<Url>,
fronting_domains: Vec<Url>,
shuffling: Vec<usize>,
client_version: String,
currently_used_api: usize,
}
impl FrontedApiTopologyProvider {
pub(crate) fn new(
config: Config,
nym_api_urls: Vec<Url>,
fronting_domains: Vec<Url>,
client_version: String,
) -> Self {
//SW for the PoC, we assume same lenght between fronting domains and api_urls
let mut shuffling = (0..nym_api_urls.len()).collect::<Vec<_>>();
shuffling.shuffle(&mut thread_rng());
FrontedApiTopologyProvider {
config,
validator_client: nym_validator_client::client::NymApiClient::new_fronted(
nym_api_urls[shuffling[0]].clone(),
fronting_domains[shuffling[0]].clone(),
),
nym_api_urls,
fronting_domains,
shuffling,
client_version,
currently_used_api: 0,
}
}
fn use_next_nym_api(&mut self) {
if self.nym_api_urls.len() == 1 {
warn!("There's only a single nym API available - it won't be possible to use a different one");
return;
}
self.currently_used_api = (self.currently_used_api + 1) % self.nym_api_urls.len();
self.validator_client.change_nym_api_with_fronting(
self.nym_api_urls[self.shuffling[self.currently_used_api]].clone(),
self.fronting_domains[self.shuffling[self.currently_used_api]].clone(),
);
}
/// Verifies whether nodes a reasonably distributed among all mix layers.
///
/// In ideal world we would have 33% nodes on layer 1, 33% on layer 2 and 33% on layer 3.
/// However, this is a rather unrealistic expectation, instead we check whether there exists
/// a layer with more than 66% of nodes or with fewer than 15% and if so, we trigger a failure.
///
/// # Arguments
///
/// * `topology`: active topology constructed from validator api data
fn check_layer_distribution(
&self,
active_topology: &NymTopology,
) -> Result<(), NymTopologyError> {
let lower_threshold = 0.15;
let upper_threshold = 0.66;
active_topology.ensure_even_layer_distribution(lower_threshold, upper_threshold)
}
async fn get_current_compatible_topology(&mut self) -> Option<NymTopology> {
let mixnodes = match self
.validator_client
.get_basic_mixnodes(Some(self.client_version.clone()))
.await
{
Err(err) => {
error!("failed to get network mixnodes - {err}");
return None;
}
Ok(mixes) => mixes,
};
let gateways = match self
.validator_client
.get_basic_gateways(Some(self.client_version.clone()))
.await
{
Err(err) => {
error!("failed to get network gateways - {err}");
return None;
}
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
}),
);
if let Err(err) = self.check_layer_distribution(&topology) {
warn!("The current filtered active topology has extremely skewed layer distribution. It cannot be used: {err}");
self.use_next_nym_api();
None
} else {
Some(topology)
}
}
}
// hehe, wasm
#[cfg(not(target_arch = "wasm32"))]
#[async_trait]
impl TopologyProvider for FrontedApiTopologyProvider {
async fn get_new_topology(&mut self) -> Option<NymTopology> {
self.get_current_compatible_topology().await
}
}
#[cfg(target_arch = "wasm32")]
#[async_trait(?Send)]
impl TopologyProvider for FrontedApiTopologyProvider {
async fn get_new_topology(&mut self) -> Option<NymTopology> {
self.get_current_compatible_topology().await
}
}
@@ -17,6 +17,7 @@ use tokio::time::sleep;
use wasmtimer::tokio::sleep;
mod accessor;
pub(crate) mod fronted_api_provider;
pub mod geo_aware_provider;
pub(crate) mod nym_api_provider;
@@ -5,7 +5,6 @@ use async_trait::async_trait;
use log::{debug, error, warn};
use nym_topology::provider_trait::TopologyProvider;
use nym_topology::{NymTopology, NymTopologyError};
use nym_validator_client::UserAgent;
use rand::prelude::SliceRandom;
use rand::thread_rng;
use url::Url;
@@ -40,26 +39,14 @@ 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(config: Config, 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,
-8
View File
@@ -63,14 +63,6 @@ pub enum ClientCoreError {
source: Box<dyn Error + Send + Sync>,
},
#[error("experienced a failure with our credentials storage: {source}")]
CredentialStoreError {
source: Box<dyn Error + Send + Sync>,
},
#[error("the provided ticket type is invalid")]
UnknownTicketType,
#[error("the gateway id is invalid - {0}")]
UnableToCreatePublicKeyFromGatewayId(Ed25519RecoveryError),
+40 -51
View File
@@ -9,7 +9,7 @@ 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::IteratorRandom;
use rand::{seq::SliceRandom, Rng};
use std::{sync::Arc, time::Duration};
use tungstenite::Message;
@@ -46,34 +46,13 @@ const MEASUREMENTS: usize = 3;
const CONN_TIMEOUT: Duration = Duration::from_millis(1500);
const PING_TIMEOUT: Duration = Duration::from_millis(1000);
// The abstraction that some of these helpers use
pub trait ConnectableGateway {
fn identity(&self) -> &identity::PublicKey;
fn clients_address(&self) -> String;
fn is_wss(&self) -> bool;
}
impl ConnectableGateway for gateway::Node {
fn identity(&self) -> &identity::PublicKey {
self.identity()
}
fn clients_address(&self) -> String {
self.clients_address()
}
fn is_wss(&self) -> bool {
self.clients_wss_port.is_some()
}
}
struct GatewayWithLatency<'a, G: ConnectableGateway> {
gateway: &'a G,
struct GatewayWithLatency<'a> {
gateway: &'a gateway::Node,
latency: Duration,
}
impl<'a, G: ConnectableGateway> GatewayWithLatency<'a, G> {
fn new(gateway: &'a G, latency: Duration) -> Self {
impl<'a> GatewayWithLatency<'a> {
fn new(gateway: &'a gateway::Node, latency: Duration) -> Self {
GatewayWithLatency { gateway, latency }
}
}
@@ -81,18 +60,29 @@ impl<'a, G: ConnectableGateway> GatewayWithLatency<'a, G> {
pub async fn current_gateways<R: Rng>(
rng: &mut R,
nym_apis: &[Url],
user_agent: Option<UserAgent>,
fronting_domains: Option<&Vec<Url>>,
) -> 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 = match fronting_domains {
Some(domains) => {
let (api_url, fronting_url) = nym_apis
.iter()
.zip(domains)
.choose(rng)
.ok_or(ClientCoreError::ListOfNymApisIsEmpty)?;
log::debug!("Fetching list of gateways from: {nym_api}");
nym_validator_client::client::NymApiClient::new_fronted(
api_url.clone(),
fronting_url.clone(),
)
}
None => {
let nym_api = nym_apis
.choose(rng)
.ok_or(ClientCoreError::ListOfNymApisIsEmpty)?;
nym_validator_client::client::NymApiClient::new(nym_api.clone())
}
};
log::debug!("Fetching list of gateways from: {}", client.api_url());
let gateways = client.get_cached_described_gateways().await?;
log::debug!("Found {} gateways", gateways.len());
@@ -151,14 +141,11 @@ async fn connect(endpoint: &str) -> Result<WsConn, ClientCoreError> {
JSWebsocket::new(endpoint).map_err(|_| ClientCoreError::GatewayJsConnectionFailure)
}
async fn measure_latency<G>(gateway: &G) -> Result<GatewayWithLatency<G>, ClientCoreError>
where
G: ConnectableGateway,
{
async fn measure_latency(gateway: &gateway::Node) -> Result<GatewayWithLatency, ClientCoreError> {
let addr = gateway.clients_address();
trace!(
"establishing connection to {} ({addr})...",
gateway.identity(),
gateway.identity_key,
);
let mut stream = connect(&addr).await?;
@@ -201,7 +188,7 @@ where
let count = results.len() as u64;
if count == 0 {
return Err(ClientCoreError::NoGatewayMeasurements {
identity: gateway.identity().to_base58_string(),
identity: gateway.identity_key.to_base58_string(),
});
}
@@ -211,11 +198,11 @@ where
Ok(GatewayWithLatency::new(gateway, avg))
}
pub async fn choose_gateway_by_latency<'a, R: Rng, G: ConnectableGateway + Clone>(
pub async fn choose_gateway_by_latency<R: Rng>(
rng: &mut R,
gateways: &[G],
gateways: &[gateway::Node],
must_use_tls: bool,
) -> Result<G, ClientCoreError> {
) -> Result<gateway::Node, ClientCoreError> {
let gateways = filter_by_tls(gateways, must_use_tls)?;
info!(
@@ -247,19 +234,21 @@ pub async fn choose_gateway_by_latency<'a, R: Rng, G: ConnectableGateway + Clone
info!(
"chose gateway {} with average latency of {:?}",
chosen.gateway.identity(),
chosen.latency
chosen.gateway.identity_key, chosen.latency
);
Ok(chosen.gateway.clone())
}
fn filter_by_tls<G: ConnectableGateway>(
gateways: &[G],
fn filter_by_tls(
gateways: &[gateway::Node],
must_use_tls: bool,
) -> Result<Vec<&G>, ClientCoreError> {
) -> Result<Vec<&gateway::Node>, ClientCoreError> {
if must_use_tls {
let filtered = gateways.iter().filter(|g| g.is_wss()).collect::<Vec<_>>();
let filtered = gateways
.iter()
.filter(|g| g.clients_wss_port.is_some())
.collect::<Vec<_>>();
if filtered.is_empty() {
return Err(ClientCoreError::NoWssGateways);
+20 -6
View File
@@ -23,6 +23,7 @@ use nym_topology::gateway;
use rand::rngs::OsRng;
use rand::{CryptoRng, RngCore};
use serde::Serialize;
use std::net::IpAddr;
pub mod helpers;
pub mod types;
@@ -51,6 +52,7 @@ async fn setup_new_gateway<K, D>(
details_store: &D,
selection_specification: GatewaySelectionSpecification,
available_gateways: Vec<gateway::Node>,
wg_tun_ip_address: Option<IpAddr>,
) -> Result<InitialisationResult, ClientCoreError>
where
K: KeyStore,
@@ -68,19 +70,19 @@ where
let selected_gateway = match selection_specification {
GatewaySelectionSpecification::UniformRemote { must_use_tls } => {
let gateway = uniformly_random_gateway(&mut rng, &available_gateways, must_use_tls)?;
SelectedGateway::from_topology_node(gateway, must_use_tls)?
SelectedGateway::from_topology_node(gateway, wg_tun_ip_address, must_use_tls)?
}
GatewaySelectionSpecification::RemoteByLatency { must_use_tls } => {
let gateway =
choose_gateway_by_latency(&mut rng, &available_gateways, must_use_tls).await?;
SelectedGateway::from_topology_node(gateway, must_use_tls)?
SelectedGateway::from_topology_node(gateway, wg_tun_ip_address, must_use_tls)?
}
GatewaySelectionSpecification::Specified {
must_use_tls,
identity,
} => {
let gateway = get_specified_gateway(&identity, &available_gateways, must_use_tls)?;
SelectedGateway::from_topology_node(gateway, must_use_tls)?
SelectedGateway::from_topology_node(gateway, wg_tun_ip_address, must_use_tls)?
}
GatewaySelectionSpecification::Custom {
gateway_identity,
@@ -102,19 +104,23 @@ where
gateway_id,
gateway_owner_address,
gateway_listener,
wg_tun_address,
} => {
// if we're using a 'normal' gateway setup, do register
let our_identity = client_keys.identity_keypair();
// if wg address is set, use that one
let url = wg_tun_address.clone().unwrap_or(gateway_listener.clone());
let registration =
helpers::register_with_gateway(gateway_id, gateway_listener.clone(), our_identity)
.await?;
helpers::register_with_gateway(gateway_id, url, our_identity).await?;
(
GatewayDetails::new_remote(
gateway_id,
registration.shared_keys,
gateway_owner_address,
gateway_listener,
wg_tun_address,
),
Some(registration.authenticated_ephemeral_client),
)
@@ -201,9 +207,17 @@ where
GatewaySetup::New {
specification,
available_gateways,
wg_tun_address,
} => {
log::debug!("GatewaySetup::New with spec: {specification:?}");
setup_new_gateway(key_store, details_store, specification, available_gateways).await
setup_new_gateway(
key_store,
details_store,
specification,
available_gateways,
wg_tun_address,
)
.await
}
GatewaySetup::ReuseConnection {
authenticated_ephemeral_client,
+41
View File
@@ -6,6 +6,7 @@ use crate::client::key_manager::ClientKeys;
use crate::config::Config;
use crate::error::ClientCoreError;
use crate::init::{setup_gateway, use_loaded_gateway_details};
use log::info;
use nym_client_core_gateways_storage::{
GatewayRegistration, GatewaysDetailsStore, RemoteGatewayDetails,
};
@@ -18,6 +19,7 @@ use nym_validator_client::client::IdentityKey;
use nym_validator_client::nyxd::AccountId;
use serde::Serialize;
use std::fmt::Display;
use std::net::IpAddr;
use std::str::FromStr;
use std::sync::Arc;
use time::OffsetDateTime;
@@ -30,6 +32,8 @@ pub enum SelectedGateway {
gateway_owner_address: Option<AccountId>,
gateway_listener: Url,
wg_tun_address: Option<Url>,
},
Custom {
gateway_id: identity::PublicKey,
@@ -37,9 +41,36 @@ pub enum SelectedGateway {
},
}
fn wg_tun_address(
tun_ip: Option<IpAddr>,
gateway: &gateway::Node,
) -> Result<Option<Url>, ClientCoreError> {
let Some(tun_ip) = tun_ip else {
return Ok(None);
};
// log this so we'd remember about it if we ever decided to actually use that port
if gateway.clients_wss_port.is_some() {
info!(
"gateway {} exposes wss but for wireguard we're going to use ws",
gateway.identity_key
);
}
let raw_url = format!("ws://{tun_ip}:{}", gateway.clients_ws_port);
Ok(Some(raw_url.as_str().parse().map_err(|source| {
ClientCoreError::MalformedListener {
gateway_id: gateway.identity_key.to_base58_string(),
raw_listener: raw_url,
source,
}
})?))
}
impl SelectedGateway {
pub fn from_topology_node(
node: gateway::Node,
wg_tun_ip_address: Option<IpAddr>,
must_use_tls: bool,
) -> Result<Self, ClientCoreError> {
let gateway_listener = if must_use_tls {
@@ -51,6 +82,8 @@ impl SelectedGateway {
node.clients_address()
};
let wg_tun_address = wg_tun_address(wg_tun_ip_address, &node)?;
let gateway_owner_address = node
.owner
.as_ref()
@@ -76,6 +109,7 @@ impl SelectedGateway {
gateway_id: node.identity_key,
gateway_owner_address,
gateway_listener,
wg_tun_address,
})
}
@@ -216,6 +250,12 @@ pub enum GatewaySetup {
// TODO: seems to be a bit inefficient to pass them by value
available_gateways: Vec<gateway::Node>,
/// Implicitly specify whether the chosen gateway must use wireguard mode by setting the tun address.
///
/// Currently this is imperfect solution as I'd imagine this address could vary from gateway to gateway
/// so perhaps it should be part of gateway::Node struct
wg_tun_address: Option<IpAddr>,
},
ReuseConnection {
@@ -250,6 +290,7 @@ impl GatewaySetup {
additional_data: None,
},
available_gateways: vec![],
wg_tun_address: None,
}
}
-2
View File
@@ -2,9 +2,7 @@ use std::future::Future;
#[cfg(all(
not(target_arch = "wasm32"),
feature = "cli",
feature = "fs-surb-storage",
feature = "fs-credentials-storage",
feature = "fs-gateways-storage"
))]
pub mod cli_helpers;
+1 -1
View File
@@ -24,7 +24,7 @@ nym-bandwidth-controller = { path = "../../bandwidth-controller" }
nym-credentials = { path = "../../credentials" }
nym-credential-storage = { path = "../../credential-storage" }
nym-crypto = { path = "../../crypto" }
nym-gateway-requests = { path = "../../gateway-requests" }
nym-gateway-requests = { path = "../../../gateway/gateway-requests" }
nym-network-defaults = { path = "../../network-defaults" }
nym-sphinx = { path = "../../nymsphinx" }
nym-pemstore = { path = "../../pemstore" }
@@ -1,89 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use si_scale::helpers::bibytes2;
use std::sync::atomic::{AtomicI64, Ordering};
use std::sync::Arc;
use std::time::Duration;
use time::OffsetDateTime;
#[derive(Clone, Default)]
pub struct ClientBandwidth {
inner: Arc<ClientBandwidthInner>,
}
#[derive(Default)]
struct ClientBandwidthInner {
/// the actual bandwidth amount (in bytes) available
available: AtomicI64,
/// defines the timestamp when the bandwidth information has been logged to the logs stream
last_logged_ts: AtomicI64,
/// defines the timestamp when the bandwidth value was last updated
last_updated_ts: AtomicI64,
}
impl ClientBandwidth {
pub(crate) fn new_empty() -> Self {
ClientBandwidth {
inner: Arc::new(ClientBandwidthInner {
available: AtomicI64::new(0),
last_logged_ts: AtomicI64::new(0),
last_updated_ts: AtomicI64::new(0),
}),
}
}
pub(crate) fn remaining(&self) -> i64 {
self.inner.available.load(Ordering::Acquire)
}
pub(crate) fn maybe_log_bandwidth(&self, now: Option<OffsetDateTime>) {
let last = self.last_logged();
let now = now.unwrap_or_else(OffsetDateTime::now_utc);
if last + Duration::from_secs(10) < now {
self.log_bandwidth(Some(now))
}
}
pub(crate) fn log_bandwidth(&self, now: Option<OffsetDateTime>) {
let now = now.unwrap_or_else(OffsetDateTime::now_utc);
let remaining = self.remaining();
let remaining_bi2 = bibytes2(remaining as f64);
if remaining < 0 {
log::warn!("OUT OF BANDWIDTH. remaining: {remaining_bi2}");
} else {
log::info!("remaining bandwidth: {remaining_bi2}");
}
self.inner
.last_logged_ts
.store(now.unix_timestamp(), Ordering::Relaxed)
}
pub(crate) fn update_and_maybe_log(&self, remaining: i64) {
let now = OffsetDateTime::now_utc();
self.inner.available.store(remaining, Ordering::Release);
self.inner
.last_updated_ts
.store(now.unix_timestamp(), Ordering::Relaxed);
self.maybe_log_bandwidth(Some(now))
}
pub(crate) fn update_and_log(&self, remaining: i64) {
let now = OffsetDateTime::now_utc();
self.inner.available.store(remaining, Ordering::Release);
self.inner
.last_updated_ts
.store(now.unix_timestamp(), Ordering::Relaxed);
self.log_bandwidth(Some(now))
}
fn last_logged(&self) -> OffsetDateTime {
// SAFETY: this value is always populated with valid timestamps
OffsetDateTime::from_unix_timestamp(self.inner.last_logged_ts.load(Ordering::Relaxed))
.unwrap()
}
}
@@ -1,18 +1,17 @@
// Copyright 2021-2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::bandwidth::ClientBandwidth;
use crate::client::config::GatewayClientConfig;
use crate::error::GatewayClientError;
use crate::packet_router::PacketRouter;
pub use crate::packet_router::{
AcknowledgementReceiver, AcknowledgementSender, MixnetMessageReceiver, MixnetMessageSender,
};
use crate::socket_state::{ws_fd, PartiallyDelegatedHandle, SocketState};
use crate::socket_state::{ws_fd, PartiallyDelegated, SocketState};
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;
@@ -24,11 +23,14 @@ use nym_gateway_requests::{
BinaryRequest, ClientControlRequest, ServerResponse, CREDENTIAL_UPDATE_V2_PROTOCOL_VERSION,
CURRENT_PROTOCOL_VERSION,
};
use nym_network_defaults::{REMAINING_BANDWIDTH_THRESHOLD, TOKENS_TO_BURN};
use nym_sphinx::forwarding::packet::MixPacket;
use nym_task::TaskClient;
use nym_validator_client::nyxd::contract_traits::DkgQueryClient;
use rand::rngs::OsRng;
use std::sync::Arc;
use std::time::Duration;
use tungstenite::protocol::Message;
use url::Url;
@@ -46,7 +48,12 @@ use wasm_utils::websocket::JSWebsocket;
#[cfg(target_arch = "wasm32")]
use wasmtimer::tokio::sleep;
pub mod config;
// 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_RECONNECTION_ATTEMPTS: usize = 10;
const DEFAULT_RECONNECTION_BACKOFF: Duration = Duration::from_secs(5);
pub struct GatewayConfig {
pub gateway_identity: identity::PublicKey,
@@ -72,53 +79,96 @@ 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> {
pub cfg: GatewayClientConfig,
authenticated: bool,
bandwidth: ClientBandwidth,
disabled_credentials_mode: bool,
bandwidth_remaining: i64,
gateway_address: String,
gateway_identity: identity::PublicKey,
local_identity: Arc<identity::KeyPair>,
shared_key: Option<Arc<SharedKeys>>,
connection: SocketState,
packet_router: PacketRouter,
response_timeout_duration: Duration,
bandwidth_controller: Option<BandwidthController<C, St>>,
// reconnection related variables
/// Specifies whether client should try to reconnect to gateway on connection failure.
should_reconnect_on_failure: bool,
/// Specifies maximum number of attempts client will try to reconnect to gateway on failure
/// before giving up.
reconnection_attempts: usize,
/// Delay between each subsequent reconnection attempt.
reconnection_backoff: Duration,
// 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> {
pub fn new(
cfg: GatewayClientConfig,
gateway_config: GatewayConfig,
config: GatewayConfig,
local_identity: Arc<identity::KeyPair>,
// TODO: make it mandatory. if you don't want to pass it, use `new_init`
shared_key: Option<Arc<SharedKeys>>,
packet_router: PacketRouter,
bandwidth_controller: Option<BandwidthController<C, St>>,
task_client: TaskClient,
shutdown: TaskClient,
) -> Self {
GatewayClient {
cfg,
authenticated: false,
bandwidth: ClientBandwidth::new_empty(),
gateway_address: gateway_config.gateway_listener,
gateway_identity: gateway_config.gateway_identity,
disabled_credentials_mode: true,
bandwidth_remaining: 0,
gateway_address: config.gateway_listener,
gateway_identity: config.gateway_identity,
local_identity,
shared_key,
connection: SocketState::NotConnected,
packet_router,
response_timeout_duration: DEFAULT_GATEWAY_RESPONSE_TIMEOUT,
bandwidth_controller,
should_reconnect_on_failure: true,
reconnection_attempts: DEFAULT_RECONNECTION_ATTEMPTS,
reconnection_backoff: DEFAULT_RECONNECTION_BACKOFF,
negotiated_protocol: None,
task_client,
shutdown,
}
}
#[must_use]
pub fn with_disabled_credentials_mode(mut self, disabled_credentials_mode: bool) -> Self {
self.disabled_credentials_mode = disabled_credentials_mode;
self
}
#[must_use]
pub fn with_reconnection_on_failure(mut self, should_reconnect_on_failure: bool) -> Self {
self.should_reconnect_on_failure = should_reconnect_on_failure;
self
}
#[must_use]
pub fn with_response_timeout(mut self, response_timeout_duration: Duration) -> Self {
self.response_timeout_duration = response_timeout_duration;
self
}
#[must_use]
pub fn with_reconnection_attempts(mut self, reconnection_attempts: usize) -> Self {
self.reconnection_attempts = reconnection_attempts;
self
}
#[must_use]
pub fn with_reconnection_backoff(mut self, backoff: Duration) -> Self {
self.reconnection_backoff = backoff;
self
}
pub fn gateway_identity(&self) -> identity::PublicKey {
self.gateway_identity
}
@@ -132,7 +182,7 @@ impl<C, St> GatewayClient<C, St> {
}
pub fn remaining_bandwidth(&self) -> i64 {
self.bandwidth.remaining()
self.bandwidth_remaining
}
#[cfg(not(target_arch = "wasm32"))]
@@ -208,21 +258,18 @@ impl<C, St> GatewayClient<C, St> {
info!("Attempting gateway reconnection...");
self.authenticated = false;
for i in 1..self.cfg.connection.reconnection_attempts {
info!("reconnection attempt {}...", i);
for i in 1..self.reconnection_attempts {
info!("attempt {}...", i);
if self.try_reconnect().await.is_ok() {
info!("managed to reconnect!");
return Ok(());
}
sleep(self.cfg.connection.reconnection_backoff).await;
sleep(self.reconnection_backoff).await;
}
// final attempt (done separately to be able to return a proper error)
info!(
"reconnection attempt {}",
self.cfg.connection.reconnection_attempts
);
info!("attempt {}", self.reconnection_attempts);
match self.try_reconnect().await {
Ok(_) => {
info!("managed to reconnect!");
@@ -231,7 +278,7 @@ impl<C, St> GatewayClient<C, St> {
Err(err) => {
error!(
"failed to reconnect after {} attempts",
self.cfg.connection.reconnection_attempts
self.reconnection_attempts
);
Err(err)
}
@@ -247,12 +294,12 @@ impl<C, St> GatewayClient<C, St> {
_ => return Err(GatewayClientError::ConnectionInInvalidState),
};
let timeout = sleep(self.cfg.connection.response_timeout_duration);
let timeout = sleep(self.response_timeout_duration);
tokio::pin!(timeout);
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);
@@ -416,7 +463,7 @@ impl<C, St> GatewayClient<C, St> {
ws_stream,
self.local_identity.as_ref(),
self.gateway_identity,
self.cfg.bandwidth.require_tickets,
!self.disabled_credentials_mode,
)
.await
.map_err(GatewayClientError::RegistrationFailure),
@@ -478,7 +525,7 @@ impl<C, St> GatewayClient<C, St> {
self_address,
encrypted_address,
iv,
self.cfg.bandwidth.require_tickets,
!self.disabled_credentials_mode,
)
.into();
@@ -490,13 +537,9 @@ impl<C, St> GatewayClient<C, St> {
} => {
self.check_gateway_protocol(protocol_version)?;
self.authenticated = status;
self.bandwidth.update_and_maybe_log(bandwidth_remaining);
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)),
@@ -530,74 +573,56 @@ impl<C, St> GatewayClient<C, St> {
}
}
async fn claim_ecash_bandwidth(
async fn claim_coconut_bandwidth(
&mut self,
credential: CredentialSpendingData,
) -> Result<(), GatewayClientError> {
let mut rng = OsRng;
let iv = IV::new_random(&mut rng);
let msg = ClientControlRequest::new_enc_ecash_credential(
let msg = ClientControlRequest::new_enc_coconut_bandwidth_credential_v2(
credential,
self.shared_key.as_ref().unwrap(),
iv,
)
.into();
let bandwidth_remaining = match self.send_websocket_message(msg).await? {
self.bandwidth_remaining = match self.send_websocket_message(msg).await? {
ServerResponse::Bandwidth { available_total } => Ok(available_total),
ServerResponse::Error { message } => Err(GatewayClientError::GatewayError(message)),
ServerResponse::TypedError { error } => {
Err(GatewayClientError::TypedGatewayError(error))
}
_ => Err(GatewayClientError::UnexpectedResponse),
}?;
// TODO: create tracing span
info!("managed to claim ecash bandwidth");
self.bandwidth.update_and_log(bandwidth_remaining);
Ok(())
}
async fn try_claim_testnet_bandwidth(&mut self) -> Result<(), GatewayClientError> {
let msg = ClientControlRequest::ClaimFreeTestnetBandwidth.into();
let bandwidth_remaining = match self.send_websocket_message(msg).await? {
self.bandwidth_remaining = match self.send_websocket_message(msg).await? {
ServerResponse::Bandwidth { available_total } => Ok(available_total),
ServerResponse::Error { message } => Err(GatewayClientError::GatewayError(message)),
_ => Err(GatewayClientError::UnexpectedResponse),
}?;
info!("managed to claim testnet bandwidth");
self.bandwidth.update_and_log(bandwidth_remaining);
Ok(())
}
fn unchecked_bandwidth_controller(&self) -> &BandwidthController<C, St> {
self.bandwidth_controller.as_ref().unwrap()
}
pub async fn claim_bandwidth(&mut self) -> Result<(), GatewayClientError>
where
C: DkgQueryClient + Send + Sync,
St: CredentialStorage,
<St as CredentialStorage>::StorageError: Send + Sync + 'static,
{
// TODO: make it configurable
const TICKETS_TO_SPEND: u32 = 1;
if !self.authenticated {
return Err(GatewayClientError::NotAuthenticated);
}
if self.shared_key.is_none() {
return Err(GatewayClientError::NoSharedKeyAvailable);
}
if self.bandwidth_controller.is_none() && self.cfg.bandwidth.require_tickets {
if self.bandwidth_controller.is_none() && !self.disabled_credentials_mode {
return Err(GatewayClientError::NoBandwidthControllerAvailable);
}
warn!("Not enough bandwidth. Trying to get more bandwidth, this might take a while");
if !self.cfg.bandwidth.require_tickets {
if self.disabled_credentials_mode {
info!("The client is running in disabled credentials mode - attempting to claim bandwidth without a credential");
return self.try_claim_testnet_bandwidth().await;
}
@@ -613,52 +638,49 @@ impl<C, St> GatewayClient<C, St> {
negotiated_protocol: Some(gateway_protocol),
});
}
let gateway_id = self.gateway_identity().to_base58_string();
let prepared_credential = self
.unchecked_bandwidth_controller()
.prepare_ecash_ticket(self.gateway_identity.to_bytes(), TICKETS_TO_SPEND)
.bandwidth_controller
.as_ref()
.unwrap()
.prepare_bandwidth_credential(&gateway_id)
.await?;
match self.claim_ecash_bandwidth(prepared_credential.data).await {
Ok(_) => Ok(()),
Err(err) => {
error!("failed to claim ecash bandwidth with the gateway...: {err}");
if err.is_ticket_replay() {
warn!("this was due to our ticket being replayed! have you messed with the database file?")
} else {
// TODO: tracing span
info!("attempting to revert ticket withdrawal...");
self.unchecked_bandwidth_controller()
.attempt_revert_ticket_usage(prepared_credential.metadata)
.await?;
}
self.claim_coconut_bandwidth(prepared_credential.data)
.await?;
self.bandwidth_controller
.as_ref()
.unwrap()
.consume_credential(prepared_credential.credential_id, &gateway_id)
.await?;
Err(err)
}
}
Ok(())
}
fn estimate_required_bandwidth(&self, packets: &[MixPacket]) -> i64 {
packets
.iter()
.map(|packet| packet.packet().len())
.sum::<usize>() as i64
}
pub async fn batch_send_mix_packets(
&mut self,
packets: Vec<MixPacket>,
) -> Result<(), GatewayClientError>
where
C: DkgQueryClient + Send + Sync,
St: CredentialStorage,
<St as CredentialStorage>::StorageError: Send + Sync + 'static,
{
) -> Result<(), GatewayClientError> {
debug!("Sending {} mix packets", packets.len());
if !self.authenticated {
return Err(GatewayClientError::NotAuthenticated);
}
let bandwidth_remaining = self.bandwidth.remaining();
if bandwidth_remaining < self.cfg.bandwidth.remaining_bandwidth_threshold {
self.cfg
.bandwidth
.ensure_above_cutoff(bandwidth_remaining)?;
self.claim_bandwidth().await?;
if self.estimate_required_bandwidth(&packets) > self.bandwidth_remaining {
return Err(GatewayClientError::NotEnoughBandwidth(
self.estimate_required_bandwidth(&packets),
self.bandwidth_remaining,
));
}
if !self.connection.is_established() {
return Err(GatewayClientError::ConnectionNotEstablished);
}
@@ -678,7 +700,7 @@ impl<C, St> GatewayClient<C, St> {
.batch_send_websocket_messages_without_response(messages)
.await
{
if err.is_closed_connection() && self.cfg.connection.should_reconnect_on_failure {
if err.is_closed_connection() && self.should_reconnect_on_failure {
self.attempt_reconnection().await
} else {
Err(err)
@@ -693,7 +715,7 @@ impl<C, St> GatewayClient<C, St> {
msg: Message,
) -> Result<(), GatewayClientError> {
if let Err(err) = self.send_websocket_message_without_response(msg).await {
if err.is_closed_connection() && self.cfg.connection.should_reconnect_on_failure {
if err.is_closed_connection() && self.should_reconnect_on_failure {
debug!("Going to attempt a reconnection");
self.attempt_reconnection().await
} else {
@@ -717,23 +739,19 @@ impl<C, St> GatewayClient<C, St> {
}
// TODO: possibly make responses optional
pub async fn send_mix_packet(&mut self, mix_packet: MixPacket) -> Result<(), GatewayClientError>
where
C: DkgQueryClient + Send + Sync,
St: CredentialStorage,
<St as CredentialStorage>::StorageError: Send + Sync + 'static,
{
pub async fn send_mix_packet(
&mut self,
mix_packet: MixPacket,
) -> Result<(), GatewayClientError> {
if !self.authenticated {
return Err(GatewayClientError::NotAuthenticated);
}
let bandwidth_remaining = self.bandwidth.remaining();
if bandwidth_remaining < self.cfg.bandwidth.remaining_bandwidth_threshold {
self.cfg
.bandwidth
.ensure_above_cutoff(bandwidth_remaining)?;
self.claim_bandwidth().await?;
if (mix_packet.packet().len() as i64) > self.bandwidth_remaining {
return Err(GatewayClientError::NotEnoughBandwidth(
mix_packet.packet().len() as i64,
self.bandwidth_remaining,
));
}
if !self.connection.is_established() {
return Err(GatewayClientError::ConnectionNotEstablished);
}
@@ -779,7 +797,7 @@ impl<C, St> GatewayClient<C, St> {
let partially_delegated =
match std::mem::replace(&mut self.connection, SocketState::Invalid) {
SocketState::Available(conn) => {
PartiallyDelegatedHandle::split_and_listen_for_mixnet_messages(
PartiallyDelegated::split_and_listen_for_mixnet_messages(
*conn,
self.packet_router.clone(),
Arc::clone(
@@ -787,8 +805,7 @@ impl<C, St> GatewayClient<C, St> {
.as_ref()
.expect("no shared key present even though we're authenticated!"),
),
self.bandwidth.clone(),
self.task_client.clone(),
self.shutdown.clone(),
)
}
_ => unreachable!(),
@@ -828,12 +845,10 @@ impl<C, St> GatewayClient<C, St> {
self.establish_connection().await?;
}
let shared_key = self.perform_initial_authentication().await?;
let bandwidth_remaining = self.bandwidth.remaining();
if bandwidth_remaining < self.cfg.bandwidth.remaining_bandwidth_threshold {
self.cfg
.bandwidth
.ensure_above_cutoff(bandwidth_remaining)?;
info!("Claiming more bandwidth with existing credentials. Stop the process now if you don't want that to happen.");
if self.bandwidth_remaining < REMAINING_BANDWIDTH_THRESHOLD {
info!("Claiming more bandwidth for your tokens. This will use {} token(s) from your wallet. \
Stop the process now if you don't want that to happen.", TOKENS_TO_BURN);
self.claim_bandwidth().await?;
}
@@ -864,22 +879,26 @@ 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 {
cfg: GatewayClientConfig::default().with_disabled_credentials_mode(true),
authenticated: false,
bandwidth: ClientBandwidth::new_empty(),
disabled_credentials_mode: true,
bandwidth_remaining: 0,
gateway_address: gateway_listener.to_string(),
gateway_identity,
local_identity,
shared_key: None,
connection: SocketState::NotConnected,
packet_router,
response_timeout_duration: DEFAULT_GATEWAY_RESPONSE_TIMEOUT,
bandwidth_controller: None,
should_reconnect_on_failure: false,
reconnection_attempts: DEFAULT_RECONNECTION_ATTEMPTS,
reconnection_backoff: DEFAULT_RECONNECTION_BACKOFF,
negotiated_protocol: None,
task_client,
shutdown,
}
}
@@ -887,7 +906,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)
@@ -896,18 +915,22 @@ impl GatewayClient<InitOnly, EphemeralCredentialStorage> {
assert!(self.shared_key.is_some());
GatewayClient {
cfg: self.cfg,
authenticated: self.authenticated,
bandwidth: self.bandwidth,
disabled_credentials_mode: self.disabled_credentials_mode,
bandwidth_remaining: self.bandwidth_remaining,
gateway_address: self.gateway_address,
gateway_identity: self.gateway_identity,
local_identity: self.local_identity,
shared_key: self.shared_key,
connection: self.connection,
packet_router,
response_timeout_duration: self.response_timeout_duration,
bandwidth_controller,
should_reconnect_on_failure: self.should_reconnect_on_failure,
reconnection_attempts: self.reconnection_attempts,
reconnection_backoff: self.reconnection_backoff,
negotiated_protocol: self.negotiated_protocol,
task_client,
shutdown,
}
}
}

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