Compare commits

..

10 Commits

Author SHA1 Message Date
dynco-nym 452ce3da8c self described field not null 2024-10-30 17:37:53 +01:00
dynco-nym f6105c9483 Point to internal deps + rebase + v0.1.5 2024-10-30 17:33:31 +01:00
dynco-nym 52004b3e13 Compatible with directory v2 2024-10-30 16:54:04 +01:00
dynco-nym f46332d24a Sqlx offline query data + clippy 2024-10-30 16:54:04 +01:00
dynco-nym 7629c5b3a0 Agent 0.1.4 2024-10-30 16:54:04 +01:00
dynco-nym 4d22ddd75a Agent 0.1.3 2024-10-30 16:54:04 +01:00
dynco-nym e21b37b1a9 Testrun stores gw identity key instead of gw pk 2024-10-30 16:54:04 +01:00
dynco-nym 493aaf7bb4 Better logging on agent 2024-10-30 16:54:04 +01:00
dynco-nym bdecab0205 Clean up stale testruns & logging
- log gw identity key
- better agent testrun logging
- log responses
- change response code for agents
2024-10-30 16:54:04 +01:00
dynco-nym 19d1939fb7 Use unstable explorer client 2024-10-30 16:54:04 +01:00
1042 changed files with 24774 additions and 54057 deletions
+28 -15
View File
@@ -6,27 +6,20 @@ on:
jobs: jobs:
build: build:
runs-on: arc-ubuntu-20.04 runs-on: arc-ubuntu-20.04
defaults:
run:
working-directory: documentation/docs
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Install Dependencies (Linux) - name: Install Dependencies (Linux)
run: sudo apt-get update && sudo apt-get install -y build-essential curl wget libssl-dev libudev-dev squashfs-tools protobuf-compiler git python3 && sudo apt-get update --fix-missing run: sudo apt-get update && sudo apt-get install -y build-essential curl wget libssl-dev libudev-dev squashfs-tools protobuf-compiler git python3 && sudo apt-get update --fix-missing
- name: Install pip3 - name: Install pip3
run: sudo apt install -y python3-pip run: sudo apt install -y python3-pip
- name: Install Python3 modules - name: Install Python3 modules
run: sudo pip3 install pandas tabulate run: sudo pip3 install pandas tabulate
- name: Install rsync - name: Install rsync
run: sudo apt-get install rsync run: sudo apt-get install rsync
- uses: rlespinasse/github-slug-action@v3.x - uses: rlespinasse/github-slug-action@v3.x
- name: Setup pnpm
uses: pnpm/action-setup@v4.0.0
with:
version: 9
- uses: actions/setup-node@v4 - uses: actions/setup-node@v4
with: with:
node-version: 20 node-version: 18
- name: Install Rust stable - name: Install Rust stable
uses: actions-rs/toolchain@v1 uses: actions-rs/toolchain@v1
with: with:
@@ -36,13 +29,33 @@ jobs:
with: with:
command: build command: build
args: --workspace --release args: --workspace --release
- name: Install mdbook and plugins
run: cd documentation && ./install_mdbook_deps.sh
- name: Remove existing Nym config directory (`~/.nym/`)
run: cd documentation && ./remove_existing_config.sh
continue-on-error: false
# This is the original flow
# - name: Build all projects in documentation/ & move to ~/dist/docs/
# run: cd documentation && ./build_all_to_dist.sh
- name: Install project dependencies # This is a workaround replacement which builds on the last working commit b332a6b55668f60988e36961f3f62a794ba82ddb and then on current branch
run: pnpm i - name: Save current branch to ~/current_branch
- name: Build project run: git rev-parse --abbrev-ref HEAD > ~/current_branch
run: pnpm run build - name: Git pull, reset & switch to b332a6b55668f60988e36961f3f62a794ba82ddb
- name: Move files to /dist/ run: git pull && git reset --hard && git checkout b332a6b55668f60988e36961f3f62a794ba82ddb
run: ../scripts/move-to-dist.sh - name: Build all projects in documentation/ & move to ~/dist/docs/ from b332a6b55668f60988e36961f3f62a794ba82ddb
run: cd documentation && ./build_all_to_dist.sh
- name: Switch to current branch
run: git checkout $echo "$(cat ~/current_branch)"
- name: Build all projects in documentation/ & move to ~/dist/docs/ on current branch
run: cd documentation && ./build_all_to_dist.sh && rm ~/current_branch
# End of replacemet
- name: Post process
run: cd documentation && ./post_process.sh
continue-on-error: false
- name: Create Vercel project file - name: Create Vercel project file
uses: mobiledevops/secret-to-file-action@v1 uses: mobiledevops/secret-to-file-action@v1
@@ -15,6 +15,24 @@ on:
type: boolean type: boolean
schedule: schedule:
- cron: "14 0 * * *" - cron: "14 0 * * *"
pull_request:
paths:
- "clients/**"
- "common/**"
- "explorer-api/**"
- "gateway/**"
- "integrations/**"
- "mixnode/**"
- "nym-api/**"
- "nym-node/**"
- "nym-outfox/**"
- 'nym-data-observatory/**'
- "nym-validator-rewarder/**"
- "sdk/rust/nym-sdk/**"
- "service-providers/**"
- "tools/**"
- "nymvisor/**"
- ".github/workflows/ci-build-upload-binaries.yml"
jobs: jobs:
publish-nym: publish-nym:
+1 -1
View File
@@ -9,7 +9,7 @@ on:
jobs: jobs:
cargo-deny: cargo-deny:
runs-on: ubuntu-latest runs-on: arc-ubuntu-22.04-dind
strategy: strategy:
matrix: matrix:
checks: checks:
@@ -2,5 +2,9 @@
{ {
"rust":"stable", "rust":"stable",
"runOnEvent":"always" "runOnEvent":"always"
},
{
"rust":"beta",
"runOnEvent":"pull_request"
} }
] ]
@@ -2,6 +2,11 @@ name: ci-contracts-upload-binaries
on: on:
workflow_dispatch: workflow_dispatch:
pull_request:
paths:
- 'common/**'
- 'contracts/**'
- '.github/workflows/ci-contracts-upload-binaries.yml'
env: env:
NETWORK: mainnet NETWORK: mainnet
+29 -19
View File
@@ -3,35 +3,28 @@ name: ci-docs
on: on:
workflow_dispatch: workflow_dispatch:
push: push:
branches-ignore: [master] branches-ignore: master
paths: paths:
- "documentation/docs/**" - 'documentation/docs/**'
- ".github/workflows/ci-docs.yml" - '.github/workflows/ci-docs.yml'
jobs: jobs:
build: build:
runs-on: arc-ubuntu-20.04 runs-on: arc-ubuntu-20.04
defaults:
run:
working-directory: documentation/docs
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Install Dependencies (Linux) - name: Install Dependencies (Linux)
run: sudo apt-get update && sudo apt-get install -y build-essential curl wget libssl-dev libudev-dev squashfs-tools protobuf-compiler git python3 && sudo apt-get update --fix-missing run: sudo apt-get update && sudo apt-get install -y build-essential curl wget libssl-dev libudev-dev squashfs-tools protobuf-compiler git python3 && sudo apt-get update --fix-missing
- name: Install pip3 - name: Install pip3
run: sudo apt install -y python3-pip run: sudo apt install -y python3-pip
- name: Install Python3 modules - name: Install Python3 modules
run: sudo pip3 install pandas tabulate run: sudo pip3 install pandas tabulate
- name: Install rsync - name: Install rsync
run: sudo apt-get install rsync run: sudo apt-get install rsync
- uses: rlespinasse/github-slug-action@v3.x - uses: rlespinasse/github-slug-action@v3.x
- name: Setup pnpm
uses: pnpm/action-setup@v4.0.0
with:
version: 9
- uses: actions/setup-node@v4 - uses: actions/setup-node@v4
with: with:
node-version: 20 node-version: 18
- name: Install Rust stable - name: Install Rust stable
uses: actions-rs/toolchain@v1 uses: actions-rs/toolchain@v1
with: with:
@@ -41,13 +34,30 @@ jobs:
with: with:
command: build command: build
args: --workspace --release args: --workspace --release
- name: Install mdbook and plugins
run: cd documentation && ./install_mdbook_deps.sh
- name: Remove existing Nym config directory (`~/.nym/`)
run: cd documentation && ./remove_existing_config.sh
continue-on-error: false
- name: Install project dependencies # This is the original flow
run: pnpm i # - name: Build all projects in documentation/ & move to ~/dist/docs/
- name: Build project # run: cd documentation && ./build_all_to_dist.sh
run: pnpm run build
- name: Move files to /dist/ # This is a workaround replacement which builds on the last working commit b332a6b55668f60988e36961f3f62a794ba82ddb and then on current branch
run: ../scripts/move-to-dist.sh - name: Save current branch to ~/current_branch
run: git rev-parse --abbrev-ref HEAD > ~/current_branch
- name: Git pull, reset & switch to b332a6b55668f60988e36961f3f62a794ba82ddb
run: git pull && git reset --hard && git checkout b332a6b55668f60988e36961f3f62a794ba82ddb
- name: Build all projects in documentation/ & move to ~/dist/docs/ from b332a6b55668f60988e36961f3f62a794ba82ddb
run: cd documentation && ./build_all_to_dist.sh
- name: Switch to current branch
run: git checkout $echo "$(cat ~/current_branch)"
- name: Build all projects in documentation/ & move to ~/dist/docs/ on current branch
run: cd documentation && ./build_all_to_dist.sh && rm ~/current_branch
# End of replacemet
- name: Deploy branch to CI www - name: Deploy branch to CI www
continue-on-error: true continue-on-error: true
@@ -58,5 +68,5 @@ jobs:
SOURCE: "dist/docs/" SOURCE: "dist/docs/"
REMOTE_HOST: ${{ secrets.CI_WWW_REMOTE_HOST }} REMOTE_HOST: ${{ secrets.CI_WWW_REMOTE_HOST }}
REMOTE_USER: ${{ secrets.CI_WWW_REMOTE_USER }} REMOTE_USER: ${{ secrets.CI_WWW_REMOTE_USER }}
TARGET: ${{ secrets.CI_WWW_REMOTE_TARGET }}/docs-nextra-${{ env.GITHUB_REF_SLUG }} TARGET: ${{ secrets.CI_WWW_REMOTE_TARGET }}/docs-${{ env.GITHUB_REF_SLUG }}
EXCLUDE: "/node_modules/" EXCLUDE: "/node_modules/"
+39
View File
@@ -0,0 +1,39 @@
name: ci-nym-api-tests
on:
workflow_dispatch:
push:
paths:
- "nym-api/**"
defaults:
run:
working-directory: nym-api/tests
jobs:
test:
name: nym-api tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: install yarn in root
run: cd ../.. && yarn install
- name: Install npm
run: npm install
- name: Node v18
uses: actions/setup-node@v4
with:
node-version: 18.1.0
- name: Install yarn
run: yarn install
- name: Run yarn
run: yarn
- name: Run tests
run: yarn test:sandbox
working-directory: nym-api/tests
@@ -0,0 +1,79 @@
name: ci-sdk-docs-typescript
on:
pull_request:
paths:
- "sdk/typescript/**"
- "wasm/**"
- '.github/workflows/ci-sdk-docs-typescript.yml'
jobs:
build:
runs-on: custom-linux
steps:
- uses: actions/checkout@v4
- name: Install rsync
run: sudo apt-get install rsync
continue-on-error: true
- uses: rlespinasse/github-slug-action@v3.x
- uses: actions/setup-node@v4
with:
node-version: 18.17
- name: Install Rust stable
uses: actions-rs/toolchain@v1
with:
toolchain: stable
- name: Setup yarn
run: npm install -g yarn
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: '1.20'
- name: Install wasm-pack
run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
- name: Install wasm-opt
uses: ./.github/actions/install-wasm-opt
with:
version: '116'
- name: Build branch WASM packages
run: make sdk-wasm-build
- name: Install
run: yarn
- name: Build
run: yarn docs:prod:build
- name: Deploy branch to CI www (docs)
continue-on-error: true
uses: easingthemes/ssh-deploy@main
env:
SSH_PRIVATE_KEY: ${{ secrets.CI_WWW_SSH_PRIVATE_KEY }}
ARGS: "-rltgoDzvO --delete"
SOURCE: "dist/ts/"
REMOTE_HOST: ${{ secrets.CI_WWW_REMOTE_HOST }}
REMOTE_USER: ${{ secrets.CI_WWW_REMOTE_USER }}
TARGET: ${{ secrets.CI_WWW_REMOTE_TARGET }}/sdk-ts-docs-${{ env.GITHUB_REF_SLUG }}
EXCLUDE: "/dist/, /node_modules/"
- name: Matrix - Node Install
run: npm install
working-directory: .github/workflows/support-files
- name: Matrix - Send Notification
env:
NYM_NOTIFICATION_KIND: ts-packages
NYM_PROJECT_NAME: "sdk-ts-docs"
NYM_CI_WWW_BASE: "${{ secrets.NYM_CI_WWW_BASE }}/docs/sdk/typescript"
NYM_CI_WWW_LOCATION: "sdk-ts-docs-${{ env.GITHUB_REF_SLUG }}"
GIT_COMMIT_MESSAGE: "${{ github.event.head_commit.message }}"
GIT_BRANCH: "${GITHUB_REF##*/}"
IS_SUCCESS: "${{ job.status == 'success' }}"
MATRIX_SERVER: "${{ secrets.MATRIX_SERVER }}"
MATRIX_ROOM: "${{ secrets.MATRIX_ROOM }}"
MATRIX_USER_ID: "${{ secrets.MATRIX_USER_ID }}"
MATRIX_TOKEN: "${{ secrets.MATRIX_TOKEN }}"
MATRIX_DEVICE_ID: "${{ secrets.MATRIX_DEVICE_ID }}"
uses: docker://keybaseio/client:stable-node
with:
args: .github/workflows/support-files/notifications/entry_point.sh
+1 -3
View File
@@ -4,9 +4,7 @@ on:
pull_request: pull_request:
branches: branches:
- develop - develop
- "release/**" - 'release/**'
paths-ignore:
- "documentation/**"
types: types:
- labeled - labeled
- unlabeled - unlabeled
+10 -15
View File
@@ -2,10 +2,6 @@ name: Build and upload Node Status agent container to harbor.nymte.ch
on: on:
workflow_dispatch: workflow_dispatch:
inputs:
gateway_probe_git_ref:
type: string
description: Which gateway probe git ref to build the image with
env: env:
WORKING_DIRECTORY: "nym-node-status-agent" WORKING_DIRECTORY: "nym-node-status-agent"
@@ -36,26 +32,25 @@ jobs:
with: with:
cmd: yq -oy '.package.version' ${{ env.WORKING_DIRECTORY }}/Cargo.toml cmd: yq -oy '.package.version' ${{ env.WORKING_DIRECTORY }}/Cargo.toml
- name: cleanup-gateway-probe-ref - name: Check if tag exists
id: cleanup_gateway_probe_ref
run: | run: |
GATEWAY_PROBE_GIT_REF=${{ github.event.inputs.gateway_probe_git_ref }} if git rev-parse ${{ steps.get_version.outputs.value }} >/dev/null 2>&1; then
GIT_REF_SLUG="${GATEWAY_PROBE_GIT_REF//\//-}" echo "Tag ${{ steps.get_version.outputs.value }} already exists"
echo "git_ref=${GIT_REF_SLUG}" >> $GITHUB_OUTPUT fi
- name: Remove existing tag if exists - name: Remove existing tag if exists
run: | run: |
if git rev-parse ${{ env.WORKING_DIRECTORY }}-${{ steps.get_version.outputs.result }}-${{ steps.cleanup_gateway_probe_ref.outputs.git_ref }} >/dev/null 2>&1; then if git rev-parse ${{ env.WORKING_DIRECTORY }}-${{ steps.get_version.outputs.result }} >/dev/null 2>&1; then
git push --delete origin ${{ env.WORKING_DIRECTORY }}-${{ steps.get_version.outputs.result }}-${{ steps.cleanup_gateway_probe_ref.outputs.git_ref }} git push --delete origin ${{ env.WORKING_DIRECTORY }}-${{ steps.get_version.outputs.result }}
git tag -d ${{ env.WORKING_DIRECTORY }}-${{ steps.get_version.outputs.result }}-${{ steps.cleanup_gateway_probe_ref.outputs.git_ref }} git tag -d ${{ env.WORKING_DIRECTORY }}-${{ steps.get_version.outputs.result }}
fi fi
- name: Create tag - name: Create tag
run: | run: |
git tag -a ${{ env.WORKING_DIRECTORY }}-${{ steps.get_version.outputs.result }}-${{ steps.cleanup_gateway_probe_ref.outputs.git_ref }} -m "Version ${{ steps.get_version.outputs.result }}-${{ steps.cleanup_gateway_probe_ref.outputs.git_ref }}" git tag -a ${{ env.WORKING_DIRECTORY }}-${{ steps.get_version.outputs.result }} -m "Version ${{ steps.get_version.outputs.result }}"
git push origin ${{ env.WORKING_DIRECTORY }}-${{ steps.get_version.outputs.result }}-${{ steps.cleanup_gateway_probe_ref.outputs.git_ref }} git push origin ${{ env.WORKING_DIRECTORY }}-${{ steps.get_version.outputs.result }}
- 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.CONTAINER_NAME }}:${{ steps.get_version.outputs.result }}-${{ steps.cleanup_gateway_probe_ref.outputs.git_ref }} docker build -f ${{ env.WORKING_DIRECTORY }}/Dockerfile . -t harbor.nymte.ch/nym/${{ env.CONTAINER_NAME }}:${{ steps.get_version.outputs.result }} -t harbor.nymte.ch/nym/${{ env.CONTAINER_NAME }}:latest
docker push harbor.nymte.ch/nym/${{ env.CONTAINER_NAME }} --all-tags docker push harbor.nymte.ch/nym/${{ env.CONTAINER_NAME }} --all-tags
-55
View File
@@ -1,55 +0,0 @@
name: Build and upload nym node container to harbor.nymte.ch
on:
workflow_dispatch:
env:
WORKING_DIRECTORY: "nym-node"
CONTAINER_NAME: "nym-node"
jobs:
build-container:
runs-on: arc-ubuntu-22.04-dind
steps:
- name: Login to Harbor
uses: docker/login-action@v3
with:
registry: harbor.nymte.ch
username: ${{ secrets.HARBOR_ROBOT_USERNAME }}
password: ${{ secrets.HARBOR_ROBOT_SECRET }}
- name: Checkout repo
uses: actions/checkout@v4
- name: Configure git identity
run: |
git config --global user.email "lawrence@nymtech.net"
git config --global user.name "Lawrence Stalder"
- name: Get version from cargo.toml
uses: mikefarah/yq@v4.44.3
id: get_version
with:
cmd: yq -oy '.package.version' ${{ env.WORKING_DIRECTORY }}/Cargo.toml
- name: Check if tag exists
run: |
if git rev-parse ${{ steps.get_version.outputs.value }} >/dev/null 2>&1; then
echo "Tag ${{ steps.get_version.outputs.value }} already exists"
fi
- name: Remove existing tag if exists
run: |
if git rev-parse ${{ env.WORKING_DIRECTORY }}-${{ steps.get_version.outputs.result }} >/dev/null 2>&1; then
git push --delete origin ${{ env.WORKING_DIRECTORY }}-${{ steps.get_version.outputs.result }}
git tag -d ${{ env.WORKING_DIRECTORY }}-${{ steps.get_version.outputs.result }}
fi
- name: Create tag
run: |
git tag -a ${{ env.WORKING_DIRECTORY }}-${{ steps.get_version.outputs.result }} -m "Version ${{ steps.get_version.outputs.result }}"
git push origin ${{ env.WORKING_DIRECTORY }}-${{ steps.get_version.outputs.result }}
- name: BuildAndPushImageOnHarbor
run: |
docker build -f ${{ env.WORKING_DIRECTORY }}/Dockerfile . -t harbor.nymte.ch/nym/${{ env.CONTAINER_NAME }}:${{ steps.get_version.outputs.result }} -t harbor.nymte.ch/nym/${{ env.CONTAINER_NAME }}:latest
docker push harbor.nymte.ch/nym/${{ env.CONTAINER_NAME }} --all-tags
@@ -1,49 +0,0 @@
name: Build and upload Validator Rewarder container to harbor.nymte.ch
on:
workflow_dispatch:
env:
WORKING_DIRECTORY: "nym-validator-rewarder"
CONTAINER_NAME: "validator-rewarder"
jobs:
build-container:
runs-on: arc-ubuntu-22.04-dind
steps:
- name: Login to Harbor
uses: docker/login-action@v3
with:
registry: harbor.nymte.ch
username: ${{ secrets.HARBOR_ROBOT_USERNAME }}
password: ${{ secrets.HARBOR_ROBOT_SECRET }}
- name: Checkout repo
uses: actions/checkout@v4
- name: Configure git identity
run: |
git config --global user.email "lawrence@nymtech.net"
git config --global user.name "Lawrence Stalder"
- name: Get version from cargo.toml
uses: mikefarah/yq@v4.44.3
id: get_version
with:
cmd: yq -oy '.package.version' ${{ env.WORKING_DIRECTORY }}/nym-credential-proxy/Cargo.toml
- name: Remove existing tag if exists
run: |
if git rev-parse ${{ env.WORKING_DIRECTORY }}-${{ steps.get_version.outputs.result }} >/dev/null 2>&1; then
git push --delete origin ${{ env.WORKING_DIRECTORY }}-${{ steps.get_version.outputs.result }}
git tag -d ${{ env.WORKING_DIRECTORY }}-${{ steps.get_version.outputs.result }}
fi
- name: Create tag
run: |
git tag -a ${{ env.WORKING_DIRECTORY }}-${{ steps.get_version.outputs.result }} -m "Version ${{ steps.get_version.outputs.result }}"
git push origin ${{ env.WORKING_DIRECTORY }}-${{ steps.get_version.outputs.result }}
- name: BuildAndPushImageOnHarbor
run: |
docker build -f ${{ env.WORKING_DIRECTORY }}/Dockerfile . -t harbor.nymte.ch/nym/${{ env.CONTAINER_NAME }}:${{ steps.get_version.outputs.result }} -t harbor.nymte.ch/nym/${{ env.CONTAINER_NAME }}:latest
docker push harbor.nymte.ch/nym/${{ env.CONTAINER_NAME }} --all-tags
Generated
+33 -62
View File
@@ -4502,9 +4502,7 @@ dependencies = [
"nym-pemstore", "nym-pemstore",
"nym-serde-helpers", "nym-serde-helpers",
"nym-sphinx", "nym-sphinx",
"nym-statistics-common",
"nym-task", "nym-task",
"nym-ticketbooks-merkle",
"nym-topology", "nym-topology",
"nym-types", "nym-types",
"nym-validator-client", "nym-validator-client",
@@ -4514,7 +4512,6 @@ dependencies = [
"rand_chacha", "rand_chacha",
"reqwest 0.12.4", "reqwest 0.12.4",
"schemars", "schemars",
"semver 1.0.23",
"serde", "serde",
"serde_json", "serde_json",
"sha2 0.9.9", "sha2 0.9.9",
@@ -4545,7 +4542,6 @@ dependencies = [
"ecdsa", "ecdsa",
"getset", "getset",
"nym-compact-ecash", "nym-compact-ecash",
"nym-contracts-common",
"nym-credentials-interface", "nym-credentials-interface",
"nym-crypto", "nym-crypto",
"nym-ecash-time", "nym-ecash-time",
@@ -4553,8 +4549,6 @@ dependencies = [
"nym-network-defaults", "nym-network-defaults",
"nym-node-requests", "nym-node-requests",
"nym-serde-helpers", "nym-serde-helpers",
"nym-ticketbooks-merkle",
"rand_chacha",
"schemars", "schemars",
"serde", "serde",
"serde_json", "serde_json",
@@ -4628,7 +4622,6 @@ dependencies = [
"hmac", "hmac",
"nym-credentials-interface", "nym-credentials-interface",
"nym-crypto", "nym-crypto",
"nym-network-defaults",
"nym-service-provider-requests-common", "nym-service-provider-requests-common",
"nym-sphinx", "nym-sphinx",
"nym-wireguard-types", "nym-wireguard-types",
@@ -4652,7 +4645,6 @@ dependencies = [
"nym-ecash-contract-common", "nym-ecash-contract-common",
"nym-ecash-time", "nym-ecash-time",
"nym-network-defaults", "nym-network-defaults",
"nym-task",
"nym-validator-client", "nym-validator-client",
"rand", "rand",
"thiserror", "thiserror",
@@ -4852,7 +4844,6 @@ dependencies = [
"nym-nonexhaustive-delayqueue", "nym-nonexhaustive-delayqueue",
"nym-pemstore", "nym-pemstore",
"nym-sphinx", "nym-sphinx",
"nym-statistics-common",
"nym-task", "nym-task",
"nym-topology", "nym-topology",
"nym-validator-client", "nym-validator-client",
@@ -5089,7 +5080,7 @@ dependencies = [
[[package]] [[package]]
name = "nym-credential-proxy" name = "nym-credential-proxy"
version = "0.1.3" version = "0.1.1"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"async-trait", "async-trait",
@@ -5429,12 +5420,19 @@ dependencies = [
"async-trait", "async-trait",
"bip39", "bip39",
"bs58", "bs58",
"clap 4.5.20",
"colored",
"dashmap", "dashmap",
"defguard_wireguard_rs", "defguard_wireguard_rs",
"dirs",
"dotenvy",
"futures", "futures",
"humantime-serde",
"ipnetwork 0.20.0", "ipnetwork 0.20.0",
"nym-api-requests", "nym-api-requests",
"nym-authenticator", "nym-authenticator",
"nym-bin-common",
"nym-config",
"nym-credential-verification", "nym-credential-verification",
"nym-credentials", "nym-credentials",
"nym-credentials-interface", "nym-credentials-interface",
@@ -5448,6 +5446,7 @@ dependencies = [
"nym-network-defaults", "nym-network-defaults",
"nym-network-requester", "nym-network-requester",
"nym-node-http-api", "nym-node-http-api",
"nym-pemstore",
"nym-sdk", "nym-sdk",
"nym-sphinx", "nym-sphinx",
"nym-statistics-common", "nym-statistics-common",
@@ -5457,9 +5456,13 @@ dependencies = [
"nym-validator-client", "nym-validator-client",
"nym-wireguard", "nym-wireguard",
"nym-wireguard-types", "nym-wireguard-types",
"once_cell",
"rand", "rand",
"sha2 0.10.8", "serde",
"serde_json",
"si-scale",
"sqlx", "sqlx",
"subtle-encoding",
"thiserror", "thiserror",
"time", "time",
"tokio", "tokio",
@@ -5487,7 +5490,6 @@ dependencies = [
"nym-network-defaults", "nym-network-defaults",
"nym-pemstore", "nym-pemstore",
"nym-sphinx", "nym-sphinx",
"nym-statistics-common",
"nym-task", "nym-task",
"nym-validator-client", "nym-validator-client",
"rand", "rand",
@@ -5762,10 +5764,10 @@ dependencies = [
"cw-storage-plus", "cw-storage-plus",
"cw2", "cw2",
"humantime-serde", "humantime-serde",
"log",
"nym-contracts-common", "nym-contracts-common",
"rand_chacha", "rand_chacha",
"schemars", "schemars",
"semver 1.0.23",
"serde", "serde",
"serde-json-wasm", "serde-json-wasm",
"serde_repr", "serde_repr",
@@ -5779,8 +5781,19 @@ dependencies = [
name = "nym-mixnode" name = "nym-mixnode"
version = "1.1.37" version = "1.1.37"
dependencies = [ dependencies = [
"anyhow",
"axum 0.7.7",
"bs58",
"clap 4.5.20",
"colored", "colored",
"cupid",
"dirs",
"futures", "futures",
"humantime-serde",
"lazy_static",
"log",
"nym-bin-common",
"nym-config",
"nym-contracts-common", "nym-contracts-common",
"nym-crypto", "nym-crypto",
"nym-http-api-common", "nym-http-api-common",
@@ -5789,6 +5802,7 @@ dependencies = [
"nym-mixnode-common", "nym-mixnode-common",
"nym-node-http-api", "nym-node-http-api",
"nym-nonexhaustive-delayqueue", "nym-nonexhaustive-delayqueue",
"nym-pemstore",
"nym-sphinx", "nym-sphinx",
"nym-sphinx-params", "nym-sphinx-params",
"nym-sphinx-types", "nym-sphinx-types",
@@ -5796,11 +5810,15 @@ dependencies = [
"nym-topology", "nym-topology",
"nym-types", "nym-types",
"nym-validator-client", "nym-validator-client",
"rand",
"serde",
"serde_json",
"sysinfo",
"thiserror", "thiserror",
"time", "time",
"tokio", "tokio",
"tokio-util", "tokio-util",
"tracing", "toml 0.8.14",
"url", "url",
] ]
@@ -5853,10 +5871,8 @@ dependencies = [
name = "nym-network-defaults" name = "nym-network-defaults"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"cargo_metadata 0.18.1",
"dotenvy", "dotenvy",
"log", "log",
"regex",
"schemars", "schemars",
"serde", "serde",
"url", "url",
@@ -5984,7 +6000,6 @@ dependencies = [
"tokio", "tokio",
"toml 0.8.14", "toml 0.8.14",
"tracing", "tracing",
"tracing-subscriber",
"url", "url",
"zeroize", "zeroize",
] ]
@@ -6234,7 +6249,6 @@ dependencies = [
"nym-socks5-client-core", "nym-socks5-client-core",
"nym-socks5-requests", "nym-socks5-requests",
"nym-sphinx", "nym-sphinx",
"nym-statistics-common",
"nym-task", "nym-task",
"nym-topology", "nym-topology",
"nym-validator-client", "nym-validator-client",
@@ -6576,20 +6590,9 @@ name = "nym-statistics-common"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"futures", "futures",
"log",
"nym-credentials-interface", "nym-credentials-interface",
"nym-crypto",
"nym-metrics",
"nym-sphinx", "nym-sphinx",
"nym-task",
"serde",
"serde_json",
"sha2 0.10.8",
"si-scale",
"sysinfo",
"thiserror",
"time", "time",
"tokio",
] ]
[[package]] [[package]]
@@ -6620,22 +6623,6 @@ dependencies = [
"wasmtimer", "wasmtimer",
] ]
[[package]]
name = "nym-ticketbooks-merkle"
version = "0.1.0"
dependencies = [
"nym-credentials-interface",
"nym-serde-helpers",
"rand",
"rand_chacha",
"rs_merkle",
"schemars",
"serde",
"serde_json",
"sha2 0.10.8",
"time",
]
[[package]] [[package]]
name = "nym-topology" name = "nym-topology"
version = "0.1.0" version = "0.1.0"
@@ -6755,7 +6742,7 @@ dependencies = [
[[package]] [[package]]
name = "nym-validator-rewarder" name = "nym-validator-rewarder"
version = "0.2.0" version = "0.1.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bip39", "bip39",
@@ -6769,21 +6756,16 @@ dependencies = [
"nym-coconut-dkg-common", "nym-coconut-dkg-common",
"nym-compact-ecash", "nym-compact-ecash",
"nym-config", "nym-config",
"nym-contracts-common",
"nym-credentials", "nym-credentials",
"nym-credentials-interface", "nym-credentials-interface",
"nym-crypto", "nym-crypto",
"nym-ecash-time", "nym-ecash-time",
"nym-network-defaults", "nym-network-defaults",
"nym-serde-helpers",
"nym-task", "nym-task",
"nym-ticketbooks-merkle",
"nym-validator-client", "nym-validator-client",
"nyxd-scraper", "nyxd-scraper",
"rand",
"rand_chacha", "rand_chacha",
"serde", "serde",
"serde_json",
"serde_with", "serde_with",
"sha2 0.10.8", "sha2 0.10.8",
"sqlx", "sqlx",
@@ -8171,15 +8153,6 @@ dependencies = [
"syn 1.0.109", "syn 1.0.109",
] ]
[[package]]
name = "rs_merkle"
version = "1.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b241d2e59b74ef9e98d94c78c47623d04c8392abaf82014dfd372a16041128f"
dependencies = [
"sha2 0.10.8",
]
[[package]] [[package]]
name = "rsa" name = "rsa"
version = "0.9.6" version = "0.9.6"
@@ -10710,7 +10683,6 @@ dependencies = [
"quote", "quote",
"regex", "regex",
"syn 2.0.82", "syn 2.0.82",
"uuid",
] ]
[[package]] [[package]]
@@ -10952,7 +10924,6 @@ dependencies = [
"nym-gateway-client", "nym-gateway-client",
"nym-sphinx", "nym-sphinx",
"nym-sphinx-acknowledgements", "nym-sphinx-acknowledgements",
"nym-statistics-common",
"nym-task", "nym-task",
"nym-topology", "nym-topology",
"nym-validator-client", "nym-validator-client",
+1 -4
View File
@@ -90,7 +90,6 @@ members = [
"common/statistics", "common/statistics",
"common/store-cipher", "common/store-cipher",
"common/task", "common/task",
"common/ticketbooks-merkle",
"common/topology", "common/topology",
"common/tun", "common/tun",
"common/types", "common/types",
@@ -99,7 +98,6 @@ members = [
"common/wasm/utils", "common/wasm/utils",
"common/wireguard", "common/wireguard",
"common/wireguard-types", "common/wireguard-types",
# "documentation/autodoc",
"explorer-api", "explorer-api",
"explorer-api/explorer-api-requests", "explorer-api/explorer-api-requests",
"explorer-api/explorer-client", "explorer-api/explorer-client",
@@ -205,7 +203,7 @@ axum-extra = "0.9.4"
base64 = "0.22.1" base64 = "0.22.1"
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? bit-vec = "0.7.0" # can we unify those?
bitvec = "1.0.0" bitvec = "1.0.0"
blake3 = "1.5.4" blake3 = "1.5.4"
bloomfilter = "1.0.14" bloomfilter = "1.0.14"
@@ -278,7 +276,6 @@ 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" maxminddb = "0.23.0"
rs_merkle = "1.4.2"
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"
@@ -102,10 +102,5 @@ average_ack_delay = '{{ debug.acknowledgements.average_ack_delay }}'
[debug.cover_traffic] [debug.cover_traffic]
loop_cover_traffic_average_delay = '{{ debug.cover_traffic.loop_cover_traffic_average_delay }}' loop_cover_traffic_average_delay = '{{ debug.cover_traffic.loop_cover_traffic_average_delay }}'
[debug.stats_reporting]
enabled = {{ debug.stats_reporting.enabled }}
provider_address = '{{ debug.stats_reporting.provider_address }}'
reporting_interval = '{{ debug.stats_reporting.reporting_interval }}'
"#; "#;
-1
View File
@@ -81,7 +81,6 @@ impl From<Init> for OverrideConfig {
nyxd_urls: init_config.common_args.nyxd_urls, nyxd_urls: init_config.common_args.nyxd_urls,
enabled_credentials_mode: init_config.common_args.enabled_credentials_mode, enabled_credentials_mode: init_config.common_args.enabled_credentials_mode,
stats_reporting_address: init_config.common_args.stats_reporting_address,
} }
} }
} }
-7
View File
@@ -13,7 +13,6 @@ use clap::{Parser, Subcommand};
use log::{error, info}; use log::{error, info};
use nym_bin_common::bin_info; use nym_bin_common::bin_info;
use nym_bin_common::completions::{fig_generate, ArgShell}; use nym_bin_common::completions::{fig_generate, ArgShell};
use nym_client::client::Recipient;
use nym_client_core::cli_helpers::CliClient; use nym_client_core::cli_helpers::CliClient;
use nym_client_core::client::base_client::storage::migration_helpers::v1_1_33; use nym_client_core::client::base_client::storage::migration_helpers::v1_1_33;
use nym_config::OptionalSet; use nym_config::OptionalSet;
@@ -105,7 +104,6 @@ pub(crate) struct OverrideConfig {
no_cover: bool, no_cover: bool,
nyxd_urls: Option<Vec<url::Url>>, nyxd_urls: Option<Vec<url::Url>>,
enabled_credentials_mode: Option<bool>, enabled_credentials_mode: Option<bool>,
stats_reporting_address: Option<Recipient>,
} }
pub(crate) async fn execute(args: Cli) -> Result<(), Box<dyn Error + Send + Sync>> { pub(crate) async fn execute(args: Cli) -> Result<(), Box<dyn Error + Send + Sync>> {
@@ -151,11 +149,6 @@ pub(crate) fn override_config(config: Config, args: OverrideConfig) -> Config {
BaseClientConfig::with_disabled_credentials, BaseClientConfig::with_disabled_credentials,
args.enabled_credentials_mode.map(|b| !b), args.enabled_credentials_mode.map(|b| !b),
) )
.with_optional_env_ext(
BaseClientConfig::with_enabled_stats_reporting_address,
args.stats_reporting_address,
nym_network_defaults::var_names::CLIENT_STATS_COLLECTION_PROVIDER,
)
} }
async fn try_upgrade_v1_1_13_config(id: &str) -> Result<bool, ClientError> { async fn try_upgrade_v1_1_13_config(id: &str) -> Result<bool, ClientError> {
-1
View File
@@ -43,7 +43,6 @@ impl From<Run> for OverrideConfig {
no_cover: run_config.common_args.no_cover, no_cover: run_config.common_args.no_cover,
nyxd_urls: run_config.common_args.nyxd_urls, nyxd_urls: run_config.common_args.nyxd_urls,
enabled_credentials_mode: run_config.common_args.enabled_credentials_mode, enabled_credentials_mode: run_config.common_args.enabled_credentials_mode,
stats_reporting_address: run_config.common_args.stats_reporting_address,
} }
} }
} }
-1
View File
@@ -92,7 +92,6 @@ impl From<Init> for OverrideConfig {
nyxd_urls: init_config.common_args.nyxd_urls, nyxd_urls: init_config.common_args.nyxd_urls,
enabled_credentials_mode: init_config.common_args.enabled_credentials_mode, enabled_credentials_mode: init_config.common_args.enabled_credentials_mode,
outfox: false, outfox: false,
stats_reporting_address: init_config.common_args.stats_reporting_address,
} }
} }
} }
-7
View File
@@ -19,7 +19,6 @@ use nym_client_core::client::base_client::storage::migration_helpers::v1_1_33;
use nym_client_core::client::topology_control::geo_aware_provider::CountryGroup; use nym_client_core::client::topology_control::geo_aware_provider::CountryGroup;
use nym_client_core::config::{GroupBy, TopologyStructure}; use nym_client_core::config::{GroupBy, TopologyStructure};
use nym_config::OptionalSet; use nym_config::OptionalSet;
use nym_sphinx::addressing::Recipient;
use nym_sphinx::params::{PacketSize, PacketType}; use nym_sphinx::params::{PacketSize, PacketType};
use std::error::Error; use std::error::Error;
use std::net::IpAddr; use std::net::IpAddr;
@@ -112,7 +111,6 @@ pub(crate) struct OverrideConfig {
nyxd_urls: Option<Vec<url::Url>>, nyxd_urls: Option<Vec<url::Url>>,
enabled_credentials_mode: Option<bool>, enabled_credentials_mode: Option<bool>,
outfox: bool, outfox: bool,
stats_reporting_address: Option<Recipient>,
} }
pub(crate) async fn execute(args: Cli) -> Result<(), Box<dyn Error + Send + Sync>> { pub(crate) async fn execute(args: Cli) -> Result<(), Box<dyn Error + Send + Sync>> {
@@ -198,11 +196,6 @@ pub(crate) fn override_config(config: Config, args: OverrideConfig) -> Config {
BaseClientConfig::with_disabled_credentials, BaseClientConfig::with_disabled_credentials,
args.enabled_credentials_mode.map(|b| !b), args.enabled_credentials_mode.map(|b| !b),
) )
.with_optional_base_env(
BaseClientConfig::with_enabled_stats_reporting_address,
args.stats_reporting_address,
nym_network_defaults::var_names::CLIENT_STATS_COLLECTION_PROVIDER,
)
} }
async fn try_upgrade_v1_1_13_config(id: &str) -> Result<bool, Socks5ClientError> { async fn try_upgrade_v1_1_13_config(id: &str) -> Result<bool, Socks5ClientError> {
-1
View File
@@ -70,7 +70,6 @@ impl From<Run> for OverrideConfig {
nyxd_urls: run_config.common_args.nyxd_urls, nyxd_urls: run_config.common_args.nyxd_urls,
enabled_credentials_mode: run_config.common_args.enabled_credentials_mode, enabled_credentials_mode: run_config.common_args.enabled_credentials_mode,
outfox: run_config.outfox, outfox: run_config.outfox,
stats_reporting_address: run_config.common_args.stats_reporting_address,
} }
} }
} }
-5
View File
@@ -108,9 +108,4 @@ average_ack_delay = '{{ core.debug.acknowledgements.average_ack_delay }}'
[core.debug.cover_traffic] [core.debug.cover_traffic]
loop_cover_traffic_average_delay = '{{ core.debug.cover_traffic.loop_cover_traffic_average_delay }}' loop_cover_traffic_average_delay = '{{ core.debug.cover_traffic.loop_cover_traffic_average_delay }}'
[core.debug.stats_reporting]
enabled = {{ core.debug.stats_reporting.enabled }}
provider_address = '{{ core.debug.stats_reporting.provider_address }}'
reporting_interval = '{{ core.debug.stats_reporting.reporting_interval }}'
"#; "#;
-1
View File
@@ -17,7 +17,6 @@ thiserror = { workspace = true }
nym-credentials-interface = { path = "../credentials-interface" } nym-credentials-interface = { path = "../credentials-interface" }
nym-crypto = { path = "../crypto", features = ["asymmetric"] } nym-crypto = { path = "../crypto", features = ["asymmetric"] }
nym-network-defaults = { path = "../network-defaults" }
nym-service-provider-requests-common = { path = "../service-provider-requests-common" } nym-service-provider-requests-common = { path = "../service-provider-requests-common" }
nym-sphinx = { path = "../nymsphinx" } nym-sphinx = { path = "../nymsphinx" }
nym-wireguard-types = { path = "../wireguard-types" } nym-wireguard-types = { path = "../wireguard-types" }
+2 -3
View File
@@ -4,14 +4,13 @@
pub mod v1; pub mod v1;
pub mod v2; pub mod v2;
pub mod v3; pub mod v3;
pub mod v4;
mod error; mod error;
pub use error::Error; pub use error::Error;
pub use v4 as latest; pub use v3 as latest;
pub const CURRENT_VERSION: u8 = 4; pub const CURRENT_VERSION: u8 = 3;
fn make_bincode_serializer() -> impl bincode::Options { fn make_bincode_serializer() -> impl bincode::Options {
use bincode::Options; use bincode::Options;
@@ -17,11 +17,6 @@ fn generate_random() -> u64 {
rng.next_u64() rng.next_u64()
} }
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct QueryMessage {
pub pub_key: PeerPublicKey,
}
#[derive(Clone, Debug, Serialize, Deserialize)] #[derive(Clone, Debug, Serialize, Deserialize)]
pub struct AuthenticatorRequest { pub struct AuthenticatorRequest {
pub protocol: Protocol, pub protocol: Protocol,
@@ -70,7 +65,7 @@ impl AuthenticatorRequest {
) )
} }
pub fn new_query_request(query_message: QueryMessage, reply_to: Recipient) -> (Self, u64) { pub fn new_query_request(peer_public_key: PeerPublicKey, reply_to: Recipient) -> (Self, u64) {
let request_id = generate_random(); let request_id = generate_random();
( (
Self { Self {
@@ -78,7 +73,7 @@ impl AuthenticatorRequest {
service_provider_type: ServiceProviderType::Authenticator, service_provider_type: ServiceProviderType::Authenticator,
version: VERSION, version: VERSION,
}, },
data: AuthenticatorRequestData::QueryBandwidth(query_message.pub_key), data: AuthenticatorRequestData::QueryBandwidth(peer_public_key),
reply_to, reply_to,
request_id, request_id,
}, },
@@ -9,7 +9,7 @@ impl From<v2::request::AuthenticatorRequest> for v3::request::AuthenticatorReque
fn from(authenticator_request: v2::request::AuthenticatorRequest) -> Self { fn from(authenticator_request: v2::request::AuthenticatorRequest) -> Self {
Self { Self {
protocol: Protocol { protocol: Protocol {
version: 3, version: 2,
service_provider_type: ServiceProviderType::Authenticator, service_provider_type: ServiceProviderType::Authenticator,
}, },
data: authenticator_request.data.into(), data: authenticator_request.data.into(),
@@ -20,11 +20,6 @@ fn generate_random() -> u64 {
rng.next_u64() rng.next_u64()
} }
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct QueryMessage {
pub pub_key: PeerPublicKey,
}
#[derive(Clone, Debug, Serialize, Deserialize)] #[derive(Clone, Debug, Serialize, Deserialize)]
pub struct AuthenticatorRequest { pub struct AuthenticatorRequest {
pub protocol: Protocol, pub protocol: Protocol,
@@ -73,7 +68,7 @@ impl AuthenticatorRequest {
) )
} }
pub fn new_query_request(query_message: QueryMessage, reply_to: Recipient) -> (Self, u64) { pub fn new_query_request(peer_public_key: PeerPublicKey, reply_to: Recipient) -> (Self, u64) {
let request_id = generate_random(); let request_id = generate_random();
( (
Self { Self {
@@ -81,7 +76,7 @@ impl AuthenticatorRequest {
service_provider_type: ServiceProviderType::Authenticator, service_provider_type: ServiceProviderType::Authenticator,
version: VERSION, version: VERSION,
}, },
data: AuthenticatorRequestData::QueryBandwidth(query_message.pub_key), data: AuthenticatorRequestData::QueryBandwidth(peer_public_key),
reply_to, reply_to,
request_id, request_id,
}, },
@@ -1,200 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use nym_service_provider_requests_common::{Protocol, ServiceProviderType};
use crate::{v3, v4};
impl From<v3::request::AuthenticatorRequest> for v4::request::AuthenticatorRequest {
fn from(authenticator_request: v3::request::AuthenticatorRequest) -> Self {
Self {
protocol: Protocol {
version: 4,
service_provider_type: ServiceProviderType::Authenticator,
},
data: authenticator_request.data.into(),
reply_to: authenticator_request.reply_to,
request_id: authenticator_request.request_id,
}
}
}
impl From<v3::request::AuthenticatorRequestData> for v4::request::AuthenticatorRequestData {
fn from(authenticator_request_data: v3::request::AuthenticatorRequestData) -> Self {
match authenticator_request_data {
v3::request::AuthenticatorRequestData::Initial(init_msg) => {
v4::request::AuthenticatorRequestData::Initial(init_msg.into())
}
v3::request::AuthenticatorRequestData::Final(gw_client) => {
v4::request::AuthenticatorRequestData::Final(gw_client.into())
}
v3::request::AuthenticatorRequestData::QueryBandwidth(pub_key) => {
v4::request::AuthenticatorRequestData::QueryBandwidth(pub_key)
}
v3::request::AuthenticatorRequestData::TopUpBandwidth(top_up_message) => {
v4::request::AuthenticatorRequestData::TopUpBandwidth(top_up_message.into())
}
}
}
}
impl From<v3::registration::InitMessage> for v4::registration::InitMessage {
fn from(init_msg: v3::registration::InitMessage) -> Self {
Self {
pub_key: init_msg.pub_key,
}
}
}
impl From<Box<v3::registration::FinalMessage>> for Box<v4::registration::FinalMessage> {
fn from(gw_client: Box<v3::registration::FinalMessage>) -> Self {
Box::new(v4::registration::FinalMessage {
gateway_client: gw_client.gateway_client.into(),
credential: gw_client.credential,
})
}
}
impl From<Box<v3::topup::TopUpMessage>> for Box<v4::topup::TopUpMessage> {
fn from(top_up_message: Box<v3::topup::TopUpMessage>) -> Self {
Box::new(v4::topup::TopUpMessage {
pub_key: top_up_message.pub_key,
credential: top_up_message.credential,
})
}
}
impl From<v3::registration::GatewayClient> for v4::registration::GatewayClient {
fn from(gw_client: v3::registration::GatewayClient) -> Self {
Self {
pub_key: gw_client.pub_key,
private_ips: gw_client.private_ip.into(),
mac: gw_client.mac.into(),
}
}
}
impl From<v4::registration::GatewayClient> for v3::registration::GatewayClient {
fn from(gw_client: v4::registration::GatewayClient) -> Self {
Self {
pub_key: gw_client.pub_key,
private_ip: gw_client.private_ips.ipv4.into(),
mac: gw_client.mac.into(),
}
}
}
impl From<v3::registration::ClientMac> for v4::registration::ClientMac {
fn from(mac: v3::registration::ClientMac) -> Self {
Self::new(mac.to_vec())
}
}
impl From<v4::registration::ClientMac> for v3::registration::ClientMac {
fn from(mac: v4::registration::ClientMac) -> Self {
Self::new(mac.to_vec())
}
}
impl TryFrom<v4::response::AuthenticatorResponse> for v3::response::AuthenticatorResponse {
type Error = crate::Error;
fn try_from(
authenticator_response: v4::response::AuthenticatorResponse,
) -> Result<Self, Self::Error> {
Ok(Self {
data: authenticator_response.data.try_into()?,
reply_to: authenticator_response.reply_to,
protocol: authenticator_response.protocol,
})
}
}
impl TryFrom<v4::response::AuthenticatorResponseData> for v3::response::AuthenticatorResponseData {
type Error = crate::Error;
fn try_from(
authenticator_response_data: v4::response::AuthenticatorResponseData,
) -> Result<Self, Self::Error> {
match authenticator_response_data {
v4::response::AuthenticatorResponseData::PendingRegistration(
pending_registration_response,
) => Ok(
v3::response::AuthenticatorResponseData::PendingRegistration(
pending_registration_response.into(),
),
),
v4::response::AuthenticatorResponseData::Registered(registered_response) => Ok(
v3::response::AuthenticatorResponseData::Registered(registered_response.into()),
),
v4::response::AuthenticatorResponseData::RemainingBandwidth(
remaining_bandwidth_response,
) => Ok(v3::response::AuthenticatorResponseData::RemainingBandwidth(
remaining_bandwidth_response.into(),
)),
v4::response::AuthenticatorResponseData::TopUpBandwidth(_) => {
Err(Self::Error::Conversion(
"a v3 request couldn't produce a v4 only type of response".to_string(),
))
}
}
}
}
impl From<v4::response::PendingRegistrationResponse> for v3::response::PendingRegistrationResponse {
fn from(value: v4::response::PendingRegistrationResponse) -> Self {
Self {
request_id: value.request_id,
reply_to: value.reply_to,
reply: value.reply.into(),
}
}
}
impl From<v4::response::RegisteredResponse> for v3::response::RegisteredResponse {
fn from(value: v4::response::RegisteredResponse) -> Self {
Self {
request_id: value.request_id,
reply_to: value.reply_to,
reply: value.reply.into(),
}
}
}
impl From<v4::response::RemainingBandwidthResponse> for v3::response::RemainingBandwidthResponse {
fn from(value: v4::response::RemainingBandwidthResponse) -> Self {
Self {
request_id: value.request_id,
reply_to: value.reply_to,
reply: value.reply.map(Into::into),
}
}
}
impl From<v4::registration::RegistrationData> for v3::registration::RegistrationData {
fn from(value: v4::registration::RegistrationData) -> Self {
Self {
nonce: value.nonce,
gateway_data: value.gateway_data.into(),
wg_port: value.wg_port,
}
}
}
impl From<v4::registration::RegistredData> for v3::registration::RegistredData {
fn from(value: v4::registration::RegistredData) -> Self {
Self {
pub_key: value.pub_key,
private_ip: value.private_ips.ipv4.into(),
wg_port: value.wg_port,
}
}
}
impl From<v4::registration::RemainingBandwidthData> for v3::registration::RemainingBandwidthData {
fn from(value: v4::registration::RemainingBandwidthData) -> Self {
Self {
available_bandwidth: value.available_bandwidth,
}
}
}
@@ -1,10 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
pub mod conversion;
pub mod registration;
pub mod request;
pub mod response;
pub mod topup;
pub const VERSION: u8 = 4;
@@ -1,281 +0,0 @@
// -2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::error::Error;
use base64::{engine::general_purpose, Engine};
use nym_credentials_interface::CredentialSpendingData;
use nym_network_defaults::constants::{WG_TUN_DEVICE_IP_ADDRESS_V4, WG_TUN_DEVICE_IP_ADDRESS_V6};
use nym_wireguard_types::PeerPublicKey;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
use std::time::SystemTime;
use std::{fmt, ops::Deref, str::FromStr};
#[cfg(feature = "verify")]
use hmac::{Hmac, Mac};
#[cfg(feature = "verify")]
use nym_crypto::asymmetric::encryption::PrivateKey;
#[cfg(feature = "verify")]
use sha2::Sha256;
pub type PendingRegistrations = HashMap<PeerPublicKey, RegistrationData>;
pub type PrivateIPs = HashMap<IpPair, Taken>;
#[cfg(feature = "verify")]
pub type HmacSha256 = Hmac<Sha256>;
pub type Nonce = u64;
pub type Taken = Option<SystemTime>;
pub const BANDWIDTH_CAP_PER_DAY: u64 = 1024 * 1024 * 1024; // 1 GB
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct IpPair {
pub ipv4: Ipv4Addr,
pub ipv6: Ipv6Addr,
}
impl IpPair {
pub fn new(ipv4: Ipv4Addr, ipv6: Ipv6Addr) -> Self {
IpPair { ipv4, ipv6 }
}
}
impl fmt::Display for IpPair {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "({}, {})", self.ipv4, self.ipv6)
}
}
impl From<IpAddr> for IpPair {
fn from(value: IpAddr) -> Self {
let (before_last_byte, last_byte) = match value {
std::net::IpAddr::V4(ipv4_addr) => (ipv4_addr.octets()[2], ipv4_addr.octets()[3]),
std::net::IpAddr::V6(ipv6_addr) => (ipv6_addr.octets()[14], ipv6_addr.octets()[15]),
};
let last_bytes = (before_last_byte as u16) << 8 | last_byte as u16;
let ipv4 = Ipv4Addr::new(
WG_TUN_DEVICE_IP_ADDRESS_V4.octets()[0],
WG_TUN_DEVICE_IP_ADDRESS_V4.octets()[1],
before_last_byte,
last_byte,
);
let ipv6 = Ipv6Addr::new(
WG_TUN_DEVICE_IP_ADDRESS_V6.segments()[0],
WG_TUN_DEVICE_IP_ADDRESS_V6.segments()[1],
WG_TUN_DEVICE_IP_ADDRESS_V6.segments()[2],
WG_TUN_DEVICE_IP_ADDRESS_V6.segments()[3],
WG_TUN_DEVICE_IP_ADDRESS_V6.segments()[4],
WG_TUN_DEVICE_IP_ADDRESS_V6.segments()[5],
WG_TUN_DEVICE_IP_ADDRESS_V6.segments()[6],
last_bytes,
);
IpPair::new(ipv4, ipv6)
}
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct InitMessage {
/// Base64 encoded x25519 public key
pub pub_key: PeerPublicKey,
}
impl InitMessage {
pub fn new(pub_key: PeerPublicKey) -> Self {
InitMessage { pub_key }
}
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct FinalMessage {
/// Gateway client data
pub gateway_client: GatewayClient,
/// Ecash credential
pub credential: Option<CredentialSpendingData>,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct RegistrationData {
pub nonce: u64,
pub gateway_data: GatewayClient,
pub wg_port: u16,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct RegistredData {
pub pub_key: PeerPublicKey,
pub private_ips: IpPair,
pub wg_port: u16,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct RemainingBandwidthData {
pub available_bandwidth: i64,
}
/// Client that wants to register sends its PublicKey bytes mac digest encrypted with a DH shared secret.
/// Gateway/Nym node can then verify pub_key payload using the same process
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct GatewayClient {
/// Base64 encoded x25519 public key
pub pub_key: PeerPublicKey,
/// Assigned private IPs (v4 and v6)
pub private_ips: IpPair,
/// Sha256 hmac on the data (alongside the prior nonce)
pub mac: ClientMac,
}
impl GatewayClient {
#[cfg(feature = "verify")]
pub fn new(
local_secret: &PrivateKey,
remote_public: x25519_dalek::PublicKey,
private_ips: IpPair,
nonce: u64,
) -> Self {
// convert from 1.0 x25519-dalek private key into 2.0 x25519-dalek
#[allow(clippy::expect_used)]
let static_secret = x25519_dalek::StaticSecret::from(local_secret.to_bytes());
let local_public: x25519_dalek::PublicKey = (&static_secret).into();
let dh = static_secret.diffie_hellman(&remote_public);
// TODO: change that to use our nym_crypto::hmac module instead
#[allow(clippy::expect_used)]
let mut mac = HmacSha256::new_from_slice(dh.as_bytes())
.expect("x25519 shared secret is always 32 bytes long");
mac.update(local_public.as_bytes());
mac.update(private_ips.to_string().as_bytes());
mac.update(&nonce.to_le_bytes());
GatewayClient {
pub_key: PeerPublicKey::new(local_public),
private_ips,
mac: ClientMac(mac.finalize().into_bytes().to_vec()),
}
}
// Reusable secret should be gateways Wireguard PK
// Client should perform this step when generating its payload, using its own WG PK
#[cfg(feature = "verify")]
pub fn verify(&self, gateway_key: &PrivateKey, nonce: u64) -> Result<(), Error> {
// convert from 1.0 x25519-dalek private key into 2.0 x25519-dalek
#[allow(clippy::expect_used)]
let static_secret = x25519_dalek::StaticSecret::from(gateway_key.to_bytes());
let dh = static_secret.diffie_hellman(&self.pub_key);
// TODO: change that to use our nym_crypto::hmac module instead
#[allow(clippy::expect_used)]
let mut mac = HmacSha256::new_from_slice(dh.as_bytes())
.expect("x25519 shared secret is always 32 bytes long");
mac.update(self.pub_key.as_bytes());
mac.update(self.private_ips.to_string().as_bytes());
mac.update(&nonce.to_le_bytes());
mac.verify_slice(&self.mac)
.map_err(|source| Error::FailedClientMacVerification {
client: self.pub_key.to_string(),
source,
})
}
pub fn pub_key(&self) -> PeerPublicKey {
self.pub_key
}
}
// TODO: change the inner type into generic array of size HmacSha256::OutputSize
// TODO2: rely on our internal crypto/hmac
#[derive(Debug, Clone)]
pub struct ClientMac(Vec<u8>);
impl fmt::Display for ClientMac {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", general_purpose::STANDARD.encode(&self.0))
}
}
impl ClientMac {
#[allow(dead_code)]
pub fn new(mac: Vec<u8>) -> Self {
ClientMac(mac)
}
}
impl Deref for ClientMac {
type Target = Vec<u8>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl FromStr for ClientMac {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let mac_bytes: Vec<u8> =
general_purpose::STANDARD
.decode(s)
.map_err(|source| Error::MalformedClientMac {
mac: s.to_string(),
source,
})?;
Ok(ClientMac(mac_bytes))
}
}
impl Serialize for ClientMac {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let encoded_key = general_purpose::STANDARD.encode(self.0.clone());
serializer.serialize_str(&encoded_key)
}
}
impl<'de> Deserialize<'de> for ClientMac {
fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
let encoded_key = String::deserialize(deserializer)?;
ClientMac::from_str(&encoded_key).map_err(serde::de::Error::custom)
}
}
#[cfg(test)]
mod tests {
use super::*;
use nym_crypto::asymmetric::encryption;
#[test]
fn create_ip_pair() {
let ipv4: IpAddr = Ipv4Addr::from_str("10.1.10.50").unwrap().into();
let ipv6: IpAddr = Ipv6Addr::from_str("fc01::0a32").unwrap().into();
assert_eq!(IpPair::from(ipv4), IpPair::from(ipv6));
}
#[test]
#[cfg(feature = "verify")]
fn client_request_roundtrip() {
let mut rng = rand::thread_rng();
let gateway_key_pair = encryption::KeyPair::new(&mut rng);
let client_key_pair = encryption::KeyPair::new(&mut rng);
let nonce = 1234567890;
let client = GatewayClient::new(
client_key_pair.private_key(),
x25519_dalek::PublicKey::from(gateway_key_pair.public_key().to_bytes()),
IpPair::new("10.0.0.42".parse().unwrap(), "fc00::42".parse().unwrap()),
nonce,
);
assert!(client.verify(gateway_key_pair.private_key(), nonce).is_ok())
}
}
@@ -1,141 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use super::{
registration::{FinalMessage, InitMessage},
topup::TopUpMessage,
};
use nym_service_provider_requests_common::{Protocol, ServiceProviderType};
use nym_sphinx::addressing::Recipient;
use nym_wireguard_types::PeerPublicKey;
use serde::{Deserialize, Serialize};
use crate::make_bincode_serializer;
use super::VERSION;
fn generate_random() -> u64 {
use rand::RngCore;
let mut rng = rand::rngs::OsRng;
rng.next_u64()
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct QueryMessage {
pub pub_key: PeerPublicKey,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct AuthenticatorRequest {
pub protocol: Protocol,
pub data: AuthenticatorRequestData,
pub reply_to: Recipient,
pub request_id: u64,
}
impl AuthenticatorRequest {
pub fn from_reconstructed_message(
message: &nym_sphinx::receiver::ReconstructedMessage,
) -> Result<Self, bincode::Error> {
use bincode::Options;
make_bincode_serializer().deserialize(&message.message)
}
pub fn new_initial_request(init_message: InitMessage, reply_to: Recipient) -> (Self, u64) {
let request_id = generate_random();
(
Self {
protocol: Protocol {
service_provider_type: ServiceProviderType::Authenticator,
version: VERSION,
},
data: AuthenticatorRequestData::Initial(init_message),
reply_to,
request_id,
},
request_id,
)
}
pub fn new_final_request(final_message: FinalMessage, reply_to: Recipient) -> (Self, u64) {
let request_id = generate_random();
(
Self {
protocol: Protocol {
service_provider_type: ServiceProviderType::Authenticator,
version: VERSION,
},
data: AuthenticatorRequestData::Final(Box::new(final_message)),
reply_to,
request_id,
},
request_id,
)
}
pub fn new_query_request(query_message: QueryMessage, reply_to: Recipient) -> (Self, u64) {
let request_id = generate_random();
(
Self {
protocol: Protocol {
service_provider_type: ServiceProviderType::Authenticator,
version: VERSION,
},
data: AuthenticatorRequestData::QueryBandwidth(query_message.pub_key),
reply_to,
request_id,
},
request_id,
)
}
pub fn new_topup_request(top_up_message: TopUpMessage, reply_to: Recipient) -> (Self, u64) {
let request_id = generate_random();
(
Self {
protocol: Protocol {
service_provider_type: ServiceProviderType::Authenticator,
version: VERSION,
},
data: AuthenticatorRequestData::TopUpBandwidth(Box::new(top_up_message)),
reply_to,
request_id,
},
request_id,
)
}
pub fn to_bytes(&self) -> Result<Vec<u8>, bincode::Error> {
use bincode::Options;
make_bincode_serializer().serialize(self)
}
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub enum AuthenticatorRequestData {
Initial(InitMessage),
Final(Box<FinalMessage>),
QueryBandwidth(PeerPublicKey),
TopUpBandwidth(Box<TopUpMessage>),
}
#[cfg(test)]
mod tests {
use super::*;
use std::str::FromStr;
#[test]
fn check_first_bytes_protocol() {
let version = 4;
let data = AuthenticatorRequest {
protocol: Protocol { version, service_provider_type: ServiceProviderType::Authenticator },
data: AuthenticatorRequestData::Initial(InitMessage::new(
PeerPublicKey::from_str("yvNUDpT5l7W/xDhiu6HkqTHDQwbs/B3J5UrLmORl1EQ=").unwrap(),
)),
reply_to: Recipient::try_from_base58_string("D1rrpsysCGCYXy9saP8y3kmNpGtJZUXN9SvFoUcqAsM9.9Ssso1ea5NfkbMASdiseDSjTN1fSWda5SgEVjdSN4CvV@GJqd3ZxpXWSNxTfx7B1pPtswpetH4LnJdFeLeuY5KUuN").unwrap(),
request_id: 1,
};
let bytes = *data.to_bytes().unwrap().first_chunk::<2>().unwrap();
assert_eq!(bytes, [version, ServiceProviderType::Authenticator as u8]);
}
}
@@ -1,157 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use super::registration::{RegistrationData, RegistredData, RemainingBandwidthData};
use nym_service_provider_requests_common::{Protocol, ServiceProviderType};
use nym_sphinx::addressing::Recipient;
use serde::{Deserialize, Serialize};
use crate::make_bincode_serializer;
use super::VERSION;
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct AuthenticatorResponse {
pub protocol: Protocol,
pub data: AuthenticatorResponseData,
pub reply_to: Recipient,
}
impl AuthenticatorResponse {
pub fn new_pending_registration_success(
registration_data: RegistrationData,
request_id: u64,
reply_to: Recipient,
) -> Self {
Self {
protocol: Protocol {
service_provider_type: ServiceProviderType::Authenticator,
version: VERSION,
},
data: AuthenticatorResponseData::PendingRegistration(PendingRegistrationResponse {
reply: registration_data,
reply_to,
request_id,
}),
reply_to,
}
}
pub fn new_registered(
registred_data: RegistredData,
reply_to: Recipient,
request_id: u64,
) -> Self {
Self {
protocol: Protocol {
service_provider_type: ServiceProviderType::Authenticator,
version: VERSION,
},
data: AuthenticatorResponseData::Registered(RegisteredResponse {
reply: registred_data,
reply_to,
request_id,
}),
reply_to,
}
}
pub fn new_remaining_bandwidth(
remaining_bandwidth_data: Option<RemainingBandwidthData>,
reply_to: Recipient,
request_id: u64,
) -> Self {
Self {
protocol: Protocol {
service_provider_type: ServiceProviderType::Authenticator,
version: VERSION,
},
data: AuthenticatorResponseData::RemainingBandwidth(RemainingBandwidthResponse {
reply: remaining_bandwidth_data,
reply_to,
request_id,
}),
reply_to,
}
}
pub fn new_topup_bandwidth(
remaining_bandwidth_data: RemainingBandwidthData,
reply_to: Recipient,
request_id: u64,
) -> Self {
Self {
protocol: Protocol {
service_provider_type: ServiceProviderType::Authenticator,
version: VERSION,
},
data: AuthenticatorResponseData::TopUpBandwidth(TopUpBandwidthResponse {
reply: remaining_bandwidth_data,
reply_to,
request_id,
}),
reply_to,
}
}
pub fn recipient(&self) -> Recipient {
self.reply_to
}
pub fn to_bytes(&self) -> Result<Vec<u8>, bincode::Error> {
use bincode::Options;
make_bincode_serializer().serialize(self)
}
pub fn from_reconstructed_message(
message: &nym_sphinx::receiver::ReconstructedMessage,
) -> Result<Self, bincode::Error> {
use bincode::Options;
make_bincode_serializer().deserialize(&message.message)
}
pub fn id(&self) -> Option<u64> {
match &self.data {
AuthenticatorResponseData::PendingRegistration(response) => Some(response.request_id),
AuthenticatorResponseData::Registered(response) => Some(response.request_id),
AuthenticatorResponseData::RemainingBandwidth(response) => Some(response.request_id),
AuthenticatorResponseData::TopUpBandwidth(response) => Some(response.request_id),
}
}
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub enum AuthenticatorResponseData {
PendingRegistration(PendingRegistrationResponse),
Registered(RegisteredResponse),
RemainingBandwidth(RemainingBandwidthResponse),
TopUpBandwidth(TopUpBandwidthResponse),
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct PendingRegistrationResponse {
pub request_id: u64,
pub reply_to: Recipient,
pub reply: RegistrationData,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct RegisteredResponse {
pub request_id: u64,
pub reply_to: Recipient,
pub reply: RegistredData,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct RemainingBandwidthResponse {
pub request_id: u64,
pub reply_to: Recipient,
pub reply: Option<RemainingBandwidthData>,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct TopUpBandwidthResponse {
pub request_id: u64,
pub reply_to: Recipient,
pub reply: RemainingBandwidthData,
}
@@ -1,15 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use nym_credentials_interface::CredentialSpendingData;
use nym_wireguard_types::PeerPublicKey;
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct TopUpMessage {
/// Base64 encoded x25519 public key
pub pub_key: PeerPublicKey,
/// Ecash credential
pub credential: CredentialSpendingData,
}
+2 -3
View File
@@ -14,15 +14,14 @@ thiserror = { workspace = true }
url = { workspace = true } url = { workspace = true }
zeroize = { workspace = true } zeroize = { workspace = true }
nym-ecash-time = { path = "../ecash-time" }
nym-credential-storage = { path = "../credential-storage" } nym-credential-storage = { path = "../credential-storage" }
nym-credentials = { path = "../credentials" } nym-credentials = { path = "../credentials" }
nym-credentials-interface = { path = "../credentials-interface" } nym-credentials-interface = { path = "../credentials-interface" }
nym-crypto = { path = "../crypto", features = ["rand", "asymmetric", "stream_cipher", "aes", "hashing"] } nym-crypto = { path = "../crypto", features = ["rand", "asymmetric", "stream_cipher", "aes", "hashing"] }
nym-ecash-contract-common = { path = "../cosmwasm-smart-contracts/ecash-contract" }
nym-ecash-time = { path = "../ecash-time" }
nym-network-defaults = { path = "../network-defaults" } nym-network-defaults = { path = "../network-defaults" }
nym-task = { path = "../task" }
nym-validator-client = { path = "../client-libs/validator-client", default-features = false } nym-validator-client = { path = "../client-libs/validator-client", default-features = false }
nym-ecash-contract-common = { path = "../cosmwasm-smart-contracts/ecash-contract" }
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.nym-validator-client] [target."cfg(not(target_arch = \"wasm32\"))".dependencies.nym-validator-client]
path = "../client-libs/validator-client" path = "../client-libs/validator-client"
+6 -18
View File
@@ -1,25 +1,13 @@
// 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
#[derive(Debug)] // See other comments for other TaskStatus message enumds about abusing the Error trait when we
// should have a new trait for TaskStatus messages
#[derive(Debug, thiserror::Error)]
pub enum BandwidthStatusMessage { pub enum BandwidthStatusMessage {
#[error("remaining bandwidth: {0}")]
RemainingBandwidth(i64), RemainingBandwidth(i64),
#[error("no bandwidth left")]
NoBandwidth, NoBandwidth,
} }
impl std::fmt::Display for BandwidthStatusMessage {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
BandwidthStatusMessage::RemainingBandwidth(b) => {
write!(f, "remaining bandwidth: {}", b)
}
BandwidthStatusMessage::NoBandwidth => write!(f, "no bandwidth left"),
}
}
}
impl nym_task::TaskStatusEvent for BandwidthStatusMessage {
fn as_any(&self) -> &dyn std::any::Any {
self
}
}
-1
View File
@@ -43,7 +43,6 @@ nym-gateway-requests = { path = "../gateway-requests" }
nym-metrics = { path = "../nym-metrics" } nym-metrics = { path = "../nym-metrics" }
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-pemstore = { path = "../pemstore" } nym-pemstore = { path = "../pemstore" }
nym-topology = { path = "../topology", features = ["serializable"] } nym-topology = { path = "../topology", features = ["serializable"] }
nym-validator-client = { path = "../client-libs/validator-client", default-features = false } nym-validator-client = { path = "../client-libs/validator-client", default-features = false }
+1 -1
View File
@@ -23,4 +23,4 @@ nym-sphinx-addressing = { path = "../../nymsphinx/addressing" }
[features] [features]
disk-persistence = ["nym-pemstore"] disk-persistence = ["nym-pemstore"]
@@ -2,7 +2,6 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
use nym_config::defaults::NymNetworkDetails; use nym_config::defaults::NymNetworkDetails;
use nym_config::serde_helpers::{de_maybe_stringified, ser_maybe_stringified};
use nym_sphinx_addressing::Recipient; use nym_sphinx_addressing::Recipient;
use nym_sphinx_params::{PacketSize, PacketType}; use nym_sphinx_params::{PacketSize, PacketType};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@@ -62,11 +61,6 @@ const DEFAULT_MAXIMUM_REPLY_SURB_AGE: Duration = Duration::from_secs(12 * 60 * 6
// 24 hours // 24 hours
const DEFAULT_MAXIMUM_REPLY_KEY_AGE: Duration = Duration::from_secs(24 * 60 * 60); const DEFAULT_MAXIMUM_REPLY_KEY_AGE: Duration = Duration::from_secs(24 * 60 * 60);
// stats reporting related
/// Time interval between reporting statistics to the given provider if it exist
const STATS_REPORT_INTERVAL_SECS: Duration = Duration::from_secs(300);
use crate::error::InvalidTrafficModeFailure; use crate::error::InvalidTrafficModeFailure;
pub use nym_country_group::CountryGroup; pub use nym_country_group::CountryGroup;
@@ -139,12 +133,6 @@ impl Config {
self self
} }
pub fn with_enabled_stats_reporting_address(mut self, address: Recipient) -> Self {
self.debug.stats_reporting.provider_address = Some(address);
self.debug.stats_reporting.enabled = true; //since we are overriding the address, we assume the reporting should be enabled
self
}
// TODO: this should be refactored properly // TODO: this should be refactored properly
// as of 12.09.23 the below is true (not sure how this comment will rot in the future) // as of 12.09.23 the below is true (not sure how this comment will rot in the future)
// medium_toggle: // medium_toggle:
@@ -643,34 +631,6 @@ impl Default for ReplySurbs {
} }
} }
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
#[serde(default, deny_unknown_fields)]
pub struct StatsReporting {
/// Is stats reporting enabled
pub enabled: bool,
/// Address of the stats collector. If this is none, no reporting will happen, regardless of `enabled`
#[serde(
serialize_with = "ser_maybe_stringified",
deserialize_with = "de_maybe_stringified"
)]
pub provider_address: Option<Recipient>,
/// With what frequence will statistics be sent
#[serde(with = "humantime_serde")]
pub reporting_interval: Duration,
}
impl Default for StatsReporting {
fn default() -> Self {
StatsReporting {
enabled: true,
provider_address: None,
reporting_interval: STATS_REPORT_INTERVAL_SECS,
}
}
}
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)] #[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
#[serde(default, deny_unknown_fields)] #[serde(default, deny_unknown_fields)]
pub struct DebugConfig { pub struct DebugConfig {
@@ -691,9 +651,6 @@ 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.
pub stats_reporting: StatsReporting,
} }
impl DebugConfig { impl DebugConfig {
@@ -715,7 +672,6 @@ impl Default for DebugConfig {
acknowledgements: Default::default(), acknowledgements: Default::default(),
topology: Default::default(), topology: Default::default(),
reply_surbs: Default::default(), reply_surbs: Default::default(),
stats_reporting: Default::default(),
} }
} }
} }
@@ -181,7 +181,6 @@ impl From<ConfigV5> for Config {
maximum_reply_key_age: value.debug.reply_surbs.maximum_reply_key_age, maximum_reply_key_age: value.debug.reply_surbs.maximum_reply_key_age,
surb_mix_hops: value.debug.reply_surbs.surb_mix_hops, surb_mix_hops: value.debug.reply_surbs.surb_mix_hops,
}, },
stats_reporting: Default::default(),
}, },
} }
} }
@@ -15,7 +15,6 @@ use crate::{
use log::info; use log::info;
use nym_client_core_gateways_storage::GatewayDetails; use nym_client_core_gateways_storage::GatewayDetails;
use nym_crypto::asymmetric::identity; use nym_crypto::asymmetric::identity;
use nym_sphinx::addressing::Recipient;
use nym_topology::NymTopology; use nym_topology::NymTopology;
use nym_validator_client::UserAgent; use nym_validator_client::UserAgent;
use rand::rngs::OsRng; use rand::rngs::OsRng;
@@ -89,10 +88,6 @@ pub struct CommonClientInitArgs {
/// Disable loop cover traffic and the Poisson rate limiter (for debugging only) /// Disable loop cover traffic and the Poisson rate limiter (for debugging only)
#[cfg_attr(feature = "cli", clap(long, hide = true))] #[cfg_attr(feature = "cli", clap(long, hide = true))]
pub no_cover: bool, pub no_cover: bool,
/// Sets the address to report statistics
#[cfg_attr(feature = "cli", clap(long, hide = true))]
pub stats_reporting_address: Option<Recipient>,
} }
pub struct InitResultsWithConfig<T> { pub struct InitResultsWithConfig<T> {
@@ -2,7 +2,6 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
use nym_crypto::asymmetric::identity; use nym_crypto::asymmetric::identity;
use nym_sphinx::addressing::Recipient;
use std::path::PathBuf; use std::path::PathBuf;
#[cfg_attr(feature = "cli", derive(clap::Args))] #[cfg_attr(feature = "cli", derive(clap::Args))]
@@ -57,8 +56,4 @@ pub struct CommonClientRunArgs {
// has defined the conflict on that field itself // has defined the conflict on that field itself
#[cfg_attr(feature = "cli", clap(long, hide = true))] #[cfg_attr(feature = "cli", clap(long, hide = true))]
pub no_cover: bool, pub no_cover: bool,
/// Sets the address to report statistics
#[cfg_attr(feature = "cli", clap(long, hide = true))]
pub stats_reporting_address: Option<Recipient>,
} }
@@ -1,8 +1,8 @@
// 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
use super::packet_statistics_control::PacketStatisticsReporter;
use super::received_buffer::ReceivedBufferMessage; use super::received_buffer::ReceivedBufferMessage;
use super::statistics_control::StatisticsControl;
use super::topology_control::geo_aware_provider::GeoAwareTopologyProvider; use super::topology_control::geo_aware_provider::GeoAwareTopologyProvider;
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;
@@ -12,6 +12,7 @@ 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};
use crate::client::packet_statistics_control::PacketStatisticsControl;
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::{
@@ -48,8 +49,6 @@ use nym_sphinx::addressing::clients::Recipient;
use nym_sphinx::addressing::nodes::NodeIdentity; use nym_sphinx::addressing::nodes::NodeIdentity;
use nym_sphinx::params::PacketType; use nym_sphinx::params::PacketType;
use nym_sphinx::receiver::{ReconstructedMessage, SphinxMessageReceiver}; use nym_sphinx::receiver::{ReconstructedMessage, SphinxMessageReceiver};
use nym_statistics_common::clients::ClientStatsSender;
use nym_statistics_common::generate_client_stats_id;
use nym_task::connections::{ConnectionCommandReceiver, ConnectionCommandSender, LaneQueueLengths}; use nym_task::connections::{ConnectionCommandReceiver, ConnectionCommandSender, LaneQueueLengths};
use nym_task::{TaskClient, TaskHandle}; use nym_task::{TaskClient, TaskHandle};
use nym_topology::provider_trait::TopologyProvider; use nym_topology::provider_trait::TopologyProvider;
@@ -60,7 +59,6 @@ use std::fmt::Debug;
use std::os::raw::c_int as RawFd; use std::os::raw::c_int as RawFd;
use std::path::Path; use std::path::Path;
use std::sync::Arc; use std::sync::Arc;
use tokio::sync::mpsc::Sender;
use url::Url; use url::Url;
#[cfg(all( #[cfg(all(
@@ -275,7 +273,7 @@ where
self_address: Recipient, self_address: Recipient,
topology_accessor: TopologyAccessor, topology_accessor: TopologyAccessor,
mix_tx: BatchMixMessageSender, mix_tx: BatchMixMessageSender,
stats_tx: ClientStatsSender, stats_tx: PacketStatisticsReporter,
shutdown: TaskClient, shutdown: TaskClient,
) { ) {
info!("Starting loop cover traffic stream..."); info!("Starting loop cover traffic stream...");
@@ -308,7 +306,7 @@ where
client_connection_rx: ConnectionCommandReceiver, client_connection_rx: ConnectionCommandReceiver,
shutdown: TaskClient, shutdown: TaskClient,
packet_type: PacketType, packet_type: PacketType,
stats_tx: ClientStatsSender, stats_tx: PacketStatisticsReporter,
) { ) {
info!("Starting real traffic stream..."); info!("Starting real traffic stream...");
@@ -337,7 +335,7 @@ where
reply_key_storage: SentReplyKeys, reply_key_storage: SentReplyKeys,
reply_controller_sender: ReplyControllerSender, reply_controller_sender: ReplyControllerSender,
shutdown: TaskClient, shutdown: TaskClient,
metrics_reporter: ClientStatsSender, packet_statistics_control: PacketStatisticsReporter,
) { ) {
info!("Starting received messages buffer controller..."); info!("Starting received messages buffer controller...");
let controller: ReceivedMessagesBufferController<SphinxMessageReceiver> = let controller: ReceivedMessagesBufferController<SphinxMessageReceiver> =
@@ -347,7 +345,7 @@ where
mixnet_receiver, mixnet_receiver,
reply_key_storage, reply_key_storage,
reply_controller_sender, reply_controller_sender,
metrics_reporter, packet_statistics_control,
); );
controller.start_with_shutdown(shutdown) controller.start_with_shutdown(shutdown)
} }
@@ -358,7 +356,6 @@ where
bandwidth_controller: Option<BandwidthController<C, S::CredentialStore>>, bandwidth_controller: Option<BandwidthController<C, S::CredentialStore>>,
details_store: &S::GatewaysDetailsStore, details_store: &S::GatewaysDetailsStore,
packet_router: PacketRouter, packet_router: PacketRouter,
stats_reporter: ClientStatsSender,
shutdown: TaskClient, shutdown: TaskClient,
) -> Result<GatewayClient<C, S::CredentialStore>, ClientCoreError> ) -> Result<GatewayClient<C, S::CredentialStore>, ClientCoreError>
where where
@@ -374,12 +371,7 @@ where
let mut gateway_client = let mut gateway_client =
if let Some(existing_client) = initialisation_result.authenticated_ephemeral_client { if let Some(existing_client) = initialisation_result.authenticated_ephemeral_client {
existing_client.upgrade( existing_client.upgrade(packet_router, bandwidth_controller, shutdown)
packet_router,
bandwidth_controller,
stats_reporter,
shutdown,
)
} else { } else {
let cfg = GatewayConfig::new( let cfg = GatewayConfig::new(
details.gateway_id, details.gateway_id,
@@ -400,7 +392,6 @@ where
Some(details.shared_key), Some(details.shared_key),
packet_router, packet_router,
bandwidth_controller, bandwidth_controller,
stats_reporter,
shutdown, shutdown,
) )
}; };
@@ -453,7 +444,6 @@ where
Ok(gateway_client) Ok(gateway_client)
} }
#[allow(clippy::too_many_arguments)]
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,
@@ -461,7 +451,6 @@ where
bandwidth_controller: Option<BandwidthController<C, S::CredentialStore>>, bandwidth_controller: Option<BandwidthController<C, S::CredentialStore>>,
details_store: &S::GatewaysDetailsStore, details_store: &S::GatewaysDetailsStore,
packet_router: PacketRouter, packet_router: PacketRouter,
stats_reporter: ClientStatsSender,
mut shutdown: TaskClient, mut shutdown: TaskClient,
) -> Result<Box<dyn GatewayTransceiver + Send>, ClientCoreError> ) -> Result<Box<dyn GatewayTransceiver + Send>, ClientCoreError>
where where
@@ -492,7 +481,6 @@ where
bandwidth_controller, bandwidth_controller,
details_store, details_store,
packet_router, packet_router,
stats_reporter,
shutdown, shutdown,
) )
.await?; .await?;
@@ -598,23 +586,11 @@ where
Ok(()) Ok(())
} }
fn start_statistics_control( fn start_packet_statistics_control(shutdown: TaskClient) -> PacketStatisticsReporter {
config: &Config, info!("Starting packet statistics control...");
user_agent: Option<UserAgent>, let (packet_statistics_control, packet_stats_reporter) = PacketStatisticsControl::new();
client_stats_id: String, packet_statistics_control.start_with_shutdown(shutdown);
input_sender: Sender<InputMessage>, packet_stats_reporter
shutdown: TaskClient,
) -> ClientStatsSender {
info!("Starting statistics control...");
StatisticsControl::create_and_start_with_shutdown(
config.debug.stats_reporting,
user_agent
.map(|u| u.application)
.unwrap_or("unknown".to_string()),
client_stats_id,
input_sender.clone(),
shutdown.with_suffix("controller"),
)
} }
fn start_mix_traffic_controller( fn start_mix_traffic_controller(
@@ -744,14 +720,6 @@ where
self.user_agent.clone(), self.user_agent.clone(),
); );
let stats_reporter = Self::start_statistics_control(
self.config,
self.user_agent.clone(),
generate_client_stats_id(*self_address.identity()),
input_sender.clone(),
shutdown.fork("statistics_control"),
);
// 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
Self::start_topology_refresher( Self::start_topology_refresher(
topology_provider, topology_provider,
@@ -763,6 +731,9 @@ where
) )
.await?; .await?;
let packet_stats_reporter =
Self::start_packet_statistics_control(shutdown.fork("packet_statistics_control"));
let gateway_packet_router = PacketRouter::new( let gateway_packet_router = PacketRouter::new(
ack_sender, ack_sender,
mixnet_messages_sender, mixnet_messages_sender,
@@ -776,7 +747,6 @@ where
bandwidth_controller, bandwidth_controller,
&details_store, &details_store,
gateway_packet_router, gateway_packet_router,
stats_reporter.clone(),
shutdown.fork("gateway_transceiver"), shutdown.fork("gateway_transceiver"),
) )
.await?; .await?;
@@ -795,7 +765,7 @@ where
reply_storage.key_storage(), reply_storage.key_storage(),
reply_controller_sender.clone(), reply_controller_sender.clone(),
shutdown.fork("received_messages_buffer"), shutdown.fork("received_messages_buffer"),
stats_reporter.clone(), packet_stats_reporter.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
@@ -834,7 +804,7 @@ where
client_connection_rx, client_connection_rx,
shutdown.fork("real_traffic_controller"), shutdown.fork("real_traffic_controller"),
self.config.debug.traffic.packet_type, self.config.debug.traffic.packet_type,
stats_reporter.clone(), packet_stats_reporter.clone(),
); );
if !self if !self
@@ -849,7 +819,7 @@ where
self_address, self_address,
shared_topology_accessor.clone(), shared_topology_accessor.clone(),
message_sender, message_sender,
stats_reporter.clone(), packet_stats_reporter,
shutdown.fork("cover_traffic_stream"), shutdown.fork("cover_traffic_stream"),
); );
} }
@@ -877,7 +847,6 @@ where
topology_accessor: shared_topology_accessor, topology_accessor: shared_topology_accessor,
gateway_connection: GatewayConnection { gateway_ws_fd }, gateway_connection: GatewayConnection { gateway_ws_fd },
}, },
stats_reporter,
task_handle: shutdown, task_handle: shutdown,
}) })
} }
@@ -889,7 +858,6 @@ pub struct BaseClient {
pub client_input: ClientInputStatus, pub client_input: ClientInputStatus,
pub client_output: ClientOutputStatus, pub client_output: ClientOutputStatus,
pub client_state: ClientState, pub client_state: ClientState,
pub stats_reporter: ClientStatsSender,
pub task_handle: TaskHandle, pub task_handle: TaskHandle,
} }
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
use crate::client::mix_traffic::BatchMixMessageSender; use crate::client::mix_traffic::BatchMixMessageSender;
use crate::client::packet_statistics_control::{PacketStatisticsEvent, PacketStatisticsReporter};
use crate::client::topology_control::TopologyAccessor; use crate::client::topology_control::TopologyAccessor;
use crate::{config, spawn_future}; use crate::{config, spawn_future};
use futures::task::{Context, Poll}; use futures::task::{Context, Poll};
@@ -12,7 +13,6 @@ use nym_sphinx::addressing::clients::Recipient;
use nym_sphinx::cover::generate_loop_cover_packet; use nym_sphinx::cover::generate_loop_cover_packet;
use nym_sphinx::params::{PacketSize, PacketType}; use nym_sphinx::params::{PacketSize, PacketType};
use nym_sphinx::utils::sample_poisson_duration; use nym_sphinx::utils::sample_poisson_duration;
use nym_statistics_common::clients::{packet_statistics::PacketStatisticsEvent, ClientStatsSender};
use rand::{rngs::OsRng, CryptoRng, Rng}; use rand::{rngs::OsRng, CryptoRng, Rng};
use std::pin::Pin; use std::pin::Pin;
use std::sync::Arc; use std::sync::Arc;
@@ -63,7 +63,7 @@ where
packet_type: PacketType, packet_type: PacketType,
stats_tx: ClientStatsSender, stats_tx: PacketStatisticsReporter,
} }
impl<R> Stream for LoopCoverTrafficStream<R> impl<R> Stream for LoopCoverTrafficStream<R>
@@ -109,7 +109,7 @@ impl LoopCoverTrafficStream<OsRng> {
topology_access: TopologyAccessor, topology_access: TopologyAccessor,
traffic_config: config::Traffic, traffic_config: config::Traffic,
cover_config: config::CoverTraffic, cover_config: config::CoverTraffic,
stats_tx: ClientStatsSender, stats_tx: PacketStatisticsReporter,
) -> Self { ) -> Self {
let rng = OsRng; let rng = OsRng;
@@ -198,9 +198,9 @@ impl LoopCoverTrafficStream<OsRng> {
} }
} }
} else { } else {
self.stats_tx.report( self.stats_tx.report(PacketStatisticsEvent::CoverPacketSent(
PacketStatisticsEvent::CoverPacketSent(cover_traffic_packet_size.size()).into(), cover_traffic_packet_size.size(),
); ));
} }
// TODO: I'm not entirely sure whether this is really required, because I'm not 100% // TODO: I'm not entirely sure whether this is really required, because I'm not 100%
+1 -1
View File
@@ -7,9 +7,9 @@ pub(crate) mod helpers;
pub mod inbound_messages; pub mod inbound_messages;
pub mod key_manager; pub mod key_manager;
pub mod mix_traffic; pub mod mix_traffic;
pub(crate) mod packet_statistics_control;
pub mod real_messages_control; pub mod real_messages_control;
pub mod received_buffer; pub mod received_buffer;
pub mod replies; pub mod replies;
pub mod statistics_control;
pub mod topology_control; pub mod topology_control;
pub(crate) mod transmission_buffer; pub(crate) mod transmission_buffer;
@@ -1,25 +1,48 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use super::ClientStatsEvents;
use core::fmt;
use std::{ use std::{
collections::VecDeque, collections::VecDeque,
time::{Duration, Instant}, time::{Duration, Instant},
}; };
use nym_metrics::{inc, inc_by}; use nym_metrics::{inc, inc_by};
use serde::{Deserialize, Serialize};
use si_scale::helpers::bibytes2; use si_scale::helpers::bibytes2;
// Metrics server
use futures::future::{FusedFuture, OptionFuture};
use futures::FutureExt;
#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
use http_body_util::Full;
#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
use hyper::body::Bytes;
#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
use hyper::server::conn::http1;
#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
use hyper::service::service_fn;
#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
use hyper::{Request, Response};
#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
use hyper_util::rt::TokioIo;
#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
use std::convert::Infallible;
#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
#[cfg(feature = "metrics-server")]
use std::net::SocketAddr;
#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
use tokio::net::TcpListener;
use crate::spawn_future;
// Time interval between reporting packet statistics
const PACKET_REPORT_INTERVAL_SECS: u64 = 2;
// Interval for taking snapshots of the packet statistics
const SNAPSHOT_INTERVAL_MS: u64 = 500;
// When computing rates, we include snapshots that are up to this old. We set it to some odd number // When computing rates, we include snapshots that are up to this old. We set it to some odd number
// a tad larger than an integer number of snapshot intervals, so that we don't have to worry about // a tad larger than an integer number of snapshot intervals, so that we don't have to worry about
// threshold effects. // threshold effects.
// Also, set it larger than the packet report interval so that we don't miss notable singular events // Also, set it larger than the packet report interval so that we don't miss notable singular events
const RECORDING_WINDOW_MS: u64 = 2300; const RECORDING_WINDOW_MS: u64 = 2300;
#[derive(Default, Debug, Clone, Serialize, Deserialize)] #[derive(Default, Debug, Clone)]
pub(crate) struct PacketStatistics { struct PacketStatistics {
// Sent // Sent
real_packets_sent: u64, real_packets_sent: u64,
real_packets_sent_size: usize, real_packets_sent_size: usize,
@@ -49,7 +72,7 @@ pub(crate) struct PacketStatistics {
} }
impl PacketStatistics { impl PacketStatistics {
fn handle(&mut self, event: PacketStatisticsEvent) { fn handle_event(&mut self, event: PacketStatisticsEvent) {
match event { match event {
PacketStatisticsEvent::RealPacketSent(packet_size) => { PacketStatisticsEvent::RealPacketSent(packet_size) => {
self.real_packets_sent += 1; self.real_packets_sent += 1;
@@ -166,64 +189,29 @@ impl std::ops::Sub for PacketStatistics {
} }
} }
pub struct MixnetBandwidthStatisticsEvent {
pub rates: PacketRates,
}
impl MixnetBandwidthStatisticsEvent {
pub fn new(rates: PacketRates) -> Self {
Self { rates }
}
}
impl nym_task::TaskStatusEvent for MixnetBandwidthStatisticsEvent {
fn as_any(&self) -> &dyn std::any::Any {
self
}
}
impl fmt::Display for MixnetBandwidthStatisticsEvent {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.rates.summary())
}
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct PacketRates { struct PacketRates {
pub real_packets_sent: f64, real_packets_sent: f64,
pub real_packets_sent_size: f64, real_packets_sent_size: f64,
pub cover_packets_sent: f64, cover_packets_sent: f64,
pub cover_packets_sent_size: f64, cover_packets_sent_size: f64,
pub real_packets_received: f64, real_packets_received: f64,
pub real_packets_received_size: f64, real_packets_received_size: f64,
pub cover_packets_received: f64, cover_packets_received: f64,
pub cover_packets_received_size: f64, cover_packets_received_size: f64,
pub total_acks_received: f64, total_acks_received: f64,
pub total_acks_received_size: f64, total_acks_received_size: f64,
pub real_acks_received: f64, real_acks_received: f64,
pub real_acks_received_size: f64, real_acks_received_size: f64,
pub cover_acks_received: f64, cover_acks_received: f64,
pub cover_acks_received_size: f64, cover_acks_received_size: f64,
pub real_packets_queued: f64, real_packets_queued: f64,
pub retransmissions_queued: f64, retransmissions_queued: f64,
pub reply_surbs_queued: f64, reply_surbs_queued: f64,
pub additional_reply_surbs_queued: f64, additional_reply_surbs_queued: f64,
}
impl fmt::Display for PacketRates {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"down: {}/s, up: {}/s (cover down: {}/s, cover up: {}/s)",
bibytes2(self.real_packets_received_size),
bibytes2(self.real_packets_sent_size),
bibytes2(self.cover_packets_received_size),
bibytes2(self.cover_packets_sent_size),
)
}
} }
impl From<PacketStatistics> for PacketRates { impl From<PacketStatistics> for PacketRates {
@@ -342,46 +330,56 @@ impl PacketRates {
} }
} }
/// Event Space used for counting the Packet types used in a connection.
#[derive(Debug)] #[derive(Debug)]
pub enum PacketStatisticsEvent { pub(crate) enum PacketStatisticsEvent {
/// The real packets sent. Recall that acks are sent by the gateway, so it's not included here. // The real packets sent. Recall that acks are sent by the gateway, so it's not included here.
RealPacketSent(usize), RealPacketSent(usize),
/// The cover packets sent // The cover packets sent
CoverPacketSent(usize), CoverPacketSent(usize),
/// Real packets received // Real packets received
RealPacketReceived(usize), RealPacketReceived(usize),
/// Cover packets received // Cover packets received
CoverPacketReceived(usize), CoverPacketReceived(usize),
/// Ack of any type received. This is mostly used as a consistency check, and should be the sum // Ack of any type received. This is mostly used as a consistency check, and should be the sum
/// of real and cover acks received. // of real and cover acks received.
AckReceived(usize), AckReceived(usize),
/// Out of the total acks received, this is the subset of those that were real // Out of the total acks received, this is the subset of those that were real
RealAckReceived(usize), RealAckReceived(usize),
/// Out of the total acks received, this is the subset of those that were for cover traffic // Out of the total acks received, this is the subset of those that were for cover traffic
CoverAckReceived(usize), CoverAckReceived(usize),
/// Types of packets queued // Types of packets queued
RealPacketQueued, RealPacketQueued,
/// Types of packets queued
RetransmissionQueued, RetransmissionQueued,
/// Types of packets queued
ReplySurbRequestQueued, ReplySurbRequestQueued,
/// Types of packets queued
AdditionalReplySurbRequestQueued, AdditionalReplySurbRequestQueued,
} }
impl From<PacketStatisticsEvent> for ClientStatsEvents { type PacketStatisticsReceiver = tokio::sync::mpsc::UnboundedReceiver<PacketStatisticsEvent>;
fn from(event: PacketStatisticsEvent) -> ClientStatsEvents {
ClientStatsEvents::PacketStatistics(event) #[derive(Clone)]
pub(crate) struct PacketStatisticsReporter {
stats_tx: tokio::sync::mpsc::UnboundedSender<PacketStatisticsEvent>,
}
impl PacketStatisticsReporter {
pub(crate) fn new(stats_tx: tokio::sync::mpsc::UnboundedSender<PacketStatisticsEvent>) -> Self {
Self { stats_tx }
}
pub(crate) fn report(&self, event: PacketStatisticsEvent) {
self.stats_tx.send(event).unwrap_or_else(|err| {
log::error!("Failed to report packet stat: {:?}", err);
});
} }
} }
/// Statistics tracking for Packet based I/O pub(crate) struct PacketStatisticsControl {
#[derive(Default)] // Incoming packet stats events from other tasks
pub struct PacketStatisticsControl { stats_rx: PacketStatisticsReceiver,
// Keep track of packet statistics over time // Keep track of packet statistics over time
stats: PacketStatistics, stats: PacketStatistics,
@@ -394,28 +392,18 @@ pub struct PacketStatisticsControl {
} }
impl PacketStatisticsControl { impl PacketStatisticsControl {
pub(crate) fn handle_event(&mut self, event: PacketStatisticsEvent) { pub(crate) fn new() -> (Self, PacketStatisticsReporter) {
self.stats.handle(event) let (stats_tx, stats_rx) = tokio::sync::mpsc::unbounded_channel();
}
pub(crate) fn snapshot(&mut self) { (
self.update_history(); Self {
self.update_rates(); stats_rx,
} stats: PacketStatistics::default(),
history: VecDeque::new(),
pub(crate) fn report(&self) -> PacketStatistics { rates: VecDeque::new(),
self.stats.clone() },
} PacketStatisticsReporter::new(stats_tx),
)
pub(crate) fn local_report(&mut self, task_client: &mut nym_task::TaskClient) {
let rates = self.report_rates();
self.check_for_notable_events();
self.report_counters();
// Report our current bandwidth used to e.g a GUI client
if let Some(rates) = rates {
task_client.send_status_msg(Box::new(MixnetBandwidthStatisticsEvent::new(rates)));
}
} }
// Add the current stats to the history, and remove old ones. // Add the current stats to the history, and remove old ones.
@@ -468,13 +456,11 @@ impl PacketStatisticsControl {
} }
} }
fn report_rates(&self) -> Option<PacketRates> { fn report_rates(&self) {
if let Some((_, rates)) = self.rates.back() { if let Some((_, rates)) = self.rates.back() {
log::debug!("{}", rates.summary()); log::debug!("{}", rates.summary());
log::debug!("{}", rates.detailed_summary()); log::debug!("{}", rates.detailed_summary());
return Some(rates.clone());
} }
None
} }
fn report_counters(&self) { fn report_counters(&self) {
@@ -512,4 +498,124 @@ impl PacketStatisticsControl {
// IDEA: if there is a burst of acks, that could indicate tokio task starvation. // IDEA: if there is a burst of acks, that could indicate tokio task starvation.
} }
pub(crate) async fn run_with_shutdown(&mut self, mut shutdown: nym_task::TaskClient) {
log::debug!("Started PacketStatisticsControl with graceful shutdown support");
let report_interval = Duration::from_secs(PACKET_REPORT_INTERVAL_SECS);
let mut report_interval = tokio::time::interval(report_interval);
let snapshot_interval = Duration::from_millis(SNAPSHOT_INTERVAL_MS);
let mut snapshot_interval = tokio::time::interval(snapshot_interval);
cfg_if::cfg_if! {
if #[cfg(all(target_arch = "wasm32", target_os = "unknown"))] {
log::warn!("Metrics server is not supported on wasm32-unknown-unknown");
let listener: Option<WasmEmpty> = None;
} else if #[cfg(feature = "metrics-server")] {
let mut metrics_port = 18000;
let listener: Option<TcpListener>;
loop {
let addr = SocketAddr::from(([0, 0, 0, 0], metrics_port));
match TcpListener::bind(addr).await {
Ok(l) => {
log::info!("###############################");
log::info!("Metrics endpoint is at: {:?}", l.local_addr());
log::info!("###############################");
listener = Some(l);
break;
},
Err(err) => {
log::warn!("Failed to bind metrics server: {:?}", err);
metrics_port += 1;
}
};
}
} else {
log::info!("Metrics server is disabled!");
let listener: Option<TcpListener> = None;
}
}
loop {
// it seems at some point tokio changed its select precondition evaluation,
// and it's no longer checked before the future is evaluated.
let accept_future: OptionFuture<_> = listener
.as_ref()
.map(|l| l.accept())
.map(FutureExt::fuse)
.into();
tokio::select! {
stats_event = self.stats_rx.recv() => match stats_event {
Some(stats_event) => {
log::trace!("PacketStatisticsControl: Received stats event");
self.stats.handle_event(stats_event);
},
None => {
log::trace!("PacketStatisticsControl: stopping since stats channel was closed");
break;
}
},
// conditional will disable the branch if we're in wasm32-unknown-unknown
// use `_` to calm down clippy when running for wasm
_result = accept_future, if !accept_future.is_terminated() => {
cfg_if::cfg_if! {
if #[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))] {
if let Some(Ok((stream, _))) = _result {
let io = TokioIo::new(stream);
tokio::task::spawn(async move {
if let Err(err) = http1::Builder::new()
.serve_connection(io, service_fn(serve_metrics))
.await
{
log::warn!("Error serving connection: {:?}", err);
}
});
} else {
log::warn!("Error accepting connection");
}
}
}
}
_ = snapshot_interval.tick() => {
self.update_history();
self.update_rates();
}
_ = report_interval.tick() => {
self.report_rates();
self.check_for_notable_events();
self.report_counters();
}
_ = shutdown.recv_with_delay() => {
log::trace!("PacketStatisticsControl: Received shutdown");
break;
},
}
}
log::debug!("PacketStatisticsControl: Exiting");
}
pub(crate) fn start_with_shutdown(mut self, task_client: nym_task::TaskClient) {
spawn_future(async move {
self.run_with_shutdown(task_client).await;
})
}
}
#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
async fn serve_metrics(
_: Request<hyper::body::Incoming>,
) -> Result<Response<Full<Bytes>>, Infallible> {
use nym_metrics::metrics;
Ok(Response::new(Full::new(Bytes::from(metrics!()))))
}
#[cfg(all(target_arch = "wasm32", target_os = "unknown"))]
struct WasmEmpty;
#[cfg(all(target_arch = "wasm32", target_os = "unknown"))]
impl WasmEmpty {
async fn accept(&self) {}
} }
@@ -1,9 +1,9 @@
// 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 super::action_controller::{AckActionSender, Action}; use crate::client::packet_statistics_control::{PacketStatisticsEvent, PacketStatisticsReporter};
use nym_statistics_common::clients::{packet_statistics::PacketStatisticsEvent, ClientStatsSender};
use super::action_controller::{AckActionSender, Action};
use futures::StreamExt; use futures::StreamExt;
use log::*; use log::*;
use nym_gateway_client::AcknowledgementReceiver; use nym_gateway_client::AcknowledgementReceiver;
@@ -19,7 +19,7 @@ pub(super) struct AcknowledgementListener {
ack_key: Arc<AckKey>, ack_key: Arc<AckKey>,
ack_receiver: AcknowledgementReceiver, ack_receiver: AcknowledgementReceiver,
action_sender: AckActionSender, action_sender: AckActionSender,
stats_tx: ClientStatsSender, stats_tx: PacketStatisticsReporter,
} }
impl AcknowledgementListener { impl AcknowledgementListener {
@@ -27,7 +27,7 @@ impl AcknowledgementListener {
ack_key: Arc<AckKey>, ack_key: Arc<AckKey>,
ack_receiver: AcknowledgementReceiver, ack_receiver: AcknowledgementReceiver,
action_sender: AckActionSender, action_sender: AckActionSender,
stats_tx: ClientStatsSender, stats_tx: PacketStatisticsReporter,
) -> Self { ) -> Self {
AcknowledgementListener { AcknowledgementListener {
ack_key, ack_key,
@@ -40,7 +40,7 @@ impl AcknowledgementListener {
async fn on_ack(&mut self, ack_content: Vec<u8>) { async fn on_ack(&mut self, ack_content: Vec<u8>) {
trace!("Received an ack"); trace!("Received an ack");
self.stats_tx self.stats_tx
.report(PacketStatisticsEvent::AckReceived(ack_content.len()).into()); .report(PacketStatisticsEvent::AckReceived(ack_content.len()));
let frag_id = match recover_identifier(&self.ack_key, &ack_content) let frag_id = match recover_identifier(&self.ack_key, &ack_content)
.map(FragmentIdentifier::try_from_bytes) .map(FragmentIdentifier::try_from_bytes)
@@ -57,13 +57,13 @@ impl AcknowledgementListener {
if frag_id == COVER_FRAG_ID { if frag_id == COVER_FRAG_ID {
trace!("Received an ack for a cover message - no need to do anything"); trace!("Received an ack for a cover message - no need to do anything");
self.stats_tx self.stats_tx
.report(PacketStatisticsEvent::CoverAckReceived(ack_content.len()).into()); .report(PacketStatisticsEvent::CoverAckReceived(ack_content.len()));
return; return;
} }
trace!("Received {} from the mix network", frag_id); trace!("Received {} from the mix network", frag_id);
self.stats_tx self.stats_tx
.report(PacketStatisticsEvent::RealAckReceived(ack_content.len()).into()); .report(PacketStatisticsEvent::RealAckReceived(ack_content.len()));
self.action_sender self.action_sender
.unbounded_send(Action::new_remove(frag_id)) .unbounded_send(Action::new_remove(frag_id))
.unwrap(); .unwrap();
@@ -8,6 +8,7 @@ use self::{
sent_notification_listener::SentNotificationListener, sent_notification_listener::SentNotificationListener,
}; };
use crate::client::inbound_messages::InputMessageReceiver; use crate::client::inbound_messages::InputMessageReceiver;
use crate::client::packet_statistics_control::PacketStatisticsReporter;
use crate::client::real_messages_control::message_handler::MessageHandler; use crate::client::real_messages_control::message_handler::MessageHandler;
use crate::client::replies::reply_controller::ReplyControllerSender; use crate::client::replies::reply_controller::ReplyControllerSender;
use crate::spawn_future; use crate::spawn_future;
@@ -23,7 +24,6 @@ use nym_sphinx::{
chunking::fragment::{Fragment, FragmentIdentifier}, chunking::fragment::{Fragment, FragmentIdentifier},
Delay as SphinxDelay, Delay as SphinxDelay,
}; };
use nym_statistics_common::clients::ClientStatsSender;
use rand::{CryptoRng, Rng}; use rand::{CryptoRng, Rng};
use std::{ use std::{
sync::{Arc, Weak}, sync::{Arc, Weak},
@@ -209,7 +209,7 @@ where
connectors: AcknowledgementControllerConnectors, connectors: AcknowledgementControllerConnectors,
message_handler: MessageHandler<R>, message_handler: MessageHandler<R>,
reply_controller_sender: ReplyControllerSender, reply_controller_sender: ReplyControllerSender,
stats_tx: ClientStatsSender, stats_tx: PacketStatisticsReporter,
) -> Self { ) -> Self {
let (retransmission_tx, retransmission_rx) = mpsc::unbounded(); let (retransmission_tx, retransmission_rx) = mpsc::unbounded();
@@ -35,7 +35,7 @@ use crate::client::replies::reply_controller;
use crate::config; use crate::config;
pub(crate) use acknowledgement_control::{AckActionSender, Action}; pub(crate) use acknowledgement_control::{AckActionSender, Action};
use nym_statistics_common::clients::ClientStatsSender; use super::packet_statistics_control::PacketStatisticsReporter;
pub(crate) mod acknowledgement_control; pub(crate) mod acknowledgement_control;
pub(crate) mod message_handler; pub(crate) mod message_handler;
@@ -145,7 +145,7 @@ impl RealMessagesController<OsRng> {
reply_controller_receiver: ReplyControllerReceiver, reply_controller_receiver: ReplyControllerReceiver,
lane_queue_lengths: LaneQueueLengths, lane_queue_lengths: LaneQueueLengths,
client_connection_rx: ConnectionCommandReceiver, client_connection_rx: ConnectionCommandReceiver,
stats_tx: ClientStatsSender, stats_tx: PacketStatisticsReporter,
) -> Self { ) -> Self {
let rng = OsRng; let rng = OsRng;
@@ -3,6 +3,7 @@
use self::sending_delay_controller::SendingDelayController; use self::sending_delay_controller::SendingDelayController;
use crate::client::mix_traffic::BatchMixMessageSender; use crate::client::mix_traffic::BatchMixMessageSender;
use crate::client::packet_statistics_control::{PacketStatisticsEvent, PacketStatisticsReporter};
use crate::client::real_messages_control::acknowledgement_control::SentPacketNotificationSender; use crate::client::real_messages_control::acknowledgement_control::SentPacketNotificationSender;
use crate::client::topology_control::TopologyAccessor; use crate::client::topology_control::TopologyAccessor;
use crate::client::transmission_buffer::TransmissionBuffer; use crate::client::transmission_buffer::TransmissionBuffer;
@@ -18,7 +19,6 @@ use nym_sphinx::forwarding::packet::MixPacket;
use nym_sphinx::params::PacketSize; use nym_sphinx::params::PacketSize;
use nym_sphinx::preparer::PreparedFragment; use nym_sphinx::preparer::PreparedFragment;
use nym_sphinx::utils::sample_poisson_duration; use nym_sphinx::utils::sample_poisson_duration;
use nym_statistics_common::clients::{packet_statistics::PacketStatisticsEvent, ClientStatsSender};
use nym_task::connections::{ use nym_task::connections::{
ConnectionCommand, ConnectionCommandReceiver, ConnectionId, LaneQueueLengths, TransmissionLane, ConnectionCommand, ConnectionCommandReceiver, ConnectionId, LaneQueueLengths, TransmissionLane,
}; };
@@ -115,8 +115,8 @@ where
/// Report queue lengths so that upstream can backoff sending data, and keep connections open. /// Report queue lengths so that upstream can backoff sending data, and keep connections open.
lane_queue_lengths: LaneQueueLengths, lane_queue_lengths: LaneQueueLengths,
/// Channel used for sending metrics events (specifically `PacketStatistics` events) to the metrics tracker. /// Channel used for sending statistics events to `PacketStatisticsControl`.
stats_tx: ClientStatsSender, stats_tx: PacketStatisticsReporter,
} }
#[derive(Debug)] #[derive(Debug)]
@@ -175,7 +175,7 @@ where
topology_access: TopologyAccessor, topology_access: TopologyAccessor,
lane_queue_lengths: LaneQueueLengths, lane_queue_lengths: LaneQueueLengths,
client_connection_rx: ConnectionCommandReceiver, client_connection_rx: ConnectionCommandReceiver,
stats_tx: ClientStatsSender, stats_tx: PacketStatisticsReporter,
) -> Self { ) -> Self {
OutQueueControl { OutQueueControl {
config, config,
@@ -277,7 +277,7 @@ where
} else { } else {
PacketStatisticsEvent::CoverPacketSent(packet_size) PacketStatisticsEvent::CoverPacketSent(packet_size)
}; };
self.stats_tx.report(event.into()); self.stats_tx.report(event);
} }
// notify ack controller about sending our message only after we actually managed to push it // notify ack controller about sending our message only after we actually managed to push it
@@ -373,13 +373,13 @@ where
TransmissionLane::Retransmission => Some(PacketStatisticsEvent::RetransmissionQueued), TransmissionLane::Retransmission => Some(PacketStatisticsEvent::RetransmissionQueued),
}; };
if let Some(stat_event) = stat_event { if let Some(stat_event) = stat_event {
self.stats_tx.report(stat_event.into()); self.stats_tx.report(stat_event);
} }
// To avoid comparing apples to oranges when presenting the fraction of packets that are // To avoid comparing apples to oranges when presenting the fraction of packets that are
// retransmissions, we also need to keep track to the total number of real messages queued, // retransmissions, we also need to keep track to the total number of real messages queued,
// even though we also track the actual number of messages sent later in the pipeline. // even though we also track the actual number of messages sent later in the pipeline.
self.stats_tx self.stats_tx
.report(PacketStatisticsEvent::RealPacketQueued.into()); .report(PacketStatisticsEvent::RealPacketQueued);
Some(real_next) Some(real_next)
} }
@@ -1,8 +1,9 @@
// 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::replies::{ use crate::client::{
reply_controller::ReplyControllerSender, reply_storage::SentReplyKeys, packet_statistics_control::{PacketStatisticsEvent, PacketStatisticsReporter},
replies::{reply_controller::ReplyControllerSender, reply_storage::SentReplyKeys},
}; };
use crate::spawn_future; use crate::spawn_future;
use futures::channel::mpsc; use futures::channel::mpsc;
@@ -19,7 +20,6 @@ use nym_sphinx::anonymous_replies::{encryption_key::EncryptionKeyDigest, SurbEnc
use nym_sphinx::message::{NymMessage, PlainMessage}; use nym_sphinx::message::{NymMessage, PlainMessage};
use nym_sphinx::params::ReplySurbKeyDigestAlgorithm; use nym_sphinx::params::ReplySurbKeyDigestAlgorithm;
use nym_sphinx::receiver::{MessageReceiver, MessageRecoveryError, ReconstructedMessage}; use nym_sphinx::receiver::{MessageReceiver, MessageRecoveryError, ReconstructedMessage};
use nym_statistics_common::clients::{packet_statistics::PacketStatisticsEvent, ClientStatsSender};
use std::collections::HashSet; use std::collections::HashSet;
use std::sync::Arc; use std::sync::Arc;
@@ -46,7 +46,7 @@ struct ReceivedMessagesBufferInner<R: MessageReceiver> {
// and every now and then remove ids older than X // and every now and then remove ids older than X
recently_reconstructed: HashSet<i32>, recently_reconstructed: HashSet<i32>,
stats_tx: ClientStatsSender, stats_tx: PacketStatisticsReporter,
} }
impl<R: MessageReceiver> ReceivedMessagesBufferInner<R> { impl<R: MessageReceiver> ReceivedMessagesBufferInner<R> {
@@ -61,12 +61,16 @@ impl<R: MessageReceiver> ReceivedMessagesBufferInner<R> {
// received and sent packets due to the sphinx layers being removed by the exit gateway // received and sent packets due to the sphinx layers being removed by the exit gateway
// before it reaches the mixnet client. // before it reaches the mixnet client.
self.stats_tx self.stats_tx
.report(PacketStatisticsEvent::CoverPacketReceived(fragment_data_size).into()); .report(PacketStatisticsEvent::CoverPacketReceived(
fragment_data_size,
));
return None; return None;
} }
self.stats_tx self.stats_tx
.report(PacketStatisticsEvent::RealPacketReceived(fragment_data_size).into()); .report(PacketStatisticsEvent::RealPacketReceived(
fragment_data_size,
));
let fragment = match self.message_receiver.recover_fragment(fragment_data) { let fragment = match self.message_receiver.recover_fragment(fragment_data) {
Err(err) => { Err(err) => {
@@ -159,7 +163,7 @@ impl<R: MessageReceiver> ReceivedMessagesBuffer<R> {
local_encryption_keypair: Arc<encryption::KeyPair>, local_encryption_keypair: Arc<encryption::KeyPair>,
reply_key_storage: SentReplyKeys, reply_key_storage: SentReplyKeys,
reply_controller_sender: ReplyControllerSender, reply_controller_sender: ReplyControllerSender,
stats_tx: ClientStatsSender, stats_tx: PacketStatisticsReporter,
) -> Self { ) -> Self {
ReceivedMessagesBuffer { ReceivedMessagesBuffer {
inner: Arc::new(Mutex::new(ReceivedMessagesBufferInner { inner: Arc::new(Mutex::new(ReceivedMessagesBufferInner {
@@ -500,13 +504,13 @@ impl<R: MessageReceiver + Clone + Send + 'static> ReceivedMessagesBufferControll
mixnet_packet_receiver: MixnetMessageReceiver, mixnet_packet_receiver: MixnetMessageReceiver,
reply_key_storage: SentReplyKeys, reply_key_storage: SentReplyKeys,
reply_controller_sender: ReplyControllerSender, reply_controller_sender: ReplyControllerSender,
metrics_reporter: ClientStatsSender, packet_statistics_reporter: PacketStatisticsReporter,
) -> Self { ) -> Self {
let received_buffer = ReceivedMessagesBuffer::new( let received_buffer = ReceivedMessagesBuffer::new(
local_encryption_keypair, local_encryption_keypair,
reply_key_storage, reply_key_storage,
reply_controller_sender, reply_controller_sender,
metrics_reporter, packet_statistics_reporter,
); );
ReceivedMessagesBufferController { ReceivedMessagesBufferController {
@@ -1,151 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
//! # Statistics collection and reporting.
//!
//! Modular metrics collection and reporting system. submodules can be added to collect different types of metrics.
//! On creation the Statistics controller will start a task that will listen for incoming stats events and
//! multiplex them out to the appropriate metrics module based on type.
//!
//! Adding A new module you need to write a new module that implements the `StatsObj` trait and add it to
//! the `stats` hashmap in the `StatisticsControl` struct during it's initialization in the `new` function in
//! this file.
#![warn(clippy::expect_used)]
#![warn(clippy::unwrap_used)]
#![warn(clippy::todo)]
#![warn(clippy::dbg_macro)]
use std::time::Duration;
use nym_client_core_config_types::StatsReporting;
use nym_sphinx::addressing::Recipient;
use nym_statistics_common::clients::{
ClientStatsController, ClientStatsReceiver, ClientStatsSender,
};
use nym_task::connections::TransmissionLane;
use crate::{
client::inbound_messages::{InputMessage, InputMessageSender},
spawn_future,
};
/// Time interval between reporting statistics locally (logging/task_client)
const LOCAL_REPORT_INTERVAL: Duration = Duration::from_secs(2);
/// Interval for taking snapshots of the statistics
const SNAPSHOT_INTERVAL: Duration = Duration::from_millis(500);
/// Launches and manages metrics collection and reporting.
///
/// This is designed to be generic to allow for multiple types of metrics to be collected and
/// reported.
pub(crate) struct StatisticsControl {
/// Keep store the different types of metrics collectors
stats: ClientStatsController,
/// Incoming packet stats events from other tasks
stats_rx: ClientStatsReceiver,
/// Channel to send stats report through the mixnet
report_tx: InputMessageSender,
/// Config for stats reporting (enabled, address, interval)
reporting_config: StatsReporting,
}
impl StatisticsControl {
pub(crate) fn create(
reporting_config: StatsReporting,
client_type: String,
client_stats_id: String,
report_tx: InputMessageSender,
) -> (Self, ClientStatsSender) {
let (stats_tx, stats_rx) = tokio::sync::mpsc::unbounded_channel();
let stats = ClientStatsController::new(client_stats_id, client_type);
(
StatisticsControl {
stats,
stats_rx,
report_tx,
reporting_config,
},
ClientStatsSender::new(Some(stats_tx)),
)
}
async fn report_stats(&mut self, recipient: Recipient) {
let stats_report = self.stats.build_report();
let report_message = InputMessage::new_regular(
recipient,
stats_report.into(),
TransmissionLane::General,
None,
);
if let Err(err) = self.report_tx.send(report_message).await {
log::error!("Failed to report client stats: {:?}", err);
} else {
self.stats.reset();
}
}
async fn run_with_shutdown(&mut self, mut task_client: nym_task::TaskClient) {
log::debug!("Started StatisticsControl with graceful shutdown support");
let mut stats_report_interval =
tokio::time::interval(self.reporting_config.reporting_interval);
let mut local_report_interval = tokio::time::interval(LOCAL_REPORT_INTERVAL);
let mut snapshot_interval = tokio::time::interval(SNAPSHOT_INTERVAL);
loop {
tokio::select! {
stats_event = self.stats_rx.recv() => match stats_event {
Some(stats_event) => self.stats.handle_event(stats_event),
None => {
log::trace!("StatisticsControl: shutting down due to closed stats channel");
break;
}
},
_ = snapshot_interval.tick() => {
self.stats.snapshot();
}
_ = stats_report_interval.tick(), if self.reporting_config.enabled && self.reporting_config.provider_address.is_some() => {
// SAFTEY : this branch executes only if reporting is not none, so unwrapp is fine
#[allow(clippy::unwrap_used)]
self.report_stats(self.reporting_config.provider_address.unwrap()).await;
}
_ = local_report_interval.tick() => {
self.stats.local_report(&mut task_client);
}
_ = task_client.recv_with_delay() => {
log::trace!("StatisticsControl: Received shutdown");
break;
},
}
}
task_client.recv_timeout().await;
log::debug!("StatisticsControl: Exiting");
}
pub(crate) fn start_with_shutdown(mut self, task_client: nym_task::TaskClient) {
spawn_future(async move {
self.run_with_shutdown(task_client).await;
})
}
pub(crate) fn create_and_start_with_shutdown(
reporting_config: StatsReporting,
client_type: String,
client_stats_id: String,
report_tx: InputMessageSender,
task_client: nym_task::TaskClient,
) -> ClientStatsSender {
let (controller, sender) =
Self::create(reporting_config, client_type, client_stats_id, report_tx);
controller.start_with_shutdown(task_client);
sender
}
}
+5 -22
View File
@@ -212,29 +212,12 @@ pub enum ClientCoreError {
} }
/// Set of messages that the client can send to listeners via the task manager /// Set of messages that the client can send to listeners via the task manager
#[derive(Debug)] #[derive(thiserror::Error, Debug)]
pub enum ClientCoreStatusMessage { pub enum ClientCoreStatusMessage {
// NOTE: The nym-connect frontend listens for these strings, so don't change them until we have a more robust mechanism in place
#[error("The connected gateway is slow, or the connection to it is slow")]
GatewayIsSlow, GatewayIsSlow,
// NOTE: The nym-connect frontend listens for these strings, so don't change them until we have a more robust mechanism in place
#[error("The connected gateway is very slow, or the connection to it is very slow")]
GatewayIsVerySlow, GatewayIsVerySlow,
} }
impl std::fmt::Display for ClientCoreStatusMessage {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
ClientCoreStatusMessage::GatewayIsSlow => write!(
f,
"The connected gateway is slow, or the connection to it is slow"
),
ClientCoreStatusMessage::GatewayIsVerySlow => write!(
f,
"The connected gateway is very slow, or the connection to it is very slow"
),
}
}
}
impl nym_task::TaskStatusEvent for ClientCoreStatusMessage {
fn as_any(&self) -> &dyn std::any::Any {
self
}
}
@@ -29,7 +29,6 @@ nym-crypto = { path = "../../crypto" }
nym-gateway-requests = { path = "../../gateway-requests" } nym-gateway-requests = { path = "../../gateway-requests" }
nym-network-defaults = { path = "../../network-defaults" } nym-network-defaults = { path = "../../network-defaults" }
nym-sphinx = { path = "../../nymsphinx" } nym-sphinx = { path = "../../nymsphinx" }
nym-statistics-common = { path = "../../statistics" }
nym-pemstore = { path = "../../pemstore" } nym-pemstore = { path = "../../pemstore" }
nym-validator-client = { path = "../validator-client", default-features = false } nym-validator-client = { path = "../validator-client", default-features = false }
nym-task = { path = "../../task" } nym-task = { path = "../../task" }
@@ -25,8 +25,6 @@ use nym_gateway_requests::{
CREDENTIAL_UPDATE_V2_PROTOCOL_VERSION, CURRENT_PROTOCOL_VERSION, CREDENTIAL_UPDATE_V2_PROTOCOL_VERSION, CURRENT_PROTOCOL_VERSION,
}; };
use nym_sphinx::forwarding::packet::MixPacket; use nym_sphinx::forwarding::packet::MixPacket;
use nym_statistics_common::clients::connection::ConnectionStatsEvent;
use nym_statistics_common::clients::ClientStatsSender;
use nym_task::TaskClient; use nym_task::TaskClient;
use nym_validator_client::nyxd::contract_traits::DkgQueryClient; use nym_validator_client::nyxd::contract_traits::DkgQueryClient;
use rand::rngs::OsRng; use rand::rngs::OsRng;
@@ -96,7 +94,6 @@ pub struct GatewayClient<C, St = EphemeralCredentialStorage> {
connection: SocketState, connection: SocketState,
packet_router: PacketRouter, packet_router: PacketRouter,
bandwidth_controller: Option<BandwidthController<C, St>>, bandwidth_controller: Option<BandwidthController<C, St>>,
stats_reporter: ClientStatsSender,
// currently unused (but populated) // currently unused (but populated)
negotiated_protocol: Option<u8>, negotiated_protocol: Option<u8>,
@@ -106,7 +103,6 @@ pub struct GatewayClient<C, St = EphemeralCredentialStorage> {
} }
impl<C, St> GatewayClient<C, St> { impl<C, St> GatewayClient<C, St> {
#[allow(clippy::too_many_arguments)]
pub fn new( pub fn new(
cfg: GatewayClientConfig, cfg: GatewayClientConfig,
gateway_config: GatewayConfig, gateway_config: GatewayConfig,
@@ -115,7 +111,6 @@ impl<C, St> GatewayClient<C, St> {
shared_key: Option<Arc<SharedGatewayKey>>, shared_key: Option<Arc<SharedGatewayKey>>,
packet_router: PacketRouter, packet_router: PacketRouter,
bandwidth_controller: Option<BandwidthController<C, St>>, bandwidth_controller: Option<BandwidthController<C, St>>,
stats_reporter: ClientStatsSender,
task_client: TaskClient, task_client: TaskClient,
) -> Self { ) -> Self {
GatewayClient { GatewayClient {
@@ -129,7 +124,6 @@ impl<C, St> GatewayClient<C, St> {
connection: SocketState::NotConnected, connection: SocketState::NotConnected,
packet_router, packet_router,
bandwidth_controller, bandwidth_controller,
stats_reporter,
negotiated_protocol: None, negotiated_protocol: None,
task_client, task_client,
} }
@@ -720,7 +714,6 @@ impl<C, St> GatewayClient<C, St> {
{ {
// TODO: make it configurable // TODO: make it configurable
const TICKETS_TO_SPEND: u32 = 1; const TICKETS_TO_SPEND: u32 = 1;
const MIXNET_TICKET: TicketType = TicketType::V1MixnetEntry;
if !self.authenticated { if !self.authenticated {
return Err(GatewayClientError::NotAuthenticated); return Err(GatewayClientError::NotAuthenticated);
@@ -757,23 +750,14 @@ impl<C, St> GatewayClient<C, St> {
let prepared_credential = self let prepared_credential = self
.unchecked_bandwidth_controller() .unchecked_bandwidth_controller()
.prepare_ecash_ticket( .prepare_ecash_ticket(
MIXNET_TICKET, TicketType::V1MixnetEntry,
self.gateway_identity.to_bytes(), self.gateway_identity.to_bytes(),
TICKETS_TO_SPEND, TICKETS_TO_SPEND,
) )
.await?; .await?;
match self.claim_ecash_bandwidth(prepared_credential.data).await { match self.claim_ecash_bandwidth(prepared_credential.data).await {
Ok(_) => { Ok(_) => Ok(()),
self.stats_reporter.report(
ConnectionStatsEvent::TicketSpent {
typ: MIXNET_TICKET,
amount: TICKETS_TO_SPEND,
}
.into(),
);
Ok(())
}
Err(err) => { Err(err) => {
error!("failed to claim ecash bandwidth with the gateway...: {err}"); error!("failed to claim ecash bandwidth with the gateway...: {err}");
if err.is_ticket_replay() { if err.is_ticket_replay() {
@@ -1046,7 +1030,6 @@ impl GatewayClient<InitOnly, EphemeralCredentialStorage> {
connection: SocketState::NotConnected, connection: SocketState::NotConnected,
packet_router, packet_router,
bandwidth_controller: None, bandwidth_controller: None,
stats_reporter: ClientStatsSender::new(None),
negotiated_protocol: None, negotiated_protocol: None,
task_client, task_client,
} }
@@ -1056,7 +1039,6 @@ impl GatewayClient<InitOnly, EphemeralCredentialStorage> {
self, self,
packet_router: PacketRouter, packet_router: PacketRouter,
bandwidth_controller: Option<BandwidthController<C, St>>, bandwidth_controller: Option<BandwidthController<C, St>>,
stats_reporter: ClientStatsSender,
task_client: TaskClient, task_client: TaskClient,
) -> GatewayClient<C, St> { ) -> GatewayClient<C, St> {
// invariants that can't be broken // invariants that can't be broken
@@ -1076,7 +1058,6 @@ impl GatewayClient<InitOnly, EphemeralCredentialStorage> {
connection: self.connection, connection: self.connection,
packet_router, packet_router,
bandwidth_controller, bandwidth_controller,
stats_reporter,
negotiated_protocol: self.negotiated_protocol, negotiated_protocol: self.negotiated_protocol,
task_client, task_client,
} }
@@ -1,7 +1,6 @@
// 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
pub use crate::nym_api::NymApiClientExt;
use crate::nyxd::{self, NyxdClient}; use crate::nyxd::{self, NyxdClient};
use crate::signing::direct_wallet::DirectSecp256k1HdWallet; use crate::signing::direct_wallet::DirectSecp256k1HdWallet;
use crate::signing::signer::{NoSigner, OfflineSigner}; use crate::signing::signer::{NoSigner, OfflineSigner};
@@ -12,30 +11,29 @@ use crate::{
use nym_api_requests::ecash::models::{ use nym_api_requests::ecash::models::{
AggregatedCoinIndicesSignatureResponse, AggregatedExpirationDateSignatureResponse, AggregatedCoinIndicesSignatureResponse, AggregatedExpirationDateSignatureResponse,
BatchRedeemTicketsBody, EcashBatchTicketRedemptionResponse, EcashTicketVerificationResponse, BatchRedeemTicketsBody, EcashBatchTicketRedemptionResponse, EcashTicketVerificationResponse,
IssuedTicketbooksChallengeResponse, IssuedTicketbooksForResponse, SpentCredentialsResponse, SpentCredentialsResponse, VerifyEcashTicketBody,
VerifyEcashTicketBody,
}; };
use nym_api_requests::ecash::{ use nym_api_requests::ecash::{
BlindSignRequestBody, BlindedSignatureResponse, PartialCoinIndicesSignatureResponse, BlindSignRequestBody, BlindedSignatureResponse, PartialCoinIndicesSignatureResponse,
PartialExpirationDateSignatureResponse, VerificationKeyResponse, PartialExpirationDateSignatureResponse, VerificationKeyResponse,
}; };
use nym_api_requests::models::{ use nym_api_requests::models::{
ApiHealthResponse, GatewayCoreStatusResponse, MixnodeCoreStatusResponse, MixnodeStatusResponse, GatewayCoreStatusResponse, MixnodeCoreStatusResponse, MixnodeStatusResponse,
NymNodeDescription, RewardEstimationResponse, StakeSaturationResponse, NymNodeDescription, RewardEstimationResponse, StakeSaturationResponse,
}; };
use nym_api_requests::models::{LegacyDescribedGateway, MixNodeBondAnnotated}; use nym_api_requests::models::{LegacyDescribedGateway, MixNodeBondAnnotated};
use nym_api_requests::nym_nodes::SkimmedNode; use nym_api_requests::nym_nodes::SkimmedNode;
use nym_coconut_dkg_common::types::EpochId; use nym_coconut_dkg_common::types::EpochId;
use nym_ecash_contract_common::deposit::DepositId;
use nym_http_api_client::UserAgent; use nym_http_api_client::UserAgent;
use nym_network_defaults::NymNetworkDetails; use nym_network_defaults::NymNetworkDetails;
use time::Date; use time::Date;
use url::Url; use url::Url;
pub use crate::nym_api::NymApiClientExt;
use nym_mixnet_contract_common::NymNodeDetails;
pub use nym_mixnet_contract_common::{ pub use nym_mixnet_contract_common::{
mixnode::MixNodeDetails, GatewayBond, IdentityKey, IdentityKeyRef, NodeId, NymNodeDetails, mixnode::MixNodeDetails, GatewayBond, IdentityKey, IdentityKeyRef, NodeId,
}; };
// re-export the type to not break existing imports // re-export the type to not break existing imports
pub use crate::coconut::EcashApiClient; pub use crate::coconut::EcashApiClient;
@@ -194,8 +192,6 @@ impl<C, S> Client<C, S> {
} }
// validator-api wrappers // validator-api wrappers
// we have to allow the use of deprecated method here as they're calling the deprecated trait methods
#[allow(deprecated)]
impl<C, S> Client<C, S> { impl<C, S> Client<C, S> {
pub fn api_url(&self) -> &Url { pub fn api_url(&self) -> &Url {
self.nym_api.current_url() self.nym_api.current_url()
@@ -205,54 +201,46 @@ impl<C, S> Client<C, S> {
self.nym_api.change_base_url(new_endpoint) self.nym_api.change_base_url(new_endpoint)
} }
#[deprecated]
pub async fn get_cached_mixnodes(&self) -> Result<Vec<MixNodeDetails>, ValidatorClientError> { pub async fn get_cached_mixnodes(&self) -> Result<Vec<MixNodeDetails>, ValidatorClientError> {
Ok(self.nym_api.get_mixnodes().await?) Ok(self.nym_api.get_mixnodes().await?)
} }
#[deprecated]
pub async fn get_cached_mixnodes_detailed( pub async fn get_cached_mixnodes_detailed(
&self, &self,
) -> Result<Vec<MixNodeBondAnnotated>, ValidatorClientError> { ) -> Result<Vec<MixNodeBondAnnotated>, ValidatorClientError> {
Ok(self.nym_api.get_mixnodes_detailed().await?) Ok(self.nym_api.get_mixnodes_detailed().await?)
} }
#[deprecated]
pub async fn get_cached_mixnodes_detailed_unfiltered( pub async fn get_cached_mixnodes_detailed_unfiltered(
&self, &self,
) -> Result<Vec<MixNodeBondAnnotated>, ValidatorClientError> { ) -> Result<Vec<MixNodeBondAnnotated>, ValidatorClientError> {
Ok(self.nym_api.get_mixnodes_detailed_unfiltered().await?) Ok(self.nym_api.get_mixnodes_detailed_unfiltered().await?)
} }
#[deprecated]
pub async fn get_cached_rewarded_mixnodes( pub async fn get_cached_rewarded_mixnodes(
&self, &self,
) -> Result<Vec<MixNodeDetails>, ValidatorClientError> { ) -> Result<Vec<MixNodeDetails>, ValidatorClientError> {
Ok(self.nym_api.get_rewarded_mixnodes().await?) Ok(self.nym_api.get_rewarded_mixnodes().await?)
} }
#[deprecated]
pub async fn get_cached_rewarded_mixnodes_detailed( pub async fn get_cached_rewarded_mixnodes_detailed(
&self, &self,
) -> Result<Vec<MixNodeBondAnnotated>, ValidatorClientError> { ) -> Result<Vec<MixNodeBondAnnotated>, ValidatorClientError> {
Ok(self.nym_api.get_rewarded_mixnodes_detailed().await?) Ok(self.nym_api.get_rewarded_mixnodes_detailed().await?)
} }
#[deprecated]
pub async fn get_cached_active_mixnodes( pub async fn get_cached_active_mixnodes(
&self, &self,
) -> Result<Vec<MixNodeDetails>, ValidatorClientError> { ) -> Result<Vec<MixNodeDetails>, ValidatorClientError> {
Ok(self.nym_api.get_active_mixnodes().await?) Ok(self.nym_api.get_active_mixnodes().await?)
} }
#[deprecated]
pub async fn get_cached_active_mixnodes_detailed( pub async fn get_cached_active_mixnodes_detailed(
&self, &self,
) -> Result<Vec<MixNodeBondAnnotated>, ValidatorClientError> { ) -> Result<Vec<MixNodeBondAnnotated>, ValidatorClientError> {
Ok(self.nym_api.get_active_mixnodes_detailed().await?) Ok(self.nym_api.get_active_mixnodes_detailed().await?)
} }
#[deprecated]
pub async fn get_cached_gateways(&self) -> Result<Vec<GatewayBond>, ValidatorClientError> { pub async fn get_cached_gateways(&self) -> Result<Vec<GatewayBond>, ValidatorClientError> {
Ok(self.nym_api.get_gateways().await?) Ok(self.nym_api.get_gateways().await?)
} }
@@ -316,8 +304,6 @@ pub struct NymApiClient {
// we could re-implement the communication with the REST API on port 1317 // we could re-implement the communication with the REST API on port 1317
} }
// we have to allow the use of deprecated method here as they're calling the deprecated trait methods
#[allow(deprecated)]
impl NymApiClient { impl NymApiClient {
pub fn new(api_url: Url) -> Self { pub fn new(api_url: Url) -> Self {
let nym_api = nym_api::Client::new(api_url, None); let nym_api = nym_api::Client::new(api_url, None);
@@ -438,38 +424,6 @@ impl NymApiClient {
Ok(nodes) Ok(nodes)
} }
/// retrieve basic information for nodes are capable of operating as a mixnode
/// this includes legacy mixnodes and nym-nodes
pub async fn get_all_basic_mixing_capable_nodes(
&self,
semver_compatibility: Option<String>,
) -> Result<Vec<SkimmedNode>, ValidatorClientError> {
// TODO: deal with paging in macro or some helper function or something, because it's the same pattern everywhere
let mut page = 0;
let mut nodes = Vec::new();
loop {
let mut res = self
.nym_api
.get_basic_mixing_capable_nodes(
semver_compatibility.clone(),
false,
Some(page),
None,
)
.await?;
nodes.append(&mut res.nodes.data);
if nodes.len() < res.nodes.pagination.total {
page += 1
} else {
break;
}
}
Ok(nodes)
}
/// retrieve basic information for all bonded nodes on the network /// retrieve basic information for all bonded nodes on the network
pub async fn get_all_basic_nodes( pub async fn get_all_basic_nodes(
&self, &self,
@@ -496,35 +450,26 @@ impl NymApiClient {
Ok(nodes) Ok(nodes)
} }
pub async fn health(&self) -> Result<ApiHealthResponse, ValidatorClientError> {
Ok(self.nym_api.health().await?)
}
#[deprecated]
pub async fn get_cached_active_mixnodes( pub async fn get_cached_active_mixnodes(
&self, &self,
) -> Result<Vec<MixNodeDetails>, ValidatorClientError> { ) -> Result<Vec<MixNodeDetails>, ValidatorClientError> {
Ok(self.nym_api.get_active_mixnodes().await?) Ok(self.nym_api.get_active_mixnodes().await?)
} }
#[deprecated]
pub async fn get_cached_rewarded_mixnodes( pub async fn get_cached_rewarded_mixnodes(
&self, &self,
) -> Result<Vec<MixNodeDetails>, ValidatorClientError> { ) -> Result<Vec<MixNodeDetails>, ValidatorClientError> {
Ok(self.nym_api.get_rewarded_mixnodes().await?) Ok(self.nym_api.get_rewarded_mixnodes().await?)
} }
#[deprecated]
pub async fn get_cached_mixnodes(&self) -> Result<Vec<MixNodeDetails>, ValidatorClientError> { pub async fn get_cached_mixnodes(&self) -> Result<Vec<MixNodeDetails>, ValidatorClientError> {
Ok(self.nym_api.get_mixnodes().await?) Ok(self.nym_api.get_mixnodes().await?)
} }
#[deprecated]
pub async fn get_cached_gateways(&self) -> Result<Vec<GatewayBond>, ValidatorClientError> { pub async fn get_cached_gateways(&self) -> Result<Vec<GatewayBond>, ValidatorClientError> {
Ok(self.nym_api.get_gateways().await?) Ok(self.nym_api.get_gateways().await?)
} }
#[deprecated]
pub async fn get_cached_described_gateways( pub async fn get_cached_described_gateways(
&self, &self,
) -> Result<Vec<LegacyDescribedGateway>, ValidatorClientError> { ) -> Result<Vec<LegacyDescribedGateway>, ValidatorClientError> {
@@ -573,7 +518,6 @@ impl NymApiClient {
Ok(bonds) Ok(bonds)
} }
#[deprecated]
pub async fn get_gateway_core_status_count( pub async fn get_gateway_core_status_count(
&self, &self,
identity: IdentityKeyRef<'_>, identity: IdentityKeyRef<'_>,
@@ -585,7 +529,6 @@ impl NymApiClient {
.await?) .await?)
} }
#[deprecated]
pub async fn get_mixnode_core_status_count( pub async fn get_mixnode_core_status_count(
&self, &self,
mix_id: NodeId, mix_id: NodeId,
@@ -597,7 +540,6 @@ impl NymApiClient {
.await?) .await?)
} }
#[deprecated]
pub async fn get_mixnode_status( pub async fn get_mixnode_status(
&self, &self,
mix_id: NodeId, mix_id: NodeId,
@@ -605,7 +547,6 @@ impl NymApiClient {
Ok(self.nym_api.get_mixnode_status(mix_id).await?) Ok(self.nym_api.get_mixnode_status(mix_id).await?)
} }
#[deprecated]
pub async fn get_mixnode_reward_estimation( pub async fn get_mixnode_reward_estimation(
&self, &self,
mix_id: NodeId, mix_id: NodeId,
@@ -613,7 +554,6 @@ impl NymApiClient {
Ok(self.nym_api.get_mixnode_reward_estimation(mix_id).await?) Ok(self.nym_api.get_mixnode_reward_estimation(mix_id).await?)
} }
#[deprecated]
pub async fn get_mixnode_stake_saturation( pub async fn get_mixnode_stake_saturation(
&self, &self,
mix_id: NodeId, mix_id: NodeId,
@@ -645,7 +585,6 @@ impl NymApiClient {
.await?) .await?)
} }
#[deprecated]
pub async fn spent_credentials_filter( pub async fn spent_credentials_filter(
&self, &self,
) -> Result<SpentCredentialsResponse, ValidatorClientError> { ) -> Result<SpentCredentialsResponse, ValidatorClientError> {
@@ -698,22 +637,4 @@ impl NymApiClient {
) -> Result<VerificationKeyResponse, ValidatorClientError> { ) -> Result<VerificationKeyResponse, ValidatorClientError> {
Ok(self.nym_api.master_verification_key(epoch_id).await?) Ok(self.nym_api.master_verification_key(epoch_id).await?)
} }
pub async fn issued_ticketbooks_for(
&self,
expiration_date: Date,
) -> Result<IssuedTicketbooksForResponse, ValidatorClientError> {
Ok(self.nym_api.issued_ticketbooks_for(expiration_date).await?)
}
pub async fn issued_ticketbooks_challenge(
&self,
expiration_date: Date,
deposits: Vec<DepositId>,
) -> Result<IssuedTicketbooksChallengeResponse, ValidatorClientError> {
Ok(self
.nym_api
.issued_ticketbooks_challenge(expiration_date, deposits)
.await?)
}
} }
@@ -164,7 +164,7 @@ async fn test_nym_api_connection(
) -> ConnectionResult { ) -> ConnectionResult {
let result = match timeout( let result = match timeout(
Duration::from_secs(CONNECTION_TEST_TIMEOUT_SEC), Duration::from_secs(CONNECTION_TEST_TIMEOUT_SEC),
client.health(), client.get_cached_mixnodes(),
) )
.await .await
{ {
@@ -7,34 +7,35 @@ use async_trait::async_trait;
use nym_api_requests::ecash::models::{ use nym_api_requests::ecash::models::{
AggregatedCoinIndicesSignatureResponse, AggregatedExpirationDateSignatureResponse, AggregatedCoinIndicesSignatureResponse, AggregatedExpirationDateSignatureResponse,
BatchRedeemTicketsBody, EcashBatchTicketRedemptionResponse, EcashTicketVerificationResponse, BatchRedeemTicketsBody, EcashBatchTicketRedemptionResponse, EcashTicketVerificationResponse,
IssuedTicketbooksChallengeRequest, IssuedTicketbooksChallengeResponse, VerifyEcashTicketBody,
IssuedTicketbooksForResponse, VerifyEcashTicketBody,
}; };
use nym_api_requests::ecash::VerificationKeyResponse; use nym_api_requests::ecash::VerificationKeyResponse;
use nym_api_requests::models::{ use nym_api_requests::models::{
AnnotationResponse, ApiHealthResponse, LegacyDescribedMixNode, NodePerformanceResponse, AnnotationResponse, LegacyDescribedMixNode, NodePerformanceResponse, NymNodeDescription,
NymNodeDescription,
}; };
use nym_api_requests::nym_nodes::PaginatedCachedNodesResponse; use nym_api_requests::nym_nodes::PaginatedCachedNodesResponse;
use nym_api_requests::pagination::PaginatedResponse; use nym_api_requests::pagination::PaginatedResponse;
pub use nym_api_requests::{ pub use nym_api_requests::{
ecash::{ ecash::{
models::SpentCredentialsResponse, BlindSignRequestBody, BlindedSignatureResponse, models::{
EpochCredentialsResponse, IssuedCredentialResponse, IssuedCredentialsResponse,
IssuedTicketbook, IssuedTicketbookBody, SpentCredentialsResponse,
},
BlindSignRequestBody, BlindedSignatureResponse, CredentialsRequestBody,
PartialCoinIndicesSignatureResponse, PartialExpirationDateSignatureResponse, PartialCoinIndicesSignatureResponse, PartialExpirationDateSignatureResponse,
VerifyEcashCredentialBody, VerifyEcashCredentialBody,
}, },
models::{ models::{
ComputeRewardEstParam, GatewayBondAnnotated, GatewayCoreStatusResponse, ComputeRewardEstParam, GatewayBondAnnotated, GatewayCoreStatusResponse,
GatewayStatusReportResponse, GatewayUptimeHistoryResponse, LegacyDescribedGateway, GatewayStatusReportResponse, GatewayUptimeHistoryResponse, InclusionProbabilityResponse,
MixNodeBondAnnotated, MixnodeCoreStatusResponse, MixnodeStatusReportResponse, LegacyDescribedGateway, MixNodeBondAnnotated, MixnodeCoreStatusResponse,
MixnodeStatusResponse, MixnodeUptimeHistoryResponse, RewardEstimationResponse, MixnodeStatusReportResponse, MixnodeStatusResponse, MixnodeUptimeHistoryResponse,
StakeSaturationResponse, UptimeResponse, RewardEstimationResponse, StakeSaturationResponse, UptimeResponse,
}, },
nym_nodes::{CachedNodesResponse, SkimmedNode}, nym_nodes::{CachedNodesResponse, SkimmedNode},
}; };
pub use nym_coconut_dkg_common::types::EpochId; pub use nym_coconut_dkg_common::types::EpochId;
use nym_contracts_common::IdentityKey; use nym_contracts_common::IdentityKey;
use nym_ecash_contract_common::deposit::DepositId;
pub use nym_http_api_client::Client; pub use nym_http_api_client::Client;
use nym_http_api_client::{ApiClient, NO_PARAMS}; use nym_http_api_client::{ApiClient, NO_PARAMS};
use nym_mixnet_contract_common::mixnode::MixNodeDetails; use nym_mixnet_contract_common::mixnode::MixNodeDetails;
@@ -53,26 +54,12 @@ pub fn rfc_3339_date() -> Vec<BorrowedFormatItem<'static>> {
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))] #[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)] #[cfg_attr(not(target_arch = "wasm32"), async_trait)]
pub trait NymApiClientExt: ApiClient { pub trait NymApiClientExt: ApiClient {
async fn health(&self) -> Result<ApiHealthResponse, NymAPIError> {
self.get_json(
&[
routes::API_VERSION,
routes::API_STATUS_ROUTES,
routes::HEALTH,
],
NO_PARAMS,
)
.await
}
#[deprecated]
#[instrument(level = "debug", skip(self))] #[instrument(level = "debug", skip(self))]
async fn get_mixnodes(&self) -> Result<Vec<MixNodeDetails>, NymAPIError> { async fn get_mixnodes(&self) -> Result<Vec<MixNodeDetails>, NymAPIError> {
self.get_json(&[routes::API_VERSION, routes::MIXNODES], NO_PARAMS) self.get_json(&[routes::API_VERSION, routes::MIXNODES], NO_PARAMS)
.await .await
} }
#[deprecated]
#[instrument(level = "debug", skip(self))] #[instrument(level = "debug", skip(self))]
async fn get_mixnodes_detailed(&self) -> Result<Vec<MixNodeBondAnnotated>, NymAPIError> { async fn get_mixnodes_detailed(&self) -> Result<Vec<MixNodeBondAnnotated>, NymAPIError> {
self.get_json( self.get_json(
@@ -87,7 +74,6 @@ pub trait NymApiClientExt: ApiClient {
.await .await
} }
#[deprecated]
#[instrument(level = "debug", skip(self))] #[instrument(level = "debug", skip(self))]
async fn get_gateways_detailed(&self) -> Result<Vec<GatewayBondAnnotated>, NymAPIError> { async fn get_gateways_detailed(&self) -> Result<Vec<GatewayBondAnnotated>, NymAPIError> {
self.get_json( self.get_json(
@@ -102,7 +88,6 @@ pub trait NymApiClientExt: ApiClient {
.await .await
} }
#[deprecated]
#[instrument(level = "debug", skip(self))] #[instrument(level = "debug", skip(self))]
async fn get_mixnodes_detailed_unfiltered( async fn get_mixnodes_detailed_unfiltered(
&self, &self,
@@ -119,14 +104,12 @@ pub trait NymApiClientExt: ApiClient {
.await .await
} }
#[deprecated]
#[instrument(level = "debug", skip(self))] #[instrument(level = "debug", skip(self))]
async fn get_gateways(&self) -> Result<Vec<GatewayBond>, NymAPIError> { async fn get_gateways(&self) -> Result<Vec<GatewayBond>, NymAPIError> {
self.get_json(&[routes::API_VERSION, routes::GATEWAYS], NO_PARAMS) self.get_json(&[routes::API_VERSION, routes::GATEWAYS], NO_PARAMS)
.await .await
} }
#[deprecated]
#[instrument(level = "debug", skip(self))] #[instrument(level = "debug", skip(self))]
async fn get_gateways_described(&self) -> Result<Vec<LegacyDescribedGateway>, NymAPIError> { async fn get_gateways_described(&self) -> Result<Vec<LegacyDescribedGateway>, NymAPIError> {
self.get_json( self.get_json(
@@ -136,7 +119,6 @@ pub trait NymApiClientExt: ApiClient {
.await .await
} }
#[deprecated]
#[instrument(level = "debug", skip(self))] #[instrument(level = "debug", skip(self))]
async fn get_mixnodes_described(&self) -> Result<Vec<LegacyDescribedMixNode>, NymAPIError> { async fn get_mixnodes_described(&self) -> Result<Vec<LegacyDescribedMixNode>, NymAPIError> {
self.get_json( self.get_json(
@@ -146,7 +128,6 @@ pub trait NymApiClientExt: ApiClient {
.await .await
} }
#[tracing::instrument(level = "debug", skip_all)]
async fn get_nodes_described( async fn get_nodes_described(
&self, &self,
page: Option<u32>, page: Option<u32>,
@@ -166,7 +147,6 @@ pub trait NymApiClientExt: ApiClient {
.await .await
} }
#[tracing::instrument(level = "debug", skip_all)]
async fn get_nym_nodes( async fn get_nym_nodes(
&self, &self,
page: Option<u32>, page: Option<u32>,
@@ -186,7 +166,6 @@ pub trait NymApiClientExt: ApiClient {
.await .await
} }
#[deprecated]
#[tracing::instrument(level = "debug", skip_all)] #[tracing::instrument(level = "debug", skip_all)]
async fn get_basic_mixnodes( async fn get_basic_mixnodes(
&self, &self,
@@ -211,7 +190,6 @@ pub trait NymApiClientExt: ApiClient {
.await .await
} }
#[deprecated]
#[instrument(level = "debug", skip(self))] #[instrument(level = "debug", skip(self))]
async fn get_basic_gateways( async fn get_basic_gateways(
&self, &self,
@@ -320,49 +298,6 @@ pub trait NymApiClientExt: ApiClient {
.await .await
} }
/// retrieve basic information for nodes that got assigned 'mixing' node in this epoch
/// this includes legacy mixnodes and nym-nodes
#[instrument(level = "debug", skip(self))]
async fn get_basic_mixing_capable_nodes(
&self,
semver_compatibility: Option<String>,
no_legacy: bool,
page: Option<u32>,
per_page: Option<u32>,
) -> Result<PaginatedCachedNodesResponse<SkimmedNode>, NymAPIError> {
let mut params = Vec::new();
if let Some(arg) = &semver_compatibility {
params.push(("semver_compatibility", arg.clone()))
}
if no_legacy {
params.push(("no_legacy", "true".to_string()))
}
if let Some(page) = page {
params.push(("page", page.to_string()))
}
if let Some(per_page) = per_page {
params.push(("per_page", per_page.to_string()))
}
self.get_json(
&[
routes::API_VERSION,
"unstable",
"nym-nodes",
"skimmed",
"mixnodes",
"all",
],
&params,
)
.await
}
#[instrument(level = "debug", skip(self))]
async fn get_basic_nodes( async fn get_basic_nodes(
&self, &self,
semver_compatibility: Option<String>, semver_compatibility: Option<String>,
@@ -395,7 +330,6 @@ pub trait NymApiClientExt: ApiClient {
.await .await
} }
#[deprecated]
#[instrument(level = "debug", skip(self))] #[instrument(level = "debug", skip(self))]
async fn get_active_mixnodes(&self) -> Result<Vec<MixNodeDetails>, NymAPIError> { async fn get_active_mixnodes(&self) -> Result<Vec<MixNodeDetails>, NymAPIError> {
self.get_json( self.get_json(
@@ -405,7 +339,6 @@ pub trait NymApiClientExt: ApiClient {
.await .await
} }
#[deprecated]
#[instrument(level = "debug", skip(self))] #[instrument(level = "debug", skip(self))]
async fn get_active_mixnodes_detailed(&self) -> Result<Vec<MixNodeBondAnnotated>, NymAPIError> { async fn get_active_mixnodes_detailed(&self) -> Result<Vec<MixNodeBondAnnotated>, NymAPIError> {
self.get_json( self.get_json(
@@ -421,7 +354,6 @@ pub trait NymApiClientExt: ApiClient {
.await .await
} }
#[deprecated]
#[instrument(level = "debug", skip(self))] #[instrument(level = "debug", skip(self))]
async fn get_rewarded_mixnodes(&self) -> Result<Vec<MixNodeDetails>, NymAPIError> { async fn get_rewarded_mixnodes(&self) -> Result<Vec<MixNodeDetails>, NymAPIError> {
self.get_json( self.get_json(
@@ -431,7 +363,6 @@ pub trait NymApiClientExt: ApiClient {
.await .await
} }
#[deprecated]
#[instrument(level = "debug", skip(self))] #[instrument(level = "debug", skip(self))]
async fn get_mixnode_report( async fn get_mixnode_report(
&self, &self,
@@ -450,7 +381,6 @@ pub trait NymApiClientExt: ApiClient {
.await .await
} }
#[deprecated]
#[instrument(level = "debug", skip(self))] #[instrument(level = "debug", skip(self))]
async fn get_gateway_report( async fn get_gateway_report(
&self, &self,
@@ -469,7 +399,6 @@ pub trait NymApiClientExt: ApiClient {
.await .await
} }
#[deprecated]
#[instrument(level = "debug", skip(self))] #[instrument(level = "debug", skip(self))]
async fn get_mixnode_history( async fn get_mixnode_history(
&self, &self,
@@ -488,7 +417,6 @@ pub trait NymApiClientExt: ApiClient {
.await .await
} }
#[deprecated]
#[instrument(level = "debug", skip(self))] #[instrument(level = "debug", skip(self))]
async fn get_gateway_history( async fn get_gateway_history(
&self, &self,
@@ -507,7 +435,6 @@ pub trait NymApiClientExt: ApiClient {
.await .await
} }
#[deprecated]
#[instrument(level = "debug", skip(self))] #[instrument(level = "debug", skip(self))]
async fn get_rewarded_mixnodes_detailed( async fn get_rewarded_mixnodes_detailed(
&self, &self,
@@ -525,7 +452,6 @@ pub trait NymApiClientExt: ApiClient {
.await .await
} }
#[deprecated]
#[instrument(level = "debug", skip(self))] #[instrument(level = "debug", skip(self))]
async fn get_gateway_core_status_count( async fn get_gateway_core_status_count(
&self, &self,
@@ -558,7 +484,6 @@ pub trait NymApiClientExt: ApiClient {
} }
} }
#[deprecated]
#[instrument(level = "debug", skip(self))] #[instrument(level = "debug", skip(self))]
async fn get_mixnode_core_status_count( async fn get_mixnode_core_status_count(
&self, &self,
@@ -592,7 +517,6 @@ pub trait NymApiClientExt: ApiClient {
} }
} }
#[deprecated]
#[instrument(level = "debug", skip(self))] #[instrument(level = "debug", skip(self))]
async fn get_mixnode_status( async fn get_mixnode_status(
&self, &self,
@@ -611,7 +535,6 @@ pub trait NymApiClientExt: ApiClient {
.await .await
} }
#[deprecated]
#[instrument(level = "debug", skip(self))] #[instrument(level = "debug", skip(self))]
async fn get_mixnode_reward_estimation( async fn get_mixnode_reward_estimation(
&self, &self,
@@ -630,7 +553,6 @@ pub trait NymApiClientExt: ApiClient {
.await .await
} }
#[deprecated]
#[instrument(level = "debug", skip(self))] #[instrument(level = "debug", skip(self))]
async fn compute_mixnode_reward_estimation( async fn compute_mixnode_reward_estimation(
&self, &self,
@@ -651,7 +573,6 @@ pub trait NymApiClientExt: ApiClient {
.await .await
} }
#[deprecated]
#[instrument(level = "debug", skip(self))] #[instrument(level = "debug", skip(self))]
async fn get_mixnode_stake_saturation( async fn get_mixnode_stake_saturation(
&self, &self,
@@ -670,13 +591,11 @@ pub trait NymApiClientExt: ApiClient {
.await .await
} }
#[deprecated]
#[allow(deprecated)]
#[instrument(level = "debug", skip(self))] #[instrument(level = "debug", skip(self))]
async fn get_mixnode_inclusion_probability( async fn get_mixnode_inclusion_probability(
&self, &self,
mix_id: NodeId, mix_id: NodeId,
) -> Result<nym_api_requests::models::InclusionProbabilityResponse, NymAPIError> { ) -> Result<InclusionProbabilityResponse, NymAPIError> {
self.get_json( self.get_json(
&[ &[
routes::API_VERSION, routes::API_VERSION,
@@ -707,7 +626,6 @@ pub trait NymApiClientExt: ApiClient {
.await .await
} }
#[deprecated]
async fn get_mixnode_avg_uptime(&self, mix_id: NodeId) -> Result<UptimeResponse, NymAPIError> { async fn get_mixnode_avg_uptime(&self, mix_id: NodeId) -> Result<UptimeResponse, NymAPIError> {
self.get_json( self.get_json(
&[ &[
@@ -722,7 +640,6 @@ pub trait NymApiClientExt: ApiClient {
.await .await
} }
#[deprecated]
#[instrument(level = "debug", skip(self))] #[instrument(level = "debug", skip(self))]
async fn get_mixnodes_blacklisted(&self) -> Result<Vec<NodeId>, NymAPIError> { async fn get_mixnodes_blacklisted(&self) -> Result<Vec<NodeId>, NymAPIError> {
self.get_json( self.get_json(
@@ -732,7 +649,6 @@ pub trait NymApiClientExt: ApiClient {
.await .await
} }
#[deprecated]
#[instrument(level = "debug", skip(self))] #[instrument(level = "debug", skip(self))]
async fn get_gateways_blacklisted(&self) -> Result<Vec<IdentityKey>, NymAPIError> { async fn get_gateways_blacklisted(&self) -> Result<Vec<IdentityKey>, NymAPIError> {
self.get_json( self.get_json(
@@ -793,7 +709,6 @@ pub trait NymApiClientExt: ApiClient {
.await .await
} }
#[deprecated]
#[instrument(level = "debug", skip(self))] #[instrument(level = "debug", skip(self))]
async fn double_spending_filter_v1(&self) -> Result<SpentCredentialsResponse, NymAPIError> { async fn double_spending_filter_v1(&self) -> Result<SpentCredentialsResponse, NymAPIError> {
self.get_json( self.get_json(
@@ -910,44 +825,62 @@ pub trait NymApiClientExt: ApiClient {
&[ &[
routes::API_VERSION, routes::API_VERSION,
routes::ECASH_ROUTES, routes::ECASH_ROUTES,
ecash::MASTER_VERIFICATION_KEY, routes::ecash::MASTER_VERIFICATION_KEY,
], ],
&params, &params,
) )
.await .await
} }
async fn issued_ticketbooks_for( #[instrument(level = "debug", skip(self))]
async fn epoch_credentials(
&self, &self,
expiration_date: Date, dkg_epoch: EpochId,
) -> Result<IssuedTicketbooksForResponse, NymAPIError> { ) -> Result<EpochCredentialsResponse, NymAPIError> {
self.get_json( self.get_json(
&[ &[
routes::API_VERSION, routes::API_VERSION,
routes::ECASH_ROUTES, routes::ECASH_ROUTES,
routes::ECASH_ISSUED_TICKETBOOKS_FOR, routes::ECASH_EPOCH_CREDENTIALS,
&expiration_date.to_string(), &dkg_epoch.to_string(),
], ],
NO_PARAMS, NO_PARAMS,
) )
.await .await
} }
async fn issued_ticketbooks_challenge( #[instrument(level = "debug", skip(self))]
async fn issued_credential(
&self, &self,
expiration_date: Date, credential_id: i64,
deposits: Vec<DepositId>, ) -> Result<IssuedCredentialResponse, NymAPIError> {
) -> Result<IssuedTicketbooksChallengeResponse, NymAPIError> { self.get_json(
&[
routes::API_VERSION,
routes::ECASH_ROUTES,
routes::ECASH_ISSUED_CREDENTIAL,
&credential_id.to_string(),
],
NO_PARAMS,
)
.await
}
#[instrument(level = "debug", skip(self))]
async fn issued_credentials(
&self,
credential_ids: Vec<i64>,
) -> Result<IssuedCredentialsResponse, NymAPIError> {
self.post_json( self.post_json(
&[ &[
routes::API_VERSION, routes::API_VERSION,
routes::ECASH_ROUTES, routes::ECASH_ROUTES,
routes::ECASH_ISSUED_TICKETBOOKS_CHALLENGE, routes::ECASH_ISSUED_CREDENTIALS,
], ],
NO_PARAMS, NO_PARAMS,
&IssuedTicketbooksChallengeRequest { &CredentialsRequestBody {
expiration_date, credential_ids,
deposits, pagination: None,
}, },
) )
.await .await
@@ -27,16 +27,15 @@ pub mod ecash {
pub const PARTIAL_COIN_INDICES_SIGNATURES: &str = "partial-coin-indices-signatures"; pub const PARTIAL_COIN_INDICES_SIGNATURES: &str = "partial-coin-indices-signatures";
pub const GLOBAL_COIN_INDICES_SIGNATURES: &str = "aggregated-coin-indices-signatures"; pub const GLOBAL_COIN_INDICES_SIGNATURES: &str = "aggregated-coin-indices-signatures";
pub const MASTER_VERIFICATION_KEY: &str = "master-verification-key"; pub const MASTER_VERIFICATION_KEY: &str = "master-verification-key";
pub const ECASH_ISSUED_TICKETBOOKS_FOR: &str = "issued-ticketbooks-for"; pub const ECASH_EPOCH_CREDENTIALS: &str = "epoch-credentials";
pub const ECASH_ISSUED_TICKETBOOKS_CHALLENGE: &str = "issued-ticketbooks-challenge"; pub const ECASH_ISSUED_CREDENTIAL: &str = "issued-credential";
pub const ECASH_ISSUED_CREDENTIALS: &str = "issued-credentials";
pub const EXPIRATION_DATE_PARAM: &str = "expiration_date"; pub const EXPIRATION_DATE_PARAM: &str = "expiration_date";
pub const EPOCH_ID_PARAM: &str = "epoch_id"; pub const EPOCH_ID_PARAM: &str = "epoch_id";
} }
pub const STATUS_ROUTES: &str = "status"; pub const STATUS_ROUTES: &str = "status";
pub const API_STATUS_ROUTES: &str = "api-status";
pub const HEALTH: &str = "health";
pub const MIXNODE: &str = "mixnode"; pub const MIXNODE: &str = "mixnode";
pub const GATEWAY: &str = "gateway"; pub const GATEWAY: &str = "gateway";
pub const NYM_NODES: &str = "nym-nodes"; pub const NYM_NODES: &str = "nym-nodes";
@@ -7,7 +7,6 @@ use crate::nyxd::error::NyxdError;
use crate::nyxd::CosmWasmClient; use crate::nyxd::CosmWasmClient;
use async_trait::async_trait; use async_trait::async_trait;
use cosmwasm_std::Coin; use cosmwasm_std::Coin;
use nym_ecash_contract_common::deposit::LatestDepositResponse;
use nym_ecash_contract_common::msg::QueryMsg as EcashQueryMsg; use nym_ecash_contract_common::msg::QueryMsg as EcashQueryMsg;
use serde::Deserialize; use serde::Deserialize;
@@ -52,11 +51,6 @@ pub trait EcashQueryClient {
.await .await
} }
async fn get_latest_deposit(&self) -> Result<LatestDepositResponse, NyxdError> {
self.query_ecash_contract(EcashQueryMsg::GetLatestDeposit {})
.await
}
async fn get_deposits_paged( async fn get_deposits_paged(
&self, &self,
start_after: Option<u32>, start_after: Option<u32>,
@@ -104,6 +98,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_ecash_contract_common::msg::QueryMsg;
// 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)]
@@ -115,17 +110,14 @@ mod tests {
EcashQueryMsg::GetBlacklistedAccount { public_key } => { EcashQueryMsg::GetBlacklistedAccount { public_key } => {
client.get_blacklisted_account(public_key).ignore() client.get_blacklisted_account(public_key).ignore()
} }
EcashQueryMsg::GetBlacklistPaged { limit, start_after } => { QueryMsg::GetBlacklistPaged { limit, start_after } => {
client.get_blacklist_paged(start_after, limit).ignore() client.get_blacklist_paged(start_after, limit).ignore()
} }
EcashQueryMsg::GetDeposit { deposit_id } => client.get_deposit(deposit_id).ignore(), QueryMsg::GetDeposit { deposit_id } => client.get_deposit(deposit_id).ignore(),
EcashQueryMsg::GetDepositsPaged { limit, start_after } => { QueryMsg::GetDepositsPaged { limit, start_after } => {
client.get_deposits_paged(start_after, limit).ignore() client.get_deposits_paged(start_after, limit).ignore()
} }
EcashQueryMsg::GetRequiredDepositAmount {} => { QueryMsg::GetRequiredDepositAmount {} => client.get_required_deposit_amount().ignore(),
client.get_required_deposit_amount().ignore()
}
EcashQueryMsg::GetLatestDeposit {} => client.get_latest_deposit().ignore(),
}; };
} }
} }
@@ -66,6 +66,11 @@ pub trait MixnetQueryClient {
.await .await
} }
async fn get_mixnet_contract_settings(&self) -> Result<ContractStateParams, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetStateParams {})
.await
}
async fn get_mixnet_contract_state_params(&self) -> Result<ContractStateParams, NyxdError> { async fn get_mixnet_contract_state_params(&self) -> Result<ContractStateParams, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetStateParams {}) self.query_mixnet_contract(MixnetQueryMsg::GetStateParams {})
.await .await
@@ -17,7 +17,7 @@ use nym_mixnet_contract_common::reward_params::{
ActiveSetUpdate, IntervalRewardingParamsUpdate, NodeRewardingParameters, ActiveSetUpdate, IntervalRewardingParamsUpdate, NodeRewardingParameters,
}; };
use nym_mixnet_contract_common::{ use nym_mixnet_contract_common::{
ContractStateParamsUpdate, ExecuteMsg as MixnetExecuteMsg, Gateway, MixNode, NodeId, NymNode, ContractStateParams, ExecuteMsg as MixnetExecuteMsg, Gateway, MixNode, NodeId, NymNode,
RoleAssignment, RoleAssignment,
}; };
@@ -59,27 +59,12 @@ pub trait MixnetSigningClient {
async fn update_contract_state_params( async fn update_contract_state_params(
&self, &self,
update: ContractStateParamsUpdate, updated_parameters: ContractStateParams,
fee: Option<Fee>, fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> { ) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract( self.execute_mixnet_contract(
fee, fee,
MixnetExecuteMsg::UpdateContractStateParams { update }, MixnetExecuteMsg::UpdateContractStateParams { updated_parameters },
vec![],
)
.await
}
async fn update_current_nym_node_semver(
&self,
current_nym_node_semver: String,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract(
fee,
MixnetExecuteMsg::UpdateCurrentNymNodeSemver {
current_version: current_nym_node_semver,
},
vec![], vec![],
) )
.await .await
@@ -697,11 +682,8 @@ mod tests {
MixnetExecuteMsg::UpdateRewardingValidatorAddress { address } => client MixnetExecuteMsg::UpdateRewardingValidatorAddress { address } => client
.update_rewarding_validator_address(address.parse().unwrap(), None) .update_rewarding_validator_address(address.parse().unwrap(), None)
.ignore(), .ignore(),
MixnetExecuteMsg::UpdateContractStateParams { update } => { MixnetExecuteMsg::UpdateContractStateParams { updated_parameters } => client
client.update_contract_state_params(update, None).ignore() .update_contract_state_params(updated_parameters, None)
}
MixnetExecuteMsg::UpdateCurrentNymNodeSemver { current_version } => client
.update_current_nym_node_semver(current_version, None)
.ignore(), .ignore(),
MixnetExecuteMsg::UpdateActiveSetDistribution { MixnetExecuteMsg::UpdateActiveSetDistribution {
update, update,
@@ -303,7 +303,7 @@ where
feature = "tendermint-rpc-http-client", feature = "tendermint-rpc-http-client",
feature = "tendermint-rpc-websocket-client" feature = "tendermint-rpc-websocket-client"
))] ))]
async fn wait_until_healthy<T>(&self, timeout: T) -> Result<(), TendermintRpcError> async fn wait_until_healthy<T>(&self, timeout: T) -> Result<(), Error>
where where
T: Into<core::time::Duration> + Send, T: Into<core::time::Duration> + Send,
{ {
@@ -823,7 +823,7 @@ where
feature = "tendermint-rpc-http-client", feature = "tendermint-rpc-http-client",
feature = "tendermint-rpc-websocket-client" feature = "tendermint-rpc-websocket-client"
))] ))]
async fn wait_until_healthy<T>(&self, timeout: T) -> Result<(), TendermintRpcError> async fn wait_until_healthy<T>(&self, timeout: T) -> Result<(), Error>
where where
T: Into<core::time::Duration> + Send, T: Into<core::time::Duration> + Send,
{ {
@@ -523,7 +523,7 @@ mod non_wasm {
))] ))]
async fn wait_until_healthy<T>(&self, timeout: T) -> Result<(), Error> async fn wait_until_healthy<T>(&self, timeout: T) -> Result<(), Error>
where where
T: Into<core::time::Duration> + Send, T: Into<Duration> + Send,
{ {
self.wait_until_healthy(timeout).await self.wait_until_healthy(timeout).await
} }
@@ -6,7 +6,6 @@ use crate::utils::CommonConfigsWrapper;
use anyhow::{anyhow, bail}; use anyhow::{anyhow, bail};
use clap::ArgGroup; use clap::ArgGroup;
use clap::Parser; use clap::Parser;
use log::info;
use nym_credential_storage::initialise_persistent_storage; use nym_credential_storage::initialise_persistent_storage;
use nym_credential_storage::storage::Storage; use nym_credential_storage::storage::Storage;
use nym_credential_utils::utils; use nym_credential_utils::utils;
@@ -151,7 +150,6 @@ async fn issue_to_file(args: Args, client: SigningClient) -> anyhow::Result<()>
exported = exported.with_master_verification_key(&EpochVerificationKey { epoch_id, key }); exported = exported.with_master_verification_key(&EpochVerificationKey { epoch_id, key });
} }
info!("the issued ticketbook has expiration of {expiration_date}");
let data = exported.pack().data; let data = exported.pack().data;
if args.bs58_output { if args.bs58_output {
@@ -33,9 +33,6 @@ pub struct Args {
#[clap(long)] #[clap(long)]
pub rewarding_denom: Option<String>, pub rewarding_denom: Option<String>,
#[clap(long)]
pub current_nym_node_version: String,
#[clap(long, default_value_t = 720)] #[clap(long, default_value_t = 720)]
pub epochs_in_interval: u32, pub epochs_in_interval: u32,
@@ -146,9 +143,6 @@ pub async fn generate(args: Args) {
epochs_in_interval: args.epochs_in_interval, epochs_in_interval: args.epochs_in_interval,
epoch_duration: Duration::from_secs(args.epoch_duration), epoch_duration: Duration::from_secs(args.epoch_duration),
initial_rewarding_params, initial_rewarding_params,
current_nym_node_version: args.current_nym_node_version,
version_score_weights: Default::default(),
version_score_params: Default::default(),
profit_margin: ProfitMarginRange { profit_margin: ProfitMarginRange {
minimum: args.minimum_profit_margin_percent, minimum: args.minimum_profit_margin_percent,
maximum: args.maximum_profit_margin_percent, maximum: args.maximum_profit_margin_percent,
@@ -2,9 +2,10 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
use crate::context::QueryClientWithNyxd; use crate::context::QueryClientWithNyxd;
use crate::utils::show_error; use crate::utils::{pretty_cosmwasm_coin, show_error};
use clap::Parser; use clap::Parser;
use comfy_table::Table; use comfy_table::Table;
use nym_validator_client::client::NymApiClientExt;
#[derive(Debug, Parser)] #[derive(Debug, Parser)]
pub struct Args { pub struct Args {
@@ -14,11 +15,12 @@ pub struct Args {
} }
pub async fn query(args: Args, client: &QueryClientWithNyxd) { pub async fn query(args: Args, client: &QueryClientWithNyxd) {
match client.get_all_cached_described_nodes().await { match client.nym_api.get_gateways().await {
Ok(res) => match args.identity_key { Ok(res) => match args.identity_key {
Some(identity_key) => { Some(identity_key) => {
let node = res.iter().find(|node| { let node = res.iter().find(|node| {
node.ed25519_identity_key() node.gateway
.identity_key
.to_string() .to_string()
.eq_ignore_ascii_case(&identity_key) .eq_ignore_ascii_case(&identity_key)
}); });
@@ -30,16 +32,14 @@ pub async fn query(args: Args, client: &QueryClientWithNyxd) {
None => { None => {
let mut table = Table::new(); let mut table = Table::new();
table.set_header(vec!["Node Id", "Identity Key", "Version", "Is Legacy"]); table.set_header(vec!["Identity Key", "Owner", "Host", "Bond", "Version"]);
for node in res for node in res {
.into_iter()
.filter(|node| node.description.declared_role.entry)
{
table.add_row(vec![ table.add_row(vec![
node.node_id.to_string(), node.gateway.identity_key.to_string(),
node.ed25519_identity_key().to_base58_string(), node.owner.to_string(),
node.description.build_information.build_version, node.gateway.host.to_string(),
(!node.contract_node_type.is_nym_node()).to_string(), pretty_cosmwasm_coin(&node.pledge_amount),
node.gateway.version.clone(),
]); ]);
} }
@@ -2,9 +2,10 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
use crate::context::QueryClientWithNyxd; use crate::context::QueryClientWithNyxd;
use crate::utils::show_error; use crate::utils::{pretty_decimal_with_denom, show_error};
use clap::Parser; use clap::Parser;
use comfy_table::Table; use comfy_table::Table;
use nym_validator_client::client::NymApiClientExt;
#[derive(Debug, Parser)] #[derive(Debug, Parser)]
pub struct Args { pub struct Args {
@@ -14,11 +15,13 @@ pub struct Args {
} }
pub async fn query(args: Args, client: &QueryClientWithNyxd) { pub async fn query(args: Args, client: &QueryClientWithNyxd) {
match client.get_all_cached_described_nodes().await { match client.nym_api.get_mixnodes().await {
Ok(res) => match args.identity_key { Ok(res) => match args.identity_key {
Some(identity_key) => { Some(identity_key) => {
let node = res.iter().find(|node| { let node = res.iter().find(|node| {
node.ed25519_identity_key() node.bond_information
.mix_node
.identity_key
.to_string() .to_string()
.eq_ignore_ascii_case(&identity_key) .eq_ignore_ascii_case(&identity_key)
}); });
@@ -30,16 +33,25 @@ pub async fn query(args: Args, client: &QueryClientWithNyxd) {
None => { None => {
let mut table = Table::new(); let mut table = Table::new();
table.set_header(vec!["Node Id", "Identity Key", "Version", "Is Legacy"]); table.set_header(vec![
for node in res "Mix id",
.into_iter() "Identity Key",
.filter(|node| node.description.declared_role.mixnode) "Owner",
{ "Host",
"Bond",
"Total Delegations",
"Version",
]);
for node in res {
let denom = &node.bond_information.original_pledge().denom;
table.add_row(vec![ table.add_row(vec![
node.node_id.to_string(), node.mix_id().to_string(),
node.ed25519_identity_key().to_base58_string(), node.bond_information.mix_node.identity_key.clone(),
node.description.build_information.build_version, node.bond_information.owner.clone().into_string(),
(!node.contract_node_type.is_nym_node()).to_string(), node.bond_information.mix_node.host.clone(),
pretty_decimal_with_denom(node.rewarding_details.operator, denom),
pretty_decimal_with_denom(node.rewarding_details.delegates, denom),
node.bond_information.mix_node.version,
]); ]);
} }
+1 -12
View File
@@ -1,7 +1,7 @@
// 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 serde::{Deserialize, Deserializer, Serializer}; use serde::{Deserialize, Deserializer};
use std::fmt::Display; use std::fmt::Display;
use std::path::PathBuf; use std::path::PathBuf;
use std::str::FromStr; use std::str::FromStr;
@@ -20,17 +20,6 @@ where
} }
} }
pub fn ser_maybe_stringified<S, T>(field: &Option<T>, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
T: Display,
{
match field {
Some(inner) => serializer.serialize_str(&inner.to_string()),
None => serializer.serialize_str(""),
}
}
pub fn de_maybe_string<'de, D>(deserializer: D) -> Result<Option<String>, D::Error> pub fn de_maybe_string<'de, D>(deserializer: D) -> Result<Option<String>, D::Error>
where where
D: Deserializer<'de>, D: Deserializer<'de>,
@@ -21,6 +21,3 @@ serde_json = { workspace = true }
[build-dependencies] [build-dependencies]
vergen = { workspace = true, features = ["build", "git", "gitcl", "rustc", "cargo"] } vergen = { workspace = true, features = ["build", "git", "gitcl", "rustc", "cargo"] }
[features]
naive_float = []
@@ -130,7 +130,7 @@ impl Deref for Percent {
} }
// this is not implemented via From traits due to its naive nature and loss of precision // this is not implemented via From traits due to its naive nature and loss of precision
#[cfg(feature = "naive_float")] #[cfg(not(target_arch = "wasm32"))]
pub trait NaiveFloat { pub trait NaiveFloat {
fn naive_to_f64(&self) -> f64; fn naive_to_f64(&self) -> f64;
@@ -139,8 +139,8 @@ pub trait NaiveFloat {
Self: Sized; Self: Sized;
} }
#[cfg(feature = "naive_float")] #[cfg(not(target_arch = "wasm32"))]
impl NaiveFloat for Decimal { impl NaiveFloat for Percent {
fn naive_to_f64(&self) -> f64 { fn naive_to_f64(&self) -> f64 {
use cosmwasm_std::Fraction; use cosmwasm_std::Fraction;
@@ -181,21 +181,7 @@ impl NaiveFloat for Decimal {
} }
let (n, d) = to_rational(val); let (n, d) = to_rational(val);
Ok(Decimal::from_ratio(n, d)) Percent::new(Decimal::from_ratio(n, d))
}
}
#[cfg(feature = "naive_float")]
impl NaiveFloat for Percent {
fn naive_to_f64(&self) -> f64 {
self.0.naive_to_f64()
}
fn naive_try_from_f64(val: f64) -> Result<Self, ContractsCommonError>
where
Self: Sized,
{
Percent::new(Decimal::naive_try_from_f64(val)?)
} }
} }
@@ -47,12 +47,6 @@ impl Deposit {
} }
} }
#[cw_serde]
#[derive(Default)]
pub struct LatestDepositResponse {
pub deposit: Option<DepositData>,
}
#[cw_serde] #[cw_serde]
pub struct DepositResponse { pub struct DepositResponse {
pub id: DepositId, pub id: DepositId,
@@ -1,4 +1,4 @@
// Copyright 2024 - 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 cosmwasm_schema::cw_serde; use cosmwasm_schema::cw_serde;
@@ -7,7 +7,7 @@ use cosmwasm_std::Coin;
#[cfg(feature = "schema")] #[cfg(feature = "schema")]
use crate::blacklist::{BlacklistedAccountResponse, PagedBlacklistedAccountResponse}; use crate::blacklist::{BlacklistedAccountResponse, PagedBlacklistedAccountResponse};
#[cfg(feature = "schema")] #[cfg(feature = "schema")]
use crate::deposit::{DepositResponse, LatestDepositResponse, PagedDepositsResponse}; use crate::deposit::{DepositResponse, PagedDepositsResponse};
#[cfg(feature = "schema")] #[cfg(feature = "schema")]
use cosmwasm_schema::QueryResponses; use cosmwasm_schema::QueryResponses;
@@ -73,9 +73,6 @@ pub enum QueryMsg {
#[cfg_attr(feature = "schema", returns(DepositResponse))] #[cfg_attr(feature = "schema", returns(DepositResponse))]
GetDeposit { deposit_id: u32 }, GetDeposit { deposit_id: u32 },
#[cfg_attr(feature = "schema", returns(LatestDepositResponse))]
GetLatestDeposit {},
#[cfg_attr(feature = "schema", returns(PagedDepositsResponse))] #[cfg_attr(feature = "schema", returns(PagedDepositsResponse))]
GetDepositsPaged { GetDepositsPaged {
limit: Option<u32>, limit: Option<u32>,
@@ -17,7 +17,6 @@ cw-controllers = { workspace = true }
cw2 = { workspace = true, optional = true } cw2 = { workspace = true, optional = true }
serde = { workspace = true, features = ["derive"] } serde = { workspace = true, features = ["derive"] }
serde_repr = { workspace = true } serde_repr = { workspace = true }
semver = { workspace = true, features = ["serde"] }
# we still have to preserve that import for `JsonSchema` for `Layer` type (since we can't use cw_serde macro due to custom serde impl) # we still have to preserve that import for `JsonSchema` for `Layer` type (since we can't use cw_serde macro due to custom serde impl)
schemars = { workspace = true } schemars = { workspace = true }
@@ -27,6 +26,8 @@ serde-json-wasm = { workspace = true }
humantime-serde = { workspace = true } humantime-serde = { workspace = true }
utoipa = { workspace = true, optional = true } utoipa = { workspace = true, optional = true }
# TO CHECK WHETHER STILL NEEDED:
log = { workspace = true }
time = { workspace = true, features = ["parsing", "formatting"] } time = { workspace = true, features = ["parsing", "formatting"] }
ts-rs = { workspace = true, optional = true } ts-rs = { workspace = true, optional = true }
@@ -37,6 +38,6 @@ time = { workspace = true, features = ["serde", "macros"] }
[features] [features]
default = [] default = []
contract-testing = [] contract-testing = []
utoipa = ["dep:utoipa"] utoipa = [ "dep:utoipa" ]
schema = ["cw2"] schema = ["cw2"]
generate-ts = ['ts-rs'] generate-ts = ['ts-rs']
@@ -166,9 +166,6 @@ pub enum MixnetContractError {
#[error("Provided message to update rewarding params did not contain any updates")] #[error("Provided message to update rewarding params did not contain any updates")]
EmptyParamsChangeMsg, EmptyParamsChangeMsg,
#[error("provided message to update state parameters did not contain any updates")]
EmptyStateUpdateMsg,
#[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,
@@ -272,9 +269,6 @@ pub enum MixnetContractError {
#[error("the total work for this epoch seems to be bigger than 1.0!")] #[error("the total work for this epoch seems to be bigger than 1.0!")]
TotalWorkAboveOne, TotalWorkAboveOne,
#[error("the provided nym-node version is not a valid semver. got: {provided}")]
InvalidNymNodeSemver { provided: String },
} }
impl MixnetContractError { impl MixnetContractError {
@@ -7,9 +7,9 @@ use crate::mixnode::{MixNodeConfigUpdate, NodeCostParams};
use crate::nym_node::Role; use crate::nym_node::Role;
use crate::reward_params::{ActiveSetUpdate, IntervalRewardParams, IntervalRewardingParamsUpdate}; use crate::reward_params::{ActiveSetUpdate, IntervalRewardParams, IntervalRewardingParamsUpdate};
use crate::rewarding::RewardDistribution; use crate::rewarding::RewardDistribution;
use crate::{BlockHeight, ContractStateParamsUpdate, EpochId, IdentityKeyRef, Interval, NodeId}; use crate::{BlockHeight, ContractStateParams, 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};
use std::fmt::Display; use std::fmt::Display;
pub const EVENT_VERSION_PREFIX: &str = "v2_"; pub const EVENT_VERSION_PREFIX: &str = "v2_";
@@ -45,7 +45,6 @@ pub enum MixnetEventType {
DelegationOnUnbonding, DelegationOnUnbonding,
Undelegation, Undelegation,
ContractSettingsUpdate, ContractSettingsUpdate,
NymNodeSemverUpdate,
RewardingValidatorUpdate, RewardingValidatorUpdate,
BeginEpochTransition, BeginEpochTransition,
AdvanceEpoch, AdvanceEpoch,
@@ -98,7 +97,6 @@ impl Display for MixnetEventType {
MixnetEventType::Delegation => "delegation", MixnetEventType::Delegation => "delegation",
MixnetEventType::Undelegation => "undelegation", MixnetEventType::Undelegation => "undelegation",
MixnetEventType::ContractSettingsUpdate => "settings_update", MixnetEventType::ContractSettingsUpdate => "settings_update",
MixnetEventType::NymNodeSemverUpdate => "nym_node_semver_update",
MixnetEventType::RewardingValidatorUpdate => "rewarding_validator_address_update", MixnetEventType::RewardingValidatorUpdate => "rewarding_validator_address_update",
MixnetEventType::BeginEpochTransition => "beginning_epoch_transition", MixnetEventType::BeginEpochTransition => "beginning_epoch_transition",
MixnetEventType::AdvanceEpoch => "advance_epoch", MixnetEventType::AdvanceEpoch => "advance_epoch",
@@ -134,13 +132,11 @@ pub const NODE_ID_KEY: &str = "node_id";
pub const NODE_IDENTITY_KEY: &str = "identity"; pub const NODE_IDENTITY_KEY: &str = "identity";
// settings change // settings change
pub const OLD_MINIMUM_PLEDGE_KEY: &str = "old_minimum_pledge";
pub const OLD_MINIMUM_DELEGATION_KEY: &str = "old_minimum_delegation";
pub const NEW_MINIMUM_PLEDGE_KEY: &str = "new_minimum_pledge"; pub const NEW_MINIMUM_PLEDGE_KEY: &str = "new_minimum_pledge";
pub const NEW_MINIMUM_DELEGATION_KEY: &str = "new_minimum_delegation"; pub const NEW_MINIMUM_DELEGATION_KEY: &str = "new_minimum_delegation";
pub const NEW_PROFIT_MARGIN_RANGE_KEY: &str = "new_profit_margin_range";
pub const NEW_INTERVAL_OPERATING_COST_RANGE_KEY: &str = "new_interval_operating_cost_range";
pub const NEW_VERSION_WEIGHTS_RANGE_KEY: &str = "new_version_weights_range";
pub const NEW_VERSION_SCORE_FORMULA_PARAMS_KEY: &str = "new_version_score_formula_params";
pub const NYM_NODE_CURRENT_SEMVER_KEY: &str = "new_current_semver";
pub const OLD_REWARDING_VALIDATOR_ADDRESS_KEY: &str = "old_rewarding_validator_address"; pub const OLD_REWARDING_VALIDATOR_ADDRESS_KEY: &str = "old_rewarding_validator_address";
pub const NEW_REWARDING_VALIDATOR_ADDRESS_KEY: &str = "new_rewarding_validator_address"; pub const NEW_REWARDING_VALIDATOR_ADDRESS_KEY: &str = "new_rewarding_validator_address";
@@ -444,73 +440,40 @@ pub fn new_rewarding_validator_address_update_event(old: Addr, new: Addr) -> Eve
.add_attribute(NEW_REWARDING_VALIDATOR_ADDRESS_KEY, new) .add_attribute(NEW_REWARDING_VALIDATOR_ADDRESS_KEY, new)
} }
pub fn new_settings_update_event(update: &ContractStateParamsUpdate) -> Event { pub fn new_settings_update_event(
old_params: &ContractStateParams,
new_params: &ContractStateParams,
) -> Event {
let mut event = Event::new(MixnetEventType::ContractSettingsUpdate); let mut event = Event::new(MixnetEventType::ContractSettingsUpdate);
// check for delegations params updates if old_params.minimum_pledge != new_params.minimum_pledge {
if let Some(delegations_update) = &update.delegations_params { event = event
event.attributes.push(attr( .add_attribute(
NEW_MINIMUM_DELEGATION_KEY, OLD_MINIMUM_PLEDGE_KEY,
delegations_update old_params.minimum_pledge.to_string(),
.minimum_delegation )
.as_ref() .add_attribute(
.map(|d| d.to_string()) NEW_MINIMUM_PLEDGE_KEY,
.unwrap_or("empty".to_string()), new_params.minimum_pledge.to_string(),
)); )
} }
// check for operators params updates if old_params.minimum_delegation != new_params.minimum_delegation {
if let Some(operators_update) = &update.operators_params { if let Some(ref old) = old_params.minimum_delegation {
if let Some(minimum_pledge) = &operators_update.minimum_pledge { event = event.add_attribute(OLD_MINIMUM_DELEGATION_KEY, old.to_string())
event } else {
.attributes event = event.add_attribute(OLD_MINIMUM_DELEGATION_KEY, "None")
.push(attr(NEW_MINIMUM_PLEDGE_KEY, minimum_pledge.to_string()))
} }
if let Some(profit_margin) = &operators_update.profit_margin { if let Some(ref new) = new_params.minimum_delegation {
event event = event.add_attribute(NEW_MINIMUM_DELEGATION_KEY, new.to_string())
.attributes } else {
.push(attr(NEW_PROFIT_MARGIN_RANGE_KEY, profit_margin.to_string())) event = event.add_attribute(NEW_MINIMUM_DELEGATION_KEY, "None")
}
if let Some(interval_operating_cost) = &operators_update.interval_operating_cost {
event.attributes.push(attr(
NEW_INTERVAL_OPERATING_COST_RANGE_KEY,
interval_operating_cost.to_string(),
))
}
}
// check for config score params updates
if let Some(config_score_update) = &update.config_score_params {
if let Some(current_nym_node_semver) = &config_score_update.current_nym_node_semver {
event.attributes.push(attr(
NYM_NODE_CURRENT_SEMVER_KEY,
current_nym_node_semver.to_string(),
))
}
if let Some(version_weights) = &config_score_update.version_weights {
event.attributes.push(attr(
NEW_VERSION_WEIGHTS_RANGE_KEY,
format!("{version_weights:?}"),
))
}
if let Some(version_score_formula_params) =
&config_score_update.version_score_formula_params
{
event.attributes.push(attr(
NEW_VERSION_SCORE_FORMULA_PARAMS_KEY,
format!("{version_score_formula_params:?}"),
))
} }
} }
event event
} }
pub fn new_update_nym_node_semver_event(new_version: &str) -> Event {
Event::new(MixnetEventType::NymNodeSemverUpdate)
.add_attribute(NYM_NODE_CURRENT_SEMVER_KEY, new_version)
}
pub fn new_not_found_node_operator_rewarding_event(interval: Interval, node_id: NodeId) -> Event { pub fn new_not_found_node_operator_rewarding_event(interval: Interval, node_id: NodeId) -> Event {
Event::new(MixnetEventType::NodeRewarding) Event::new(MixnetEventType::NodeRewarding)
.add_attribute( .add_attribute(
@@ -12,11 +12,8 @@ use crate::reward_params::{
ActiveSetUpdate, IntervalRewardParams, IntervalRewardingParamsUpdate, NodeRewardingParameters, ActiveSetUpdate, IntervalRewardParams, IntervalRewardingParamsUpdate, NodeRewardingParameters,
Performance, RewardedSetParams, RewardingParams, WorkFactor, Performance, RewardedSetParams, RewardingParams, WorkFactor,
}; };
use crate::types::NodeId; use crate::types::{ContractStateParams, NodeId};
use crate::{ use crate::{NymNode, RoleAssignment};
ContractStateParamsUpdate, NymNode, OutdatedVersionWeights, RoleAssignment,
VersionScoreFormulaParams,
};
use crate::{OperatingCostRange, ProfitMarginRange}; use crate::{OperatingCostRange, ProfitMarginRange};
use contracts_common::{signing::MessageSignature, IdentityKey, Percent}; use contracts_common::{signing::MessageSignature, IdentityKey, Percent};
use cosmwasm_schema::cw_serde; use cosmwasm_schema::cw_serde;
@@ -50,7 +47,7 @@ use crate::{
PendingIntervalEventResponse, PendingIntervalEventsResponse, PendingIntervalEventResponse, PendingIntervalEventsResponse,
}, },
rewarding::{EstimatedCurrentEpochRewardResponse, PendingRewardResponse}, rewarding::{EstimatedCurrentEpochRewardResponse, PendingRewardResponse},
types::{ContractState, ContractStateParams}, types::ContractState,
}; };
#[cfg(feature = "schema")] #[cfg(feature = "schema")]
use contracts_common::{signing::Nonce, ContractBuildInformation}; use contracts_common::{signing::Nonce, ContractBuildInformation};
@@ -67,14 +64,6 @@ pub struct InstantiateMsg {
pub epoch_duration: Duration, pub epoch_duration: Duration,
pub initial_rewarding_params: InitialRewardingParams, pub initial_rewarding_params: InitialRewardingParams,
pub current_nym_node_version: String,
#[serde(default)]
pub version_score_weights: OutdatedVersionWeights,
#[serde(default)]
pub version_score_params: VersionScoreFormulaParams,
#[serde(default)] #[serde(default)]
pub profit_margin: ProfitMarginRange, pub profit_margin: ProfitMarginRange,
@@ -137,10 +126,7 @@ pub enum ExecuteMsg {
address: String, address: String,
}, },
UpdateContractStateParams { UpdateContractStateParams {
update: ContractStateParamsUpdate, updated_parameters: ContractStateParams,
},
UpdateCurrentNymNodeSemver {
current_version: String,
}, },
UpdateActiveSetDistribution { UpdateActiveSetDistribution {
update: ActiveSetUpdate, update: ActiveSetUpdate,
@@ -309,9 +295,6 @@ impl ExecuteMsg {
ExecuteMsg::UpdateContractStateParams { .. } => { ExecuteMsg::UpdateContractStateParams { .. } => {
"updating mixnet state parameters".into() "updating mixnet state parameters".into()
} }
ExecuteMsg::UpdateCurrentNymNodeSemver { current_version } => {
format!("updating current nym-node semver to {current_version}")
}
ExecuteMsg::UpdateActiveSetDistribution { ExecuteMsg::UpdateActiveSetDistribution {
force_immediately, .. force_immediately, ..
} => format!("updating active set distribution. forced: {force_immediately}"), } => format!("updating active set distribution. forced: {force_immediately}"),
@@ -846,13 +829,6 @@ pub enum QueryMsg {
#[cw_serde] #[cw_serde]
pub struct MigrateMsg { pub struct MigrateMsg {
pub unsafe_skip_state_updates: Option<bool>,
pub vesting_contract_address: Option<String>, pub vesting_contract_address: Option<String>,
pub current_nym_node_semver: String, pub unsafe_skip_state_updates: Option<bool>,
#[serde(default)]
pub version_score_weights: OutdatedVersionWeights,
#[serde(default)]
pub version_score_params: VersionScoreFormulaParams,
} }
@@ -4,8 +4,8 @@
use crate::nym_node::Role; use crate::nym_node::Role;
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::{Addr, Uint128}; use cosmwasm_std::{Addr, Uint128};
use cosmwasm_std::{Coin, Decimal};
use std::fmt::{Display, Formatter}; use std::fmt::{Display, Formatter};
// type aliases for better reasoning about available data // type aliases for better reasoning about available data
@@ -161,156 +161,19 @@ pub struct ContractState {
/// Contract parameters that could be adjusted in a transaction by the contract admin. /// Contract parameters that could be adjusted in a transaction by the contract admin.
#[cw_serde] #[cw_serde]
pub struct ContractStateParams { pub struct ContractStateParams {
/// Parameters to do with delegations.
pub delegations_params: DelegationsParams,
/// Parameters to do with node operators.
pub operators_params: OperatorsParams,
/// Parameters to do with the config score
pub config_score_params: ConfigScoreParams,
}
#[cw_serde]
pub struct ContractStateParamsUpdate {
pub delegations_params: Option<DelegationsParams>,
pub operators_params: Option<OperatorsParamsUpdate>,
pub config_score_params: Option<ConfigScoreParamsUpdate>,
}
impl ContractStateParamsUpdate {
pub fn contains_updates(&self) -> bool {
self.delegations_params.is_some()
|| self.operators_params.is_some()
|| self.config_score_params.is_some()
}
}
#[cw_serde]
pub struct DelegationsParams {
/// Minimum amount a delegator must stake in orders for his delegation to get accepted. /// Minimum amount a delegator must stake in orders for his delegation to get accepted.
pub minimum_delegation: Option<Coin>, pub minimum_delegation: Option<Coin>,
}
#[cw_serde]
pub struct OperatorsParams {
/// Minimum amount a node must pledge to get into the system. /// Minimum amount a node must pledge to get into the system.
pub minimum_pledge: Coin, pub minimum_pledge: Coin,
/// Defines the allowed profit margin range of operators. /// Defines the allowed profit margin range of operators.
/// default: 0% - 100% /// default: 0% - 100%
#[serde(default)]
pub profit_margin: ProfitMarginRange, pub profit_margin: ProfitMarginRange,
/// Defines the allowed interval operating cost range of operators. /// Defines the allowed interval operating cost range of operators.
/// default: 0 - 1'000'000'000'000'000 (1 Billion native tokens - the total supply) /// default: 0 - 1'000'000'000'000'000 (1 Billion native tokens - the total supply)
#[serde(default)]
pub interval_operating_cost: OperatingCostRange, pub interval_operating_cost: OperatingCostRange,
} }
#[cw_serde]
pub struct OperatorsParamsUpdate {
pub minimum_pledge: Option<Coin>,
pub profit_margin: Option<ProfitMarginRange>,
pub interval_operating_cost: Option<OperatingCostRange>,
}
impl OperatorsParamsUpdate {
pub fn contains_updates(&self) -> bool {
self.minimum_pledge.is_some()
|| self.profit_margin.is_some()
|| self.interval_operating_cost.is_some()
}
}
#[cw_serde]
pub struct ConfigScoreParams {
/// Current version of the nym node that is going to be used for determining the version score of a node.
/// note: value stored here is pre-validated `semver::Version`
pub current_nym_node_semver: String,
/// Defines weights for calculating numbers of versions behind the current release.
pub version_weights: OutdatedVersionWeights,
/// Defines the parameters of the formula for calculating the version score
pub version_score_formula_params: VersionScoreFormulaParams,
}
impl ConfigScoreParams {
// SAFETY: the value stored in the contract is always valid
#[allow(clippy::unwrap_used)]
pub fn unchecked_nym_node_version(&self) -> semver::Version {
self.current_nym_node_semver.parse().unwrap()
}
pub fn versions_behind(&self, node_semver: &semver::Version) -> u32 {
let expected = self.unchecked_nym_node_version();
let major_diff = (node_semver.major as i64 - expected.major as i64).unsigned_abs() as u32;
let minor_diff = (node_semver.minor as i64 - expected.minor as i64).unsigned_abs() as u32;
let patch_diff = (node_semver.patch as i64 - expected.patch as i64).unsigned_abs() as u32;
let prerelease_diff = if node_semver.pre == expected.pre {
0
} else {
1
};
major_diff * self.version_weights.major
+ minor_diff * self.version_weights.minor
+ patch_diff * self.version_weights.patch
+ prerelease_diff * self.version_weights.prerelease
}
}
/// Defines weights for calculating numbers of versions behind the current release.
#[cw_serde]
#[derive(Copy)]
pub struct OutdatedVersionWeights {
pub major: u32,
pub minor: u32,
pub patch: u32,
pub prerelease: u32,
}
impl Default for OutdatedVersionWeights {
fn default() -> Self {
OutdatedVersionWeights {
major: 100,
minor: 10,
patch: 1,
prerelease: 1,
}
}
}
/// Given the formula of version_score = penalty ^ (num_versions_behind ^ penalty_scaling)
/// define the relevant parameters
#[cw_serde]
#[derive(Copy)]
pub struct VersionScoreFormulaParams {
pub penalty: Decimal,
pub penalty_scaling: Decimal,
}
impl Default for VersionScoreFormulaParams {
fn default() -> Self {
#[allow(clippy::unwrap_used)]
VersionScoreFormulaParams {
penalty: "0.8".parse().unwrap(),
penalty_scaling: "2.0".parse().unwrap(),
}
}
}
#[cw_serde]
pub struct ConfigScoreParamsUpdate {
pub current_nym_node_semver: Option<String>,
pub version_weights: Option<OutdatedVersionWeights>,
pub version_score_formula_params: Option<VersionScoreFormulaParams>,
}
impl ConfigScoreParamsUpdate {
pub fn contains_updates(&self) -> bool {
self.current_nym_node_semver.is_some()
|| self.version_weights.is_some()
|| self.version_score_formula_params.is_some()
}
}
@@ -21,7 +21,7 @@ pub mod error;
mod helpers; mod helpers;
mod state; mod state;
pub const TIME_RANGE_SEC: i64 = 30; const TIME_RANGE_SEC: i64 = 30;
pub struct EcashManager<S> { pub struct EcashManager<S> {
shared_state: SharedState<S>, shared_state: SharedState<S>,
+2 -2
View File
@@ -6,7 +6,7 @@ use std::sync::Arc;
use time::{Date, OffsetDateTime}; use time::{Date, OffsetDateTime};
use tracing::*; use tracing::*;
use nym_credentials::ecash::utils::{cred_exp_date, ecash_today, EcashTime}; use nym_credentials::ecash::utils::{ecash_today, EcashTime};
use nym_credentials_interface::{Bandwidth, ClientTicket, TicketType}; use nym_credentials_interface::{Bandwidth, ClientTicket, TicketType};
use nym_gateway_requests::models::CredentialSpendingRequest; use nym_gateway_requests::models::CredentialSpendingRequest;
use nym_gateway_storage::Storage; use nym_gateway_storage::Storage;
@@ -131,7 +131,7 @@ impl<S: Storage + Clone + 'static> CredentialVerifier<S> {
let bandwidth = Bandwidth::ticket_amount(credential_type.into()); let bandwidth = Bandwidth::ticket_amount(credential_type.into());
self.bandwidth_storage_manager self.bandwidth_storage_manager
.increase_bandwidth(bandwidth, cred_exp_date()) .increase_bandwidth(bandwidth, spend_date)
.await?; .await?;
Ok(self Ok(self
+2 -2
View File
@@ -104,8 +104,8 @@ impl PersistentStatsStorage {
.await?) .await?)
} }
pub async fn get_unique_users(&self, date: Date) -> Result<Vec<String>, StatsStorageError> { pub async fn get_unique_users_count(&self, date: Date) -> Result<i32, StatsStorageError> {
Ok(self.session_manager.get_unique_users(date).await?) Ok(self.session_manager.get_unique_users_count(date).await?)
} }
pub async fn delete_unique_users(&self, before_date: Date) -> Result<(), StatsStorageError> { pub async fn delete_unique_users(&self, before_date: Date) -> Result<(), StatsStorageError> {
+6 -5
View File
@@ -71,13 +71,14 @@ impl SessionManager {
Ok(()) Ok(())
} }
pub(crate) async fn get_unique_users(&self, date: Date) -> Result<Vec<String>> { pub(crate) async fn get_unique_users_count(&self, date: Date) -> Result<i32> {
sqlx::query_scalar!( Ok(sqlx::query!(
"SELECT client_address as count FROM sessions_unique_users WHERE day = ?", "SELECT COUNT(*) as count FROM sessions_unique_users WHERE day = ?",
date date
) )
.fetch_all(&self.connection_pool) .fetch_one(&self.connection_pool)
.await .await?
.count)
} }
pub(crate) async fn delete_unique_users(&self, before_date: Date) -> Result<()> { pub(crate) async fn delete_unique_users(&self, before_date: Date) -> Result<()> {
+10 -12
View File
@@ -534,19 +534,17 @@ where
} }
if res.status().is_success() { if res.status().is_success() {
#[cfg(debug_assertions)] let text = res.text().await?;
{ match serde_json::from_str(&text) {
let text = res.text().await.inspect_err(|err| { Ok(res) => Ok(res),
tracing::error!("Couldn't even get response text: {err}"); Err(source) => {
})?; #[cfg(debug_assertions)]
tracing::trace!("Result:\n{:#?}", text); {
tracing::trace!("Result:\n{:#?}", text);
serde_json::from_str(&text) }
.map_err(|err| HttpClientError::GenericRequestFailure(err.to_string())) Err(HttpClientError::ResponseDeserialisationFailure { source })
}
} }
#[cfg(not(debug_assertions))]
Ok(res.json().await?)
} else if res.status() == StatusCode::NOT_FOUND { } else if res.status() == StatusCode::NOT_FOUND {
Err(HttpClientError::NotFound) Err(HttpClientError::NotFound)
} else { } else {
+1 -1
View File
@@ -248,7 +248,7 @@ mod tests {
data: IpPacketRequestData::StaticConnect( data: IpPacketRequestData::StaticConnect(
StaticConnectRequest { StaticConnectRequest {
request_id: 123, request_id: 123,
ips: IpPair::new(Ipv4Addr::from_str("10.0.0.1").unwrap(), Ipv6Addr::from_str("fc00::1").unwrap()), ips: IpPair::new(Ipv4Addr::from_str("10.0.0.1").unwrap(), Ipv6Addr::from_str("2001:db8:a160::1").unwrap()),
reply_to: Recipient::try_from_base58_string("D1rrpsysCGCYXy9saP8y3kmNpGtJZUXN9SvFoUcqAsM9.9Ssso1ea5NfkbMASdiseDSjTN1fSWda5SgEVjdSN4CvV@GJqd3ZxpXWSNxTfx7B1pPtswpetH4LnJdFeLeuY5KUuN").unwrap(), reply_to: Recipient::try_from_base58_string("D1rrpsysCGCYXy9saP8y3kmNpGtJZUXN9SvFoUcqAsM9.9Ssso1ea5NfkbMASdiseDSjTN1fSWda5SgEVjdSN4CvV@GJqd3ZxpXWSNxTfx7B1pPtswpetH4LnJdFeLeuY5KUuN").unwrap(),
reply_to_hops: None, reply_to_hops: None,
reply_to_avg_mix_delays: None, reply_to_avg_mix_delays: None,
+1 -1
View File
@@ -429,7 +429,7 @@ mod tests {
SignedStaticConnectRequest { SignedStaticConnectRequest {
request: StaticConnectRequest { request: StaticConnectRequest {
request_id: 123, request_id: 123,
ips: IpPair::new(Ipv4Addr::from_str("10.0.0.1").unwrap(), Ipv6Addr::from_str("fc00::1").unwrap()), ips: IpPair::new(Ipv4Addr::from_str("10.0.0.1").unwrap(), Ipv6Addr::from_str("2001:db8:a160::1").unwrap()),
reply_to: Recipient::try_from_base58_string("D1rrpsysCGCYXy9saP8y3kmNpGtJZUXN9SvFoUcqAsM9.9Ssso1ea5NfkbMASdiseDSjTN1fSWda5SgEVjdSN4CvV@GJqd3ZxpXWSNxTfx7B1pPtswpetH4LnJdFeLeuY5KUuN").unwrap(), reply_to: Recipient::try_from_base58_string("D1rrpsysCGCYXy9saP8y3kmNpGtJZUXN9SvFoUcqAsM9.9Ssso1ea5NfkbMASdiseDSjTN1fSWda5SgEVjdSN4CvV@GJqd3ZxpXWSNxTfx7B1pPtswpetH4LnJdFeLeuY5KUuN").unwrap(),
reply_to_hops: None, reply_to_hops: None,
reply_to_avg_mix_delays: None, reply_to_avg_mix_delays: None,
+16 -7
View File
@@ -14,6 +14,7 @@ use nym_task::TaskClient;
use rand::seq::SliceRandom; use rand::seq::SliceRandom;
use rand::thread_rng; use rand::thread_rng;
use std::net::SocketAddr; use std::net::SocketAddr;
use std::net::ToSocketAddrs;
use std::sync::Arc; use std::sync::Arc;
use std::time::Duration; use std::time::Duration;
use tokio::task::JoinHandle; use tokio::task::JoinHandle;
@@ -312,7 +313,7 @@ impl VerlocMeasurer {
info!("Starting verloc measurements"); info!("Starting verloc measurements");
// TODO: should we also measure gateways? // TODO: should we also measure gateways?
let all_mixes = match self.validator_client.get_all_described_nodes().await { let all_mixes = match self.validator_client.get_cached_mixnodes().await {
Ok(nodes) => nodes, Ok(nodes) => nodes,
Err(err) => { Err(err) => {
error!( error!(
@@ -331,14 +332,22 @@ impl VerlocMeasurer {
// we only care about address and identity // we only care about address and identity
let tested_nodes = all_mixes let tested_nodes = all_mixes
.into_iter() .into_iter()
.filter(|n| n.description.declared_role.mixnode)
.filter_map(|node| { .filter_map(|node| {
// try to parse the identity and host let mix_node = node.bond_information.mix_node;
let node_identity = node.ed25519_identity_key(); // check if the node has sufficient version to be able to understand the packets
let node_version = parse_version(&mix_node.version).ok()?;
if node_version < self.config.minimum_compatible_node_version {
return None;
}
let ip = node.description.host_information.ip_address.first()?; // try to parse the identity and host
let verloc_port = node.description.verloc_port(); let node_identity =
let verloc_host = SocketAddr::new(*ip, verloc_port); identity::PublicKey::from_base58_string(mix_node.identity_key).ok()?;
let verloc_host = (&*mix_node.host, mix_node.verloc_port)
.to_socket_addrs()
.ok()?
.next()?;
// TODO: possible problem in the future, this does name resolution and theoretically // TODO: possible problem in the future, this does name resolution and theoretically
// if a lot of nodes maliciously mis-configured themselves, it might take a while to resolve them all // if a lot of nodes maliciously mis-configured themselves, it might take a while to resolve them all
-4
View File
@@ -23,7 +23,3 @@ default = ["env", "network"]
env = ["dotenvy", "log"] env = ["dotenvy", "log"]
network = ["schemars", "serde", "url"] network = ["schemars", "serde", "url"]
utoipa = [ "dep:utoipa" ] utoipa = [ "dep:utoipa" ]
[build-dependencies]
regex = { workspace = true }
cargo_metadata = { version = "0.18" }
-85
View File
@@ -1,85 +0,0 @@
use cargo_metadata::MetadataCommand;
use regex::Regex;
use std::{collections::HashMap, fs, path::PathBuf};
/// Sync variable values defined in code with .env file
fn main() {
let source_of_truth = include_str!("src/mainnet.rs");
let mut output_path = workspace_root();
output_path.push("envs");
output_path.push("mainnet.env");
println!("{}", output_path.display());
let variables_to_track = [
"NETWORK_NAME",
"BECH32_PREFIX",
"MIXNET_CONTRACT_ADDRESS",
"VESTING_CONTRACT_ADDRESS",
"GROUP_CONTRACT_ADDRESS",
"ECASH_CONTRACT_ADDRESS",
"MULTISIG_CONTRACT_ADDRESS",
"COCONUT_DKG_CONTRACT_ADDRESS",
"REWARDING_VALIDATOR_ADDRESS",
"NYM_API",
"NYXD_WS",
"EXPLORER_API",
"NYM_VPN_API",
];
let mut replace_with = HashMap::new();
for var in variables_to_track {
// if script fails, debug with `cargo check -vv``
println!("Looking for {}", var);
// read pattern that looks like:
// <var>: &str = "<whatever is between quotes>"
let pattern = format!(r#"{}: &str\s*=\s*"([^"]*)""#, regex::escape(var));
let re = Regex::new(&pattern).unwrap();
let value = re
.captures(source_of_truth)
.and_then(|caps| caps.get(1).map(|match_| match_.as_str().to_string()))
.expect("Couldn't find var in source file");
println!("Storing {}={}", var, value);
replace_with.insert(var, value);
}
let mut contents = fs::read_to_string(&output_path).unwrap();
for (var, value) in replace_with {
// match a pattern that looks like:
// <var> = <value>
// where `<var>` is a variable name inserted into search pattern
let pattern = format!(r#"{}\s*=\s*([^\n]*)"#, regex::escape(var));
// replace matched pattern with
// <var>=<value>
let re = Regex::new(&pattern).unwrap();
contents = re
.replace(&contents, |_: &regex::Captures| {
format!(r#"{}={}"#, var, value)
})
.to_string();
}
println!("File contents to write:\n{}", contents);
if output_path.exists() {
fs::write(output_path, contents).unwrap();
} else {
panic!("{} doesn't exist", output_path.display());
}
}
fn workspace_root() -> PathBuf {
let metadata = MetadataCommand::new()
.exec()
.expect("Failed to get cargo metadata");
metadata
.workspace_root
.into_std_path_buf()
.canonicalize()
.expect("Failed to canonicalize path")
}
+3 -5
View File
@@ -45,15 +45,13 @@ pub mod nyx {
} }
pub mod wireguard { pub mod wireguard {
use std::net::{Ipv4Addr, Ipv6Addr}; use std::net::{IpAddr, Ipv4Addr};
pub const WG_PORT: u16 = 51822; pub const WG_PORT: u16 = 51822;
// The interface used to route traffic // The interface used to route traffic
pub const WG_TUN_BASE_NAME: &str = "nymwg"; pub const WG_TUN_BASE_NAME: &str = "nymwg";
pub const WG_TUN_DEVICE_ADDRESS: &str = "10.1.0.1"; pub const WG_TUN_DEVICE_ADDRESS: &str = "10.1.0.1";
pub const WG_TUN_DEVICE_IP_ADDRESS_V4: Ipv4Addr = Ipv4Addr::new(10, 1, 0, 1); pub const WG_TUN_DEVICE_IP_ADDRESS: IpAddr = IpAddr::V4(Ipv4Addr::new(10, 1, 0, 1));
pub const WG_TUN_DEVICE_NETMASK_V4: u8 = 16; pub const WG_TUN_DEVICE_NETMASK: &str = "255.255.255.0";
pub const WG_TUN_DEVICE_IP_ADDRESS_V6: Ipv6Addr = Ipv6Addr::new(0xfc01, 0, 0, 0, 0, 0, 0, 0x1); // fc01::1
pub const WG_TUN_DEVICE_NETMASK_V6: u8 = 112;
} }
-1
View File
@@ -25,7 +25,6 @@ pub const NYXD_WEBSOCKET: &str = "NYXD_WS";
pub const EXPLORER_API: &str = "EXPLORER_API"; pub const EXPLORER_API: &str = "EXPLORER_API";
pub const EXIT_POLICY_URL: &str = "EXIT_POLICY"; pub const EXIT_POLICY_URL: &str = "EXIT_POLICY";
pub const NYM_VPN_API: &str = "NYM_VPN_API"; pub const NYM_VPN_API: &str = "NYM_VPN_API";
pub const CLIENT_STATS_COLLECTION_PROVIDER: &str = "CLIENT_STATS_COLLECTION_PROVIDER";
pub const DKG_TIME_CONFIGURATION: &str = "DKG_TIME_CONFIGURATION"; pub const DKG_TIME_CONFIGURATION: &str = "DKG_TIME_CONFIGURATION";
-6
View File
@@ -28,9 +28,3 @@ impl From<ConnectionError> for Socks5ClientCoreError {
} }
} }
} }
impl nym_task::TaskStatusEvent for Socks5ClientCoreError {
fn as_any(&self) -> &dyn std::any::Any {
self
}
}
+2 -1
View File
@@ -23,7 +23,8 @@ use nym_client_core::init::types::GatewaySetup;
use nym_credential_storage::storage::Storage as CredentialStorage; use nym_credential_storage::storage::Storage as CredentialStorage;
use nym_sphinx::addressing::clients::Recipient; use nym_sphinx::addressing::clients::Recipient;
use nym_sphinx::params::PacketType; use nym_sphinx::params::PacketType;
use nym_task::{TaskClient, TaskHandle, TaskStatus}; use nym_task::manager::TaskStatus;
use nym_task::{TaskClient, TaskHandle};
use anyhow::anyhow; use anyhow::anyhow;
use nym_validator_client::UserAgent; use nym_validator_client::UserAgent;
-11
View File
@@ -11,18 +11,7 @@ license.workspace = true
[dependencies] [dependencies]
futures = { workspace = true } futures = { workspace = true }
log = { workspace = true }
sysinfo = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
sha2 = { workspace = true }
thiserror = { workspace = true }
time = { workspace = true } time = { workspace = true }
tokio = { workspace = true }
si-scale = { workspace = true }
nym-crypto = { path = "../crypto" }
nym-sphinx = { path = "../nymsphinx" } nym-sphinx = { path = "../nymsphinx" }
nym-credentials-interface = { path = "../credentials-interface" } nym-credentials-interface = { path = "../credentials-interface" }
nym-metrics = { path = "../nym-metrics" }
nym-task = { path = "../task" }
@@ -1,67 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use super::ClientStatsEvents;
use nym_credentials_interface::TicketType;
use serde::{Deserialize, Serialize};
#[derive(Default, Debug, Clone, Serialize, Deserialize)]
pub(crate) struct ConnectionStats {
//tickets
mixnet_entry_spent: u32,
vpn_entry_spent: u32,
mixnet_exit_spent: u32,
vpn_exit_spent: u32,
//country_connection
wg_exit_country_code: String,
mix_exit_country_code: String,
}
/// Event space for Nym API statistics tracking
#[derive(Debug)]
pub enum ConnectionStatsEvent {
/// ecash ticket was spend
TicketSpent {
typ: TicketType,
amount: u32,
},
WgCountry(String),
MixCountry(String),
}
impl From<ConnectionStatsEvent> for ClientStatsEvents {
fn from(event: ConnectionStatsEvent) -> ClientStatsEvents {
ClientStatsEvents::Connection(event)
}
}
/// Nym API statistics tracking object
#[derive(Default)]
pub struct ConnectionStatsControl {
// Keep track of packet statistics over time
stats: ConnectionStats,
}
impl ConnectionStatsControl {
pub(crate) fn handle_event(&mut self, event: ConnectionStatsEvent) {
match event {
ConnectionStatsEvent::TicketSpent { typ, amount } => match typ {
TicketType::V1MixnetEntry => self.stats.mixnet_entry_spent += amount,
TicketType::V1MixnetExit => self.stats.mixnet_exit_spent += amount,
TicketType::V1WireguardEntry => self.stats.vpn_entry_spent += amount,
TicketType::V1WireguardExit => self.stats.vpn_exit_spent += amount,
},
ConnectionStatsEvent::WgCountry(cc) => {
self.stats.wg_exit_country_code = cc;
}
ConnectionStatsEvent::MixCountry(cc) => {
self.stats.mix_exit_country_code = cc;
}
}
}
pub(crate) fn report(&self) -> ConnectionStats {
self.stats.clone()
}
}
@@ -1,83 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
//! # Gateway Connection statistics
//!
//! Metrics collected by the client while establishing and maintaining connections to the gateway.
use super::ClientStatsEvents;
use std::collections::VecDeque;
use nym_metrics::{inc, inc_by};
use serde::{Deserialize, Serialize};
#[derive(Default, Debug, Clone, Serialize, Deserialize)]
pub(crate) struct GatewayStats {
// Sent
real_packets_sent: u64,
real_packets_sent_size: usize,
/// failed connection statistics
failures: VecDeque<()>, // TODO
}
impl GatewayStats {
fn handle(&mut self, event: GatewayStatsEvent) {
match event {
GatewayStatsEvent::RealPacketSent(packet_size) => {
self.real_packets_sent += 1;
self.real_packets_sent_size += packet_size;
inc!("real_packets_sent");
inc_by!("real_packets_sent_size", packet_size);
}
}
}
fn summary(&self) -> (String, String) {
(
format!("packets sent: {}", self.real_packets_sent),
"packets received: todo".to_owned(),
)
}
}
impl From<GatewayStatsEvent> for ClientStatsEvents {
fn from(event: GatewayStatsEvent) -> ClientStatsEvents {
ClientStatsEvents::GatewayConn(event)
}
}
/// Event space for Gateway Connection Events
#[derive(Debug)]
pub enum GatewayStatsEvent {
/// The real packets sent. Recall that acks are sent by the gateway, so it's not included here.
RealPacketSent(usize),
}
/// Gateway Statistics Tracking
#[derive(Default)]
pub struct GatewayStatsControl {
// Keep track of packet statistics over time
stats: GatewayStats,
}
impl GatewayStatsControl {
pub(crate) fn handle_event(&mut self, event: GatewayStatsEvent) {
self.stats.handle(event)
}
pub(crate) fn report(&self) -> GatewayStats {
self.stats.clone()
}
pub(crate) fn local_report(&self) {
self.report_counters();
}
fn report_counters(&self) {
log::trace!("packet statistics: {:?}", &self.stats);
let (summary_sent, summary_recv) = self.stats.summary();
log::debug!("{}", summary_sent);
log::debug!("{}", summary_recv);
}
}
-144
View File
@@ -1,144 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::report::{ClientStatsReport, OsInformation};
use nym_task::TaskClient;
use time::{OffsetDateTime, Time};
use tokio::sync::mpsc::UnboundedSender;
/// Active gateway connection statistics.
pub mod gateway_conn_statistics;
/// Nym API connection statistics.
pub mod nym_api_statistics;
/// Packet count based statistics.
pub mod packet_statistics;
pub mod connection;
/// Channel receiving generic stats events to be used by a statistics aggregator.
pub type ClientStatsReceiver = tokio::sync::mpsc::UnboundedReceiver<ClientStatsEvents>;
/// Channel allowing generic statistics events to be reported to a stats event aggregator
#[derive(Clone)]
pub struct ClientStatsSender {
stats_tx: Option<UnboundedSender<ClientStatsEvents>>,
}
impl ClientStatsSender {
/// Create a new statistics Sender
pub fn new(stats_tx: Option<UnboundedSender<ClientStatsEvents>>) -> Self {
ClientStatsSender { stats_tx }
}
/// Report a statistics event using the sender.
pub fn report(&self, event: ClientStatsEvents) {
if let Some(tx) = &self.stats_tx {
if let Err(err) = tx.send(event) {
log::error!("Failed to send stats event: {:?}", err);
}
}
}
}
/// Client Statistics events (static for now)
pub enum ClientStatsEvents {
/// Packet count events
PacketStatistics(packet_statistics::PacketStatisticsEvent),
/// Gateway Connection events
GatewayConn(gateway_conn_statistics::GatewayStatsEvent),
/// Nym API connection events
NymApi(nym_api_statistics::NymApiStatsEvent),
/// Credential events
Connection(connection::ConnectionStatsEvent),
}
/// Controls stats event handling and reporting
pub struct ClientStatsController {
//static infos
last_update_time: OffsetDateTime,
client_id: String,
client_type: String,
os_information: OsInformation,
// stats collection modules
packet_stats: packet_statistics::PacketStatisticsControl,
gateway_conn_stats: gateway_conn_statistics::GatewayStatsControl,
nym_api_stats: nym_api_statistics::NymApiStatsControl,
connection_stats: connection::ConnectionStatsControl,
}
impl ClientStatsController {
/// Creates a ClientStatsController given a client_id
pub fn new(client_id: String, client_type: String) -> Self {
ClientStatsController {
last_update_time: ClientStatsController::get_update_time(),
client_id,
client_type,
os_information: OsInformation::new(),
packet_stats: Default::default(),
gateway_conn_stats: Default::default(),
nym_api_stats: Default::default(),
connection_stats: Default::default(),
}
}
/// Returns a static ClientStatsReport that can be sent somewhere
pub fn build_report(&self) -> ClientStatsReport {
ClientStatsReport {
last_update_time: self.last_update_time,
client_id: self.client_id.clone(),
client_type: self.client_type.clone(),
os_information: self.os_information.clone(),
packet_stats: self.packet_stats.report(),
gateway_conn_stats: self.gateway_conn_stats.report(),
nym_api_stats: self.nym_api_stats.report(),
connection_stats: self.connection_stats.report(),
}
}
/// Handle and dispatch incoming stats event
pub fn handle_event(&mut self, stats_event: ClientStatsEvents) {
match stats_event {
ClientStatsEvents::PacketStatistics(event) => self.packet_stats.handle_event(event),
ClientStatsEvents::GatewayConn(event) => self.gateway_conn_stats.handle_event(event),
ClientStatsEvents::NymApi(event) => self.nym_api_stats.handle_event(event),
ClientStatsEvents::Connection(event) => self.connection_stats.handle_event(event),
}
}
/// Reset the metrics to their initial state.
///
/// Used to periodically reset the metrics in accordance with periodic reporting strategy
pub fn reset(&mut self) {
self.nym_api_stats = Default::default();
self.gateway_conn_stats = Default::default();
self.connection_stats = Default::default();
//no periodic reset for packet stats
self.last_update_time = ClientStatsController::get_update_time();
}
/// snapshot the current state of the metrics for module that needs it
pub fn snapshot(&mut self) {
//no snapshot for gateway_conn_stats
//no snapshot for nym_api_stats
self.packet_stats.snapshot();
}
pub fn local_report(&mut self, task_client: &mut TaskClient) {
self.packet_stats.local_report(task_client);
self.gateway_conn_stats.local_report();
self.nym_api_stats.local_report();
}
fn get_update_time() -> OffsetDateTime {
let now = OffsetDateTime::now_utc();
#[allow(clippy::unwrap_used)]
//Safety : 0 is always a valid number of seconds, hours and minutes comes from a valid source
let new_time = Time::from_hms(now.hour(), now.minute(), 0).unwrap();
//allows a bigger anonymity by hiding exact sending time
now.replace_time(new_time)
}
}
@@ -1,83 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
//! # API Connection statistics
//!
//! Metrics collected by the client while attempting to pull config from the API.
use super::ClientStatsEvents;
use std::collections::VecDeque;
use nym_metrics::{inc, inc_by};
use serde::{Deserialize, Serialize};
#[derive(Default, Debug, Clone, Serialize, Deserialize)]
pub(crate) struct NymApiStats {
// Sent
real_packets_sent: u64,
real_packets_sent_size: usize,
/// API connection failure statistics
failures: VecDeque<()>, // TODO
}
impl NymApiStats {
fn handle(&mut self, event: NymApiStatsEvent) {
match event {
NymApiStatsEvent::RealPacketSent(packet_size) => {
self.real_packets_sent += 1;
self.real_packets_sent_size += packet_size;
inc!("real_packets_sent");
inc_by!("real_packets_sent_size", packet_size);
}
}
}
fn summary(&self) -> (String, String) {
(
format!("packets sent: {}", self.real_packets_sent,),
"packets received: todo".to_owned(),
)
}
}
/// Event space for Nym API statistics tracking
#[derive(Debug)]
pub enum NymApiStatsEvent {
/// The real packets sent. Recall that acks are sent by the Api, so it's not included here.
RealPacketSent(usize),
}
impl From<NymApiStatsEvent> for ClientStatsEvents {
fn from(event: NymApiStatsEvent) -> ClientStatsEvents {
ClientStatsEvents::NymApi(event)
}
}
/// Nym API statistics tracking object
#[derive(Default)]
pub struct NymApiStatsControl {
// Keep track of packet statistics over time
stats: NymApiStats,
}
impl NymApiStatsControl {
pub(crate) fn handle_event(&mut self, event: NymApiStatsEvent) {
self.stats.handle(event)
}
pub(crate) fn report(&self) -> NymApiStats {
self.stats.clone()
}
pub(crate) fn local_report(&self) {
self.report_counters();
}
fn report_counters(&self) {
log::trace!("packet statistics: {:?}", &self.stats);
let (summary_sent, summary_recv) = self.stats.summary();
log::debug!("{}", summary_sent);
log::debug!("{}", summary_recv);
}
}
-15
View File
@@ -1,15 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use thiserror::Error;
/// Error types occurring while processing statistics events and reporting.
#[derive(Debug, Error)]
#[allow(missing_docs)]
pub enum StatsError {
#[error("Failed to (de)serialize stats report : {0}")]
ReportJsonSerialization(#[from] serde_json::Error),
}
/// Result of a statistics operation.
pub type Result<T> = core::result::Result<T, StatsError>;
+54
View File
@@ -0,0 +1,54 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
use futures::channel::mpsc;
use nym_credentials_interface::TicketType;
use nym_sphinx::DestinationAddressBytes;
use time::OffsetDateTime;
pub type StatsEventSender = mpsc::UnboundedSender<StatsEvent>;
pub type StatsEventReceiver = mpsc::UnboundedReceiver<StatsEvent>;
pub enum StatsEvent {
SessionStatsEvent(SessionEvent),
}
impl StatsEvent {
pub fn new_session_start(client: DestinationAddressBytes) -> StatsEvent {
StatsEvent::SessionStatsEvent(SessionEvent::SessionStart {
start_time: OffsetDateTime::now_utc(),
client,
})
}
pub fn new_session_stop(client: DestinationAddressBytes) -> StatsEvent {
StatsEvent::SessionStatsEvent(SessionEvent::SessionStop {
stop_time: OffsetDateTime::now_utc(),
client,
})
}
pub fn new_ecash_ticket(
client: DestinationAddressBytes,
ticket_type: TicketType,
) -> StatsEvent {
StatsEvent::SessionStatsEvent(SessionEvent::EcashTicket {
ticket_type,
client,
})
}
}
pub enum SessionEvent {
SessionStart {
start_time: OffsetDateTime,
client: DestinationAddressBytes,
},
SessionStop {
stop_time: OffsetDateTime,
client: DestinationAddressBytes,
},
EcashTicket {
ticket_type: TicketType,
client: DestinationAddressBytes,
},
}
-89
View File
@@ -1,89 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use nym_credentials_interface::TicketType;
use nym_sphinx::DestinationAddressBytes;
use time::OffsetDateTime;
/// Channel for receiving incoming Stats events
pub type GatewayStatsReceiver = tokio::sync::mpsc::UnboundedReceiver<GatewayStatsEvent>;
/// Channel allowing for generic statistics events to be reported to a stats event aggregator.
#[derive(Clone)]
pub struct GatewayStatsReporter {
stats_tx: tokio::sync::mpsc::UnboundedSender<GatewayStatsEvent>,
}
impl GatewayStatsReporter {
/// Construct a new gateway statistics event reporter
pub fn new(stats_tx: tokio::sync::mpsc::UnboundedSender<GatewayStatsEvent>) -> Self {
Self { stats_tx }
}
/// Report a gateway statistivs event using the reporter
pub fn report(&self, event: GatewayStatsEvent) {
self.stats_tx.send(event).unwrap_or_else(|err| {
log::error!("Failed to report gateway stat event : {err}");
});
}
}
/// Gateway Statistics events
pub enum GatewayStatsEvent {
/// Events in the lifecycle of an established client tunnel
SessionStatsEvent(SessionEvent),
}
impl GatewayStatsEvent {
/// A new session between this gateway and the client remote has successfully opened
pub fn new_session_start(client: DestinationAddressBytes) -> GatewayStatsEvent {
GatewayStatsEvent::SessionStatsEvent(SessionEvent::SessionStart {
start_time: OffsetDateTime::now_utc(),
client,
})
}
/// An existing session with the client remote has ended
pub fn new_session_stop(client: DestinationAddressBytes) -> GatewayStatsEvent {
GatewayStatsEvent::SessionStatsEvent(SessionEvent::SessionStop {
stop_time: OffsetDateTime::now_utc(),
client,
})
}
/// A new ecash ticket has been added / requested
pub fn new_ecash_ticket(
client: DestinationAddressBytes,
ticket_type: TicketType,
) -> GatewayStatsEvent {
GatewayStatsEvent::SessionStatsEvent(SessionEvent::EcashTicket {
ticket_type,
client,
})
}
}
/// Events in the lifecycle of an established client tunnel
pub enum SessionEvent {
/// A new session between this gateway and the client remote has successfully opened
SessionStart {
/// The timestamp of the session open event
start_time: OffsetDateTime,
/// Address of the remote client opening the connection
client: DestinationAddressBytes,
},
/// An existing session with the client remote has ended
SessionStop {
/// Timestamp of the session end event
stop_time: OffsetDateTime,
/// Address of the remote client opening the connection
client: DestinationAddressBytes,
},
/// A new ecash ticket has been added / requested
EcashTicket {
/// Type of ecash ticket that has been created as part of the session
ticket_type: TicketType,
/// Address of the remote client opening the connection
client: DestinationAddressBytes,
},
}

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