Compare commits
177 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 012a81857b | |||
| 8c752b3028 | |||
| a44819b14c | |||
| 5455110810 | |||
| a0178d28f7 | |||
| 3e42160426 | |||
| 673a3e45d3 | |||
| d9c2f6ebda | |||
| e24e094711 | |||
| 378f32e6d7 | |||
| 3e9b8d237f | |||
| f5a4dbc555 | |||
| 4480534e4d | |||
| d355f9d752 | |||
| 9f3a370496 | |||
| e4adc5d954 | |||
| 00373b70e2 | |||
| 65f2017422 | |||
| 192f258463 | |||
| a5eee7444b | |||
| 6abd7e7352 | |||
| 3306ca5357 | |||
| 9c2ccead0e | |||
| b7aeb51362 | |||
| e9e725defe | |||
| c74494a21d | |||
| 54f6c98c22 | |||
| 846484bbb4 | |||
| fb3f5501ba | |||
| e8a607f520 | |||
| f5f6df9eaf | |||
| c647ab5605 | |||
| 416c21a42e | |||
| fd5a95fa4d | |||
| c61df79182 | |||
| 08559a7660 | |||
| 6dce55a99b | |||
| bc0b89b31c | |||
| 67c32faa11 | |||
| aa0d15ee67 | |||
| 4f0974fcf1 | |||
| bd2174641e | |||
| 59b62fabc9 | |||
| e6f4bae895 | |||
| d71742af32 | |||
| 3b7c07e249 | |||
| 3b429dde69 | |||
| 3a29c296da | |||
| 8544c54f8f | |||
| 9f9639950b | |||
| 111a0b20b6 | |||
| 67b300d0b8 | |||
| 88c4e0ce6c | |||
| f6800aff0a | |||
| 0c7c927ca2 | |||
| a69c8b1660 | |||
| f3ea310a46 | |||
| 92f9ff035d | |||
| 5a817e1df1 | |||
| a07a24db00 | |||
| a0cb812eff | |||
| 923c1fa184 | |||
| 35ea7e4926 | |||
| d1cb9afaf0 | |||
| 79d4b4b2e3 | |||
| 8460b33946 | |||
| ae6539e07c | |||
| 18cebdfedc | |||
| c448ec823a | |||
| a266137278 | |||
| 6f4dfd1dab | |||
| 57719787db | |||
| 29a57bf172 | |||
| 17d11f201e | |||
| fef7e42eb4 | |||
| ceeeb6211b | |||
| cd77b1032f | |||
| 6bbb14f12f | |||
| de8030d85a | |||
| e18e64bf21 | |||
| a50c9ac3fb | |||
| db813b6e3e | |||
| 1be5ba310a | |||
| 41ff3f7824 | |||
| c9d4d62446 | |||
| e839a0d80e | |||
| cd61f930bf | |||
| 0674f31227 | |||
| 3e4f563dce | |||
| edcf2b1204 | |||
| b07fb18113 | |||
| 017dea4afd | |||
| 5a9ce13beb | |||
| 514cf25c68 | |||
| 49ee0636e4 | |||
| bb971ce99c | |||
| 54de369c1e | |||
| 6d6ce284df | |||
| 56ad1c6c8e | |||
| 10b4a288c8 | |||
| bbbb9486ce | |||
| 16e86e1a07 | |||
| ca0c9898f0 | |||
| 8b73d4e615 | |||
| 6a9a767ab4 | |||
| 2235a6e147 | |||
| e03a9fa16f | |||
| db6defa122 | |||
| a0fbd57d5b | |||
| 9856198356 | |||
| 5c33846e57 | |||
| cfa7635ae1 | |||
| 5d45544c27 | |||
| aa6a79cb3e | |||
| b3a940770a | |||
| e980f76a81 | |||
| 9b38fef28f | |||
| 43910ca635 | |||
| d3ccd7575a | |||
| 422f889df7 | |||
| c9e96edc35 | |||
| 7768317046 | |||
| 0ebbb1a540 | |||
| 827c13b69e | |||
| 18ff09608c | |||
| 8cc996bc0d | |||
| 83a598907f | |||
| df7768dec0 | |||
| f3a449b7cc | |||
| 48c06545ab | |||
| f53e5fe8dd | |||
| fc98c497b4 | |||
| cf21593ffa | |||
| 92a88cdf9a | |||
| 026d3a6466 | |||
| 53c4fde314 | |||
| 3f55e62764 | |||
| 00cc54f5c3 | |||
| c1904840e1 | |||
| c652e3bdcd | |||
| f9844416df | |||
| bbea2ff9e9 | |||
| 4acaec48b4 | |||
| 51779c06a4 | |||
| 5cc650e901 | |||
| a7ec178c9f | |||
| 4e97a2f871 | |||
| 5fbfc21fb2 | |||
| 3d45801bb7 | |||
| 3aea9f127b | |||
| a26ff644cc | |||
| a0e37e78e2 | |||
| b3d02e3ba7 | |||
| f5b5177073 | |||
| f0d8dabb9f | |||
| bb06a1b7a8 | |||
| e783a5fced | |||
| 8a24b45b5d | |||
| f105bcbafe | |||
| dc0f4af2c1 | |||
| 10e4eba727 | |||
| 8ebf482f36 | |||
| 6940ca427e | |||
| 24f877fda5 | |||
| 2a621e07a8 | |||
| 485aeebabd | |||
| 3b726bada9 | |||
| 1d1b2e17d2 | |||
| b5b2dbdfd8 | |||
| 82806f47d8 | |||
| c6f85cf23e | |||
| ed8de7234d | |||
| e25d83b047 | |||
| 9974d480b5 | |||
| 2211f13cdd | |||
| 4505f18a02 | |||
| a717a18948 |
@@ -8,10 +8,13 @@ on:
|
|||||||
- 'gateway/**'
|
- 'gateway/**'
|
||||||
- 'integrations/**'
|
- 'integrations/**'
|
||||||
- 'nym-api/**'
|
- 'nym-api/**'
|
||||||
|
- 'nym-authenticator-client/**'
|
||||||
- 'nym-credential-proxy/**'
|
- 'nym-credential-proxy/**'
|
||||||
|
- 'nym-ip-packet-client/**'
|
||||||
- 'nym-network-monitor/**'
|
- 'nym-network-monitor/**'
|
||||||
- 'nym-node/**'
|
- 'nym-node/**'
|
||||||
- 'nym-node-status-api/**'
|
- 'nym-node-status-api/**'
|
||||||
|
- 'nym-registration-client/**'
|
||||||
- 'nym-statistics-api/**'
|
- 'nym-statistics-api/**'
|
||||||
- 'nym-outfox/**'
|
- 'nym-outfox/**'
|
||||||
- 'nym-validator-rewarder/**'
|
- 'nym-validator-rewarder/**'
|
||||||
@@ -81,12 +84,21 @@ jobs:
|
|||||||
command: fmt
|
command: fmt
|
||||||
args: --all -- --check
|
args: --all -- --check
|
||||||
|
|
||||||
- name: Clippy
|
- name: Clippy (macos)
|
||||||
|
if: contains(matrix.os, 'mac')
|
||||||
|
uses: actions-rs/cargo@v1
|
||||||
|
with:
|
||||||
|
command: clippy
|
||||||
|
args: --workspace --all-targets --exclude nym-gateway-probe -- -D warnings
|
||||||
|
|
||||||
|
- name: Clippy (non-macos)
|
||||||
|
if: contains(matrix.os, 'linux') || contains(matrix.os, 'windows')
|
||||||
uses: actions-rs/cargo@v1
|
uses: actions-rs/cargo@v1
|
||||||
with:
|
with:
|
||||||
command: clippy
|
command: clippy
|
||||||
args: --workspace --all-targets -- -D warnings
|
args: --workspace --all-targets -- -D warnings
|
||||||
|
|
||||||
|
|
||||||
- name: Build all binaries
|
- name: Build all binaries
|
||||||
uses: actions-rs/cargo@v1
|
uses: actions-rs/cargo@v1
|
||||||
with:
|
with:
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ env:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
check-if-tag-exists:
|
check-if-tag-exists:
|
||||||
runs-on: arc-ubuntu-22.04-dind
|
runs-on: arc-linux-latest-dind
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repo
|
- name: Checkout repo
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
platform: [ arc-ubuntu-22.04 ]
|
platform: [ arc-linux-latest-dind ]
|
||||||
|
|
||||||
runs-on: ${{ matrix.platform }}
|
runs-on: ${{ matrix.platform }}
|
||||||
env:
|
env:
|
||||||
@@ -28,18 +28,11 @@ jobs:
|
|||||||
mkdir -p $OUTPUT_DIR
|
mkdir -p $OUTPUT_DIR
|
||||||
echo $OUTPUT_DIR
|
echo $OUTPUT_DIR
|
||||||
|
|
||||||
- name: Install Rust stable
|
- name: Build contracts
|
||||||
uses: actions-rs/toolchain@v1
|
run: make optimize-contracts
|
||||||
with:
|
|
||||||
toolchain: stable
|
|
||||||
target: wasm32-unknown-unknown
|
|
||||||
override: true
|
|
||||||
|
|
||||||
- name: Install cosmwasm-check
|
- name: Check optimized contracts
|
||||||
run: cargo install cosmwasm-check
|
run: make docker-check-contracts
|
||||||
|
|
||||||
- name: Build release contracts
|
|
||||||
run: make publish-contracts
|
|
||||||
|
|
||||||
- name: Prepare build output
|
- name: Prepare build output
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ jobs:
|
|||||||
build:
|
build:
|
||||||
# since it's going to be compiled into wasm, there's absolutely
|
# since it's going to be compiled into wasm, there's absolutely
|
||||||
# no point in running CI on different OS-es
|
# no point in running CI on different OS-es
|
||||||
runs-on: ubuntu-22.04
|
runs-on: arc-linux-latest
|
||||||
env:
|
env:
|
||||||
CARGO_TERM_COLOR: always
|
CARGO_TERM_COLOR: always
|
||||||
RUSTUP_PERMIT_COPY_RENAME: 1
|
RUSTUP_PERMIT_COPY_RENAME: 1
|
||||||
@@ -54,7 +54,7 @@ jobs:
|
|||||||
uses: actions-rs/cargo@v1
|
uses: actions-rs/cargo@v1
|
||||||
with:
|
with:
|
||||||
command: test
|
command: test
|
||||||
args: --lib --manifest-path contracts/Cargo.toml
|
args: --lib --manifest-path contracts/Cargo.toml --all-features
|
||||||
|
|
||||||
- name: Check formatting
|
- name: Check formatting
|
||||||
uses: actions-rs/cargo@v1
|
uses: actions-rs/cargo@v1
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ on:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: arc-ubuntu-22.04
|
runs-on: arc-linux-latest
|
||||||
env:
|
env:
|
||||||
RUSTUP_PERMIT_COPY_RENAME: 1
|
RUSTUP_PERMIT_COPY_RENAME: 1
|
||||||
defaults:
|
defaults:
|
||||||
|
|||||||
@@ -6,16 +6,14 @@ on:
|
|||||||
paths:
|
paths:
|
||||||
- "ts-packages/**"
|
- "ts-packages/**"
|
||||||
- "sdk/typescript/**"
|
- "sdk/typescript/**"
|
||||||
- "nym-connect/desktop/src/**"
|
|
||||||
- "nym-connect/desktop/package.json"
|
|
||||||
- "nym-wallet/src/**"
|
- "nym-wallet/src/**"
|
||||||
- "nym-wallet/package.json"
|
- "nym-wallet/package.json"
|
||||||
- "explorer/**"
|
- "explorer-v2/**"
|
||||||
- ".github/workflows/ci-lint-typescript.yml"
|
- ".github/workflows/ci-lint-typescript.yml"
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-22.04
|
runs-on: arc-linux-latest
|
||||||
env:
|
env:
|
||||||
RUSTUP_PERMIT_COPY_RENAME: 1
|
RUSTUP_PERMIT_COPY_RENAME: 1
|
||||||
steps:
|
steps:
|
||||||
@@ -25,6 +23,7 @@ jobs:
|
|||||||
- uses: actions/setup-node@v4
|
- uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: 20
|
node-version: 20
|
||||||
|
|
||||||
- name: Setup yarn
|
- name: Setup yarn
|
||||||
run: npm install -g yarn
|
run: npm install -g yarn
|
||||||
|
|
||||||
@@ -37,14 +36,12 @@ jobs:
|
|||||||
run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
|
run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
|
||||||
|
|
||||||
- name: Install wasm-opt
|
- name: Install wasm-opt
|
||||||
uses: ./.github/actions/install-wasm-opt
|
run: cargo install wasm-opt
|
||||||
with:
|
|
||||||
version: '116'
|
|
||||||
|
|
||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@v6
|
||||||
with:
|
with:
|
||||||
go-version: "1.23.7"
|
go-version: "1.24.6"
|
||||||
|
|
||||||
- name: Install
|
- name: Install
|
||||||
run: yarn
|
run: yarn
|
||||||
@@ -52,7 +49,11 @@ jobs:
|
|||||||
- name: Build packages
|
- name: Build packages
|
||||||
run: yarn build:ci
|
run: yarn build:ci
|
||||||
|
|
||||||
|
- name: Install again
|
||||||
|
run: yarn
|
||||||
|
|
||||||
- name: Lint
|
- name: Lint
|
||||||
run: yarn lint
|
run: yarn lint
|
||||||
|
|
||||||
- name: Typecheck with tsc
|
- name: Typecheck with tsc
|
||||||
run: yarn tsc
|
run: yarn tsc
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ on:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: custom-linux
|
runs-on: arc-linux-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
|||||||
@@ -4,10 +4,10 @@ on:
|
|||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
pull_request:
|
pull_request:
|
||||||
paths:
|
paths:
|
||||||
- 'wasm/**'
|
- "wasm/**"
|
||||||
- 'clients/client-core/**'
|
- "clients/client-core/**"
|
||||||
- 'common/**'
|
- "common/**"
|
||||||
- '.github/workflows/ci-sdk-wasm.yml'
|
- ".github/workflows/ci-sdk-wasm.yml"
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
wasm:
|
wasm:
|
||||||
@@ -33,7 +33,7 @@ jobs:
|
|||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: "1.23.7"
|
go-version: "1.24.6"
|
||||||
|
|
||||||
- name: Install wasm-pack
|
- name: Install wasm-pack
|
||||||
run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
|
run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
|
||||||
@@ -41,7 +41,7 @@ jobs:
|
|||||||
- name: Install wasm-opt
|
- name: Install wasm-opt
|
||||||
uses: ./.github/actions/install-wasm-opt
|
uses: ./.github/actions/install-wasm-opt
|
||||||
with:
|
with:
|
||||||
version: '116'
|
version: "116"
|
||||||
|
|
||||||
- name: Install wasm-bindgen-cli
|
- name: Install wasm-bindgen-cli
|
||||||
run: cargo install wasm-bindgen-cli
|
run: cargo install wasm-bindgen-cli
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ jobs:
|
|||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
- os: arc-ubuntu-22.04
|
- os: arc-linux-latest
|
||||||
target: x86_64-unknown-linux-gnu
|
target: x86_64-unknown-linux-gnu
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
|
|
||||||
@@ -30,11 +30,13 @@ jobs:
|
|||||||
release_date: ${{ fromJSON(steps.create-release.outputs.assets)[0].published_at }}
|
release_date: ${{ fromJSON(steps.create-release.outputs.assets)[0].published_at }}
|
||||||
client_hash: ${{ steps.binary-hashes.outputs.client_hash }}
|
client_hash: ${{ steps.binary-hashes.outputs.client_hash }}
|
||||||
nymvisor_hash: ${{ steps.binary-hashes.outputs.nymvisor_hash }}
|
nymvisor_hash: ${{ steps.binary-hashes.outputs.nymvisor_hash }}
|
||||||
|
nymnode_hash: ${{ steps.binary-hashes.outputs.nymnode_hash }}
|
||||||
socks5_hash: ${{ steps.binary-hashes.outputs.socks5_hash }}
|
socks5_hash: ${{ steps.binary-hashes.outputs.socks5_hash }}
|
||||||
netreq_hash: ${{ steps.binary-hashes.outputs.netreq_hash }}
|
netreq_hash: ${{ steps.binary-hashes.outputs.netreq_hash }}
|
||||||
cli_hash: ${{ steps.binary-hashes.outputs.cli_hash }}
|
cli_hash: ${{ steps.binary-hashes.outputs.cli_hash }}
|
||||||
client_version: ${{ steps.binary-versions.outputs.client_version }}
|
client_version: ${{ steps.binary-versions.outputs.client_version }}
|
||||||
nymvisor_version: ${{ steps.binary-versions.outputs.nymvisor_version }}
|
nymvisor_version: ${{ steps.binary-versions.outputs.nymvisor_version }}
|
||||||
|
nymnode_version: ${{ steps.binary-versions.outputs.nymnode_version }}
|
||||||
socks5_version: ${{ steps.binary-versions.outputs.socks5_version }}
|
socks5_version: ${{ steps.binary-versions.outputs.socks5_version }}
|
||||||
netreq_version: ${{ steps.binary-versions.outputs.netreq_version }}
|
netreq_version: ${{ steps.binary-versions.outputs.netreq_version }}
|
||||||
cli_version: ${{ steps.binary-versions.outputs.cli_version }}
|
cli_version: ${{ steps.binary-versions.outputs.cli_version }}
|
||||||
@@ -74,6 +76,7 @@ jobs:
|
|||||||
target/release/nym-network-requester
|
target/release/nym-network-requester
|
||||||
target/release/nym-cli
|
target/release/nym-cli
|
||||||
target/release/nymvisor
|
target/release/nymvisor
|
||||||
|
target/release/nym-node
|
||||||
retention-days: 30
|
retention-days: 30
|
||||||
|
|
||||||
- id: create-release
|
- id: create-release
|
||||||
@@ -88,6 +91,7 @@ jobs:
|
|||||||
target/release/nym-network-requester
|
target/release/nym-network-requester
|
||||||
target/release/nym-cli
|
target/release/nym-cli
|
||||||
target/release/nymvisor
|
target/release/nymvisor
|
||||||
|
target/release/nym-node
|
||||||
|
|
||||||
push-release-data-client:
|
push-release-data-client:
|
||||||
if: ${{ (startsWith(github.ref, 'refs/tags/nym-binaries-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
|
if: ${{ (startsWith(github.ref, 'refs/tags/nym-binaries-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ on:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
publish:
|
publish:
|
||||||
runs-on: arc-ubuntu-22.04
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
@@ -17,10 +17,13 @@ jobs:
|
|||||||
- name: Setup yarn
|
- name: Setup yarn
|
||||||
run: npm install -g yarn
|
run: npm install -g yarn
|
||||||
|
|
||||||
- name: Install Rust stable
|
- name: Install rust toolchain
|
||||||
uses: actions-rs/toolchain@v1
|
uses: actions-rs/toolchain@v1
|
||||||
with:
|
with:
|
||||||
|
profile: minimal
|
||||||
toolchain: stable
|
toolchain: stable
|
||||||
|
override: true
|
||||||
|
components: rustfmt, clippy
|
||||||
|
|
||||||
- name: Install wasm-pack
|
- name: Install wasm-pack
|
||||||
run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
|
run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
|
||||||
@@ -29,9 +32,9 @@ jobs:
|
|||||||
run: cargo install wasm-opt
|
run: cargo install wasm-opt
|
||||||
|
|
||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@v6
|
||||||
with:
|
with:
|
||||||
go-version: "1.23.7"
|
go-version: "1.24.6"
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: yarn
|
run: yarn
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ env:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build-container:
|
build-container:
|
||||||
runs-on: arc-ubuntu-22.04-dind
|
runs-on: arc-linux-latest-dind
|
||||||
steps:
|
steps:
|
||||||
- name: Login to Harbor
|
- name: Login to Harbor
|
||||||
uses: docker/login-action@v3
|
uses: docker/login-action@v3
|
||||||
|
|||||||
@@ -3,11 +3,6 @@ name: Build and upload Node Status agent container to harbor.nymte.ch
|
|||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
inputs:
|
inputs:
|
||||||
gateway_probe_git_ref:
|
|
||||||
type: string
|
|
||||||
default: nym-vpn-core-v1.4.0
|
|
||||||
required: true
|
|
||||||
description: Which gateway probe git ref to build the image with
|
|
||||||
release_image:
|
release_image:
|
||||||
description: 'Tag image as a release'
|
description: 'Tag image as a release'
|
||||||
required: true
|
required: true
|
||||||
@@ -20,7 +15,7 @@ env:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build-container:
|
build-container:
|
||||||
runs-on: arc-ubuntu-22.04-dind
|
runs-on: arc-linux-latest-dind
|
||||||
steps:
|
steps:
|
||||||
- name: Login to Harbor
|
- name: Login to Harbor
|
||||||
uses: docker/login-action@v3
|
uses: docker/login-action@v3
|
||||||
@@ -43,16 +38,6 @@ jobs:
|
|||||||
VERSION=$(yq -oy '.package.version' ${{ env.WORKING_DIRECTORY }}/Cargo.toml)
|
VERSION=$(yq -oy '.package.version' ${{ env.WORKING_DIRECTORY }}/Cargo.toml)
|
||||||
echo "result=$VERSION" >> $GITHUB_OUTPUT
|
echo "result=$VERSION" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: cleanup-gateway-probe-ref
|
|
||||||
id: cleanup_gateway_probe_ref
|
|
||||||
run: |
|
|
||||||
GATEWAY_PROBE_GIT_REF=${{ github.event.inputs.gateway_probe_git_ref }}
|
|
||||||
GIT_REF_SLUG="${GATEWAY_PROBE_GIT_REF//\//-}"
|
|
||||||
echo "git_ref=${GIT_REF_SLUG}" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
- name: Set GIT_TAG variable
|
|
||||||
run: echo "GIT_TAG=${{ env.WORKING_DIRECTORY }}-${{ steps.get_version.outputs.result }}-${{ steps.cleanup_gateway_probe_ref.outputs.git_ref }}" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Initialize RELEASE_TAG
|
- name: Initialize RELEASE_TAG
|
||||||
run: echo "RELEASE_TAG=" >> $GITHUB_ENV
|
run: echo "RELEASE_TAG=" >> $GITHUB_ENV
|
||||||
|
|
||||||
@@ -61,24 +46,12 @@ jobs:
|
|||||||
run: echo "RELEASE_TAG=golden-" >> $GITHUB_ENV
|
run: echo "RELEASE_TAG=golden-" >> $GITHUB_ENV
|
||||||
|
|
||||||
- name: Set IMAGE_NAME_AND_TAGS variable
|
- name: Set IMAGE_NAME_AND_TAGS variable
|
||||||
run: echo "IMAGE_NAME_AND_TAGS=${{ env.CONTAINER_NAME }}:${{ env.RELEASE_TAG }}${{ steps.get_version.outputs.result }}-${{ steps.cleanup_gateway_probe_ref.outputs.git_ref }}" >> $GITHUB_ENV
|
run: echo "IMAGE_NAME_AND_TAGS=${{ env.CONTAINER_NAME }}:${{ env.RELEASE_TAG }}${{ steps.get_version.outputs.result }}" >> $GITHUB_ENV
|
||||||
|
|
||||||
- name: New env vars
|
- name: New env vars
|
||||||
run: echo "RELEASE_TAG='$RELEASE_TAG' GIT_TAG='$GIT_TAG' IMAGE_NAME_AND_TAGS='$IMAGE_NAME_AND_TAGS'"
|
run: echo "RELEASE_TAG='$RELEASE_TAG' IMAGE_NAME_AND_TAGS='$IMAGE_NAME_AND_TAGS'"
|
||||||
|
|
||||||
# - name: Remove existing tag if exists
|
|
||||||
# run: |
|
|
||||||
# if git rev-parse $${{ env.GIT_TAG }} >/dev/null 2>&1; then
|
|
||||||
# git push --delete origin $${{ env.GIT_TAG }}
|
|
||||||
# git tag -d $${{ env.GIT_TAG }}
|
|
||||||
# fi
|
|
||||||
|
|
||||||
# - name: Create tag
|
|
||||||
# run: |
|
|
||||||
# git tag -a $${{ env.GIT_TAG }} -m "Version ${{ steps.get_version.outputs.result }}-${{ steps.cleanup_gateway_probe_ref.outputs.git_ref }}"
|
|
||||||
# git push origin $${{ env.GIT_TAG }}
|
|
||||||
|
|
||||||
- name: BuildAndPushImageOnHarbor
|
- name: BuildAndPushImageOnHarbor
|
||||||
run: |
|
run: |
|
||||||
docker build --build-arg GIT_REF=${{ github.event.inputs.gateway_probe_git_ref }} -f ${{ env.WORKING_DIRECTORY }}/Dockerfile . -t harbor.nymte.ch/nym/${{ env.IMAGE_NAME_AND_TAGS }}
|
docker build -f ${{ env.WORKING_DIRECTORY }}/Dockerfile . -t harbor.nymte.ch/nym/${{ env.IMAGE_NAME_AND_TAGS }}
|
||||||
docker push harbor.nymte.ch/nym/${{ env.CONTAINER_NAME }} --all-tags
|
docker push harbor.nymte.ch/nym/${{ env.CONTAINER_NAME }} --all-tags
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ env:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build-container:
|
build-container:
|
||||||
runs-on: arc-ubuntu-22.04-dind
|
runs-on: arc-linux-latest-dind
|
||||||
steps:
|
steps:
|
||||||
- name: Login to Harbor
|
- name: Login to Harbor
|
||||||
uses: docker/login-action@v3
|
uses: docker/login-action@v3
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ env:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build-container:
|
build-container:
|
||||||
runs-on: arc-ubuntu-22.04-dind
|
runs-on: arc-linux-latest-dind
|
||||||
steps:
|
steps:
|
||||||
- name: Login to Harbor
|
- name: Login to Harbor
|
||||||
uses: docker/login-action@v3
|
uses: docker/login-action@v3
|
||||||
|
|||||||
+162
@@ -4,6 +4,168 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
|
|||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
## [2025.19-kase] (2025-10-30)
|
||||||
|
|
||||||
|
- update ns agent workflow ([#6154])
|
||||||
|
- Cherry pick - request #6143 from nymtech/bugfix/mix-tx-closed-v2 ([#6153])
|
||||||
|
- bugfix: nym-credential-proxy query params parsing regression ([#6121])
|
||||||
|
- bugfix: revert some dep updates introduced in #6043 ([#6120])
|
||||||
|
- Skip ipv6 metadata endpoint request ([#6118])
|
||||||
|
- update to no longer use 1mb files ([#6117])
|
||||||
|
- chore: restore pending dkg contract state migration ([#6116])
|
||||||
|
- Revert "Propagate cancel token to mixnet client" ([#6115])
|
||||||
|
- Update dirs to 6.0 ([#6109])
|
||||||
|
- Propagate cancel token to mixnet client ([#6105])
|
||||||
|
- bugfix: retrieve and update ticketbook in the same query ([#6101])
|
||||||
|
- bugfix: include network name in the default gateway probe config path ([#6100])
|
||||||
|
- Bugfix/incompatibility fixes ([#6099])
|
||||||
|
- [DOCs/operators] QUIC deployment script & docs ([#6098])
|
||||||
|
- bugfix: testnet manager 02sql migration ([#6096])
|
||||||
|
- feat: move gateway probe to monorepo (and update to rust edition 2024) ([#6094])
|
||||||
|
- bugfix: use custom topology provider for list of init gateways ([#6092])
|
||||||
|
- Max/fix wasm client + build commands ([#6043])
|
||||||
|
|
||||||
|
[#6154]: https://github.com/nymtech/nym/pull/6154
|
||||||
|
[#6153]: https://github.com/nymtech/nym/pull/6153
|
||||||
|
[#6121]: https://github.com/nymtech/nym/pull/6121
|
||||||
|
[#6120]: https://github.com/nymtech/nym/pull/6120
|
||||||
|
[#6118]: https://github.com/nymtech/nym/pull/6118
|
||||||
|
[#6117]: https://github.com/nymtech/nym/pull/6117
|
||||||
|
[#6116]: https://github.com/nymtech/nym/pull/6116
|
||||||
|
[#6115]: https://github.com/nymtech/nym/pull/6115
|
||||||
|
[#6109]: https://github.com/nymtech/nym/pull/6109
|
||||||
|
[#6105]: https://github.com/nymtech/nym/pull/6105
|
||||||
|
[#6101]: https://github.com/nymtech/nym/pull/6101
|
||||||
|
[#6100]: https://github.com/nymtech/nym/pull/6100
|
||||||
|
[#6099]: https://github.com/nymtech/nym/pull/6099
|
||||||
|
[#6098]: https://github.com/nymtech/nym/pull/6098
|
||||||
|
[#6096]: https://github.com/nymtech/nym/pull/6096
|
||||||
|
[#6094]: https://github.com/nymtech/nym/pull/6094
|
||||||
|
[#6092]: https://github.com/nymtech/nym/pull/6092
|
||||||
|
[#6043]: https://github.com/nymtech/nym/pull/6043
|
||||||
|
|
||||||
|
## [2025.18-jarlsberg] (2025-10-14)
|
||||||
|
|
||||||
|
- ns-api: add descriptions to dVPN gateway responses ([#6102])
|
||||||
|
- NS API: use new probe download filesize and milliseconds field ([#6097])
|
||||||
|
- ns-api: use download files size from probes instead of parsing filenames ([#6095])
|
||||||
|
- ns-api: add new fields for probe output for query_metadata and download file size and duration in ms ([#6091])
|
||||||
|
- Bugfix/bloomfilters purge ([#6089])
|
||||||
|
- Hotfix: Update API source in node ping tester script ([#6082])
|
||||||
|
- Get wireguard keypair as arg instead of reading it from disk ([#6078])
|
||||||
|
- Feature: Ping probe all nodes /described nodes from a server ([#6074])
|
||||||
|
- Node Status API: add bridge information to dVPN endpoint ([#6069])
|
||||||
|
- frontdoor typo fix ([#6067])
|
||||||
|
- Feature: Node rewards tracker ([#6064])
|
||||||
|
- [chore] Clippy fix ([#6060])
|
||||||
|
- Registration Client ([#6059])
|
||||||
|
- Bugfix: Nym node CLI download nym-node exception ([#6058])
|
||||||
|
- Feature: Nym node html landing page ([#6053])
|
||||||
|
- feat: DKG contract method for updating announce address ([#6050])
|
||||||
|
- feat: NS ticket faucet ([#6047])
|
||||||
|
- Bridge proto client params in Self-Described ([#6035])
|
||||||
|
- Node Status API: remove sqlite support ([#6004])
|
||||||
|
- Benny/ci contract fix ([#5962])
|
||||||
|
|
||||||
|
[#6102]: https://github.com/nymtech/nym/pull/6102
|
||||||
|
[#6097]: https://github.com/nymtech/nym/pull/6097
|
||||||
|
[#6095]: https://github.com/nymtech/nym/pull/6095
|
||||||
|
[#6091]: https://github.com/nymtech/nym/pull/6091
|
||||||
|
[#6089]: https://github.com/nymtech/nym/pull/6089
|
||||||
|
[#6082]: https://github.com/nymtech/nym/pull/6082
|
||||||
|
[#6078]: https://github.com/nymtech/nym/pull/6078
|
||||||
|
[#6074]: https://github.com/nymtech/nym/pull/6074
|
||||||
|
[#6069]: https://github.com/nymtech/nym/pull/6069
|
||||||
|
[#6067]: https://github.com/nymtech/nym/pull/6067
|
||||||
|
[#6064]: https://github.com/nymtech/nym/pull/6064
|
||||||
|
[#6060]: https://github.com/nymtech/nym/pull/6060
|
||||||
|
[#6059]: https://github.com/nymtech/nym/pull/6059
|
||||||
|
[#6058]: https://github.com/nymtech/nym/pull/6058
|
||||||
|
[#6053]: https://github.com/nymtech/nym/pull/6053
|
||||||
|
[#6050]: https://github.com/nymtech/nym/pull/6050
|
||||||
|
[#6047]: https://github.com/nymtech/nym/pull/6047
|
||||||
|
[#6035]: https://github.com/nymtech/nym/pull/6035
|
||||||
|
[#6004]: https://github.com/nymtech/nym/pull/6004
|
||||||
|
[#5962]: https://github.com/nymtech/nym/pull/5962
|
||||||
|
|
||||||
|
## [2025.17-isabirra] (2025-09-29)
|
||||||
|
|
||||||
|
- Bugfix | Fix the registration handshake ([#6062])
|
||||||
|
- Convenience for ShutdownTracker ([#6038])
|
||||||
|
- chore: made http-api-client-macro doctest compile ([#6037])
|
||||||
|
- feat: refresh mixnet contract on epoch progression ([#6023])
|
||||||
|
- chore: remove legacy nodes from nym api [and kinda-ish from node status api] ([#6021])
|
||||||
|
- Feature/credential proxy crate ([#6018])
|
||||||
|
- Moving clients crate from vpn-client repo to here ([#6015])
|
||||||
|
- Feature/cancellation migration ([#6014])
|
||||||
|
- Use default value for the ports until api is deployed ([#6007])
|
||||||
|
- bugfix: return from MixTrafficController if client request channel has closed ([#6002])
|
||||||
|
- Revert "Create an axum_test client for more integrated unit testing (… ([#5999])
|
||||||
|
- chore: upgraded syn to 2.0 and removed nym-execute ([#5998])
|
||||||
|
- feat: use `ShutdownToken` (`CancellationToken` inside) for nym-api ([#5997])
|
||||||
|
- bugfix: Recipient deserialisation for deserialisers missing bytes specialisation ([#5991])
|
||||||
|
- chore: use updated version of simulate endpoint ([#5988])
|
||||||
|
- chore: purge temp databases on build ([#5984])
|
||||||
|
- Bump sha.js from 2.4.11 to 2.4.12 ([#5983])
|
||||||
|
- Feature: Delegation program stake checker and adjuster ([#5980])
|
||||||
|
- build(deps): bump actions/setup-java from 4 to 5 ([#5975])
|
||||||
|
- Domain fronting integration ([#5974])
|
||||||
|
- chore: internal hidden command to force advance nyx epoch ([#5964])
|
||||||
|
- Create an axum_test client for more integrated unit testing ([#5956])
|
||||||
|
- feat: shared library for attempting to retrieve update mode attestation ([#5954])
|
||||||
|
- Bump slab from 0.4.10 to 0.4.11 ([#5952])
|
||||||
|
- build(deps): bump actions/first-interaction from 1 to 3 ([#5950])
|
||||||
|
- fix: use WASM compatible time API in client ([#5948])
|
||||||
|
- feat: credential proxy deposit pool ([#5945])
|
||||||
|
- build(deps): bump actions/download-artifact from 4 to 5 ([#5939])
|
||||||
|
- feat: nym signers monitor ([#5933])
|
||||||
|
- Bump console from 0.15.11 to 0.16.0 ([#5931])
|
||||||
|
- Bump mock_instant from 0.5.3 to 0.6.0 ([#5930])
|
||||||
|
- Bump tokio from 1.46.1 to 1.47.1 ([#5929])
|
||||||
|
- Bump defguard_wireguard_rs from v0.4.7 to v0.7.5 ([#5928])
|
||||||
|
- Bump indicatif from 0.17.11 to 0.18.0 ([#5924])
|
||||||
|
- Feature: Nym node autorun CLI ([#5916])
|
||||||
|
- build(deps): bump mikefarah/yq from 4.45.4 to 4.47.1 ([#5911])
|
||||||
|
- build(deps): bump pbkdf2 from 3.1.2 to 3.1.3 ([#5869])
|
||||||
|
|
||||||
|
[#6062]: https://github.com/nymtech/nym/pull/6062
|
||||||
|
[#6038]: https://github.com/nymtech/nym/pull/6038
|
||||||
|
[#6037]: https://github.com/nymtech/nym/pull/6037
|
||||||
|
[#6023]: https://github.com/nymtech/nym/pull/6023
|
||||||
|
[#6021]: https://github.com/nymtech/nym/pull/6021
|
||||||
|
[#6018]: https://github.com/nymtech/nym/pull/6018
|
||||||
|
[#6015]: https://github.com/nymtech/nym/pull/6015
|
||||||
|
[#6014]: https://github.com/nymtech/nym/pull/6014
|
||||||
|
[#6007]: https://github.com/nymtech/nym/pull/6007
|
||||||
|
[#6002]: https://github.com/nymtech/nym/pull/6002
|
||||||
|
[#5999]: https://github.com/nymtech/nym/pull/5999
|
||||||
|
[#5998]: https://github.com/nymtech/nym/pull/5998
|
||||||
|
[#5997]: https://github.com/nymtech/nym/pull/5997
|
||||||
|
[#5991]: https://github.com/nymtech/nym/pull/5991
|
||||||
|
[#5988]: https://github.com/nymtech/nym/pull/5988
|
||||||
|
[#5984]: https://github.com/nymtech/nym/pull/5984
|
||||||
|
[#5983]: https://github.com/nymtech/nym/pull/5983
|
||||||
|
[#5980]: https://github.com/nymtech/nym/pull/5980
|
||||||
|
[#5975]: https://github.com/nymtech/nym/pull/5975
|
||||||
|
[#5974]: https://github.com/nymtech/nym/pull/5974
|
||||||
|
[#5964]: https://github.com/nymtech/nym/pull/5964
|
||||||
|
[#5956]: https://github.com/nymtech/nym/pull/5956
|
||||||
|
[#5954]: https://github.com/nymtech/nym/pull/5954
|
||||||
|
[#5952]: https://github.com/nymtech/nym/pull/5952
|
||||||
|
[#5950]: https://github.com/nymtech/nym/pull/5950
|
||||||
|
[#5948]: https://github.com/nymtech/nym/pull/5948
|
||||||
|
[#5945]: https://github.com/nymtech/nym/pull/5945
|
||||||
|
[#5939]: https://github.com/nymtech/nym/pull/5939
|
||||||
|
[#5933]: https://github.com/nymtech/nym/pull/5933
|
||||||
|
[#5931]: https://github.com/nymtech/nym/pull/5931
|
||||||
|
[#5930]: https://github.com/nymtech/nym/pull/5930
|
||||||
|
[#5929]: https://github.com/nymtech/nym/pull/5929
|
||||||
|
[#5928]: https://github.com/nymtech/nym/pull/5928
|
||||||
|
[#5924]: https://github.com/nymtech/nym/pull/5924
|
||||||
|
[#5916]: https://github.com/nymtech/nym/pull/5916
|
||||||
|
[#5911]: https://github.com/nymtech/nym/pull/5911
|
||||||
|
[#5869]: https://github.com/nymtech/nym/pull/5869
|
||||||
|
|
||||||
## [2025.16-halloumi] (2025-09-16)
|
## [2025.16-halloumi] (2025-09-16)
|
||||||
|
|
||||||
- Backport metadata endpoint ([#6010])
|
- Backport metadata endpoint ([#6010])
|
||||||
|
|||||||
Generated
+1329
-1068
File diff suppressed because it is too large
Load Diff
+34
-33
@@ -31,6 +31,7 @@ members = [
|
|||||||
"common/client-libs/mixnet-client",
|
"common/client-libs/mixnet-client",
|
||||||
"common/client-libs/validator-client",
|
"common/client-libs/validator-client",
|
||||||
"common/commands",
|
"common/commands",
|
||||||
|
"common/nym-common",
|
||||||
"common/config",
|
"common/config",
|
||||||
"common/cosmwasm-smart-contracts/coconut-dkg",
|
"common/cosmwasm-smart-contracts/coconut-dkg",
|
||||||
"common/cosmwasm-smart-contracts/contracts-common",
|
"common/cosmwasm-smart-contracts/contracts-common",
|
||||||
@@ -58,7 +59,8 @@ members = [
|
|||||||
"common/gateway-requests",
|
"common/gateway-requests",
|
||||||
"common/gateway-stats-storage",
|
"common/gateway-stats-storage",
|
||||||
"common/gateway-storage",
|
"common/gateway-storage",
|
||||||
"common/http-api-client", "common/http-api-client-macro",
|
"common/http-api-client",
|
||||||
|
"common/http-api-client-macro",
|
||||||
"common/http-api-common",
|
"common/http-api-common",
|
||||||
"common/inclusion-probability",
|
"common/inclusion-probability",
|
||||||
"common/ip-packet-requests",
|
"common/ip-packet-requests",
|
||||||
@@ -67,6 +69,8 @@ members = [
|
|||||||
"common/network-defaults",
|
"common/network-defaults",
|
||||||
"common/node-tester-utils",
|
"common/node-tester-utils",
|
||||||
"common/nonexhaustive-delayqueue",
|
"common/nonexhaustive-delayqueue",
|
||||||
|
"common/nym-cache",
|
||||||
|
"common/nym-connection-monitor",
|
||||||
"common/nym-id",
|
"common/nym-id",
|
||||||
"common/nym-metrics",
|
"common/nym-metrics",
|
||||||
"common/nym_offline_compact_ecash",
|
"common/nym_offline_compact_ecash",
|
||||||
@@ -85,6 +89,7 @@ members = [
|
|||||||
"common/nymsphinx/types",
|
"common/nymsphinx/types",
|
||||||
"common/nyxd-scraper",
|
"common/nyxd-scraper",
|
||||||
"common/pemstore",
|
"common/pemstore",
|
||||||
|
"common/registration",
|
||||||
"common/serde-helpers",
|
"common/serde-helpers",
|
||||||
"common/service-provider-requests-common",
|
"common/service-provider-requests-common",
|
||||||
"common/socks5-client-core",
|
"common/socks5-client-core",
|
||||||
@@ -92,11 +97,13 @@ members = [
|
|||||||
"common/socks5/requests",
|
"common/socks5/requests",
|
||||||
"common/statistics",
|
"common/statistics",
|
||||||
"common/store-cipher",
|
"common/store-cipher",
|
||||||
"common/task", "common/test-utils",
|
"common/task",
|
||||||
|
"common/test-utils",
|
||||||
"common/ticketbooks-merkle",
|
"common/ticketbooks-merkle",
|
||||||
"common/topology",
|
"common/topology",
|
||||||
"common/tun",
|
"common/tun",
|
||||||
"common/types", "common/upgrade-mode-check",
|
"common/types",
|
||||||
|
"common/upgrade-mode-check",
|
||||||
"common/verloc",
|
"common/verloc",
|
||||||
"common/wasm/client-core",
|
"common/wasm/client-core",
|
||||||
"common/wasm/storage",
|
"common/wasm/storage",
|
||||||
@@ -125,10 +132,11 @@ members = [
|
|||||||
"nym-node-status-api/nym-node-status-client",
|
"nym-node-status-api/nym-node-status-client",
|
||||||
"nym-node/nym-node-metrics",
|
"nym-node/nym-node-metrics",
|
||||||
"nym-node/nym-node-requests",
|
"nym-node/nym-node-requests",
|
||||||
"nym-outfox", "nym-signers-monitor",
|
"nym-outfox",
|
||||||
|
"nym-registration-client",
|
||||||
|
"nym-signers-monitor",
|
||||||
"nym-statistics-api",
|
"nym-statistics-api",
|
||||||
"nym-validator-rewarder",
|
"nym-validator-rewarder",
|
||||||
"nym-wg-gateway-client",
|
|
||||||
"nyx-chain-watcher",
|
"nyx-chain-watcher",
|
||||||
"sdk/ffi/cpp",
|
"sdk/ffi/cpp",
|
||||||
"sdk/ffi/go",
|
"sdk/ffi/go",
|
||||||
@@ -142,10 +150,9 @@ members = [
|
|||||||
"tools/internal/contract-state-importer/importer-cli",
|
"tools/internal/contract-state-importer/importer-cli",
|
||||||
"tools/internal/contract-state-importer/importer-contract",
|
"tools/internal/contract-state-importer/importer-contract",
|
||||||
"tools/internal/mixnet-connectivity-check",
|
"tools/internal/mixnet-connectivity-check",
|
||||||
# "tools/internal/sdk-version-bump",
|
# "tools/internal/sdk-version-bump",
|
||||||
"tools/internal/ssl-inject",
|
"tools/internal/ssl-inject",
|
||||||
"tools/internal/testnet-manager",
|
"tools/internal/testnet-manager",
|
||||||
"tools/internal/testnet-manager",
|
|
||||||
"tools/internal/testnet-manager/dkg-bypass-contract",
|
"tools/internal/testnet-manager/dkg-bypass-contract",
|
||||||
"tools/internal/validator-status-check",
|
"tools/internal/validator-status-check",
|
||||||
"tools/nym-cli",
|
"tools/nym-cli",
|
||||||
@@ -158,7 +165,8 @@ members = [
|
|||||||
"wasm/mix-fetch",
|
"wasm/mix-fetch",
|
||||||
"wasm/node-tester",
|
"wasm/node-tester",
|
||||||
"wasm/zknym-lib",
|
"wasm/zknym-lib",
|
||||||
]
|
"nym-gateway-probe"
|
||||||
|
, "query-tester"]
|
||||||
|
|
||||||
default-members = [
|
default-members = [
|
||||||
"clients/native",
|
"clients/native",
|
||||||
@@ -176,16 +184,16 @@ default-members = [
|
|||||||
"tools/nymvisor",
|
"tools/nymvisor",
|
||||||
]
|
]
|
||||||
|
|
||||||
exclude = ["explorer", "contracts", "nym-wallet", "cpu-cycles"]
|
exclude = ["contracts", "nym-wallet", "cpu-cycles"]
|
||||||
|
|
||||||
[workspace.package]
|
[workspace.package]
|
||||||
authors = ["Nym Technologies SA"]
|
authors = ["Nym Technologies SA"]
|
||||||
repository = "https://github.com/nymtech/nym"
|
repository = "https://github.com/nymtech/nym"
|
||||||
homepage = "https://nymtech.net"
|
homepage = "https://nymtech.net"
|
||||||
documentation = "https://nymtech.net"
|
documentation = "https://nymtech.net"
|
||||||
edition = "2021"
|
edition = "2024"
|
||||||
license = "Apache-2.0"
|
license = "Apache-2.0"
|
||||||
rust-version = "1.81"
|
rust-version = "1.85"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
@@ -207,7 +215,6 @@ base64 = "0.22.1"
|
|||||||
base85rs = "0.1.3"
|
base85rs = "0.1.3"
|
||||||
bincode = "1.3.3"
|
bincode = "1.3.3"
|
||||||
bip39 = { version = "2.0.0", features = ["zeroize"] }
|
bip39 = { version = "2.0.0", features = ["zeroize"] }
|
||||||
bit-vec = "0.7.0" # can we unify those?
|
|
||||||
bitvec = "1.0.0"
|
bitvec = "1.0.0"
|
||||||
blake3 = "1.7.0"
|
blake3 = "1.7.0"
|
||||||
bloomfilter = "3.0.1"
|
bloomfilter = "3.0.1"
|
||||||
@@ -235,13 +242,11 @@ criterion = "0.5"
|
|||||||
csv = "1.3.1"
|
csv = "1.3.1"
|
||||||
ctr = "0.9.1"
|
ctr = "0.9.1"
|
||||||
cupid = "0.6.1"
|
cupid = "0.6.1"
|
||||||
curve25519-dalek = "4.1"
|
|
||||||
dashmap = "5.5.3"
|
dashmap = "5.5.3"
|
||||||
# We want https://github.com/DefGuard/wireguard-rs/pull/64 , but there's no crates.io release being pushed out anymore
|
# We want https://github.com/DefGuard/wireguard-rs/pull/64 , but there's no crates.io release being pushed out anymore
|
||||||
defguard_wireguard_rs = { git = "https://github.com/DefGuard/wireguard-rs.git", rev = "v0.4.7" }
|
defguard_wireguard_rs = { git = "https://github.com/DefGuard/wireguard-rs.git", rev = "v0.4.7" }
|
||||||
digest = "0.10.7"
|
digest = "0.10.7"
|
||||||
dirs = "5.0"
|
dirs = "6.0"
|
||||||
doc-comment = "0.3"
|
|
||||||
dotenvy = "0.15.6"
|
dotenvy = "0.15.6"
|
||||||
dyn-clone = "1.0.19"
|
dyn-clone = "1.0.19"
|
||||||
ecdsa = "0.16"
|
ecdsa = "0.16"
|
||||||
@@ -257,11 +262,8 @@ futures = "0.3.31"
|
|||||||
futures-util = "0.3"
|
futures-util = "0.3"
|
||||||
generic-array = "0.14.7"
|
generic-array = "0.14.7"
|
||||||
getrandom = "0.2.10"
|
getrandom = "0.2.10"
|
||||||
getset = "0.1.5"
|
|
||||||
handlebars = "3.5.5"
|
handlebars = "3.5.5"
|
||||||
headers = "0.4.0"
|
|
||||||
hex = "0.4.3"
|
hex = "0.4.3"
|
||||||
hex-literal = "0.3.3"
|
|
||||||
hickory-resolver = "0.25"
|
hickory-resolver = "0.25"
|
||||||
hkdf = "0.12.3"
|
hkdf = "0.12.3"
|
||||||
hmac = "0.12.1"
|
hmac = "0.12.1"
|
||||||
@@ -285,23 +287,18 @@ lazy_static = "1.5.0"
|
|||||||
ledger-transport = "0.10.0"
|
ledger-transport = "0.10.0"
|
||||||
ledger-transport-hid = "0.10.0"
|
ledger-transport-hid = "0.10.0"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
maxminddb = "0.23.0"
|
|
||||||
mime = "0.3.17"
|
mime = "0.3.17"
|
||||||
moka = { version = "0.12", features = ["future"] }
|
moka = { version = "0.12", features = ["future"] }
|
||||||
nix = "0.27.1"
|
nix = "0.27.1"
|
||||||
notify = "5.1.0"
|
notify = "5.1.0"
|
||||||
okapi = "0.7.0"
|
|
||||||
once_cell = "1.21.3"
|
once_cell = "1.21.3"
|
||||||
opentelemetry = "0.30.0"
|
opentelemetry = "0.19.0"
|
||||||
opentelemetry-otlp = "0.30.0"
|
opentelemetry-jaeger = "0.18.0"
|
||||||
opentelemetry-semantic-conventions = "0.30.0"
|
|
||||||
opentelemetry_sdk = "0.30.0"
|
|
||||||
opentelemetry-stdout = "0.30.0"
|
|
||||||
parking_lot = "0.12.3"
|
parking_lot = "0.12.3"
|
||||||
pem = "0.8"
|
pem = "0.8"
|
||||||
petgraph = "0.6.5"
|
petgraph = "0.6.5"
|
||||||
pin-project = "1.1"
|
pin-project = "1.1"
|
||||||
pin-project-lite = "0.2.16"
|
pnet_packet = "0.35.0"
|
||||||
publicsuffix = "2.3.0"
|
publicsuffix = "2.3.0"
|
||||||
proc_pidinfo = "0.1.3"
|
proc_pidinfo = "0.1.3"
|
||||||
quote = "1"
|
quote = "1"
|
||||||
@@ -309,13 +306,10 @@ rand = "0.8.5"
|
|||||||
rand_chacha = "0.3"
|
rand_chacha = "0.3"
|
||||||
rand_core = "0.6.3"
|
rand_core = "0.6.3"
|
||||||
rand_distr = "0.4"
|
rand_distr = "0.4"
|
||||||
rand_pcg = "0.3.1"
|
|
||||||
rand_seeder = "0.2.3"
|
|
||||||
rayon = "1.5.1"
|
rayon = "1.5.1"
|
||||||
regex = "1.10.6"
|
regex = "1.10.6"
|
||||||
reqwest = { version = "0.12.15", default-features = false }
|
reqwest = { version = "0.12.15", default-features = false }
|
||||||
rs_merkle = "1.5.0"
|
rs_merkle = "1.5.0"
|
||||||
safer-ffi = "0.1.13"
|
|
||||||
schemars = "0.8.22"
|
schemars = "0.8.22"
|
||||||
semver = "1.0.26"
|
semver = "1.0.26"
|
||||||
serde = "1.0.219"
|
serde = "1.0.219"
|
||||||
@@ -354,15 +348,15 @@ toml = "0.8.22"
|
|||||||
tower = "0.5.2"
|
tower = "0.5.2"
|
||||||
tower-http = "0.5.2"
|
tower-http = "0.5.2"
|
||||||
tracing = "0.1.41"
|
tracing = "0.1.41"
|
||||||
tracing-core = "0.1.33"
|
|
||||||
tracing-log = "0.2"
|
tracing-log = "0.2"
|
||||||
tracing-opentelemetry = "0.31.0"
|
tracing-opentelemetry = "0.19.0"
|
||||||
tracing-serde = "0.2.0"
|
|
||||||
tracing-subscriber = "0.3.19"
|
tracing-subscriber = "0.3.19"
|
||||||
tracing-tree = "0.2.2"
|
tracing-tree = "0.2.2"
|
||||||
tracing-indicatif = "0.3.9"
|
tracing-indicatif = "0.3.9"
|
||||||
|
tracing-test = "0.2.5"
|
||||||
ts-rs = "10.1.0"
|
ts-rs = "10.1.0"
|
||||||
tungstenite = { version = "0.20.1", default-features = false }
|
tungstenite = { version = "0.20.1", default-features = false }
|
||||||
|
typed-builder = "0.23.0"
|
||||||
uniffi = "0.29.2"
|
uniffi = "0.29.2"
|
||||||
uniffi_build = "0.29.0"
|
uniffi_build = "0.29.0"
|
||||||
url = "2.5"
|
url = "2.5"
|
||||||
@@ -371,6 +365,7 @@ utoipa-swagger-ui = "8.1"
|
|||||||
utoipauto = "0.2"
|
utoipauto = "0.2"
|
||||||
uuid = "*"
|
uuid = "*"
|
||||||
vergen = { version = "=8.3.1", default-features = false }
|
vergen = { version = "=8.3.1", default-features = false }
|
||||||
|
vergen-gitcl = { version = "1.0.8", default-features = false }
|
||||||
walkdir = "2"
|
walkdir = "2"
|
||||||
x25519-dalek = "2.0.0"
|
x25519-dalek = "2.0.0"
|
||||||
zeroize = "1.7.0"
|
zeroize = "1.7.0"
|
||||||
@@ -410,18 +405,19 @@ prost = { version = "0.13", default-features = false }
|
|||||||
# wasm-related dependencies
|
# wasm-related dependencies
|
||||||
gloo-utils = "0.2.0"
|
gloo-utils = "0.2.0"
|
||||||
gloo-net = "0.6.0"
|
gloo-net = "0.6.0"
|
||||||
|
gloo-timers = "0.3.0"
|
||||||
|
|
||||||
indexed_db_futures = "0.6.4"
|
indexed_db_futures = "0.6.4"
|
||||||
js-sys = "0.3.76"
|
js-sys = "0.3.76"
|
||||||
serde-wasm-bindgen = "0.6.5"
|
serde-wasm-bindgen = "0.6.5"
|
||||||
tsify = "0.4.5"
|
tsify = "0.4.5"
|
||||||
|
tokio_with_wasm = { version = "0.8.7" }
|
||||||
wasm-bindgen = "0.2.99"
|
wasm-bindgen = "0.2.99"
|
||||||
wasm-bindgen-futures = "0.4.49"
|
wasm-bindgen-futures = "0.4.49"
|
||||||
wasm-bindgen-test = "0.3.49"
|
wasm-bindgen-test = "0.3.49"
|
||||||
wasmtimer = "0.4.1"
|
wasmtimer = "0.4.1"
|
||||||
web-sys = "0.3.76"
|
web-sys = "0.3.76"
|
||||||
|
|
||||||
|
|
||||||
# for local development:
|
# for local development:
|
||||||
#[patch.crates-io]
|
#[patch.crates-io]
|
||||||
#sphinx-packet = { path = "../sphinx" }
|
#sphinx-packet = { path = "../sphinx" }
|
||||||
@@ -457,6 +453,11 @@ opt-level = 'z'
|
|||||||
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(tokio_unstable)'] }
|
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(tokio_unstable)'] }
|
||||||
|
|
||||||
[workspace.lints.clippy]
|
[workspace.lints.clippy]
|
||||||
|
suspicious = "deny"
|
||||||
|
complexity = "deny"
|
||||||
|
perf = "deny"
|
||||||
|
style = "deny"
|
||||||
|
|
||||||
unwrap_used = "deny"
|
unwrap_used = "deny"
|
||||||
expect_used = "deny"
|
expect_used = "deny"
|
||||||
todo = "deny"
|
todo = "deny"
|
||||||
|
|||||||
@@ -109,7 +109,7 @@ sdk-wasm-build:
|
|||||||
$(MAKE) -C wasm/node-tester
|
$(MAKE) -C wasm/node-tester
|
||||||
$(MAKE) -C wasm/mix-fetch
|
$(MAKE) -C wasm/mix-fetch
|
||||||
$(MAKE) -C wasm/zknym-lib
|
$(MAKE) -C wasm/zknym-lib
|
||||||
#$(MAKE) -C wasm/full-nym-wasm
|
# $(MAKE) -C wasm/full-nym-wasm
|
||||||
|
|
||||||
# run this from npm/yarn to ensure tools are in the path, e.g. yarn build:sdk from root of repo
|
# run this from npm/yarn to ensure tools are in the path, e.g. yarn build:sdk from root of repo
|
||||||
sdk-typescript-build:
|
sdk-typescript-build:
|
||||||
@@ -140,7 +140,8 @@ clippy: sdk-wasm-lint
|
|||||||
|
|
||||||
WASM_CONTRACT_DIR := contracts/target/wasm32-unknown-unknown/release
|
WASM_CONTRACT_DIR := contracts/target/wasm32-unknown-unknown/release
|
||||||
# Find every direct contract folder that contains a Cargo.toml
|
# Find every direct contract folder that contains a Cargo.toml
|
||||||
CONTRACT_DIRS := $(shell find contracts -type f -name Cargo.toml \( ! -path "contracts/Cargo.toml" \) | grep -v integration-tests | xargs -n1 dirname | sort -u)
|
#CONTRACT_DIRS := $(shell find contracts -type f -name Cargo.toml \( ! -path "contracts/Cargo.toml" \) | grep -v integration-tests | xargs -n1 dirname | sort -u)
|
||||||
|
CONTRACT_DIRS := contracts/example-contract
|
||||||
|
|
||||||
CONTRACTS_OUT_DIR = contracts/artifacts
|
CONTRACTS_OUT_DIR = contracts/artifacts
|
||||||
|
|
||||||
@@ -154,6 +155,7 @@ CONTRACTS_OUT_DIR = contracts/artifacts
|
|||||||
#
|
#
|
||||||
COSMWASM_OPTIMIZER_IMAGE ?= cosmwasm/optimizer:0.17.0
|
COSMWASM_OPTIMIZER_IMAGE ?= cosmwasm/optimizer:0.17.0
|
||||||
COSMWASM_OPTIMIZER_PLATFORM ?= linux/amd64
|
COSMWASM_OPTIMIZER_PLATFORM ?= linux/amd64
|
||||||
|
COSMWASM_CHECK_IMAGE ?= rust:1.88
|
||||||
|
|
||||||
# Ensure clean build environment and run the optimizer
|
# Ensure clean build environment and run the optimizer
|
||||||
optimize-contracts:
|
optimize-contracts:
|
||||||
@@ -179,6 +181,13 @@ optimize-contracts:
|
|||||||
# Cleanup temporary artefacts directory
|
# Cleanup temporary artefacts directory
|
||||||
@rm -rf artifacts 2>/dev/null || true
|
@rm -rf artifacts 2>/dev/null || true
|
||||||
|
|
||||||
|
# Check artifacts with cosmwasm-check inside the optimizer image
|
||||||
|
docker-check-contracts:
|
||||||
|
@docker run --rm --platform $(COSMWASM_OPTIMIZER_PLATFORM) \
|
||||||
|
-v $(CURDIR):/code --workdir /code \
|
||||||
|
--entrypoint /bin/sh \
|
||||||
|
$(COSMWASM_CHECK_IMAGE) -lc 'apt-get update && apt-get install -y --no-install-recommends llvm-dev libclang-dev pkg-config && export PATH="/usr/local/cargo/bin:/usr/local/rustup/bin:$$PATH" && cargo install cosmwasm-check --locked && WASMER_ENGINE=universal WASMER_COMPILER=singlepass cosmwasm-check contracts/artifacts/*.wasm'
|
||||||
|
|
||||||
wasm-opt-contracts:
|
wasm-opt-contracts:
|
||||||
@for WASM in $(WASM_CONTRACT_DIR)/*.wasm; do \
|
@for WASM in $(WASM_CONTRACT_DIR)/*.wasm; do \
|
||||||
echo "Running wasm-opt on $$WASM"; \
|
echo "Running wasm-opt on $$WASM"; \
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "nym-client"
|
name = "nym-client"
|
||||||
version = "1.1.63"
|
version = "1.1.65"
|
||||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"]
|
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"]
|
||||||
description = "Implementation of the Nym Client"
|
description = "Implementation of the Nym Client"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
rust-version = "1.70"
|
rust-version = "1.85"
|
||||||
license.workspace = true
|
license.workspace = true
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
@@ -46,6 +46,7 @@ nym-bandwidth-controller = { path = "../../common/bandwidth-controller" }
|
|||||||
nym-bin-common = { path = "../../common/bin-common", features = [
|
nym-bin-common = { path = "../../common/bin-common", features = [
|
||||||
"output_format",
|
"output_format",
|
||||||
"clap",
|
"clap",
|
||||||
|
"basic_tracing",
|
||||||
] }
|
] }
|
||||||
nym-client-core = { path = "../../common/client-core", features = [
|
nym-client-core = { path = "../../common/client-core", features = [
|
||||||
"fs-credentials-storage",
|
"fs-credentials-storage",
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ impl SocketClient {
|
|||||||
let ClientInput {
|
let ClientInput {
|
||||||
connection_command_sender,
|
connection_command_sender,
|
||||||
input_sender,
|
input_sender,
|
||||||
|
..
|
||||||
} = client_input;
|
} = client_input;
|
||||||
|
|
||||||
let ClientOutput {
|
let ClientOutput {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
|
|
||||||
use clap::{crate_name, crate_version, Parser};
|
use clap::{crate_name, crate_version, Parser};
|
||||||
use nym_bin_common::logging::{maybe_print_banner, setup_no_otel_logger};
|
use nym_bin_common::logging::{maybe_print_banner, setup_tracing_logger};
|
||||||
use nym_network_defaults::setup_env;
|
use nym_network_defaults::setup_env;
|
||||||
|
|
||||||
pub mod client;
|
pub mod client;
|
||||||
@@ -20,7 +20,7 @@ async fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
|
|||||||
if !args.no_banner {
|
if !args.no_banner {
|
||||||
maybe_print_banner(crate_name!(), crate_version!());
|
maybe_print_banner(crate_name!(), crate_version!());
|
||||||
}
|
}
|
||||||
setup_no_otel_logger().expect("failed to initialize logging");
|
setup_tracing_logger();
|
||||||
|
|
||||||
if let Err(err) = commands::execute(args).await {
|
if let Err(err) = commands::execute(args).await {
|
||||||
log::error!("{err}");
|
log::error!("{err}");
|
||||||
|
|||||||
@@ -184,7 +184,7 @@ impl Handler {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// the ack control is now responsible for chunking, etc.
|
// the ack control is now responsible for chunking, etc.
|
||||||
let input_msg = InputMessage::new_regular(recipient, message, lane, self.packet_type, None);
|
let input_msg = InputMessage::new_regular(recipient, message, lane, self.packet_type);
|
||||||
if let Err(err) = self.msg_input.send(input_msg).await {
|
if let Err(err) = self.msg_input.send(input_msg).await {
|
||||||
if !self.shutdown_token.is_cancelled() {
|
if !self.shutdown_token.is_cancelled() {
|
||||||
error!("Failed to send message to the input buffer: {err}");
|
error!("Failed to send message to the input buffer: {err}");
|
||||||
@@ -217,7 +217,7 @@ impl Handler {
|
|||||||
});
|
});
|
||||||
|
|
||||||
let input_msg =
|
let input_msg =
|
||||||
InputMessage::new_anonymous(recipient, message, reply_surbs, lane, self.packet_type, None);
|
InputMessage::new_anonymous(recipient, message, reply_surbs, lane, self.packet_type);
|
||||||
if let Err(err) = self.msg_input.send(input_msg).await {
|
if let Err(err) = self.msg_input.send(input_msg).await {
|
||||||
if !self.shutdown_token.is_cancelled() {
|
if !self.shutdown_token.is_cancelled() {
|
||||||
error!("Failed to send anonymous message to the input buffer: {err}");
|
error!("Failed to send anonymous message to the input buffer: {err}");
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "nym-socks5-client"
|
name = "nym-socks5-client"
|
||||||
version = "1.1.63"
|
version = "1.1.65"
|
||||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
|
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
|
||||||
description = "A SOCKS5 localhost proxy that converts incoming messages to Sphinx and sends them to a Nym address"
|
description = "A SOCKS5 localhost proxy that converts incoming messages to Sphinx and sends them to a Nym address"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
rust-version = "1.70"
|
rust-version = "1.85"
|
||||||
license.workspace = true
|
license.workspace = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
@@ -27,6 +27,7 @@ zeroize = { workspace = true }
|
|||||||
nym-bin-common = { path = "../../common/bin-common", features = [
|
nym-bin-common = { path = "../../common/bin-common", features = [
|
||||||
"output_format",
|
"output_format",
|
||||||
"clap",
|
"clap",
|
||||||
|
"basic_tracing",
|
||||||
] }
|
] }
|
||||||
nym-client-core = { path = "../../common/client-core", features = [
|
nym-client-core = { path = "../../common/client-core", features = [
|
||||||
"fs-credentials-storage",
|
"fs-credentials-storage",
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
|
|
||||||
use clap::{crate_name, crate_version, Parser};
|
use clap::{crate_name, crate_version, Parser};
|
||||||
use nym_bin_common::logging::{maybe_print_banner, setup_no_otel_logger};
|
use nym_bin_common::logging::{maybe_print_banner, setup_tracing_logger};
|
||||||
use nym_network_defaults::setup_env;
|
use nym_network_defaults::setup_env;
|
||||||
|
|
||||||
mod commands;
|
mod commands;
|
||||||
@@ -19,7 +19,7 @@ async fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
|
|||||||
if !args.no_banner {
|
if !args.no_banner {
|
||||||
maybe_print_banner(crate_name!(), crate_version!());
|
maybe_print_banner(crate_name!(), crate_version!());
|
||||||
}
|
}
|
||||||
setup_no_otel_logger().expect("failed to initialize logging");
|
setup_tracing_logger();
|
||||||
|
|
||||||
if let Err(err) = commands::execute(args).await {
|
if let Err(err) = commands::execute(args).await {
|
||||||
log::error!("{err}");
|
log::error!("{err}");
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use futures::channel::mpsc;
|
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
|
use futures::channel::mpsc;
|
||||||
use notify::event::{DataChange, MetadataKind, ModifyKind};
|
use notify::event::{DataChange, MetadataKind, ModifyKind};
|
||||||
use notify::{Config, Event, EventKind, RecommendedWatcher, RecursiveMode, Watcher};
|
use notify::{Config, Event, EventKind, RecommendedWatcher, RecursiveMode, Watcher};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
@@ -96,10 +96,10 @@ impl AsyncFileWatcher {
|
|||||||
// when testing I was consistently getting two `Modify(Data(Any))` events in quick succession
|
// when testing I was consistently getting two `Modify(Data(Any))` events in quick succession
|
||||||
// (probably to modify content and metadata).
|
// (probably to modify content and metadata).
|
||||||
// we really only want to propagate one of them
|
// we really only want to propagate one of them
|
||||||
if let Some(previous) = self.last_received.get(&event.kind) {
|
if let Some(previous) = self.last_received.get(&event.kind)
|
||||||
if now.duration_since(*previous) < self.tick_duration {
|
&& now.duration_since(*previous) < self.tick_duration
|
||||||
return false;
|
{
|
||||||
}
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
let Some(filters) = &self.filters else {
|
let Some(filters) = &self.filters else {
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ base64 = { workspace = true }
|
|||||||
bincode = { workspace = true }
|
bincode = { workspace = true }
|
||||||
rand = { workspace = true }
|
rand = { workspace = true }
|
||||||
serde = { workspace = true, features = ["derive"] }
|
serde = { workspace = true, features = ["derive"] }
|
||||||
|
semver = { workspace = true }
|
||||||
|
strum_macros = { workspace = true }
|
||||||
thiserror = { workspace = true }
|
thiserror = { workspace = true }
|
||||||
|
|
||||||
nym-credentials-interface = { path = "../credentials-interface" }
|
nym-credentials-interface = { path = "../credentials-interface" }
|
||||||
|
|||||||
@@ -0,0 +1,273 @@
|
|||||||
|
// Copyright 2025 Nym Technologies SA <contact@nymtech.net>
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
|
use nym_sphinx::addressing::Recipient;
|
||||||
|
use nym_wireguard_types::PeerPublicKey;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
AuthenticatorVersion, Error,
|
||||||
|
latest::registration::IpPair,
|
||||||
|
traits::{FinalMessage, InitMessage, QueryBandwidthMessage, TopUpMessage, Versionable},
|
||||||
|
v2, v3, v4, v5,
|
||||||
|
};
|
||||||
|
|
||||||
|
// This is very redundant with AuthenticatorRequest and I reckon they could be smooshed.
|
||||||
|
// It is a bit out of scope for me at the moment though
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum ClientMessage {
|
||||||
|
Initial(Box<dyn InitMessage + Send + Sync + 'static>),
|
||||||
|
Final(Box<dyn FinalMessage + Send + Sync + 'static>),
|
||||||
|
Query(Box<dyn QueryBandwidthMessage + Send + Sync + 'static>),
|
||||||
|
TopUp(Box<dyn TopUpMessage + Send + Sync + 'static>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ClientMessage {
|
||||||
|
// check if message is wasteful e.g. contains a credential
|
||||||
|
pub fn is_wasteful(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
Self::Final(msg) => msg.credential().is_some(),
|
||||||
|
Self::TopUp(_) => true,
|
||||||
|
Self::Initial(_) | Self::Query(_) => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn version(&self) -> AuthenticatorVersion {
|
||||||
|
match self {
|
||||||
|
ClientMessage::Initial(msg) => msg.version(),
|
||||||
|
ClientMessage::Final(msg) => msg.version(),
|
||||||
|
ClientMessage::Query(msg) => msg.version(),
|
||||||
|
ClientMessage::TopUp(msg) => msg.version(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn bytes(&self, reply_to: Recipient) -> Result<(Vec<u8>, u64), Error> {
|
||||||
|
match self.version() {
|
||||||
|
AuthenticatorVersion::V1 => Err(Error::UnsupportedVersion),
|
||||||
|
AuthenticatorVersion::V2 => {
|
||||||
|
use v2::{
|
||||||
|
registration::{ClientMac, FinalMessage, GatewayClient, InitMessage},
|
||||||
|
request::AuthenticatorRequest,
|
||||||
|
};
|
||||||
|
match self {
|
||||||
|
ClientMessage::Initial(init_message) => {
|
||||||
|
let (req, id) = AuthenticatorRequest::new_initial_request(
|
||||||
|
InitMessage {
|
||||||
|
pub_key: init_message.pub_key(),
|
||||||
|
},
|
||||||
|
reply_to,
|
||||||
|
);
|
||||||
|
Ok((req.to_bytes()?, id))
|
||||||
|
}
|
||||||
|
ClientMessage::Final(final_message) => {
|
||||||
|
let (req, id) = AuthenticatorRequest::new_final_request(
|
||||||
|
FinalMessage {
|
||||||
|
gateway_client: GatewayClient {
|
||||||
|
pub_key: final_message.gateway_client_pub_key(),
|
||||||
|
private_ip: final_message
|
||||||
|
.gateway_client_ipv4()
|
||||||
|
.ok_or(Error::UnsupportedMessage)?
|
||||||
|
.into(),
|
||||||
|
mac: ClientMac::new(final_message.gateway_client_mac()),
|
||||||
|
},
|
||||||
|
credential: final_message.credential(),
|
||||||
|
},
|
||||||
|
reply_to,
|
||||||
|
);
|
||||||
|
Ok((req.to_bytes()?, id))
|
||||||
|
}
|
||||||
|
ClientMessage::Query(query_message) => {
|
||||||
|
let (req, id) = AuthenticatorRequest::new_query_request(
|
||||||
|
query_message.pub_key(),
|
||||||
|
reply_to,
|
||||||
|
);
|
||||||
|
Ok((req.to_bytes()?, id))
|
||||||
|
}
|
||||||
|
_ => Err(Error::UnsupportedMessage),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AuthenticatorVersion::V3 => {
|
||||||
|
use v3::{
|
||||||
|
registration::{ClientMac, FinalMessage, GatewayClient, InitMessage},
|
||||||
|
request::AuthenticatorRequest,
|
||||||
|
topup::TopUpMessage,
|
||||||
|
};
|
||||||
|
match self {
|
||||||
|
ClientMessage::Initial(init_message) => {
|
||||||
|
let (req, id) = AuthenticatorRequest::new_initial_request(
|
||||||
|
InitMessage {
|
||||||
|
pub_key: init_message.pub_key(),
|
||||||
|
},
|
||||||
|
reply_to,
|
||||||
|
);
|
||||||
|
Ok((req.to_bytes()?, id))
|
||||||
|
}
|
||||||
|
ClientMessage::Final(final_message) => {
|
||||||
|
let (req, id) = AuthenticatorRequest::new_final_request(
|
||||||
|
FinalMessage {
|
||||||
|
gateway_client: GatewayClient {
|
||||||
|
pub_key: final_message.gateway_client_pub_key(),
|
||||||
|
private_ip: final_message
|
||||||
|
.gateway_client_ipv4()
|
||||||
|
.ok_or(Error::UnsupportedMessage)?
|
||||||
|
.into(),
|
||||||
|
mac: ClientMac::new(final_message.gateway_client_mac()),
|
||||||
|
},
|
||||||
|
credential: final_message.credential(),
|
||||||
|
},
|
||||||
|
reply_to,
|
||||||
|
);
|
||||||
|
Ok((req.to_bytes()?, id))
|
||||||
|
}
|
||||||
|
ClientMessage::Query(query_message) => {
|
||||||
|
let (req, id) = AuthenticatorRequest::new_query_request(
|
||||||
|
query_message.pub_key(),
|
||||||
|
reply_to,
|
||||||
|
);
|
||||||
|
Ok((req.to_bytes()?, id))
|
||||||
|
}
|
||||||
|
ClientMessage::TopUp(top_up_message) => {
|
||||||
|
let (req, id) = AuthenticatorRequest::new_topup_request(
|
||||||
|
TopUpMessage {
|
||||||
|
pub_key: top_up_message.pub_key(),
|
||||||
|
credential: top_up_message.credential(),
|
||||||
|
},
|
||||||
|
reply_to,
|
||||||
|
);
|
||||||
|
Ok((req.to_bytes()?, id))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AuthenticatorVersion::V4 => {
|
||||||
|
use v4::{
|
||||||
|
registration::{ClientMac, FinalMessage, GatewayClient, InitMessage},
|
||||||
|
request::AuthenticatorRequest,
|
||||||
|
topup::TopUpMessage,
|
||||||
|
};
|
||||||
|
match self {
|
||||||
|
ClientMessage::Initial(init_message) => {
|
||||||
|
let (req, id) = AuthenticatorRequest::new_initial_request(
|
||||||
|
InitMessage {
|
||||||
|
pub_key: init_message.pub_key(),
|
||||||
|
},
|
||||||
|
reply_to,
|
||||||
|
);
|
||||||
|
Ok((req.to_bytes()?, id))
|
||||||
|
}
|
||||||
|
ClientMessage::Final(final_message) => {
|
||||||
|
let (req, id) = AuthenticatorRequest::new_final_request(
|
||||||
|
FinalMessage {
|
||||||
|
gateway_client: GatewayClient {
|
||||||
|
pub_key: final_message.gateway_client_pub_key(),
|
||||||
|
private_ips: IpPair {
|
||||||
|
ipv4: final_message
|
||||||
|
.gateway_client_ipv4()
|
||||||
|
.ok_or(Error::UnsupportedMessage)?,
|
||||||
|
ipv6: final_message
|
||||||
|
.gateway_client_ipv6()
|
||||||
|
.ok_or(Error::UnsupportedMessage)?,
|
||||||
|
}
|
||||||
|
.into(),
|
||||||
|
mac: ClientMac::new(final_message.gateway_client_mac()),
|
||||||
|
},
|
||||||
|
credential: final_message.credential(),
|
||||||
|
},
|
||||||
|
reply_to,
|
||||||
|
);
|
||||||
|
Ok((req.to_bytes()?, id))
|
||||||
|
}
|
||||||
|
ClientMessage::Query(query_message) => {
|
||||||
|
let (req, id) = AuthenticatorRequest::new_query_request(
|
||||||
|
query_message.pub_key(),
|
||||||
|
reply_to,
|
||||||
|
);
|
||||||
|
Ok((req.to_bytes()?, id))
|
||||||
|
}
|
||||||
|
ClientMessage::TopUp(top_up_message) => {
|
||||||
|
let (req, id) = AuthenticatorRequest::new_topup_request(
|
||||||
|
TopUpMessage {
|
||||||
|
pub_key: top_up_message.pub_key(),
|
||||||
|
credential: top_up_message.credential(),
|
||||||
|
},
|
||||||
|
reply_to,
|
||||||
|
);
|
||||||
|
Ok((req.to_bytes()?, id))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AuthenticatorVersion::V5 => {
|
||||||
|
use v5::{
|
||||||
|
registration::{ClientMac, FinalMessage, GatewayClient, InitMessage},
|
||||||
|
request::AuthenticatorRequest,
|
||||||
|
topup::TopUpMessage,
|
||||||
|
};
|
||||||
|
match self {
|
||||||
|
ClientMessage::Initial(init_message) => {
|
||||||
|
let (req, id) = AuthenticatorRequest::new_initial_request(InitMessage {
|
||||||
|
pub_key: init_message.pub_key(),
|
||||||
|
});
|
||||||
|
Ok((req.to_bytes()?, id))
|
||||||
|
}
|
||||||
|
ClientMessage::Final(final_message) => {
|
||||||
|
let (req, id) = AuthenticatorRequest::new_final_request(FinalMessage {
|
||||||
|
gateway_client: GatewayClient {
|
||||||
|
pub_key: final_message.gateway_client_pub_key(),
|
||||||
|
private_ips: IpPair {
|
||||||
|
ipv4: final_message
|
||||||
|
.gateway_client_ipv4()
|
||||||
|
.ok_or(Error::UnsupportedMessage)?,
|
||||||
|
ipv6: final_message
|
||||||
|
.gateway_client_ipv6()
|
||||||
|
.ok_or(Error::UnsupportedMessage)?,
|
||||||
|
},
|
||||||
|
mac: ClientMac::new(final_message.gateway_client_mac()),
|
||||||
|
},
|
||||||
|
credential: final_message.credential(),
|
||||||
|
});
|
||||||
|
Ok((req.to_bytes()?, id))
|
||||||
|
}
|
||||||
|
ClientMessage::Query(query_message) => {
|
||||||
|
let (req, id) =
|
||||||
|
AuthenticatorRequest::new_query_request(query_message.pub_key());
|
||||||
|
Ok((req.to_bytes()?, id))
|
||||||
|
}
|
||||||
|
ClientMessage::TopUp(top_up_message) => {
|
||||||
|
let (req, id) = AuthenticatorRequest::new_topup_request(TopUpMessage {
|
||||||
|
pub_key: top_up_message.pub_key(),
|
||||||
|
credential: top_up_message.credential(),
|
||||||
|
});
|
||||||
|
Ok((req.to_bytes()?, id))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AuthenticatorVersion::UNKNOWN => Err(Error::UnknownVersion),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn use_surbs(&self) -> bool {
|
||||||
|
use AuthenticatorVersion::*;
|
||||||
|
match self.version() {
|
||||||
|
V1 | V2 | V3 | V4 => false,
|
||||||
|
V5 => true,
|
||||||
|
UNKNOWN => true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Same comment as above struct
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct QueryMessageImpl {
|
||||||
|
pub pub_key: PeerPublicKey,
|
||||||
|
pub version: AuthenticatorVersion,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Versionable for QueryMessageImpl {
|
||||||
|
fn version(&self) -> AuthenticatorVersion {
|
||||||
|
self.version
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl QueryBandwidthMessage for QueryMessageImpl {
|
||||||
|
fn pub_key(&self) -> PeerPublicKey {
|
||||||
|
self.pub_key
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -23,6 +23,17 @@ pub enum Error {
|
|||||||
#[error("conversion: {0}")]
|
#[error("conversion: {0}")]
|
||||||
Conversion(String),
|
Conversion(String),
|
||||||
|
|
||||||
#[error("failed to serialize response packet: {source}")]
|
// TODO add version number for debugging
|
||||||
FailedToSerializeResponsePacket { source: Box<bincode::ErrorKind> },
|
#[error("unknown version number")]
|
||||||
|
UnknownVersion,
|
||||||
|
|
||||||
|
// TODO add version number for debugging
|
||||||
|
#[error("unsupported request version")]
|
||||||
|
UnsupportedVersion,
|
||||||
|
|
||||||
|
#[error("gateway doesn't support this type of message")]
|
||||||
|
UnsupportedMessage,
|
||||||
|
|
||||||
|
#[error(transparent)]
|
||||||
|
Bincode(#[from] bincode::Error),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
pub mod client_message;
|
||||||
|
pub mod request;
|
||||||
|
pub mod response;
|
||||||
pub mod traits;
|
pub mod traits;
|
||||||
pub mod v1;
|
pub mod v1;
|
||||||
pub mod v2;
|
pub mod v2;
|
||||||
@@ -10,11 +13,13 @@ pub mod v5;
|
|||||||
|
|
||||||
mod error;
|
mod error;
|
||||||
mod util;
|
mod util;
|
||||||
|
mod version;
|
||||||
|
|
||||||
pub use error::Error;
|
pub use error::Error;
|
||||||
pub use v5 as latest;
|
pub use v5 as latest;
|
||||||
|
pub use version::AuthenticatorVersion;
|
||||||
|
|
||||||
pub const CURRENT_VERSION: u8 = 5;
|
pub const CURRENT_VERSION: u8 = latest::VERSION;
|
||||||
|
|
||||||
fn make_bincode_serializer() -> impl bincode::Options {
|
fn make_bincode_serializer() -> impl bincode::Options {
|
||||||
use bincode::Options;
|
use bincode::Options;
|
||||||
|
|||||||
@@ -0,0 +1,204 @@
|
|||||||
|
// Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
use nym_service_provider_requests_common::{Protocol, ServiceProviderType};
|
||||||
|
use nym_sphinx::addressing::Recipient;
|
||||||
|
|
||||||
|
use crate::traits::{FinalMessage, InitMessage, QueryBandwidthMessage, TopUpMessage};
|
||||||
|
use crate::{v1, v2, v3, v4, v5};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum AuthenticatorRequest {
|
||||||
|
Initial {
|
||||||
|
msg: Box<dyn InitMessage + Send + Sync + 'static>,
|
||||||
|
protocol: Protocol,
|
||||||
|
reply_to: Option<Recipient>,
|
||||||
|
request_id: u64,
|
||||||
|
},
|
||||||
|
Final {
|
||||||
|
msg: Box<dyn FinalMessage + Send + Sync + 'static>,
|
||||||
|
protocol: Protocol,
|
||||||
|
reply_to: Option<Recipient>,
|
||||||
|
request_id: u64,
|
||||||
|
},
|
||||||
|
QueryBandwidth {
|
||||||
|
msg: Box<dyn QueryBandwidthMessage + Send + Sync + 'static>,
|
||||||
|
protocol: Protocol,
|
||||||
|
reply_to: Option<Recipient>,
|
||||||
|
request_id: u64,
|
||||||
|
},
|
||||||
|
TopUpBandwidth {
|
||||||
|
msg: Box<dyn TopUpMessage + Send + Sync + 'static>,
|
||||||
|
protocol: Protocol,
|
||||||
|
reply_to: Option<Recipient>,
|
||||||
|
request_id: u64,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<v1::request::AuthenticatorRequest> for AuthenticatorRequest {
|
||||||
|
fn from(value: v1::request::AuthenticatorRequest) -> Self {
|
||||||
|
match value.data {
|
||||||
|
v1::request::AuthenticatorRequestData::Initial(init_message) => Self::Initial {
|
||||||
|
msg: Box::new(init_message),
|
||||||
|
protocol: Protocol {
|
||||||
|
version: value.version,
|
||||||
|
service_provider_type: ServiceProviderType::Authenticator,
|
||||||
|
},
|
||||||
|
reply_to: Some(value.reply_to),
|
||||||
|
request_id: value.request_id,
|
||||||
|
},
|
||||||
|
v1::request::AuthenticatorRequestData::Final(gateway_client) => Self::Final {
|
||||||
|
msg: Box::new(gateway_client),
|
||||||
|
protocol: Protocol {
|
||||||
|
version: value.version,
|
||||||
|
service_provider_type: ServiceProviderType::Authenticator,
|
||||||
|
},
|
||||||
|
reply_to: Some(value.reply_to),
|
||||||
|
request_id: value.request_id,
|
||||||
|
},
|
||||||
|
v1::request::AuthenticatorRequestData::QueryBandwidth(peer_public_key) => {
|
||||||
|
Self::QueryBandwidth {
|
||||||
|
msg: Box::new(peer_public_key),
|
||||||
|
protocol: Protocol {
|
||||||
|
version: value.version,
|
||||||
|
service_provider_type: ServiceProviderType::Authenticator,
|
||||||
|
},
|
||||||
|
reply_to: Some(value.reply_to),
|
||||||
|
request_id: value.request_id,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<v2::request::AuthenticatorRequest> for AuthenticatorRequest {
|
||||||
|
fn from(value: v2::request::AuthenticatorRequest) -> Self {
|
||||||
|
match value.data {
|
||||||
|
v2::request::AuthenticatorRequestData::Initial(init_message) => Self::Initial {
|
||||||
|
msg: Box::new(init_message),
|
||||||
|
protocol: value.protocol,
|
||||||
|
reply_to: Some(value.reply_to),
|
||||||
|
request_id: value.request_id,
|
||||||
|
},
|
||||||
|
v2::request::AuthenticatorRequestData::Final(final_message) => Self::Final {
|
||||||
|
msg: final_message,
|
||||||
|
protocol: value.protocol,
|
||||||
|
reply_to: Some(value.reply_to),
|
||||||
|
request_id: value.request_id,
|
||||||
|
},
|
||||||
|
v2::request::AuthenticatorRequestData::QueryBandwidth(peer_public_key) => {
|
||||||
|
Self::QueryBandwidth {
|
||||||
|
msg: Box::new(peer_public_key),
|
||||||
|
protocol: value.protocol,
|
||||||
|
reply_to: Some(value.reply_to),
|
||||||
|
request_id: value.request_id,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<v3::request::AuthenticatorRequest> for AuthenticatorRequest {
|
||||||
|
fn from(value: v3::request::AuthenticatorRequest) -> Self {
|
||||||
|
match value.data {
|
||||||
|
v3::request::AuthenticatorRequestData::Initial(init_message) => Self::Initial {
|
||||||
|
msg: Box::new(init_message),
|
||||||
|
protocol: value.protocol,
|
||||||
|
reply_to: Some(value.reply_to),
|
||||||
|
request_id: value.request_id,
|
||||||
|
},
|
||||||
|
v3::request::AuthenticatorRequestData::Final(final_message) => Self::Final {
|
||||||
|
msg: final_message,
|
||||||
|
protocol: value.protocol,
|
||||||
|
reply_to: Some(value.reply_to),
|
||||||
|
request_id: value.request_id,
|
||||||
|
},
|
||||||
|
v3::request::AuthenticatorRequestData::QueryBandwidth(peer_public_key) => {
|
||||||
|
Self::QueryBandwidth {
|
||||||
|
msg: Box::new(peer_public_key),
|
||||||
|
protocol: value.protocol,
|
||||||
|
reply_to: Some(value.reply_to),
|
||||||
|
request_id: value.request_id,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
v3::request::AuthenticatorRequestData::TopUpBandwidth(top_up_message) => {
|
||||||
|
Self::TopUpBandwidth {
|
||||||
|
msg: top_up_message,
|
||||||
|
protocol: value.protocol,
|
||||||
|
reply_to: Some(value.reply_to),
|
||||||
|
request_id: value.request_id,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<v4::request::AuthenticatorRequest> for AuthenticatorRequest {
|
||||||
|
fn from(value: v4::request::AuthenticatorRequest) -> Self {
|
||||||
|
match value.data {
|
||||||
|
v4::request::AuthenticatorRequestData::Initial(init_message) => Self::Initial {
|
||||||
|
msg: Box::new(init_message),
|
||||||
|
protocol: value.protocol,
|
||||||
|
reply_to: Some(value.reply_to),
|
||||||
|
request_id: value.request_id,
|
||||||
|
},
|
||||||
|
v4::request::AuthenticatorRequestData::Final(final_message) => Self::Final {
|
||||||
|
msg: final_message,
|
||||||
|
protocol: value.protocol,
|
||||||
|
reply_to: Some(value.reply_to),
|
||||||
|
request_id: value.request_id,
|
||||||
|
},
|
||||||
|
v4::request::AuthenticatorRequestData::QueryBandwidth(peer_public_key) => {
|
||||||
|
Self::QueryBandwidth {
|
||||||
|
msg: Box::new(peer_public_key),
|
||||||
|
protocol: value.protocol,
|
||||||
|
reply_to: Some(value.reply_to),
|
||||||
|
request_id: value.request_id,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
v4::request::AuthenticatorRequestData::TopUpBandwidth(top_up_message) => {
|
||||||
|
Self::TopUpBandwidth {
|
||||||
|
msg: top_up_message,
|
||||||
|
protocol: value.protocol,
|
||||||
|
reply_to: Some(value.reply_to),
|
||||||
|
request_id: value.request_id,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<v5::request::AuthenticatorRequest> for AuthenticatorRequest {
|
||||||
|
fn from(value: v5::request::AuthenticatorRequest) -> Self {
|
||||||
|
match value.data {
|
||||||
|
v5::request::AuthenticatorRequestData::Initial(init_message) => Self::Initial {
|
||||||
|
msg: Box::new(init_message),
|
||||||
|
protocol: value.protocol,
|
||||||
|
reply_to: None,
|
||||||
|
request_id: value.request_id,
|
||||||
|
},
|
||||||
|
v5::request::AuthenticatorRequestData::Final(final_message) => Self::Final {
|
||||||
|
msg: final_message,
|
||||||
|
protocol: value.protocol,
|
||||||
|
reply_to: None,
|
||||||
|
request_id: value.request_id,
|
||||||
|
},
|
||||||
|
v5::request::AuthenticatorRequestData::QueryBandwidth(peer_public_key) => {
|
||||||
|
Self::QueryBandwidth {
|
||||||
|
msg: Box::new(peer_public_key),
|
||||||
|
protocol: value.protocol,
|
||||||
|
reply_to: None,
|
||||||
|
request_id: value.request_id,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
v5::request::AuthenticatorRequestData::TopUpBandwidth(top_up_message) => {
|
||||||
|
Self::TopUpBandwidth {
|
||||||
|
msg: top_up_message,
|
||||||
|
protocol: value.protocol,
|
||||||
|
reply_to: None,
|
||||||
|
request_id: value.request_id,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,106 @@
|
|||||||
|
// Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
use crate::traits::{
|
||||||
|
Id, PendingRegistrationResponse, RegisteredResponse, RemainingBandwidthResponse,
|
||||||
|
TopUpBandwidthResponse,
|
||||||
|
};
|
||||||
|
use crate::{v2, v3, v4, v5};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum AuthenticatorResponse {
|
||||||
|
PendingRegistration(Box<dyn PendingRegistrationResponse + Send + Sync + 'static>),
|
||||||
|
Registered(Box<dyn RegisteredResponse + Send + Sync + 'static>),
|
||||||
|
RemainingBandwidth(Box<dyn RemainingBandwidthResponse + Send + Sync + 'static>),
|
||||||
|
TopUpBandwidth(Box<dyn TopUpBandwidthResponse + Send + Sync + 'static>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Id for AuthenticatorResponse {
|
||||||
|
fn id(&self) -> u64 {
|
||||||
|
match self {
|
||||||
|
AuthenticatorResponse::PendingRegistration(pending_registration_response) => {
|
||||||
|
pending_registration_response.id()
|
||||||
|
}
|
||||||
|
AuthenticatorResponse::Registered(registered_response) => registered_response.id(),
|
||||||
|
AuthenticatorResponse::RemainingBandwidth(remaining_bandwidth_response) => {
|
||||||
|
remaining_bandwidth_response.id()
|
||||||
|
}
|
||||||
|
AuthenticatorResponse::TopUpBandwidth(top_up_bandwidth_response) => {
|
||||||
|
top_up_bandwidth_response.id()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<v2::response::AuthenticatorResponse> for AuthenticatorResponse {
|
||||||
|
fn from(value: v2::response::AuthenticatorResponse) -> Self {
|
||||||
|
match value.data {
|
||||||
|
v2::response::AuthenticatorResponseData::PendingRegistration(
|
||||||
|
pending_registration_response,
|
||||||
|
) => Self::PendingRegistration(Box::new(pending_registration_response)),
|
||||||
|
v2::response::AuthenticatorResponseData::Registered(registered_response) => {
|
||||||
|
Self::Registered(Box::new(registered_response))
|
||||||
|
}
|
||||||
|
v2::response::AuthenticatorResponseData::RemainingBandwidth(
|
||||||
|
remaining_bandwidth_response,
|
||||||
|
) => Self::RemainingBandwidth(Box::new(remaining_bandwidth_response)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<v3::response::AuthenticatorResponse> for AuthenticatorResponse {
|
||||||
|
fn from(value: v3::response::AuthenticatorResponse) -> Self {
|
||||||
|
match value.data {
|
||||||
|
v3::response::AuthenticatorResponseData::PendingRegistration(
|
||||||
|
pending_registration_response,
|
||||||
|
) => Self::PendingRegistration(Box::new(pending_registration_response)),
|
||||||
|
v3::response::AuthenticatorResponseData::Registered(registered_response) => {
|
||||||
|
Self::Registered(Box::new(registered_response))
|
||||||
|
}
|
||||||
|
v3::response::AuthenticatorResponseData::RemainingBandwidth(
|
||||||
|
remaining_bandwidth_response,
|
||||||
|
) => Self::RemainingBandwidth(Box::new(remaining_bandwidth_response)),
|
||||||
|
v3::response::AuthenticatorResponseData::TopUpBandwidth(top_up_bandwidth_response) => {
|
||||||
|
Self::TopUpBandwidth(Box::new(top_up_bandwidth_response))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<v4::response::AuthenticatorResponse> for AuthenticatorResponse {
|
||||||
|
fn from(value: v4::response::AuthenticatorResponse) -> Self {
|
||||||
|
match value.data {
|
||||||
|
v4::response::AuthenticatorResponseData::PendingRegistration(
|
||||||
|
pending_registration_response,
|
||||||
|
) => Self::PendingRegistration(Box::new(pending_registration_response)),
|
||||||
|
v4::response::AuthenticatorResponseData::Registered(registered_response) => {
|
||||||
|
Self::Registered(Box::new(registered_response))
|
||||||
|
}
|
||||||
|
v4::response::AuthenticatorResponseData::RemainingBandwidth(
|
||||||
|
remaining_bandwidth_response,
|
||||||
|
) => Self::RemainingBandwidth(Box::new(remaining_bandwidth_response)),
|
||||||
|
v4::response::AuthenticatorResponseData::TopUpBandwidth(top_up_bandwidth_response) => {
|
||||||
|
Self::TopUpBandwidth(Box::new(top_up_bandwidth_response))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<v5::response::AuthenticatorResponse> for AuthenticatorResponse {
|
||||||
|
fn from(value: v5::response::AuthenticatorResponse) -> Self {
|
||||||
|
match value.data {
|
||||||
|
v5::response::AuthenticatorResponseData::PendingRegistration(
|
||||||
|
pending_registration_response,
|
||||||
|
) => Self::PendingRegistration(Box::new(pending_registration_response)),
|
||||||
|
v5::response::AuthenticatorResponseData::Registered(registered_response) => {
|
||||||
|
Self::Registered(Box::new(registered_response))
|
||||||
|
}
|
||||||
|
v5::response::AuthenticatorResponseData::RemainingBandwidth(
|
||||||
|
remaining_bandwidth_response,
|
||||||
|
) => Self::RemainingBandwidth(Box::new(remaining_bandwidth_response)),
|
||||||
|
v5::response::AuthenticatorResponseData::TopUpBandwidth(top_up_bandwidth_response) => {
|
||||||
|
Self::TopUpBandwidth(Box::new(top_up_bandwidth_response))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,49 +1,105 @@
|
|||||||
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
use std::fmt;
|
||||||
|
use std::net::{Ipv4Addr, Ipv6Addr};
|
||||||
|
|
||||||
use nym_credentials_interface::CredentialSpendingData;
|
use nym_credentials_interface::CredentialSpendingData;
|
||||||
use nym_crypto::asymmetric::x25519::PrivateKey;
|
use nym_crypto::asymmetric::x25519::PrivateKey;
|
||||||
use nym_service_provider_requests_common::{Protocol, ServiceProviderType};
|
|
||||||
use nym_sphinx::addressing::clients::Recipient;
|
|
||||||
use nym_wireguard_types::PeerPublicKey;
|
use nym_wireguard_types::PeerPublicKey;
|
||||||
|
|
||||||
use crate::{
|
use crate::latest::registration::IpPair;
|
||||||
v1, v2, v3, v4,
|
use crate::{AuthenticatorVersion, Error, v1, v2, v3, v4, v5};
|
||||||
v5::{self, registration::IpPair},
|
|
||||||
Error,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
pub trait Versionable {
|
||||||
pub enum AuthenticatorVersion {
|
fn version(&self) -> AuthenticatorVersion;
|
||||||
V1,
|
|
||||||
V2,
|
|
||||||
V3,
|
|
||||||
V4,
|
|
||||||
V5,
|
|
||||||
UNKNOWN,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Protocol> for AuthenticatorVersion {
|
impl Versionable for v1::GatewayClient {
|
||||||
fn from(value: Protocol) -> Self {
|
fn version(&self) -> AuthenticatorVersion {
|
||||||
if value.service_provider_type != ServiceProviderType::Authenticator {
|
AuthenticatorVersion::V1
|
||||||
AuthenticatorVersion::UNKNOWN
|
|
||||||
} else if value.version == v1::VERSION {
|
|
||||||
AuthenticatorVersion::V1
|
|
||||||
} else if value.version == v2::VERSION {
|
|
||||||
AuthenticatorVersion::V2
|
|
||||||
} else if value.version == v3::VERSION {
|
|
||||||
AuthenticatorVersion::V3
|
|
||||||
} else if value.version == v4::VERSION {
|
|
||||||
AuthenticatorVersion::V4
|
|
||||||
} else if value.version == v5::VERSION {
|
|
||||||
AuthenticatorVersion::V5
|
|
||||||
} else {
|
|
||||||
AuthenticatorVersion::UNKNOWN
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait InitMessage {
|
impl Versionable for v1::registration::InitMessage {
|
||||||
|
fn version(&self) -> AuthenticatorVersion {
|
||||||
|
AuthenticatorVersion::V1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Versionable for v2::registration::InitMessage {
|
||||||
|
fn version(&self) -> AuthenticatorVersion {
|
||||||
|
AuthenticatorVersion::V2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Versionable for v3::registration::InitMessage {
|
||||||
|
fn version(&self) -> AuthenticatorVersion {
|
||||||
|
AuthenticatorVersion::V3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Versionable for v4::registration::InitMessage {
|
||||||
|
fn version(&self) -> AuthenticatorVersion {
|
||||||
|
AuthenticatorVersion::V4
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Versionable for v5::registration::InitMessage {
|
||||||
|
fn version(&self) -> AuthenticatorVersion {
|
||||||
|
AuthenticatorVersion::V5
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Versionable for v2::registration::FinalMessage {
|
||||||
|
fn version(&self) -> AuthenticatorVersion {
|
||||||
|
AuthenticatorVersion::V2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Versionable for v3::registration::FinalMessage {
|
||||||
|
fn version(&self) -> AuthenticatorVersion {
|
||||||
|
AuthenticatorVersion::V3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Versionable for v4::registration::FinalMessage {
|
||||||
|
fn version(&self) -> AuthenticatorVersion {
|
||||||
|
AuthenticatorVersion::V4
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Versionable for v5::registration::FinalMessage {
|
||||||
|
fn version(&self) -> AuthenticatorVersion {
|
||||||
|
AuthenticatorVersion::V5
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Versionable for PeerPublicKey {
|
||||||
|
fn version(&self) -> AuthenticatorVersion {
|
||||||
|
AuthenticatorVersion::V3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Versionable for v3::topup::TopUpMessage {
|
||||||
|
fn version(&self) -> AuthenticatorVersion {
|
||||||
|
AuthenticatorVersion::V3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Versionable for v4::topup::TopUpMessage {
|
||||||
|
fn version(&self) -> AuthenticatorVersion {
|
||||||
|
AuthenticatorVersion::V4
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Versionable for v5::topup::TopUpMessage {
|
||||||
|
fn version(&self) -> AuthenticatorVersion {
|
||||||
|
AuthenticatorVersion::V5
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait InitMessage: Versionable + fmt::Debug {
|
||||||
fn pub_key(&self) -> PeerPublicKey;
|
fn pub_key(&self) -> PeerPublicKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,15 +133,18 @@ impl InitMessage for v5::registration::InitMessage {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait FinalMessage {
|
pub trait FinalMessage: Versionable + fmt::Debug {
|
||||||
fn pub_key(&self) -> PeerPublicKey;
|
fn gateway_client_pub_key(&self) -> PeerPublicKey;
|
||||||
fn verify(&self, private_key: &PrivateKey, nonce: u64) -> Result<(), Error>;
|
fn verify(&self, private_key: &PrivateKey, nonce: u64) -> Result<(), Error>;
|
||||||
fn private_ips(&self) -> IpPair;
|
fn private_ips(&self) -> IpPair;
|
||||||
|
fn gateway_client_ipv4(&self) -> Option<Ipv4Addr>;
|
||||||
|
fn gateway_client_ipv6(&self) -> Option<Ipv6Addr>;
|
||||||
|
fn gateway_client_mac(&self) -> Vec<u8>;
|
||||||
fn credential(&self) -> Option<CredentialSpendingData>;
|
fn credential(&self) -> Option<CredentialSpendingData>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FinalMessage for v1::GatewayClient {
|
impl FinalMessage for v1::GatewayClient {
|
||||||
fn pub_key(&self) -> PeerPublicKey {
|
fn gateway_client_pub_key(&self) -> PeerPublicKey {
|
||||||
self.pub_key
|
self.pub_key
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,13 +156,28 @@ impl FinalMessage for v1::GatewayClient {
|
|||||||
self.private_ip.into()
|
self.private_ip.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn gateway_client_ipv4(&self) -> Option<Ipv4Addr> {
|
||||||
|
match self.private_ip {
|
||||||
|
std::net::IpAddr::V4(ipv4_addr) => Some(ipv4_addr),
|
||||||
|
std::net::IpAddr::V6(_) => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gateway_client_ipv6(&self) -> Option<Ipv6Addr> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gateway_client_mac(&self) -> Vec<u8> {
|
||||||
|
self.mac.to_vec()
|
||||||
|
}
|
||||||
|
|
||||||
fn credential(&self) -> Option<CredentialSpendingData> {
|
fn credential(&self) -> Option<CredentialSpendingData> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FinalMessage for v2::registration::FinalMessage {
|
impl FinalMessage for v2::registration::FinalMessage {
|
||||||
fn pub_key(&self) -> PeerPublicKey {
|
fn gateway_client_pub_key(&self) -> PeerPublicKey {
|
||||||
self.gateway_client.pub_key
|
self.gateway_client.pub_key
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,13 +189,28 @@ impl FinalMessage for v2::registration::FinalMessage {
|
|||||||
self.gateway_client.private_ip.into()
|
self.gateway_client.private_ip.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn gateway_client_ipv4(&self) -> Option<Ipv4Addr> {
|
||||||
|
match self.gateway_client.private_ip {
|
||||||
|
std::net::IpAddr::V4(ipv4_addr) => Some(ipv4_addr),
|
||||||
|
std::net::IpAddr::V6(_) => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gateway_client_ipv6(&self) -> Option<Ipv6Addr> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gateway_client_mac(&self) -> Vec<u8> {
|
||||||
|
self.gateway_client.mac.to_vec()
|
||||||
|
}
|
||||||
|
|
||||||
fn credential(&self) -> Option<CredentialSpendingData> {
|
fn credential(&self) -> Option<CredentialSpendingData> {
|
||||||
self.credential.clone()
|
self.credential.clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FinalMessage for v3::registration::FinalMessage {
|
impl FinalMessage for v3::registration::FinalMessage {
|
||||||
fn pub_key(&self) -> PeerPublicKey {
|
fn gateway_client_pub_key(&self) -> PeerPublicKey {
|
||||||
self.gateway_client.pub_key
|
self.gateway_client.pub_key
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,13 +222,28 @@ impl FinalMessage for v3::registration::FinalMessage {
|
|||||||
self.gateway_client.private_ip.into()
|
self.gateway_client.private_ip.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn gateway_client_ipv4(&self) -> Option<Ipv4Addr> {
|
||||||
|
match self.gateway_client.private_ip {
|
||||||
|
std::net::IpAddr::V4(ipv4_addr) => Some(ipv4_addr),
|
||||||
|
std::net::IpAddr::V6(_) => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gateway_client_ipv6(&self) -> Option<Ipv6Addr> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gateway_client_mac(&self) -> Vec<u8> {
|
||||||
|
self.gateway_client.mac.to_vec()
|
||||||
|
}
|
||||||
|
|
||||||
fn credential(&self) -> Option<CredentialSpendingData> {
|
fn credential(&self) -> Option<CredentialSpendingData> {
|
||||||
self.credential.clone()
|
self.credential.clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FinalMessage for v4::registration::FinalMessage {
|
impl FinalMessage for v4::registration::FinalMessage {
|
||||||
fn pub_key(&self) -> PeerPublicKey {
|
fn gateway_client_pub_key(&self) -> PeerPublicKey {
|
||||||
self.gateway_client.pub_key
|
self.gateway_client.pub_key
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,13 +255,25 @@ impl FinalMessage for v4::registration::FinalMessage {
|
|||||||
self.gateway_client.private_ips.into()
|
self.gateway_client.private_ips.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn gateway_client_ipv4(&self) -> Option<Ipv4Addr> {
|
||||||
|
Some(self.gateway_client.private_ips.ipv4)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gateway_client_ipv6(&self) -> Option<Ipv6Addr> {
|
||||||
|
Some(self.gateway_client.private_ips.ipv6)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gateway_client_mac(&self) -> Vec<u8> {
|
||||||
|
self.gateway_client.mac.to_vec()
|
||||||
|
}
|
||||||
|
|
||||||
fn credential(&self) -> Option<CredentialSpendingData> {
|
fn credential(&self) -> Option<CredentialSpendingData> {
|
||||||
self.credential.clone()
|
self.credential.clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FinalMessage for v5::registration::FinalMessage {
|
impl FinalMessage for v5::registration::FinalMessage {
|
||||||
fn pub_key(&self) -> PeerPublicKey {
|
fn gateway_client_pub_key(&self) -> PeerPublicKey {
|
||||||
self.gateway_client.pub_key
|
self.gateway_client.pub_key
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -169,12 +285,24 @@ impl FinalMessage for v5::registration::FinalMessage {
|
|||||||
self.gateway_client.private_ips
|
self.gateway_client.private_ips
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn gateway_client_ipv4(&self) -> Option<Ipv4Addr> {
|
||||||
|
Some(self.gateway_client.private_ips.ipv4)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gateway_client_ipv6(&self) -> Option<Ipv6Addr> {
|
||||||
|
Some(self.gateway_client.private_ips.ipv6)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gateway_client_mac(&self) -> Vec<u8> {
|
||||||
|
self.gateway_client.mac.to_vec()
|
||||||
|
}
|
||||||
|
|
||||||
fn credential(&self) -> Option<CredentialSpendingData> {
|
fn credential(&self) -> Option<CredentialSpendingData> {
|
||||||
self.credential.clone()
|
self.credential.clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait QueryBandwidthMessage {
|
pub trait QueryBandwidthMessage: Versionable + fmt::Debug {
|
||||||
fn pub_key(&self) -> PeerPublicKey;
|
fn pub_key(&self) -> PeerPublicKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -184,7 +312,7 @@ impl QueryBandwidthMessage for PeerPublicKey {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait TopUpMessage {
|
pub trait TopUpMessage: Versionable + fmt::Debug {
|
||||||
fn pub_key(&self) -> PeerPublicKey;
|
fn pub_key(&self) -> PeerPublicKey;
|
||||||
fn credential(&self) -> CredentialSpendingData;
|
fn credential(&self) -> CredentialSpendingData;
|
||||||
}
|
}
|
||||||
@@ -219,197 +347,286 @@ impl TopUpMessage for v5::topup::TopUpMessage {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum AuthenticatorRequest {
|
pub trait Id {
|
||||||
Initial {
|
fn id(&self) -> u64;
|
||||||
msg: Box<dyn InitMessage + Send + Sync + 'static>,
|
|
||||||
protocol: Protocol,
|
|
||||||
reply_to: Option<Recipient>,
|
|
||||||
request_id: u64,
|
|
||||||
},
|
|
||||||
Final {
|
|
||||||
msg: Box<dyn FinalMessage + Send + Sync + 'static>,
|
|
||||||
protocol: Protocol,
|
|
||||||
reply_to: Option<Recipient>,
|
|
||||||
request_id: u64,
|
|
||||||
},
|
|
||||||
QueryBandwidth {
|
|
||||||
msg: Box<dyn QueryBandwidthMessage + Send + Sync + 'static>,
|
|
||||||
protocol: Protocol,
|
|
||||||
reply_to: Option<Recipient>,
|
|
||||||
request_id: u64,
|
|
||||||
},
|
|
||||||
TopUpBandwidth {
|
|
||||||
msg: Box<dyn TopUpMessage + Send + Sync + 'static>,
|
|
||||||
protocol: Protocol,
|
|
||||||
reply_to: Option<Recipient>,
|
|
||||||
request_id: u64,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<v1::request::AuthenticatorRequest> for AuthenticatorRequest {
|
impl Id for v2::response::PendingRegistrationResponse {
|
||||||
fn from(value: v1::request::AuthenticatorRequest) -> Self {
|
fn id(&self) -> u64 {
|
||||||
match value.data {
|
self.request_id
|
||||||
v1::request::AuthenticatorRequestData::Initial(init_message) => Self::Initial {
|
|
||||||
msg: Box::new(init_message),
|
|
||||||
protocol: Protocol {
|
|
||||||
version: value.version,
|
|
||||||
service_provider_type: ServiceProviderType::Authenticator,
|
|
||||||
},
|
|
||||||
reply_to: Some(value.reply_to),
|
|
||||||
request_id: value.request_id,
|
|
||||||
},
|
|
||||||
v1::request::AuthenticatorRequestData::Final(gateway_client) => Self::Final {
|
|
||||||
msg: Box::new(gateway_client),
|
|
||||||
protocol: Protocol {
|
|
||||||
version: value.version,
|
|
||||||
service_provider_type: ServiceProviderType::Authenticator,
|
|
||||||
},
|
|
||||||
reply_to: Some(value.reply_to),
|
|
||||||
request_id: value.request_id,
|
|
||||||
},
|
|
||||||
v1::request::AuthenticatorRequestData::QueryBandwidth(peer_public_key) => {
|
|
||||||
Self::QueryBandwidth {
|
|
||||||
msg: Box::new(peer_public_key),
|
|
||||||
protocol: Protocol {
|
|
||||||
version: value.version,
|
|
||||||
service_provider_type: ServiceProviderType::Authenticator,
|
|
||||||
},
|
|
||||||
reply_to: Some(value.reply_to),
|
|
||||||
request_id: value.request_id,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<v2::request::AuthenticatorRequest> for AuthenticatorRequest {
|
impl Id for v3::response::PendingRegistrationResponse {
|
||||||
fn from(value: v2::request::AuthenticatorRequest) -> Self {
|
fn id(&self) -> u64 {
|
||||||
match value.data {
|
self.request_id
|
||||||
v2::request::AuthenticatorRequestData::Initial(init_message) => Self::Initial {
|
|
||||||
msg: Box::new(init_message),
|
|
||||||
protocol: value.protocol,
|
|
||||||
reply_to: Some(value.reply_to),
|
|
||||||
request_id: value.request_id,
|
|
||||||
},
|
|
||||||
v2::request::AuthenticatorRequestData::Final(final_message) => Self::Final {
|
|
||||||
msg: final_message,
|
|
||||||
protocol: value.protocol,
|
|
||||||
reply_to: Some(value.reply_to),
|
|
||||||
request_id: value.request_id,
|
|
||||||
},
|
|
||||||
v2::request::AuthenticatorRequestData::QueryBandwidth(peer_public_key) => {
|
|
||||||
Self::QueryBandwidth {
|
|
||||||
msg: Box::new(peer_public_key),
|
|
||||||
protocol: value.protocol,
|
|
||||||
reply_to: Some(value.reply_to),
|
|
||||||
request_id: value.request_id,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<v3::request::AuthenticatorRequest> for AuthenticatorRequest {
|
impl Id for v4::response::PendingRegistrationResponse {
|
||||||
fn from(value: v3::request::AuthenticatorRequest) -> Self {
|
fn id(&self) -> u64 {
|
||||||
match value.data {
|
self.request_id
|
||||||
v3::request::AuthenticatorRequestData::Initial(init_message) => Self::Initial {
|
|
||||||
msg: Box::new(init_message),
|
|
||||||
protocol: value.protocol,
|
|
||||||
reply_to: Some(value.reply_to),
|
|
||||||
request_id: value.request_id,
|
|
||||||
},
|
|
||||||
v3::request::AuthenticatorRequestData::Final(final_message) => Self::Final {
|
|
||||||
msg: final_message,
|
|
||||||
protocol: value.protocol,
|
|
||||||
reply_to: Some(value.reply_to),
|
|
||||||
request_id: value.request_id,
|
|
||||||
},
|
|
||||||
v3::request::AuthenticatorRequestData::QueryBandwidth(peer_public_key) => {
|
|
||||||
Self::QueryBandwidth {
|
|
||||||
msg: Box::new(peer_public_key),
|
|
||||||
protocol: value.protocol,
|
|
||||||
reply_to: Some(value.reply_to),
|
|
||||||
request_id: value.request_id,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
v3::request::AuthenticatorRequestData::TopUpBandwidth(top_up_message) => {
|
|
||||||
Self::TopUpBandwidth {
|
|
||||||
msg: top_up_message,
|
|
||||||
protocol: value.protocol,
|
|
||||||
reply_to: Some(value.reply_to),
|
|
||||||
request_id: value.request_id,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<v4::request::AuthenticatorRequest> for AuthenticatorRequest {
|
impl Id for v5::response::PendingRegistrationResponse {
|
||||||
fn from(value: v4::request::AuthenticatorRequest) -> Self {
|
fn id(&self) -> u64 {
|
||||||
match value.data {
|
self.request_id
|
||||||
v4::request::AuthenticatorRequestData::Initial(init_message) => Self::Initial {
|
|
||||||
msg: Box::new(init_message),
|
|
||||||
protocol: value.protocol,
|
|
||||||
reply_to: Some(value.reply_to),
|
|
||||||
request_id: value.request_id,
|
|
||||||
},
|
|
||||||
v4::request::AuthenticatorRequestData::Final(final_message) => Self::Final {
|
|
||||||
msg: final_message,
|
|
||||||
protocol: value.protocol,
|
|
||||||
reply_to: Some(value.reply_to),
|
|
||||||
request_id: value.request_id,
|
|
||||||
},
|
|
||||||
v4::request::AuthenticatorRequestData::QueryBandwidth(peer_public_key) => {
|
|
||||||
Self::QueryBandwidth {
|
|
||||||
msg: Box::new(peer_public_key),
|
|
||||||
protocol: value.protocol,
|
|
||||||
reply_to: Some(value.reply_to),
|
|
||||||
request_id: value.request_id,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
v4::request::AuthenticatorRequestData::TopUpBandwidth(top_up_message) => {
|
|
||||||
Self::TopUpBandwidth {
|
|
||||||
msg: top_up_message,
|
|
||||||
protocol: value.protocol,
|
|
||||||
reply_to: Some(value.reply_to),
|
|
||||||
request_id: value.request_id,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<v5::request::AuthenticatorRequest> for AuthenticatorRequest {
|
impl Id for v2::response::RegisteredResponse {
|
||||||
fn from(value: v5::request::AuthenticatorRequest) -> Self {
|
fn id(&self) -> u64 {
|
||||||
match value.data {
|
self.request_id
|
||||||
v5::request::AuthenticatorRequestData::Initial(init_message) => Self::Initial {
|
}
|
||||||
msg: Box::new(init_message),
|
}
|
||||||
protocol: value.protocol,
|
|
||||||
reply_to: None,
|
impl Id for v3::response::RegisteredResponse {
|
||||||
request_id: value.request_id,
|
fn id(&self) -> u64 {
|
||||||
},
|
self.request_id
|
||||||
v5::request::AuthenticatorRequestData::Final(final_message) => Self::Final {
|
}
|
||||||
msg: final_message,
|
}
|
||||||
protocol: value.protocol,
|
|
||||||
reply_to: None,
|
impl Id for v4::response::RegisteredResponse {
|
||||||
request_id: value.request_id,
|
fn id(&self) -> u64 {
|
||||||
},
|
self.request_id
|
||||||
v5::request::AuthenticatorRequestData::QueryBandwidth(peer_public_key) => {
|
}
|
||||||
Self::QueryBandwidth {
|
}
|
||||||
msg: Box::new(peer_public_key),
|
|
||||||
protocol: value.protocol,
|
impl Id for v5::response::RegisteredResponse {
|
||||||
reply_to: None,
|
fn id(&self) -> u64 {
|
||||||
request_id: value.request_id,
|
self.request_id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
v5::request::AuthenticatorRequestData::TopUpBandwidth(top_up_message) => {
|
|
||||||
Self::TopUpBandwidth {
|
impl Id for v2::response::RemainingBandwidthResponse {
|
||||||
msg: top_up_message,
|
fn id(&self) -> u64 {
|
||||||
protocol: value.protocol,
|
self.request_id
|
||||||
reply_to: None,
|
}
|
||||||
request_id: value.request_id,
|
}
|
||||||
}
|
|
||||||
}
|
impl Id for v3::response::RemainingBandwidthResponse {
|
||||||
}
|
fn id(&self) -> u64 {
|
||||||
|
self.request_id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Id for v4::response::RemainingBandwidthResponse {
|
||||||
|
fn id(&self) -> u64 {
|
||||||
|
self.request_id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Id for v5::response::RemainingBandwidthResponse {
|
||||||
|
fn id(&self) -> u64 {
|
||||||
|
self.request_id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Id for v3::response::TopUpBandwidthResponse {
|
||||||
|
fn id(&self) -> u64 {
|
||||||
|
self.request_id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Id for v4::response::TopUpBandwidthResponse {
|
||||||
|
fn id(&self) -> u64 {
|
||||||
|
self.request_id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Id for v5::response::TopUpBandwidthResponse {
|
||||||
|
fn id(&self) -> u64 {
|
||||||
|
self.request_id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait PendingRegistrationResponse: Id + fmt::Debug {
|
||||||
|
fn nonce(&self) -> u64;
|
||||||
|
fn verify(&self, gateway_key: &PrivateKey) -> std::result::Result<(), Error>;
|
||||||
|
fn pub_key(&self) -> PeerPublicKey;
|
||||||
|
fn private_ips(&self) -> IpPair;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PendingRegistrationResponse for v2::response::PendingRegistrationResponse {
|
||||||
|
fn nonce(&self) -> u64 {
|
||||||
|
self.reply.nonce
|
||||||
|
}
|
||||||
|
|
||||||
|
fn verify(&self, gateway_key: &PrivateKey) -> std::result::Result<(), Error> {
|
||||||
|
self.reply.gateway_data.verify(gateway_key, self.nonce())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pub_key(&self) -> PeerPublicKey {
|
||||||
|
self.reply.gateway_data.pub_key
|
||||||
|
}
|
||||||
|
|
||||||
|
fn private_ips(&self) -> IpPair {
|
||||||
|
self.reply.gateway_data.private_ip.into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PendingRegistrationResponse for v3::response::PendingRegistrationResponse {
|
||||||
|
fn nonce(&self) -> u64 {
|
||||||
|
self.reply.nonce
|
||||||
|
}
|
||||||
|
|
||||||
|
fn verify(&self, gateway_key: &PrivateKey) -> std::result::Result<(), Error> {
|
||||||
|
self.reply.gateway_data.verify(gateway_key, self.nonce())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pub_key(&self) -> PeerPublicKey {
|
||||||
|
self.reply.gateway_data.pub_key
|
||||||
|
}
|
||||||
|
|
||||||
|
fn private_ips(&self) -> IpPair {
|
||||||
|
self.reply.gateway_data.private_ip.into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PendingRegistrationResponse for v4::response::PendingRegistrationResponse {
|
||||||
|
fn nonce(&self) -> u64 {
|
||||||
|
self.reply.nonce
|
||||||
|
}
|
||||||
|
|
||||||
|
fn verify(&self, gateway_key: &PrivateKey) -> std::result::Result<(), Error> {
|
||||||
|
self.reply.gateway_data.verify(gateway_key, self.nonce())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pub_key(&self) -> PeerPublicKey {
|
||||||
|
self.reply.gateway_data.pub_key
|
||||||
|
}
|
||||||
|
|
||||||
|
fn private_ips(&self) -> IpPair {
|
||||||
|
self.reply.gateway_data.private_ips.into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PendingRegistrationResponse for v5::response::PendingRegistrationResponse {
|
||||||
|
fn nonce(&self) -> u64 {
|
||||||
|
self.reply.nonce
|
||||||
|
}
|
||||||
|
|
||||||
|
fn verify(&self, gateway_key: &PrivateKey) -> std::result::Result<(), Error> {
|
||||||
|
self.reply.gateway_data.verify(gateway_key, self.nonce())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pub_key(&self) -> PeerPublicKey {
|
||||||
|
self.reply.gateway_data.pub_key
|
||||||
|
}
|
||||||
|
|
||||||
|
fn private_ips(&self) -> IpPair {
|
||||||
|
self.reply.gateway_data.private_ips
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait RegisteredResponse: Id + fmt::Debug {
|
||||||
|
fn private_ips(&self) -> IpPair;
|
||||||
|
fn pub_key(&self) -> PeerPublicKey;
|
||||||
|
fn wg_port(&self) -> u16;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RegisteredResponse for v2::response::RegisteredResponse {
|
||||||
|
fn private_ips(&self) -> IpPair {
|
||||||
|
self.reply.private_ip.into()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pub_key(&self) -> PeerPublicKey {
|
||||||
|
self.reply.pub_key
|
||||||
|
}
|
||||||
|
|
||||||
|
fn wg_port(&self) -> u16 {
|
||||||
|
self.reply.wg_port
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RegisteredResponse for v3::response::RegisteredResponse {
|
||||||
|
fn private_ips(&self) -> IpPair {
|
||||||
|
self.reply.private_ip.into()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pub_key(&self) -> PeerPublicKey {
|
||||||
|
self.reply.pub_key
|
||||||
|
}
|
||||||
|
|
||||||
|
fn wg_port(&self) -> u16 {
|
||||||
|
self.reply.wg_port
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl RegisteredResponse for v4::response::RegisteredResponse {
|
||||||
|
fn private_ips(&self) -> IpPair {
|
||||||
|
self.reply.private_ips.into()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pub_key(&self) -> PeerPublicKey {
|
||||||
|
self.reply.pub_key
|
||||||
|
}
|
||||||
|
|
||||||
|
fn wg_port(&self) -> u16 {
|
||||||
|
self.reply.wg_port
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RegisteredResponse for v5::response::RegisteredResponse {
|
||||||
|
fn private_ips(&self) -> IpPair {
|
||||||
|
self.reply.private_ips
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pub_key(&self) -> PeerPublicKey {
|
||||||
|
self.reply.pub_key
|
||||||
|
}
|
||||||
|
|
||||||
|
fn wg_port(&self) -> u16 {
|
||||||
|
self.reply.wg_port
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait RemainingBandwidthResponse: Id + fmt::Debug {
|
||||||
|
fn available_bandwidth(&self) -> Option<i64>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RemainingBandwidthResponse for v2::response::RemainingBandwidthResponse {
|
||||||
|
fn available_bandwidth(&self) -> Option<i64> {
|
||||||
|
self.reply.as_ref().map(|r| r.available_bandwidth)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RemainingBandwidthResponse for v3::response::RemainingBandwidthResponse {
|
||||||
|
fn available_bandwidth(&self) -> Option<i64> {
|
||||||
|
self.reply.as_ref().map(|r| r.available_bandwidth)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RemainingBandwidthResponse for v4::response::RemainingBandwidthResponse {
|
||||||
|
fn available_bandwidth(&self) -> Option<i64> {
|
||||||
|
self.reply.as_ref().map(|r| r.available_bandwidth)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RemainingBandwidthResponse for v5::response::RemainingBandwidthResponse {
|
||||||
|
fn available_bandwidth(&self) -> Option<i64> {
|
||||||
|
self.reply.as_ref().map(|r| r.available_bandwidth)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait TopUpBandwidthResponse: Id + fmt::Debug {
|
||||||
|
fn available_bandwidth(&self) -> i64;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TopUpBandwidthResponse for v3::response::TopUpBandwidthResponse {
|
||||||
|
fn available_bandwidth(&self) -> i64 {
|
||||||
|
self.reply.available_bandwidth
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TopUpBandwidthResponse for v4::response::TopUpBandwidthResponse {
|
||||||
|
fn available_bandwidth(&self) -> i64 {
|
||||||
|
self.reply.available_bandwidth
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TopUpBandwidthResponse for v5::response::TopUpBandwidthResponse {
|
||||||
|
fn available_bandwidth(&self) -> i64 {
|
||||||
|
self.reply.available_bandwidth
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use crate::error::Error;
|
use crate::error::Error;
|
||||||
use base64::{engine::general_purpose, Engine};
|
use base64::{Engine, engine::general_purpose};
|
||||||
use nym_wireguard_types::PeerPublicKey;
|
use nym_wireguard_types::PeerPublicKey;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use crate::error::Error;
|
use crate::error::Error;
|
||||||
use base64::{engine::general_purpose, Engine};
|
use base64::{Engine, engine::general_purpose};
|
||||||
use nym_credentials_interface::CredentialSpendingData;
|
use nym_credentials_interface::CredentialSpendingData;
|
||||||
use nym_wireguard_types::PeerPublicKey;
|
use nym_wireguard_types::PeerPublicKey;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use crate::error::Error;
|
use crate::error::Error;
|
||||||
use base64::{engine::general_purpose, Engine};
|
use base64::{Engine, engine::general_purpose};
|
||||||
use nym_credentials_interface::CredentialSpendingData;
|
use nym_credentials_interface::CredentialSpendingData;
|
||||||
use nym_wireguard_types::PeerPublicKey;
|
use nym_wireguard_types::PeerPublicKey;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use crate::error::Error;
|
use crate::error::Error;
|
||||||
use base64::{engine::general_purpose, Engine};
|
use base64::{Engine, engine::general_purpose};
|
||||||
use nym_credentials_interface::CredentialSpendingData;
|
use nym_credentials_interface::CredentialSpendingData;
|
||||||
use nym_network_defaults::constants::{WG_TUN_DEVICE_IP_ADDRESS_V4, WG_TUN_DEVICE_IP_ADDRESS_V6};
|
use nym_network_defaults::constants::{WG_TUN_DEVICE_IP_ADDRESS_V4, WG_TUN_DEVICE_IP_ADDRESS_V6};
|
||||||
use nym_wireguard_types::PeerPublicKey;
|
use nym_wireguard_types::PeerPublicKey;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use crate::error::Error;
|
use crate::error::Error;
|
||||||
use base64::{engine::general_purpose, Engine};
|
use base64::{Engine, engine::general_purpose};
|
||||||
use nym_credentials_interface::CredentialSpendingData;
|
use nym_credentials_interface::CredentialSpendingData;
|
||||||
use nym_network_defaults::constants::{WG_TUN_DEVICE_IP_ADDRESS_V4, WG_TUN_DEVICE_IP_ADDRESS_V6};
|
use nym_network_defaults::constants::{WG_TUN_DEVICE_IP_ADDRESS_V4, WG_TUN_DEVICE_IP_ADDRESS_V6};
|
||||||
use nym_wireguard_types::PeerPublicKey;
|
use nym_wireguard_types::PeerPublicKey;
|
||||||
|
|||||||
@@ -0,0 +1,195 @@
|
|||||||
|
// Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
use super::{v1, v2, v3, v4, v5};
|
||||||
|
use nym_service_provider_requests_common::{Protocol, ServiceProviderType};
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, PartialEq, strum_macros::Display)]
|
||||||
|
#[strum(serialize_all = "snake_case")]
|
||||||
|
pub enum AuthenticatorVersion {
|
||||||
|
/// introduced in wispa release (1.1.5)
|
||||||
|
V1,
|
||||||
|
|
||||||
|
/// introduced in aero release (1.1.9)
|
||||||
|
V2,
|
||||||
|
|
||||||
|
/// introduced in magura release (1.1.10)
|
||||||
|
V3,
|
||||||
|
|
||||||
|
/// introduced in crunch release (1.2.0)
|
||||||
|
V4,
|
||||||
|
|
||||||
|
/// introduced in dorina-patched release (1.6.1)
|
||||||
|
V5,
|
||||||
|
|
||||||
|
UNKNOWN,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AuthenticatorVersion {
|
||||||
|
pub const LATEST: Self = Self::V5;
|
||||||
|
|
||||||
|
pub const fn release_version(&self) -> semver::Version {
|
||||||
|
match self {
|
||||||
|
AuthenticatorVersion::V1 => semver::Version::new(1, 1, 5),
|
||||||
|
AuthenticatorVersion::V2 => semver::Version::new(1, 1, 9),
|
||||||
|
AuthenticatorVersion::V3 => semver::Version::new(1, 1, 10),
|
||||||
|
AuthenticatorVersion::V4 => semver::Version::new(1, 2, 0),
|
||||||
|
AuthenticatorVersion::V5 => semver::Version::new(1, 6, 1),
|
||||||
|
AuthenticatorVersion::UNKNOWN => semver::Version::new(0, 0, 0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Protocol> for AuthenticatorVersion {
|
||||||
|
fn from(value: Protocol) -> Self {
|
||||||
|
if value.service_provider_type != ServiceProviderType::Authenticator {
|
||||||
|
AuthenticatorVersion::UNKNOWN
|
||||||
|
} else if value.version == v1::VERSION {
|
||||||
|
AuthenticatorVersion::V1
|
||||||
|
} else if value.version == v2::VERSION {
|
||||||
|
AuthenticatorVersion::V2
|
||||||
|
} else if value.version == v3::VERSION {
|
||||||
|
AuthenticatorVersion::V3
|
||||||
|
} else if value.version == v4::VERSION {
|
||||||
|
AuthenticatorVersion::V4
|
||||||
|
} else if value.version == v5::VERSION {
|
||||||
|
AuthenticatorVersion::V5
|
||||||
|
} else {
|
||||||
|
AuthenticatorVersion::UNKNOWN
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<u8> for AuthenticatorVersion {
|
||||||
|
fn from(value: u8) -> Self {
|
||||||
|
if value == v1::VERSION {
|
||||||
|
AuthenticatorVersion::V1
|
||||||
|
} else if value == v2::VERSION {
|
||||||
|
AuthenticatorVersion::V2
|
||||||
|
} else if value == v3::VERSION {
|
||||||
|
AuthenticatorVersion::V3
|
||||||
|
} else if value == v4::VERSION {
|
||||||
|
AuthenticatorVersion::V4
|
||||||
|
} else if value == v5::VERSION {
|
||||||
|
AuthenticatorVersion::V5
|
||||||
|
} else {
|
||||||
|
AuthenticatorVersion::UNKNOWN
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&str> for AuthenticatorVersion {
|
||||||
|
fn from(value: &str) -> Self {
|
||||||
|
let Ok(semver) = semver::Version::parse(value) else {
|
||||||
|
return Self::UNKNOWN;
|
||||||
|
};
|
||||||
|
|
||||||
|
semver.into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Option<&String>> for AuthenticatorVersion {
|
||||||
|
fn from(value: Option<&String>) -> Self {
|
||||||
|
match value {
|
||||||
|
None => Self::UNKNOWN,
|
||||||
|
Some(value) => value.as_str().into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<String> for AuthenticatorVersion {
|
||||||
|
fn from(value: String) -> Self {
|
||||||
|
Self::from(value.as_str())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Option<String>> for AuthenticatorVersion {
|
||||||
|
fn from(value: Option<String>) -> Self {
|
||||||
|
value.as_ref().into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<semver::Version> for AuthenticatorVersion {
|
||||||
|
fn from(semver: semver::Version) -> Self {
|
||||||
|
if semver < AuthenticatorVersion::V1.release_version() {
|
||||||
|
return Self::UNKNOWN;
|
||||||
|
}
|
||||||
|
if semver < AuthenticatorVersion::V2.release_version() {
|
||||||
|
return Self::V1;
|
||||||
|
}
|
||||||
|
if semver < AuthenticatorVersion::V3.release_version() {
|
||||||
|
return Self::V2;
|
||||||
|
}
|
||||||
|
if semver < AuthenticatorVersion::V4.release_version() {
|
||||||
|
return Self::V3;
|
||||||
|
}
|
||||||
|
if semver < AuthenticatorVersion::V5.release_version() {
|
||||||
|
return Self::V4;
|
||||||
|
}
|
||||||
|
// if provided version is higher (or equal) to release version of V5,
|
||||||
|
// we return the latest (i.e. v5)
|
||||||
|
|
||||||
|
debug_assert_eq!(
|
||||||
|
Self::V5,
|
||||||
|
Self::LATEST,
|
||||||
|
"a new AuthenticatorVersion variant has been introduced without adjusting the `From<semver::Version>` trait"
|
||||||
|
);
|
||||||
|
Self::LATEST
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::super::latest;
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn strum_display() {
|
||||||
|
// sanity check on formatting and casing
|
||||||
|
assert_eq!("v1", AuthenticatorVersion::V1.to_string());
|
||||||
|
assert_eq!("v2", AuthenticatorVersion::V2.to_string());
|
||||||
|
assert_eq!("unknown", AuthenticatorVersion::UNKNOWN.to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn u8_conversion() {
|
||||||
|
assert_eq!(AuthenticatorVersion::V1, AuthenticatorVersion::from(1u8));
|
||||||
|
assert_eq!(AuthenticatorVersion::V2, AuthenticatorVersion::from(2u8));
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
AuthenticatorVersion::UNKNOWN,
|
||||||
|
AuthenticatorVersion::from(latest::VERSION + 1)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
AuthenticatorVersion::UNKNOWN,
|
||||||
|
AuthenticatorVersion::from(0u8)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
AuthenticatorVersion::UNKNOWN,
|
||||||
|
AuthenticatorVersion::from(255u8)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn semver_checks() {
|
||||||
|
assert_eq!(AuthenticatorVersion::UNKNOWN, "1.1.4".into());
|
||||||
|
assert_eq!(AuthenticatorVersion::UNKNOWN, "0.1.0".into());
|
||||||
|
assert_eq!(AuthenticatorVersion::UNKNOWN, "1.0.4".into());
|
||||||
|
assert_eq!(AuthenticatorVersion::V1, "1.1.5".into());
|
||||||
|
assert_eq!(AuthenticatorVersion::V1, "1.1.6".into());
|
||||||
|
assert_eq!(AuthenticatorVersion::V1, "1.1.8".into());
|
||||||
|
assert_eq!(AuthenticatorVersion::V2, "1.1.9".into());
|
||||||
|
assert_eq!(AuthenticatorVersion::V3, "1.1.10".into());
|
||||||
|
assert_eq!(AuthenticatorVersion::V3, "1.1.11".into());
|
||||||
|
assert_eq!(AuthenticatorVersion::V3, "1.1.60".into());
|
||||||
|
assert_eq!(AuthenticatorVersion::V4, "1.2.0".into());
|
||||||
|
assert_eq!(AuthenticatorVersion::V4, "1.2.1".into());
|
||||||
|
assert_eq!(AuthenticatorVersion::V4, "1.5.1".into());
|
||||||
|
assert_eq!(AuthenticatorVersion::V4, "1.6.0".into());
|
||||||
|
assert_eq!(AuthenticatorVersion::V5, "1.6.1".into());
|
||||||
|
assert_eq!(AuthenticatorVersion::V5, "1.6.11".into());
|
||||||
|
assert_eq!(AuthenticatorVersion::V5, "1.7.0".into());
|
||||||
|
assert_eq!(AuthenticatorVersion::V5, "1.16.11".into());
|
||||||
|
assert_eq!(AuthenticatorVersion::V5, "1.17.0".into());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,6 +7,7 @@ license.workspace = true
|
|||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
async-trait = { workspace = true }
|
||||||
bip39 = { workspace = true }
|
bip39 = { workspace = true }
|
||||||
log = { workspace = true }
|
log = { workspace = true }
|
||||||
rand = { workspace = true }
|
rand = { workspace = true }
|
||||||
|
|||||||
@@ -23,10 +23,12 @@ use nym_validator_client::nym_api::EpochId;
|
|||||||
use nym_validator_client::nyxd::contract_traits::DkgQueryClient;
|
use nym_validator_client::nyxd::contract_traits::DkgQueryClient;
|
||||||
|
|
||||||
pub use event::BandwidthStatusMessage;
|
pub use event::BandwidthStatusMessage;
|
||||||
|
pub use traits::{BandwidthTicketProvider, DEFAULT_TICKETS_TO_SPEND};
|
||||||
|
|
||||||
pub mod acquire;
|
pub mod acquire;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
mod event;
|
mod event;
|
||||||
|
mod traits;
|
||||||
mod utils;
|
mod utils;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
// Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
use async_trait::async_trait;
|
||||||
|
use nym_credential_storage::storage::Storage;
|
||||||
|
use nym_credentials_interface::TicketType;
|
||||||
|
use nym_crypto::asymmetric::ed25519;
|
||||||
|
use nym_validator_client::nyxd::contract_traits::DkgQueryClient;
|
||||||
|
|
||||||
|
use crate::{error::BandwidthControllerError, BandwidthController, PreparedCredential};
|
||||||
|
|
||||||
|
pub const DEFAULT_TICKETS_TO_SPEND: u32 = 1;
|
||||||
|
|
||||||
|
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
|
||||||
|
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
|
||||||
|
pub trait BandwidthTicketProvider: Send + Sync {
|
||||||
|
async fn get_ecash_ticket(
|
||||||
|
&self,
|
||||||
|
ticket_type: TicketType,
|
||||||
|
gateway_id: ed25519::PublicKey,
|
||||||
|
tickets_to_spend: u32,
|
||||||
|
) -> Result<PreparedCredential, BandwidthControllerError>;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
|
||||||
|
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
|
||||||
|
impl<C, St> BandwidthTicketProvider for BandwidthController<C, St>
|
||||||
|
where
|
||||||
|
C: DkgQueryClient + Sync + Send,
|
||||||
|
St: nym_credential_storage::storage::Storage,
|
||||||
|
<St as Storage>::StorageError: Send + Sync + 'static,
|
||||||
|
{
|
||||||
|
async fn get_ecash_ticket(
|
||||||
|
&self,
|
||||||
|
ticket_type: TicketType,
|
||||||
|
gateway_id: ed25519::PublicKey,
|
||||||
|
tickets_to_spend: u32,
|
||||||
|
) -> Result<PreparedCredential, BandwidthControllerError> {
|
||||||
|
self.prepare_ecash_ticket(ticket_type, gateway_id.to_bytes(), tickets_to_spend)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,30 +8,24 @@ license = { workspace = true }
|
|||||||
repository = { workspace = true }
|
repository = { workspace = true }
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
chrono = { workspace = true, optional = true }
|
|
||||||
cfg-if = { workspace = true }
|
|
||||||
clap = { workspace = true, features = ["derive"], optional = true }
|
clap = { workspace = true, features = ["derive"], optional = true }
|
||||||
clap_complete = { workspace = true, optional = true }
|
clap_complete = { workspace = true, optional = true }
|
||||||
clap_complete_fig = { workspace = true, optional = true }
|
clap_complete_fig = { workspace = true, optional = true }
|
||||||
const-str = { workspace = true }
|
const-str = { workspace = true }
|
||||||
opentelemetry = { workspace = true, optional = true }
|
log = { workspace = true }
|
||||||
opentelemetry-otlp = { workspace = true,features=["metrics", "grpc-tonic", "tls",
|
|
||||||
"tls-webpki-roots"], optional = true }
|
|
||||||
opentelemetry-semantic-conventions = { workspace = true, features = ["semconv_experimental"], optional = true }
|
|
||||||
opentelemetry-stdout = { workspace = true, features = ["trace", "metrics"], optional = true }
|
|
||||||
opentelemetry_sdk = { workspace = true, optional = true }
|
|
||||||
rand = { workspace = true, optional = true }
|
|
||||||
schemars = { workspace = true, features = ["preserve_order"], optional = true }
|
schemars = { workspace = true, features = ["preserve_order"], optional = true }
|
||||||
serde = { workspace = true, features = ["derive"] }
|
serde = { workspace = true, features = ["derive"] }
|
||||||
serde_json = { workspace = true, optional = true }
|
serde_json = { workspace = true, optional = true }
|
||||||
thiserror = { workspace = true }
|
|
||||||
tracing = { workspace = true }
|
## tracing
|
||||||
tracing-core = { workspace = true }
|
tracing-subscriber = { workspace = true, features = ["env-filter"], optional = true }
|
||||||
|
tracing-tree = { workspace = true, optional = true }
|
||||||
|
tracing = { workspace = true, optional = true }
|
||||||
|
opentelemetry-jaeger = { workspace = true, features = ["rt-tokio", "collector_client", "isahc_collector_client"], optional = true }
|
||||||
tracing-opentelemetry = { workspace = true, optional = true }
|
tracing-opentelemetry = { workspace = true, optional = true }
|
||||||
tracing-serde = { workspace = true }
|
|
||||||
tracing-subscriber = { workspace = true, features = ["env-filter", "json"] }
|
|
||||||
tracing-tree = { workspace = true }
|
|
||||||
utoipa = { workspace = true, optional = true }
|
utoipa = { workspace = true, optional = true }
|
||||||
|
opentelemetry = { workspace = true, features = ["rt-tokio"], optional = true }
|
||||||
|
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
vergen = { workspace = true, features = ["build", "git", "gitcl", "rustc", "cargo"] }
|
vergen = { workspace = true, features = ["build", "git", "gitcl", "rustc", "cargo"] }
|
||||||
@@ -41,17 +35,13 @@ default = []
|
|||||||
openapi = ["utoipa"]
|
openapi = ["utoipa"]
|
||||||
output_format = ["serde_json", "dep:clap"]
|
output_format = ["serde_json", "dep:clap"]
|
||||||
bin_info_schema = ["schemars"]
|
bin_info_schema = ["schemars"]
|
||||||
tokio-console = ["otel"]
|
basic_tracing = ["dep:tracing", "tracing-subscriber"]
|
||||||
otel = [
|
tracing = [
|
||||||
"chrono",
|
"basic_tracing",
|
||||||
|
"tracing-tree",
|
||||||
|
"opentelemetry-jaeger",
|
||||||
"tracing-opentelemetry",
|
"tracing-opentelemetry",
|
||||||
"opentelemetry",
|
"opentelemetry",
|
||||||
"opentelemetry-otlp",
|
|
||||||
"opentelemetry-semantic-conventions",
|
|
||||||
"opentelemetry-stdout",
|
|
||||||
"opentelemetry_sdk",
|
|
||||||
"serde_json",
|
|
||||||
"rand",
|
|
||||||
]
|
]
|
||||||
clap = ["dep:clap", "dep:clap_complete", "dep:clap_complete_fig"]
|
clap = ["dep:clap", "dep:clap_complete", "dep:clap_complete_fig"]
|
||||||
models = []
|
models = []
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
|
use clap::Args;
|
||||||
use clap::builder::Command;
|
use clap::builder::Command;
|
||||||
use clap::clap_derive::ValueEnum;
|
use clap::clap_derive::ValueEnum;
|
||||||
use clap::Args;
|
|
||||||
use clap_complete::generator::generate;
|
|
||||||
use clap_complete::Shell as ClapShell;
|
use clap_complete::Shell as ClapShell;
|
||||||
|
use clap_complete::generator::generate;
|
||||||
use std::io;
|
use std::io;
|
||||||
|
|
||||||
pub fn fig_generate(command: &mut Command, name: &str) {
|
pub fn fig_generate(command: &mut Command, name: &str) {
|
||||||
|
|||||||
@@ -4,9 +4,6 @@
|
|||||||
pub mod build_information;
|
pub mod build_information;
|
||||||
pub mod logging;
|
pub mod logging;
|
||||||
|
|
||||||
#[cfg(feature = "otel")]
|
|
||||||
pub mod opentelemetry;
|
|
||||||
|
|
||||||
#[cfg(feature = "clap")]
|
#[cfg(feature = "clap")]
|
||||||
pub mod completions;
|
pub mod completions;
|
||||||
|
|
||||||
|
|||||||
@@ -1,20 +0,0 @@
|
|||||||
// Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
#[cfg(feature = "otel")]
|
|
||||||
use opentelemetry_otlp::ExporterBuildError;
|
|
||||||
|
|
||||||
#[derive(thiserror::Error, Debug)]
|
|
||||||
pub enum TracingError {
|
|
||||||
#[error("tracing logger already initialised")]
|
|
||||||
TracingLoggerAlreadyInitialised,
|
|
||||||
|
|
||||||
#[error("Logging error: {0}")]
|
|
||||||
TracingTryInitError(tracing_subscriber::util::TryInitError),
|
|
||||||
|
|
||||||
#[cfg(feature = "otel")]
|
|
||||||
#[error("{0}")]
|
|
||||||
TracingExporterBuildError(#[from] ExporterBuildError),
|
|
||||||
|
|
||||||
#[error("{0}")]
|
|
||||||
TracingFilterParseError(#[from] tracing_subscriber::filter::ParseError),
|
|
||||||
}
|
|
||||||
@@ -1,12 +1,19 @@
|
|||||||
// Copyright 2022-2023 - Nym Technologies SA <contact@nymtech.net>
|
// Copyright 2022-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
pub mod error;
|
|
||||||
|
|
||||||
use error::TracingError;
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::io::IsTerminal;
|
use std::io::IsTerminal;
|
||||||
use tracing_subscriber::{filter::Directive, layer::SubscriberExt, util::SubscriberInitExt};
|
|
||||||
|
#[cfg(feature = "tracing")]
|
||||||
|
pub use opentelemetry;
|
||||||
|
#[cfg(feature = "tracing")]
|
||||||
|
pub use opentelemetry_jaeger;
|
||||||
|
#[cfg(feature = "tracing")]
|
||||||
|
pub use tracing_opentelemetry;
|
||||||
|
#[cfg(feature = "tracing")]
|
||||||
|
pub use tracing_subscriber;
|
||||||
|
#[cfg(feature = "tracing")]
|
||||||
|
pub use tracing_tree;
|
||||||
|
|
||||||
#[derive(Debug, Default, Copy, Clone, Deserialize, PartialEq, Eq, Serialize)]
|
#[derive(Debug, Default, Copy, Clone, Deserialize, PartialEq, Eq, Serialize)]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
@@ -15,6 +22,7 @@ pub struct LoggingSettings {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// don't call init so that we could attach additional layers
|
// don't call init so that we could attach additional layers
|
||||||
|
#[cfg(feature = "basic_tracing")]
|
||||||
pub fn build_tracing_logger() -> impl tracing_subscriber::layer::SubscriberExt {
|
pub fn build_tracing_logger() -> impl tracing_subscriber::layer::SubscriberExt {
|
||||||
use tracing_subscriber::prelude::*;
|
use tracing_subscriber::prelude::*;
|
||||||
|
|
||||||
@@ -23,6 +31,7 @@ pub fn build_tracing_logger() -> impl tracing_subscriber::layer::SubscriberExt {
|
|||||||
.with(default_tracing_env_filter())
|
.with(default_tracing_env_filter())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "basic_tracing")]
|
||||||
pub fn default_tracing_env_filter() -> tracing_subscriber::filter::EnvFilter {
|
pub fn default_tracing_env_filter() -> tracing_subscriber::filter::EnvFilter {
|
||||||
if ::std::env::var("RUST_LOG").is_ok() {
|
if ::std::env::var("RUST_LOG").is_ok() {
|
||||||
tracing_subscriber::filter::EnvFilter::from_default_env()
|
tracing_subscriber::filter::EnvFilter::from_default_env()
|
||||||
@@ -34,6 +43,7 @@ pub fn default_tracing_env_filter() -> tracing_subscriber::filter::EnvFilter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "basic_tracing")]
|
||||||
pub fn default_tracing_fmt_layer<S, W>(
|
pub fn default_tracing_fmt_layer<S, W>(
|
||||||
writer: W,
|
writer: W,
|
||||||
) -> impl tracing_subscriber::Layer<S> + Sync + Send + 'static
|
) -> impl tracing_subscriber::Layer<S> + Sync + Send + 'static
|
||||||
@@ -53,47 +63,45 @@ where
|
|||||||
.with_target(false)
|
.with_target(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a tracing filter that sets more granular log levels for specific crates.
|
#[cfg(feature = "basic_tracing")]
|
||||||
/// This allows for finer control over logging verbosity.
|
pub fn setup_tracing_logger() {
|
||||||
pub(crate) fn granual_filtered_env() -> Result<tracing_subscriber::filter::EnvFilter, TracingError>
|
use tracing_subscriber::util::SubscriberInitExt;
|
||||||
{
|
build_tracing_logger().init()
|
||||||
fn directive_checked(directive: impl Into<String>) -> Result<Directive, TracingError> {
|
|
||||||
directive.into().parse().map_err(From::from)
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut filter = default_tracing_env_filter();
|
|
||||||
|
|
||||||
// these crates are more granularly filtered
|
|
||||||
let filter_crates = ["defguard_wireguard_rs"];
|
|
||||||
for crate_name in filter_crates {
|
|
||||||
filter = filter.add_directive(directive_checked(format!("{crate_name}=warn"))?);
|
|
||||||
}
|
|
||||||
Ok(filter)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn setup_no_otel_logger() -> Result<(), TracingError> {
|
|
||||||
// Only set up if not already initialized
|
|
||||||
if tracing::dispatcher::has_been_set() {
|
|
||||||
// It shouldn't be - this is really checking that it is torn down between async command executions
|
|
||||||
return Err(TracingError::TracingLoggerAlreadyInitialised);
|
|
||||||
}
|
|
||||||
|
|
||||||
let registry = tracing_subscriber::registry()
|
|
||||||
.with(default_tracing_fmt_layer(std::io::stderr))
|
|
||||||
.with(granual_filtered_env()?);
|
|
||||||
|
|
||||||
registry
|
|
||||||
.try_init()
|
|
||||||
.map_err(|e| TracingError::TracingTryInitError(e))?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: This has to be a macro, running it as a function does not work for the file_appender for some reason
|
// TODO: This has to be a macro, running it as a function does not work for the file_appender for some reason
|
||||||
|
#[cfg(feature = "tracing")]
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! setup_tracing {
|
macro_rules! setup_tracing {
|
||||||
($service_name: expr) => {
|
($service_name: expr) => {
|
||||||
setup_no_otel_logger()
|
use nym_bin_common::logging::tracing_subscriber::layer::SubscriberExt;
|
||||||
|
use nym_bin_common::logging::tracing_subscriber::util::SubscriberInitExt;
|
||||||
|
|
||||||
|
let registry = nym_bin_common::logging::tracing_subscriber::Registry::default()
|
||||||
|
.with(nym_bin_common::logging::tracing_subscriber::EnvFilter::from_default_env())
|
||||||
|
.with(
|
||||||
|
nym_bin_common::logging::tracing_tree::HierarchicalLayer::new(4)
|
||||||
|
.with_targets(true)
|
||||||
|
.with_bracketed_fields(true),
|
||||||
|
);
|
||||||
|
|
||||||
|
let tracer = nym_bin_common::logging::opentelemetry_jaeger::new_collector_pipeline()
|
||||||
|
.with_endpoint("http://44.199.230.10:14268/api/traces")
|
||||||
|
.with_service_name($service_name)
|
||||||
|
.with_isahc()
|
||||||
|
.with_trace_config(
|
||||||
|
nym_bin_common::logging::opentelemetry::sdk::trace::config().with_sampler(
|
||||||
|
nym_bin_common::logging::opentelemetry::sdk::trace::Sampler::TraceIdRatioBased(
|
||||||
|
0.1,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.install_batch(nym_bin_common::logging::opentelemetry::runtime::Tokio)
|
||||||
|
.expect("Could not init tracer");
|
||||||
|
|
||||||
|
let telemetry = nym_bin_common::logging::tracing_opentelemetry::layer().with_tracer(tracer);
|
||||||
|
|
||||||
|
registry.with(telemetry).init();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,47 +0,0 @@
|
|||||||
use opentelemetry_sdk::trace::IdGenerator;
|
|
||||||
use opentelemetry::trace::{TraceId, SpanId};
|
|
||||||
use rand::RngCore;
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub struct Compact13BytesIdGenerator;
|
|
||||||
|
|
||||||
impl IdGenerator for Compact13BytesIdGenerator {
|
|
||||||
fn new_trace_id(&self) -> TraceId {
|
|
||||||
let mut rng = rand::thread_rng();
|
|
||||||
let mut bytes = [0u8; 16];
|
|
||||||
|
|
||||||
// Fill the first 13 bytes with random data
|
|
||||||
rng.fill_bytes(&mut bytes[0..12]);
|
|
||||||
// Set the last 4 bytes to zero
|
|
||||||
bytes[12] = 0;
|
|
||||||
bytes[13] = 0;
|
|
||||||
bytes[14] = 0;
|
|
||||||
bytes[15] = 0;
|
|
||||||
|
|
||||||
TraceId::from_bytes(bytes)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn new_span_id(&self) -> SpanId {
|
|
||||||
let mut rng = rand::thread_rng();
|
|
||||||
let mut bytes = [0u8; 8];
|
|
||||||
rng.fill_bytes(&mut bytes);
|
|
||||||
|
|
||||||
SpanId::from_bytes(bytes)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn compress_trace_id(trace_id: &TraceId) -> [u8; 12] {
|
|
||||||
let bytes = trace_id.to_bytes();
|
|
||||||
|
|
||||||
let mut compressed = [0u8; 12];
|
|
||||||
compressed.copy_from_slice(&bytes[0..12]);
|
|
||||||
|
|
||||||
compressed
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn decompress_trace_id(compressed: &[u8; 12]) -> [u8; 16] {
|
|
||||||
let mut bytes = [0u8; 16];
|
|
||||||
bytes[0..12].copy_from_slice(compressed);
|
|
||||||
bytes[12..].copy_from_slice(&[0u8; 4]);
|
|
||||||
bytes
|
|
||||||
}
|
|
||||||
@@ -1,156 +0,0 @@
|
|||||||
use opentelemetry::{Context, TraceFlags};
|
|
||||||
use opentelemetry::propagation::{Injector, Extractor, TextMapPropagator};
|
|
||||||
use opentelemetry::trace::{SpanContext, TraceContextExt, TraceId};
|
|
||||||
use opentelemetry_sdk::{propagation::TraceContextPropagator, trace::IdGenerator};
|
|
||||||
use tracing_opentelemetry::OpenTelemetrySpanExt;
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::fmt::Display;
|
|
||||||
use tracing::instrument;
|
|
||||||
|
|
||||||
/// Make a Carrier for context propagation
|
|
||||||
pub struct ContextCarrier {
|
|
||||||
data: HashMap<String, String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ContextCarrier {
|
|
||||||
pub fn new_empty() -> Self {
|
|
||||||
ContextCarrier {
|
|
||||||
data: HashMap::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new_with_data(data: HashMap<String, String>) -> Self {
|
|
||||||
if data.is_empty() {
|
|
||||||
return ContextCarrier::new_empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
ContextCarrier { data }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new_with_current_context(context: Context) -> Self {
|
|
||||||
let mut carrier = ContextCarrier::new_empty();
|
|
||||||
let propagator = TraceContextPropagator::new();
|
|
||||||
propagator.inject_context(&context, &mut carrier);
|
|
||||||
carrier
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn iter(&self) -> impl Iterator<Item = (&String, &String)> {
|
|
||||||
self.data.iter()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn from_map(data: HashMap<String, String>) -> Self {
|
|
||||||
ContextCarrier { data }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn into_map(self) -> HashMap<String, String> {
|
|
||||||
self.data
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn extract_trace_id(&self) -> Option<TraceId> {
|
|
||||||
self.get("traceparent").and_then(|tp| {
|
|
||||||
let parts: Vec<&str> = tp.split('-').collect();
|
|
||||||
if parts.len() == 4 {
|
|
||||||
TraceId::from_hex(parts[1]).ok()
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn extract_trace_id_into_bytes(&self) -> Option<[u8; 16]> {
|
|
||||||
self.extract_trace_id().map(|id| id.to_bytes())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn extract_traceparent(&self) -> Option<String> {
|
|
||||||
self.get("traceparent").map(|s| s.to_string())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Injector for ContextCarrier {
|
|
||||||
fn set(&mut self, key: &str, value: String) {
|
|
||||||
self.data.insert(key.to_string(), value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Extractor for ContextCarrier {
|
|
||||||
fn get(&self, key: &str) -> Option<&str> {
|
|
||||||
self.data.get(key).map(|s| s.as_str())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn keys(&self) -> Vec<&str> {
|
|
||||||
self.data.keys().map(|k| k.as_str()).collect()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for ContextCarrier {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
write!(f, "{:?}", self.data)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct ManualContextPropagator {
|
|
||||||
pub root_span: tracing::Span,
|
|
||||||
pub trace_id: TraceId,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ManualContextPropagator {
|
|
||||||
#[instrument(skip_all, level = "debug")]
|
|
||||||
pub fn new(name: &str, context: HashMap<String, String>) -> Self {
|
|
||||||
let carrier = ContextCarrier::new_with_data(context);
|
|
||||||
let trace_id = match carrier.extract_trace_id() {
|
|
||||||
Some(id) => id,
|
|
||||||
None => Context::current().span().span_context().trace_id(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let root_span_builder = new_span_context_with_id(trace_id.clone());
|
|
||||||
|
|
||||||
let root_span = tracing::info_span!("trace_root", name = %name, trace_id = %trace_id);
|
|
||||||
root_span.set_parent(root_span_builder);
|
|
||||||
|
|
||||||
ManualContextPropagator {
|
|
||||||
root_span,
|
|
||||||
trace_id,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[instrument(skip_all, level = "debug")]
|
|
||||||
pub fn new_from_tid(name: &str, trace_id: TraceId) -> Self {
|
|
||||||
let root_span_builder = new_span_context_with_id(trace_id.clone());
|
|
||||||
|
|
||||||
let root_span = tracing::info_span!("trace_root", name = %name, trace_id = %trace_id);
|
|
||||||
root_span.set_parent(root_span_builder);
|
|
||||||
|
|
||||||
ManualContextPropagator {
|
|
||||||
root_span,
|
|
||||||
trace_id,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn root_span(&self) -> &tracing::Span {
|
|
||||||
&self.root_span
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#[instrument(skip_all, level = "debug")]
|
|
||||||
pub fn new_span_context_with_id(trace_id: TraceId) -> Context {
|
|
||||||
let id_gen = opentelemetry_sdk::trace::RandomIdGenerator::default();
|
|
||||||
let span_id = id_gen.new_span_id();
|
|
||||||
let span_context = SpanContext::new(
|
|
||||||
trace_id,
|
|
||||||
span_id,
|
|
||||||
TraceFlags::SAMPLED,
|
|
||||||
true,
|
|
||||||
Default::default(),
|
|
||||||
);
|
|
||||||
|
|
||||||
Context::current().with_remote_span_context(span_context)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[instrument(skip_all, level = "debug")]
|
|
||||||
pub fn extract_trace_id_from_tracing_cx() -> TraceId {
|
|
||||||
let cx = tracing::Span::current().context();
|
|
||||||
let binding = cx.span();
|
|
||||||
let trace_id = binding.span_context().trace_id();
|
|
||||||
trace_id
|
|
||||||
}
|
|
||||||
@@ -1,308 +0,0 @@
|
|||||||
pub mod context;
|
|
||||||
pub mod compact_id_generator;
|
|
||||||
mod trace_id_format;
|
|
||||||
|
|
||||||
use tracing::{info, Level};
|
|
||||||
use tracing_subscriber::filter::Directive;
|
|
||||||
use tracing_subscriber::layer::SubscriberExt;
|
|
||||||
use tracing_subscriber::util::SubscriberInitExt;
|
|
||||||
use tracing_subscriber::fmt;
|
|
||||||
|
|
||||||
use crate::logging::default_tracing_env_filter;
|
|
||||||
use crate::logging::error::TracingError;
|
|
||||||
use crate::opentelemetry::compact_id_generator::Compact13BytesIdGenerator;
|
|
||||||
use opentelemetry::trace::TracerProvider;
|
|
||||||
use opentelemetry::{global, KeyValue};
|
|
||||||
use opentelemetry_otlp::tonic_types::metadata::MetadataMap;
|
|
||||||
use opentelemetry_otlp::tonic_types::transport::ClientTlsConfig;
|
|
||||||
use opentelemetry_otlp::{WithExportConfig, WithTonicConfig};
|
|
||||||
use opentelemetry_sdk::metrics::{MeterProviderBuilder, PeriodicReader, SdkMeterProvider};
|
|
||||||
use opentelemetry_sdk::trace::SdkTracerProvider;
|
|
||||||
use opentelemetry_sdk::{trace::Sampler, Resource};
|
|
||||||
use opentelemetry_semantic_conventions::resource::{DEPLOYMENT_ENVIRONMENT_NAME, SERVICE_VERSION};
|
|
||||||
use opentelemetry_semantic_conventions::SCHEMA_URL;
|
|
||||||
use tracing_opentelemetry::{MetricsLayer, OpenTelemetryLayer};
|
|
||||||
use tracing_subscriber::fmt::format::FmtSpan;
|
|
||||||
|
|
||||||
pub struct TracerProviderGuard(Option<SdkTracerProvider>);
|
|
||||||
|
|
||||||
impl Drop for TracerProviderGuard {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
if let Some(tracer_provider) = self.0.take() {
|
|
||||||
// Ensure all spans are flushed before exit
|
|
||||||
if let Err(e) = tracer_provider.shutdown() {
|
|
||||||
eprintln!("Error shutting down tracer provider: {:?}", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn granual_filtered_env() -> Result<tracing_subscriber::filter::EnvFilter, TracingError>
|
|
||||||
{
|
|
||||||
fn directive_checked(directive: impl Into<String>) -> Result<Directive, TracingError> {
|
|
||||||
directive.into().parse().map_err(From::from)
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut filter = default_tracing_env_filter();
|
|
||||||
|
|
||||||
// these crates are more granularly filtered
|
|
||||||
let filter_crates = ["defguard_wireguard_rs"];
|
|
||||||
for crate_name in filter_crates {
|
|
||||||
filter = filter.add_directive(directive_checked(format!("{crate_name}=warn"))?);
|
|
||||||
}
|
|
||||||
Ok(filter)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn setup_tracing_logger(service_name: String) -> Result<TracerProviderGuard, TracingError> {
|
|
||||||
if tracing::dispatcher::has_been_set() {
|
|
||||||
// It shouldn't be - this is really checking that it is torn down between async command executions
|
|
||||||
return Err(TracingError::TracingLoggerAlreadyInitialised);
|
|
||||||
}
|
|
||||||
|
|
||||||
// define ingestion points
|
|
||||||
let endpoint = std::env::var("SIGNOZ_ENDPOINT").expect("SIGNOZ_ENDPOINT not set");
|
|
||||||
let key = std::env::var("SIGNOZ_INGESTION_KEY").expect("SIGNOZ_INGESTION_KEY not set");
|
|
||||||
let mut metadata = MetadataMap::new();
|
|
||||||
metadata.insert(
|
|
||||||
"signoz-ingestion-key",
|
|
||||||
key.parse().expect("Could not parse signoz ingestion key"),
|
|
||||||
);
|
|
||||||
|
|
||||||
// Build resources
|
|
||||||
let resource = build_resource(&service_name);
|
|
||||||
|
|
||||||
// Initialize tracer and meter providers
|
|
||||||
let tracer_provider = init_tracer_provider(&endpoint, metadata.clone(), resource.clone())?;
|
|
||||||
let meter_provider = init_meter_provider(&endpoint, metadata.clone(), resource.clone())?;
|
|
||||||
|
|
||||||
// Bridge tracing and opentelemetry
|
|
||||||
let tracer = tracer_provider.tracer("otel-subscriber");
|
|
||||||
let fmt_layer = fmt::layer()
|
|
||||||
.json()
|
|
||||||
.with_writer(std::io::stderr)
|
|
||||||
.with_span_events(FmtSpan::NEW | FmtSpan::CLOSE)
|
|
||||||
.with_span_list(false)
|
|
||||||
.with_current_span(true)
|
|
||||||
.event_format(trace_id_format::TraceIdFormat);
|
|
||||||
|
|
||||||
let registry = tracing_subscriber::registry()
|
|
||||||
.with(fmt_layer)
|
|
||||||
.with(granual_filtered_env()?)
|
|
||||||
.with(tracing_subscriber::filter::LevelFilter::from_level(Level::INFO))
|
|
||||||
.with(MetricsLayer::new(meter_provider.clone()))
|
|
||||||
.with(OpenTelemetryLayer::new(tracer));
|
|
||||||
|
|
||||||
registry.try_init().map_err(TracingError::TracingTryInitError)?;
|
|
||||||
|
|
||||||
global::set_tracer_provider(tracer_provider.clone());
|
|
||||||
global::set_meter_provider(meter_provider.clone());
|
|
||||||
|
|
||||||
info!("Tracing initialized with service name: {}", service_name);
|
|
||||||
|
|
||||||
Ok(TracerProviderGuard(Some(tracer_provider)))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn build_resource(service_name: &str) -> Resource {
|
|
||||||
Resource::builder()
|
|
||||||
.with_service_name(service_name.to_string())
|
|
||||||
.with_schema_url(
|
|
||||||
[
|
|
||||||
KeyValue::new(SERVICE_VERSION, env!("CARGO_PKG_VERSION")),
|
|
||||||
KeyValue::new(DEPLOYMENT_ENVIRONMENT_NAME, "develop"),
|
|
||||||
],
|
|
||||||
SCHEMA_URL,
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn init_tracer_provider(
|
|
||||||
endpoint: &str,
|
|
||||||
metadata: MetadataMap,
|
|
||||||
resource: Resource,
|
|
||||||
) -> Result<SdkTracerProvider, TracingError> {
|
|
||||||
let mut exporter_builder = opentelemetry_otlp::SpanExporter::builder()
|
|
||||||
.with_tonic()
|
|
||||||
.with_metadata(metadata)
|
|
||||||
.with_endpoint(endpoint);
|
|
||||||
|
|
||||||
if endpoint.starts_with("https://") {
|
|
||||||
exporter_builder =
|
|
||||||
exporter_builder.with_tls_config(ClientTlsConfig::new().with_enabled_roots());
|
|
||||||
}
|
|
||||||
|
|
||||||
let exporter = exporter_builder.build()?;
|
|
||||||
|
|
||||||
let tracer = SdkTracerProvider::builder()
|
|
||||||
.with_sampler(Sampler::ParentBased(Box::new(Sampler::TraceIdRatioBased(
|
|
||||||
1.0,
|
|
||||||
))))
|
|
||||||
.with_id_generator(Compact13BytesIdGenerator)
|
|
||||||
.with_resource(resource)
|
|
||||||
.with_batch_exporter(exporter)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
global::set_tracer_provider(tracer.clone());
|
|
||||||
Ok(tracer)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn init_meter_provider(
|
|
||||||
endpoint: &str,
|
|
||||||
metadata: MetadataMap,
|
|
||||||
resource: Resource,
|
|
||||||
) -> Result<SdkMeterProvider, TracingError> {
|
|
||||||
let mut exporter_builder = opentelemetry_otlp::MetricExporter::builder()
|
|
||||||
.with_tonic()
|
|
||||||
.with_metadata(metadata)
|
|
||||||
.with_endpoint(endpoint)
|
|
||||||
.with_temporality(opentelemetry_sdk::metrics::Temporality::default());
|
|
||||||
|
|
||||||
if endpoint.starts_with("https://") {
|
|
||||||
exporter_builder = exporter_builder.with_tls_config(ClientTlsConfig::new().with_enabled_roots());
|
|
||||||
}
|
|
||||||
|
|
||||||
let exporter = exporter_builder.build()?;
|
|
||||||
|
|
||||||
let reader = PeriodicReader::builder(exporter)
|
|
||||||
.with_interval(std::time::Duration::from_secs(30))
|
|
||||||
.build();
|
|
||||||
|
|
||||||
let stdout_reader =
|
|
||||||
PeriodicReader::builder(opentelemetry_stdout::MetricExporter::default()).build();
|
|
||||||
|
|
||||||
let meter_provider = MeterProviderBuilder::default()
|
|
||||||
.with_resource(resource)
|
|
||||||
.with_reader(reader)
|
|
||||||
.with_reader(stdout_reader)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
global::set_meter_provider(meter_provider.clone());
|
|
||||||
|
|
||||||
Ok(meter_provider)
|
|
||||||
}
|
|
||||||
|
|
||||||
// pub fn setup_tracing_logger(service_name: String) -> Result<(), TracingError> {
|
|
||||||
// if tracing::dispatcher::has_been_set() {
|
|
||||||
// // It shouldn't be - this is really checking that it is torn down between async command executions
|
|
||||||
// return Err(TracingError::TracingLoggerAlreadyInitialised);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// let key =
|
|
||||||
// std::env::var("SIGNOZ_INGESTION_KEY".to_string()).expect("SIGNOZ_INGESTION_KEY not set");
|
|
||||||
// let mut metadata = MetadataMap::new();
|
|
||||||
// metadata.insert(
|
|
||||||
// "signoz-ingestion-key",
|
|
||||||
// key.parse().expect("Could not parse signoz ingestion key"),
|
|
||||||
// );
|
|
||||||
|
|
||||||
// let tracer_provider = init_tracer_provider(metadata.clone(), service_name.clone())?;
|
|
||||||
// let meter_provider = init_meter_provider(metadata.clone(), service_name.clone())?;
|
|
||||||
// let tracer = tracer_provider.tracer("tracing-otel-subscriber");
|
|
||||||
// let fmt_layer = fmt::layer()
|
|
||||||
// .json()
|
|
||||||
// .with_writer(std::io::stderr)
|
|
||||||
// .with_span_events(FmtSpan::NEW | FmtSpan::CLOSE)
|
|
||||||
// .with_span_list(false)
|
|
||||||
// .with_current_span(true)
|
|
||||||
// .event_format(trace_id_format::TraceIdFormat);
|
|
||||||
|
|
||||||
// cfg_if::cfg_if! {if #[cfg(feature = "tokio-console")] {
|
|
||||||
// // instrument tokio console subscriber needs RUSTFLAGS="--cfg tokio_unstable" at build time
|
|
||||||
// let console_layer = console_subscriber::spawn();
|
|
||||||
|
|
||||||
// tracing_subscriber::registry()
|
|
||||||
// .with(console_layer)
|
|
||||||
// .with(fmt_layer)
|
|
||||||
// .with(granual_filtered_env()?)
|
|
||||||
// .with(tracing_subscriber::filter::LevelFilter::from_level(Level::INFO))
|
|
||||||
// .with(MetricsLayer::new(meter_provider))
|
|
||||||
// .with(OpenTelemetryLayer::new(tracer))
|
|
||||||
// .try_init()
|
|
||||||
// .map_err(|e| TracingError::TracingTryInitError(e))?;
|
|
||||||
// } else {
|
|
||||||
// tracing_subscriber::registry()
|
|
||||||
// .with(fmt_layer)
|
|
||||||
// .with(granual_filtered_env()?)
|
|
||||||
// .with(tracing_subscriber::filter::LevelFilter::from_level(Level::INFO))
|
|
||||||
// .with(MetricsLayer::new(meter_provider))
|
|
||||||
// .with(OpenTelemetryLayer::new(tracer))
|
|
||||||
// .try_init()
|
|
||||||
// .map_err(|e| TracingError::TracingTryInitError(e))?;
|
|
||||||
// }}
|
|
||||||
|
|
||||||
// Ok(())
|
|
||||||
// }
|
|
||||||
|
|
||||||
// fn resource(service_name: String) -> Resource {
|
|
||||||
// Resource::builder()
|
|
||||||
// .with_service_name(service_name)
|
|
||||||
// .with_schema_url(
|
|
||||||
// [
|
|
||||||
// KeyValue::new(SERVICE_VERSION, env!("CARGO_PKG_VERSION")),
|
|
||||||
// KeyValue::new(DEPLOYMENT_ENVIRONMENT_NAME, "develop"),
|
|
||||||
// ],
|
|
||||||
// SCHEMA_URL,
|
|
||||||
// )
|
|
||||||
// .build()
|
|
||||||
// }
|
|
||||||
|
|
||||||
// fn init_tracer_provider(metadata: MetadataMap, service_name: String) -> Result<SdkTracerProvider, TracingError> {
|
|
||||||
// let endpoint = std::env::var("SIGNOZ_ENDPOINT".to_string()).expect("SIGNOZ_ENDPOINT not set");
|
|
||||||
// info!("SIGNOZ_ENDPOINT = {}", endpoint);
|
|
||||||
|
|
||||||
// let mut exporter_builder = opentelemetry_otlp::SpanExporter::builder()
|
|
||||||
// .with_tonic()
|
|
||||||
// .with_metadata(metadata)
|
|
||||||
// .with_endpoint(&endpoint);
|
|
||||||
|
|
||||||
// if endpoint.starts_with("https://") {
|
|
||||||
// exporter_builder =
|
|
||||||
// exporter_builder.with_tls_config(ClientTlsConfig::new().with_enabled_roots());
|
|
||||||
// }
|
|
||||||
|
|
||||||
// let exporter = exporter_builder.build()?;
|
|
||||||
|
|
||||||
// let tracer = SdkTracerProvider::builder()
|
|
||||||
// .with_sampler(Sampler::ParentBased(Box::new(Sampler::TraceIdRatioBased(
|
|
||||||
// 1.0,
|
|
||||||
// ))))
|
|
||||||
// .with_id_generator(Compact13BytesIdGenerator)
|
|
||||||
// .with_resource(resource(service_name))
|
|
||||||
// .with_batch_exporter(exporter)
|
|
||||||
// .build();
|
|
||||||
|
|
||||||
// global::set_tracer_provider(tracer.clone());
|
|
||||||
// Ok(tracer)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// fn init_meter_provider(metadata: MetadataMap, service_name: String) -> Result<SdkMeterProvider, TracingError> {
|
|
||||||
// let endpoint = std::env::var("SIGNOZ_ENDPOINT".to_string()).expect("SIGNOZ_ENDPOINT not set");
|
|
||||||
|
|
||||||
// let mut exporter_builder = opentelemetry_otlp::MetricExporter::builder()
|
|
||||||
// .with_tonic()
|
|
||||||
// .with_metadata(metadata)
|
|
||||||
// .with_endpoint(&endpoint)
|
|
||||||
// .with_temporality(opentelemetry_sdk::metrics::Temporality::default());
|
|
||||||
|
|
||||||
// if endpoint.starts_with("https://") {
|
|
||||||
// exporter_builder = exporter_builder.with_tls_config(ClientTlsConfig::new().with_enabled_roots());
|
|
||||||
// }
|
|
||||||
|
|
||||||
// let exporter = exporter_builder.build()?;
|
|
||||||
|
|
||||||
// let reader = PeriodicReader::builder(exporter)
|
|
||||||
// .with_interval(std::time::Duration::from_secs(30))
|
|
||||||
// .build();
|
|
||||||
|
|
||||||
// let stdout_reader =
|
|
||||||
// PeriodicReader::builder(opentelemetry_stdout::MetricExporter::default()).build();
|
|
||||||
|
|
||||||
// let meter_provider = MeterProviderBuilder::default()
|
|
||||||
// .with_resource(resource(service_name))
|
|
||||||
// .with_reader(reader)
|
|
||||||
// .with_reader(stdout_reader)
|
|
||||||
// .build();
|
|
||||||
|
|
||||||
// global::set_meter_provider(meter_provider.clone());
|
|
||||||
|
|
||||||
// Ok(meter_provider)
|
|
||||||
// }
|
|
||||||
@@ -1,88 +0,0 @@
|
|||||||
use chrono::Utc;
|
|
||||||
use opentelemetry::trace::TraceContextExt;
|
|
||||||
use opentelemetry::{SpanId, TraceId};
|
|
||||||
use serde::ser::{SerializeMap, Serializer as _};
|
|
||||||
use std::io;
|
|
||||||
use tracing::{Event, Subscriber};
|
|
||||||
use tracing_opentelemetry::OpenTelemetrySpanExt;
|
|
||||||
use tracing_serde::fields::AsMap;
|
|
||||||
use tracing_serde::AsSerde;
|
|
||||||
use tracing_subscriber::fmt::format::Writer;
|
|
||||||
use tracing_subscriber::fmt::{FmtContext, FormatEvent, FormatFields};
|
|
||||||
use tracing_subscriber::registry::LookupSpan;
|
|
||||||
|
|
||||||
pub struct WriteAdaptor<'a> {
|
|
||||||
fmt_write: &'a mut dyn std::fmt::Write,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> WriteAdaptor<'a> {
|
|
||||||
pub fn new(fmt_write: &'a mut dyn std::fmt::Write) -> Self {
|
|
||||||
Self { fmt_write }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> io::Write for WriteAdaptor<'a> {
|
|
||||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
|
||||||
let s =
|
|
||||||
std::str::from_utf8(buf).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
|
|
||||||
|
|
||||||
self.fmt_write
|
|
||||||
.write_str(s)
|
|
||||||
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
|
|
||||||
|
|
||||||
Ok(s.as_bytes().len())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn flush(&mut self) -> io::Result<()> {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct TraceIdFormat;
|
|
||||||
|
|
||||||
impl<S, N> FormatEvent<S, N> for TraceIdFormat
|
|
||||||
where
|
|
||||||
S: Subscriber + for<'lookup> LookupSpan<'lookup>,
|
|
||||||
N: for<'writer> FormatFields<'writer> + 'static,
|
|
||||||
{
|
|
||||||
fn format_event(
|
|
||||||
&self,
|
|
||||||
_ctx: &FmtContext<'_, S, N>,
|
|
||||||
mut writer: Writer<'_>,
|
|
||||||
event: &Event<'_>,
|
|
||||||
) -> std::fmt::Result
|
|
||||||
where
|
|
||||||
S: Subscriber + for<'a> LookupSpan<'a>,
|
|
||||||
{
|
|
||||||
let meta = event.metadata();
|
|
||||||
|
|
||||||
let mut visit = || {
|
|
||||||
let mut serializer = serde_json::Serializer::new(WriteAdaptor::new(&mut writer));
|
|
||||||
let mut serializer = serializer.serialize_map(None)?;
|
|
||||||
serializer.serialize_entry("timestamp", &Utc::now().to_rfc3339())?;
|
|
||||||
serializer.serialize_entry("level", &meta.level().as_serde())?;
|
|
||||||
serializer.serialize_entry("fields", &event.field_map())?;
|
|
||||||
serializer.serialize_entry("target", meta.target())?;
|
|
||||||
|
|
||||||
let current_span = tracing::Span::current();
|
|
||||||
let context = current_span.context();
|
|
||||||
let span_ref = context.span();
|
|
||||||
let span_context = span_ref.span_context();
|
|
||||||
|
|
||||||
let trace_id = span_context.trace_id();
|
|
||||||
if trace_id != TraceId::INVALID {
|
|
||||||
serializer.serialize_entry("trace_id", &trace_id.to_string())?;
|
|
||||||
|
|
||||||
let span_id = span_context.span_id();
|
|
||||||
if span_id != SpanId::INVALID {
|
|
||||||
serializer.serialize_entry("span_id", &span_id.to_string())?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
serializer.end()
|
|
||||||
};
|
|
||||||
|
|
||||||
visit().map_err(|_| std::fmt::Error)?;
|
|
||||||
writeln!(writer)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -3,7 +3,7 @@ name = "nym-client-core"
|
|||||||
version = "1.1.15"
|
version = "1.1.15"
|
||||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
|
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
rust-version = "1.76"
|
rust-version = "1.85"
|
||||||
license.workspace = true
|
license.workspace = true
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
@@ -36,7 +36,7 @@ nym-bandwidth-controller = { path = "../bandwidth-controller" }
|
|||||||
nym-crypto = { path = "../crypto" }
|
nym-crypto = { path = "../crypto" }
|
||||||
nym-gateway-client = { path = "../client-libs/gateway-client" }
|
nym-gateway-client = { path = "../client-libs/gateway-client" }
|
||||||
nym-gateway-requests = { path = "../gateway-requests" }
|
nym-gateway-requests = { path = "../gateway-requests" }
|
||||||
nym-http-api-client = { path = "../http-api-client" }
|
nym-http-api-client = { path = "../http-api-client", features = ["network-defaults"] }
|
||||||
nym-nonexhaustive-delayqueue = { path = "../nonexhaustive-delayqueue" }
|
nym-nonexhaustive-delayqueue = { path = "../nonexhaustive-delayqueue" }
|
||||||
nym-sphinx = { path = "../nymsphinx" }
|
nym-sphinx = { path = "../nymsphinx" }
|
||||||
nym-statistics-common = { path = "../statistics" }
|
nym-statistics-common = { path = "../statistics" }
|
||||||
@@ -69,7 +69,6 @@ workspace = true
|
|||||||
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.hyper-util]
|
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.hyper-util]
|
||||||
workspace = true
|
workspace = true
|
||||||
features = ["tokio"]
|
features = ["tokio"]
|
||||||
###
|
|
||||||
|
|
||||||
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.tokio-stream]
|
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.tokio-stream]
|
||||||
workspace = true
|
workspace = true
|
||||||
@@ -103,7 +102,7 @@ workspace = true
|
|||||||
features = ["tokio"]
|
features = ["tokio"]
|
||||||
|
|
||||||
[target."cfg(target_arch = \"wasm32\")".dependencies.gloo-timers]
|
[target."cfg(target_arch = \"wasm32\")".dependencies.gloo-timers]
|
||||||
version = "0.3.0"
|
workspace = true
|
||||||
features = ["futures"]
|
features = ["futures"]
|
||||||
|
|
||||||
[target."cfg(target_arch = \"wasm32\")".dependencies.wasm-utils]
|
[target."cfg(target_arch = \"wasm32\")".dependencies.wasm-utils]
|
||||||
@@ -114,6 +113,10 @@ features = ["websocket"]
|
|||||||
workspace = true
|
workspace = true
|
||||||
features = ["wasm-bindgen"]
|
features = ["wasm-bindgen"]
|
||||||
|
|
||||||
|
[target."cfg(target_arch = \"wasm32\")".dependencies.tokio_with_wasm]
|
||||||
|
workspace = true
|
||||||
|
features = ["full"]
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
tempfile = { workspace = true }
|
tempfile = { workspace = true }
|
||||||
|
|
||||||
@@ -123,7 +126,6 @@ cli = ["clap", "comfy-table"]
|
|||||||
fs-credentials-storage = ["nym-credential-storage/persistent-storage"]
|
fs-credentials-storage = ["nym-credential-storage/persistent-storage"]
|
||||||
fs-surb-storage = ["nym-client-core-surb-storage/fs-surb-storage"]
|
fs-surb-storage = ["nym-client-core-surb-storage/fs-surb-storage"]
|
||||||
fs-gateways-storage = ["nym-client-core-gateways-storage/fs-gateways-storage"]
|
fs-gateways-storage = ["nym-client-core-gateways-storage/fs-gateways-storage"]
|
||||||
otel = ["nym-sphinx/otel"]
|
|
||||||
wasm = ["nym-gateway-client/wasm"]
|
wasm = ["nym-gateway-client/wasm"]
|
||||||
metrics-server = []
|
metrics-server = []
|
||||||
|
|
||||||
|
|||||||
@@ -707,13 +707,10 @@ pub struct DebugConfig {
|
|||||||
|
|
||||||
/// Defines all configuration options related to reply SURBs.
|
/// Defines all configuration options related to reply SURBs.
|
||||||
pub reply_surbs: ReplySurbs,
|
pub reply_surbs: ReplySurbs,
|
||||||
|
|
||||||
/// Defines all configuration options related to stats reporting.
|
/// Defines all configuration options related to stats reporting.
|
||||||
pub stats_reporting: StatsReporting,
|
pub stats_reporting: StatsReporting,
|
||||||
|
|
||||||
/// Defines all configuration options related to the forget me flag.
|
/// Defines all configuration options related to the forget me flag.
|
||||||
pub forget_me: ForgetMe,
|
pub forget_me: ForgetMe,
|
||||||
|
|
||||||
/// Defines all configuration options related to the remember me flag.
|
/// Defines all configuration options related to the remember me flag.
|
||||||
pub remember_me: RememberMe,
|
pub remember_me: RememberMe,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -543,10 +543,8 @@ pub struct DebugConfigV6 {
|
|||||||
|
|
||||||
/// Defines all configuration options related to reply SURBs.
|
/// Defines all configuration options related to reply SURBs.
|
||||||
pub reply_surbs: ReplySurbsV6,
|
pub reply_surbs: ReplySurbsV6,
|
||||||
|
|
||||||
/// Defines all configuration options related to stats reporting.
|
/// Defines all configuration options related to stats reporting.
|
||||||
pub stats_reporting: StatsReportingV6,
|
pub stats_reporting: StatsReportingV6,
|
||||||
|
|
||||||
/// Defines all configuration options related to the forget me flag.
|
/// Defines all configuration options related to the forget me flag.
|
||||||
pub forget_me: ForgetMeV6,
|
pub forget_me: ForgetMeV6,
|
||||||
|
|
||||||
|
|||||||
@@ -31,7 +31,6 @@ impl StorageManager {
|
|||||||
}
|
}
|
||||||
})?;
|
})?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let opts = sqlx::sqlite::SqliteConnectOptions::new()
|
let opts = sqlx::sqlite::SqliteConnectOptions::new()
|
||||||
.journal_mode(sqlx::sqlite::SqliteJournalMode::Wal)
|
.journal_mode(sqlx::sqlite::SqliteJournalMode::Wal)
|
||||||
.synchronous(SqliteSynchronous::Normal)
|
.synchronous(SqliteSynchronous::Normal)
|
||||||
|
|||||||
@@ -114,13 +114,12 @@ where
|
|||||||
})?;
|
})?;
|
||||||
hardcoded_topology.entry_capable_nodes().cloned().collect()
|
hardcoded_topology.entry_capable_nodes().cloned().collect()
|
||||||
} else {
|
} else {
|
||||||
let mut rng = rand::thread_rng();
|
|
||||||
crate::init::helpers::gateways_for_init(
|
crate::init::helpers::gateways_for_init(
|
||||||
&mut rng,
|
|
||||||
&core.client.nym_api_urls,
|
&core.client.nym_api_urls,
|
||||||
user_agent,
|
user_agent,
|
||||||
core.debug.topology.minimum_gateway_performance,
|
core.debug.topology.minimum_gateway_performance,
|
||||||
core.debug.topology.ignore_ingress_epoch_role,
|
core.debug.topology.ignore_ingress_epoch_role,
|
||||||
|
None,
|
||||||
)
|
)
|
||||||
.await?
|
.await?
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -173,13 +173,12 @@ where
|
|||||||
})?;
|
})?;
|
||||||
hardcoded_topology.entry_capable_nodes().cloned().collect()
|
hardcoded_topology.entry_capable_nodes().cloned().collect()
|
||||||
} else {
|
} else {
|
||||||
let mut rng = rand::thread_rng();
|
|
||||||
crate::init::helpers::gateways_for_init(
|
crate::init::helpers::gateways_for_init(
|
||||||
&mut rng,
|
|
||||||
&core.client.nym_api_urls,
|
&core.client.nym_api_urls,
|
||||||
user_agent,
|
user_agent,
|
||||||
core.debug.topology.minimum_gateway_performance,
|
core.debug.topology.minimum_gateway_performance,
|
||||||
core.debug.topology.ignore_ingress_epoch_role,
|
core.debug.topology.ignore_ingress_epoch_role,
|
||||||
|
None,
|
||||||
)
|
)
|
||||||
.await?
|
.await?
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -7,11 +7,12 @@ use super::statistics_control::StatisticsControl;
|
|||||||
use crate::client::base_client::storage::helpers::store_client_keys;
|
use crate::client::base_client::storage::helpers::store_client_keys;
|
||||||
use crate::client::base_client::storage::MixnetClientStorage;
|
use crate::client::base_client::storage::MixnetClientStorage;
|
||||||
use crate::client::cover_traffic_stream::LoopCoverTrafficStream;
|
use crate::client::cover_traffic_stream::LoopCoverTrafficStream;
|
||||||
|
use crate::client::event_control::EventControl;
|
||||||
use crate::client::inbound_messages::{InputMessage, InputMessageReceiver, InputMessageSender};
|
use crate::client::inbound_messages::{InputMessage, InputMessageReceiver, InputMessageSender};
|
||||||
use crate::client::key_manager::persistence::KeyStore;
|
use crate::client::key_manager::persistence::KeyStore;
|
||||||
use crate::client::key_manager::ClientKeys;
|
use crate::client::key_manager::ClientKeys;
|
||||||
use crate::client::mix_traffic::transceiver::{GatewayReceiver, GatewayTransceiver, RemoteGateway};
|
use crate::client::mix_traffic::transceiver::{GatewayReceiver, GatewayTransceiver, RemoteGateway};
|
||||||
use crate::client::mix_traffic::{BatchMixMessageSender, MixTrafficController};
|
use crate::client::mix_traffic::{BatchMixMessageSender, MixTrafficController, MixTrafficEvent};
|
||||||
use crate::client::real_messages_control;
|
use crate::client::real_messages_control;
|
||||||
use crate::client::real_messages_control::RealMessagesController;
|
use crate::client::real_messages_control::RealMessagesController;
|
||||||
use crate::client::received_buffer::{
|
use crate::client::received_buffer::{
|
||||||
@@ -66,9 +67,16 @@ use std::path::Path;
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use time::OffsetDateTime;
|
use time::OffsetDateTime;
|
||||||
use tokio::sync::mpsc::Sender;
|
use tokio::sync::mpsc::Sender;
|
||||||
use tracing::*;
|
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
|
#[cfg(target_arch = "wasm32")]
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
use wasm_utils::console_log;
|
||||||
|
|
||||||
|
/// Default number of retries for Nym API requests when using network details with domain fronting.
|
||||||
|
/// This allows the client to try alternative URLs if the primary endpoint is unavailable.
|
||||||
|
const DEFAULT_NYM_API_RETRIES: usize = 3;
|
||||||
|
|
||||||
#[cfg(all(
|
#[cfg(all(
|
||||||
not(target_arch = "wasm32"),
|
not(target_arch = "wasm32"),
|
||||||
feature = "fs-surb-storage",
|
feature = "fs-surb-storage",
|
||||||
@@ -79,10 +87,28 @@ pub mod non_wasm_helpers;
|
|||||||
pub mod helpers;
|
pub mod helpers;
|
||||||
pub mod storage;
|
pub mod storage;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub enum MixnetClientEvent {
|
||||||
|
Traffic(MixTrafficEvent),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type EventReceiver = mpsc::UnboundedReceiver<MixnetClientEvent>;
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct EventSender(pub mpsc::UnboundedSender<MixnetClientEvent>);
|
||||||
|
|
||||||
|
impl EventSender {
|
||||||
|
pub fn send(&self, event: MixnetClientEvent) {
|
||||||
|
if let Err(err) = self.0.unbounded_send(event) {
|
||||||
|
tracing::warn!("Failed to send error event. The caller event reader was closed: {err}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct ClientInput {
|
pub struct ClientInput {
|
||||||
pub connection_command_sender: ConnectionCommandSender,
|
pub connection_command_sender: ConnectionCommandSender,
|
||||||
pub input_sender: InputMessageSender,
|
pub input_sender: InputMessageSender,
|
||||||
|
pub client_request_sender: ClientRequestSender,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ClientInput {
|
impl ClientInput {
|
||||||
@@ -99,7 +125,6 @@ pub struct ClientOutput {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ClientOutput {
|
impl ClientOutput {
|
||||||
#[instrument(name = "ClientOutput::register_receiver", skip_all)]
|
|
||||||
pub fn register_receiver(
|
pub fn register_receiver(
|
||||||
&mut self,
|
&mut self,
|
||||||
) -> Result<mpsc::UnboundedReceiver<Vec<ReconstructedMessage>>, ClientCoreError> {
|
) -> Result<mpsc::UnboundedReceiver<Vec<ReconstructedMessage>>, ClientCoreError> {
|
||||||
@@ -191,10 +216,14 @@ pub struct BaseClientBuilder<C, S: MixnetClientStorage> {
|
|||||||
client_store: S,
|
client_store: S,
|
||||||
dkg_query_client: Option<C>,
|
dkg_query_client: Option<C>,
|
||||||
|
|
||||||
|
// Optional API URLs for domain fronting support
|
||||||
|
nym_api_urls: Option<Vec<nym_network_defaults::ApiUrl>>,
|
||||||
|
|
||||||
wait_for_gateway: bool,
|
wait_for_gateway: bool,
|
||||||
custom_topology_provider: Option<Box<dyn TopologyProvider + Send + Sync>>,
|
custom_topology_provider: Option<Box<dyn TopologyProvider + Send + Sync>>,
|
||||||
custom_gateway_transceiver: Option<Box<dyn GatewayTransceiver + Send>>,
|
custom_gateway_transceiver: Option<Box<dyn GatewayTransceiver + Send>>,
|
||||||
shutdown: Option<ShutdownTracker>,
|
shutdown: Option<ShutdownTracker>,
|
||||||
|
event_tx: Option<EventSender>,
|
||||||
user_agent: Option<UserAgent>,
|
user_agent: Option<UserAgent>,
|
||||||
|
|
||||||
setup_method: GatewaySetup,
|
setup_method: GatewaySetup,
|
||||||
@@ -219,10 +248,12 @@ where
|
|||||||
config: base_config,
|
config: base_config,
|
||||||
client_store,
|
client_store,
|
||||||
dkg_query_client,
|
dkg_query_client,
|
||||||
|
nym_api_urls: None,
|
||||||
wait_for_gateway: false,
|
wait_for_gateway: false,
|
||||||
custom_topology_provider: None,
|
custom_topology_provider: None,
|
||||||
custom_gateway_transceiver: None,
|
custom_gateway_transceiver: None,
|
||||||
shutdown: None,
|
shutdown: None,
|
||||||
|
event_tx: None,
|
||||||
user_agent: None,
|
user_agent: None,
|
||||||
setup_method: GatewaySetup::MustLoad { gateway_id: None },
|
setup_method: GatewaySetup::MustLoad { gateway_id: None },
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
@@ -240,6 +271,16 @@ where
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set Nym API URLs for domain fronting support.
|
||||||
|
///
|
||||||
|
/// When provided, the client will use these API URLs (which include front_hosts)
|
||||||
|
/// to construct HTTP clients with domain fronting enabled.
|
||||||
|
#[must_use]
|
||||||
|
pub fn with_nym_api_urls(mut self, nym_api_urls: Vec<nym_network_defaults::ApiUrl>) -> Self {
|
||||||
|
self.nym_api_urls = Some(nym_api_urls);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn with_forget_me(mut self, forget_me: &ForgetMe) -> Self {
|
pub fn with_forget_me(mut self, forget_me: &ForgetMe) -> Self {
|
||||||
self.config.debug.forget_me = *forget_me;
|
self.config.debug.forget_me = *forget_me;
|
||||||
@@ -285,6 +326,12 @@ where
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn with_event_tx(mut self, event_tx: EventSender) -> Self {
|
||||||
|
self.event_tx = Some(event_tx);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn with_user_agent(mut self, user_agent: UserAgent) -> Self {
|
pub fn with_user_agent(mut self, user_agent: UserAgent) -> Self {
|
||||||
self.user_agent = Some(user_agent);
|
self.user_agent = Some(user_agent);
|
||||||
@@ -315,6 +362,18 @@ where
|
|||||||
details.client_address()
|
details.client_address()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn start_event_control(
|
||||||
|
parent_event_tx: Option<EventSender>,
|
||||||
|
children_event_rx: EventReceiver,
|
||||||
|
shutdown_tracker: &ShutdownTracker,
|
||||||
|
) {
|
||||||
|
let event_control = EventControl::new(parent_event_tx, children_event_rx);
|
||||||
|
shutdown_tracker.try_spawn_named_with_shutdown(
|
||||||
|
async move { event_control.run().await },
|
||||||
|
"EventControl",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// future constantly pumping loop cover traffic at some specified average rate
|
// future constantly pumping loop cover traffic at some specified average rate
|
||||||
// the pumped traffic goes to the MixTrafficController
|
// the pumped traffic goes to the MixTrafficController
|
||||||
fn start_cover_traffic_stream(
|
fn start_cover_traffic_stream(
|
||||||
@@ -326,7 +385,7 @@ where
|
|||||||
stats_tx: ClientStatsSender,
|
stats_tx: ClientStatsSender,
|
||||||
shutdown_tracker: &ShutdownTracker,
|
shutdown_tracker: &ShutdownTracker,
|
||||||
) {
|
) {
|
||||||
info!("Starting loop cover traffic stream...");
|
tracing::info!("Starting loop cover traffic stream...");
|
||||||
|
|
||||||
let mut stream = LoopCoverTrafficStream::new(
|
let mut stream = LoopCoverTrafficStream::new(
|
||||||
ack_key,
|
ack_key,
|
||||||
@@ -358,7 +417,7 @@ where
|
|||||||
stats_tx: ClientStatsSender,
|
stats_tx: ClientStatsSender,
|
||||||
shutdown_tracker: &ShutdownTracker,
|
shutdown_tracker: &ShutdownTracker,
|
||||||
) {
|
) {
|
||||||
info!("Starting real traffic stream...");
|
tracing::info!("Starting real traffic stream...");
|
||||||
|
|
||||||
let real_messages_controller = RealMessagesController::new(
|
let real_messages_controller = RealMessagesController::new(
|
||||||
controller_config,
|
controller_config,
|
||||||
@@ -434,7 +493,6 @@ where
|
|||||||
|
|
||||||
// buffer controlling all messages fetched from provider
|
// buffer controlling all messages fetched from provider
|
||||||
// required so that other components would be able to use them (say the websocket)
|
// required so that other components would be able to use them (say the websocket)
|
||||||
#[instrument(skip_all)]
|
|
||||||
fn start_received_messages_buffer_controller(
|
fn start_received_messages_buffer_controller(
|
||||||
local_encryption_keypair: Arc<x25519::KeyPair>,
|
local_encryption_keypair: Arc<x25519::KeyPair>,
|
||||||
query_receiver: ReceivedBufferRequestReceiver,
|
query_receiver: ReceivedBufferRequestReceiver,
|
||||||
@@ -444,7 +502,7 @@ where
|
|||||||
metrics_reporter: ClientStatsSender,
|
metrics_reporter: ClientStatsSender,
|
||||||
shutdown_tracker: &ShutdownTracker,
|
shutdown_tracker: &ShutdownTracker,
|
||||||
) {
|
) {
|
||||||
info!("Starting received messages buffer controller...");
|
tracing::info!("Starting received messages buffer controller...");
|
||||||
let controller = ReceivedMessagesBufferController::<SphinxMessageReceiver>::new(
|
let controller = ReceivedMessagesBufferController::<SphinxMessageReceiver>::new(
|
||||||
local_encryption_keypair,
|
local_encryption_keypair,
|
||||||
query_receiver,
|
query_receiver,
|
||||||
@@ -467,7 +525,6 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
#[instrument(skip_all)]
|
|
||||||
async fn start_gateway_client(
|
async fn start_gateway_client(
|
||||||
config: &Config,
|
config: &Config,
|
||||||
initialisation_result: InitialisationResult,
|
initialisation_result: InitialisationResult,
|
||||||
@@ -556,7 +613,7 @@ where
|
|||||||
details_store
|
details_store
|
||||||
.upgrade_stored_remote_gateway_key(gateway_client.gateway_identity(), &updated_key)
|
.upgrade_stored_remote_gateway_key(gateway_client.gateway_identity(), &updated_key)
|
||||||
.await.map_err(|err| {
|
.await.map_err(|err| {
|
||||||
error!("failed to store upgraded gateway key! this connection might be forever broken now: {err}");
|
tracing::error!("failed to store upgraded gateway key! this connection might be forever broken now: {err}");
|
||||||
ClientCoreError::GatewaysDetailsStoreError { source: Box::new(err) }
|
ClientCoreError::GatewaysDetailsStoreError { source: Box::new(err) }
|
||||||
})?
|
})?
|
||||||
}
|
}
|
||||||
@@ -574,7 +631,6 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
#[instrument(skip_all)]
|
|
||||||
async fn setup_gateway_transceiver(
|
async fn setup_gateway_transceiver(
|
||||||
custom_gateway_transceiver: Option<Box<dyn GatewayTransceiver + Send>>,
|
custom_gateway_transceiver: Option<Box<dyn GatewayTransceiver + Send>>,
|
||||||
config: &Config,
|
config: &Config,
|
||||||
@@ -654,7 +710,7 @@ where
|
|||||||
|
|
||||||
if topology_config.disable_refreshing {
|
if topology_config.disable_refreshing {
|
||||||
// if we're not spawning the refresher, don't cause shutdown immediately
|
// if we're not spawning the refresher, don't cause shutdown immediately
|
||||||
info!("The background topology refresher is not going to be started");
|
tracing::info!("The background topology refresher is not going to be started");
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut topology_refresher = TopologyRefresher::new(
|
let mut topology_refresher = TopologyRefresher::new(
|
||||||
@@ -664,7 +720,7 @@ where
|
|||||||
);
|
);
|
||||||
// before returning, block entire runtime to refresh the current network view so that any
|
// before returning, block entire runtime to refresh the current network view so that any
|
||||||
// components depending on topology would see a non-empty view
|
// components depending on topology would see a non-empty view
|
||||||
info!("Obtaining initial network topology");
|
tracing::info!("Obtaining initial network topology");
|
||||||
topology_refresher.try_refresh().await;
|
topology_refresher.try_refresh().await;
|
||||||
|
|
||||||
if let Err(err) = topology_refresher.ensure_topology_is_routable().await {
|
if let Err(err) = topology_refresher.ensure_topology_is_routable().await {
|
||||||
@@ -690,13 +746,13 @@ where
|
|||||||
.wait_for_gateway(local_gateway, waiting_timeout)
|
.wait_for_gateway(local_gateway, waiting_timeout)
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
error!(
|
tracing::error!(
|
||||||
"the gateway did not come back online within the specified timeout: {err}"
|
"the gateway did not come back online within the specified timeout: {err}"
|
||||||
);
|
);
|
||||||
return Err(err.into());
|
return Err(err.into());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
error!("the gateway we're supposedly connected to does not exist. We'll not be able to send any packets to ourselves: {err}");
|
tracing::error!("the gateway we're supposedly connected to does not exist. We'll not be able to send any packets to ourselves: {err}");
|
||||||
return Err(err.into());
|
return Err(err.into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -704,7 +760,7 @@ where
|
|||||||
if !topology_config.disable_refreshing {
|
if !topology_config.disable_refreshing {
|
||||||
// don't spawn the refresher if we don't want to be refreshing the topology.
|
// don't spawn the refresher if we don't want to be refreshing the topology.
|
||||||
// only use the initial values obtained
|
// only use the initial values obtained
|
||||||
info!("Starting topology refresher...");
|
tracing::info!("Starting topology refresher...");
|
||||||
shutdown_tracker.try_spawn_named_with_shutdown(
|
shutdown_tracker.try_spawn_named_with_shutdown(
|
||||||
async move { topology_refresher.run().await },
|
async move { topology_refresher.run().await },
|
||||||
"TopologyRefresher",
|
"TopologyRefresher",
|
||||||
@@ -721,7 +777,7 @@ where
|
|||||||
input_sender: Sender<InputMessage>,
|
input_sender: Sender<InputMessage>,
|
||||||
shutdown_tracker: &ShutdownTracker,
|
shutdown_tracker: &ShutdownTracker,
|
||||||
) -> ClientStatsSender {
|
) -> ClientStatsSender {
|
||||||
info!("Starting statistics control...");
|
tracing::info!("Starting statistics control...");
|
||||||
StatisticsControl::create_and_start(
|
StatisticsControl::create_and_start(
|
||||||
config.debug.stats_reporting,
|
config.debug.stats_reporting,
|
||||||
user_agent
|
user_agent
|
||||||
@@ -732,14 +788,21 @@ where
|
|||||||
shutdown_tracker,
|
shutdown_tracker,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
#[instrument(skip_all)]
|
|
||||||
fn start_mix_traffic_controller(
|
fn start_mix_traffic_controller(
|
||||||
gateway_transceiver: Box<dyn GatewayTransceiver + Send>,
|
gateway_transceiver: Box<dyn GatewayTransceiver + Send>,
|
||||||
shutdown_tracker: &ShutdownTracker,
|
shutdown_tracker: &ShutdownTracker,
|
||||||
|
event_tx: EventSender,
|
||||||
) -> (BatchMixMessageSender, ClientRequestSender) {
|
) -> (BatchMixMessageSender, ClientRequestSender) {
|
||||||
info!("Starting mix traffic controller...");
|
tracing::info!("Starting mix traffic controller...");
|
||||||
let (mut mix_traffic_controller, mix_tx, client_tx) =
|
let mut mix_traffic_controller = MixTrafficController::new(
|
||||||
MixTrafficController::new(gateway_transceiver, shutdown_tracker.clone_shutdown_token());
|
gateway_transceiver,
|
||||||
|
shutdown_tracker.clone_shutdown_token(),
|
||||||
|
event_tx,
|
||||||
|
);
|
||||||
|
|
||||||
|
let mix_tx = mix_traffic_controller.mix_tx();
|
||||||
|
let client_tx = mix_traffic_controller.client_tx();
|
||||||
|
|
||||||
shutdown_tracker.try_spawn_named(
|
shutdown_tracker.try_spawn_named(
|
||||||
async move { mix_traffic_controller.run().await },
|
async move { mix_traffic_controller.run().await },
|
||||||
@@ -803,7 +866,7 @@ where
|
|||||||
{
|
{
|
||||||
// if client keys do not exist already, create and persist them
|
// if client keys do not exist already, create and persist them
|
||||||
if key_store.load_keys().await.is_err() {
|
if key_store.load_keys().await.is_err() {
|
||||||
info!("could not find valid client keys - a new set will be generated");
|
tracing::info!("could not find valid client keys - a new set will be generated");
|
||||||
let mut rng = OsRng;
|
let mut rng = OsRng;
|
||||||
let keys = if let Some(derivation_material) = derivation_material {
|
let keys = if let Some(derivation_material) = derivation_material {
|
||||||
ClientKeys::from_master_key(&mut rng, &derivation_material)
|
ClientKeys::from_master_key(&mut rng, &derivation_material)
|
||||||
@@ -818,21 +881,67 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn construct_nym_api_client(
|
fn construct_nym_api_client(
|
||||||
|
nym_api_urls: Option<&Vec<nym_network_defaults::ApiUrl>>,
|
||||||
config: &Config,
|
config: &Config,
|
||||||
user_agent: Option<UserAgent>,
|
user_agent: Option<UserAgent>,
|
||||||
) -> Result<nym_http_api_client::Client, ClientCoreError> {
|
) -> Result<nym_http_api_client::Client, ClientCoreError> {
|
||||||
|
tracing::debug!(
|
||||||
|
"construct_nym_api_client called with nym_api_urls: {}",
|
||||||
|
nym_api_urls.is_some()
|
||||||
|
);
|
||||||
|
|
||||||
|
// If API URLs are provided, use new_with_fronted_urls() which handles domain fronting
|
||||||
|
if let Some(nym_api_urls) = nym_api_urls {
|
||||||
|
if nym_api_urls.is_empty() {
|
||||||
|
tracing::warn!("Provided nym_api_urls is empty, falling back to config endpoints");
|
||||||
|
} else {
|
||||||
|
tracing::info!(
|
||||||
|
"Building nym-api client from provided URLs (with domain fronting support): {} URLs",
|
||||||
|
nym_api_urls.len()
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut builder =
|
||||||
|
nym_http_api_client::ClientBuilder::new_with_fronted_urls(nym_api_urls.clone())
|
||||||
|
.map_err(ClientCoreError::from)?
|
||||||
|
.with_retries(DEFAULT_NYM_API_RETRIES);
|
||||||
|
|
||||||
|
if let Some(user_agent) = user_agent {
|
||||||
|
builder = builder.with_user_agent(user_agent);
|
||||||
|
}
|
||||||
|
|
||||||
|
return builder.build().map_err(ClientCoreError::from);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback to basic client for backwards compatibility
|
||||||
|
tracing::debug!("Building basic nym-api HTTP client from config endpoints");
|
||||||
|
|
||||||
let mut nym_api_urls = config.get_nym_api_endpoints();
|
let mut nym_api_urls = config.get_nym_api_endpoints();
|
||||||
|
if nym_api_urls.is_empty() {
|
||||||
|
tracing::warn!("No API endpoints configured in config, this may cause issues");
|
||||||
|
}
|
||||||
nym_api_urls.shuffle(&mut thread_rng());
|
nym_api_urls.shuffle(&mut thread_rng());
|
||||||
|
|
||||||
let mut builder = nym_http_api_client::Client::builder(nym_api_urls[0].clone())
|
// Convert config URLs to ApiUrl format for consistency
|
||||||
.map_err(ClientCoreError::from)?;
|
let api_urls: Vec<nym_network_defaults::ApiUrl> = nym_api_urls
|
||||||
|
.into_iter()
|
||||||
|
.map(|url| nym_network_defaults::ApiUrl {
|
||||||
|
url: url.to_string(),
|
||||||
|
front_hosts: None,
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
tracing::debug!("Using {} config API endpoints", api_urls.len());
|
||||||
|
|
||||||
|
let mut builder = nym_http_api_client::ClientBuilder::new_with_fronted_urls(api_urls)
|
||||||
|
.map_err(ClientCoreError::from)?
|
||||||
|
.with_retries(DEFAULT_NYM_API_RETRIES)
|
||||||
|
.with_bincode();
|
||||||
|
|
||||||
if let Some(user_agent) = user_agent {
|
if let Some(user_agent) = user_agent {
|
||||||
builder = builder.with_user_agent(user_agent);
|
builder = builder.with_user_agent(user_agent);
|
||||||
}
|
}
|
||||||
|
|
||||||
builder = builder.with_bincode();
|
|
||||||
|
|
||||||
builder.build().map_err(ClientCoreError::from)
|
builder.build().map_err(ClientCoreError::from)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -842,7 +951,6 @@ where
|
|||||||
Ok(client.get_key_rotation_info().await?.into())
|
Ok(client.get_key_rotation_info().await?.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(skip_all)]
|
|
||||||
pub async fn start_base(mut self) -> Result<BaseClient, ClientCoreError>
|
pub async fn start_base(mut self) -> Result<BaseClient, ClientCoreError>
|
||||||
where
|
where
|
||||||
S::ReplyStore: Send + Sync,
|
S::ReplyStore: Send + Sync,
|
||||||
@@ -851,7 +959,12 @@ where
|
|||||||
<S::CredentialStore as CredentialStorage>::StorageError: Send + Sync + 'static,
|
<S::CredentialStore as CredentialStorage>::StorageError: Send + Sync + 'static,
|
||||||
<S::GatewaysDetailsStore as GatewaysDetailsStore>::StorageError: Sync + Send,
|
<S::GatewaysDetailsStore as GatewaysDetailsStore>::StorageError: Sync + Send,
|
||||||
{
|
{
|
||||||
info!("Starting nym client");
|
tracing::info!("Starting nym client");
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
#[cfg(target_arch = "wasm32")]
|
||||||
|
{
|
||||||
|
console_log!("Starting base Nym Client");
|
||||||
|
}
|
||||||
|
|
||||||
// derive (or load) client keys and gateway configuration
|
// derive (or load) client keys and gateway configuration
|
||||||
let init_res = Self::initialise_keys_and_gateway(
|
let init_res = Self::initialise_keys_and_gateway(
|
||||||
@@ -880,6 +993,9 @@ where
|
|||||||
// channels responsible for controlling real messages
|
// channels responsible for controlling real messages
|
||||||
let (input_sender, input_receiver) = tokio::sync::mpsc::channel::<InputMessage>(1);
|
let (input_sender, input_receiver) = tokio::sync::mpsc::channel::<InputMessage>(1);
|
||||||
|
|
||||||
|
// channels responsible for event management
|
||||||
|
let (event_sender, event_receiver) = mpsc::unbounded();
|
||||||
|
|
||||||
// channels responsible for controlling ack messages
|
// channels responsible for controlling ack messages
|
||||||
let (ack_sender, ack_receiver) = mpsc::unbounded();
|
let (ack_sender, ack_receiver) = mpsc::unbounded();
|
||||||
let shared_topology_accessor =
|
let shared_topology_accessor =
|
||||||
@@ -888,10 +1004,12 @@ where
|
|||||||
// Create a shutdown tracker for this client - either as a child of provided tracker
|
// Create a shutdown tracker for this client - either as a child of provided tracker
|
||||||
// or get one from the registry
|
// or get one from the registry
|
||||||
let shutdown_tracker = match self.shutdown {
|
let shutdown_tracker = match self.shutdown {
|
||||||
Some(parent_tracker) => parent_tracker.child_tracker(),
|
Some(parent_tracker) => parent_tracker.clone(),
|
||||||
None => nym_task::get_sdk_shutdown_tracker()?,
|
None => nym_task::create_sdk_shutdown_tracker()?,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Self::start_event_control(self.event_tx, event_receiver, &shutdown_tracker);
|
||||||
|
|
||||||
// channels responsible for dealing with reply-related fun
|
// channels responsible for dealing with reply-related fun
|
||||||
let (reply_controller_sender, reply_controller_receiver) =
|
let (reply_controller_sender, reply_controller_receiver) =
|
||||||
reply_controller::requests::new_control_channels();
|
reply_controller::requests::new_control_channels();
|
||||||
@@ -907,7 +1025,11 @@ where
|
|||||||
.dkg_query_client
|
.dkg_query_client
|
||||||
.map(|client| BandwidthController::new(credential_store, client));
|
.map(|client| BandwidthController::new(credential_store, client));
|
||||||
|
|
||||||
let nym_api_client = Self::construct_nym_api_client(&self.config, self.user_agent.clone())?;
|
let nym_api_client = Self::construct_nym_api_client(
|
||||||
|
self.nym_api_urls.as_ref(),
|
||||||
|
&self.config,
|
||||||
|
self.user_agent.clone(),
|
||||||
|
)?;
|
||||||
let key_rotation_config = Self::determine_key_rotation_state(&nym_api_client).await?;
|
let key_rotation_config = Self::determine_key_rotation_state(&nym_api_client).await?;
|
||||||
|
|
||||||
let topology_provider = Self::setup_topology_provider(
|
let topology_provider = Self::setup_topology_provider(
|
||||||
@@ -922,7 +1044,7 @@ where
|
|||||||
self.user_agent.clone(),
|
self.user_agent.clone(),
|
||||||
generate_client_stats_id(*self_address.identity()),
|
generate_client_stats_id(*self_address.identity()),
|
||||||
input_sender.clone(),
|
input_sender.clone(),
|
||||||
&shutdown_tracker.child_tracker(),
|
&shutdown_tracker.clone(),
|
||||||
);
|
);
|
||||||
|
|
||||||
// needs to be started as the first thing to block if required waiting for the gateway
|
// needs to be started as the first thing to block if required waiting for the gateway
|
||||||
@@ -932,7 +1054,7 @@ where
|
|||||||
shared_topology_accessor.clone(),
|
shared_topology_accessor.clone(),
|
||||||
self_address.gateway(),
|
self_address.gateway(),
|
||||||
self.wait_for_gateway,
|
self.wait_for_gateway,
|
||||||
&shutdown_tracker.child_tracker(),
|
&shutdown_tracker.clone(),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
@@ -952,7 +1074,7 @@ where
|
|||||||
stats_reporter.clone(),
|
stats_reporter.clone(),
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
self.connection_fd_callback,
|
self.connection_fd_callback,
|
||||||
&shutdown_tracker.child_tracker(),
|
&shutdown_tracker.clone(),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
let gateway_ws_fd = gateway_transceiver.ws_fd();
|
let gateway_ws_fd = gateway_transceiver.ws_fd();
|
||||||
@@ -960,7 +1082,7 @@ where
|
|||||||
let reply_storage = Self::setup_persistent_reply_storage(
|
let reply_storage = Self::setup_persistent_reply_storage(
|
||||||
reply_storage_backend,
|
reply_storage_backend,
|
||||||
key_rotation_config,
|
key_rotation_config,
|
||||||
&shutdown_tracker.child_tracker(),
|
&shutdown_tracker.clone(),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
@@ -971,7 +1093,7 @@ where
|
|||||||
reply_storage.key_storage(),
|
reply_storage.key_storage(),
|
||||||
reply_controller_sender.clone(),
|
reply_controller_sender.clone(),
|
||||||
stats_reporter.clone(),
|
stats_reporter.clone(),
|
||||||
&shutdown_tracker.child_tracker(),
|
&shutdown_tracker.clone(),
|
||||||
);
|
);
|
||||||
|
|
||||||
// The message_sender is the transmitter for any component generating sphinx packets
|
// The message_sender is the transmitter for any component generating sphinx packets
|
||||||
@@ -981,7 +1103,8 @@ where
|
|||||||
|
|
||||||
let (message_sender, client_request_sender) = Self::start_mix_traffic_controller(
|
let (message_sender, client_request_sender) = Self::start_mix_traffic_controller(
|
||||||
gateway_transceiver,
|
gateway_transceiver,
|
||||||
&shutdown_tracker.child_tracker(),
|
&shutdown_tracker.clone(),
|
||||||
|
EventSender(event_sender),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Channels that the websocket listener can use to signal downstream to the real traffic
|
// Channels that the websocket listener can use to signal downstream to the real traffic
|
||||||
@@ -1011,7 +1134,7 @@ where
|
|||||||
shared_lane_queue_lengths.clone(),
|
shared_lane_queue_lengths.clone(),
|
||||||
client_connection_rx,
|
client_connection_rx,
|
||||||
stats_reporter.clone(),
|
stats_reporter.clone(),
|
||||||
&shutdown_tracker.child_tracker(),
|
&shutdown_tracker.clone(),
|
||||||
);
|
);
|
||||||
|
|
||||||
if !self
|
if !self
|
||||||
@@ -1027,12 +1150,19 @@ where
|
|||||||
shared_topology_accessor.clone(),
|
shared_topology_accessor.clone(),
|
||||||
message_sender,
|
message_sender,
|
||||||
stats_reporter.clone(),
|
stats_reporter.clone(),
|
||||||
&shutdown_tracker.child_tracker(),
|
&shutdown_tracker.clone(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
debug!("Core client startup finished!");
|
tracing::debug!("Core client startup finished!");
|
||||||
debug!("The address of this client is: {self_address}");
|
tracing::debug!("The address of this client is: {self_address}");
|
||||||
|
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
#[cfg(target_arch = "wasm32")]
|
||||||
|
{
|
||||||
|
console_log!("Core client startup finished!");
|
||||||
|
console_log!("Rust::start_base: the address of this client is: {self_address}");
|
||||||
|
}
|
||||||
|
|
||||||
Ok(BaseClient {
|
Ok(BaseClient {
|
||||||
address: self_address,
|
address: self_address,
|
||||||
@@ -1041,6 +1171,7 @@ where
|
|||||||
client_input: ClientInput {
|
client_input: ClientInput {
|
||||||
connection_command_sender: client_connection_tx,
|
connection_command_sender: client_connection_tx,
|
||||||
input_sender,
|
input_sender,
|
||||||
|
client_request_sender,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
client_output: ClientOutputStatus::AwaitingConsumer {
|
client_output: ClientOutputStatus::AwaitingConsumer {
|
||||||
@@ -1055,8 +1186,7 @@ where
|
|||||||
gateway_connection: GatewayConnection { gateway_ws_fd },
|
gateway_connection: GatewayConnection { gateway_ws_fd },
|
||||||
},
|
},
|
||||||
stats_reporter,
|
stats_reporter,
|
||||||
shutdown_handle: Some(shutdown_tracker), // The primary tracker for this client
|
shutdown_handle: shutdown_tracker, // The primary tracker for this client
|
||||||
client_request_sender,
|
|
||||||
forget_me: self.config.debug.forget_me,
|
forget_me: self.config.debug.forget_me,
|
||||||
remember_me: self.config.debug.remember_me,
|
remember_me: self.config.debug.remember_me,
|
||||||
})
|
})
|
||||||
@@ -1070,8 +1200,57 @@ pub struct BaseClient {
|
|||||||
pub client_output: ClientOutputStatus,
|
pub client_output: ClientOutputStatus,
|
||||||
pub client_state: ClientState,
|
pub client_state: ClientState,
|
||||||
pub stats_reporter: ClientStatsSender,
|
pub stats_reporter: ClientStatsSender,
|
||||||
pub client_request_sender: ClientRequestSender,
|
pub shutdown_handle: ShutdownTracker,
|
||||||
pub shutdown_handle: Option<ShutdownTracker>,
|
|
||||||
pub forget_me: ForgetMe,
|
pub forget_me: ForgetMe,
|
||||||
pub remember_me: RememberMe,
|
pub remember_me: RememberMe,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use nym_network_defaults::{ApiUrl, NymNetworkDetails};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_network_details_with_multiple_urls() {
|
||||||
|
// Verify that network details can be configured with multiple API URLs
|
||||||
|
let mut network_details = NymNetworkDetails::new_empty();
|
||||||
|
network_details.nym_api_urls = Some(vec![
|
||||||
|
ApiUrl {
|
||||||
|
url: "https://validator.nymtech.net/api/".to_string(),
|
||||||
|
front_hosts: None,
|
||||||
|
},
|
||||||
|
ApiUrl {
|
||||||
|
url: "https://nym-frontdoor.vercel.app/api/".to_string(),
|
||||||
|
front_hosts: Some(vec!["vercel.app".to_string(), "vercel.com".to_string()]),
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
assert_eq!(network_details.nym_api_urls.as_ref().unwrap().len(), 2);
|
||||||
|
assert!(network_details.nym_api_urls.as_ref().unwrap()[1]
|
||||||
|
.front_hosts
|
||||||
|
.is_some());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_network_details_with_front_hosts() {
|
||||||
|
// Verify that ApiUrl can store domain fronting configuration
|
||||||
|
let api_url = ApiUrl {
|
||||||
|
url: "https://nym-frontdoor.vercel.app/api/".to_string(),
|
||||||
|
front_hosts: Some(vec!["vercel.app".to_string(), "vercel.com".to_string()]),
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(api_url.url, "https://nym-frontdoor.vercel.app/api/");
|
||||||
|
assert_eq!(api_url.front_hosts.as_ref().unwrap().len(), 2);
|
||||||
|
assert!(api_url
|
||||||
|
.front_hosts
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.contains(&"vercel.app".to_string()));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_default_nym_api_retries_constant() {
|
||||||
|
// Verify the retry constant is set correctly
|
||||||
|
assert_eq!(DEFAULT_NYM_API_RETRIES, 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -205,7 +205,7 @@ impl LoopCoverTrafficStream<OsRng> {
|
|||||||
TrySendError::Full(_) => {
|
TrySendError::Full(_) => {
|
||||||
// This isn't a problem, if the channel is full means we're already sending the
|
// This isn't a problem, if the channel is full means we're already sending the
|
||||||
// max amount of messages downstream can handle.
|
// max amount of messages downstream can handle.
|
||||||
tracing::debug!("Failed to send cover message - channel full");
|
tracing::trace!("Failed to send cover message - channel full");
|
||||||
}
|
}
|
||||||
TrySendError::Closed(_) => {
|
TrySendError::Closed(_) => {
|
||||||
tracing::warn!("Failed to send cover message - channel closed");
|
tracing::warn!("Failed to send cover message - channel closed");
|
||||||
@@ -225,9 +225,15 @@ impl LoopCoverTrafficStream<OsRng> {
|
|||||||
// JS: due to identical logical structure to OutQueueControl::on_message(), this is also
|
// JS: due to identical logical structure to OutQueueControl::on_message(), this is also
|
||||||
// presumably required to prevent bugs in the future. Exact reason is still unknown to me.
|
// presumably required to prevent bugs in the future. Exact reason is still unknown to me.
|
||||||
|
|
||||||
// TODO: temporary and BAD workaround for wasm (we should find a way to yield here in wasm)
|
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
tokio::task::yield_now().await;
|
{
|
||||||
|
tokio::task::yield_now().await;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_arch = "wasm32")]
|
||||||
|
{
|
||||||
|
tokio_with_wasm::task::yield_now().await;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// it's fine if cover traffic stream task gets killed whilst processing next message
|
// it's fine if cover traffic stream task gets killed whilst processing next message
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
// Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
use futures::StreamExt;
|
||||||
|
|
||||||
|
use crate::client::base_client::{EventReceiver, EventSender, MixnetClientEvent};
|
||||||
|
|
||||||
|
/// Launches and manages task events, propagating upwards what is not strictly internal.
|
||||||
|
pub(crate) struct EventControl {
|
||||||
|
parent_event_tx: Option<EventSender>,
|
||||||
|
children_event_rx: EventReceiver,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EventControl {
|
||||||
|
pub(crate) fn new(
|
||||||
|
parent_event_tx: Option<EventSender>,
|
||||||
|
children_event_rx: EventReceiver,
|
||||||
|
) -> Self {
|
||||||
|
EventControl {
|
||||||
|
parent_event_tx,
|
||||||
|
children_event_rx,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_internal(event: MixnetClientEvent) -> bool {
|
||||||
|
match event {
|
||||||
|
MixnetClientEvent::Traffic(_) => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) async fn run(mut self) {
|
||||||
|
while let Some(event) = self.children_event_rx.next().await {
|
||||||
|
if let Some(parent_event_tx) = &self.parent_event_tx {
|
||||||
|
if !Self::is_internal(event) {
|
||||||
|
parent_event_tx.send(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,9 +2,9 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
#![allow(unused_imports)]
|
#![allow(unused_imports)]
|
||||||
|
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
|
#[cfg(target_arch = "wasm32")]
|
||||||
pub use wasmtimer::{std::Instant, tokio::*};
|
pub use wasmtimer::{std::Instant, tokio::*};
|
||||||
pub type IntervalStream = gloo_timers::future::IntervalStream;
|
pub type IntervalStream = gloo_timers::future::IntervalStream;
|
||||||
|
|
||||||
|
|||||||
@@ -29,8 +29,6 @@ pub enum InputMessage {
|
|||||||
data: Vec<u8>,
|
data: Vec<u8>,
|
||||||
lane: TransmissionLane,
|
lane: TransmissionLane,
|
||||||
max_retransmissions: Option<u32>,
|
max_retransmissions: Option<u32>,
|
||||||
// add trace_id for optional tracing of individual messages in debug mode
|
|
||||||
trace_id: Option<[u8; 12]>,
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/// Creates a message used for a duplex anonymous communication where the recipient
|
/// Creates a message used for a duplex anonymous communication where the recipient
|
||||||
@@ -47,7 +45,6 @@ pub enum InputMessage {
|
|||||||
reply_surbs: u32,
|
reply_surbs: u32,
|
||||||
lane: TransmissionLane,
|
lane: TransmissionLane,
|
||||||
max_retransmissions: Option<u32>,
|
max_retransmissions: Option<u32>,
|
||||||
trace_id: Option<[u8; 12]>,
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/// Attempt to use our internally received and stored `ReplySurb` to send the message back
|
/// Attempt to use our internally received and stored `ReplySurb` to send the message back
|
||||||
@@ -93,14 +90,12 @@ impl InputMessage {
|
|||||||
data: Vec<u8>,
|
data: Vec<u8>,
|
||||||
lane: TransmissionLane,
|
lane: TransmissionLane,
|
||||||
packet_type: Option<PacketType>,
|
packet_type: Option<PacketType>,
|
||||||
trace_id: Option<[u8; 12]>,
|
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let message = InputMessage::Regular {
|
let message = InputMessage::Regular {
|
||||||
recipient,
|
recipient,
|
||||||
data,
|
data,
|
||||||
lane,
|
lane,
|
||||||
max_retransmissions: None,
|
max_retransmissions: None,
|
||||||
trace_id,
|
|
||||||
};
|
};
|
||||||
if let Some(packet_type) = packet_type {
|
if let Some(packet_type) = packet_type {
|
||||||
InputMessage::new_wrapper(message, packet_type)
|
InputMessage::new_wrapper(message, packet_type)
|
||||||
@@ -115,7 +110,6 @@ impl InputMessage {
|
|||||||
reply_surbs: u32,
|
reply_surbs: u32,
|
||||||
lane: TransmissionLane,
|
lane: TransmissionLane,
|
||||||
packet_type: Option<PacketType>,
|
packet_type: Option<PacketType>,
|
||||||
trace_id: Option<[u8; 12]>,
|
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let message = InputMessage::Anonymous {
|
let message = InputMessage::Anonymous {
|
||||||
recipient,
|
recipient,
|
||||||
@@ -123,7 +117,6 @@ impl InputMessage {
|
|||||||
reply_surbs,
|
reply_surbs,
|
||||||
lane,
|
lane,
|
||||||
max_retransmissions: None,
|
max_retransmissions: None,
|
||||||
trace_id,
|
|
||||||
};
|
};
|
||||||
if let Some(packet_type) = packet_type {
|
if let Some(packet_type) = packet_type {
|
||||||
InputMessage::new_wrapper(message, packet_type)
|
InputMessage::new_wrapper(message, packet_type)
|
||||||
@@ -192,13 +185,4 @@ impl InputMessage {
|
|||||||
self.set_max_retransmissions(max_retransmissions);
|
self.set_max_retransmissions(max_retransmissions);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn trace_id(&self) -> Option<[u8; 12]> {
|
|
||||||
match self {
|
|
||||||
InputMessage::Regular { trace_id, .. } => *trace_id,
|
|
||||||
InputMessage::Anonymous { trace_id, .. } => *trace_id,
|
|
||||||
InputMessage::Premade { .. } | InputMessage::Reply { .. } => None,
|
|
||||||
InputMessage::MessageWrapper { message, .. } => message.trace_id(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use crate::client::mix_traffic::transceiver::GatewayTransceiver;
|
use crate::client::{
|
||||||
|
base_client::{EventSender, MixnetClientEvent},
|
||||||
|
mix_traffic::transceiver::GatewayTransceiver,
|
||||||
|
};
|
||||||
use nym_gateway_requests::ClientRequest;
|
use nym_gateway_requests::ClientRequest;
|
||||||
use nym_sphinx::forwarding::packet::MixPacket;
|
use nym_sphinx::forwarding::packet::MixPacket;
|
||||||
use nym_task::ShutdownToken;
|
use nym_task::ShutdownToken;
|
||||||
@@ -17,33 +20,41 @@ pub mod transceiver;
|
|||||||
|
|
||||||
// We remind ourselves that 32 x 32kb = 1024kb, a reasonable size for a network buffer.
|
// We remind ourselves that 32 x 32kb = 1024kb, a reasonable size for a network buffer.
|
||||||
pub const MIX_MESSAGE_RECEIVER_BUFFER_SIZE: usize = 32;
|
pub const MIX_MESSAGE_RECEIVER_BUFFER_SIZE: usize = 32;
|
||||||
const MAX_FAILURE_COUNT: usize = 100;
|
|
||||||
|
/// Reduced from 100 to 20 to fail fast (~1-2 seconds instead of ~6 seconds).
|
||||||
|
/// If we can't send 20 packets in a row, the gateway is unreachable.
|
||||||
|
const MAX_FAILURE_COUNT: usize = 20;
|
||||||
|
|
||||||
// that's also disgusting.
|
// that's also disgusting.
|
||||||
pub struct Empty;
|
pub struct Empty;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub enum MixTrafficEvent {
|
||||||
|
FailedSendingSphinx,
|
||||||
|
}
|
||||||
|
|
||||||
pub struct MixTrafficController {
|
pub struct MixTrafficController {
|
||||||
gateway_transceiver: Box<dyn GatewayTransceiver + Send>,
|
gateway_transceiver: Box<dyn GatewayTransceiver + Send>,
|
||||||
|
|
||||||
|
mix_tx: BatchMixMessageSender,
|
||||||
mix_rx: BatchMixMessageReceiver,
|
mix_rx: BatchMixMessageReceiver,
|
||||||
client_rx: ClientRequestReceiver,
|
client_rx: ClientRequestReceiver,
|
||||||
|
client_tx: ClientRequestSender,
|
||||||
|
|
||||||
// TODO: this is temporary work-around.
|
// TODO: this is temporary work-around.
|
||||||
// in long run `gateway_client` will be moved away from `MixTrafficController` anyway.
|
// in long run `gateway_client` will be moved away from `MixTrafficController` anyway.
|
||||||
consecutive_gateway_failure_count: usize,
|
consecutive_gateway_failure_count: usize,
|
||||||
|
|
||||||
shutdown_token: ShutdownToken,
|
shutdown_token: ShutdownToken,
|
||||||
|
event_tx: EventSender,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MixTrafficController {
|
impl MixTrafficController {
|
||||||
pub fn new<T>(
|
pub fn new<T>(
|
||||||
gateway_transceiver: T,
|
gateway_transceiver: T,
|
||||||
shutdown_token: ShutdownToken,
|
shutdown_token: ShutdownToken,
|
||||||
) -> (
|
event_tx: EventSender,
|
||||||
MixTrafficController,
|
) -> MixTrafficController
|
||||||
BatchMixMessageSender,
|
|
||||||
ClientRequestSender,
|
|
||||||
)
|
|
||||||
where
|
where
|
||||||
T: GatewayTransceiver + Send + 'static,
|
T: GatewayTransceiver + Send + 'static,
|
||||||
{
|
{
|
||||||
@@ -52,41 +63,32 @@ impl MixTrafficController {
|
|||||||
|
|
||||||
let (client_sender, client_receiver) = tokio::sync::mpsc::channel(8);
|
let (client_sender, client_receiver) = tokio::sync::mpsc::channel(8);
|
||||||
|
|
||||||
(
|
MixTrafficController {
|
||||||
MixTrafficController {
|
gateway_transceiver: Box::new(gateway_transceiver),
|
||||||
gateway_transceiver: Box::new(gateway_transceiver),
|
mix_tx: message_sender,
|
||||||
mix_rx: message_receiver,
|
mix_rx: message_receiver,
|
||||||
client_rx: client_receiver,
|
client_rx: client_receiver,
|
||||||
consecutive_gateway_failure_count: 0,
|
client_tx: client_sender,
|
||||||
shutdown_token,
|
consecutive_gateway_failure_count: 0,
|
||||||
},
|
shutdown_token,
|
||||||
message_sender,
|
event_tx,
|
||||||
client_sender,
|
}
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_dynamic(
|
pub fn new_dynamic(
|
||||||
gateway_transceiver: Box<dyn GatewayTransceiver + Send>,
|
gateway_transceiver: Box<dyn GatewayTransceiver + Send>,
|
||||||
shutdown_token: ShutdownToken,
|
shutdown_token: ShutdownToken,
|
||||||
) -> (
|
event_tx: EventSender,
|
||||||
MixTrafficController,
|
) -> MixTrafficController {
|
||||||
BatchMixMessageSender,
|
Self::new(gateway_transceiver, shutdown_token, event_tx)
|
||||||
ClientRequestSender,
|
}
|
||||||
) {
|
|
||||||
let (message_sender, message_receiver) =
|
pub fn client_tx(&self) -> ClientRequestSender {
|
||||||
tokio::sync::mpsc::channel(MIX_MESSAGE_RECEIVER_BUFFER_SIZE);
|
self.client_tx.clone()
|
||||||
let (client_sender, client_receiver) = tokio::sync::mpsc::channel(8);
|
}
|
||||||
(
|
|
||||||
MixTrafficController {
|
pub fn mix_tx(&self) -> BatchMixMessageSender {
|
||||||
gateway_transceiver,
|
self.mix_tx.clone()
|
||||||
mix_rx: message_receiver,
|
|
||||||
client_rx: client_receiver,
|
|
||||||
consecutive_gateway_failure_count: 0,
|
|
||||||
shutdown_token,
|
|
||||||
},
|
|
||||||
message_sender,
|
|
||||||
client_sender,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn on_messages(
|
async fn on_messages(
|
||||||
@@ -145,33 +147,31 @@ impl MixTrafficController {
|
|||||||
trace!("MixTrafficController: Received shutdown");
|
trace!("MixTrafficController: Received shutdown");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
mix_packets = self.mix_rx.recv() => match mix_packets {
|
// mix_rx should never error out as we're holding one instance of the sender
|
||||||
Some(mix_packets) => {
|
|
||||||
if let Err(err) = self.on_messages(mix_packets).await {
|
Some(mix_packets) = self.mix_rx.recv() => {
|
||||||
error!("Failed to send sphinx packet(s) to the gateway: {err}");
|
if let Err(err) = self.on_messages(mix_packets).await {
|
||||||
if self.consecutive_gateway_failure_count == MAX_FAILURE_COUNT {
|
error!("Failed to send sphinx packet(s) to the gateway: {err}");
|
||||||
// Disconnect from the gateway. If we should try to re-connect
|
if self.consecutive_gateway_failure_count == MAX_FAILURE_COUNT {
|
||||||
// is handled at a higher layer.
|
// Disconnect from the gateway. If we should try to re-connect
|
||||||
error!("Failed to send sphinx packet to the gateway {MAX_FAILURE_COUNT} times in a row - assuming the gateway is dead");
|
// is handled at a higher layer.
|
||||||
// Do we need to handle the embedded mixnet client case
|
error!("Failed to send sphinx packet to the gateway {MAX_FAILURE_COUNT} times in a row - assuming the gateway is dead");
|
||||||
// separately?
|
// Do we need to handle the embedded mixnet client case
|
||||||
break;
|
// separately?
|
||||||
}
|
self.event_tx.send(MixnetClientEvent::Traffic(MixTrafficEvent::FailedSendingSphinx));
|
||||||
|
// IMO it shouldn't be signalled from there but it is how it is
|
||||||
|
// TODO : report the failure upwards and shutdown from upwards
|
||||||
|
// Gateway is dead, we have to shut down currently
|
||||||
|
error!("Signalling shutdown from the MixTrafficController");
|
||||||
|
self.shutdown_token.cancel();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
},
|
|
||||||
None => {
|
|
||||||
trace!("MixTrafficController: Stopping since channel closed");
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
client_request = self.client_rx.recv() => match client_request {
|
// client_rx should never error out as we're holding one instance of the sender
|
||||||
Some(client_request) => {
|
Some(client_request) = self.client_rx.recv() => {
|
||||||
self.on_client_request(client_request).await;
|
self.on_client_request(client_request).await;
|
||||||
},
|
}
|
||||||
None => {
|
|
||||||
trace!("MixTrafficController, client request channel closed");
|
|
||||||
break}
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
debug!("MixTrafficController: Exiting");
|
debug!("MixTrafficController: Exiting");
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
pub mod base_client;
|
pub mod base_client;
|
||||||
pub mod cover_traffic_stream;
|
pub mod cover_traffic_stream;
|
||||||
|
pub(crate) mod event_control;
|
||||||
pub(crate) mod helpers;
|
pub(crate) mod helpers;
|
||||||
pub mod inbound_messages;
|
pub mod inbound_messages;
|
||||||
pub mod key_manager;
|
pub mod key_manager;
|
||||||
|
|||||||
+1
-25
@@ -70,7 +70,6 @@ where
|
|||||||
.send_reply(recipient_tag, data, lane, max_retransmissions);
|
.send_reply(recipient_tag, data, lane, max_retransmissions);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(skip_all)]
|
|
||||||
async fn handle_plain_message(
|
async fn handle_plain_message(
|
||||||
&mut self,
|
&mut self,
|
||||||
recipient: Recipient,
|
recipient: Recipient,
|
||||||
@@ -78,18 +77,16 @@ where
|
|||||||
lane: TransmissionLane,
|
lane: TransmissionLane,
|
||||||
packet_type: PacketType,
|
packet_type: PacketType,
|
||||||
max_retransmissions: Option<u32>,
|
max_retransmissions: Option<u32>,
|
||||||
trace_id: Option<[u8; 12]>,
|
|
||||||
) {
|
) {
|
||||||
if let Err(err) = self
|
if let Err(err) = self
|
||||||
.message_handler
|
.message_handler
|
||||||
.try_send_plain_message(recipient, content, lane, packet_type, max_retransmissions, trace_id)
|
.try_send_plain_message(recipient, content, lane, packet_type, max_retransmissions)
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
warn!("failed to send a plain message - {err}")
|
warn!("failed to send a plain message - {err}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(skip_all)]
|
|
||||||
async fn handle_repliable_message(
|
async fn handle_repliable_message(
|
||||||
&mut self,
|
&mut self,
|
||||||
recipient: Recipient,
|
recipient: Recipient,
|
||||||
@@ -98,7 +95,6 @@ where
|
|||||||
lane: TransmissionLane,
|
lane: TransmissionLane,
|
||||||
packet_type: PacketType,
|
packet_type: PacketType,
|
||||||
max_retransmissions: Option<u32>,
|
max_retransmissions: Option<u32>,
|
||||||
trace_id: Option<[u8; 12]>,
|
|
||||||
) {
|
) {
|
||||||
if let Err(err) = self
|
if let Err(err) = self
|
||||||
.message_handler
|
.message_handler
|
||||||
@@ -109,7 +105,6 @@ where
|
|||||||
lane,
|
lane,
|
||||||
packet_type,
|
packet_type,
|
||||||
max_retransmissions,
|
max_retransmissions,
|
||||||
trace_id,
|
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
@@ -118,29 +113,20 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::panic)]
|
#[allow(clippy::panic)]
|
||||||
#[instrument(skip_all)]
|
|
||||||
async fn on_input_message(&mut self, msg: InputMessage) {
|
async fn on_input_message(&mut self, msg: InputMessage) {
|
||||||
let trace_id = msg.trace_id();
|
|
||||||
if let Some(tid) = trace_id {
|
|
||||||
tracing::warn!("Processing input message with trace_id: {:?}", tid);
|
|
||||||
}
|
|
||||||
|
|
||||||
match msg {
|
match msg {
|
||||||
InputMessage::Regular {
|
InputMessage::Regular {
|
||||||
recipient,
|
recipient,
|
||||||
data,
|
data,
|
||||||
lane,
|
lane,
|
||||||
max_retransmissions,
|
max_retransmissions,
|
||||||
..
|
|
||||||
} => {
|
} => {
|
||||||
warn!("Handling regular input message with trace_id: {:?}", trace_id);
|
|
||||||
self.handle_plain_message(
|
self.handle_plain_message(
|
||||||
recipient,
|
recipient,
|
||||||
data,
|
data,
|
||||||
lane,
|
lane,
|
||||||
PacketType::Mix,
|
PacketType::Mix,
|
||||||
max_retransmissions,
|
max_retransmissions,
|
||||||
trace_id
|
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
@@ -150,9 +136,7 @@ where
|
|||||||
reply_surbs,
|
reply_surbs,
|
||||||
lane,
|
lane,
|
||||||
max_retransmissions,
|
max_retransmissions,
|
||||||
..
|
|
||||||
} => {
|
} => {
|
||||||
warn!("Handling anonymous input message with trace_id: {:?}", trace_id);
|
|
||||||
self.handle_repliable_message(
|
self.handle_repliable_message(
|
||||||
recipient,
|
recipient,
|
||||||
data,
|
data,
|
||||||
@@ -160,7 +144,6 @@ where
|
|||||||
lane,
|
lane,
|
||||||
PacketType::Mix,
|
PacketType::Mix,
|
||||||
max_retransmissions,
|
max_retransmissions,
|
||||||
trace_id
|
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
@@ -170,7 +153,6 @@ where
|
|||||||
lane,
|
lane,
|
||||||
max_retransmissions,
|
max_retransmissions,
|
||||||
} => {
|
} => {
|
||||||
warn!("Handling reply input message with trace_id: {:?}", trace_id);
|
|
||||||
self.handle_reply(recipient_tag, data, lane, max_retransmissions)
|
self.handle_reply(recipient_tag, data, lane, max_retransmissions)
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
@@ -184,16 +166,13 @@ where
|
|||||||
data,
|
data,
|
||||||
lane,
|
lane,
|
||||||
max_retransmissions,
|
max_retransmissions,
|
||||||
..
|
|
||||||
} => {
|
} => {
|
||||||
tracing::warn!("Handling regular input message with trace_id: {:?}", trace_id);
|
|
||||||
self.handle_plain_message(
|
self.handle_plain_message(
|
||||||
recipient,
|
recipient,
|
||||||
data,
|
data,
|
||||||
lane,
|
lane,
|
||||||
packet_type,
|
packet_type,
|
||||||
max_retransmissions,
|
max_retransmissions,
|
||||||
trace_id
|
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
@@ -203,7 +182,6 @@ where
|
|||||||
reply_surbs,
|
reply_surbs,
|
||||||
lane,
|
lane,
|
||||||
max_retransmissions,
|
max_retransmissions,
|
||||||
..
|
|
||||||
} => {
|
} => {
|
||||||
self.handle_repliable_message(
|
self.handle_repliable_message(
|
||||||
recipient,
|
recipient,
|
||||||
@@ -212,7 +190,6 @@ where
|
|||||||
lane,
|
lane,
|
||||||
packet_type,
|
packet_type,
|
||||||
max_retransmissions,
|
max_retransmissions,
|
||||||
trace_id
|
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
@@ -236,7 +213,6 @@ where
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(skip_all)]
|
|
||||||
pub(crate) async fn run(&mut self, shutdown_token: ShutdownToken) {
|
pub(crate) async fn run(&mut self, shutdown_token: ShutdownToken) {
|
||||||
debug!("Started InputMessageListener with graceful shutdown support");
|
debug!("Started InputMessageListener with graceful shutdown support");
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -60,7 +60,7 @@ where
|
|||||||
|
|
||||||
// TODO: Figure out retransmission packet type signaling
|
// TODO: Figure out retransmission packet type signaling
|
||||||
self.message_handler
|
self.message_handler
|
||||||
.try_prepare_single_chunk_for_sending(packet_recipient, chunk_data, packet_type, None)
|
.try_prepare_single_chunk_for_sending(packet_recipient, chunk_data, packet_type)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ use std::collections::HashMap;
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use tracing::{debug, error, info, instrument, trace, warn};
|
use tracing::{debug, error, info, trace, warn};
|
||||||
|
|
||||||
// TODO: move that error elsewhere since it seems to be contaminating different files
|
// TODO: move that error elsewhere since it seems to be contaminating different files
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
@@ -476,7 +476,6 @@ where
|
|||||||
self.forward_messages(msgs, lane).await;
|
self.forward_messages(msgs, lane).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(skip_all)]
|
|
||||||
pub(crate) async fn try_send_plain_message(
|
pub(crate) async fn try_send_plain_message(
|
||||||
&mut self,
|
&mut self,
|
||||||
recipient: Recipient,
|
recipient: Recipient,
|
||||||
@@ -484,7 +483,6 @@ where
|
|||||||
lane: TransmissionLane,
|
lane: TransmissionLane,
|
||||||
packet_type: PacketType,
|
packet_type: PacketType,
|
||||||
max_retransmissions: Option<u32>,
|
max_retransmissions: Option<u32>,
|
||||||
trace_id: Option<[u8; 12]>,
|
|
||||||
) -> Result<(), PreparationError> {
|
) -> Result<(), PreparationError> {
|
||||||
let message = NymMessage::new_plain(message);
|
let message = NymMessage::new_plain(message);
|
||||||
self.try_split_and_send_non_reply_message(
|
self.try_split_and_send_non_reply_message(
|
||||||
@@ -493,12 +491,10 @@ where
|
|||||||
lane,
|
lane,
|
||||||
packet_type,
|
packet_type,
|
||||||
max_retransmissions,
|
max_retransmissions,
|
||||||
trace_id,
|
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(skip_all)]
|
|
||||||
pub(crate) async fn try_split_and_send_non_reply_message(
|
pub(crate) async fn try_split_and_send_non_reply_message(
|
||||||
&mut self,
|
&mut self,
|
||||||
message: NymMessage,
|
message: NymMessage,
|
||||||
@@ -506,7 +502,6 @@ where
|
|||||||
lane: TransmissionLane,
|
lane: TransmissionLane,
|
||||||
packet_type: PacketType,
|
packet_type: PacketType,
|
||||||
max_retransmissions: Option<u32>,
|
max_retransmissions: Option<u32>,
|
||||||
trace_id: Option<[u8; 12]>,
|
|
||||||
) -> Result<(), PreparationError> {
|
) -> Result<(), PreparationError> {
|
||||||
debug!("Sending non-reply message with packet type {packet_type}");
|
debug!("Sending non-reply message with packet type {packet_type}");
|
||||||
// TODO: I really dislike existence of this assertion, it implies code has to be re-organised
|
// TODO: I really dislike existence of this assertion, it implies code has to be re-organised
|
||||||
@@ -539,7 +534,6 @@ where
|
|||||||
&self.config.ack_key,
|
&self.config.ack_key,
|
||||||
&recipient,
|
&recipient,
|
||||||
packet_type,
|
packet_type,
|
||||||
trace_id
|
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let real_message = RealMessage::new(
|
let real_message = RealMessage::new(
|
||||||
@@ -591,7 +585,6 @@ where
|
|||||||
TransmissionLane::AdditionalReplySurbs,
|
TransmissionLane::AdditionalReplySurbs,
|
||||||
packet_type,
|
packet_type,
|
||||||
max_retransmissions,
|
max_retransmissions,
|
||||||
None,
|
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
@@ -609,7 +602,6 @@ where
|
|||||||
lane: TransmissionLane,
|
lane: TransmissionLane,
|
||||||
packet_type: PacketType,
|
packet_type: PacketType,
|
||||||
max_retransmissions: Option<u32>,
|
max_retransmissions: Option<u32>,
|
||||||
trace_id: Option<[u8; 12]>,
|
|
||||||
) -> Result<(), SurbWrappedPreparationError> {
|
) -> Result<(), SurbWrappedPreparationError> {
|
||||||
debug!("Sending message with reply SURBs with packet type {packet_type}");
|
debug!("Sending message with reply SURBs with packet type {packet_type}");
|
||||||
let sender_tag = self.get_or_create_sender_tag(&recipient);
|
let sender_tag = self.get_or_create_sender_tag(&recipient);
|
||||||
@@ -633,7 +625,6 @@ where
|
|||||||
lane,
|
lane,
|
||||||
packet_type,
|
packet_type,
|
||||||
max_retransmissions,
|
max_retransmissions,
|
||||||
trace_id,
|
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
@@ -648,7 +639,6 @@ where
|
|||||||
recipient: Recipient,
|
recipient: Recipient,
|
||||||
chunk: Fragment,
|
chunk: Fragment,
|
||||||
packet_type: PacketType,
|
packet_type: PacketType,
|
||||||
trace_id: Option<[u8; 12]>,
|
|
||||||
) -> Result<PreparedFragment, PreparationError> {
|
) -> Result<PreparedFragment, PreparationError> {
|
||||||
debug!("Sending single chunk with packet type {packet_type}");
|
debug!("Sending single chunk with packet type {packet_type}");
|
||||||
let topology_permit = self.topology_access.get_read_permit().await;
|
let topology_permit = self.topology_access.get_read_permit().await;
|
||||||
@@ -660,7 +650,6 @@ where
|
|||||||
&self.config.ack_key,
|
&self.config.ack_key,
|
||||||
&recipient,
|
&recipient,
|
||||||
packet_type,
|
packet_type,
|
||||||
trace_id,
|
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
Ok(prepared_fragment)
|
Ok(prepared_fragment)
|
||||||
|
|||||||
@@ -31,9 +31,9 @@ use tracing::*;
|
|||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
use tokio::time::{sleep, Sleep};
|
use tokio::time::{sleep, Sleep};
|
||||||
|
|
||||||
|
// use wasm_utils::console_log;
|
||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
use wasmtimer::tokio::{sleep, Sleep};
|
use wasmtimer::tokio::{sleep, Sleep};
|
||||||
|
|
||||||
mod sending_delay_controller;
|
mod sending_delay_controller;
|
||||||
|
|
||||||
/// Configurable parameters of the `OutQueueControl`
|
/// Configurable parameters of the `OutQueueControl`
|
||||||
@@ -298,6 +298,8 @@ where
|
|||||||
"failed to send mixnet packet due to closed channel (outside of shutdown!)"
|
"failed to send mixnet packet due to closed channel (outside of shutdown!)"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
// Early return to avoid further processing when channel is closed
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
let event = if fragment_id.is_some() {
|
let event = if fragment_id.is_some() {
|
||||||
@@ -325,9 +327,15 @@ where
|
|||||||
// ready and hence was immediately re-scheduled causing other tasks to be starved;
|
// ready and hence was immediately re-scheduled causing other tasks to be starved;
|
||||||
// yield makes it go back the scheduling queue regardless of its value availability
|
// yield makes it go back the scheduling queue regardless of its value availability
|
||||||
|
|
||||||
// TODO: temporary and BAD workaround for wasm (we should find a way to yield here in wasm)
|
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
tokio::task::yield_now().await;
|
{
|
||||||
|
tokio::task::yield_now().await;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_arch = "wasm32")]
|
||||||
|
{
|
||||||
|
tokio_with_wasm::task::yield_now().await;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_close_connection(&mut self, connection_id: ConnectionId) {
|
fn on_close_connection(&mut self, connection_id: ConnectionId) {
|
||||||
|
|||||||
@@ -80,7 +80,6 @@ impl StatisticsControl {
|
|||||||
stats_report.into(),
|
stats_report.into(),
|
||||||
TransmissionLane::General,
|
TransmissionLane::General,
|
||||||
None,
|
None,
|
||||||
None,
|
|
||||||
);
|
);
|
||||||
if let Err(err) = self.report_tx.send(report_message).await {
|
if let Err(err) = self.report_tx.send(report_message).await {
|
||||||
tracing::error!("Failed to report client stats: {err:?}");
|
tracing::error!("Failed to report client stats: {err:?}");
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ type WsConn = JSWebsocket;
|
|||||||
|
|
||||||
const CONCURRENT_GATEWAYS_MEASURED: usize = 20;
|
const CONCURRENT_GATEWAYS_MEASURED: usize = 20;
|
||||||
const MEASUREMENTS: usize = 3;
|
const MEASUREMENTS: usize = 3;
|
||||||
|
const DEFAULT_NYM_API_RETRIES: usize = 3;
|
||||||
|
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
const CONN_TIMEOUT: Duration = Duration::from_millis(1500);
|
const CONN_TIMEOUT: Duration = Duration::from_millis(1500);
|
||||||
@@ -132,25 +133,27 @@ impl<'a, G: ConnectableGateway> GatewayWithLatency<'a, G> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn gateways_for_init<R: Rng>(
|
pub async fn gateways_for_init(
|
||||||
rng: &mut R,
|
|
||||||
nym_apis: &[Url],
|
nym_apis: &[Url],
|
||||||
user_agent: Option<UserAgent>,
|
user_agent: Option<UserAgent>,
|
||||||
minimum_performance: u8,
|
minimum_performance: u8,
|
||||||
ignore_epoch_roles: bool,
|
ignore_epoch_roles: bool,
|
||||||
|
retry_count: Option<usize>,
|
||||||
) -> Result<Vec<RoutingNode>, ClientCoreError> {
|
) -> Result<Vec<RoutingNode>, ClientCoreError> {
|
||||||
let nym_api = nym_apis
|
// Build client with ALL URLs for fallback support
|
||||||
.choose(rng)
|
let nym_api_urls: Vec<nym_http_api_client::Url> = nym_apis
|
||||||
.ok_or(ClientCoreError::ListOfNymApisIsEmpty)?;
|
.iter()
|
||||||
|
.map(|url| nym_http_api_client::Url::from(url.clone()))
|
||||||
|
.collect();
|
||||||
|
|
||||||
// Use the unified HTTP client directly with optional user agent
|
if nym_api_urls.is_empty() {
|
||||||
let mut builder = nym_http_api_client::Client::builder(nym_api.clone())
|
return Err(ClientCoreError::ListOfNymApisIsEmpty);
|
||||||
.map_err(|e| {
|
}
|
||||||
ClientCoreError::ValidatorClientError(nym_validator_client::ValidatorClientError::from(
|
|
||||||
e,
|
let retry_count = retry_count.unwrap_or(DEFAULT_NYM_API_RETRIES);
|
||||||
))
|
let mut builder = nym_http_api_client::ClientBuilder::new_with_urls(nym_api_urls.clone())?
|
||||||
})?
|
.with_retries(retry_count)
|
||||||
.with_bincode(); // Use bincode for better performance
|
.with_bincode();
|
||||||
|
|
||||||
if let Some(user_agent) = user_agent {
|
if let Some(user_agent) = user_agent {
|
||||||
builder = builder.with_user_agent(user_agent);
|
builder = builder.with_user_agent(user_agent);
|
||||||
@@ -160,7 +163,7 @@ pub async fn gateways_for_init<R: Rng>(
|
|||||||
ClientCoreError::ValidatorClientError(nym_validator_client::ValidatorClientError::from(e))
|
ClientCoreError::ValidatorClientError(nym_validator_client::ValidatorClientError::from(e))
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
tracing::debug!("Fetching list of gateways from: {nym_api}");
|
tracing::debug!("Fetching list of gateways from: {:?}", nym_api_urls);
|
||||||
|
|
||||||
// Use our helper to handle pagination
|
// Use our helper to handle pagination
|
||||||
let gateways = get_all_basic_entry_nodes_with_metadata(&client, true)
|
let gateways = get_all_basic_entry_nodes_with_metadata(&client, true)
|
||||||
@@ -172,17 +175,15 @@ pub async fn gateways_for_init<R: Rng>(
|
|||||||
|
|
||||||
// filter out gateways below minimum performance and ones that could operate as a mixnode
|
// filter out gateways below minimum performance and ones that could operate as a mixnode
|
||||||
// (we don't want instability)
|
// (we don't want instability)
|
||||||
let valid_gateways = gateways
|
let valid_gateways: Vec<RoutingNode> = gateways
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|g| ignore_epoch_roles || !g.supported_roles.mixnode)
|
.filter(|g| ignore_epoch_roles || !g.supported_roles.mixnode)
|
||||||
.filter(|g| g.performance.round_to_integer() >= minimum_performance)
|
.filter(|g| g.performance.round_to_integer() >= minimum_performance)
|
||||||
.filter_map(|gateway| gateway.try_into().ok())
|
.filter_map(|gateway| gateway.try_into().ok())
|
||||||
.collect::<Vec<_>>();
|
.collect();
|
||||||
tracing::debug!("After checking validity: {}", valid_gateways.len());
|
|
||||||
tracing::trace!("Valid gateways: {valid_gateways:#?}");
|
|
||||||
|
|
||||||
tracing::info!(
|
tracing::info!(
|
||||||
"and {} after validity and performance filtering",
|
"Found {} valid gateways after filtering",
|
||||||
valid_gateways.len()
|
valid_gateways.len()
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -345,13 +346,20 @@ pub(super) fn get_specified_gateway(
|
|||||||
must_use_tls: bool,
|
must_use_tls: bool,
|
||||||
) -> Result<RoutingNode, ClientCoreError> {
|
) -> Result<RoutingNode, ClientCoreError> {
|
||||||
tracing::debug!("Requesting specified gateway: {gateway_identity}");
|
tracing::debug!("Requesting specified gateway: {gateway_identity}");
|
||||||
|
|
||||||
let user_gateway = ed25519::PublicKey::from_base58_string(gateway_identity)
|
let user_gateway = ed25519::PublicKey::from_base58_string(gateway_identity)
|
||||||
.map_err(ClientCoreError::UnableToCreatePublicKeyFromGatewayId)?;
|
.map_err(ClientCoreError::UnableToCreatePublicKeyFromGatewayId)?;
|
||||||
|
|
||||||
let gateway = gateways
|
let gateway = gateways
|
||||||
.iter()
|
.iter()
|
||||||
.find(|gateway| gateway.identity_key == user_gateway)
|
.find(|gateway| gateway.identity_key == user_gateway)
|
||||||
.ok_or_else(|| ClientCoreError::NoGatewayWithId(gateway_identity.to_string()))?;
|
.ok_or_else(|| {
|
||||||
|
tracing::debug!(
|
||||||
|
"Gateway {gateway_identity} not found in {} available gateways",
|
||||||
|
gateways.len()
|
||||||
|
);
|
||||||
|
ClientCoreError::NoGatewayWithId(gateway_identity.to_string())
|
||||||
|
})?;
|
||||||
|
|
||||||
let Some(entry_details) = gateway.entry.as_ref() else {
|
let Some(entry_details) = gateway.entry.as_ref() else {
|
||||||
return Err(ClientCoreError::UnsupportedEntry {
|
return Err(ClientCoreError::UnsupportedEntry {
|
||||||
@@ -414,3 +422,52 @@ pub(super) async fn register_with_gateway(
|
|||||||
authenticated_ephemeral_client: gateway_client,
|
authenticated_ephemeral_client: gateway_client,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use url::Url;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_single_url_builds_without_retries() {
|
||||||
|
let urls = [Url::parse("https://api.nym.com").unwrap()];
|
||||||
|
|
||||||
|
let nym_api_urls: Vec<nym_http_api_client::Url> = urls
|
||||||
|
.iter()
|
||||||
|
.map(|url| nym_http_api_client::Url::from(url.clone()))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
assert_eq!(nym_api_urls.len(), 1, "Should have exactly one URL");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_multiple_urls_prepared_for_retries() {
|
||||||
|
let urls = [
|
||||||
|
Url::parse("https://api1.nym.com").unwrap(),
|
||||||
|
Url::parse("https://api2.nym.com").unwrap(),
|
||||||
|
Url::parse("https://api3.nym.com").unwrap(),
|
||||||
|
];
|
||||||
|
|
||||||
|
let nym_api_urls: Vec<nym_http_api_client::Url> = urls
|
||||||
|
.iter()
|
||||||
|
.map(|url| nym_http_api_client::Url::from(url.clone()))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
assert_eq!(nym_api_urls.len(), 3, "Should have all three URLs");
|
||||||
|
assert!(
|
||||||
|
nym_api_urls.len() > 1,
|
||||||
|
"Multiple URLs trigger retry behavior"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_empty_url_list_is_detected() {
|
||||||
|
let urls: Vec<Url> = vec![];
|
||||||
|
|
||||||
|
let nym_api_urls: Vec<nym_http_api_client::Url> = urls
|
||||||
|
.iter()
|
||||||
|
.map(|url| nym_http_api_client::Url::from(url.clone()))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
assert!(nym_api_urls.is_empty(), "Empty list should remain empty");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -24,7 +24,9 @@ pub fn spawn_future<F>(future: F)
|
|||||||
where
|
where
|
||||||
F: Future<Output = ()> + 'static,
|
F: Future<Output = ()> + 'static,
|
||||||
{
|
{
|
||||||
wasm_bindgen_futures::spawn_local(future);
|
wasm_bindgen_futures::spawn_local(async move {
|
||||||
|
future.await;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[deprecated(note = "use spawn_future from nym_task crate instead")]
|
#[deprecated(note = "use spawn_future from nym_task crate instead")]
|
||||||
|
|||||||
@@ -1043,12 +1043,6 @@ impl<C, St> GatewayClient<C, St> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Note: this requires prior authentication
|
// Note: this requires prior authentication
|
||||||
#[instrument(skip_all,
|
|
||||||
fields(
|
|
||||||
gateway = %self.gateway_identity,
|
|
||||||
gateway_address = %self.gateway_address
|
|
||||||
)
|
|
||||||
)]
|
|
||||||
pub fn start_listening_for_mixnet_messages(&mut self) -> Result<(), GatewayClientError> {
|
pub fn start_listening_for_mixnet_messages(&mut self) -> Result<(), GatewayClientError> {
|
||||||
if !self.authenticated {
|
if !self.authenticated {
|
||||||
return Err(GatewayClientError::NotAuthenticated);
|
return Err(GatewayClientError::NotAuthenticated);
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ name = "nym-validator-client"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
authors = ["Jędrzej Stuczyński <andrew@nymtech.net>"]
|
authors = ["Jędrzej Stuczyński <andrew@nymtech.net>"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
rust-version = "1.56"
|
rust-version = "1.85"
|
||||||
license.workspace = true
|
license.workspace = true
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|||||||
@@ -136,6 +136,27 @@ pub trait DkgSigningClient {
|
|||||||
self.execute_dkg_contract(fee, req, "trigger DKG resharing".to_string(), vec![])
|
self.execute_dkg_contract(fee, req, "trigger DKG resharing".to_string(), vec![])
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn transfer_ownership(
|
||||||
|
&self,
|
||||||
|
transfer_to: String,
|
||||||
|
fee: Option<Fee>,
|
||||||
|
) -> Result<ExecuteResult, NyxdError> {
|
||||||
|
let req = DkgExecuteMsg::TransferOwnership { transfer_to };
|
||||||
|
|
||||||
|
self.execute_dkg_contract(fee, req, "".to_string(), vec![])
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
async fn update_announce_address(
|
||||||
|
&self,
|
||||||
|
new_address: String,
|
||||||
|
fee: Option<Fee>,
|
||||||
|
) -> Result<ExecuteResult, NyxdError> {
|
||||||
|
let req = DkgExecuteMsg::UpdateAnnounceAddress { new_address };
|
||||||
|
|
||||||
|
self.execute_dkg_contract(fee, req, "".to_string(), vec![])
|
||||||
|
.await
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
|
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
|
||||||
@@ -168,6 +189,7 @@ where
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::nyxd::contract_traits::tests::IgnoreValue;
|
use crate::nyxd::contract_traits::tests::IgnoreValue;
|
||||||
|
use nym_coconut_dkg_common::msg::ExecuteMsg;
|
||||||
|
|
||||||
// it's enough that this compiles and clippy is happy about it
|
// it's enough that this compiles and clippy is happy about it
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
@@ -210,6 +232,12 @@ mod tests {
|
|||||||
DkgExecuteMsg::AdvanceEpochState {} => client.advance_dkg_epoch_state(None).ignore(),
|
DkgExecuteMsg::AdvanceEpochState {} => client.advance_dkg_epoch_state(None).ignore(),
|
||||||
DkgExecuteMsg::TriggerReset {} => client.trigger_dkg_reset(None).ignore(),
|
DkgExecuteMsg::TriggerReset {} => client.trigger_dkg_reset(None).ignore(),
|
||||||
DkgExecuteMsg::TriggerResharing {} => client.trigger_dkg_resharing(None).ignore(),
|
DkgExecuteMsg::TriggerResharing {} => client.trigger_dkg_resharing(None).ignore(),
|
||||||
|
ExecuteMsg::TransferOwnership { transfer_to } => {
|
||||||
|
client.transfer_ownership(transfer_to, None).ignore()
|
||||||
|
}
|
||||||
|
ExecuteMsg::UpdateAnnounceAddress { new_address } => {
|
||||||
|
client.update_announce_address(new_address, None).ignore()
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ use cosmrs::tx;
|
|||||||
use cosmrs::tx::SignDoc;
|
use cosmrs::tx::SignDoc;
|
||||||
use nym_config::defaults;
|
use nym_config::defaults;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use zeroize::{Zeroize, ZeroizeOnDrop};
|
use zeroize::{Zeroize, ZeroizeOnDrop, Zeroizing};
|
||||||
|
|
||||||
type Secp256k1Keypair = (SigningKey, PublicKey);
|
type Secp256k1Keypair = (SigningKey, PublicKey);
|
||||||
|
|
||||||
@@ -128,9 +128,20 @@ impl DirectSecp256k1HdWallet {
|
|||||||
Ok(accounts)
|
Ok(accounts)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn secret(&self) -> &bip39::Mnemonic {
|
||||||
|
&self.secret
|
||||||
|
}
|
||||||
|
|
||||||
|
#[deprecated(
|
||||||
|
note = "use either .secret() for obtaining &bip39::Mnemonic or .mnemonic_string() for Zeroizing wrapper around the String"
|
||||||
|
)]
|
||||||
pub fn mnemonic(&self) -> String {
|
pub fn mnemonic(&self) -> String {
|
||||||
self.secret.to_string()
|
self.secret.to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn mnemonic_string(&self) -> Zeroizing<String> {
|
||||||
|
Zeroizing::new(self.secret.to_string())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
|
|||||||
@@ -18,6 +18,6 @@ pub fn create_account(args: Args, prefix: &str) {
|
|||||||
let wallet = DirectSecp256k1HdWallet::from_mnemonic(prefix, mnemonic);
|
let wallet = DirectSecp256k1HdWallet::from_mnemonic(prefix, mnemonic);
|
||||||
|
|
||||||
// Output address and mnemonics into separate lines for easier parsing
|
// Output address and mnemonics into separate lines for easier parsing
|
||||||
println!("{}", wallet.mnemonic());
|
println!("{}", wallet.mnemonic_string().as_str());
|
||||||
println!("{}", wallet.try_derive_accounts().unwrap()[0].address());
|
println!("{}", wallet.try_derive_accounts().unwrap()[0].address());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,16 @@ use crate::types::{EncodedBTEPublicKeyWithProof, NodeIndex};
|
|||||||
use cosmwasm_schema::cw_serde;
|
use cosmwasm_schema::cw_serde;
|
||||||
use cosmwasm_std::Addr;
|
use cosmwasm_std::Addr;
|
||||||
|
|
||||||
|
pub type BlockHeight = u64;
|
||||||
|
pub type TransactionIndex = u32;
|
||||||
|
|
||||||
|
#[cw_serde]
|
||||||
|
pub struct OwnershipTransfer {
|
||||||
|
pub node_index: NodeIndex,
|
||||||
|
pub from: Addr,
|
||||||
|
pub to: Addr,
|
||||||
|
}
|
||||||
|
|
||||||
#[cw_serde]
|
#[cw_serde]
|
||||||
pub struct DealerDetails {
|
pub struct DealerDetails {
|
||||||
pub address: Addr,
|
pub address: Addr,
|
||||||
|
|||||||
@@ -73,6 +73,17 @@ pub enum ExecuteMsg {
|
|||||||
TriggerReset {},
|
TriggerReset {},
|
||||||
|
|
||||||
TriggerResharing {},
|
TriggerResharing {},
|
||||||
|
|
||||||
|
/// Transfers ownership of the epoch dealer to another address.
|
||||||
|
/// This assumes off-chain hand-over of keys
|
||||||
|
TransferOwnership {
|
||||||
|
transfer_to: String,
|
||||||
|
},
|
||||||
|
|
||||||
|
/// Update announce address of this signer
|
||||||
|
UpdateAnnounceAddress {
|
||||||
|
new_address: String,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cw_serde]
|
#[cw_serde]
|
||||||
|
|||||||
@@ -241,23 +241,28 @@ impl Epoch {
|
|||||||
//
|
//
|
||||||
// Note: It's important that the variant ordering is not changed otherwise it would mess up the derived `PartialOrd`
|
// Note: It's important that the variant ordering is not changed otherwise it would mess up the derived `PartialOrd`
|
||||||
#[cw_serde]
|
#[cw_serde]
|
||||||
#[derive(Copy)]
|
#[derive(Copy, Default)]
|
||||||
pub enum EpochState {
|
pub enum EpochState {
|
||||||
|
#[default]
|
||||||
WaitingInitialisation,
|
WaitingInitialisation,
|
||||||
PublicKeySubmission { resharing: bool },
|
PublicKeySubmission {
|
||||||
DealingExchange { resharing: bool },
|
resharing: bool,
|
||||||
VerificationKeySubmission { resharing: bool },
|
},
|
||||||
VerificationKeyValidation { resharing: bool },
|
DealingExchange {
|
||||||
VerificationKeyFinalization { resharing: bool },
|
resharing: bool,
|
||||||
|
},
|
||||||
|
VerificationKeySubmission {
|
||||||
|
resharing: bool,
|
||||||
|
},
|
||||||
|
VerificationKeyValidation {
|
||||||
|
resharing: bool,
|
||||||
|
},
|
||||||
|
VerificationKeyFinalization {
|
||||||
|
resharing: bool,
|
||||||
|
},
|
||||||
InProgress,
|
InProgress,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for EpochState {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self::WaitingInitialisation
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for EpochState {
|
impl Display for EpochState {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
|
|||||||
@@ -20,5 +20,7 @@ rand_chacha = { workspace = true }
|
|||||||
rand = { workspace = true }
|
rand = { workspace = true }
|
||||||
cw-multi-test = { workspace = true }
|
cw-multi-test = { workspace = true }
|
||||||
|
|
||||||
|
nym-contracts-common = { path = "../contracts-common" }
|
||||||
|
|
||||||
[lints]
|
[lints]
|
||||||
workspace = true
|
workspace = true
|
||||||
|
|||||||
@@ -1,20 +1,100 @@
|
|||||||
// Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
|
// Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use cosmwasm_std::testing::{message_info, MockApi, MockQuerier, MockStorage};
|
use cosmwasm_std::testing::{MockApi, MockQuerier, MockStorage, message_info};
|
||||||
use cosmwasm_std::{
|
use cosmwasm_std::{
|
||||||
coins, Addr, BankMsg, CosmosMsg, Empty, Env, MemoryStorage, MessageInfo, Order, OwnedDeps,
|
Addr, BankMsg, CosmosMsg, Decimal, Empty, Env, MemoryStorage, MessageInfo, Order, OwnedDeps,
|
||||||
Response, StdResult, Storage,
|
Response, StdResult, Storage, coins,
|
||||||
};
|
};
|
||||||
use cw_storage_plus::{KeyDeserialize, Map, Prefix, PrimaryKey};
|
use cw_storage_plus::{KeyDeserialize, Map, Prefix, PrimaryKey};
|
||||||
|
use nym_contracts_common::events::may_find_attribute;
|
||||||
use rand::{RngCore, SeedableRng};
|
use rand::{RngCore, SeedableRng};
|
||||||
use rand_chacha::ChaCha20Rng;
|
use rand_chacha::ChaCha20Rng;
|
||||||
use serde::de::DeserializeOwned;
|
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
use serde::de::DeserializeOwned;
|
||||||
|
use std::fmt::Debug;
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
pub const TEST_DENOM: &str = "unym";
|
pub const TEST_DENOM: &str = "unym";
|
||||||
pub const TEST_PREFIX: &str = "n";
|
pub const TEST_PREFIX: &str = "n";
|
||||||
|
|
||||||
|
pub trait FindAttribute {
|
||||||
|
fn attribute<E, S>(&self, event_type: E, attribute: &str) -> String
|
||||||
|
where
|
||||||
|
E: Into<Option<S>>,
|
||||||
|
S: Into<String>;
|
||||||
|
|
||||||
|
fn any_attribute(&self, attribute: &str) -> String {
|
||||||
|
self.attribute::<_, String>(None, attribute)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn any_parsed_attribute<T>(&self, attribute: &str) -> T
|
||||||
|
where
|
||||||
|
T: FromStr,
|
||||||
|
<T as FromStr>::Err: Debug,
|
||||||
|
{
|
||||||
|
self.parsed_attribute::<_, String, T>(None, attribute)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parsed_attribute<E, S, T>(&self, event_type: E, attribute: &str) -> T
|
||||||
|
where
|
||||||
|
E: Into<Option<S>>,
|
||||||
|
S: Into<String>,
|
||||||
|
T: FromStr,
|
||||||
|
<T as FromStr>::Err: Debug;
|
||||||
|
|
||||||
|
fn decimal<E, S>(&self, event_type: E, attribute: &str) -> Decimal
|
||||||
|
where
|
||||||
|
E: Into<Option<S>>,
|
||||||
|
S: Into<String>,
|
||||||
|
{
|
||||||
|
self.parsed_attribute(event_type, attribute)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[track_caller]
|
||||||
|
pub fn find_attribute<S: Into<String>>(
|
||||||
|
event_type: Option<S>,
|
||||||
|
attribute: &str,
|
||||||
|
response: &Response,
|
||||||
|
) -> String {
|
||||||
|
let event_type = event_type.map(Into::into);
|
||||||
|
for event in &response.events {
|
||||||
|
if let Some(typ) = &event_type {
|
||||||
|
if &event.ty != typ {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(attr) = may_find_attribute(event, attribute) {
|
||||||
|
return attr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// this is only used in tests so panic here is fine
|
||||||
|
panic!("did not find the attribute")
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FindAttribute for Response {
|
||||||
|
fn attribute<E, S>(&self, event_type: E, attribute: &str) -> String
|
||||||
|
where
|
||||||
|
E: Into<Option<S>>,
|
||||||
|
S: Into<String>,
|
||||||
|
{
|
||||||
|
find_attribute(event_type.into(), attribute, self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parsed_attribute<E, S, T>(&self, event_type: E, attribute: &str) -> T
|
||||||
|
where
|
||||||
|
E: Into<Option<S>>,
|
||||||
|
S: Into<String>,
|
||||||
|
T: FromStr,
|
||||||
|
<T as FromStr>::Err: Debug,
|
||||||
|
{
|
||||||
|
find_attribute(event_type.into(), attribute, self)
|
||||||
|
.parse()
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn mock_api() -> MockApi {
|
pub fn mock_api() -> MockApi {
|
||||||
MockApi::default().with_prefix(TEST_PREFIX)
|
MockApi::default().with_prefix(TEST_PREFIX)
|
||||||
}
|
}
|
||||||
|
|||||||
+43
-11
@@ -4,12 +4,12 @@
|
|||||||
use crate::{ContractTester, TestableNymContract};
|
use crate::{ContractTester, TestableNymContract};
|
||||||
use cosmwasm_std::testing::{message_info, mock_env};
|
use cosmwasm_std::testing::{message_info, mock_env};
|
||||||
use cosmwasm_std::{
|
use cosmwasm_std::{
|
||||||
from_json, Addr, Coin, ContractInfo, Deps, DepsMut, Env, MessageInfo, Response, StdResult,
|
Addr, BlockInfo, Coin, ContractInfo, Deps, DepsMut, Env, MessageInfo, Response, StdResult,
|
||||||
Storage, Timestamp,
|
Storage, Timestamp, from_json,
|
||||||
};
|
};
|
||||||
use cw_multi_test::{next_block, AppResponse, Executor};
|
use cw_multi_test::{AppResponse, Executor, next_block};
|
||||||
use serde::de::DeserializeOwned;
|
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
use serde::de::DeserializeOwned;
|
||||||
use std::any::type_name;
|
use std::any::type_name;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
|
||||||
@@ -62,6 +62,8 @@ pub trait ContractOpts {
|
|||||||
coins: &[Coin],
|
coins: &[Coin],
|
||||||
message: Self::ExecuteMsg,
|
message: Self::ExecuteMsg,
|
||||||
) -> Result<Response, Self::ContractError>;
|
) -> Result<Response, Self::ContractError>;
|
||||||
|
|
||||||
|
fn unchecked_contract_address<D: TestableNymContract>(&self) -> Addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C> ContractOpts for ContractTester<C>
|
impl<C> ContractOpts for ContractTester<C>
|
||||||
@@ -130,14 +132,47 @@ where
|
|||||||
|
|
||||||
C::execute()(self.deps_mut(), env, info, message)
|
C::execute()(self.deps_mut(), env, info, message)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn unchecked_contract_address<D: TestableNymContract>(&self) -> Addr {
|
||||||
|
self.unchecked_contract_address::<D>()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ChainOpts: ContractOpts {
|
pub trait ChainOpts: ContractOpts {
|
||||||
fn set_contract_balance(&mut self, balance: Coin);
|
fn set_contract_balance(&mut self, balance: Coin);
|
||||||
|
|
||||||
fn next_block(&mut self);
|
fn update_block<F: Fn(&mut BlockInfo)>(&mut self, action: F);
|
||||||
|
fn set_to_epoch(&mut self) {
|
||||||
|
self.set_block_time(Timestamp::from_seconds(0))
|
||||||
|
}
|
||||||
|
|
||||||
fn set_block_time(&mut self, time: Timestamp);
|
fn set_to_genesis(&mut self) {
|
||||||
|
self.update_block(|block| {
|
||||||
|
block.height = 1;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn next_block(&mut self) {
|
||||||
|
self.update_block(next_block)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn advance_day_of_blocks(&mut self) {
|
||||||
|
self.update_block(|block| {
|
||||||
|
block.time = block.time.plus_seconds(24 * 60 * 60);
|
||||||
|
block.height += 17280;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn advance_time_by(&mut self, delta_secs: u64) {
|
||||||
|
self.update_block(|block| {
|
||||||
|
block.time = block.time.plus_seconds(delta_secs);
|
||||||
|
block.height += 1
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_block_time(&mut self, time: Timestamp) {
|
||||||
|
self.update_block(|b| b.time = time)
|
||||||
|
}
|
||||||
|
|
||||||
fn execute_msg(
|
fn execute_msg(
|
||||||
&mut self,
|
&mut self,
|
||||||
@@ -186,12 +221,9 @@ where
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
fn next_block(&mut self) {
|
|
||||||
self.app.update_block(next_block)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_block_time(&mut self, time: Timestamp) {
|
fn update_block<F: Fn(&mut BlockInfo)>(&mut self, action: F) {
|
||||||
self.app.update_block(|b| b.time = time)
|
self.app.update_block(action)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn execute_msg(
|
fn execute_msg(
|
||||||
|
|||||||
@@ -2,22 +2,23 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
CommonStorageKeys, ContractOpts, ContractTester, StorageWrapper, TestableNymContract,
|
CommonStorageKeys, ContractOpts, ContractTester, StorageWrapper, TEST_DENOM,
|
||||||
TEST_DENOM,
|
TestableNymContract,
|
||||||
};
|
};
|
||||||
use cosmwasm_std::testing::message_info;
|
use cosmwasm_std::testing::message_info;
|
||||||
use cosmwasm_std::{
|
use cosmwasm_std::{
|
||||||
coin, coins, from_json, to_json_vec, Addr, Coin, MessageInfo, StdError, StdResult, Storage,
|
Addr, Coin, MessageInfo, StdError, StdResult, Storage, coin, coins, from_json, to_json_vec,
|
||||||
};
|
};
|
||||||
use cw_multi_test::Executor;
|
use cw_multi_test::Executor;
|
||||||
use cw_storage_plus::{Key, Path, PrimaryKey};
|
use cw_storage_plus::{Key, Path, PrimaryKey};
|
||||||
use rand::RngCore;
|
|
||||||
use rand_chacha::ChaCha20Rng;
|
use rand_chacha::ChaCha20Rng;
|
||||||
use serde::de::DeserializeOwned;
|
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
use serde::de::DeserializeOwned;
|
||||||
use std::any::type_name;
|
use std::any::type_name;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
|
||||||
|
pub use rand::prelude::*;
|
||||||
|
|
||||||
pub trait StorageReader {
|
pub trait StorageReader {
|
||||||
fn common_key(&self, key: CommonStorageKeys) -> Option<&[u8]>;
|
fn common_key(&self, key: CommonStorageKeys) -> Option<&[u8]>;
|
||||||
|
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
// Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
|
// Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use crate::{mock_api, test_rng, TEST_DENOM};
|
use crate::{TEST_DENOM, mock_api, test_rng};
|
||||||
use cosmwasm_std::testing::MockApi;
|
use cosmwasm_std::testing::MockApi;
|
||||||
use cosmwasm_std::{
|
use cosmwasm_std::{
|
||||||
coin, coins, Addr, Binary, Deps, DepsMut, Empty, Env, MessageInfo, Order, QuerierWrapper,
|
Addr, Binary, Deps, DepsMut, Empty, Env, MessageInfo, Order, QuerierWrapper, Record, Response,
|
||||||
Record, Response, Storage,
|
Storage, coin, coins,
|
||||||
};
|
};
|
||||||
use cw_multi_test::{App, AppBuilder, BankKeeper, Contract, ContractWrapper, Executor};
|
use cw_multi_test::{App, AppBuilder, BankKeeper, Contract, ContractWrapper, Executor};
|
||||||
use rand_chacha::ChaCha20Rng;
|
use rand_chacha::ChaCha20Rng;
|
||||||
use serde::de::DeserializeOwned;
|
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
use serde::de::DeserializeOwned;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fmt::{Debug, Display};
|
use std::fmt::{Debug, Display};
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
@@ -47,27 +47,11 @@ pub trait TestableNymContract {
|
|||||||
fn query() -> QueryFn<Self::QueryMsg, Self::ContractError>;
|
fn query() -> QueryFn<Self::QueryMsg, Self::ContractError>;
|
||||||
fn migrate() -> PermissionedFn<Self::MigrateMsg, Self::ContractError>;
|
fn migrate() -> PermissionedFn<Self::MigrateMsg, Self::ContractError>;
|
||||||
|
|
||||||
fn base_init_msg() -> Self::InitMsg;
|
// not all instances will require default init message, some will always have to provide customised values
|
||||||
|
#[allow(clippy::unimplemented)]
|
||||||
// // for now we don't care about custom queriers
|
fn base_init_msg() -> Self::InitMsg {
|
||||||
// fn contract_wrapper() -> ContractWrapper<
|
unimplemented!("attempted to instantiate contract without defining instantiate message")
|
||||||
// Self::ExecuteMsg,
|
}
|
||||||
// Self::InitMsg,
|
|
||||||
// Self::QueryMsg,
|
|
||||||
// Self::ContractError,
|
|
||||||
// anyhow::Error,
|
|
||||||
// anyhow::Error,
|
|
||||||
// Empty,
|
|
||||||
// Empty,
|
|
||||||
// Empty,
|
|
||||||
// Self::ContractError,
|
|
||||||
// Self::ContractError,
|
|
||||||
// Self::MigrateMsg,
|
|
||||||
// Self::ContractError,
|
|
||||||
// > {
|
|
||||||
// ContractWrapper::new(Self::execute(), Self::instantiate(), Self::query())
|
|
||||||
// .with_migrate(Self::migrate())
|
|
||||||
// }
|
|
||||||
|
|
||||||
fn dyn_contract() -> Box<dyn Contract<Empty>> {
|
fn dyn_contract() -> Box<dyn Contract<Empty>> {
|
||||||
Box::new(
|
Box::new(
|
||||||
@@ -92,6 +76,7 @@ pub struct ContractTesterBuilder<C> {
|
|||||||
app: App<BankKeeper, MockApi, StorageWrapper>,
|
app: App<BankKeeper, MockApi, StorageWrapper>,
|
||||||
storage: StorageWrapper,
|
storage: StorageWrapper,
|
||||||
pub well_known_contracts: HashMap<&'static str, Addr>,
|
pub well_known_contracts: HashMap<&'static str, Addr>,
|
||||||
|
code_ids: HashMap<&'static str, u64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C> ContractTesterBuilder<C> {
|
impl<C> ContractTesterBuilder<C> {
|
||||||
@@ -125,20 +110,33 @@ impl<C> ContractTesterBuilder<C> {
|
|||||||
app,
|
app,
|
||||||
storage,
|
storage,
|
||||||
well_known_contracts: Default::default(),
|
well_known_contracts: Default::default(),
|
||||||
|
code_ids: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn master_address(&self) -> Addr {
|
||||||
|
self.master_address.clone()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn instantiate<D: TestableNymContract>(
|
pub fn instantiate<D: TestableNymContract>(
|
||||||
mut self,
|
mut self,
|
||||||
custom_init_msg: Option<D::InitMsg>,
|
custom_init_msg: Option<D::InitMsg>,
|
||||||
) -> ContractTesterBuilder<C> {
|
) -> ContractTesterBuilder<C> {
|
||||||
|
self.instantiate_contract::<D>(custom_init_msg);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn instantiate_contract<D: TestableNymContract>(
|
||||||
|
&mut self,
|
||||||
|
custom_init_msg: Option<D::InitMsg>,
|
||||||
|
) {
|
||||||
let code_id = self.app.store_code(D::dyn_contract());
|
let code_id = self.app.store_code(D::dyn_contract());
|
||||||
let contract_address = self
|
let contract_address = self
|
||||||
.app
|
.app
|
||||||
.instantiate_contract(
|
.instantiate_contract(
|
||||||
code_id,
|
code_id,
|
||||||
self.master_address.clone(),
|
self.master_address.clone(),
|
||||||
&custom_init_msg.unwrap_or(D::base_init_msg()),
|
&custom_init_msg.unwrap_or_else(|| D::base_init_msg()),
|
||||||
&[],
|
&[],
|
||||||
D::NAME,
|
D::NAME,
|
||||||
Some(self.master_address.to_string()),
|
Some(self.master_address.to_string()),
|
||||||
@@ -154,8 +152,28 @@ impl<C> ContractTesterBuilder<C> {
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
self.code_ids.insert(D::NAME, code_id);
|
||||||
self.well_known_contracts.insert(D::NAME, contract_address);
|
self.well_known_contracts.insert(D::NAME, contract_address);
|
||||||
self
|
}
|
||||||
|
|
||||||
|
// uses the SAME code
|
||||||
|
pub fn migrate_contract<D: TestableNymContract>(&mut self, migrate_msg: &D::MigrateMsg) {
|
||||||
|
self.app
|
||||||
|
.migrate_contract(
|
||||||
|
self.master_address.clone(),
|
||||||
|
self.unchecked_contract_address::<D>(),
|
||||||
|
migrate_msg,
|
||||||
|
self.unchecked_contract_code_id::<D>(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unchecked_contract_address<D: TestableNymContract>(&self) -> Addr {
|
||||||
|
self.well_known_contracts.get(D::NAME).unwrap().clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unchecked_contract_code_id<D: TestableNymContract>(&self) -> u64 {
|
||||||
|
*self.code_ids.get(D::NAME).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build(self) -> ContractTester<C>
|
pub fn build(self) -> ContractTester<C>
|
||||||
@@ -229,6 +247,10 @@ where
|
|||||||
self.insert_common_storage_key(key, value);
|
self.insert_common_storage_key(key, value);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn unchecked_contract_address<D: TestableNymContract>(&self) -> Addr {
|
||||||
|
self.well_known_contracts.get(D::NAME).unwrap().clone()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C> Storage for ContractTester<C>
|
impl<C> Storage for ContractTester<C>
|
||||||
|
|||||||
@@ -0,0 +1,53 @@
|
|||||||
|
// Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
use cosmwasm_std::{Binary, CustomQuery, QuerierWrapper, StdResult, from_json};
|
||||||
|
use serde::Serialize;
|
||||||
|
use serde::de::DeserializeOwned;
|
||||||
|
|
||||||
|
// re-expose methods from QuerierWrapper as traits so that we could more easily define extension traits
|
||||||
|
pub trait ContractQuerier {
|
||||||
|
fn query_contract<T: DeserializeOwned>(
|
||||||
|
&self,
|
||||||
|
address: impl Into<String>,
|
||||||
|
msg: &impl Serialize,
|
||||||
|
) -> StdResult<T>;
|
||||||
|
|
||||||
|
fn query_contract_storage(
|
||||||
|
&self,
|
||||||
|
address: impl Into<String>,
|
||||||
|
key: impl Into<Binary>,
|
||||||
|
) -> StdResult<Option<Vec<u8>>>;
|
||||||
|
|
||||||
|
fn query_contract_storage_value<T: DeserializeOwned>(
|
||||||
|
&self,
|
||||||
|
address: impl Into<String>,
|
||||||
|
key: impl Into<Binary>,
|
||||||
|
) -> StdResult<Option<T>> {
|
||||||
|
match self.query_contract_storage(address, key)? {
|
||||||
|
None => Ok(None),
|
||||||
|
Some(value) => Ok(Some(from_json(&value)?)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<C> ContractQuerier for QuerierWrapper<'_, C>
|
||||||
|
where
|
||||||
|
C: CustomQuery,
|
||||||
|
{
|
||||||
|
fn query_contract<T: DeserializeOwned>(
|
||||||
|
&self,
|
||||||
|
address: impl Into<String>,
|
||||||
|
msg: &impl Serialize,
|
||||||
|
) -> StdResult<T> {
|
||||||
|
self.query_wasm_smart(address, msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn query_contract_storage(
|
||||||
|
&self,
|
||||||
|
address: impl Into<String>,
|
||||||
|
key: impl Into<Binary>,
|
||||||
|
) -> StdResult<Option<Vec<u8>>> {
|
||||||
|
self.query_wasm_raw(address, key)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,6 +10,7 @@ pub mod events;
|
|||||||
pub mod signing;
|
pub mod signing;
|
||||||
pub mod types;
|
pub mod types;
|
||||||
|
|
||||||
|
pub mod contract_querier;
|
||||||
pub mod helpers;
|
pub mod helpers;
|
||||||
|
|
||||||
pub use types::*;
|
pub use types::*;
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use cosmwasm_std::{from_json, to_json_vec, Addr, Coin, MessageInfo, StdResult};
|
use cosmwasm_std::{Addr, Coin, MessageInfo, StdResult, from_json, to_json_vec};
|
||||||
use schemars::JsonSchema;
|
use schemars::JsonSchema;
|
||||||
use serde::de::DeserializeOwned;
|
use serde::de::DeserializeOwned;
|
||||||
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
|
use serde::{Deserialize, Deserializer, Serialize, Serializer, de};
|
||||||
use std::fmt::{Display, Formatter};
|
use std::fmt::{Display, Formatter};
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
pub use verifier::Verifier;
|
pub use verifier::Verifier;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
name = "nym-mixnet-contract-common"
|
name = "nym-mixnet-contract-common"
|
||||||
version = "0.6.0"
|
version = "0.6.0"
|
||||||
description = "Common library for the Nym mixnet contract"
|
description = "Common library for the Nym mixnet contract"
|
||||||
rust-version = "1.62"
|
rust-version = "1.85"
|
||||||
edition = { workspace = true }
|
edition = { workspace = true }
|
||||||
authors = { workspace = true }
|
authors = { workspace = true }
|
||||||
license = { workspace = true }
|
license = { workspace = true }
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ use crate::nym_node::Role;
|
|||||||
use crate::{
|
use crate::{
|
||||||
EpochEventId, EpochState, IntervalEventId, NodeId, OperatingCostRange, ProfitMarginRange,
|
EpochEventId, EpochState, IntervalEventId, NodeId, OperatingCostRange, ProfitMarginRange,
|
||||||
};
|
};
|
||||||
use contracts_common::signing::verifier::ApiVerifierError;
|
|
||||||
use contracts_common::Percent;
|
use contracts_common::Percent;
|
||||||
|
use contracts_common::signing::verifier::ApiVerifierError;
|
||||||
use cosmwasm_std::{Addr, Coin, Decimal, Uint128};
|
use cosmwasm_std::{Addr, Coin, Decimal, Uint128};
|
||||||
use cw_controllers::AdminError;
|
use cw_controllers::AdminError;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
@@ -47,7 +47,9 @@ pub enum MixnetContractError {
|
|||||||
)]
|
)]
|
||||||
InvalidPubKey,
|
InvalidPubKey,
|
||||||
|
|
||||||
#[error("Attempted to reduce node pledge ({current}{denom} - {decrease_by}{denom}) below the minimum amount: {minimum}{denom}")]
|
#[error(
|
||||||
|
"Attempted to reduce node pledge ({current}{denom} - {decrease_by}{denom}) below the minimum amount: {minimum}{denom}"
|
||||||
|
)]
|
||||||
InvalidPledgeReduction {
|
InvalidPledgeReduction {
|
||||||
current: Uint128,
|
current: Uint128,
|
||||||
decrease_by: Uint128,
|
decrease_by: Uint128,
|
||||||
@@ -123,7 +125,9 @@ pub enum MixnetContractError {
|
|||||||
#[error("Provided ed25519 signature did not verify correctly")]
|
#[error("Provided ed25519 signature did not verify correctly")]
|
||||||
InvalidEd25519Signature,
|
InvalidEd25519Signature,
|
||||||
|
|
||||||
#[error("Can't perform the specified action as the current epoch is still progress. It started at {epoch_start} and finishes at {epoch_end}, while the current block time is {current_block_time}")]
|
#[error(
|
||||||
|
"Can't perform the specified action as the current epoch is still progress. It started at {epoch_start} and finishes at {epoch_end}, while the current block time is {current_block_time}"
|
||||||
|
)]
|
||||||
EpochInProgress {
|
EpochInProgress {
|
||||||
current_block_time: u64,
|
current_block_time: u64,
|
||||||
epoch_start: i64,
|
epoch_start: i64,
|
||||||
@@ -133,7 +137,9 @@ pub enum MixnetContractError {
|
|||||||
#[error("attempted to reward a gateway node - this has not been fully integrated yet")]
|
#[error("attempted to reward a gateway node - this has not been fully integrated yet")]
|
||||||
GatewayRewarding,
|
GatewayRewarding,
|
||||||
|
|
||||||
#[error("node {node_id} has already been rewarded during the current rewarding epoch ({absolute_epoch_id})")]
|
#[error(
|
||||||
|
"node {node_id} has already been rewarded during the current rewarding epoch ({absolute_epoch_id})"
|
||||||
|
)]
|
||||||
NodeAlreadyRewarded {
|
NodeAlreadyRewarded {
|
||||||
node_id: NodeId,
|
node_id: NodeId,
|
||||||
absolute_epoch_id: u32,
|
absolute_epoch_id: u32,
|
||||||
@@ -172,7 +178,9 @@ pub enum MixnetContractError {
|
|||||||
#[error("one of the roles in the new active set is empty")]
|
#[error("one of the roles in the new active set is empty")]
|
||||||
EmptyRoleAssignment,
|
EmptyRoleAssignment,
|
||||||
|
|
||||||
#[error("the number of mixnodes in the rewarded set is not divisible by the number of mix-layers (3)")]
|
#[error(
|
||||||
|
"the number of mixnodes in the rewarded set is not divisible by the number of mix-layers (3)"
|
||||||
|
)]
|
||||||
UnevenLayerAssignment,
|
UnevenLayerAssignment,
|
||||||
|
|
||||||
#[error("provided active set is bigger than the rewarded set")]
|
#[error("provided active set is bigger than the rewarded set")]
|
||||||
@@ -196,25 +204,35 @@ pub enum MixnetContractError {
|
|||||||
#[error("key rotation validity below minimum value")]
|
#[error("key rotation validity below minimum value")]
|
||||||
TooShortRotationInterval,
|
TooShortRotationInterval,
|
||||||
|
|
||||||
#[error("this validator ({current_validator}) is not the one responsible for advancing this epoch. It's responsibility of {chosen_validator}.")]
|
#[error(
|
||||||
|
"this validator ({current_validator}) is not the one responsible for advancing this epoch. It's responsibility of {chosen_validator}."
|
||||||
|
)]
|
||||||
RewardingValidatorMismatch {
|
RewardingValidatorMismatch {
|
||||||
current_validator: Addr,
|
current_validator: Addr,
|
||||||
chosen_validator: Addr,
|
chosen_validator: Addr,
|
||||||
},
|
},
|
||||||
|
|
||||||
#[error("the epoch is currently in the process of being advanced. (the state is {current_state}) Please try sending your transaction again once this has finished")]
|
#[error(
|
||||||
|
"the epoch is currently in the process of being advanced. (the state is {current_state}) Please try sending your transaction again once this has finished"
|
||||||
|
)]
|
||||||
EpochAdvancementInProgress { current_state: EpochState },
|
EpochAdvancementInProgress { current_state: EpochState },
|
||||||
|
|
||||||
#[error("the epoch is in an unexpected state. expected 'mix rewarding' state, but we're in {current_state} instead.")]
|
#[error(
|
||||||
|
"the epoch is in an unexpected state. expected 'mix rewarding' state, but we're in {current_state} instead."
|
||||||
|
)]
|
||||||
UnexpectedNonRewardingEpochState { current_state: EpochState },
|
UnexpectedNonRewardingEpochState { current_state: EpochState },
|
||||||
|
|
||||||
#[error("attempted to reward mixnode out of order. Attempted to reward {attempted_to_reward} while last rewarded was {last_rewarded}.")]
|
#[error(
|
||||||
|
"attempted to reward mixnode out of order. Attempted to reward {attempted_to_reward} while last rewarded was {last_rewarded}."
|
||||||
|
)]
|
||||||
RewardingOutOfOrder {
|
RewardingOutOfOrder {
|
||||||
last_rewarded: NodeId,
|
last_rewarded: NodeId,
|
||||||
attempted_to_reward: NodeId,
|
attempted_to_reward: NodeId,
|
||||||
},
|
},
|
||||||
|
|
||||||
#[error("the epoch is currently not in the 'event reconciliation' state. (the state is {current_state})")]
|
#[error(
|
||||||
|
"the epoch is currently not in the 'event reconciliation' state. (the state is {current_state})"
|
||||||
|
)]
|
||||||
EpochNotInEventReconciliationState { current_state: EpochState },
|
EpochNotInEventReconciliationState { current_state: EpochState },
|
||||||
|
|
||||||
#[error(
|
#[error(
|
||||||
@@ -225,14 +243,18 @@ pub enum MixnetContractError {
|
|||||||
#[error("unexpected role assignment. got: {got} while expected: {expected}")]
|
#[error("unexpected role assignment. got: {got} while expected: {expected}")]
|
||||||
UnexpectedRoleAssignment { expected: Role, got: Role },
|
UnexpectedRoleAssignment { expected: Role, got: Role },
|
||||||
|
|
||||||
#[error("attempted to assign an invalid number of nodes for a role of {role}. got {assigned}, but the maximum allowed is {allowed}")]
|
#[error(
|
||||||
|
"attempted to assign an invalid number of nodes for a role of {role}. got {assigned}, but the maximum allowed is {allowed}"
|
||||||
|
)]
|
||||||
IllegalRoleCount {
|
IllegalRoleCount {
|
||||||
role: Role,
|
role: Role,
|
||||||
assigned: u32,
|
assigned: u32,
|
||||||
allowed: u32,
|
allowed: u32,
|
||||||
},
|
},
|
||||||
|
|
||||||
#[error("the epoch is currently not in the 'epoch advancement' state. (the state is {current_state})")]
|
#[error(
|
||||||
|
"the epoch is currently not in the 'epoch advancement' state. (the state is {current_state})"
|
||||||
|
)]
|
||||||
EpochNotInAdvancementState { current_state: EpochState },
|
EpochNotInAdvancementState { current_state: EpochState },
|
||||||
|
|
||||||
#[error("failed to verify message signature: {source}")]
|
#[error("failed to verify message signature: {source}")]
|
||||||
@@ -241,7 +263,9 @@ pub enum MixnetContractError {
|
|||||||
source: ApiVerifierError,
|
source: ApiVerifierError,
|
||||||
},
|
},
|
||||||
|
|
||||||
#[error("this operation is no longer allowed to be performed with vesting tokens. please move them to your liquid balance and try again")]
|
#[error(
|
||||||
|
"this operation is no longer allowed to be performed with vesting tokens. please move them to your liquid balance and try again"
|
||||||
|
)]
|
||||||
DisabledVestingOperation,
|
DisabledVestingOperation,
|
||||||
|
|
||||||
#[error(
|
#[error(
|
||||||
@@ -249,7 +273,9 @@ pub enum MixnetContractError {
|
|||||||
)]
|
)]
|
||||||
NotAVestingMixnode,
|
NotAVestingMixnode,
|
||||||
|
|
||||||
#[error("this delegation has not been performed with the vesting tokens or has already been migrated")]
|
#[error(
|
||||||
|
"this delegation has not been performed with the vesting tokens or has already been migrated"
|
||||||
|
)]
|
||||||
NotAVestingDelegation,
|
NotAVestingDelegation,
|
||||||
|
|
||||||
#[error("the provided profit margin ({provided}) is outside the allowed range: {range}")]
|
#[error("the provided profit margin ({provided}) is outside the allowed range: {range}")]
|
||||||
@@ -258,7 +284,9 @@ pub enum MixnetContractError {
|
|||||||
range: ProfitMarginRange,
|
range: ProfitMarginRange,
|
||||||
},
|
},
|
||||||
|
|
||||||
#[error("the provided interval operating cost ({provided}{denom}) is outside the allowed range: {range}")]
|
#[error(
|
||||||
|
"the provided interval operating cost ({provided}{denom}) is outside the allowed range: {range}"
|
||||||
|
)]
|
||||||
OperatingCostOutsideRange {
|
OperatingCostOutsideRange {
|
||||||
denom: String,
|
denom: String,
|
||||||
provided: Uint128,
|
provided: Uint128,
|
||||||
@@ -279,7 +307,9 @@ pub enum MixnetContractError {
|
|||||||
#[error("the provided nym-node version is not a valid semver. got: {provided}")]
|
#[error("the provided nym-node version is not a valid semver. got: {provided}")]
|
||||||
InvalidNymNodeSemver { provided: String },
|
InvalidNymNodeSemver { provided: String },
|
||||||
|
|
||||||
#[error("the provided nym-node version is not greater than the current one. got: {provided}. current: {current}")]
|
#[error(
|
||||||
|
"the provided nym-node version is not greater than the current one. got: {provided}. current: {current}"
|
||||||
|
)]
|
||||||
NonIncreasingSemver { provided: String, current: String },
|
NonIncreasingSemver { provided: String, current: String },
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ use crate::reward_params::{ActiveSetUpdate, IntervalRewardParams, IntervalReward
|
|||||||
use crate::rewarding::RewardDistribution;
|
use crate::rewarding::RewardDistribution;
|
||||||
use crate::{BlockHeight, ContractStateParamsUpdate, EpochId, IdentityKeyRef, Interval, NodeId};
|
use crate::{BlockHeight, ContractStateParamsUpdate, EpochId, IdentityKeyRef, Interval, NodeId};
|
||||||
pub use contracts_common::events::*;
|
pub use contracts_common::events::*;
|
||||||
use cosmwasm_std::{attr, Addr, Coin, Decimal, Event};
|
use cosmwasm_std::{Addr, Coin, Decimal, Event, attr};
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
|
|
||||||
pub const EVENT_VERSION_PREFIX: &str = "v2_";
|
pub const EVENT_VERSION_PREFIX: &str = "v2_";
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
use crate::{IdentityKey, NodeId, SphinxKey};
|
use crate::{IdentityKey, NodeId, SphinxKey};
|
||||||
use cosmwasm_schema::cw_serde;
|
use cosmwasm_schema::cw_serde;
|
||||||
use cosmwasm_std::{to_json_string, Addr, Coin};
|
use cosmwasm_std::{Addr, Coin, to_json_string};
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
use crate::NodeId;
|
||||||
use crate::error::MixnetContractError;
|
use crate::error::MixnetContractError;
|
||||||
use crate::nym_node::Role;
|
use crate::nym_node::Role;
|
||||||
use crate::NodeId;
|
|
||||||
use cosmwasm_schema::cw_serde;
|
use cosmwasm_schema::cw_serde;
|
||||||
use cosmwasm_schema::schemars::gen::SchemaGenerator;
|
|
||||||
use cosmwasm_schema::schemars::schema::{InstanceType, Schema, SchemaObject};
|
|
||||||
use cosmwasm_schema::schemars::JsonSchema;
|
use cosmwasm_schema::schemars::JsonSchema;
|
||||||
|
use cosmwasm_schema::schemars::r#gen::SchemaGenerator;
|
||||||
|
use cosmwasm_schema::schemars::schema::{InstanceType, Schema, SchemaObject};
|
||||||
use cosmwasm_std::{Addr, Env};
|
use cosmwasm_std::{Addr, Env};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::fmt::{Display, Formatter};
|
use std::fmt::{Display, Formatter};
|
||||||
@@ -27,8 +27,8 @@ pub(crate) mod string_rfc3339_offset_date_time {
|
|||||||
use serde::ser::Error;
|
use serde::ser::Error;
|
||||||
use serde::{Deserializer, Serialize, Serializer};
|
use serde::{Deserializer, Serialize, Serializer};
|
||||||
use std::fmt::Formatter;
|
use std::fmt::Formatter;
|
||||||
use time::format_description::well_known::Rfc3339;
|
|
||||||
use time::OffsetDateTime;
|
use time::OffsetDateTime;
|
||||||
|
use time::format_description::well_known::Rfc3339;
|
||||||
|
|
||||||
struct Rfc3339OffsetDateTimeVisitor;
|
struct Rfc3339OffsetDateTimeVisitor;
|
||||||
|
|
||||||
@@ -91,7 +91,7 @@ impl EpochStatus {
|
|||||||
) -> Result<bool, MixnetContractError> {
|
) -> Result<bool, MixnetContractError> {
|
||||||
match &mut self.state {
|
match &mut self.state {
|
||||||
EpochState::Rewarding {
|
EpochState::Rewarding {
|
||||||
ref mut last_rewarded,
|
last_rewarded,
|
||||||
final_node_id,
|
final_node_id,
|
||||||
} => {
|
} => {
|
||||||
if new_last_rewarded <= *last_rewarded {
|
if new_last_rewarded <= *last_rewarded {
|
||||||
@@ -254,7 +254,7 @@ impl JsonSchema for Interval {
|
|||||||
"Interval".to_owned()
|
"Interval".to_owned()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn json_schema(gen: &mut SchemaGenerator) -> Schema {
|
fn json_schema(r#gen: &mut SchemaGenerator) -> Schema {
|
||||||
let mut schema_object = SchemaObject {
|
let mut schema_object = SchemaObject {
|
||||||
instance_type: Some(InstanceType::Object.into()),
|
instance_type: Some(InstanceType::Object.into()),
|
||||||
..SchemaObject::default()
|
..SchemaObject::default()
|
||||||
@@ -263,12 +263,13 @@ impl JsonSchema for Interval {
|
|||||||
let object_validation = schema_object.object();
|
let object_validation = schema_object.object();
|
||||||
object_validation
|
object_validation
|
||||||
.properties
|
.properties
|
||||||
.insert("id".to_owned(), gen.subschema_for::<IntervalId>());
|
.insert("id".to_owned(), r#gen.subschema_for::<IntervalId>());
|
||||||
object_validation.required.insert("id".to_owned());
|
object_validation.required.insert("id".to_owned());
|
||||||
|
|
||||||
object_validation
|
object_validation.properties.insert(
|
||||||
.properties
|
"epochs_in_interval".to_owned(),
|
||||||
.insert("epochs_in_interval".to_owned(), gen.subschema_for::<u32>());
|
r#gen.subschema_for::<u32>(),
|
||||||
|
);
|
||||||
object_validation
|
object_validation
|
||||||
.required
|
.required
|
||||||
.insert("epochs_in_interval".to_owned());
|
.insert("epochs_in_interval".to_owned());
|
||||||
@@ -277,7 +278,7 @@ impl JsonSchema for Interval {
|
|||||||
// serialization to string, so we just specify the schema to be String.
|
// serialization to string, so we just specify the schema to be String.
|
||||||
object_validation.properties.insert(
|
object_validation.properties.insert(
|
||||||
"current_epoch_start".to_owned(),
|
"current_epoch_start".to_owned(),
|
||||||
gen.subschema_for::<String>(),
|
r#gen.subschema_for::<String>(),
|
||||||
);
|
);
|
||||||
object_validation
|
object_validation
|
||||||
.required
|
.required
|
||||||
@@ -285,7 +286,7 @@ impl JsonSchema for Interval {
|
|||||||
|
|
||||||
object_validation.properties.insert(
|
object_validation.properties.insert(
|
||||||
"current_epoch_id".to_owned(),
|
"current_epoch_id".to_owned(),
|
||||||
gen.subschema_for::<EpochId>(),
|
r#gen.subschema_for::<EpochId>(),
|
||||||
);
|
);
|
||||||
object_validation
|
object_validation
|
||||||
.required
|
.required
|
||||||
@@ -293,12 +294,12 @@ impl JsonSchema for Interval {
|
|||||||
|
|
||||||
object_validation
|
object_validation
|
||||||
.properties
|
.properties
|
||||||
.insert("epoch_length".to_owned(), gen.subschema_for::<Duration>());
|
.insert("epoch_length".to_owned(), r#gen.subschema_for::<Duration>());
|
||||||
object_validation.required.insert("epoch_length".to_owned());
|
object_validation.required.insert("epoch_length".to_owned());
|
||||||
|
|
||||||
object_validation.properties.insert(
|
object_validation.properties.insert(
|
||||||
"total_elapsed_epochs".to_owned(),
|
"total_elapsed_epochs".to_owned(),
|
||||||
gen.subschema_for::<EpochId>(),
|
r#gen.subschema_for::<EpochId>(),
|
||||||
);
|
);
|
||||||
object_validation
|
object_validation
|
||||||
.required
|
.required
|
||||||
|
|||||||
@@ -9,14 +9,14 @@ use crate::error::MixnetContractError;
|
|||||||
use crate::helpers::IntoBaseDecimal;
|
use crate::helpers::IntoBaseDecimal;
|
||||||
use crate::nym_node::Role;
|
use crate::nym_node::Role;
|
||||||
use crate::reward_params::{NodeRewardingParameters, RewardingParams};
|
use crate::reward_params::{NodeRewardingParameters, RewardingParams};
|
||||||
use crate::rewarding::helpers::truncate_reward;
|
|
||||||
use crate::rewarding::RewardDistribution;
|
use crate::rewarding::RewardDistribution;
|
||||||
|
use crate::rewarding::helpers::truncate_reward;
|
||||||
use crate::{
|
use crate::{
|
||||||
Delegation, EpochEventId, EpochId, IdentityKey, IntervalEventId, NodeId, OperatingCostRange,
|
Delegation, EpochEventId, EpochId, IdentityKey, IntervalEventId, NodeId, OperatingCostRange,
|
||||||
Percent, ProfitMarginRange, SphinxKey,
|
Percent, ProfitMarginRange, SphinxKey,
|
||||||
};
|
};
|
||||||
use cosmwasm_schema::cw_serde;
|
use cosmwasm_schema::cw_serde;
|
||||||
use cosmwasm_std::{to_json_string, Addr, Coin, Decimal, StdResult, Uint128};
|
use cosmwasm_std::{Addr, Coin, Decimal, StdResult, Uint128, to_json_string};
|
||||||
use schemars::JsonSchema;
|
use schemars::JsonSchema;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_repr::{Deserialize_repr, Serialize_repr};
|
use serde_repr::{Deserialize_repr, Serialize_repr};
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ use crate::{
|
|||||||
VersionScoreFormulaParams,
|
VersionScoreFormulaParams,
|
||||||
};
|
};
|
||||||
use crate::{OperatingCostRange, ProfitMarginRange};
|
use crate::{OperatingCostRange, ProfitMarginRange};
|
||||||
use contracts_common::{signing::MessageSignature, IdentityKey, Percent};
|
use contracts_common::{IdentityKey, Percent, signing::MessageSignature};
|
||||||
use cosmwasm_schema::cw_serde;
|
use cosmwasm_schema::cw_serde;
|
||||||
use cosmwasm_std::{Coin, Decimal};
|
use cosmwasm_std::{Coin, Decimal};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
@@ -55,7 +55,7 @@ use crate::{
|
|||||||
types::{ContractState, ContractStateParams},
|
types::{ContractState, ContractStateParams},
|
||||||
};
|
};
|
||||||
#[cfg(feature = "schema")]
|
#[cfg(feature = "schema")]
|
||||||
use contracts_common::{signing::Nonce, ContractBuildInformation};
|
use contracts_common::{ContractBuildInformation, signing::Nonce};
|
||||||
#[cfg(feature = "schema")]
|
#[cfg(feature = "schema")]
|
||||||
use cosmwasm_schema::QueryResponses;
|
use cosmwasm_schema::QueryResponses;
|
||||||
|
|
||||||
|
|||||||
@@ -3,9 +3,9 @@
|
|||||||
|
|
||||||
use crate::helpers::IntoBaseDecimal;
|
use crate::helpers::IntoBaseDecimal;
|
||||||
use crate::nym_node::Role;
|
use crate::nym_node::Role;
|
||||||
use crate::{error::MixnetContractError, Percent};
|
use crate::{Percent, error::MixnetContractError};
|
||||||
use cosmwasm_schema::cw_serde;
|
use cosmwasm_schema::cw_serde;
|
||||||
use cosmwasm_std::{to_json_string, Decimal};
|
use cosmwasm_std::{Decimal, to_json_string};
|
||||||
|
|
||||||
pub type Performance = Percent;
|
pub type Performance = Percent;
|
||||||
pub type WorkFactor = Decimal;
|
pub type WorkFactor = Decimal;
|
||||||
|
|||||||
@@ -4,8 +4,8 @@
|
|||||||
use crate::error::MixnetContractError;
|
use crate::error::MixnetContractError;
|
||||||
use crate::helpers::IntoBaseDecimal;
|
use crate::helpers::IntoBaseDecimal;
|
||||||
use crate::reward_params::{NodeRewardingParameters, WorkFactor};
|
use crate::reward_params::{NodeRewardingParameters, WorkFactor};
|
||||||
use crate::rewarding::simulator::simulated_node::SimulatedNode;
|
|
||||||
use crate::rewarding::RewardDistribution;
|
use crate::rewarding::RewardDistribution;
|
||||||
|
use crate::rewarding::simulator::simulated_node::SimulatedNode;
|
||||||
use crate::{Delegation, Interval, IntervalRewardParams, NodeCostParams, NodeId, RewardingParams};
|
use crate::{Delegation, Interval, IntervalRewardParams, NodeCostParams, NodeId, RewardingParams};
|
||||||
use cosmwasm_std::{Coin, Decimal};
|
use cosmwasm_std::{Coin, Decimal};
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
@@ -226,9 +226,9 @@ impl Simulator {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::Percent;
|
||||||
use crate::helpers::compare_decimals;
|
use crate::helpers::compare_decimals;
|
||||||
use crate::reward_params::RewardedSetParams;
|
use crate::reward_params::RewardedSetParams;
|
||||||
use crate::Percent;
|
|
||||||
use cosmwasm_std::testing::mock_env;
|
use cosmwasm_std::testing::mock_env;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
use crate::EpochId;
|
||||||
use crate::config_score::{ConfigScoreParams, OutdatedVersionWeights, VersionScoreFormulaParams};
|
use crate::config_score::{ConfigScoreParams, OutdatedVersionWeights, VersionScoreFormulaParams};
|
||||||
use crate::nym_node::Role;
|
use crate::nym_node::Role;
|
||||||
use crate::reward_params::RewardedSetParams;
|
use crate::reward_params::RewardedSetParams;
|
||||||
use crate::EpochId;
|
|
||||||
use contracts_common::Percent;
|
use contracts_common::Percent;
|
||||||
use cosmwasm_schema::cw_serde;
|
use cosmwasm_schema::cw_serde;
|
||||||
use cosmwasm_std::Coin;
|
use cosmwasm_std::Coin;
|
||||||
|
|||||||
@@ -23,7 +23,9 @@ pub enum NymPerformanceContractError {
|
|||||||
#[error("{address} is not an authorised network monitor")]
|
#[error("{address} is not an authorised network monitor")]
|
||||||
NotAuthorised { address: Addr },
|
NotAuthorised { address: Addr },
|
||||||
|
|
||||||
#[error("attempted to submit performance data for epoch {epoch_id} and node {node_id} whilst last submitted was {last_epoch_id} for node {last_node_id}")]
|
#[error(
|
||||||
|
"attempted to submit performance data for epoch {epoch_id} and node {node_id} whilst last submitted was {last_epoch_id} for node {last_node_id}"
|
||||||
|
)]
|
||||||
StalePerformanceSubmission {
|
StalePerformanceSubmission {
|
||||||
epoch_id: EpochId,
|
epoch_id: EpochId,
|
||||||
node_id: NodeId,
|
node_id: NodeId,
|
||||||
|
|||||||
@@ -16,7 +16,9 @@ pub enum NymPoolContractError {
|
|||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
StdErr(#[from] cosmwasm_std::StdError),
|
StdErr(#[from] cosmwasm_std::StdError),
|
||||||
|
|
||||||
#[error("this sender is not authorised to revoke this grant. its neither the admin or the original (and still whitelisted) granter")]
|
#[error(
|
||||||
|
"this sender is not authorised to revoke this grant. its neither the admin or the original (and still whitelisted) granter"
|
||||||
|
)]
|
||||||
UnauthorizedGrantRevocation,
|
UnauthorizedGrantRevocation,
|
||||||
|
|
||||||
#[error("the specified address is already a whitelisted granter")]
|
#[error("the specified address is already a whitelisted granter")]
|
||||||
@@ -28,7 +30,9 @@ pub enum NymPoolContractError {
|
|||||||
#[error("invalid coin denomination. got {got}, but expected {expected}")]
|
#[error("invalid coin denomination. got {got}, but expected {expected}")]
|
||||||
InvalidDenom { expected: String, got: String },
|
InvalidDenom { expected: String, got: String },
|
||||||
|
|
||||||
#[error("there already exists an active grant for {grantee}. it was granted by {granter} at block height {created_at_height}")]
|
#[error(
|
||||||
|
"there already exists an active grant for {grantee}. it was granted by {granter} at block height {created_at_height}"
|
||||||
|
)]
|
||||||
GrantAlreadyExist {
|
GrantAlreadyExist {
|
||||||
granter: String,
|
granter: String,
|
||||||
grantee: String,
|
grantee: String,
|
||||||
@@ -38,13 +42,17 @@ pub enum NymPoolContractError {
|
|||||||
#[error("could not find any active grants for {grantee}")]
|
#[error("could not find any active grants for {grantee}")]
|
||||||
GrantNotFound { grantee: String },
|
GrantNotFound { grantee: String },
|
||||||
|
|
||||||
#[error("the provided timestamp value ({timestamp}) is set in the past. the current block timestamp is {current_block_timestamp}")]
|
#[error(
|
||||||
|
"the provided timestamp value ({timestamp}) is set in the past. the current block timestamp is {current_block_timestamp}"
|
||||||
|
)]
|
||||||
TimestampInThePast {
|
TimestampInThePast {
|
||||||
timestamp: u64,
|
timestamp: u64,
|
||||||
current_block_timestamp: u64,
|
current_block_timestamp: u64,
|
||||||
},
|
},
|
||||||
|
|
||||||
#[error("there are not enough tokens to process this request. {available} are available, but {required} is needed.")]
|
#[error(
|
||||||
|
"there are not enough tokens to process this request. {available} are available, but {required} is needed."
|
||||||
|
)]
|
||||||
InsufficientTokens { available: Coin, required: Coin },
|
InsufficientTokens { available: Coin, required: Coin },
|
||||||
|
|
||||||
#[error("the period length can't be zero")]
|
#[error("the period length can't be zero")]
|
||||||
@@ -53,22 +61,30 @@ pub enum NymPoolContractError {
|
|||||||
#[error("the provided coin value is zero")]
|
#[error("the provided coin value is zero")]
|
||||||
ZeroAmount,
|
ZeroAmount,
|
||||||
|
|
||||||
#[error("the periodic spend limit of {periodic} was set to be higher than the total spend limit {total_limit}")]
|
#[error(
|
||||||
|
"the periodic spend limit of {periodic} was set to be higher than the total spend limit {total_limit}"
|
||||||
|
)]
|
||||||
PeriodicGrantOverSpendLimit { periodic: Coin, total_limit: Coin },
|
PeriodicGrantOverSpendLimit { periodic: Coin, total_limit: Coin },
|
||||||
|
|
||||||
#[error("the accumulation spend limit of {accumulation} was set to be lower than the periodic grant amount of {periodic_grant}")]
|
#[error(
|
||||||
|
"the accumulation spend limit of {accumulation} was set to be lower than the periodic grant amount of {periodic_grant}"
|
||||||
|
)]
|
||||||
AccumulationBelowGrantAmount {
|
AccumulationBelowGrantAmount {
|
||||||
accumulation: Coin,
|
accumulation: Coin,
|
||||||
periodic_grant: Coin,
|
periodic_grant: Coin,
|
||||||
},
|
},
|
||||||
|
|
||||||
#[error("the accumulation spend limit of {accumulation} was set to be higher than the total spend limit of {total_limit}")]
|
#[error(
|
||||||
|
"the accumulation spend limit of {accumulation} was set to be higher than the total spend limit of {total_limit}"
|
||||||
|
)]
|
||||||
AccumulationOverSpendLimit {
|
AccumulationOverSpendLimit {
|
||||||
accumulation: Coin,
|
accumulation: Coin,
|
||||||
total_limit: Coin,
|
total_limit: Coin,
|
||||||
},
|
},
|
||||||
|
|
||||||
#[error("the specified delayed allowance would never be available. it would become active at {available_timestamp} yet it expires at {expiration_timestamp}")]
|
#[error(
|
||||||
|
"the specified delayed allowance would never be available. it would become active at {available_timestamp} yet it expires at {expiration_timestamp}"
|
||||||
|
)]
|
||||||
UnattainableDelayedAllowance {
|
UnattainableDelayedAllowance {
|
||||||
expiration_timestamp: u64,
|
expiration_timestamp: u64,
|
||||||
available_timestamp: u64,
|
available_timestamp: u64,
|
||||||
|
|||||||
@@ -88,10 +88,10 @@ pub mod grants {
|
|||||||
|
|
||||||
pub fn basic_mut(&mut self) -> &mut BasicAllowance {
|
pub fn basic_mut(&mut self) -> &mut BasicAllowance {
|
||||||
match self {
|
match self {
|
||||||
Allowance::Basic(ref mut allowance) => allowance,
|
Allowance::Basic(allowance) => allowance,
|
||||||
Allowance::ClassicPeriodic(ref mut allowance) => &mut allowance.basic,
|
Allowance::ClassicPeriodic(allowance) => &mut allowance.basic,
|
||||||
Allowance::CumulativePeriodic(ref mut allowance) => &mut allowance.basic,
|
Allowance::CumulativePeriodic(allowance) => &mut allowance.basic,
|
||||||
Allowance::Delayed(ref mut allowance) => &mut allowance.basic,
|
Allowance::Delayed(allowance) => &mut allowance.basic,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -752,7 +752,7 @@ pub mod query_responses {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use cosmwasm_std::{coin, Uint128};
|
use cosmwasm_std::{Uint128, coin};
|
||||||
|
|
||||||
const TEST_DENOM: &str = "unym";
|
const TEST_DENOM: &str = "unym";
|
||||||
|
|
||||||
@@ -873,8 +873,8 @@ mod tests {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod basic_allowance {
|
mod basic_allowance {
|
||||||
use super::*;
|
use super::*;
|
||||||
use cosmwasm_std::testing::mock_env;
|
|
||||||
use cosmwasm_std::Timestamp;
|
use cosmwasm_std::Timestamp;
|
||||||
|
use cosmwasm_std::testing::mock_env;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn doesnt_allow_expirations_in_the_past() {
|
fn doesnt_allow_expirations_in_the_past() {
|
||||||
@@ -1158,8 +1158,8 @@ mod tests {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod delayed_allowance {
|
mod delayed_allowance {
|
||||||
use super::*;
|
use super::*;
|
||||||
use cosmwasm_std::testing::mock_env;
|
|
||||||
use cosmwasm_std::Timestamp;
|
use cosmwasm_std::Timestamp;
|
||||||
|
use cosmwasm_std::testing::mock_env;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn doesnt_allow_availability_in_the_past() {
|
fn doesnt_allow_availability_in_the_past() {
|
||||||
|
|||||||
@@ -20,8 +20,8 @@ pub fn ensure_unix_timestamp_not_in_the_past(
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use cosmwasm_std::testing::mock_env;
|
|
||||||
use cosmwasm_std::Timestamp;
|
use cosmwasm_std::Timestamp;
|
||||||
|
use cosmwasm_std::testing::mock_env;
|
||||||
use time::macros::datetime;
|
use time::macros::datetime;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user