Compare commits
332 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6598d677da | |||
| e736a01ecc | |||
| a708fa2d4a | |||
| a512217382 | |||
| 086611c7ac | |||
| 05d6652177 | |||
| 9c514fe3b7 | |||
| 924160b3e7 | |||
| 23d14b60de | |||
| a4b47ef3a5 | |||
| 47303bcf48 | |||
| 60917ec9e7 | |||
| f616b3c15a | |||
| be2b44c46b | |||
| f6db1a87c6 | |||
| e8e86c273e | |||
| b67ad8c23e | |||
| f655fe81d2 | |||
| 86fa7024a2 | |||
| cbea1d554a | |||
| c08e7d2b11 | |||
| c3eb433960 | |||
| 4c5147390a | |||
| f70e8a3b9e | |||
| 5f7499604d | |||
| 8c021e9537 | |||
| f2d56882fe | |||
| 891fdeb4b5 | |||
| 12e8d3468b | |||
| 01221a8e8c | |||
| 58c74199d1 | |||
| eb98c1bf33 | |||
| d6393c1496 | |||
| 48dfc24c33 | |||
| 61eaffe91b | |||
| 63d0ab49e1 | |||
| 0f59fd4eee | |||
| 55694f0341 | |||
| c3aec2b01f | |||
| c023c8fb9f | |||
| 1162de3673 | |||
| 74252269bc | |||
| fe88321a50 | |||
| babc84779c | |||
| 7e40207d46 | |||
| 85758be9ca | |||
| dd70192508 | |||
| f884331284 | |||
| 45e6011961 | |||
| 04a2f59034 | |||
| 43b0b3eb37 | |||
| 27afe645c6 | |||
| 052dbeaef8 | |||
| fb0b9da14f | |||
| 230e4393c5 | |||
| b7baff1a79 | |||
| 18891e5f20 | |||
| f3fcef60c3 | |||
| ed7a84a1ce | |||
| 3c4bd13c2a | |||
| e76bb0db12 | |||
| 48e18684a2 | |||
| e76c8e06be | |||
| 858b6c6094 | |||
| 7b4dc78f41 | |||
| bb7a8e84e4 | |||
| 17bdb583b5 | |||
| 3300942529 | |||
| 4be5af0c40 | |||
| fa42cf8939 | |||
| d0b380cd99 | |||
| 51d1803ddd | |||
| 3d8520dfc7 | |||
| bf8d54b201 | |||
| 58c9a58a38 | |||
| abc6d61d84 | |||
| d094bb60c6 | |||
| bdf45cafb5 | |||
| a7910c1049 | |||
| 6b93309482 | |||
| 9a209c4f3d | |||
| 4d212f73fc | |||
| d7a7b643ef | |||
| c486a87824 | |||
| a0fea6edb4 | |||
| afc1b90b57 | |||
| 33b85a3ca1 | |||
| a3183ab313 | |||
| 3635cbdc8d | |||
| ff0ad976c6 | |||
| 74cd73a58f | |||
| dd89026065 | |||
| 07c80e5150 | |||
| c17f0ac3f8 | |||
| 7ae56b08b3 | |||
| ae7206e0c2 | |||
| 73fc2d6bb2 | |||
| a5289cd431 | |||
| ec0e1b67a0 | |||
| eafbed6c9f | |||
| 37d9f91922 | |||
| 5f21f8334b | |||
| 9378100957 | |||
| 4635db73f1 | |||
| 9a43d1079a | |||
| 279de8a09b | |||
| 3238722ade | |||
| b6c15deae6 | |||
| 8c250adcfd | |||
| 72306f1215 | |||
| dd695129dd | |||
| f1d97e5578 | |||
| 00aff01deb | |||
| c521ee6702 | |||
| 17686ddd9a | |||
| 40e72ce37a | |||
| 5498bee893 | |||
| 92a1fb514f | |||
| 519d999785 | |||
| d859ad0a51 | |||
| f2d354f6ec | |||
| 72c86ebe7c | |||
| 1ac262ec90 | |||
| a6ad6c7d49 | |||
| 7c1fca8ce4 | |||
| cbc977c491 | |||
| f40c05a34c | |||
| 776443131e | |||
| b5eab7f07f | |||
| eeeb4b3246 | |||
| e3e4dc6db9 | |||
| f3ac17eb9d | |||
| 461b7bcfb7 | |||
| 6296d09adf | |||
| 2ae81f6da0 | |||
| bbf0d06583 | |||
| 6393d6093f | |||
| 1d5e8b62ac | |||
| c0ea599913 | |||
| 581cdd5bdf | |||
| e2e49e7136 | |||
| 16d09a35ba | |||
| e6c5eddbe5 | |||
| dff82f946f | |||
| d473e8743e | |||
| ec61728654 | |||
| 61471e9058 | |||
| ed4fd84503 | |||
| cb4b0403b5 | |||
| da8e513627 | |||
| 3f6de8b10c | |||
| 1e01a8e633 | |||
| aaf3dca5b9 | |||
| f939cae3d9 | |||
| 1db61f800c | |||
| 5096c1e60e | |||
| 7e36595d8f | |||
| 515aedac60 | |||
| dca2b2c763 | |||
| c92f09543e | |||
| b45eb16783 | |||
| f8523dc7d1 | |||
| 996ce6a233 | |||
| 1dcb0a0456 | |||
| 55b99e4ce1 | |||
| bd94dd3055 | |||
| 0d19bb4ddc | |||
| dcd70155cd | |||
| a469aeff05 | |||
| 107199bd9c | |||
| 53524447c4 | |||
| bc832c97d8 | |||
| 4989d47ea2 | |||
| 3cb69780a6 | |||
| 68b61bfa84 | |||
| 06fca9bd1f | |||
| 4c10cebf1b | |||
| aea962b546 | |||
| ab2a1c3fe5 | |||
| 8d0c040015 | |||
| 42efff83da | |||
| 86fe955592 | |||
| c3ce0d0b5c | |||
| 0e2cfa5be0 | |||
| 17a5872c6d | |||
| 969155bf91 | |||
| f4fafbfea5 | |||
| 5e97b1f79a | |||
| b52bf951a6 | |||
| 98805a11e4 | |||
| 0a2f28b0ec | |||
| db1ad4dcab | |||
| 78ca539018 | |||
| 04cafc72dc | |||
| 63812994a1 | |||
| 19dee11539 | |||
| 6f3a6b7855 | |||
| 7c84ad4384 | |||
| bc647fc8e2 | |||
| 429ff6045d | |||
| 0de1deced4 | |||
| fc2eedfc66 | |||
| 7ddd819ff3 | |||
| 83b416d12d | |||
| b9c775c3ae | |||
| b613cf87c8 | |||
| 6f669866e9 | |||
| 4e61fefec8 | |||
| b4514ecd83 | |||
| 4f6902525e | |||
| 881139e36f | |||
| 32e2557456 | |||
| 8b44820e51 | |||
| 5e6417f837 | |||
| 3d5ac0b883 | |||
| dfb2a2f380 | |||
| d1de751850 | |||
| ecee6ca863 | |||
| 31ea3f92e2 | |||
| f19c934fae | |||
| 10d6f20de7 | |||
| 96b33bfbe4 | |||
| 444c787d0a | |||
| 61fcd4ac69 | |||
| b76802e6eb | |||
| 7d351029a4 | |||
| 4ee445c119 | |||
| 61ddeea495 | |||
| 7b802033b3 | |||
| b484f47369 | |||
| 66979df10c | |||
| 82f161fb91 | |||
| 9d0fd681d4 | |||
| c2ab47a102 | |||
| 8704c21621 | |||
| 03ffb25bf9 | |||
| 70db1ad062 | |||
| 952ed9b642 | |||
| f57fe79686 | |||
| 9179f1c351 | |||
| c4f7a1e09d | |||
| 701012a968 | |||
| 9767f72b8f | |||
| de0fb7459d | |||
| e2ead6dbe1 | |||
| 7b10d92ca4 | |||
| 2c6e5eb673 | |||
| 02fde4e530 | |||
| cc25fc1f32 | |||
| c971e486b5 | |||
| 96a9eb6f6a | |||
| 9eeb61ea0a | |||
| 08042c61ad | |||
| 36c74f30e5 | |||
| fd1d437211 | |||
| 4956d13bdc | |||
| 6478736654 | |||
| d9f6c0723e | |||
| f86050d916 | |||
| 52f5656190 | |||
| 21cd90f238 | |||
| 4e51188d35 | |||
| 22eb199936 | |||
| a2fc1bbc96 | |||
| 621599692f | |||
| 3ad3837c87 | |||
| 4d745e3b7e | |||
| 3a053b8dd6 | |||
| 1f144690da | |||
| eec1895acc | |||
| 72e243042e | |||
| 99864cb7a9 | |||
| 3155728119 | |||
| c253b22f69 | |||
| 66f3a3e9a8 | |||
| 65a1d6d91e | |||
| 44cf9b054b | |||
| 39e2473ef3 | |||
| 93a108863c | |||
| 0905593123 | |||
| ed9223d5a3 | |||
| c2ad4e5bb4 | |||
| 5f7f5ef92d | |||
| 962684ff56 | |||
| 7b3804c078 | |||
| 170f1823e1 | |||
| dc2020559a | |||
| 2b9444cce3 | |||
| 68c1c068ac | |||
| 3d0b70a237 | |||
| 65a6edc78c | |||
| 2ec8349897 | |||
| 38a2d94f80 | |||
| c7fa910516 | |||
| 2fe08274dd | |||
| be89d848dc | |||
| a230a9b8b9 | |||
| 72eae7cdf3 | |||
| 7cae195370 | |||
| dfb16e385c | |||
| 660e1cad0a | |||
| 7c1aa57a7e | |||
| a06e496f78 | |||
| 70599b97b9 | |||
| 02b194bde0 | |||
| 20ec049db5 | |||
| ebac4e8564 | |||
| da81664729 | |||
| fec3d46b33 | |||
| a4eb3a7dbf | |||
| 28d15f2c4f | |||
| c6f93e38f5 | |||
| 2159f71888 | |||
| a9abea3446 | |||
| 8e2713c9ba | |||
| 2ba0ef0e35 | |||
| d3713cbc79 | |||
| 4d3fb2b585 | |||
| ebfb9c4bc1 | |||
| 8e7918cc45 | |||
| c465eb3efc | |||
| b90136ac4e | |||
| ae5373168d | |||
| 6f3942f6b7 | |||
| 13f38343aa | |||
| f75b4843e8 | |||
| 008afe7a85 | |||
| b43844bd7a | |||
| cd89feb57e | |||
| 17553d606e | |||
| b6d9ed960b | |||
| 1d89a887fb |
@@ -0,0 +1,7 @@
|
||||
.git
|
||||
.github
|
||||
.gitignore
|
||||
**/node_modules
|
||||
**/target
|
||||
dist
|
||||
documentation
|
||||
@@ -14,3 +14,20 @@ 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
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
name: build-deb-meta
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: arc-ubuntu-22.04
|
||||
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Build Environment
|
||||
run: sudo apt-get update && sudo apt-get install -y make dpkg-dev
|
||||
|
||||
- name: Build Debian Packages
|
||||
working-directory: ppa/packages
|
||||
run: make
|
||||
|
||||
- name: Find .deb files
|
||||
working-directory: ppa/packages
|
||||
run: |
|
||||
echo "file1=$(ls nym-repo-setup*.deb)" >> $GITHUB_ENV
|
||||
echo "file2=$(ls nym-vpn*.deb)" >> $GITHUB_ENV
|
||||
|
||||
- name: Upload nym-repo-setup
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ env.file1 }}
|
||||
path: ppa/packages/nym-repo-setup*.deb
|
||||
retention-days: 10
|
||||
|
||||
- name: Upload nym-vpn
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ env.file2 }}
|
||||
path: ppa/packages/nym-vpn*.deb
|
||||
retention-days: 10
|
||||
@@ -7,7 +7,7 @@ jobs:
|
||||
build:
|
||||
runs-on: ubuntu-20.04-16-core
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- 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@v3
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18
|
||||
- name: Install Rust stable
|
||||
|
||||
@@ -13,6 +13,7 @@ on:
|
||||
- 'mixnode/**'
|
||||
- 'sdk/rust/nym-sdk/**'
|
||||
- 'service-providers/**'
|
||||
- '.github/workflows/ci-binary-config-checker.yml'
|
||||
pull_request:
|
||||
paths:
|
||||
- 'clients/**'
|
||||
@@ -22,6 +23,7 @@ on:
|
||||
- 'mixnode/**'
|
||||
- 'sdk/rust/nym-sdk/**'
|
||||
- 'service-providers/**'
|
||||
- '.github/workflows/ci-binary-config-checker.yml'
|
||||
|
||||
env:
|
||||
NETWORK: mainnet
|
||||
@@ -31,11 +33,11 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform: [custom-linux]
|
||||
platform: [arc-ubuntu-20.04]
|
||||
|
||||
runs-on: ${{ matrix.platform }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- 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
|
||||
|
||||
@@ -5,17 +5,18 @@ on:
|
||||
paths:
|
||||
- "ts-packages/**"
|
||||
- "sdk/typescript/**"
|
||||
- ".github/workflows/ci-build-ts.yml"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-20.04-16-core
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4
|
||||
- name: Install rsync
|
||||
run: sudo apt-get install rsync
|
||||
continue-on-error: true
|
||||
- uses: rlespinasse/github-slug-action@v3.x
|
||||
- uses: actions/setup-node@v3
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18
|
||||
- name: Setup yarn
|
||||
|
||||
@@ -8,11 +8,6 @@ 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
|
||||
@@ -36,19 +31,20 @@ on:
|
||||
- "service-providers/**"
|
||||
- "tools/**"
|
||||
- "nymvisor/**"
|
||||
- ".github/workflows/ci-build-upload-binaries.yml"
|
||||
|
||||
jobs:
|
||||
publish-nym:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform: [ubuntu-20.04]
|
||||
platform: [ arc-ubuntu-20.04 ]
|
||||
|
||||
runs-on: ${{ matrix.platform }}
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Prepare build output directory
|
||||
shell: bash
|
||||
@@ -67,13 +63,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
|
||||
if: >
|
||||
github.event_name == 'schedule' ||
|
||||
(github.event_name == 'workflow_dispatch' && inputs.enable_wireguard == true)
|
||||
|
||||
- name: Install Rust stable
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
@@ -99,13 +88,11 @@ jobs:
|
||||
|
||||
- name: Upload Artifact
|
||||
if: github.event_name == 'workflow_dispatch'
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: nym-binaries-artifacts
|
||||
path: |
|
||||
target/release/nym-client
|
||||
target/release/nym-gateway
|
||||
target/release/nym-mixnode
|
||||
target/release/nym-socks5-client
|
||||
target/release/nym-api
|
||||
target/release/nym-network-requester
|
||||
@@ -123,8 +110,6 @@ jobs:
|
||||
OUTPUT_DIR: ci-builds/${{ github.ref_name }}
|
||||
run: |
|
||||
cp target/release/nym-client $OUTPUT_DIR
|
||||
cp target/release/nym-gateway $OUTPUT_DIR
|
||||
cp target/release/nym-mixnode $OUTPUT_DIR
|
||||
cp target/release/nym-socks5-client $OUTPUT_DIR
|
||||
cp target/release/nym-api $OUTPUT_DIR
|
||||
cp target/release/nym-network-requester $OUTPUT_DIR
|
||||
|
||||
@@ -1,23 +1,6 @@
|
||||
name: ci-build
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- 'clients/**'
|
||||
- 'common/**'
|
||||
- 'explorer-api/**'
|
||||
- 'gateway/**'
|
||||
- 'integrations/**'
|
||||
- 'mixnode/**'
|
||||
- 'sdk/lib/socks5-listener/**'
|
||||
- 'sdk/rust/nym-sdk/**'
|
||||
- 'service-providers/**'
|
||||
- 'nym-api/**'
|
||||
- 'nym-outfox/**'
|
||||
- 'tools/nym-cli/**'
|
||||
- 'tools/nym-nr-query/**'
|
||||
- 'tools/ts-rs-cli/**'
|
||||
- 'Cargo.toml'
|
||||
pull_request:
|
||||
paths:
|
||||
- 'clients/**'
|
||||
@@ -26,15 +9,19 @@ on:
|
||||
- 'gateway/**'
|
||||
- 'integrations/**'
|
||||
- 'mixnode/**'
|
||||
- 'sdk/lib/socks5-listener/**'
|
||||
- 'sdk/rust/nym-sdk/**'
|
||||
- 'sdk/rust/**'
|
||||
- 'sdk/lib/**'
|
||||
- 'service-providers/**'
|
||||
- 'nym-network-monitor/**'
|
||||
- 'nym-api/**'
|
||||
- 'nym-node/**'
|
||||
- 'nym-outfox/**'
|
||||
- 'tools/nym-cli/**'
|
||||
- 'tools/nym-nr-query/**'
|
||||
- 'tools/ts-rs-cli/**'
|
||||
- 'nym-validator-rewarder/**'
|
||||
- 'tools/**'
|
||||
- 'wasm/**'
|
||||
- 'Cargo.toml'
|
||||
- 'Cargo.lock'
|
||||
- '.github/workflows/ci-build.yml'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
@@ -42,7 +29,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [custom-linux, custom-runner-mac-m1]
|
||||
os: [arc-ubuntu-20.04, custom-runner-mac-m1]
|
||||
runs-on: ${{ matrix.os }}
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
@@ -50,10 +37,10 @@ jobs:
|
||||
- name: Install Dependencies (Linux)
|
||||
run: sudo apt-get update && sudo apt-get -y install libwebkit2gtk-4.0-dev build-essential curl wget libssl-dev libgtk-3-dev libudev-dev squashfs-tools protobuf-compiler
|
||||
continue-on-error: true
|
||||
if: matrix.os == 'custom-linux'
|
||||
if: contains(matrix.os, 'ubuntu')
|
||||
|
||||
- name: Check out repository code
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install rust toolchain
|
||||
uses: actions-rs/toolchain@v1
|
||||
@@ -73,40 +60,46 @@ jobs:
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: build
|
||||
# Enable wireguard by default on linux only
|
||||
args: --workspace --features wireguard
|
||||
|
||||
- name: Build all examples
|
||||
if: matrix.os == 'custom-linux'
|
||||
# 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: --workspace --examples --features wireguard
|
||||
args: --features axum
|
||||
|
||||
- name: Build all examples
|
||||
if: contains(matrix.os, 'ubuntu')
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: build
|
||||
args: --workspace --examples
|
||||
|
||||
- name: Run all tests
|
||||
if: matrix.os == 'custom-linux'
|
||||
if: contains(matrix.os, 'ubuntu')
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: test
|
||||
args: --workspace --features wireguard
|
||||
args: --workspace
|
||||
|
||||
- name: Run expensive tests
|
||||
if: (github.ref == 'refs/heads/develop' || github.event.pull_request.base.ref == 'develop' || github.event.pull_request.base.ref == 'master') && matrix.os == 'custom-linux'
|
||||
if: (github.ref == 'refs/heads/develop' || github.event.pull_request.base.ref == 'develop' || github.event.pull_request.base.ref == 'master') && contains(matrix.os, 'ubuntu')
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: test
|
||||
args: --workspace --features wireguard -- --ignored
|
||||
args: --workspace -- --ignored
|
||||
|
||||
- name: Annotate with clippy checks
|
||||
if: matrix.os == 'custom-linux'
|
||||
if: contains(matrix.os, 'ubuntu')
|
||||
uses: actions-rs/clippy-check@v1
|
||||
continue-on-error: true
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
args: --workspace --features wireguard
|
||||
args: --workspace
|
||||
|
||||
- name: Clippy
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: clippy
|
||||
args: --workspace --all-targets --features wireguard -- -D warnings
|
||||
args: --workspace --all-targets --features axum -- -D warnings
|
||||
|
||||
@@ -2,10 +2,14 @@ name: ci-cargo-deny
|
||||
on:
|
||||
workflow_dispatch:
|
||||
pull_request:
|
||||
paths:
|
||||
- 'Cargo.toml'
|
||||
- 'Cargo.lock'
|
||||
- '.github/workflows/ci-cargo-deny.yml'
|
||||
|
||||
jobs:
|
||||
cargo-deny:
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: arc-ubuntu-22.04-dind
|
||||
strategy:
|
||||
matrix:
|
||||
checks:
|
||||
@@ -13,7 +17,7 @@ jobs:
|
||||
- licenses bans sources
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- uses: EmbarkStudios/cargo-deny-action@v1
|
||||
with:
|
||||
log-level: warn
|
||||
|
||||
@@ -6,16 +6,17 @@ on:
|
||||
paths:
|
||||
- 'contracts/**'
|
||||
- 'common/**'
|
||||
- '.github/workflows/ci-contracts-schema.yml'
|
||||
|
||||
jobs:
|
||||
check-schema:
|
||||
name: Generate and check schema
|
||||
runs-on: custom-linux
|
||||
runs-on: arc-ubuntu-20.04
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
steps:
|
||||
- name: Check out repository code
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install Rust toolchain
|
||||
uses: actions-rs/toolchain@v1
|
||||
|
||||
@@ -6,6 +6,7 @@ on:
|
||||
paths:
|
||||
- 'common/**'
|
||||
- 'contracts/**'
|
||||
- '.github/workflows/ci-contracts-upload-binaries.yml'
|
||||
|
||||
env:
|
||||
NETWORK: mainnet
|
||||
@@ -15,13 +16,13 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform: [ubuntu-20.04]
|
||||
platform: arc-ubuntu-20.04
|
||||
|
||||
runs-on: ${{ matrix.platform }}
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Prepare build output directory
|
||||
shell: bash
|
||||
@@ -58,6 +59,7 @@ 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
|
||||
|
||||
@@ -9,15 +9,16 @@ on:
|
||||
paths:
|
||||
- 'contracts/**'
|
||||
- 'common/**'
|
||||
- '.github/workflows/ci-contracts.yml'
|
||||
|
||||
jobs:
|
||||
matrix_prep:
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: arc-ubuntu-20.04
|
||||
outputs:
|
||||
matrix: ${{ steps.set-matrix.outputs.matrix }}
|
||||
steps:
|
||||
# creates the matrix strategy from ci-contracts-matrix-includes.json
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4
|
||||
- id: set-matrix
|
||||
uses: JoshuaTheMiller/conditional-build-matrix@main
|
||||
with:
|
||||
@@ -34,7 +35,7 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix: ${{fromJson(needs.matrix_prep.outputs.matrix)}}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup rust
|
||||
uses: actions-rs/toolchain@v1
|
||||
|
||||
@@ -6,12 +6,13 @@ on:
|
||||
branches-ignore: master
|
||||
paths:
|
||||
- 'documentation/docs/**'
|
||||
- '.github/workflows/ci-docs.yml'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-20.04-16-core
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- 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 +22,7 @@ jobs:
|
||||
- name: Install rsync
|
||||
run: sudo apt-get install rsync
|
||||
- uses: rlespinasse/github-slug-action@v3.x
|
||||
- uses: actions/setup-node@v3
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18
|
||||
- name: Install Rust stable
|
||||
|
||||
@@ -10,15 +10,16 @@ on:
|
||||
- "nym-wallet/src/**"
|
||||
- "nym-wallet/package.json"
|
||||
- "explorer/**"
|
||||
- ".github/workflows/ci-lint-typescript.yml"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-20.04-16-core
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4
|
||||
- uses: rlespinasse/github-slug-action@v3.x
|
||||
|
||||
- uses: actions/setup-node@v3
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18
|
||||
- name: Setup yarn
|
||||
@@ -38,7 +39,7 @@ jobs:
|
||||
version: '116'
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v4
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.20'
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ jobs:
|
||||
name: nym-api tests
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: install yarn in root
|
||||
run: cd ../.. && yarn install
|
||||
@@ -24,7 +24,7 @@ jobs:
|
||||
run: npm install
|
||||
|
||||
- name: Node v18
|
||||
uses: actions/setup-node@v3
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18.1.0
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ on:
|
||||
push:
|
||||
paths:
|
||||
- 'explorer/**'
|
||||
- '.github/workflows/ci-nym-network-explorer.yml'
|
||||
|
||||
defaults:
|
||||
run:
|
||||
@@ -14,12 +15,12 @@ jobs:
|
||||
build:
|
||||
runs-on: custom-linux
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4
|
||||
- name: Install rsync
|
||||
run: sudo apt-get install rsync
|
||||
continue-on-error: true
|
||||
- uses: rlespinasse/github-slug-action@v3.x
|
||||
- uses: actions/setup-node@v3
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18
|
||||
- name: Setup yarn
|
||||
|
||||
@@ -1,22 +1,17 @@
|
||||
name: ci-nym-wallet-rust
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- 'nym-wallet/**'
|
||||
- 'common/**'
|
||||
- 'contracts/vesting/**'
|
||||
- 'nym-api/nym-api-requests/**'
|
||||
pull_request:
|
||||
paths:
|
||||
- 'nym-wallet/**'
|
||||
- 'common/**'
|
||||
- 'contracts/vesting/**'
|
||||
- 'nym-api/nym-api-requests/**'
|
||||
- '.github/workflows/ci-nym-wallet-rust.yml'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: [ self-hosted, custom-linux ]
|
||||
runs-on: arc-ubuntu-20.04
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
steps:
|
||||
@@ -25,7 +20,7 @@ jobs:
|
||||
continue-on-error: true
|
||||
|
||||
- name: Check out repository code
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install rust toolchain
|
||||
uses: actions-rs/toolchain@v1
|
||||
|
||||
@@ -4,12 +4,13 @@ on:
|
||||
pull_request:
|
||||
paths:
|
||||
- 'nym-wallet/**'
|
||||
- '.github/workflows/ci-nym-wallet-storybook.yml'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: custom-linux
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install rsync
|
||||
run: sudo apt-get install rsync
|
||||
@@ -17,7 +18,7 @@ jobs:
|
||||
|
||||
- uses: rlespinasse/github-slug-action@v3.x
|
||||
|
||||
- uses: actions/setup-node@v3
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18
|
||||
|
||||
|
||||
@@ -5,17 +5,18 @@ on:
|
||||
paths:
|
||||
- "sdk/typescript/**"
|
||||
- "wasm/**"
|
||||
- '.github/workflows/ci-sdk-docs-typescript.yml'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: custom-linux
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4
|
||||
- name: Install rsync
|
||||
run: sudo apt-get install rsync
|
||||
continue-on-error: true
|
||||
- uses: rlespinasse/github-slug-action@v3.x
|
||||
- uses: actions/setup-node@v3
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18.17
|
||||
- name: Install Rust stable
|
||||
@@ -26,7 +27,7 @@ jobs:
|
||||
run: npm install -g yarn
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v4
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.20'
|
||||
|
||||
|
||||
@@ -6,16 +6,17 @@ on:
|
||||
- 'wasm/**'
|
||||
- 'clients/client-core/**'
|
||||
- 'common/**'
|
||||
- '.github/workflows/ci-sdk-wasm.yml'
|
||||
|
||||
jobs:
|
||||
wasm:
|
||||
runs-on: [custom-linux]
|
||||
runs-on: arc-ubuntu-20.04
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/setup-node@v3
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18
|
||||
|
||||
@@ -28,7 +29,7 @@ jobs:
|
||||
components: rustfmt, clippy
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v4
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.20'
|
||||
|
||||
|
||||
@@ -30,14 +30,14 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
- name: Setup Pages
|
||||
uses: actions/configure-pages@v3
|
||||
uses: actions/configure-pages@v5
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-pages-artifact@v2
|
||||
uses: actions/upload-pages-artifact@v3
|
||||
with:
|
||||
# Upload entire repository
|
||||
path: './ppa'
|
||||
- name: Deploy to GitHub Pages
|
||||
id: deployment
|
||||
uses: actions/deploy-pages@v2
|
||||
uses: actions/deploy-pages@v4
|
||||
|
||||
@@ -18,7 +18,7 @@ jobs:
|
||||
continue-on-error: true
|
||||
steps:
|
||||
- name: Check out repository code
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- 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@v2
|
||||
uses: arduino/setup-protoc@v3
|
||||
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@v2
|
||||
uses: technote-space/workflow-conclusion-action@v3
|
||||
- name: Check out repository code
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
- name: install npm
|
||||
uses: actions/setup-node@v3
|
||||
uses: actions/setup-node@v4
|
||||
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@v3
|
||||
uses: actions/checkout@v4
|
||||
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@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Setup git user
|
||||
@@ -47,7 +47,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
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@v3
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- 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@v2
|
||||
uses: technote-space/workflow-conclusion-action@v3
|
||||
- name: Check out repository code
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
- name: install npm
|
||||
uses: actions/setup-node@v3
|
||||
uses: actions/setup-node@v4
|
||||
if: env.WORKFLOW_CONCLUSION == 'failure'
|
||||
with:
|
||||
node-version: 18
|
||||
|
||||
@@ -8,7 +8,7 @@ jobs:
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- name: Checkout repository code
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v4
|
||||
- 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@v3
|
||||
- uses: actions/upload-artifact@v4
|
||||
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@v2
|
||||
uses: actions/checkout@v4
|
||||
- name: Download report from previous job
|
||||
uses: actions/download-artifact@v3
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: report
|
||||
path: .github/workflows/support-files/notifications
|
||||
- name: install npm
|
||||
uses: actions/setup-node@v3
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18
|
||||
- name: Matrix - Node Install
|
||||
|
||||
@@ -40,7 +40,7 @@ jobs:
|
||||
cli_version: ${{ steps.binary-versions.outputs.cli_version }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- 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
|
||||
@@ -60,10 +60,10 @@ jobs:
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: build
|
||||
args: --workspace --release
|
||||
|
||||
args: --workspace --release ${{ env.CARGO_FEATURES }}
|
||||
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: my-artifact
|
||||
path: |
|
||||
@@ -79,7 +79,7 @@ jobs:
|
||||
|
||||
- id: create-release
|
||||
name: Upload to release based on tag name
|
||||
uses: softprops/action-gh-release@v1
|
||||
uses: softprops/action-gh-release@v2
|
||||
if: github.event_name == 'release'
|
||||
with:
|
||||
files: |
|
||||
|
||||
@@ -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@v2
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- 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@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
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@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
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@v1
|
||||
uses: softprops/action-gh-release@v2
|
||||
if: github.event_name == 'release'
|
||||
with:
|
||||
files: |
|
||||
|
||||
@@ -25,10 +25,10 @@ jobs:
|
||||
file_hash: ${{ steps.release-info.outputs.file_hash }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Node
|
||||
uses: actions/setup-node@v3
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18
|
||||
- name: Install Rust stable
|
||||
@@ -83,7 +83,7 @@ jobs:
|
||||
run: yarn && yarn build
|
||||
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
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@v1
|
||||
uses: softprops/action-gh-release@v2
|
||||
if: github.event_name == 'release'
|
||||
with:
|
||||
files: |
|
||||
|
||||
@@ -25,7 +25,7 @@ jobs:
|
||||
file_hash: ${{ steps.release-info.outputs.file_hash }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Tauri dependencies
|
||||
run: >
|
||||
@@ -34,7 +34,7 @@ jobs:
|
||||
continue-on-error: true
|
||||
|
||||
- name: Node
|
||||
uses: actions/setup-node@v3
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18
|
||||
|
||||
@@ -62,7 +62,7 @@ jobs:
|
||||
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
|
||||
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
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@v1
|
||||
uses: softprops/action-gh-release@v2
|
||||
if: github.event_name == 'release'
|
||||
with:
|
||||
files: |
|
||||
|
||||
+9
-6
@@ -1,4 +1,4 @@
|
||||
name: publish-nym-wallet-win10
|
||||
name: publish-nym-wallet-win11
|
||||
on:
|
||||
workflow_dispatch:
|
||||
release:
|
||||
@@ -14,7 +14,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform: [windows10]
|
||||
platform: [custom-windows-11]
|
||||
runs-on: ${{ matrix.platform }}
|
||||
|
||||
outputs:
|
||||
@@ -33,7 +33,7 @@ jobs:
|
||||
del /s /q /A:H nym
|
||||
rmdir /s /q nym
|
||||
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- 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@v3
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18
|
||||
|
||||
@@ -62,6 +62,9 @@ jobs:
|
||||
fileName: '.env'
|
||||
encodedString: ${{ secrets.WALLET_ADMIN_ADDRESS }}
|
||||
|
||||
- name: Install Yarn
|
||||
run: npm install -g yarn
|
||||
|
||||
- name: Install project dependencies
|
||||
shell: bash
|
||||
run: cd .. && yarn --network-timeout 100000
|
||||
@@ -82,7 +85,7 @@ jobs:
|
||||
run: yarn build
|
||||
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: nym-wallet_1.0.0_x64_en-US.msi
|
||||
path: nym-wallet/target/release/bundle/msi/nym-wallet_1.*.msi
|
||||
@@ -90,7 +93,7 @@ jobs:
|
||||
|
||||
- id: create-release
|
||||
name: Upload to release based on tag name
|
||||
uses: softprops/action-gh-release@v1
|
||||
uses: softprops/action-gh-release@v2
|
||||
if: github.event_name == 'release'
|
||||
with:
|
||||
files: |
|
||||
@@ -22,10 +22,10 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install Java
|
||||
uses: actions/setup-java@v3
|
||||
uses: actions/setup-java@v4
|
||||
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.70.0
|
||||
uses: dtolnay/rust-toolchain@1.90.0
|
||||
|
||||
- name: Install rust android targets
|
||||
run: |
|
||||
@@ -84,7 +84,7 @@ jobs:
|
||||
apk/nyms5-arch64-release.apk
|
||||
|
||||
- name: Upload APKs
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: nyms5-apk-arch64
|
||||
path: |
|
||||
@@ -97,14 +97,14 @@ jobs:
|
||||
runs-on: custom-linux
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
- name: Download binary artifact
|
||||
uses: actions/download-artifact@v3
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: nyms5-apk-arch64
|
||||
path: apk
|
||||
- name: Release
|
||||
uses: softprops/action-gh-release@v1
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
files: |
|
||||
apk/nyms5-arch64-debug.apk
|
||||
|
||||
@@ -6,10 +6,10 @@ jobs:
|
||||
publish:
|
||||
runs-on: ubuntu-20.04-16-core
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install Node
|
||||
uses: actions/setup-node@v3
|
||||
uses: actions/setup-node@v4
|
||||
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@v4
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: "1.20"
|
||||
|
||||
- name: Install TinyGo
|
||||
uses: acifani/setup-tinygo@v1
|
||||
uses: acifani/setup-tinygo@v2
|
||||
with:
|
||||
tinygo-version: "0.27.0"
|
||||
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
name: Build and upload Network monitor container to harbor.nymte.ch
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
WORKING_DIRECTORY: "."
|
||||
CONTAINER_NAME: "network-monitor"
|
||||
|
||||
jobs:
|
||||
build-container:
|
||||
runs-on: arc-ubuntu-22.04-dind
|
||||
steps:
|
||||
- name: Login to Harbor
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: harbor.nymte.ch
|
||||
username: ${{ secrets.HARBOR_ROBOT_USERNAME }}
|
||||
password: ${{ secrets.HARBOR_ROBOT_SECRET }}
|
||||
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Configure git identity
|
||||
run: |
|
||||
git config --global user.email "lawrence@nymtech.net"
|
||||
git config --global user.name "Lawrence Stalder"
|
||||
|
||||
- name: Get version from package.json
|
||||
uses: sergeysova/jq-action@v2
|
||||
id: get_version
|
||||
with:
|
||||
cmd: jq -r '.version' ${{ env.WORKING_DIRECTORY }}/package.json
|
||||
|
||||
- name: Check if tag exists
|
||||
run: |
|
||||
if git rev-parse ${{ steps.get_version.outputs.value }} >/dev/null 2>&1; then
|
||||
echo "Tag ${{ steps.get_version.outputs.value }} already exists"
|
||||
fi
|
||||
|
||||
- name: Remove existing tag if exists
|
||||
run: |
|
||||
if git rev-parse ${{ steps.get_version.outputs.value }} >/dev/null 2>&1; then
|
||||
git push --delete origin ${{ steps.get_version.outputs.value }}
|
||||
git tag -d ${{ steps.get_version.outputs.value }}
|
||||
fi
|
||||
|
||||
- name: Create tag
|
||||
run: |
|
||||
git tag -a ${{ steps.get_version.outputs.value }} -m "Version ${{ steps.get_version.outputs.value }}"
|
||||
git push origin ${{ steps.get_version.outputs.value }}
|
||||
|
||||
- name: BuildAndPushImageOnHarbor
|
||||
run: |
|
||||
docker build -f nym-network-monitor.dockerfile ${{ env.WORKING_DIRECTORY }} -t harbor.nymte.ch/nym/${{ env.CONTAINER_NAME }}:${{ steps.get_version.outputs.value }} -t harbor.nymte.ch/nym/${{ env.CONTAINER_NAME }}:latest
|
||||
docker push harbor.nymte.ch/nym/${{ env.CONTAINER_NAME }} --all-tags
|
||||
@@ -20,8 +20,8 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check out repository code
|
||||
uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3
|
||||
uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
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@v2
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: Asset Hashes
|
||||
path: hashes.json
|
||||
|
||||
+4
-1
@@ -48,4 +48,7 @@ foxyfox.env
|
||||
|
||||
.next
|
||||
ppa-private-key.b64
|
||||
ppa-private-key.asc
|
||||
ppa-private-key.asc
|
||||
nym-network-monitor/topology.json
|
||||
nym-network-monitor/__pycache__
|
||||
nym-network-monitor/*.key
|
||||
+124
-1
@@ -4,6 +4,130 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [2024.10-caramello] (2024-09-10)
|
||||
|
||||
- Backport 4844 and 4845 ([#4857])
|
||||
- Bugfix/client registration vol2 ([#4856])
|
||||
- Remove wireguard feature flag and pass runtime enabled flag ([#4839])
|
||||
- Eliminate cancel unsafe sig awaiting ([#4834])
|
||||
- added explicit updateable admin to the mixnet contract ([#4822])
|
||||
- using legacy signing payload in CLI and verifying both variants in contract ([#4821])
|
||||
- adding ecash contract address ([#4819])
|
||||
- Check profit margin of node before defaulting to hardcoded value ([#4802])
|
||||
- Sync last_seen_bandwidth immediately ([#4774])
|
||||
- Feature/additional ecash nym cli utils ([#4773])
|
||||
- Better storage error logging ([#4772])
|
||||
- bugfix: make sure DKG parses data out of events if logs are empty ([#4764])
|
||||
- Fix clippy on rustc beta toolchain ([#4746])
|
||||
- Fix clippy for beta toolchain ([#4742])
|
||||
- Disable testnet-manager on non-unix ([#4741])
|
||||
- Don't set NYM_VPN_API to default ([#4740])
|
||||
- Update publish-nym-binaries.yml ([#4739])
|
||||
- Update ci-build-upload-binaries.yml ([#4738])
|
||||
- Add NYM_VPN_API to network config ([#4736])
|
||||
- Re-export RecipientFormattingError in nym sdk ([#4735])
|
||||
- Persist wireguard peers ([#4732])
|
||||
- Fix tokio error in 1.39 ([#4730])
|
||||
- Feature/vesting purge plus ranged cost params ([#4716])
|
||||
- Fix (some) feature unification build failures ([#4681])
|
||||
- Feature Compact Ecash : The One PR ([#4623])
|
||||
|
||||
[#4857]: https://github.com/nymtech/nym/pull/4857
|
||||
[#4856]: https://github.com/nymtech/nym/pull/4856
|
||||
[#4839]: https://github.com/nymtech/nym/pull/4839
|
||||
[#4834]: https://github.com/nymtech/nym/pull/4834
|
||||
[#4822]: https://github.com/nymtech/nym/pull/4822
|
||||
[#4821]: https://github.com/nymtech/nym/pull/4821
|
||||
[#4819]: https://github.com/nymtech/nym/pull/4819
|
||||
[#4802]: https://github.com/nymtech/nym/pull/4802
|
||||
[#4774]: https://github.com/nymtech/nym/pull/4774
|
||||
[#4773]: https://github.com/nymtech/nym/pull/4773
|
||||
[#4772]: https://github.com/nymtech/nym/pull/4772
|
||||
[#4764]: https://github.com/nymtech/nym/pull/4764
|
||||
[#4746]: https://github.com/nymtech/nym/pull/4746
|
||||
[#4742]: https://github.com/nymtech/nym/pull/4742
|
||||
[#4741]: https://github.com/nymtech/nym/pull/4741
|
||||
[#4740]: https://github.com/nymtech/nym/pull/4740
|
||||
[#4739]: https://github.com/nymtech/nym/pull/4739
|
||||
[#4738]: https://github.com/nymtech/nym/pull/4738
|
||||
[#4736]: https://github.com/nymtech/nym/pull/4736
|
||||
[#4735]: https://github.com/nymtech/nym/pull/4735
|
||||
[#4732]: https://github.com/nymtech/nym/pull/4732
|
||||
[#4730]: https://github.com/nymtech/nym/pull/4730
|
||||
[#4716]: https://github.com/nymtech/nym/pull/4716
|
||||
[#4681]: https://github.com/nymtech/nym/pull/4681
|
||||
[#4623]: https://github.com/nymtech/nym/pull/4623
|
||||
|
||||
## [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])
|
||||
- Bump braces from 3.0.2 to 3.0.3 in /wasm/mix-fetch/internal-dev ([#4672])
|
||||
- add expiry returned on import ([#4670])
|
||||
- [bugfix] missing rustls feature ([#4666])
|
||||
- Bump ws from 8.13.0 to 8.17.1 in /wasm/client/internal-dev-node ([#4665])
|
||||
- Bump braces from 3.0.2 to 3.0.3 in /clients/native/examples/js-examples/websocket ([#4663])
|
||||
- Bump ws from 8.14.2 to 8.17.1 in /sdk/typescript/packages/nodejs-client ([#4662])
|
||||
- Update setup.md ([#4661])
|
||||
- New clippy lints ([#4660])
|
||||
- Bump braces from 3.0.2 to 3.0.3 in /nym-api/tests ([#4659])
|
||||
- Bump braces from 3.0.2 to 3.0.3 in /docker/typescript_client/upload_contract ([#4658])
|
||||
- Update vps-setup.md ([#4656])
|
||||
- Update configuration.md ([#4655])
|
||||
- Remove old PR template ([#4639])
|
||||
|
||||
[#4686]: https://github.com/nymtech/nym/pull/4686
|
||||
[#4672]: https://github.com/nymtech/nym/pull/4672
|
||||
[#4670]: https://github.com/nymtech/nym/pull/4670
|
||||
[#4666]: https://github.com/nymtech/nym/pull/4666
|
||||
[#4665]: https://github.com/nymtech/nym/pull/4665
|
||||
[#4663]: https://github.com/nymtech/nym/pull/4663
|
||||
[#4662]: https://github.com/nymtech/nym/pull/4662
|
||||
[#4661]: https://github.com/nymtech/nym/pull/4661
|
||||
[#4660]: https://github.com/nymtech/nym/pull/4660
|
||||
[#4659]: https://github.com/nymtech/nym/pull/4659
|
||||
[#4658]: https://github.com/nymtech/nym/pull/4658
|
||||
[#4656]: https://github.com/nymtech/nym/pull/4656
|
||||
[#4655]: https://github.com/nymtech/nym/pull/4655
|
||||
[#4639]: https://github.com/nymtech/nym/pull/4639
|
||||
|
||||
## [2024.6-chomp] (2024-06-25)
|
||||
|
||||
- Remove additional code as part of Ephemera Purge and SP and contracts ([#4650])
|
||||
@@ -481,7 +605,6 @@ 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
+1628
-790
File diff suppressed because it is too large
Load Diff
+85
-54
@@ -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,6 +33,7 @@ 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",
|
||||
@@ -44,10 +45,15 @@ members = [
|
||||
"common/credentials",
|
||||
"common/credential-utils",
|
||||
"common/credentials-interface",
|
||||
"common/credential-verification",
|
||||
"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",
|
||||
@@ -58,6 +64,7 @@ members = [
|
||||
"common/node-tester-utils",
|
||||
"common/nonexhaustive-delayqueue",
|
||||
"common/nymcoconut",
|
||||
"common/nym_offline_compact_ecash",
|
||||
"common/nym-id",
|
||||
"common/nym-metrics",
|
||||
"common/nymsphinx",
|
||||
@@ -73,6 +80,7 @@ members = [
|
||||
"common/nymsphinx/types",
|
||||
"common/nyxd-scraper",
|
||||
"common/pemstore",
|
||||
"common/serde-helpers",
|
||||
"common/socks5-client-core",
|
||||
"common/socks5/proxy-helpers",
|
||||
"common/socks5/requests",
|
||||
@@ -90,14 +98,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",
|
||||
"nym-api",
|
||||
"nym-browser-extension/storage",
|
||||
"nym-api/nym-api-requests",
|
||||
@@ -108,6 +117,8 @@ members = [
|
||||
"nym-validator-rewarder",
|
||||
"tools/internal/ssl-inject",
|
||||
# "tools/internal/sdk-version-bump",
|
||||
"tools/internal/testnet-manager",
|
||||
"tools/internal/testnet-manager/dkg-bypass-contract",
|
||||
"tools/nym-cli",
|
||||
"tools/nym-id-cli",
|
||||
"tools/nym-nr-query",
|
||||
@@ -123,20 +134,23 @@ members = [
|
||||
default-members = [
|
||||
"clients/native",
|
||||
"clients/socks5",
|
||||
"explorer-api",
|
||||
"gateway",
|
||||
"service-providers/network-requester",
|
||||
"mixnode",
|
||||
"nym-api",
|
||||
"tools/nymvisor",
|
||||
"explorer-api",
|
||||
"nym-node",
|
||||
"nym-validator-rewarder",
|
||||
"nym-node"
|
||||
"service-providers/authenticator",
|
||||
"service-providers/ip-packet-router",
|
||||
"service-providers/network-requester",
|
||||
"tools/nymvisor",
|
||||
]
|
||||
|
||||
exclude = [
|
||||
"explorer",
|
||||
"contracts",
|
||||
"nym-wallet",
|
||||
"nym-vpn/ui/src-tauri",
|
||||
"cpu-cycles",
|
||||
"sdk/ffi/cpp",
|
||||
]
|
||||
@@ -148,24 +162,31 @@ 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"
|
||||
aes = "0.8.1"
|
||||
aes-gcm = "0.10.1"
|
||||
anyhow = "1.0.71"
|
||||
anyhow = "1.0.87"
|
||||
argon2 = "0.5.0"
|
||||
async-trait = "0.1.68"
|
||||
async-trait = "0.1.82"
|
||||
axum = "0.7.5"
|
||||
axum-extra = "0.9.3"
|
||||
base64 = "0.21.4"
|
||||
base64 = "0.22.1"
|
||||
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.3.1"
|
||||
|
||||
blake3 = "1.5.4"
|
||||
bloomfilter = "1.0.14"
|
||||
bs58 = "0.5.1"
|
||||
bytecodec = "0.4.15"
|
||||
bytes = "1.5.0"
|
||||
bytes = "1.7.1"
|
||||
cargo_metadata = "0.18.1"
|
||||
celes = "2.4.0"
|
||||
cfg-if = "1.0.0"
|
||||
@@ -173,15 +194,16 @@ chacha20 = "0.9.0"
|
||||
chacha20poly1305 = "0.10.1"
|
||||
chrono = "0.4.31"
|
||||
cipher = "0.4.3"
|
||||
clap = "4.4.7"
|
||||
clap_complete = "4.0"
|
||||
clap_complete_fig = "4.0"
|
||||
clap = "4.5.17"
|
||||
clap_complete = "4.5"
|
||||
clap_complete_fig = "4.5"
|
||||
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"
|
||||
const_format = "0.2.32"
|
||||
const_format = "0.2.33"
|
||||
criterion = "0.4"
|
||||
csv = "1.3.0"
|
||||
ctr = "0.9.1"
|
||||
@@ -190,15 +212,15 @@ curve25519-dalek = "4.1"
|
||||
dashmap = "5.5.3"
|
||||
defguard_wireguard_rs = "0.4.2"
|
||||
digest = "0.10.7"
|
||||
dirs = "4.0"
|
||||
dirs = "5.0"
|
||||
doc-comment = "0.3"
|
||||
dotenvy = "0.15.6"
|
||||
ecdsa = "0.16"
|
||||
ed25519-dalek = "2.1"
|
||||
etherparse = "0.13.0"
|
||||
eyre = "0.6.9"
|
||||
fastrand = "2.1.0"
|
||||
flate2 = "1.0.28"
|
||||
fastrand = "2.1.1"
|
||||
flate2 = "1.0.33"
|
||||
futures = "0.3.28"
|
||||
generic-array = "0.14.7"
|
||||
getrandom = "0.2.10"
|
||||
@@ -214,11 +236,12 @@ httpcodec = "0.2.3"
|
||||
humantime = "2.1.0"
|
||||
humantime-serde = "1.1.1"
|
||||
hyper = "1.3.1"
|
||||
indexed_db_futures = "0.3.0"
|
||||
indicatif = "0.17.8"
|
||||
inquire = "0.6.2"
|
||||
ip_network = "0.4.1"
|
||||
ipnetwork = "0.16"
|
||||
ipnetwork = "0.20"
|
||||
isocountry = "0.3.2"
|
||||
itertools = "0.13.0"
|
||||
k256 = "0.13"
|
||||
lazy_static = "1.4.0"
|
||||
ledger-transport = "0.10.0"
|
||||
@@ -232,54 +255,53 @@ okapi = "0.7.0"
|
||||
once_cell = "1.7.2"
|
||||
opentelemetry = "0.19.0"
|
||||
opentelemetry-jaeger = "0.18.0"
|
||||
parking_lot = "0.12.1"
|
||||
parking_lot = "0.12.3"
|
||||
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.8.4"
|
||||
regex = "1.10.6"
|
||||
reqwest = { version = "0.12.4", default-features = false }
|
||||
rocket = "0.5.0"
|
||||
rocket_cors = "0.6.0"
|
||||
rocket_okapi = "0.8.0"
|
||||
safer-ffi = "0.1.4"
|
||||
schemars = "0.8.1"
|
||||
safer-ffi = "0.1.12"
|
||||
schemars = "0.8.21"
|
||||
semver = "1.0.23"
|
||||
serde = "1.0.152"
|
||||
serde_bytes = "0.11.6"
|
||||
serde = "1.0.210"
|
||||
serde_bytes = "0.11.15"
|
||||
serde_derive = "1.0"
|
||||
serde_json = "1.0.91"
|
||||
serde_json = "1.0.128"
|
||||
serde_repr = "0.1"
|
||||
serde_with = "3.4.0"
|
||||
serde_with = "3.9.0"
|
||||
serde_yaml = "0.9.25"
|
||||
sha2 = "0.10.8"
|
||||
si-scale = "0.2.2"
|
||||
si-scale = "0.2.3"
|
||||
sphinx-packet = "0.1.1"
|
||||
sqlx = "0.6.3"
|
||||
strum = "0.25"
|
||||
strum = "0.26"
|
||||
subtle-encoding = "0.5"
|
||||
syn = "1"
|
||||
sysinfo = "0.30.12"
|
||||
tap = "1.0.1"
|
||||
tar = "0.4.40"
|
||||
tar = "0.4.41"
|
||||
tempfile = "3.5.0"
|
||||
thiserror = "1.0.48"
|
||||
thiserror = "1.0.63"
|
||||
time = "0.3.30"
|
||||
tokio = "1.33.0"
|
||||
tokio-stream = "0.1.14"
|
||||
tokio-test = "0.4.2"
|
||||
tokio = "1.39"
|
||||
tokio-stream = "0.1.16"
|
||||
tokio-test = "0.4.4"
|
||||
tokio-tungstenite = { version = "0.20.1" }
|
||||
tokio-util = "0.7.10"
|
||||
tokio-util = "0.7.12"
|
||||
toml = "0.8.14"
|
||||
tower = "0.4.13"
|
||||
tower-http = "0.5.2"
|
||||
@@ -289,12 +311,15 @@ 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.4"
|
||||
utoipa = "4.2.0"
|
||||
utoipa-swagger-ui = "6.0.0"
|
||||
url = "2.5"
|
||||
utoipa = "4.2"
|
||||
utoipa-rapidoc = "4.0"
|
||||
utoipa-swagger-ui = "7.1"
|
||||
utoipauto = "0.1"
|
||||
uuid = "*"
|
||||
vergen = { version = "=8.3.1", default-features = false }
|
||||
walkdir = "2"
|
||||
wasm-bindgen-test = "0.3.36"
|
||||
wasm-bindgen-test = "0.3.43"
|
||||
x25519-dalek = "2.0.0"
|
||||
zeroize = "1.6.0"
|
||||
|
||||
@@ -303,7 +328,8 @@ prometheus = { version = "0.13.0" }
|
||||
# coconut/DKG related
|
||||
# unfortunately until https://github.com/zkcrypto/bls12_381/issues/10 is resolved, we have to rely on the fork
|
||||
# as we need to be able to serialize Gt so that we could create the lookup table for baby-step-giant-step algorithm
|
||||
bls12_381 = { git = "https://github.com/jstuczyn/bls12_381", default-features = false, branch = "feature/gt-serialization-0.8.0" }
|
||||
# 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" }
|
||||
group = { version = "0.13.0", default-features = false }
|
||||
ff = { version = "0.13.0", default-features = false }
|
||||
|
||||
@@ -324,26 +350,31 @@ cw4 = { version = "=1.1.2" }
|
||||
cw-controllers = { version = "=1.1.0" }
|
||||
|
||||
# cosmrs-related
|
||||
bip32 = { version = "0.5.1", default-features = false }
|
||||
bip32 = { version = "0.5.2", default-features = false }
|
||||
|
||||
# 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
|
||||
# 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
|
||||
prost = { version = "0.12", default-features = false }
|
||||
|
||||
# wasm-related dependencies
|
||||
gloo-utils = "0.2.0"
|
||||
gloo-net = "0.5.0"
|
||||
js-sys = "0.3.69"
|
||||
|
||||
# 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"
|
||||
serde-wasm-bindgen = "0.6.5"
|
||||
tsify = "0.4.5"
|
||||
wasm-bindgen = "0.2.92"
|
||||
wasm-bindgen-futures = "0.4.39"
|
||||
wasm-bindgen = "0.2.93"
|
||||
wasm-bindgen-futures = "0.4.43"
|
||||
wasmtimer = "0.2.0"
|
||||
web-sys = "0.3.69"
|
||||
itertools = "0.12.0"
|
||||
web-sys = "0.3.70"
|
||||
|
||||
|
||||
# Profile settings for individual crates
|
||||
|
||||
@@ -133,7 +133,7 @@ clippy: sdk-wasm-lint
|
||||
# Build contracts ready for deploy
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
CONTRACTS=vesting_contract mixnet_contract
|
||||
CONTRACTS=vesting_contract mixnet_contract nym_ecash
|
||||
CONTRACTS_WASM=$(addsuffix .wasm, $(CONTRACTS))
|
||||
CONTRACTS_OUT_DIR=contracts/target/wasm32-unknown-unknown/release
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ References for developers:
|
||||
|
||||
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](discord.gg/nymproject)
|
||||
* The various developer channels on [Discord](https://nymtech.net/go/discord)
|
||||
|
||||
### Tokenomics & Rewards
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "nym-client"
|
||||
version = "1.1.36"
|
||||
version = "1.1.40"
|
||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"]
|
||||
description = "Implementation of the Nym Client"
|
||||
edition = "2021"
|
||||
@@ -26,30 +26,46 @@ clap = { workspace = true, features = ["cargo", "derive"] }
|
||||
dirs = { workspace = true }
|
||||
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-surb-storage", "fs-gateways-storage", "cli"] }
|
||||
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-config = { path = "../../common/config" }
|
||||
nym-credential-storage = { path = "../../common/credential-storage" }
|
||||
nym-credentials = { path = "../../common/credentials" }
|
||||
nym-crypto = { path = "../../common/crypto" }
|
||||
nym-gateway-requests = { path = "../../gateway/gateway-requests" }
|
||||
nym-gateway-requests = { path = "../../common/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" }
|
||||
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::commands::CliNativeClient;
|
||||
use crate::error::ClientError;
|
||||
use nym_client_core::cli_helpers::client_import_coin_index_signatures::{
|
||||
import_coin_index_signatures, CommonClientImportCoinIndexSignaturesArgs,
|
||||
};
|
||||
|
||||
pub(crate) async fn execute(
|
||||
args: CommonClientImportCoinIndexSignaturesArgs,
|
||||
) -> Result<(), ClientError> {
|
||||
import_coin_index_signatures::<CliNativeClient, _>(args).await?;
|
||||
println!("successfully imported coin index signatures!");
|
||||
Ok(())
|
||||
}
|
||||
+2
-2
@@ -4,10 +4,10 @@
|
||||
use crate::commands::CliNativeClient;
|
||||
use crate::error::ClientError;
|
||||
use nym_client_core::cli_helpers::client_import_credential::{
|
||||
import_credential, CommonClientImportCredentialArgs,
|
||||
import_credential, CommonClientImportTicketBookArgs,
|
||||
};
|
||||
|
||||
pub(crate) async fn execute(args: CommonClientImportCredentialArgs) -> Result<(), ClientError> {
|
||||
pub(crate) async fn execute(args: CommonClientImportTicketBookArgs) -> Result<(), ClientError> {
|
||||
import_credential::<CliNativeClient, _>(args).await?;
|
||||
println!("successfully imported credential!");
|
||||
Ok(())
|
||||
@@ -0,0 +1,16 @@
|
||||
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::commands::CliNativeClient;
|
||||
use crate::error::ClientError;
|
||||
use nym_client_core::cli_helpers::client_import_expiration_date_signatures::{
|
||||
import_expiration_date_signatures, CommonClientImportExpirationDateSignaturesArgs,
|
||||
};
|
||||
|
||||
pub(crate) async fn execute(
|
||||
args: CommonClientImportExpirationDateSignaturesArgs,
|
||||
) -> Result<(), ClientError> {
|
||||
import_expiration_date_signatures::<CliNativeClient, _>(args).await?;
|
||||
println!("successfully imported expiration date signatures!");
|
||||
Ok(())
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::commands::CliNativeClient;
|
||||
use crate::error::ClientError;
|
||||
use nym_client_core::cli_helpers::client_import_master_verification_key::{
|
||||
import_master_verification_key, CommonClientImportMasterVerificationKeyArgs,
|
||||
};
|
||||
|
||||
pub(crate) async fn execute(
|
||||
args: CommonClientImportMasterVerificationKeyArgs,
|
||||
) -> Result<(), ClientError> {
|
||||
import_master_verification_key::<CliNativeClient, _>(args).await?;
|
||||
println!("successfully imported master verification key!");
|
||||
Ok(())
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use clap::{Args, Subcommand};
|
||||
use nym_client_core::cli_helpers::client_import_coin_index_signatures::CommonClientImportCoinIndexSignaturesArgs;
|
||||
use nym_client_core::cli_helpers::client_import_credential::CommonClientImportTicketBookArgs;
|
||||
use nym_client_core::cli_helpers::client_import_expiration_date_signatures::CommonClientImportExpirationDateSignaturesArgs;
|
||||
use nym_client_core::cli_helpers::client_import_master_verification_key::CommonClientImportMasterVerificationKeyArgs;
|
||||
use std::error::Error;
|
||||
|
||||
pub(crate) mod import_coin_index_signatures;
|
||||
pub(crate) mod import_credential;
|
||||
pub(crate) mod import_expiration_date_signatures;
|
||||
pub(crate) mod import_master_verification_key;
|
||||
pub(crate) mod show_ticketbooks;
|
||||
|
||||
#[derive(Args)]
|
||||
#[clap(args_conflicts_with_subcommands = true, subcommand_required = true)]
|
||||
pub struct Ecash {
|
||||
#[clap(subcommand)]
|
||||
pub command: EcashCommands,
|
||||
}
|
||||
|
||||
impl Ecash {
|
||||
pub async fn execute(self) -> Result<(), Box<dyn Error + Send + Sync>> {
|
||||
match self.command {
|
||||
EcashCommands::ShowTicketBooks(args) => show_ticketbooks::execute(args).await?,
|
||||
EcashCommands::ImportTicketBook(args) => import_credential::execute(args).await?,
|
||||
EcashCommands::ImportCoinIndexSignatures(args) => {
|
||||
import_coin_index_signatures::execute(args).await?
|
||||
}
|
||||
EcashCommands::ImportExpirationDateSignatures(args) => {
|
||||
import_expiration_date_signatures::execute(args).await?
|
||||
}
|
||||
EcashCommands::ImportMasterVerificationKey(args) => {
|
||||
import_master_verification_key::execute(args).await?
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Subcommand)]
|
||||
pub enum EcashCommands {
|
||||
/// Display information associated with the imported ticketbooks,
|
||||
ShowTicketBooks(show_ticketbooks::Args),
|
||||
|
||||
/// Import a pre-generated ticketbook
|
||||
ImportTicketBook(CommonClientImportTicketBookArgs),
|
||||
|
||||
/// Import coin index signatures needed for ticketbooks
|
||||
ImportCoinIndexSignatures(CommonClientImportCoinIndexSignaturesArgs),
|
||||
|
||||
/// Import expiration date signatures needed for ticketbooks
|
||||
ImportExpirationDateSignatures(CommonClientImportExpirationDateSignaturesArgs),
|
||||
|
||||
/// Import master verification key needed for ticketbooks
|
||||
ImportMasterVerificationKey(CommonClientImportMasterVerificationKeyArgs),
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
// 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(())
|
||||
}
|
||||
@@ -6,13 +6,13 @@ use crate::client::config::old_config_v1_1_20::ConfigV1_1_20;
|
||||
use crate::client::config::old_config_v1_1_20_2::ConfigV1_1_20_2;
|
||||
use crate::client::config::old_config_v1_1_33::ConfigV1_1_33;
|
||||
use crate::client::config::{BaseClientConfig, Config};
|
||||
use crate::commands::ecash::Ecash;
|
||||
use crate::error::ClientError;
|
||||
use clap::CommandFactory;
|
||||
use clap::{Parser, Subcommand};
|
||||
use log::{error, info};
|
||||
use nym_bin_common::bin_info;
|
||||
use nym_bin_common::completions::{fig_generate, ArgShell};
|
||||
use nym_client_core::cli_helpers::client_import_credential::CommonClientImportCredentialArgs;
|
||||
use nym_client_core::cli_helpers::CliClient;
|
||||
use nym_client_core::client::base_client::storage::migration_helpers::v1_1_33;
|
||||
use nym_config::OptionalSet;
|
||||
@@ -22,7 +22,7 @@ use std::sync::OnceLock;
|
||||
|
||||
mod add_gateway;
|
||||
pub(crate) mod build_info;
|
||||
pub(crate) mod import_credential;
|
||||
pub(crate) mod ecash;
|
||||
pub(crate) mod init;
|
||||
mod list_gateways;
|
||||
pub(crate) mod run;
|
||||
@@ -72,8 +72,8 @@ pub(crate) enum Commands {
|
||||
/// Run the Nym client with provided configuration client optionally overriding set parameters
|
||||
Run(run::Run),
|
||||
|
||||
/// Import a pre-generated credential
|
||||
ImportCredential(CommonClientImportCredentialArgs),
|
||||
/// Ecash-related functionalities
|
||||
Ecash(Ecash),
|
||||
|
||||
/// List all registered with gateways
|
||||
ListGateways(list_gateways::Args),
|
||||
@@ -112,7 +112,7 @@ pub(crate) async fn execute(args: Cli) -> Result<(), Box<dyn Error + Send + Sync
|
||||
match args.command {
|
||||
Commands::Init(m) => init::execute(m).await?,
|
||||
Commands::Run(m) => run::execute(m).await?,
|
||||
Commands::ImportCredential(m) => import_credential::execute(m).await?,
|
||||
Commands::Ecash(ecash) => ecash.execute().await?,
|
||||
Commands::ListGateways(args) => list_gateways::execute(args).await?,
|
||||
Commands::AddGateway(args) => add_gateway::execute(args).await?,
|
||||
Commands::SwitchGateway(args) => switch_gateway::execute(args).await?,
|
||||
|
||||
@@ -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.mark_as_success();
|
||||
task_client.disarm();
|
||||
|
||||
let ws_stream = match accept_async(socket).await {
|
||||
Ok(ws_stream) => ws_stream,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "nym-socks5-client"
|
||||
version = "1.1.36"
|
||||
version = "1.1.40"
|
||||
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,7 +11,9 @@ 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 }
|
||||
@@ -22,13 +24,21 @@ url = { workspace = true }
|
||||
zeroize = { workspace = true }
|
||||
|
||||
# internal
|
||||
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-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-config = { path = "../../common/config" }
|
||||
nym-credential-storage = { path = "../../common/credential-storage" }
|
||||
nym-credentials = { path = "../../common/credentials" }
|
||||
nym-crypto = { path = "../../common/crypto" }
|
||||
nym-gateway-requests = { path = "../../gateway/gateway-requests" }
|
||||
nym-gateway-requests = { path = "../../common/gateway-requests" }
|
||||
nym-id = { path = "../../common/nym-id" }
|
||||
nym-network-defaults = { path = "../../common/network-defaults" }
|
||||
nym-ordered-buffer = { path = "../../common/socks5/ordered-buffer" }
|
||||
@@ -36,7 +46,9 @@ 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-validator-client = { path = "../../common/client-libs/validator-client", features = [
|
||||
"http-client",
|
||||
] }
|
||||
|
||||
[features]
|
||||
default = []
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::commands::CliSocks5Client;
|
||||
use crate::error::Socks5ClientError;
|
||||
use nym_client_core::cli_helpers::client_import_coin_index_signatures::{
|
||||
import_coin_index_signatures, CommonClientImportCoinIndexSignaturesArgs,
|
||||
};
|
||||
|
||||
pub(crate) async fn execute(
|
||||
args: CommonClientImportCoinIndexSignaturesArgs,
|
||||
) -> Result<(), Socks5ClientError> {
|
||||
import_coin_index_signatures::<CliSocks5Client, _>(args).await?;
|
||||
println!("successfully imported coin index signatures!");
|
||||
Ok(())
|
||||
}
|
||||
+2
-4
@@ -4,12 +4,10 @@
|
||||
use crate::commands::CliSocks5Client;
|
||||
use crate::error::Socks5ClientError;
|
||||
use nym_client_core::cli_helpers::client_import_credential::{
|
||||
import_credential, CommonClientImportCredentialArgs,
|
||||
import_credential, CommonClientImportTicketBookArgs,
|
||||
};
|
||||
|
||||
pub(crate) async fn execute(
|
||||
args: CommonClientImportCredentialArgs,
|
||||
) -> Result<(), Socks5ClientError> {
|
||||
pub async fn execute(args: CommonClientImportTicketBookArgs) -> Result<(), Socks5ClientError> {
|
||||
import_credential::<CliSocks5Client, _>(args).await?;
|
||||
println!("successfully imported credential!");
|
||||
Ok(())
|
||||
@@ -0,0 +1,16 @@
|
||||
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::commands::CliSocks5Client;
|
||||
use crate::error::Socks5ClientError;
|
||||
use nym_client_core::cli_helpers::client_import_expiration_date_signatures::{
|
||||
import_expiration_date_signatures, CommonClientImportExpirationDateSignaturesArgs,
|
||||
};
|
||||
|
||||
pub(crate) async fn execute(
|
||||
args: CommonClientImportExpirationDateSignaturesArgs,
|
||||
) -> Result<(), Socks5ClientError> {
|
||||
import_expiration_date_signatures::<CliSocks5Client, _>(args).await?;
|
||||
println!("successfully imported expiration date signatures!");
|
||||
Ok(())
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::commands::CliSocks5Client;
|
||||
use crate::error::Socks5ClientError;
|
||||
use nym_client_core::cli_helpers::client_import_master_verification_key::{
|
||||
import_master_verification_key, CommonClientImportMasterVerificationKeyArgs,
|
||||
};
|
||||
|
||||
pub(crate) async fn execute(
|
||||
args: CommonClientImportMasterVerificationKeyArgs,
|
||||
) -> Result<(), Socks5ClientError> {
|
||||
import_master_verification_key::<CliSocks5Client, _>(args).await?;
|
||||
println!("successfully imported master verification key!");
|
||||
Ok(())
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use clap::{Args, Subcommand};
|
||||
use nym_client_core::cli_helpers::client_import_coin_index_signatures::CommonClientImportCoinIndexSignaturesArgs;
|
||||
use nym_client_core::cli_helpers::client_import_credential::CommonClientImportTicketBookArgs;
|
||||
use nym_client_core::cli_helpers::client_import_expiration_date_signatures::CommonClientImportExpirationDateSignaturesArgs;
|
||||
use nym_client_core::cli_helpers::client_import_master_verification_key::CommonClientImportMasterVerificationKeyArgs;
|
||||
use std::error::Error;
|
||||
|
||||
pub(crate) mod import_coin_index_signatures;
|
||||
pub(crate) mod import_credential;
|
||||
pub(crate) mod import_expiration_date_signatures;
|
||||
pub(crate) mod import_master_verification_key;
|
||||
pub(crate) mod show_ticketbooks;
|
||||
|
||||
#[derive(Args)]
|
||||
#[clap(args_conflicts_with_subcommands = true, subcommand_required = true)]
|
||||
pub struct Ecash {
|
||||
#[clap(subcommand)]
|
||||
pub command: EcashCommands,
|
||||
}
|
||||
|
||||
impl Ecash {
|
||||
pub async fn execute(self) -> Result<(), Box<dyn Error + Send + Sync>> {
|
||||
match self.command {
|
||||
EcashCommands::ShowTicketBooks(args) => show_ticketbooks::execute(args).await?,
|
||||
EcashCommands::ImportTicketBook(args) => import_credential::execute(args).await?,
|
||||
EcashCommands::ImportCoinIndexSignatures(args) => {
|
||||
import_coin_index_signatures::execute(args).await?
|
||||
}
|
||||
EcashCommands::ImportExpirationDateSignatures(args) => {
|
||||
import_expiration_date_signatures::execute(args).await?
|
||||
}
|
||||
EcashCommands::ImportMasterVerificationKey(args) => {
|
||||
import_master_verification_key::execute(args).await?
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Subcommand)]
|
||||
pub enum EcashCommands {
|
||||
/// Display information associated with the imported ticketbooks,
|
||||
ShowTicketBooks(show_ticketbooks::Args),
|
||||
|
||||
/// Import a pre-generated ticketbook
|
||||
ImportTicketBook(CommonClientImportTicketBookArgs),
|
||||
|
||||
/// Import coin index signatures needed for ticketbooks
|
||||
ImportCoinIndexSignatures(CommonClientImportCoinIndexSignaturesArgs),
|
||||
|
||||
/// Import expiration date signatures needed for ticketbooks
|
||||
ImportExpirationDateSignatures(CommonClientImportExpirationDateSignaturesArgs),
|
||||
|
||||
/// Import master verification key needed for ticketbooks
|
||||
ImportMasterVerificationKey(CommonClientImportMasterVerificationKeyArgs),
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
// 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 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 async fn execute(args: Args) -> Result<(), Socks5ClientError> {
|
||||
let output = args.output;
|
||||
let res = show_ticketbooks::<CliSocks5Client, _>(args).await?;
|
||||
|
||||
println!("{}", output.format(&res));
|
||||
Ok(())
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::commands::ecash::Ecash;
|
||||
use crate::config::old_config_v1_1_13::OldConfigV1_1_13;
|
||||
use crate::config::old_config_v1_1_20::ConfigV1_1_20;
|
||||
use crate::config::old_config_v1_1_20_2::ConfigV1_1_20_2;
|
||||
@@ -13,7 +14,6 @@ use clap::{Parser, Subcommand};
|
||||
use log::{error, info};
|
||||
use nym_bin_common::bin_info;
|
||||
use nym_bin_common::completions::{fig_generate, ArgShell};
|
||||
use nym_client_core::cli_helpers::client_import_credential::CommonClientImportCredentialArgs;
|
||||
use nym_client_core::cli_helpers::CliClient;
|
||||
use nym_client_core::client::base_client::storage::migration_helpers::v1_1_33;
|
||||
use nym_client_core::client::topology_control::geo_aware_provider::CountryGroup;
|
||||
@@ -26,7 +26,7 @@ use std::sync::OnceLock;
|
||||
|
||||
mod add_gateway;
|
||||
pub(crate) mod build_info;
|
||||
mod import_credential;
|
||||
pub mod ecash;
|
||||
pub mod init;
|
||||
mod list_gateways;
|
||||
pub(crate) mod run;
|
||||
@@ -76,8 +76,8 @@ pub(crate) enum Commands {
|
||||
/// Run the Nym client with provided configuration client optionally overriding set parameters
|
||||
Run(run::Run),
|
||||
|
||||
/// Import a pre-generated credential
|
||||
ImportCredential(CommonClientImportCredentialArgs),
|
||||
/// Ecash-related functionalities
|
||||
Ecash(Ecash),
|
||||
|
||||
/// List all registered with gateways
|
||||
ListGateways(list_gateways::Args),
|
||||
@@ -119,7 +119,7 @@ pub(crate) async fn execute(args: Cli) -> Result<(), Box<dyn Error + Send + Sync
|
||||
match args.command {
|
||||
Commands::Init(m) => init::execute(m).await?,
|
||||
Commands::Run(m) => run::execute(m).await?,
|
||||
Commands::ImportCredential(m) => import_credential::execute(m).await?,
|
||||
Commands::Ecash(ecash) => ecash.execute().await?,
|
||||
Commands::ListGateways(args) => list_gateways::execute(args).await?,
|
||||
Commands::AddGateway(args) => add_gateway::execute(args).await?,
|
||||
Commands::SwitchGateway(args) => switch_gateway::execute(args).await?,
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
[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" }
|
||||
@@ -0,0 +1,13 @@
|
||||
// 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()
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
pub mod request;
|
||||
pub mod response;
|
||||
|
||||
const VERSION: u8 = 1;
|
||||
@@ -0,0 +1,84 @@
|
||||
// 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),
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
// 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>,
|
||||
}
|
||||
@@ -14,13 +14,14 @@ thiserror = { workspace = true }
|
||||
url = { workspace = true }
|
||||
zeroize = { workspace = true }
|
||||
|
||||
nym-coconut = { path = "../nymcoconut" }
|
||||
nym-ecash-time = { path = "../ecash-time" }
|
||||
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"
|
||||
|
||||
@@ -1,87 +1,132 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2023-2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::error::BandwidthControllerError;
|
||||
use nym_credential_storage::models::StorableIssuedCredential;
|
||||
use crate::utils::{
|
||||
get_aggregate_verification_key, get_coin_index_signatures, get_expiration_date_signatures,
|
||||
};
|
||||
use log::info;
|
||||
use nym_credential_storage::storage::Storage;
|
||||
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 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 rand::rngs::OsRng;
|
||||
use state::State;
|
||||
use zeroize::Zeroizing;
|
||||
|
||||
pub mod state;
|
||||
|
||||
pub async fn deposit<C>(client: &C, amount: Coin) -> Result<State, BandwidthControllerError>
|
||||
pub async fn make_deposit<C>(
|
||||
client: &C,
|
||||
client_id: &[u8],
|
||||
expiration: Option<Date>,
|
||||
ticketbook_type: TicketType,
|
||||
) -> Result<IssuanceTicketBook, BandwidthControllerError>
|
||||
where
|
||||
C: CoconutBandwidthSigningClient + Sync,
|
||||
C: EcashSigningClient + EcashQueryClient + Sync,
|
||||
{
|
||||
let mut rng = OsRng;
|
||||
let signing_key = identity::PrivateKey::new(&mut rng);
|
||||
let encryption_key = encryption::PrivateKey::new(&mut rng);
|
||||
let expiration = expiration.unwrap_or_else(ecash_default_expiration_date);
|
||||
|
||||
let tx_hash = client
|
||||
.deposit(
|
||||
amount.clone(),
|
||||
CredentialType::Voucher.to_string(),
|
||||
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(
|
||||
signing_key.public_key().to_base58_string(),
|
||||
encryption_key.public_key().to_base58_string(),
|
||||
deposit_amount.into(),
|
||||
None,
|
||||
)
|
||||
.await?
|
||||
.transaction_hash;
|
||||
.await?;
|
||||
|
||||
let voucher =
|
||||
IssuanceBandwidthCredential::new_voucher(amount, tx_hash, signing_key, encryption_key);
|
||||
let deposit_id = result.parse_singleton_u32_contract_data()?;
|
||||
|
||||
let state = State { voucher };
|
||||
info!("our ticketbook deposit has been stored under id {deposit_id}");
|
||||
|
||||
Ok(state)
|
||||
Ok(IssuanceTicketBook::new_with_expiration(
|
||||
deposit_id,
|
||||
client_id,
|
||||
signing_key,
|
||||
ticketbook_type,
|
||||
expiration,
|
||||
))
|
||||
}
|
||||
|
||||
pub async fn get_bandwidth_voucher<C, St>(
|
||||
state: &State,
|
||||
pub async fn query_and_persist_required_global_data<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 master verification key");
|
||||
// this will also persist the key in the storage if was not there already
|
||||
get_aggregate_verification_key(storage, epoch_id, apis.clone()).await?;
|
||||
|
||||
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,
|
||||
client: &C,
|
||||
storage: &St,
|
||||
) -> Result<(), BandwidthControllerError>
|
||||
apis: Option<Vec<EcashApiClient>>,
|
||||
) -> Result<IssuedTicketBook, 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 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!"),
|
||||
let apis = match apis {
|
||||
Some(apis) => apis,
|
||||
None => all_ecash_api_clients(client, epoch_id).await?,
|
||||
};
|
||||
|
||||
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_credential(storable)
|
||||
.insert_issued_ticketbook(&issued)
|
||||
.await
|
||||
.map_err(|err| BandwidthControllerError::CredentialStorageError(Box::new(err)))
|
||||
.map_err(|err| BandwidthControllerError::CredentialStorageError(Box::new(err)))?;
|
||||
Ok(issued)
|
||||
}
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
// 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 }
|
||||
}
|
||||
}
|
||||
@@ -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::CoconutApiError;
|
||||
use nym_validator_client::coconut::EcashApiError;
|
||||
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] CoconutApiError),
|
||||
CoconutApiError(#[from] EcashApiError),
|
||||
|
||||
#[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("Coconut error - {0}")]
|
||||
CoconutError(#[from] CoconutError),
|
||||
#[error("Ecash error - {0}")]
|
||||
EcashError(#[from] CompactEcashError),
|
||||
|
||||
#[error("Validator client error - {0}")]
|
||||
ValidatorError(#[from] ValidatorClientError),
|
||||
@@ -51,4 +51,15 @@ 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))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
// 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,
|
||||
}
|
||||
@@ -1,21 +1,32 @@
|
||||
// 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::stored_credential_to_issued_bandwidth;
|
||||
use log::{debug, error, warn};
|
||||
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 nym_credential_storage::storage::Storage;
|
||||
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_credentials::ecash::bandwidth::CredentialSpendingData;
|
||||
use nym_credentials_interface::{
|
||||
AnnotatedCoinIndexSignature, AnnotatedExpirationDateSignature, VerificationKeyAuth,
|
||||
};
|
||||
use nym_ecash_time::Date;
|
||||
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)]
|
||||
@@ -32,13 +43,20 @@ pub struct PreparedCredential {
|
||||
/// could use correct verification key for validation.
|
||||
pub epoch_id: EpochId,
|
||||
|
||||
/// The database id of the stored credential.
|
||||
pub credential_id: i64,
|
||||
/// Auxiliary metadata associated with the withdrawn credential
|
||||
pub metadata: PreparedCredentialMetadata,
|
||||
}
|
||||
|
||||
pub struct RetrievedCredential {
|
||||
pub credential: IssuedBandwidthCredential,
|
||||
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,
|
||||
}
|
||||
|
||||
impl<C, St: Storage> BandwidthController<C, St> {
|
||||
@@ -47,111 +65,157 @@ impl<C, St: Storage> BandwidthController<C, St> {
|
||||
}
|
||||
|
||||
/// Tries to retrieve one of the stored, unused credentials that hasn't yet expired.
|
||||
/// It marks any retrieved intermediate credentials as expired.
|
||||
pub async fn get_next_usable_credential(
|
||||
pub async fn get_next_usable_ticketbook(
|
||||
&self,
|
||||
gateway_id: &str,
|
||||
) -> Result<RetrievedCredential, BandwidthControllerError>
|
||||
tickets: u32,
|
||||
) -> Result<RetrievedTicketbook, BandwidthControllerError>
|
||||
where
|
||||
<St as Storage>::StorageError: Send + Sync + 'static,
|
||||
{
|
||||
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;
|
||||
let Some(ticketbook) = self
|
||||
.storage
|
||||
.get_next_unspent_usable_ticketbook(tickets)
|
||||
.await
|
||||
.map_err(BandwidthControllerError::credential_storage_error)?
|
||||
else {
|
||||
return Err(BandwidthControllerError::NoCredentialsAvailable);
|
||||
};
|
||||
|
||||
// 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,
|
||||
});
|
||||
}
|
||||
Ok(ticketbook)
|
||||
}
|
||||
|
||||
pub fn storage(&self) -> &St {
|
||||
&self.storage
|
||||
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)
|
||||
}
|
||||
|
||||
async fn get_aggregate_verification_key(
|
||||
&self,
|
||||
epoch_id: EpochId,
|
||||
) -> Result<VerificationKey, BandwidthControllerError>
|
||||
apis: &mut ApiClientsWrapper,
|
||||
) -> Result<VerificationKeyAuth, BandwidthControllerError>
|
||||
where
|
||||
C: DkgQueryClient + Sync + Send,
|
||||
<St as Storage>::StorageError: Send + Sync + 'static,
|
||||
{
|
||||
let coconut_api_clients = all_coconut_api_clients(&self.client, epoch_id).await?;
|
||||
Ok(obtain_aggregate_verification_key(&coconut_api_clients)?)
|
||||
let ecash_apis = apis.get_or_init(epoch_id, &self.client).await?;
|
||||
get_aggregate_verification_key(&self.storage, epoch_id, ecash_apis).await
|
||||
}
|
||||
|
||||
pub async fn prepare_bandwidth_credential(
|
||||
async fn get_coin_index_signatures(
|
||||
&self,
|
||||
gateway_id: &str,
|
||||
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 = retrieved_ticketbook
|
||||
.ticketbook
|
||||
.generate_pay_info(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,
|
||||
) -> Result<PreparedCredential, BandwidthControllerError>
|
||||
where
|
||||
C: DkgQueryClient + Sync + Send,
|
||||
<St as Storage>::StorageError: Send + Sync + 'static,
|
||||
{
|
||||
let retrieved_credential = self.get_next_usable_credential(gateway_id).await?;
|
||||
let retrieved_ticketbook = self.get_next_usable_ticketbook(tickets_to_spend).await?;
|
||||
|
||||
let epoch_id = retrieved_credential.credential.epoch_id();
|
||||
let credential_id = retrieved_credential.credential_id;
|
||||
let ticketbook_id = retrieved_ticketbook.ticketbook_id;
|
||||
let epoch_id = retrieved_ticketbook.ticketbook.epoch_id();
|
||||
|
||||
let verification_key = self.get_aggregate_verification_key(epoch_id).await?;
|
||||
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 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)
|
||||
match self
|
||||
.prepare_ecash_ticket_inner(provider_pk, tickets_to_spend, retrieved_ticketbook)
|
||||
.await
|
||||
.map_err(|err| BandwidthControllerError::CredentialStorageError(Box::new(err)))
|
||||
{
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,21 +2,200 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::error::BandwidthControllerError;
|
||||
use nym_credential_storage::models::StoredIssuedCredential;
|
||||
use nym_credentials::coconut::bandwidth::issued::CURRENT_SERIALIZATION_REVISION;
|
||||
use nym_credentials::coconut::bandwidth::IssuedBandwidthCredential;
|
||||
use log::warn;
|
||||
use nym_credential_storage::storage::Storage;
|
||||
use nym_credentials::ecash::bandwidth::serialiser::keys::EpochVerificationKey;
|
||||
use nym_credentials::ecash::bandwidth::serialiser::signatures::{
|
||||
AggregatedCoinIndicesSignatures, AggregatedExpirationDateSignatures,
|
||||
};
|
||||
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;
|
||||
|
||||
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,
|
||||
},
|
||||
);
|
||||
// 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)
|
||||
}
|
||||
|
||||
Ok(IssuedBandwidthCredential::unpack_v1(&cred.credential_data)?)
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
let full = EpochVerificationKey {
|
||||
epoch_id,
|
||||
key: master_vk,
|
||||
};
|
||||
|
||||
// store the retrieved key
|
||||
storage
|
||||
.insert_master_verification_key(&full)
|
||||
.await
|
||||
.map_err(BandwidthControllerError::credential_storage_error)?;
|
||||
|
||||
Ok(full.key)
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
let aggregated = AggregatedCoinIndicesSignatures {
|
||||
epoch_id,
|
||||
signatures: index_sigs,
|
||||
};
|
||||
|
||||
// store the retrieved key
|
||||
storage
|
||||
.insert_coin_index_signatures(&aggregated)
|
||||
.await
|
||||
.map_err(BandwidthControllerError::credential_storage_error)?;
|
||||
|
||||
Ok(aggregated.signatures)
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
let aggregated = AggregatedExpirationDateSignatures {
|
||||
epoch_id,
|
||||
expiration_date,
|
||||
signatures: expiration_sigs,
|
||||
};
|
||||
|
||||
// store the retrieved key
|
||||
storage
|
||||
.insert_expiration_date_signatures(&aggregated)
|
||||
.await
|
||||
.map_err(BandwidthControllerError::credential_storage_error)?;
|
||||
|
||||
Ok(aggregated.signatures)
|
||||
}
|
||||
|
||||
@@ -14,10 +14,12 @@ base64 = { workspace = true }
|
||||
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 }
|
||||
@@ -37,7 +39,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/gateway-requests" }
|
||||
nym-gateway-requests = { path = "../gateway-requests" }
|
||||
nym-metrics = { path = "../nym-metrics" }
|
||||
nym-nonexhaustive-delayqueue = { path = "../nonexhaustive-delayqueue" }
|
||||
nym-sphinx = { path = "../nymsphinx" }
|
||||
@@ -45,11 +47,15 @@ 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]
|
||||
@@ -65,7 +71,7 @@ features = ["tokio"]
|
||||
###
|
||||
|
||||
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.tokio-stream]
|
||||
version = "0.1.11"
|
||||
version = "0.1.16"
|
||||
features = ["time"]
|
||||
|
||||
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.tokio]
|
||||
@@ -96,7 +102,7 @@ workspace = true
|
||||
features = ["tokio"]
|
||||
|
||||
[target."cfg(target_arch = \"wasm32\")".dependencies.gloo-timers]
|
||||
version = "0.2.4"
|
||||
version = "0.3.0"
|
||||
features = ["futures"]
|
||||
|
||||
[target."cfg(target_arch = \"wasm32\")".dependencies.wasm-utils]
|
||||
@@ -112,7 +118,8 @@ tempfile = { workspace = true }
|
||||
|
||||
[features]
|
||||
default = []
|
||||
cli = ["clap"]
|
||||
cli = ["clap", "comfy-table"]
|
||||
fs-credentials-storage = ["nym-credential-storage/persistent-storage"]
|
||||
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"]
|
||||
|
||||
@@ -18,7 +18,7 @@ url.workspace = true
|
||||
zeroize = { workspace = true, features = ["zeroize_derive"] }
|
||||
|
||||
nym-crypto = { path = "../../crypto", features = ["asymmetric"] }
|
||||
nym-gateway-requests = { path = "../../../gateway/gateway-requests" }
|
||||
nym-gateway-requests = { path = "../../gateway-requests" }
|
||||
|
||||
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.sqlx]
|
||||
workspace = true
|
||||
@@ -27,7 +27,12 @@ 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"]
|
||||
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* 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,14 +155,13 @@ 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, wg_tun_address)
|
||||
VALUES (?, ?, ?, ?, ?)
|
||||
INSERT INTO remote_gateway_details(gateway_id_bs58, derived_aes128_ctr_blake3_hmac_keys_bs58, gateway_owner_address, gateway_listener)
|
||||
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,14 +67,12 @@ 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,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -172,7 +170,6 @@ 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 {
|
||||
@@ -217,24 +214,11 @@ 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,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -248,7 +232,6 @@ 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()),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -264,8 +247,6 @@ pub struct RemoteGatewayDetails {
|
||||
pub gateway_owner_address: Option<AccountId>,
|
||||
|
||||
pub gateway_listener: Url,
|
||||
|
||||
pub wg_tun_address: Option<Url>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
|
||||
@@ -133,7 +133,6 @@ where
|
||||
let gateway_setup = GatewaySetup::New {
|
||||
specification: selection_spec,
|
||||
available_gateways,
|
||||
wg_tun_address: None,
|
||||
};
|
||||
|
||||
let init_details =
|
||||
@@ -162,6 +161,5 @@ 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(),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::cli_helpers::{CliClient, CliClientConfig};
|
||||
use std::fs;
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[cfg(feature = "cli")]
|
||||
fn parse_encoded_signatures_data(raw: &str) -> bs58::decode::Result<Vec<u8>> {
|
||||
bs58::decode(raw).into_vec()
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "cli", derive(clap::Args))]
|
||||
#[cfg_attr(feature = "cli",
|
||||
clap(
|
||||
group(clap::ArgGroup::new("sig_data").required(true)),
|
||||
))
|
||||
]
|
||||
pub struct CommonClientImportCoinIndexSignaturesArgs {
|
||||
/// Id of client that is going to import the signatures
|
||||
#[cfg_attr(feature = "cli", clap(long))]
|
||||
pub id: String,
|
||||
|
||||
/// Config file of the client that is supposed to use the signatures.
|
||||
#[cfg_attr(feature = "cli", clap(long))]
|
||||
pub(crate) client_config: PathBuf,
|
||||
|
||||
/// Explicitly provide the encoded signatures data (as base58)
|
||||
#[cfg_attr(feature = "cli", clap(long, group = "sig_data", value_parser = parse_encoded_signatures_data))]
|
||||
pub(crate) signatures_data: Option<Vec<u8>>,
|
||||
|
||||
/// Specifies the path to file containing binary signatures data
|
||||
#[cfg_attr(feature = "cli", clap(long, group = "sig_data"))]
|
||||
pub(crate) signatures_path: Option<PathBuf>,
|
||||
|
||||
// currently hidden as there exists only a single serialization standard
|
||||
#[cfg_attr(feature = "cli", clap(long, hide = true))]
|
||||
pub(crate) version: Option<u8>,
|
||||
}
|
||||
|
||||
pub async fn import_coin_index_signatures<C, A>(args: A) -> Result<(), C::Error>
|
||||
where
|
||||
A: Into<CommonClientImportCoinIndexSignaturesArgs>,
|
||||
C: CliClient,
|
||||
C::Error: From<std::io::Error> + From<nym_id::NymIdError>,
|
||||
{
|
||||
let common_args = args.into();
|
||||
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 version = common_args.version;
|
||||
let raw_key = match common_args.signatures_data {
|
||||
Some(data) => data,
|
||||
None => {
|
||||
// SAFETY: one of those arguments must have been set
|
||||
fs::read(common_args.signatures_path.unwrap())?
|
||||
}
|
||||
};
|
||||
|
||||
nym_id::import_coin_index_signatures(credentials_store, raw_key, version).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -11,9 +11,14 @@ fn parse_encoded_credential_data(raw: &str) -> bs58::decode::Result<Vec<u8>> {
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "cli", derive(clap::Args))]
|
||||
#[cfg_attr(feature = "cli", clap(group(clap::ArgGroup::new("cred_data").required(true))))]
|
||||
#[cfg_attr(feature = "cli",
|
||||
clap(
|
||||
group(clap::ArgGroup::new("cred_data").required(true)),
|
||||
group(clap::ArgGroup::new("type").required(true)),
|
||||
))
|
||||
]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct CommonClientImportCredentialArgs {
|
||||
pub struct CommonClientImportTicketBookArgs {
|
||||
/// Id of client that is going to import the credential
|
||||
#[cfg_attr(feature = "cli", clap(long))]
|
||||
pub id: String,
|
||||
@@ -26,6 +31,15 @@ pub struct CommonClientImportCredentialArgs {
|
||||
#[cfg_attr(feature = "cli", clap(long, group = "cred_data"))]
|
||||
pub(crate) credential_path: Option<PathBuf>,
|
||||
|
||||
/// Specifies whether we're attempting to import a standalone ticketbook (i.e. serialised `IssuedTicketBook`)
|
||||
#[cfg_attr(feature = "cli", clap(long, group = "type"))]
|
||||
pub(crate) standalone: bool,
|
||||
|
||||
/// Specifies whether we're attempting to import full ticketboot
|
||||
/// (i.e. one that **might** contain required global signatures; that is serialised `ImportableTicketBook`)
|
||||
#[cfg_attr(feature = "cli", clap(long, group = "type"))]
|
||||
pub(crate) full: bool,
|
||||
|
||||
// currently hidden as there exists only a single serialization standard
|
||||
#[cfg_attr(feature = "cli", clap(long, hide = true))]
|
||||
pub(crate) version: Option<u8>,
|
||||
@@ -33,7 +47,7 @@ pub struct CommonClientImportCredentialArgs {
|
||||
|
||||
pub async fn import_credential<C, A>(args: A) -> Result<(), C::Error>
|
||||
where
|
||||
A: Into<CommonClientImportCredentialArgs>,
|
||||
A: Into<CommonClientImportTicketBookArgs>,
|
||||
C: CliClient,
|
||||
C::Error: From<std::io::Error> + From<nym_id::NymIdError>,
|
||||
{
|
||||
@@ -54,6 +68,19 @@ where
|
||||
}
|
||||
};
|
||||
|
||||
nym_id::import_credential(credentials_store, raw_credential, common_args.version).await?;
|
||||
if common_args.standalone {
|
||||
nym_id::import_standalone_ticketbook(
|
||||
credentials_store,
|
||||
raw_credential,
|
||||
common_args.version,
|
||||
)
|
||||
.await?;
|
||||
} else {
|
||||
// sanity check; clap should have ensured it
|
||||
assert!(common_args.full);
|
||||
nym_id::import_full_ticketbook(credentials_store, raw_credential, common_args.version)
|
||||
.await?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::cli_helpers::{CliClient, CliClientConfig};
|
||||
use std::fs;
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[cfg(feature = "cli")]
|
||||
fn parse_encoded_signatures_data(raw: &str) -> bs58::decode::Result<Vec<u8>> {
|
||||
bs58::decode(raw).into_vec()
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "cli", derive(clap::Args))]
|
||||
#[cfg_attr(feature = "cli",
|
||||
clap(
|
||||
group(clap::ArgGroup::new("sig_data").required(true)),
|
||||
))
|
||||
]
|
||||
pub struct CommonClientImportExpirationDateSignaturesArgs {
|
||||
/// Id of client that is going to import the signatures
|
||||
#[cfg_attr(feature = "cli", clap(long))]
|
||||
pub id: String,
|
||||
|
||||
/// Config file of the client that is supposed to use the signatures.
|
||||
#[cfg_attr(feature = "cli", clap(long))]
|
||||
pub(crate) client_config: PathBuf,
|
||||
|
||||
/// Explicitly provide the encoded signatures data (as base58)
|
||||
#[cfg_attr(feature = "cli", clap(long, group = "sig_data", value_parser = parse_encoded_signatures_data))]
|
||||
pub(crate) signatures_data: Option<Vec<u8>>,
|
||||
|
||||
/// Specifies the path to file containing binary signatures data
|
||||
#[cfg_attr(feature = "cli", clap(long, group = "sig_data"))]
|
||||
pub(crate) signatures_path: Option<PathBuf>,
|
||||
|
||||
// currently hidden as there exists only a single serialization standard
|
||||
#[cfg_attr(feature = "cli", clap(long, hide = true))]
|
||||
pub(crate) version: Option<u8>,
|
||||
}
|
||||
|
||||
pub async fn import_expiration_date_signatures<C, A>(args: A) -> Result<(), C::Error>
|
||||
where
|
||||
A: Into<CommonClientImportExpirationDateSignaturesArgs>,
|
||||
C: CliClient,
|
||||
C::Error: From<std::io::Error> + From<nym_id::NymIdError>,
|
||||
{
|
||||
let common_args = args.into();
|
||||
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 version = common_args.version;
|
||||
let raw_key = match common_args.signatures_data {
|
||||
Some(data) => data,
|
||||
None => {
|
||||
// SAFETY: one of those arguments must have been set
|
||||
fs::read(common_args.signatures_path.unwrap())?
|
||||
}
|
||||
};
|
||||
|
||||
nym_id::import_expiration_date_signatures(credentials_store, raw_key, version).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::cli_helpers::{CliClient, CliClientConfig};
|
||||
use std::fs;
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[cfg(feature = "cli")]
|
||||
fn parse_encoded_key_data(raw: &str) -> bs58::decode::Result<Vec<u8>> {
|
||||
bs58::decode(raw).into_vec()
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "cli", derive(clap::Args))]
|
||||
#[cfg_attr(feature = "cli",
|
||||
clap(
|
||||
group(clap::ArgGroup::new("key_data_group").required(true)),
|
||||
))
|
||||
]
|
||||
pub struct CommonClientImportMasterVerificationKeyArgs {
|
||||
/// Id of client that is going to import the key
|
||||
#[cfg_attr(feature = "cli", clap(long))]
|
||||
pub id: String,
|
||||
|
||||
/// Config file of the client that is supposed to use the key.
|
||||
#[cfg_attr(feature = "cli", clap(long))]
|
||||
pub(crate) client_config: PathBuf,
|
||||
|
||||
/// Explicitly provide the encoded key data (as base58)
|
||||
#[cfg_attr(feature = "cli", clap(long, group = "key_data_group", value_parser = parse_encoded_key_data))]
|
||||
pub(crate) key_data: Option<Vec<u8>>,
|
||||
|
||||
/// Specifies the path to file containing binary key data
|
||||
#[cfg_attr(feature = "cli", clap(long, group = "key_data_group"))]
|
||||
pub(crate) key_path: Option<PathBuf>,
|
||||
|
||||
// currently hidden as there exists only a single serialization standard
|
||||
#[cfg_attr(feature = "cli", clap(long, hide = true))]
|
||||
pub(crate) version: Option<u8>,
|
||||
}
|
||||
|
||||
pub async fn import_master_verification_key<C, A>(args: A) -> Result<(), C::Error>
|
||||
where
|
||||
A: Into<CommonClientImportMasterVerificationKeyArgs>,
|
||||
C: CliClient,
|
||||
C::Error: From<std::io::Error> + From<nym_id::NymIdError>,
|
||||
{
|
||||
let common_args = args.into();
|
||||
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 version = common_args.version;
|
||||
let raw_key = match common_args.key_data {
|
||||
Some(data) => data,
|
||||
None => {
|
||||
// SAFETY: one of those arguments must have been set
|
||||
fs::read(common_args.key_path.unwrap())?
|
||||
}
|
||||
};
|
||||
|
||||
nym_id::import_master_verification_key(credentials_store, raw_key, version).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -172,7 +172,6 @@ where
|
||||
let gateway_setup = GatewaySetup::New {
|
||||
specification: selection_spec,
|
||||
available_gateways,
|
||||
wg_tun_address: None,
|
||||
};
|
||||
|
||||
let init_details =
|
||||
|
||||
@@ -57,7 +57,6 @@ 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,
|
||||
@@ -65,7 +64,6 @@ where
|
||||
active: active_gateway == Some(gateway.details.gateway_id()),
|
||||
typ: gateway.details.typ().to_string(),
|
||||
endpoint: None,
|
||||
wg_tun_address: None,
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
// 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<_, _>>()?,
|
||||
))
|
||||
}
|
||||
@@ -2,10 +2,14 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
pub mod client_add_gateway;
|
||||
pub mod client_import_coin_index_signatures;
|
||||
pub mod client_import_credential;
|
||||
pub mod client_import_expiration_date_signatures;
|
||||
pub mod client_import_master_verification_key;
|
||||
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,7 +15,6 @@ pub struct GatewayInfo {
|
||||
|
||||
pub typ: String,
|
||||
pub endpoint: Option<Url>,
|
||||
pub wg_tun_address: Option<Url>,
|
||||
}
|
||||
|
||||
impl Display for GatewayInfo {
|
||||
@@ -31,10 +30,6 @@ 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(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,15 +35,15 @@ use crate::init::{
|
||||
};
|
||||
use crate::{config, spawn_future};
|
||||
use futures::channel::mpsc;
|
||||
use log::{debug, error, info, warn};
|
||||
use log::*;
|
||||
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;
|
||||
@@ -180,7 +180,6 @@ 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>,
|
||||
@@ -204,7 +203,6 @@ where
|
||||
client_store,
|
||||
dkg_query_client,
|
||||
wait_for_gateway: false,
|
||||
wireguard_connection: false,
|
||||
custom_topology_provider: None,
|
||||
custom_gateway_transceiver: None,
|
||||
shutdown: None,
|
||||
@@ -225,12 +223,6 @@ 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,
|
||||
@@ -360,7 +352,6 @@ where
|
||||
|
||||
async fn start_gateway_client(
|
||||
config: &Config,
|
||||
wireguard_connection: bool,
|
||||
initialisation_result: InitialisationResult,
|
||||
bandwidth_controller: Option<BandwidthController<C, S::CredentialStore>>,
|
||||
packet_router: PacketRouter,
|
||||
@@ -376,44 +367,33 @@ 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)
|
||||
} 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
|
||||
}
|
||||
let mut gateway_client =
|
||||
if let Some(existing_client) = initialisation_result.authenticated_ephemeral_client {
|
||||
existing_client.upgrade(packet_router, bandwidth_controller, shutdown)
|
||||
} else {
|
||||
details.gateway_listener.to_string()
|
||||
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,
|
||||
)
|
||||
};
|
||||
|
||||
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
|
||||
@@ -431,7 +411,6 @@ 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,
|
||||
@@ -451,7 +430,7 @@ where
|
||||
Err(ClientCoreError::CustomGatewaySelectionExpected)
|
||||
} else {
|
||||
// and make sure to invalidate the task client so we wouldn't cause premature shutdown
|
||||
shutdown.mark_as_success();
|
||||
shutdown.disarm();
|
||||
custom_gateway_transceiver.set_packet_router(packet_router)?;
|
||||
Ok(custom_gateway_transceiver)
|
||||
};
|
||||
@@ -460,7 +439,6 @@ where
|
||||
// otherwise, setup normal gateway client, etc
|
||||
let gateway_client = Self::start_gateway_client(
|
||||
config,
|
||||
wireguard_connection,
|
||||
initialisation_result,
|
||||
bandwidth_controller,
|
||||
packet_router,
|
||||
@@ -558,7 +536,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.mark_as_success();
|
||||
shutdown.disarm();
|
||||
} else {
|
||||
// don't spawn the refresher if we don't want to be refreshing the topology.
|
||||
// only use the initial values obtained
|
||||
@@ -725,7 +703,6 @@ 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,7 +102,6 @@ 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-surb-storage"))]
|
||||
#[cfg(all(not(target_arch = "wasm32"), feature = "fs-credentials-storage"))]
|
||||
use nym_credential_storage::persistent_storage::PersistentStorage as PersistentCredentialStorage;
|
||||
|
||||
pub use nym_client_core_gateways_storage as gateways_storage;
|
||||
|
||||
@@ -3,10 +3,12 @@
|
||||
|
||||
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;
|
||||
@@ -111,8 +113,9 @@ impl<C, St> RemoteGateway<C, St> {
|
||||
|
||||
impl<C, St> GatewayTransceiver for RemoteGateway<C, St>
|
||||
where
|
||||
C: Send,
|
||||
St: Send,
|
||||
C: DkgQueryClient + Send + Sync,
|
||||
St: CredentialStorage,
|
||||
<St as CredentialStorage>::StorageError: Send + Sync + 'static,
|
||||
{
|
||||
fn gateway_identity(&self) -> identity::PublicKey {
|
||||
self.gateway_client.gateway_identity()
|
||||
@@ -126,8 +129,9 @@ where
|
||||
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
|
||||
impl<C, St> GatewaySender for RemoteGateway<C, St>
|
||||
where
|
||||
C: Send,
|
||||
St: Send,
|
||||
C: DkgQueryClient + Send + Sync,
|
||||
St: CredentialStorage,
|
||||
<St as CredentialStorage>::StorageError: Send + Sync + 'static,
|
||||
{
|
||||
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::info!("{}", rates.summary());
|
||||
log::debug!("{}", 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::info!(
|
||||
log::debug!(
|
||||
"mix packet retransmissions/real mix packets: {}/{}",
|
||||
delta.retransmissions_queued,
|
||||
delta.real_packets_queued,
|
||||
|
||||
@@ -453,6 +453,7 @@ 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,13 +474,6 @@ 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");
|
||||
|
||||
@@ -63,6 +63,14 @@ 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),
|
||||
|
||||
|
||||
@@ -46,13 +46,34 @@ const MEASUREMENTS: usize = 3;
|
||||
const CONN_TIMEOUT: Duration = Duration::from_millis(1500);
|
||||
const PING_TIMEOUT: Duration = Duration::from_millis(1000);
|
||||
|
||||
struct GatewayWithLatency<'a> {
|
||||
gateway: &'a gateway::Node,
|
||||
// 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,
|
||||
latency: Duration,
|
||||
}
|
||||
|
||||
impl<'a> GatewayWithLatency<'a> {
|
||||
fn new(gateway: &'a gateway::Node, latency: Duration) -> Self {
|
||||
impl<'a, G: ConnectableGateway> GatewayWithLatency<'a, G> {
|
||||
fn new(gateway: &'a G, latency: Duration) -> Self {
|
||||
GatewayWithLatency { gateway, latency }
|
||||
}
|
||||
}
|
||||
@@ -130,11 +151,14 @@ async fn connect(endpoint: &str) -> Result<WsConn, ClientCoreError> {
|
||||
JSWebsocket::new(endpoint).map_err(|_| ClientCoreError::GatewayJsConnectionFailure)
|
||||
}
|
||||
|
||||
async fn measure_latency(gateway: &gateway::Node) -> Result<GatewayWithLatency, ClientCoreError> {
|
||||
async fn measure_latency<G>(gateway: &G) -> Result<GatewayWithLatency<G>, ClientCoreError>
|
||||
where
|
||||
G: ConnectableGateway,
|
||||
{
|
||||
let addr = gateway.clients_address();
|
||||
trace!(
|
||||
"establishing connection to {} ({addr})...",
|
||||
gateway.identity_key,
|
||||
gateway.identity(),
|
||||
);
|
||||
let mut stream = connect(&addr).await?;
|
||||
|
||||
@@ -177,7 +201,7 @@ async fn measure_latency(gateway: &gateway::Node) -> Result<GatewayWithLatency,
|
||||
let count = results.len() as u64;
|
||||
if count == 0 {
|
||||
return Err(ClientCoreError::NoGatewayMeasurements {
|
||||
identity: gateway.identity_key.to_base58_string(),
|
||||
identity: gateway.identity().to_base58_string(),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -187,11 +211,11 @@ async fn measure_latency(gateway: &gateway::Node) -> Result<GatewayWithLatency,
|
||||
Ok(GatewayWithLatency::new(gateway, avg))
|
||||
}
|
||||
|
||||
pub async fn choose_gateway_by_latency<R: Rng>(
|
||||
pub async fn choose_gateway_by_latency<'a, R: Rng, G: ConnectableGateway + Clone>(
|
||||
rng: &mut R,
|
||||
gateways: &[gateway::Node],
|
||||
gateways: &[G],
|
||||
must_use_tls: bool,
|
||||
) -> Result<gateway::Node, ClientCoreError> {
|
||||
) -> Result<G, ClientCoreError> {
|
||||
let gateways = filter_by_tls(gateways, must_use_tls)?;
|
||||
|
||||
info!(
|
||||
@@ -223,21 +247,19 @@ pub async fn choose_gateway_by_latency<R: Rng>(
|
||||
|
||||
info!(
|
||||
"chose gateway {} with average latency of {:?}",
|
||||
chosen.gateway.identity_key, chosen.latency
|
||||
chosen.gateway.identity(),
|
||||
chosen.latency
|
||||
);
|
||||
|
||||
Ok(chosen.gateway.clone())
|
||||
}
|
||||
|
||||
fn filter_by_tls(
|
||||
gateways: &[gateway::Node],
|
||||
fn filter_by_tls<G: ConnectableGateway>(
|
||||
gateways: &[G],
|
||||
must_use_tls: bool,
|
||||
) -> Result<Vec<&gateway::Node>, ClientCoreError> {
|
||||
) -> Result<Vec<&G>, ClientCoreError> {
|
||||
if must_use_tls {
|
||||
let filtered = gateways
|
||||
.iter()
|
||||
.filter(|g| g.clients_wss_port.is_some())
|
||||
.collect::<Vec<_>>();
|
||||
let filtered = gateways.iter().filter(|g| g.is_wss()).collect::<Vec<_>>();
|
||||
|
||||
if filtered.is_empty() {
|
||||
return Err(ClientCoreError::NoWssGateways);
|
||||
|
||||
@@ -23,7 +23,6 @@ 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;
|
||||
@@ -52,7 +51,6 @@ 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,
|
||||
@@ -70,19 +68,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, wg_tun_ip_address, must_use_tls)?
|
||||
SelectedGateway::from_topology_node(gateway, 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, wg_tun_ip_address, must_use_tls)?
|
||||
SelectedGateway::from_topology_node(gateway, 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, wg_tun_ip_address, must_use_tls)?
|
||||
SelectedGateway::from_topology_node(gateway, must_use_tls)?
|
||||
}
|
||||
GatewaySelectionSpecification::Custom {
|
||||
gateway_identity,
|
||||
@@ -104,23 +102,19 @@ 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, url, our_identity).await?;
|
||||
helpers::register_with_gateway(gateway_id, gateway_listener.clone(), our_identity)
|
||||
.await?;
|
||||
(
|
||||
GatewayDetails::new_remote(
|
||||
gateway_id,
|
||||
registration.shared_keys,
|
||||
gateway_owner_address,
|
||||
gateway_listener,
|
||||
wg_tun_address,
|
||||
),
|
||||
Some(registration.authenticated_ephemeral_client),
|
||||
)
|
||||
@@ -207,17 +201,9 @@ 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,
|
||||
wg_tun_address,
|
||||
)
|
||||
.await
|
||||
setup_new_gateway(key_store, details_store, specification, available_gateways).await
|
||||
}
|
||||
GatewaySetup::ReuseConnection {
|
||||
authenticated_ephemeral_client,
|
||||
|
||||
@@ -6,7 +6,6 @@ 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,
|
||||
};
|
||||
@@ -19,7 +18,6 @@ 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;
|
||||
@@ -32,8 +30,6 @@ pub enum SelectedGateway {
|
||||
gateway_owner_address: Option<AccountId>,
|
||||
|
||||
gateway_listener: Url,
|
||||
|
||||
wg_tun_address: Option<Url>,
|
||||
},
|
||||
Custom {
|
||||
gateway_id: identity::PublicKey,
|
||||
@@ -41,36 +37,9 @@ 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 {
|
||||
@@ -82,8 +51,6 @@ 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()
|
||||
@@ -109,7 +76,6 @@ impl SelectedGateway {
|
||||
gateway_id: node.identity_key,
|
||||
gateway_owner_address,
|
||||
gateway_listener,
|
||||
wg_tun_address,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -250,12 +216,6 @@ 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 {
|
||||
@@ -290,7 +250,6 @@ impl GatewaySetup {
|
||||
additional_data: None,
|
||||
},
|
||||
available_gateways: vec![],
|
||||
wg_tun_address: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,9 @@ 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;
|
||||
|
||||
@@ -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/gateway-requests" }
|
||||
nym-gateway-requests = { path = "../../gateway-requests" }
|
||||
nym-network-defaults = { path = "../../network-defaults" }
|
||||
nym-sphinx = { path = "../../nymsphinx" }
|
||||
nym-pemstore = { path = "../../pemstore" }
|
||||
@@ -43,7 +43,7 @@ workspace = true
|
||||
features = ["macros", "rt", "net", "sync", "time"]
|
||||
|
||||
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.tokio-stream]
|
||||
version = "0.1.11"
|
||||
version = "0.1.16"
|
||||
features = ["net", "sync", "time"]
|
||||
|
||||
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.tokio-tungstenite]
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
// 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()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::error::GatewayClientError;
|
||||
use nym_network_defaults::TicketTypeRepr::V1MixnetEntry;
|
||||
use si_scale::helpers::bibytes2;
|
||||
use std::time::Duration;
|
||||
|
||||
#[derive(Debug, Default, Clone, Copy)]
|
||||
pub struct GatewayClientConfig {
|
||||
pub connection: Connection,
|
||||
pub bandwidth: BandwidthTickets,
|
||||
}
|
||||
|
||||
impl GatewayClientConfig {
|
||||
pub fn new_default() -> Self {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn with_disabled_credentials_mode(mut self, disabled_credentials_mode: bool) -> Self {
|
||||
self.bandwidth.require_tickets = !disabled_credentials_mode;
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn with_reconnection_on_failure(mut self, should_reconnect_on_failure: bool) -> Self {
|
||||
self.connection.should_reconnect_on_failure = should_reconnect_on_failure;
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn with_response_timeout(mut self, response_timeout_duration: Duration) -> Self {
|
||||
self.connection.response_timeout_duration = response_timeout_duration;
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn with_reconnection_attempts(mut self, reconnection_attempts: usize) -> Self {
|
||||
self.connection.reconnection_attempts = reconnection_attempts;
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn with_reconnection_backoff(mut self, backoff: Duration) -> Self {
|
||||
self.connection.reconnection_backoff = backoff;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct Connection {
|
||||
/// Specifies the timeout for gateway responses
|
||||
pub response_timeout_duration: Duration,
|
||||
|
||||
/// Specifies whether client should try to reconnect to gateway on connection failure.
|
||||
pub should_reconnect_on_failure: bool,
|
||||
|
||||
/// Specifies maximum number of attempts client will try to reconnect to gateway on failure
|
||||
/// before giving up.
|
||||
pub reconnection_attempts: usize,
|
||||
|
||||
/// Delay between each subsequent reconnection attempt.
|
||||
pub reconnection_backoff: Duration,
|
||||
}
|
||||
|
||||
impl Connection {
|
||||
// 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
|
||||
pub const DEFAULT_RESPONSE_TIMEOUT: Duration = Duration::from_secs(5 * 60);
|
||||
pub const DEFAULT_RECONNECTION_ATTEMPTS: usize = 10;
|
||||
pub const DEFAULT_RECONNECTION_BACKOFF: Duration = Duration::from_secs(5);
|
||||
}
|
||||
|
||||
impl Default for Connection {
|
||||
fn default() -> Self {
|
||||
Connection {
|
||||
response_timeout_duration: Self::DEFAULT_RESPONSE_TIMEOUT,
|
||||
should_reconnect_on_failure: true,
|
||||
reconnection_attempts: Self::DEFAULT_RECONNECTION_ATTEMPTS,
|
||||
reconnection_backoff: Self::DEFAULT_RECONNECTION_BACKOFF,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct BandwidthTickets {
|
||||
/// specifies whether this client will be sending bandwidth tickets or will attempt to use 'free' testnet bandwidth instead
|
||||
pub require_tickets: bool,
|
||||
|
||||
/// specifies threshold (in bytes) under which the client should send another ticket to the gateway
|
||||
pub remaining_bandwidth_threshold: i64,
|
||||
|
||||
/// specifies threshold (in bytes) under which the client will NOT send any tickets because it got accused of double spending and got its bandwidth revoked
|
||||
/// if not specified, the client will always send tickets
|
||||
pub cutoff_remaining_bandwidth_threshold: Option<i64>,
|
||||
}
|
||||
|
||||
impl BandwidthTickets {
|
||||
// TO BE CHANGED \/
|
||||
pub const DEFAULT_REQUIRES_TICKETS: bool = false;
|
||||
|
||||
// 20% of entry ticket value
|
||||
pub const DEFAULT_REMAINING_BANDWIDTH_THRESHOLD: i64 =
|
||||
(V1MixnetEntry.bandwidth_value() / 5) as i64;
|
||||
|
||||
pub const DEFAULT_CUTOFF_REMAINING_BANDWIDTH_THRESHOLD: Option<i64> = None;
|
||||
|
||||
pub fn ensure_above_cutoff(&self, available: i64) -> Result<(), GatewayClientError> {
|
||||
if let Some(cutoff) = self.cutoff_remaining_bandwidth_threshold {
|
||||
if available < cutoff {
|
||||
let available_bi2 = bibytes2(available as f64);
|
||||
let cutoff_bi2 = bibytes2(cutoff as f64);
|
||||
return Err(GatewayClientError::BandwidthBelowCutoffValue {
|
||||
available_bi2,
|
||||
cutoff_bi2,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for BandwidthTickets {
|
||||
fn default() -> Self {
|
||||
BandwidthTickets {
|
||||
require_tickets: Self::DEFAULT_REQUIRES_TICKETS,
|
||||
remaining_bandwidth_threshold: Self::DEFAULT_REMAINING_BANDWIDTH_THRESHOLD,
|
||||
cutoff_remaining_bandwidth_threshold:
|
||||
Self::DEFAULT_CUTOFF_REMAINING_BANDWIDTH_THRESHOLD,
|
||||
}
|
||||
}
|
||||
}
|
||||
+146
-154
@@ -1,17 +1,18 @@
|
||||
// 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, PartiallyDelegated, SocketState};
|
||||
use crate::socket_state::{ws_fd, PartiallyDelegatedHandle, 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;
|
||||
use nym_bandwidth_controller::{BandwidthController, BandwidthStatusMessage};
|
||||
use nym_credential_storage::ephemeral_storage::EphemeralStorage as EphemeralCredentialStorage;
|
||||
use nym_credential_storage::storage::Storage as CredentialStorage;
|
||||
use nym_credentials::CredentialSpendingData;
|
||||
@@ -23,14 +24,11 @@ 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;
|
||||
|
||||
@@ -48,12 +46,7 @@ use wasm_utils::websocket::JSWebsocket;
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
use wasmtimer::tokio::sleep;
|
||||
|
||||
// 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 mod config;
|
||||
|
||||
pub struct GatewayConfig {
|
||||
pub gateway_identity: identity::PublicKey,
|
||||
@@ -79,96 +72,53 @@ 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,
|
||||
disabled_credentials_mode: bool,
|
||||
bandwidth_remaining: i64,
|
||||
bandwidth: ClientBandwidth,
|
||||
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.
|
||||
shutdown: TaskClient,
|
||||
/// Listen to shutdown messages and send notifications back to the task manager
|
||||
task_client: TaskClient,
|
||||
}
|
||||
|
||||
impl<C, St> GatewayClient<C, St> {
|
||||
pub fn new(
|
||||
config: GatewayConfig,
|
||||
cfg: GatewayClientConfig,
|
||||
gateway_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>>,
|
||||
shutdown: TaskClient,
|
||||
task_client: TaskClient,
|
||||
) -> Self {
|
||||
GatewayClient {
|
||||
cfg,
|
||||
authenticated: false,
|
||||
disabled_credentials_mode: true,
|
||||
bandwidth_remaining: 0,
|
||||
gateway_address: config.gateway_listener,
|
||||
gateway_identity: config.gateway_identity,
|
||||
bandwidth: ClientBandwidth::new_empty(),
|
||||
gateway_address: gateway_config.gateway_listener,
|
||||
gateway_identity: gateway_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,
|
||||
shutdown,
|
||||
task_client,
|
||||
}
|
||||
}
|
||||
|
||||
#[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
|
||||
}
|
||||
@@ -182,7 +132,7 @@ impl<C, St> GatewayClient<C, St> {
|
||||
}
|
||||
|
||||
pub fn remaining_bandwidth(&self) -> i64 {
|
||||
self.bandwidth_remaining
|
||||
self.bandwidth.remaining()
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
@@ -258,18 +208,21 @@ impl<C, St> GatewayClient<C, St> {
|
||||
info!("Attempting gateway reconnection...");
|
||||
self.authenticated = false;
|
||||
|
||||
for i in 1..self.reconnection_attempts {
|
||||
info!("attempt {}...", i);
|
||||
for i in 1..self.cfg.connection.reconnection_attempts {
|
||||
info!("reconnection attempt {}...", i);
|
||||
if self.try_reconnect().await.is_ok() {
|
||||
info!("managed to reconnect!");
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
sleep(self.reconnection_backoff).await;
|
||||
sleep(self.cfg.connection.reconnection_backoff).await;
|
||||
}
|
||||
|
||||
// final attempt (done separately to be able to return a proper error)
|
||||
info!("attempt {}", self.reconnection_attempts);
|
||||
info!(
|
||||
"reconnection attempt {}",
|
||||
self.cfg.connection.reconnection_attempts
|
||||
);
|
||||
match self.try_reconnect().await {
|
||||
Ok(_) => {
|
||||
info!("managed to reconnect!");
|
||||
@@ -278,7 +231,7 @@ impl<C, St> GatewayClient<C, St> {
|
||||
Err(err) => {
|
||||
error!(
|
||||
"failed to reconnect after {} attempts",
|
||||
self.reconnection_attempts
|
||||
self.cfg.connection.reconnection_attempts
|
||||
);
|
||||
Err(err)
|
||||
}
|
||||
@@ -294,12 +247,12 @@ impl<C, St> GatewayClient<C, St> {
|
||||
_ => return Err(GatewayClientError::ConnectionInInvalidState),
|
||||
};
|
||||
|
||||
let timeout = sleep(self.response_timeout_duration);
|
||||
let timeout = sleep(self.cfg.connection.response_timeout_duration);
|
||||
tokio::pin!(timeout);
|
||||
|
||||
loop {
|
||||
tokio::select! {
|
||||
_ = self.shutdown.recv() => {
|
||||
_ = self.task_client.recv() => {
|
||||
log::trace!("GatewayClient control response: Received shutdown");
|
||||
log::debug!("GatewayClient control response: Exiting");
|
||||
break Err(GatewayClientError::ConnectionClosedGatewayShutdown);
|
||||
@@ -340,7 +293,7 @@ impl<C, St> GatewayClient<C, St> {
|
||||
// as we need to be able to write the request and read the subsequent response
|
||||
async fn send_websocket_message(
|
||||
&mut self,
|
||||
msg: Message,
|
||||
msg: impl Into<Message>,
|
||||
) -> Result<ServerResponse, GatewayClientError> {
|
||||
let should_restart_mixnet_listener = if self.connection.is_partially_delegated() {
|
||||
self.recover_socket_connection().await?;
|
||||
@@ -354,7 +307,7 @@ impl<C, St> GatewayClient<C, St> {
|
||||
SocketState::NotConnected => return Err(GatewayClientError::ConnectionNotEstablished),
|
||||
_ => return Err(GatewayClientError::ConnectionInInvalidState),
|
||||
};
|
||||
conn.send(msg).await?;
|
||||
conn.send(msg.into()).await?;
|
||||
let response = self.read_control_response().await;
|
||||
|
||||
if should_restart_mixnet_listener {
|
||||
@@ -463,7 +416,9 @@ impl<C, St> GatewayClient<C, St> {
|
||||
ws_stream,
|
||||
self.local_identity.as_ref(),
|
||||
self.gateway_identity,
|
||||
!self.disabled_credentials_mode,
|
||||
self.cfg.bandwidth.require_tickets,
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
self.task_client.clone(),
|
||||
)
|
||||
.await
|
||||
.map_err(GatewayClientError::RegistrationFailure),
|
||||
@@ -525,9 +480,8 @@ impl<C, St> GatewayClient<C, St> {
|
||||
self_address,
|
||||
encrypted_address,
|
||||
iv,
|
||||
!self.disabled_credentials_mode,
|
||||
)
|
||||
.into();
|
||||
self.cfg.bandwidth.require_tickets,
|
||||
);
|
||||
|
||||
match self.send_websocket_message(msg).await? {
|
||||
ServerResponse::Authenticate {
|
||||
@@ -537,9 +491,13 @@ impl<C, St> GatewayClient<C, St> {
|
||||
} => {
|
||||
self.check_gateway_protocol(protocol_version)?;
|
||||
self.authenticated = status;
|
||||
self.bandwidth_remaining = bandwidth_remaining;
|
||||
self.bandwidth.update_and_maybe_log(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)),
|
||||
@@ -573,56 +531,88 @@ impl<C, St> GatewayClient<C, St> {
|
||||
}
|
||||
}
|
||||
|
||||
async fn claim_coconut_bandwidth(
|
||||
pub async fn get_gateway_protocol(&mut self) -> Result<u8, GatewayClientError> {
|
||||
if !self.connection.is_established() {
|
||||
return Err(GatewayClientError::ConnectionNotEstablished);
|
||||
}
|
||||
|
||||
match self
|
||||
.send_websocket_message(ClientControlRequest::SupportedProtocol {})
|
||||
.await?
|
||||
{
|
||||
ServerResponse::SupportedProtocol { version } => Ok(version),
|
||||
ServerResponse::Error { message } => Err(GatewayClientError::GatewayError(message)),
|
||||
_ => Err(GatewayClientError::UnexpectedResponse),
|
||||
}
|
||||
}
|
||||
|
||||
async fn claim_ecash_bandwidth(
|
||||
&mut self,
|
||||
credential: CredentialSpendingData,
|
||||
) -> Result<(), GatewayClientError> {
|
||||
let mut rng = OsRng;
|
||||
let iv = IV::new_random(&mut rng);
|
||||
|
||||
let msg = ClientControlRequest::new_enc_coconut_bandwidth_credential_v2(
|
||||
let msg = ClientControlRequest::new_enc_ecash_credential(
|
||||
credential,
|
||||
self.shared_key.as_ref().unwrap(),
|
||||
iv,
|
||||
)
|
||||
.into();
|
||||
self.bandwidth_remaining = match self.send_websocket_message(msg).await? {
|
||||
);
|
||||
let 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();
|
||||
self.bandwidth_remaining = match self.send_websocket_message(msg).await? {
|
||||
let msg = ClientControlRequest::ClaimFreeTestnetBandwidth;
|
||||
let 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.disabled_credentials_mode {
|
||||
if self.bandwidth_controller.is_none() && self.cfg.bandwidth.require_tickets {
|
||||
return Err(GatewayClientError::NoBandwidthControllerAvailable);
|
||||
}
|
||||
|
||||
warn!("Not enough bandwidth. Trying to get more bandwidth, this might take a while");
|
||||
if self.disabled_credentials_mode {
|
||||
if !self.cfg.bandwidth.require_tickets {
|
||||
info!("The client is running in disabled credentials mode - attempting to claim bandwidth without a credential");
|
||||
return self.try_claim_testnet_bandwidth().await;
|
||||
}
|
||||
@@ -638,49 +628,52 @@ impl<C, St> GatewayClient<C, St> {
|
||||
negotiated_protocol: Some(gateway_protocol),
|
||||
});
|
||||
}
|
||||
|
||||
let gateway_id = self.gateway_identity().to_base58_string();
|
||||
|
||||
let prepared_credential = self
|
||||
.bandwidth_controller
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.prepare_bandwidth_credential(&gateway_id)
|
||||
.unchecked_bandwidth_controller()
|
||||
.prepare_ecash_ticket(self.gateway_identity.to_bytes(), TICKETS_TO_SPEND)
|
||||
.await?;
|
||||
|
||||
self.claim_coconut_bandwidth(prepared_credential.data)
|
||||
.await?;
|
||||
self.bandwidth_controller
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.consume_credential(prepared_credential.credential_id, &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?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn estimate_required_bandwidth(&self, packets: &[MixPacket]) -> i64 {
|
||||
packets
|
||||
.iter()
|
||||
.map(|packet| packet.packet().len())
|
||||
.sum::<usize>() as i64
|
||||
Err(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn batch_send_mix_packets(
|
||||
&mut self,
|
||||
packets: Vec<MixPacket>,
|
||||
) -> Result<(), GatewayClientError> {
|
||||
) -> Result<(), GatewayClientError>
|
||||
where
|
||||
C: DkgQueryClient + Send + Sync,
|
||||
St: CredentialStorage,
|
||||
<St as CredentialStorage>::StorageError: Send + Sync + 'static,
|
||||
{
|
||||
debug!("Sending {} mix packets", packets.len());
|
||||
|
||||
if !self.authenticated {
|
||||
return Err(GatewayClientError::NotAuthenticated);
|
||||
}
|
||||
if self.estimate_required_bandwidth(&packets) > self.bandwidth_remaining {
|
||||
return Err(GatewayClientError::NotEnoughBandwidth(
|
||||
self.estimate_required_bandwidth(&packets),
|
||||
self.bandwidth_remaining,
|
||||
));
|
||||
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.connection.is_established() {
|
||||
return Err(GatewayClientError::ConnectionNotEstablished);
|
||||
}
|
||||
@@ -700,7 +693,7 @@ impl<C, St> GatewayClient<C, St> {
|
||||
.batch_send_websocket_messages_without_response(messages)
|
||||
.await
|
||||
{
|
||||
if err.is_closed_connection() && self.should_reconnect_on_failure {
|
||||
if err.is_closed_connection() && self.cfg.connection.should_reconnect_on_failure {
|
||||
self.attempt_reconnection().await
|
||||
} else {
|
||||
Err(err)
|
||||
@@ -715,7 +708,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.should_reconnect_on_failure {
|
||||
if err.is_closed_connection() && self.cfg.connection.should_reconnect_on_failure {
|
||||
debug!("Going to attempt a reconnection");
|
||||
self.attempt_reconnection().await
|
||||
} else {
|
||||
@@ -739,19 +732,23 @@ impl<C, St> GatewayClient<C, St> {
|
||||
}
|
||||
|
||||
// TODO: possibly make responses optional
|
||||
pub async fn send_mix_packet(
|
||||
&mut self,
|
||||
mix_packet: MixPacket,
|
||||
) -> Result<(), GatewayClientError> {
|
||||
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,
|
||||
{
|
||||
if !self.authenticated {
|
||||
return Err(GatewayClientError::NotAuthenticated);
|
||||
}
|
||||
if (mix_packet.packet().len() as i64) > self.bandwidth_remaining {
|
||||
return Err(GatewayClientError::NotEnoughBandwidth(
|
||||
mix_packet.packet().len() as i64,
|
||||
self.bandwidth_remaining,
|
||||
));
|
||||
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.connection.is_established() {
|
||||
return Err(GatewayClientError::ConnectionNotEstablished);
|
||||
}
|
||||
@@ -797,7 +794,7 @@ impl<C, St> GatewayClient<C, St> {
|
||||
let partially_delegated =
|
||||
match std::mem::replace(&mut self.connection, SocketState::Invalid) {
|
||||
SocketState::Available(conn) => {
|
||||
PartiallyDelegated::split_and_listen_for_mixnet_messages(
|
||||
PartiallyDelegatedHandle::split_and_listen_for_mixnet_messages(
|
||||
*conn,
|
||||
self.packet_router.clone(),
|
||||
Arc::clone(
|
||||
@@ -805,7 +802,8 @@ impl<C, St> GatewayClient<C, St> {
|
||||
.as_ref()
|
||||
.expect("no shared key present even though we're authenticated!"),
|
||||
),
|
||||
self.shutdown.clone(),
|
||||
self.bandwidth.clone(),
|
||||
self.task_client.clone(),
|
||||
)
|
||||
}
|
||||
_ => unreachable!(),
|
||||
@@ -845,10 +843,12 @@ impl<C, St> GatewayClient<C, St> {
|
||||
self.establish_connection().await?;
|
||||
}
|
||||
let shared_key = self.perform_initial_authentication().await?;
|
||||
|
||||
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);
|
||||
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.");
|
||||
self.claim_bandwidth().await?;
|
||||
}
|
||||
|
||||
@@ -879,26 +879,22 @@ 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 shutdown = TaskClient::dummy();
|
||||
let packet_router = PacketRouter::new(ack_tx, mix_tx, shutdown.clone());
|
||||
let task_client = TaskClient::dummy();
|
||||
let packet_router = PacketRouter::new(ack_tx, mix_tx, task_client.clone());
|
||||
|
||||
GatewayClient {
|
||||
cfg: GatewayClientConfig::default().with_disabled_credentials_mode(true),
|
||||
authenticated: false,
|
||||
disabled_credentials_mode: true,
|
||||
bandwidth_remaining: 0,
|
||||
bandwidth: ClientBandwidth::new_empty(),
|
||||
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,
|
||||
shutdown,
|
||||
task_client,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -906,7 +902,7 @@ impl GatewayClient<InitOnly, EphemeralCredentialStorage> {
|
||||
self,
|
||||
packet_router: PacketRouter,
|
||||
bandwidth_controller: Option<BandwidthController<C, St>>,
|
||||
shutdown: TaskClient,
|
||||
task_client: TaskClient,
|
||||
) -> GatewayClient<C, St> {
|
||||
// invariants that can't be broken
|
||||
// (unless somebody decided to expose some field that wasn't meant to be exposed)
|
||||
@@ -915,22 +911,18 @@ impl GatewayClient<InitOnly, EphemeralCredentialStorage> {
|
||||
assert!(self.shared_key.is_some());
|
||||
|
||||
GatewayClient {
|
||||
cfg: self.cfg,
|
||||
authenticated: self.authenticated,
|
||||
disabled_credentials_mode: self.disabled_credentials_mode,
|
||||
bandwidth_remaining: self.bandwidth_remaining,
|
||||
bandwidth: self.bandwidth,
|
||||
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,
|
||||
shutdown,
|
||||
task_client,
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user