Compare commits

..

4 Commits

Author SHA1 Message Date
Bogdan-Ștefan Neacşu 8d305c29eb Gateway peer fixes (#4985)
* Create bandwidth entry

* Remove mismatch possibilities
2024-10-18 12:49:31 +03:00
Bogdan-Ștefan Neacşu e057f672fa Add topup req constructor (#4983) 2024-10-18 08:55:56 +03:00
Bogdan-Ștefan Neacşu edc2a367c0 Top up bandwidth (#4975)
* Top up wg bandwidth

* Introduce v3 with top up

* Verify and increase cred bw

* Add log

* Fix clippy
2024-10-17 16:35:30 +03:00
Bogdan-Ștefan Neacşu e78040f0ec Use ticket type when retrieving from storage (#4947) 2024-10-15 11:23:34 +03:00
1687 changed files with 34581 additions and 95447 deletions
+28 -15
View File
@@ -6,27 +6,20 @@ on:
jobs:
build:
runs-on: arc-ubuntu-20.04
defaults:
run:
working-directory: documentation/docs
steps:
- uses: actions/checkout@v4
- name: Install Dependencies (Linux)
run: sudo apt-get update && sudo apt-get install -y build-essential curl wget libssl-dev libudev-dev squashfs-tools protobuf-compiler git python3 && sudo apt-get update --fix-missing
- name: Install pip3
run: sudo apt install -y python3-pip
run: sudo apt install -y python3-pip
- name: Install Python3 modules
run: sudo pip3 install pandas tabulate
- name: Install rsync
run: sudo apt-get install rsync
- 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
with:
node-version: 20
node-version: 18
- name: Install Rust stable
uses: actions-rs/toolchain@v1
with:
@@ -36,13 +29,33 @@ jobs:
with:
command: build
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
run: pnpm i
- name: Build project
run: pnpm run build
- name: Move files to /dist/
run: ../scripts/move-to-dist.sh
# This is a workaround replacement which builds on the last working commit b332a6b55668f60988e36961f3f62a794ba82ddb and then on current branch
- name: Save current branch to ~/current_branch
run: git rev-parse --abbrev-ref HEAD > ~/current_branch
- name: Git pull, reset & switch to b332a6b55668f60988e36961f3f62a794ba82ddb
run: git pull && git reset --hard && git checkout b332a6b55668f60988e36961f3f62a794ba82ddb
- name: Build all projects in documentation/ & move to ~/dist/docs/ from b332a6b55668f60988e36961f3f62a794ba82ddb
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
uses: mobiledevops/secret-to-file-action@v1
@@ -1,41 +0,0 @@
name: ci-build-vpn-api-wasm
on:
pull_request:
paths:
- 'common/**'
- 'nym-credential-proxy/**'
- '.github/workflows/ci-build-vpn-api-wasm.yml'
jobs:
wasm:
runs-on: arc-ubuntu-22.04
env:
CARGO_TERM_COLOR: always
steps:
- name: Check out repository code
uses: actions/checkout@v4
- name: Install Rust toolchain
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
target: wasm32-unknown-unknown
override: true
components: rustfmt, clippy
- 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: Install wasm-bindgen-cli
run: cargo install wasm-bindgen-cli
- name: "Build"
run: make
working-directory: nym-credential-proxy/vpn-api-lib-wasm
+15 -7
View File
@@ -30,7 +30,7 @@ jobs:
strategy:
fail-fast: false
matrix:
os: [ arc-ubuntu-20.04, custom-runner-mac-m1 ]
os: [arc-ubuntu-20.04, custom-runner-mac-m1]
runs-on: ${{ matrix.os }}
env:
CARGO_TERM_COLOR: always
@@ -57,17 +57,19 @@ jobs:
command: fmt
args: --all -- --check
- name: Clippy
uses: actions-rs/cargo@v1
with:
command: clippy
args: --workspace --all-targets -- -D warnings
- name: Build all binaries
uses: actions-rs/cargo@v1
with:
command: build
# while disabled by default, this build ensures nothing is broken within
# `axum` feature
- name: Build with `axum` feature
uses: actions-rs/cargo@v1
with:
command: build
args: --features axum
- name: Build all examples
if: contains(matrix.os, 'ubuntu')
uses: actions-rs/cargo@v1
@@ -88,3 +90,9 @@ jobs:
with:
command: test
args: --workspace -- --ignored
- name: Clippy
uses: actions-rs/cargo@v1
with:
command: clippy
args: --workspace --all-targets --features axum -- -D warnings
@@ -16,7 +16,7 @@ jobs:
strategy:
fail-fast: false
matrix:
platform: [ arc-ubuntu-20.04 ]
platform: arc-ubuntu-20.04
runs-on: ${{ matrix.platform }}
env:
+29 -19
View File
@@ -3,35 +3,28 @@ name: ci-docs
on:
workflow_dispatch:
push:
branches-ignore: [master]
branches-ignore: master
paths:
- "documentation/docs/**"
- ".github/workflows/ci-docs.yml"
- 'documentation/docs/**'
- '.github/workflows/ci-docs.yml'
jobs:
build:
runs-on: arc-ubuntu-20.04
defaults:
run:
working-directory: documentation/docs
steps:
- uses: actions/checkout@v4
- name: Install Dependencies (Linux)
run: sudo apt-get update && sudo apt-get install -y build-essential curl wget libssl-dev libudev-dev squashfs-tools protobuf-compiler git python3 && sudo apt-get update --fix-missing
- name: Install pip3
run: sudo apt install -y python3-pip
run: sudo apt install -y python3-pip
- name: Install Python3 modules
run: sudo pip3 install pandas tabulate
- name: Install rsync
run: sudo apt-get install rsync
- 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
with:
node-version: 20
node-version: 18
- name: Install Rust stable
uses: actions-rs/toolchain@v1
with:
@@ -41,13 +34,30 @@ jobs:
with:
command: build
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
run: pnpm i
- name: Build project
run: pnpm run build
- name: Move files to /dist/
run: ../scripts/move-to-dist.sh
# This is the original flow
# - name: Build all projects in documentation/ & move to ~/dist/docs/
# run: cd documentation && ./build_all_to_dist.sh
# This is a workaround replacement which builds on the last working commit b332a6b55668f60988e36961f3f62a794ba82ddb and then on current branch
- name: Save current branch to ~/current_branch
run: git rev-parse --abbrev-ref HEAD > ~/current_branch
- name: Git pull, reset & switch to b332a6b55668f60988e36961f3f62a794ba82ddb
run: git pull && git reset --hard && git checkout b332a6b55668f60988e36961f3f62a794ba82ddb
- name: Build all projects in documentation/ & move to ~/dist/docs/ from b332a6b55668f60988e36961f3f62a794ba82ddb
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
continue-on-error: true
@@ -58,5 +68,5 @@ jobs:
SOURCE: "dist/docs/"
REMOTE_HOST: ${{ secrets.CI_WWW_REMOTE_HOST }}
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/"
@@ -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
-11
View File
@@ -1,11 +0,0 @@
name: Hello world
on:
workflow_dispatch:
jobs:
my-job:
runs-on: arc-ubuntu-22.04
steps:
- name: my-step
run: echo "Hello World!"
+1 -3
View File
@@ -4,9 +4,7 @@ on:
pull_request:
branches:
- develop
- "release/**"
paths-ignore:
- "documentation/**"
- 'release/**'
types:
- labeled
- unlabeled
@@ -1,55 +0,0 @@
name: Build and upload Credential Proxy container to harbor.nymte.ch
on:
workflow_dispatch:
env:
WORKING_DIRECTORY: "nym-credential-proxy"
CONTAINER_NAME: "credential-proxy"
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: 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 }}/nym-credential-proxy/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,55 +0,0 @@
name: Build and upload Data observatory container to harbor.nymte.ch
on:
workflow_dispatch:
env:
WORKING_DIRECTORY: "nym-data-observatory"
CONTAINER_NAME: "data-observatory"
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,56 +0,0 @@
name: Build and upload Node Status agent container to harbor.nymte.ch
on:
workflow_dispatch:
env:
WORKING_DIRECTORY: "nym-node-status-agent"
CONTAINER_NAME: "node-status-agent"
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,55 +0,0 @@
name: Build and upload Node Status API container to harbor.nymte.ch
on:
workflow_dispatch:
env:
WORKING_DIRECTORY: "nym-node-status-api"
CONTAINER_NAME: "node-status-api"
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 ${{ env.WORKING_DIRECTORY }}-${{ steps.get_version.outputs.result }} >/dev/null 2>&1; then
echo "Tag ${{ steps.get_version.outputs.result }} 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
-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
-74
View File
@@ -4,80 +4,6 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
## [Unreleased]
## [2024.12-aero] (2024-10-17)
- nym-node: don't use bloomfilters for double spending checks ([#4960])
- bugfix: replace unreachable macro with an error return ([#4958])
- [DOCs:/operators]: Update FAQ sphinx size ([#4946])
- [DOCs/operators]: Release notes v2024.11-wedel ([#4939])
- Fix handle drop ([#4934])
- Assume offline mode ([#4926])
- Make ip-packet-request VERSION pub ([#4925])
- Expose error type ([#4924])
- Fix argument to cargo-deny action ([#4922])
- Fix nymvpn.com url in mainnet defaults ([#4920])
- Check both version and type in message header ([#4918])
- Bump http-api-client default timeout to 30 sec ([#4917])
- Max/proxy ffi ([#4906])
- Data Observatory stub ([#4905])
- Fix missing duplication of modified tables ([#4904])
- Update cargo deny ([#4901])
- docs: add hostname instructions for wss ([#4900])
- build(deps): bump the patch-updates group across 1 directory with 9 updates ([#4898])
- Fix clippy for beta toolchain ([#4897])
- Remove clippy github PR annotations ([#4896])
- Fix apt install in ci-build-upload-binaries.yml ([#4894])
- Update network monitor entrypoint ([#4893])
- Update nym-vpn metapackage and replace nymvpn-x with nym-vpn-app ([#4889])
- Entry wireguard tickets ([#4888])
- Build and Push CI ([#4887])
- Feature/updated gateway registration ([#4885])
- Few fixes to NNM pre deploy ([#4883])
- Fix sql serde with enum ([#4875])
- allow clients to send stateless gateway requests without prior registration ([#4873])
- chore: remove queued migration for adding explicit admin ([#4871])
- Gateway database modifications for different modes ([#4868])
- build(deps): bump strum from 0.25.0 to 0.26.3 ([#4848])
- Use serde from workspace ([#4833])
- build(deps): bump toml from 0.5.11 to 0.8.14 ([#4805])
- Max/rust sdk stream abstraction ([#4743])
[#4960]: https://github.com/nymtech/nym/pull/4960
[#4958]: https://github.com/nymtech/nym/pull/4958
[#4946]: https://github.com/nymtech/nym/pull/4946
[#4939]: https://github.com/nymtech/nym/pull/4939
[#4934]: https://github.com/nymtech/nym/pull/4934
[#4926]: https://github.com/nymtech/nym/pull/4926
[#4925]: https://github.com/nymtech/nym/pull/4925
[#4924]: https://github.com/nymtech/nym/pull/4924
[#4922]: https://github.com/nymtech/nym/pull/4922
[#4920]: https://github.com/nymtech/nym/pull/4920
[#4918]: https://github.com/nymtech/nym/pull/4918
[#4917]: https://github.com/nymtech/nym/pull/4917
[#4906]: https://github.com/nymtech/nym/pull/4906
[#4905]: https://github.com/nymtech/nym/pull/4905
[#4904]: https://github.com/nymtech/nym/pull/4904
[#4901]: https://github.com/nymtech/nym/pull/4901
[#4900]: https://github.com/nymtech/nym/pull/4900
[#4898]: https://github.com/nymtech/nym/pull/4898
[#4897]: https://github.com/nymtech/nym/pull/4897
[#4896]: https://github.com/nymtech/nym/pull/4896
[#4894]: https://github.com/nymtech/nym/pull/4894
[#4893]: https://github.com/nymtech/nym/pull/4893
[#4889]: https://github.com/nymtech/nym/pull/4889
[#4888]: https://github.com/nymtech/nym/pull/4888
[#4887]: https://github.com/nymtech/nym/pull/4887
[#4885]: https://github.com/nymtech/nym/pull/4885
[#4883]: https://github.com/nymtech/nym/pull/4883
[#4875]: https://github.com/nymtech/nym/pull/4875
[#4873]: https://github.com/nymtech/nym/pull/4873
[#4871]: https://github.com/nymtech/nym/pull/4871
[#4868]: https://github.com/nymtech/nym/pull/4868
[#4848]: https://github.com/nymtech/nym/pull/4848
[#4833]: https://github.com/nymtech/nym/pull/4833
[#4805]: https://github.com/nymtech/nym/pull/4805
[#4743]: https://github.com/nymtech/nym/pull/4743
## [2024.11-wedel] (2024-09-23)
- Backport #4894 to fix ci ([#4899])
Generated
+356 -902
View File
File diff suppressed because it is too large Load Diff
+33 -57
View File
@@ -19,33 +19,33 @@ members = [
"clients/native",
"clients/native/websocket-requests",
"clients/socks5",
"common/async-file-watcher",
"common/authenticator-requests",
"common/async-file-watcher",
"common/bandwidth-controller",
"common/bin-common",
"common/client-core",
"common/client-core/config-types",
"common/client-core/gateways-storage",
"common/client-core/surb-storage",
"common/client-core/gateways-storage",
"common/client-libs/gateway-client",
"common/client-libs/mixnet-client",
"common/client-libs/validator-client",
"common/commands",
"common/config",
"common/cosmwasm-smart-contracts/coconut-bandwidth-contract",
"common/cosmwasm-smart-contracts/ecash-contract",
"common/cosmwasm-smart-contracts/coconut-dkg",
"common/cosmwasm-smart-contracts/contracts-common",
"common/cosmwasm-smart-contracts/ecash-contract",
"common/cosmwasm-smart-contracts/group-contract",
"common/cosmwasm-smart-contracts/mixnet-contract",
"common/cosmwasm-smart-contracts/multisig-contract",
"common/cosmwasm-smart-contracts/vesting-contract",
"common/country-group",
"common/credential-storage",
"common/credential-utils",
"common/credential-verification",
"common/credentials",
"common/credential-utils",
"common/credentials-interface",
"common/credential-verification",
"common/crypto",
"common/dkg",
"common/ecash-double-spending",
@@ -54,21 +54,19 @@ members = [
"common/exit-policy",
"common/gateway-requests",
"common/gateway-storage",
"common/gateway-stats-storage",
"common/http-api-client",
"common/http-api-common",
"common/inclusion-probability",
"common/ip-packet-requests",
"common/ledger",
"common/mixnode-common",
"common/models",
"common/network-defaults",
"common/node-tester-utils",
"common/nonexhaustive-delayqueue",
"common/nymcoconut",
"common/nym_offline_compact_ecash",
"common/nym-id",
"common/nym-metrics",
"common/nym_offline_compact_ecash",
"common/nymcoconut",
"common/nymsphinx",
"common/nymsphinx/acknowledgements",
"common/nymsphinx/addressing",
@@ -87,7 +85,6 @@ members = [
"common/socks5-client-core",
"common/socks5/proxy-helpers",
"common/socks5/requests",
"common/statistics",
"common/store-cipher",
"common/task",
"common/topology",
@@ -98,35 +95,29 @@ members = [
"common/wasm/utils",
"common/wireguard",
"common/wireguard-types",
# "documentation/autodoc",
"explorer-api",
"explorer-api/explorer-api-requests",
"explorer-api/explorer-client",
"gateway",
"integrations/bity",
"mixnode",
"sdk/ffi/cpp",
"sdk/ffi/go",
"sdk/ffi/shared",
"sdk/lib/socks5-listener",
"sdk/rust/nym-sdk",
"sdk/ffi/shared",
"sdk/ffi/go",
"sdk/ffi/cpp",
"service-providers/authenticator",
"service-providers/common",
"service-providers/ip-packet-router",
"service-providers/network-requester",
"nym-api",
"nym-api/nym-api-requests",
"nym-browser-extension/storage",
"nym-credential-proxy/nym-credential-proxy",
"nym-credential-proxy/nym-credential-proxy-requests",
"nym-credential-proxy/vpn-api-lib-wasm",
"nym-data-observatory",
"nym-network-monitor",
"nym-api",
"nym-browser-extension/storage",
"nym-api/nym-api-requests",
"nym-data-observatory",
"nym-node",
"nym-node/nym-node-http-api",
"nym-node/nym-node-requests",
"nym-node-status-api",
"nym-node-status-agent",
"nym-outfox",
"nym-validator-rewarder",
"tools/echo-server",
@@ -144,27 +135,23 @@ members = [
"wasm/mix-fetch",
"wasm/node-tester",
"wasm/zknym-lib",
"tools/internal/testnet-manager",
"tools/internal/testnet-manager/dkg-bypass-contract",
"tools/echo-server",
"tools/internal/contract-state-importer/importer-cli",
"tools/internal/contract-state-importer/importer-contract",
"tools/internal/testnet-manager",
"tools/internal/testnet-manager/dkg-bypass-contract",
]
default-members = [
"clients/native",
"clients/socks5",
"common/models",
"explorer-api",
"gateway",
"mixnode",
"nym-api",
"nym-credential-proxy/nym-credential-proxy",
"nym-data-observatory",
"nym-node",
"nym-node-status-api",
"nym-validator-rewarder",
"nym-node-status-api",
"service-providers/authenticator",
"service-providers/ip-packet-router",
"service-providers/network-requester",
@@ -195,17 +182,19 @@ aes = "0.8.1"
aes-gcm = "0.10.1"
aes-gcm-siv = "0.11.1"
aead = "0.5.2"
anyhow = "1.0.90"
anyhow = "1.0.89"
argon2 = "0.5.0"
async-trait = "0.1.83"
axum-client-ip = "0.6.1"
axum = "0.7.5"
axum-extra = "0.9.4"
base64 = "0.22.1"
bincode = "1.3.3"
bip39 = { version = "2.0.0", features = ["zeroize"] }
bit-vec = "0.7.0" # can we unify those?
# can we unify those?
bit-vec = "0.7.0"
bitvec = "1.0.0"
blake3 = "1.5.4"
bloomfilter = "1.0.14"
bs58 = "0.5.1"
@@ -218,7 +207,7 @@ chacha20 = "0.9.0"
chacha20poly1305 = "0.10.1"
chrono = "0.4.31"
cipher = "0.4.3"
clap = "4.5.20"
clap = "4.5.18"
clap_complete = "4.5"
clap_complete_fig = "4.5"
colored = "2.0"
@@ -243,12 +232,10 @@ dotenvy = "0.15.6"
ecdsa = "0.16"
ed25519-dalek = "2.1"
etherparse = "0.13.0"
envy = "0.4"
eyre = "0.6.9"
fastrand = "2.1.1"
flate2 = "1.0.34"
futures = "0.3.28"
futures-util = "0.3"
generic-array = "0.14.7"
getrandom = "0.2.10"
getset = "0.1.3"
@@ -272,24 +259,22 @@ ipnetwork = "0.20"
isocountry = "0.3.2"
itertools = "0.13.0"
k256 = "0.13"
lazy_static = "1.5.0"
lazy_static = "1.4.0"
ledger-transport = "0.10.0"
ledger-transport-hid = "0.10.0"
log = "0.4"
maxminddb = "0.23.0"
mime = "0.3.17"
moka = { version = "0.12", features = ["future"] }
nix = "0.27.1"
notify = "5.1.0"
okapi = "0.7.0"
once_cell = "1.20.2"
once_cell = "1.7.2"
opentelemetry = "0.19.0"
opentelemetry-jaeger = "0.18.0"
parking_lot = "0.12.3"
pem = "0.8"
petgraph = "0.6.5"
pin-project = "1.1"
pin-project-lite = "0.2.14"
pin-project = "1.0"
pretty_env_logger = "0.4.0"
publicsuffix = "2.2.3"
quote = "1"
@@ -308,20 +293,18 @@ rocket_okapi = "0.8.0"
safer-ffi = "0.1.13"
schemars = "0.8.21"
semver = "1.0.23"
serde = "1.0.211"
serde = "1.0.210"
serde_bytes = "0.11.15"
serde_derive = "1.0"
serde_json = "1.0.132"
serde_json_path = "0.6.7"
serde_json = "1.0.128"
serde_repr = "0.1"
serde_with = "3.9.0"
serde_yaml = "0.9.25"
sha2 = "0.10.8"
si-scale = "0.2.3"
sphinx-packet = "0.1.1"
sqlx = "0.7.4"
sqlx = "0.6.3"
strum = "0.26"
strum_macros = "0.26"
subtle-encoding = "0.5"
syn = "1"
sysinfo = "0.30.13"
@@ -343,8 +326,7 @@ tracing = "0.1.37"
tracing-opentelemetry = "0.19.0"
tracing-subscriber = "0.3.16"
tracing-tree = "0.2.2"
tracing-log = "0.2"
ts-rs = "10.0.0"
ts-rs = "7.0.0"
tungstenite = { version = "0.20.1", default-features = false }
url = "2.5"
utoipa = "4.2"
@@ -366,7 +348,6 @@ prometheus = { version = "0.13.0" }
bls12_381 = { git = "https://github.com/jstuczyn/bls12_381", default-features = false, branch = "temp/experimental-serdect" }
group = { version = "0.13.0", default-features = false }
ff = { version = "0.13.0", default-features = false }
subtle = "2.5.0"
# cosmwasm-related
cosmwasm-schema = "=1.4.3"
@@ -405,19 +386,14 @@ indexed_db_futures = { git = "https://github.com/TiemenSch/rust-indexed-db", bra
js-sys = "0.3.70"
serde-wasm-bindgen = "0.6.5"
tsify = "0.4.5"
wasm-bindgen = "0.2.95"
wasm-bindgen-futures = "0.4.45"
wasm-bindgen = "0.2.93"
wasm-bindgen-futures = "0.4.43"
wasmtimer = "0.2.0"
web-sys = "0.3.72"
web-sys = "0.3.70"
# Profile settings for individual crates
# Compile-time verified queries do quite a bit of work at compile time. Incremental
# actions like cargo check and cargo build can be significantly faster when
# using an optimized build
[profile.dev.package.sqlx-macros]
opt-level = 3
[profile.release.package.nym-socks5-listener]
strip = true
codegen-units = 1
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "nym-client"
version = "1.1.42"
version = "1.1.41"
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"]
description = "Implementation of the Nym Client"
edition = "2021"
+1 -3
View File
@@ -1,5 +1,3 @@
# Nym Desktop Client
The Nym Desktop Client communicates with the remote, decentralised nodes which make up the Nym system as a whole.
TEST CI PICKUP
The Nym Desktop Client communicates with the remote, decentralised nodes which make up the Nym system as a whole.
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "nym-socks5-client"
version = "1.1.42"
version = "1.1.41"
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
description = "A SOCKS5 localhost proxy that converts incoming messages to Sphinx and sends them to a Nym address"
edition = "2021"
-1
View File
@@ -45,4 +45,3 @@ tracing = [
"opentelemetry",
]
clap = [ "dep:clap", "dep:clap_complete", "dep:clap_complete_fig" ]
models = []
@@ -1,20 +0,0 @@
{
"db_name": "SQLite",
"query": "SELECT EXISTS (SELECT 1 FROM registered_gateway WHERE gateway_id_bs58 = ?) AS 'exists'",
"describe": {
"columns": [
{
"name": "exists",
"ordinal": 0,
"type_info": "Int"
}
],
"parameters": {
"Right": 1
},
"nullable": [
null
]
},
"hash": "06e743d143fcc4be20ca2af5e99b19f15d22fff72490473587a14cdc046fda32"
}
@@ -1,44 +0,0 @@
{
"db_name": "SQLite",
"query": "SELECT * FROM remote_gateway_details WHERE gateway_id_bs58 = ?",
"describe": {
"columns": [
{
"name": "gateway_id_bs58",
"ordinal": 0,
"type_info": "Text"
},
{
"name": "gateway_owner_address",
"ordinal": 1,
"type_info": "Text"
},
{
"name": "gateway_listener",
"ordinal": 2,
"type_info": "Text"
},
{
"name": "derived_aes128_ctr_blake3_hmac_keys_bs58",
"ordinal": 3,
"type_info": "Text"
},
{
"name": "derived_aes256_gcm_siv_key",
"ordinal": 4,
"type_info": "Blob"
}
],
"parameters": {
"Right": 1
},
"nullable": [
false,
true,
false,
true,
true
]
},
"hash": "0e85ec18da67cf4e3df04ad80136571f6e920eb2290f20b1b8c5b0ab4b489985"
}
@@ -1,12 +0,0 @@
{
"db_name": "SQLite",
"query": "\n UPDATE remote_gateway_details\n SET\n derived_aes128_ctr_blake3_hmac_keys_bs58 = ?,\n derived_aes256_gcm_siv_key = ?\n WHERE gateway_id_bs58 = ?\n ",
"describe": {
"columns": [],
"parameters": {
"Right": 3
},
"nullable": []
},
"hash": "0f1dfb89f1eb39f4a58787af0f53a7a93afb7e4d2e54e2d38fd79d31c8575a54"
}
@@ -1,12 +0,0 @@
{
"db_name": "SQLite",
"query": "DELETE FROM remote_gateway_details WHERE gateway_id_bs58 = ?",
"describe": {
"columns": [],
"parameters": {
"Right": 1
},
"nullable": []
},
"hash": "1da6904e72b5abb9abf75affb13af7974d7795b4cbdba234273345fe161df233"
}
@@ -1,12 +0,0 @@
{
"db_name": "SQLite",
"query": "DELETE FROM custom_gateway_details WHERE gateway_id_bs58 = ?",
"describe": {
"columns": [],
"parameters": {
"Right": 1
},
"nullable": []
},
"hash": "4f78619aca933484cd67cb89a376b2a5bec1c191993ff58f0c71c03e3ef6d92d"
}
@@ -1,26 +0,0 @@
{
"db_name": "SQLite",
"query": "SELECT * FROM custom_gateway_details WHERE gateway_id_bs58 = ?",
"describe": {
"columns": [
{
"name": "gateway_id_bs58",
"ordinal": 0,
"type_info": "Text"
},
{
"name": "data",
"ordinal": 1,
"type_info": "Blob"
}
],
"parameters": {
"Right": 1
},
"nullable": [
false,
true
]
},
"hash": "54f552a9dbe95236f946ac2b6615e03504afa58e345ae16a128629d8e76f0a11"
}
@@ -1,20 +0,0 @@
{
"db_name": "SQLite",
"query": "SELECT gateway_id_bs58 FROM registered_gateway",
"describe": {
"columns": [
{
"name": "gateway_id_bs58",
"ordinal": 0,
"type_info": "Text"
}
],
"parameters": {
"Right": 0
},
"nullable": [
false
]
},
"hash": "5661cf1ad8bd5ca062e855e1971a8787133ee41814bd3efdd501f9ee0c050f2b"
}
@@ -1,12 +0,0 @@
{
"db_name": "SQLite",
"query": "UPDATE active_gateway SET active_gateway_id_bs58 = ?",
"describe": {
"columns": [],
"parameters": {
"Right": 1
},
"nullable": []
},
"hash": "80476cf2906eb0ecf7f66c16bc5682169b87f488b6927fa67fade6bf5abf7582"
}
@@ -1,12 +0,0 @@
{
"db_name": "SQLite",
"query": "\n INSERT INTO registered_gateway(gateway_id_bs58, registration_timestamp, gateway_type) \n VALUES (?, ?, ?)\n ",
"describe": {
"columns": [],
"parameters": {
"Right": 3
},
"nullable": []
},
"hash": "8909fd329e7e5fb16c4989b15b3d3a12bba1569520e01f6f074178e23d6ee89e"
}
@@ -1,12 +0,0 @@
{
"db_name": "SQLite",
"query": "\n INSERT INTO remote_gateway_details(gateway_id_bs58, derived_aes128_ctr_blake3_hmac_keys_bs58, derived_aes256_gcm_siv_key, gateway_owner_address, gateway_listener)\n VALUES (?, ?, ?, ?, ?)\n ",
"describe": {
"columns": [],
"parameters": {
"Right": 5
},
"nullable": []
},
"hash": "a6939bea03b10cde810a9a099bd597b4f51092e30a41c4085a8f8668f039f7c0"
}
@@ -1,12 +0,0 @@
{
"db_name": "SQLite",
"query": "\n INSERT INTO custom_gateway_details(gateway_id_bs58, data) \n VALUES (?, ?)\n ",
"describe": {
"columns": [],
"parameters": {
"Right": 2
},
"nullable": []
},
"hash": "b059bc3688b6b7f83f47048db9897720fd4e6f3211bf74030a9638f7bf6738e4"
}
@@ -1,20 +0,0 @@
{
"db_name": "SQLite",
"query": "SELECT active_gateway_id_bs58 FROM active_gateway",
"describe": {
"columns": [
{
"name": "active_gateway_id_bs58",
"ordinal": 0,
"type_info": "Text"
}
],
"parameters": {
"Right": 0
},
"nullable": [
true
]
},
"hash": "bf249752f08c283bf5942b6ff48125c24750b523cfcad1e5e9069dbf7050e2a1"
}
@@ -1,12 +0,0 @@
{
"db_name": "SQLite",
"query": "DELETE FROM registered_gateway WHERE gateway_id_bs58 = ?",
"describe": {
"columns": [],
"parameters": {
"Right": 1
},
"nullable": []
},
"hash": "f3ebe259e26c05ecdd33bd9085dbb91cd5046a8c9d4434cf085a4fa2ebf03e93"
}
@@ -29,10 +29,11 @@ impl StorageManager {
})?;
}
let opts = sqlx::sqlite::SqliteConnectOptions::new()
let mut opts = sqlx::sqlite::SqliteConnectOptions::new()
.filename(database_path)
.create_if_missing(true)
.disable_statement_logging();
.create_if_missing(true);
opts.disable_statement_logging();
let connection_pool = sqlx::SqlitePool::connect_with(opts)
.await
@@ -81,7 +82,7 @@ impl StorageManager {
sqlx::query!("SELECT EXISTS (SELECT 1 FROM registered_gateway WHERE gateway_id_bs58 = ?) AS 'exists'", gateway_id)
.fetch_one(&self.connection_pool)
.await
.map(|result| result.exists == Some(1))
.map(|result| result.exists == 1)
}
pub(crate) async fn maybe_get_registered_gateway(
@@ -3,11 +3,11 @@ use log::{debug, error};
use nym_explorer_client::{ExplorerClient, PrettyDetailedMixNodeBond};
use nym_network_defaults::var_names::EXPLORER_API;
use nym_topology::{
nym_topology_from_basic_info,
nym_topology_from_detailed,
provider_trait::{async_trait, TopologyProvider},
NymTopology,
};
use nym_validator_client::client::NodeId;
use nym_validator_client::client::MixId;
use rand::{prelude::SliceRandom, thread_rng};
use std::collections::HashMap;
use tap::TapOptional;
@@ -39,10 +39,10 @@ fn create_explorer_client() -> Option<ExplorerClient> {
fn group_mixnodes_by_country_code(
mixnodes: Vec<PrettyDetailedMixNodeBond>,
) -> HashMap<CountryGroup, Vec<NodeId>> {
) -> HashMap<CountryGroup, Vec<MixId>> {
mixnodes
.into_iter()
.fold(HashMap::<CountryGroup, Vec<NodeId>>::new(), |mut acc, m| {
.fold(HashMap::<CountryGroup, Vec<MixId>>::new(), |mut acc, m| {
if let Some(ref location) = m.location {
let country_code = location.two_letter_iso_country_code.clone();
let group_code = CountryGroup::new(country_code.as_str());
@@ -53,7 +53,7 @@ fn group_mixnodes_by_country_code(
})
}
fn log_mixnode_distribution(mixnodes: &HashMap<CountryGroup, Vec<NodeId>>) {
fn log_mixnode_distribution(mixnodes: &HashMap<CountryGroup, Vec<MixId>>) {
let mixnode_distribution = mixnodes
.iter()
.map(|(k, v)| format!("{}: {}", k, v.len()))
@@ -110,11 +110,7 @@ impl GeoAwareTopologyProvider {
}
async fn get_topology(&self) -> Option<NymTopology> {
let mixnodes = match self
.validator_client
.get_all_basic_active_mixing_assigned_nodes(Some(self.client_version.clone()))
.await
{
let mixnodes = match self.validator_client.get_cached_active_mixnodes().await {
Err(err) => {
error!("failed to get network mixnodes - {err}");
return None;
@@ -122,11 +118,7 @@ impl GeoAwareTopologyProvider {
Ok(mixes) => mixes,
};
let gateways = match self
.validator_client
.get_all_basic_entry_assigned_nodes(Some(self.client_version.clone()))
.await
{
let gateways = match self.validator_client.get_cached_gateways().await {
Err(err) => {
error!("failed to get network gateways - {err}");
return None;
@@ -190,10 +182,11 @@ impl GeoAwareTopologyProvider {
let mixnodes = mixnodes
.into_iter()
.filter(|m| filtered_mixnode_ids.contains(&m.node_id))
.filter(|m| filtered_mixnode_ids.contains(&m.mix_id()))
.collect::<Vec<_>>();
let topology = nym_topology_from_basic_info(&mixnodes, &gateways);
let topology = nym_topology_from_detailed(mixnodes, gateways)
.filter_system_version(&self.client_version);
// TODO: return real error type
check_layer_integrity(topology.clone()).ok()?;
@@ -6,6 +6,7 @@ pub(crate) use accessor::{TopologyAccessor, TopologyReadPermit};
use futures::StreamExt;
use log::*;
use nym_sphinx::addressing::nodes::NodeIdentity;
use nym_topology::provider_trait::TopologyProvider;
use nym_topology::NymTopologyError;
use std::time::Duration;
@@ -17,11 +18,7 @@ use wasmtimer::tokio::sleep;
mod accessor;
pub mod geo_aware_provider;
pub mod nym_api_provider;
pub use geo_aware_provider::GeoAwareTopologyProvider;
pub use nym_api_provider::{Config as NymApiTopologyProviderConfig, NymApiTopologyProvider};
pub use nym_topology::provider_trait::TopologyProvider;
pub(crate) mod nym_api_provider;
// TODO: move it to config later
const MAX_FAILURE_COUNT: usize = 10;
@@ -14,10 +14,9 @@ use url::Url;
pub const DEFAULT_MIN_MIXNODE_PERFORMANCE: u8 = 50;
pub const DEFAULT_MIN_GATEWAY_PERFORMANCE: u8 = 50;
#[derive(Debug)]
pub struct Config {
pub min_mixnode_performance: u8,
pub min_gateway_performance: u8,
pub(crate) struct Config {
pub(crate) min_mixnode_performance: u8,
pub(crate) min_gateway_performance: u8,
}
impl Default for Config {
@@ -30,7 +29,7 @@ impl Default for Config {
}
}
pub struct NymApiTopologyProvider {
pub(crate) struct NymApiTopologyProvider {
config: Config,
validator_client: nym_validator_client::client::NymApiClient,
@@ -41,7 +40,7 @@ pub struct NymApiTopologyProvider {
}
impl NymApiTopologyProvider {
pub fn new(
pub(crate) fn new(
config: Config,
mut nym_api_urls: Vec<Url>,
client_version: String,
@@ -99,7 +98,7 @@ impl NymApiTopologyProvider {
async fn get_current_compatible_topology(&mut self) -> Option<NymTopology> {
let mixnodes = match self
.validator_client
.get_all_basic_active_mixing_assigned_nodes(Some(self.client_version.clone()))
.get_basic_mixnodes(Some(self.client_version.clone()))
.await
{
Err(err) => {
@@ -111,7 +110,7 @@ impl NymApiTopologyProvider {
let gateways = match self
.validator_client
.get_all_basic_entry_assigned_nodes(Some(self.client_version.clone()))
.get_basic_gateways(Some(self.client_version.clone()))
.await
{
Err(err) => {
@@ -135,6 +134,7 @@ impl NymApiTopologyProvider {
g.performance.round_to_integer() >= self.config.min_gateway_performance
}),
);
if let Err(err) = self.check_layer_distribution(&topology) {
warn!("The current filtered active topology has extremely skewed layer distribution. It cannot be used: {err}");
self.use_next_nym_api();
+10
View File
@@ -187,6 +187,16 @@ pub enum ClientCoreError {
source: Ed25519RecoveryError,
},
#[error("the account owner of gateway {gateway_id} ({raw_owner}) is malformed: {err}")]
MalformedGatewayOwnerAccountAddress {
gateway_id: String,
raw_owner: String,
// just use the string formatting as opposed to underlying type to avoid having to import cosmrs
err: String,
},
#[error(
"the listening address of gateway {gateway_id} ({raw_listener}) is malformed: {source}"
)]
+26 -21
View File
@@ -7,7 +7,7 @@ use futures::{SinkExt, StreamExt};
use log::{debug, info, trace, warn};
use nym_crypto::asymmetric::identity;
use nym_gateway_client::GatewayClient;
use nym_topology::{gateway, mix};
use nym_topology::{filter::VersionFilterable, gateway, mix};
use nym_validator_client::client::IdentityKeyRef;
use nym_validator_client::UserAgent;
use rand::{seq::SliceRandom, Rng};
@@ -53,7 +53,7 @@ pub trait ConnectableGateway {
fn is_wss(&self) -> bool;
}
impl ConnectableGateway for gateway::LegacyNode {
impl ConnectableGateway for gateway::Node {
fn identity(&self) -> &identity::PublicKey {
self.identity()
}
@@ -82,7 +82,7 @@ pub async fn current_gateways<R: Rng>(
rng: &mut R,
nym_apis: &[Url],
user_agent: Option<UserAgent>,
) -> Result<Vec<gateway::LegacyNode>, ClientCoreError> {
) -> Result<Vec<gateway::Node>, ClientCoreError> {
let nym_api = nym_apis
.choose(rng)
.ok_or(ClientCoreError::ListOfNymApisIsEmpty)?;
@@ -94,26 +94,31 @@ pub async fn current_gateways<R: Rng>(
log::debug!("Fetching list of gateways from: {nym_api}");
let gateways = client.get_all_basic_entry_assigned_nodes(None).await?;
let gateways = client.get_cached_described_gateways().await?;
log::debug!("Found {} gateways", gateways.len());
log::trace!("Gateways: {:#?}", gateways);
let valid_gateways = gateways
.iter()
.into_iter()
.filter_map(|gateway| gateway.try_into().ok())
.collect::<Vec<gateway::LegacyNode>>();
log::debug!("After checking validity: {}", valid_gateways.len());
.collect::<Vec<gateway::Node>>();
log::debug!("Ater checking validity: {}", valid_gateways.len());
log::trace!("Valid gateways: {:#?}", valid_gateways);
log::info!("nym-api reports {} valid gateways", valid_gateways.len());
// we were always filtering by version so I'm not removing that 'feature'
let filtered_gateways = valid_gateways.filter_by_version(env!("CARGO_PKG_VERSION"));
log::debug!("After filtering for version: {}", filtered_gateways.len());
log::trace!("Filtered gateways: {:#?}", filtered_gateways);
Ok(valid_gateways)
log::info!("nym-api reports {} valid gateways", filtered_gateways.len());
Ok(filtered_gateways)
}
pub async fn current_mixnodes<R: Rng>(
rng: &mut R,
nym_apis: &[Url],
) -> Result<Vec<mix::LegacyNode>, ClientCoreError> {
) -> Result<Vec<mix::Node>, ClientCoreError> {
let nym_api = nym_apis
.choose(rng)
.ok_or(ClientCoreError::ListOfNymApisIsEmpty)?;
@@ -121,15 +126,15 @@ pub async fn current_mixnodes<R: Rng>(
log::trace!("Fetching list of mixnodes from: {nym_api}");
let mixnodes = client
.get_all_basic_active_mixing_assigned_nodes(None)
.await?;
let mixnodes = client.get_cached_mixnodes().await?;
let valid_mixnodes = mixnodes
.iter()
.filter_map(|mixnode| mixnode.try_into().ok())
.collect::<Vec<mix::LegacyNode>>();
.into_iter()
.filter_map(|mixnode| (&mixnode.bond_information).try_into().ok())
.collect::<Vec<mix::Node>>();
Ok(valid_mixnodes)
// we were always filtering by version so I'm not removing that 'feature'
let filtered_mixnodes = valid_mixnodes.filter_by_version(env!("CARGO_PKG_VERSION"));
Ok(filtered_mixnodes)
}
#[cfg(not(target_arch = "wasm32"))]
@@ -268,9 +273,9 @@ fn filter_by_tls<G: ConnectableGateway>(
pub(super) fn uniformly_random_gateway<R: Rng>(
rng: &mut R,
gateways: &[gateway::LegacyNode],
gateways: &[gateway::Node],
must_use_tls: bool,
) -> Result<gateway::LegacyNode, ClientCoreError> {
) -> Result<gateway::Node, ClientCoreError> {
filter_by_tls(gateways, must_use_tls)?
.choose(rng)
.ok_or(ClientCoreError::NoGatewaysOnNetwork)
@@ -279,9 +284,9 @@ pub(super) fn uniformly_random_gateway<R: Rng>(
pub(super) fn get_specified_gateway(
gateway_identity: IdentityKeyRef,
gateways: &[gateway::LegacyNode],
gateways: &[gateway::Node],
must_use_tls: bool,
) -> Result<gateway::LegacyNode, ClientCoreError> {
) -> Result<gateway::Node, ClientCoreError> {
log::debug!("Requesting specified gateway: {}", gateway_identity);
let user_gateway = identity::PublicKey::from_base58_string(gateway_identity)
.map_err(ClientCoreError::UnableToCreatePublicKeyFromGatewayId)?;
+1 -1
View File
@@ -50,7 +50,7 @@ async fn setup_new_gateway<K, D>(
key_store: &K,
details_store: &D,
selection_specification: GatewaySelectionSpecification,
available_gateways: Vec<gateway::LegacyNode>,
available_gateways: Vec<gateway::Node>,
) -> Result<InitialisationResult, ClientCoreError>
where
K: KeyStore,
+18 -3
View File
@@ -18,6 +18,7 @@ use nym_validator_client::client::IdentityKey;
use nym_validator_client::nyxd::AccountId;
use serde::Serialize;
use std::fmt::Display;
use std::str::FromStr;
use std::sync::Arc;
use time::OffsetDateTime;
use url::Url;
@@ -38,7 +39,7 @@ pub enum SelectedGateway {
impl SelectedGateway {
pub fn from_topology_node(
node: gateway::LegacyNode,
node: gateway::Node,
must_use_tls: bool,
) -> Result<Self, ClientCoreError> {
let gateway_listener = if must_use_tls {
@@ -50,6 +51,20 @@ impl SelectedGateway {
node.clients_address()
};
let gateway_owner_address = node
.owner
.as_ref()
.map(|raw_owner| {
AccountId::from_str(raw_owner).map_err(|source| {
ClientCoreError::MalformedGatewayOwnerAccountAddress {
gateway_id: node.identity_key.to_base58_string(),
raw_owner: raw_owner.clone(),
err: source.to_string(),
}
})
})
.transpose()?;
let gateway_listener =
Url::parse(&gateway_listener).map_err(|source| ClientCoreError::MalformedListener {
gateway_id: node.identity_key.to_base58_string(),
@@ -59,7 +74,7 @@ impl SelectedGateway {
Ok(SelectedGateway::Remote {
gateway_id: node.identity_key,
gateway_owner_address: None,
gateway_owner_address,
gateway_listener,
})
}
@@ -200,7 +215,7 @@ pub enum GatewaySetup {
specification: GatewaySelectionSpecification,
// TODO: seems to be a bit inefficient to pass them by value
available_gateways: Vec<gateway::LegacyNode>,
available_gateways: Vec<gateway::Node>,
},
ReuseConnection {
@@ -1,12 +1,9 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::backend::fs_backend::{
error::StorageError,
models::{
ReplySurbStorageMetadata, StoredReplyKey, StoredReplySurb, StoredSenderTag,
StoredSurbSender,
},
use crate::backend::fs_backend::error::StorageError;
use crate::backend::fs_backend::models::{
ReplySurbStorageMetadata, StoredReplyKey, StoredReplySurb, StoredSenderTag, StoredSurbSender,
};
use log::{error, info};
use sqlx::ConnectOptions;
@@ -30,10 +27,11 @@ impl StorageManager {
})?;
}
let opts = sqlx::sqlite::SqliteConnectOptions::new()
let mut opts = sqlx::sqlite::SqliteConnectOptions::new()
.filename(database_path)
.create_if_missing(fresh)
.disable_statement_logging();
.create_if_missing(fresh);
opts.disable_statement_logging();
let connection_pool = match sqlx::SqlitePool::connect_with(opts).await {
Ok(pool) => pool,
@@ -25,7 +25,7 @@ serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true }
nym-http-api-client = { path = "../../../common/http-api-client" }
thiserror = { workspace = true }
tracing = { workspace = true }
log = { workspace = true }
url = { workspace = true, features = ["serde"] }
tokio = { workspace = true, features = ["sync", "time"] }
time = { workspace = true, features = ["formatting"] }
+10 -256
View File
@@ -17,11 +17,11 @@ use nym_api_requests::ecash::{
BlindSignRequestBody, BlindedSignatureResponse, PartialCoinIndicesSignatureResponse,
PartialExpirationDateSignatureResponse, VerificationKeyResponse,
};
use nym_api_requests::models::{DescribedGateway, MixNodeBondAnnotated};
use nym_api_requests::models::{
ApiHealthResponse, GatewayCoreStatusResponse, MixnodeCoreStatusResponse, MixnodeStatusResponse,
NymNodeDescription, RewardEstimationResponse, StakeSaturationResponse,
GatewayCoreStatusResponse, MixnodeCoreStatusResponse, MixnodeStatusResponse,
RewardEstimationResponse, StakeSaturationResponse,
};
use nym_api_requests::models::{LegacyDescribedGateway, MixNodeBondAnnotated};
use nym_api_requests::nym_nodes::SkimmedNode;
use nym_coconut_dkg_common::types::EpochId;
use nym_http_api_client::UserAgent;
@@ -30,10 +30,10 @@ use time::Date;
use url::Url;
pub use crate::nym_api::NymApiClientExt;
use nym_mixnet_contract_common::NymNodeDetails;
pub use nym_mixnet_contract_common::{
mixnode::MixNodeDetails, GatewayBond, IdentityKey, IdentityKeyRef, NodeId,
mixnode::MixNodeDetails, GatewayBond, IdentityKey, IdentityKeyRef, MixId,
};
// re-export the type to not break existing imports
pub use crate::coconut::EcashApiClient;
@@ -106,9 +106,7 @@ impl Config {
pub struct Client<C, S = NoSigner> {
// ideally they would have been read-only, but unfortunately rust doesn't have such features
// #[deprecated(note = "please use `nym_api_client` instead")]
pub nym_api: nym_api::Client,
// pub nym_api_client: NymApiClient,
pub nyxd: NyxdClient<C, S>,
}
@@ -192,8 +190,6 @@ impl<C, S> Client<C, S> {
}
// 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> {
pub fn api_url(&self) -> &Url {
self.nym_api.current_url()
@@ -203,102 +199,50 @@ impl<C, S> Client<C, S> {
self.nym_api.change_base_url(new_endpoint)
}
#[deprecated]
pub async fn get_cached_mixnodes(&self) -> Result<Vec<MixNodeDetails>, ValidatorClientError> {
Ok(self.nym_api.get_mixnodes().await?)
}
#[deprecated]
pub async fn get_cached_mixnodes_detailed(
&self,
) -> Result<Vec<MixNodeBondAnnotated>, ValidatorClientError> {
Ok(self.nym_api.get_mixnodes_detailed().await?)
}
#[deprecated]
pub async fn get_cached_mixnodes_detailed_unfiltered(
&self,
) -> Result<Vec<MixNodeBondAnnotated>, ValidatorClientError> {
Ok(self.nym_api.get_mixnodes_detailed_unfiltered().await?)
}
#[deprecated]
pub async fn get_cached_rewarded_mixnodes(
&self,
) -> Result<Vec<MixNodeDetails>, ValidatorClientError> {
Ok(self.nym_api.get_rewarded_mixnodes().await?)
}
#[deprecated]
pub async fn get_cached_rewarded_mixnodes_detailed(
&self,
) -> Result<Vec<MixNodeBondAnnotated>, ValidatorClientError> {
Ok(self.nym_api.get_rewarded_mixnodes_detailed().await?)
}
#[deprecated]
pub async fn get_cached_active_mixnodes(
&self,
) -> Result<Vec<MixNodeDetails>, ValidatorClientError> {
Ok(self.nym_api.get_active_mixnodes().await?)
}
#[deprecated]
pub async fn get_cached_active_mixnodes_detailed(
&self,
) -> Result<Vec<MixNodeBondAnnotated>, ValidatorClientError> {
Ok(self.nym_api.get_active_mixnodes_detailed().await?)
}
#[deprecated]
pub async fn get_cached_gateways(&self) -> Result<Vec<GatewayBond>, ValidatorClientError> {
Ok(self.nym_api.get_gateways().await?)
}
// TODO: combine with NymApiClient...
pub async fn get_all_cached_described_nodes(
&self,
) -> Result<Vec<NymNodeDescription>, 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 descriptions = Vec::new();
loop {
let mut res = self.nym_api.get_nodes_described(Some(page), None).await?;
descriptions.append(&mut res.data);
if descriptions.len() < res.pagination.total {
page += 1
} else {
break;
}
}
Ok(descriptions)
}
// TODO: combine with NymApiClient...
pub async fn get_all_cached_bonded_nym_nodes(
&self,
) -> Result<Vec<NymNodeDetails>, 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 bonds = Vec::new();
loop {
let mut res = self.nym_api.get_nym_nodes(Some(page), None).await?;
bonds.append(&mut res.data);
if bonds.len() < res.pagination.total {
page += 1
} else {
break;
}
}
Ok(bonds)
}
pub async fn blind_sign(
&self,
request_body: &BlindSignRequestBody,
@@ -314,8 +258,6 @@ pub struct NymApiClient {
// 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 {
pub fn new(api_url: Url) -> Self {
let nym_api = nym_api::Client::new(api_url, None);
@@ -323,13 +265,6 @@ impl NymApiClient {
NymApiClient { nym_api }
}
#[cfg(not(target_arch = "wasm32"))]
pub fn new_with_timeout(api_url: Url, timeout: std::time::Duration) -> Self {
let nym_api = nym_api::Client::new(api_url, Some(timeout));
NymApiClient { nym_api }
}
pub fn new_with_user_agent(api_url: Url, user_agent: UserAgent) -> Self {
let nym_api = nym_api::Client::builder::<_, ValidatorClientError>(api_url)
.expect("invalid api url")
@@ -348,7 +283,6 @@ impl NymApiClient {
self.nym_api.change_base_url(new_endpoint);
}
#[deprecated(note = "use get_all_basic_active_mixing_assigned_nodes instead")]
pub async fn get_basic_mixnodes(
&self,
semver_compatibility: Option<String>,
@@ -360,7 +294,6 @@ impl NymApiClient {
.nodes)
}
#[deprecated(note = "use get_all_basic_entry_assigned_nodes instead")]
pub async fn get_basic_gateways(
&self,
semver_compatibility: Option<String>,
@@ -372,206 +305,32 @@ impl NymApiClient {
.nodes)
}
/// retrieve basic information for nodes are capable of operating as an entry gateway
/// this includes legacy gateways and nym-nodes
pub async fn get_all_basic_entry_assigned_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_entry_assigned_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 nodes that got assigned 'mixing' node in this epoch
/// this includes legacy mixnodes and nym-nodes
pub async fn get_all_basic_active_mixing_assigned_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_active_mixing_assigned_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 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
pub async fn get_all_basic_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_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)
}
pub async fn health(&self) -> Result<ApiHealthResponse, ValidatorClientError> {
Ok(self.nym_api.health().await?)
}
#[deprecated]
pub async fn get_cached_active_mixnodes(
&self,
) -> Result<Vec<MixNodeDetails>, ValidatorClientError> {
Ok(self.nym_api.get_active_mixnodes().await?)
}
#[deprecated]
pub async fn get_cached_rewarded_mixnodes(
&self,
) -> Result<Vec<MixNodeDetails>, ValidatorClientError> {
Ok(self.nym_api.get_rewarded_mixnodes().await?)
}
#[deprecated]
pub async fn get_cached_mixnodes(&self) -> Result<Vec<MixNodeDetails>, ValidatorClientError> {
Ok(self.nym_api.get_mixnodes().await?)
}
#[deprecated]
pub async fn get_cached_gateways(&self) -> Result<Vec<GatewayBond>, ValidatorClientError> {
Ok(self.nym_api.get_gateways().await?)
}
#[deprecated]
pub async fn get_cached_described_gateways(
&self,
) -> Result<Vec<LegacyDescribedGateway>, ValidatorClientError> {
) -> Result<Vec<DescribedGateway>, ValidatorClientError> {
Ok(self.nym_api.get_gateways_described().await?)
}
pub async fn get_all_described_nodes(
&self,
) -> Result<Vec<NymNodeDescription>, 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 descriptions = Vec::new();
loop {
let mut res = self.nym_api.get_nodes_described(Some(page), None).await?;
descriptions.append(&mut res.data);
if descriptions.len() < res.pagination.total {
page += 1
} else {
break;
}
}
Ok(descriptions)
}
pub async fn get_all_bonded_nym_nodes(
&self,
) -> Result<Vec<NymNodeDetails>, 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 bonds = Vec::new();
loop {
let mut res = self.nym_api.get_nym_nodes(Some(page), None).await?;
bonds.append(&mut res.data);
if bonds.len() < res.pagination.total {
page += 1
} else {
break;
}
}
Ok(bonds)
}
#[deprecated]
pub async fn get_gateway_core_status_count(
&self,
identity: IdentityKeyRef<'_>,
@@ -583,10 +342,9 @@ impl NymApiClient {
.await?)
}
#[deprecated]
pub async fn get_mixnode_core_status_count(
&self,
mix_id: NodeId,
mix_id: MixId,
since: Option<i64>,
) -> Result<MixnodeCoreStatusResponse, ValidatorClientError> {
Ok(self
@@ -595,26 +353,23 @@ impl NymApiClient {
.await?)
}
#[deprecated]
pub async fn get_mixnode_status(
&self,
mix_id: NodeId,
mix_id: MixId,
) -> Result<MixnodeStatusResponse, ValidatorClientError> {
Ok(self.nym_api.get_mixnode_status(mix_id).await?)
}
#[deprecated]
pub async fn get_mixnode_reward_estimation(
&self,
mix_id: NodeId,
mix_id: MixId,
) -> Result<RewardEstimationResponse, ValidatorClientError> {
Ok(self.nym_api.get_mixnode_reward_estimation(mix_id).await?)
}
#[deprecated]
pub async fn get_mixnode_stake_saturation(
&self,
mix_id: NodeId,
mix_id: MixId,
) -> Result<StakeSaturationResponse, ValidatorClientError> {
Ok(self.nym_api.get_mixnode_stake_saturation(mix_id).await?)
}
@@ -643,7 +398,6 @@ impl NymApiClient {
.await?)
}
#[deprecated]
pub async fn spent_credentials_filter(
&self,
) -> Result<SpentCredentialsResponse, ValidatorClientError> {
@@ -121,36 +121,36 @@ async fn test_nyxd_connection(
{
Ok(Err(NyxdError::TendermintErrorRpc(e))) => {
// If we get a tendermint-rpc error, we classify the node as not contactable
tracing::warn!("Checking: nyxd url: {url}: {}: {}", "failed".red(), e);
log::warn!("Checking: nyxd url: {url}: {}: {}", "failed".red(), e);
false
}
Ok(Err(NyxdError::AbciError { code, log, .. })) => {
// We accept the mixnet contract not found as ok from a connection standpoint. This happens
// for example on a pre-launch network.
tracing::debug!(
log::debug!(
"Checking: nyxd url: {url}: {}, but with abci error: {code}: {log}",
"success".green()
);
code == 18
}
Ok(Err(error @ NyxdError::NoContractAddressAvailable(_))) => {
tracing::warn!("Checking: nyxd url: {url}: {}: {error}", "failed".red());
log::warn!("Checking: nyxd url: {url}: {}: {error}", "failed".red());
false
}
Ok(Err(e)) => {
// For any other error, we're optimistic and just try anyway.
tracing::warn!(
log::warn!(
"Checking: nyxd_url: {url}: {}, but with error: {e}",
"success".green()
);
true
}
Ok(Ok(_)) => {
tracing::debug!("Checking: nyxd_url: {url}: {}", "success".green());
log::debug!("Checking: nyxd_url: {url}: {}", "success".green());
true
}
Err(e) => {
tracing::warn!("Checking: nyxd_url: {url}: {}: {e}", "failed".red());
log::warn!("Checking: nyxd_url: {url}: {}: {e}", "failed".red());
false
}
};
@@ -164,20 +164,20 @@ async fn test_nym_api_connection(
) -> ConnectionResult {
let result = match timeout(
Duration::from_secs(CONNECTION_TEST_TIMEOUT_SEC),
client.health(),
client.get_cached_mixnodes(),
)
.await
{
Ok(Ok(_)) => {
tracing::debug!("Checking: api_url: {url}: {}", "success".green());
log::debug!("Checking: api_url: {url}: {}", "success".green());
true
}
Ok(Err(e)) => {
tracing::debug!("Checking: api_url: {url}: {}: {e}", "failed".red());
log::debug!("Checking: api_url: {url}: {}: {e}", "failed".red());
false
}
Err(e) => {
tracing::debug!("Checking: api_url: {url}: {}: {e}", "failed".red());
log::debug!("Checking: api_url: {url}: {}: {e}", "failed".red());
false
}
};
@@ -10,12 +10,8 @@ use nym_api_requests::ecash::models::{
VerifyEcashTicketBody,
};
use nym_api_requests::ecash::VerificationKeyResponse;
use nym_api_requests::models::{
AnnotationResponse, ApiHealthResponse, LegacyDescribedMixNode, NodePerformanceResponse,
NymNodeDescription,
};
use nym_api_requests::nym_nodes::PaginatedCachedNodesResponse;
use nym_api_requests::pagination::PaginatedResponse;
use nym_api_requests::models::DescribedMixNode;
use nym_api_requests::nym_nodes::{CachedNodesResponse, SkimmedNode};
pub use nym_api_requests::{
ecash::{
models::{
@@ -27,23 +23,21 @@ pub use nym_api_requests::{
VerifyEcashCredentialBody,
},
models::{
ComputeRewardEstParam, GatewayBondAnnotated, GatewayCoreStatusResponse,
ComputeRewardEstParam, DescribedGateway, GatewayBondAnnotated, GatewayCoreStatusResponse,
GatewayStatusReportResponse, GatewayUptimeHistoryResponse, InclusionProbabilityResponse,
LegacyDescribedGateway, MixNodeBondAnnotated, MixnodeCoreStatusResponse,
MixnodeStatusReportResponse, MixnodeStatusResponse, MixnodeUptimeHistoryResponse,
RewardEstimationResponse, StakeSaturationResponse, UptimeResponse,
MixNodeBondAnnotated, MixnodeCoreStatusResponse, MixnodeStatusReportResponse,
MixnodeStatusResponse, MixnodeUptimeHistoryResponse, RewardEstimationResponse,
StakeSaturationResponse, UptimeResponse,
},
nym_nodes::{CachedNodesResponse, SkimmedNode},
};
pub use nym_coconut_dkg_common::types::EpochId;
use nym_contracts_common::IdentityKey;
pub use nym_http_api_client::Client;
use nym_http_api_client::{ApiClient, NO_PARAMS};
use nym_mixnet_contract_common::mixnode::MixNodeDetails;
use nym_mixnet_contract_common::{GatewayBond, IdentityKeyRef, NodeId, NymNodeDetails};
use nym_mixnet_contract_common::{GatewayBond, IdentityKeyRef, MixId};
use time::format_description::BorrowedFormatItem;
use time::Date;
use tracing::instrument;
pub mod error;
pub mod routes;
@@ -55,27 +49,11 @@ pub fn rfc_3339_date() -> Vec<BorrowedFormatItem<'static>> {
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
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))]
async fn get_mixnodes(&self) -> Result<Vec<MixNodeDetails>, NymAPIError> {
self.get_json(&[routes::API_VERSION, routes::MIXNODES], NO_PARAMS)
.await
}
#[deprecated]
#[instrument(level = "debug", skip(self))]
async fn get_mixnodes_detailed(&self) -> Result<Vec<MixNodeBondAnnotated>, NymAPIError> {
self.get_json(
&[
@@ -89,8 +67,6 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[deprecated]
#[instrument(level = "debug", skip(self))]
async fn get_gateways_detailed(&self) -> Result<Vec<GatewayBondAnnotated>, NymAPIError> {
self.get_json(
&[
@@ -104,8 +80,6 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[deprecated]
#[instrument(level = "debug", skip(self))]
async fn get_mixnodes_detailed_unfiltered(
&self,
) -> Result<Vec<MixNodeBondAnnotated>, NymAPIError> {
@@ -121,16 +95,12 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[deprecated]
#[instrument(level = "debug", skip(self))]
async fn get_gateways(&self) -> Result<Vec<GatewayBond>, NymAPIError> {
self.get_json(&[routes::API_VERSION, routes::GATEWAYS], NO_PARAMS)
.await
}
#[deprecated]
#[instrument(level = "debug", skip(self))]
async fn get_gateways_described(&self) -> Result<Vec<LegacyDescribedGateway>, NymAPIError> {
async fn get_gateways_described(&self) -> Result<Vec<DescribedGateway>, NymAPIError> {
self.get_json(
&[routes::API_VERSION, routes::GATEWAYS, routes::DESCRIBED],
NO_PARAMS,
@@ -138,9 +108,7 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[deprecated]
#[instrument(level = "debug", skip(self))]
async fn get_mixnodes_described(&self) -> Result<Vec<LegacyDescribedMixNode>, NymAPIError> {
async fn get_mixnodes_described(&self) -> Result<Vec<DescribedMixNode>, NymAPIError> {
self.get_json(
&[routes::API_VERSION, routes::MIXNODES, routes::DESCRIBED],
NO_PARAMS,
@@ -148,48 +116,6 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[tracing::instrument(level = "debug", skip_all)]
async fn get_nodes_described(
&self,
page: Option<u32>,
per_page: Option<u32>,
) -> Result<PaginatedResponse<NymNodeDescription>, NymAPIError> {
let mut params = Vec::new();
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, "nym-nodes", "described"], &params)
.await
}
#[tracing::instrument(level = "debug", skip_all)]
async fn get_nym_nodes(
&self,
page: Option<u32>,
per_page: Option<u32>,
) -> Result<PaginatedResponse<NymNodeDetails>, NymAPIError> {
let mut params = Vec::new();
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, "nym-nodes", "bonded"], &params)
.await
}
#[deprecated]
#[tracing::instrument(level = "debug", skip_all)]
async fn get_basic_mixnodes(
&self,
semver_compatibility: Option<String>,
@@ -213,8 +139,6 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[deprecated]
#[instrument(level = "debug", skip(self))]
async fn get_basic_gateways(
&self,
semver_compatibility: Option<String>,
@@ -238,167 +162,6 @@ pub trait NymApiClientExt: ApiClient {
.await
}
/// retrieve basic information for nodes are capable of operating as an entry gateway
/// this includes legacy gateways and nym-nodes
#[instrument(level = "debug", skip(self))]
async fn get_basic_entry_assigned_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",
"entry-gateways",
"all",
],
&params,
)
.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_active_mixing_assigned_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",
"active",
],
&params,
)
.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(
&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"],
&params,
)
.await
}
#[deprecated]
#[instrument(level = "debug", skip(self))]
async fn get_active_mixnodes(&self) -> Result<Vec<MixNodeDetails>, NymAPIError> {
self.get_json(
&[routes::API_VERSION, routes::MIXNODES, routes::ACTIVE],
@@ -407,8 +170,6 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[deprecated]
#[instrument(level = "debug", skip(self))]
async fn get_active_mixnodes_detailed(&self) -> Result<Vec<MixNodeBondAnnotated>, NymAPIError> {
self.get_json(
&[
@@ -423,8 +184,6 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[deprecated]
#[instrument(level = "debug", skip(self))]
async fn get_rewarded_mixnodes(&self) -> Result<Vec<MixNodeDetails>, NymAPIError> {
self.get_json(
&[routes::API_VERSION, routes::MIXNODES, routes::REWARDED],
@@ -433,11 +192,9 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[deprecated]
#[instrument(level = "debug", skip(self))]
async fn get_mixnode_report(
&self,
mix_id: NodeId,
mix_id: MixId,
) -> Result<MixnodeStatusReportResponse, NymAPIError> {
self.get_json(
&[
@@ -452,8 +209,6 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[deprecated]
#[instrument(level = "debug", skip(self))]
async fn get_gateway_report(
&self,
identity: IdentityKeyRef<'_>,
@@ -471,11 +226,9 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[deprecated]
#[instrument(level = "debug", skip(self))]
async fn get_mixnode_history(
&self,
mix_id: NodeId,
mix_id: MixId,
) -> Result<MixnodeUptimeHistoryResponse, NymAPIError> {
self.get_json(
&[
@@ -490,8 +243,6 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[deprecated]
#[instrument(level = "debug", skip(self))]
async fn get_gateway_history(
&self,
identity: IdentityKeyRef<'_>,
@@ -509,8 +260,6 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[deprecated]
#[instrument(level = "debug", skip(self))]
async fn get_rewarded_mixnodes_detailed(
&self,
) -> Result<Vec<MixNodeBondAnnotated>, NymAPIError> {
@@ -527,8 +276,6 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[deprecated]
#[instrument(level = "debug", skip(self))]
async fn get_gateway_core_status_count(
&self,
identity: IdentityKeyRef<'_>,
@@ -560,11 +307,9 @@ pub trait NymApiClientExt: ApiClient {
}
}
#[deprecated]
#[instrument(level = "debug", skip(self))]
async fn get_mixnode_core_status_count(
&self,
mix_id: NodeId,
mix_id: MixId,
since: Option<i64>,
) -> Result<MixnodeCoreStatusResponse, NymAPIError> {
if let Some(since) = since {
@@ -594,11 +339,9 @@ pub trait NymApiClientExt: ApiClient {
}
}
#[deprecated]
#[instrument(level = "debug", skip(self))]
async fn get_mixnode_status(
&self,
mix_id: NodeId,
mix_id: MixId,
) -> Result<MixnodeStatusResponse, NymAPIError> {
self.get_json(
&[
@@ -613,11 +356,9 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[deprecated]
#[instrument(level = "debug", skip(self))]
async fn get_mixnode_reward_estimation(
&self,
mix_id: NodeId,
mix_id: MixId,
) -> Result<RewardEstimationResponse, NymAPIError> {
self.get_json(
&[
@@ -632,11 +373,9 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[deprecated]
#[instrument(level = "debug", skip(self))]
async fn compute_mixnode_reward_estimation(
&self,
mix_id: NodeId,
mix_id: MixId,
request_body: &ComputeRewardEstParam,
) -> Result<RewardEstimationResponse, NymAPIError> {
self.post_json(
@@ -653,11 +392,9 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[deprecated]
#[instrument(level = "debug", skip(self))]
async fn get_mixnode_stake_saturation(
&self,
mix_id: NodeId,
mix_id: MixId,
) -> Result<StakeSaturationResponse, NymAPIError> {
self.get_json(
&[
@@ -672,11 +409,9 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[deprecated]
#[instrument(level = "debug", skip(self))]
async fn get_mixnode_inclusion_probability(
&self,
mix_id: NodeId,
mix_id: MixId,
) -> Result<InclusionProbabilityResponse, NymAPIError> {
self.get_json(
&[
@@ -691,25 +426,7 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[instrument(level = "debug", skip(self))]
async fn get_current_node_performance(
&self,
node_id: NodeId,
) -> Result<NodePerformanceResponse, NymAPIError> {
self.get_json_from(format!("/v1/nym-nodes/performance/{node_id}"))
.await
}
async fn get_node_annotation(
&self,
node_id: NodeId,
) -> Result<AnnotationResponse, NymAPIError> {
self.get_json_from(format!("/v1/nym-nodes/annotation/{node_id}"))
.await
}
#[deprecated]
async fn get_mixnode_avg_uptime(&self, mix_id: NodeId) -> Result<UptimeResponse, NymAPIError> {
async fn get_mixnode_avg_uptime(&self, mix_id: MixId) -> Result<UptimeResponse, NymAPIError> {
self.get_json(
&[
routes::API_VERSION,
@@ -723,9 +440,7 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[deprecated]
#[instrument(level = "debug", skip(self))]
async fn get_mixnodes_blacklisted(&self) -> Result<Vec<NodeId>, NymAPIError> {
async fn get_mixnodes_blacklisted(&self) -> Result<Vec<MixId>, NymAPIError> {
self.get_json(
&[routes::API_VERSION, routes::MIXNODES, routes::BLACKLISTED],
NO_PARAMS,
@@ -733,8 +448,6 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[deprecated]
#[instrument(level = "debug", skip(self))]
async fn get_gateways_blacklisted(&self) -> Result<Vec<IdentityKey>, NymAPIError> {
self.get_json(
&[routes::API_VERSION, routes::GATEWAYS, routes::BLACKLISTED],
@@ -743,7 +456,6 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[instrument(level = "debug", skip(self, request_body))]
async fn blind_sign(
&self,
request_body: &BlindSignRequestBody,
@@ -760,7 +472,6 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[instrument(level = "debug", skip(self, request_body))]
async fn verify_ecash_ticket(
&self,
request_body: &VerifyEcashTicketBody,
@@ -777,7 +488,6 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[instrument(level = "debug", skip(self, request_body))]
async fn batch_redeem_ecash_tickets(
&self,
request_body: &BatchRedeemTicketsBody,
@@ -794,8 +504,6 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[deprecated]
#[instrument(level = "debug", skip(self))]
async fn double_spending_filter_v1(&self) -> Result<SpentCredentialsResponse, NymAPIError> {
self.get_json(
&[
@@ -808,7 +516,6 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[instrument(level = "debug", skip(self))]
async fn partial_expiration_date_signatures(
&self,
expiration_date: Option<Date>,
@@ -832,7 +539,6 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[instrument(level = "debug", skip(self))]
async fn partial_coin_indices_signatures(
&self,
epoch_id: Option<EpochId>,
@@ -853,7 +559,6 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[instrument(level = "debug", skip(self))]
async fn global_expiration_date_signatures(
&self,
expiration_date: Option<Date>,
@@ -877,7 +582,6 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[instrument(level = "debug", skip(self))]
async fn global_coin_indices_signatures(
&self,
epoch_id: Option<EpochId>,
@@ -898,7 +602,6 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[instrument(level = "debug", skip(self))]
async fn master_verification_key(
&self,
epoch_id: Option<EpochId>,
@@ -918,7 +621,6 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[instrument(level = "debug", skip(self))]
async fn epoch_credentials(
&self,
dkg_epoch: EpochId,
@@ -935,7 +637,6 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[instrument(level = "debug", skip(self))]
async fn issued_credential(
&self,
credential_id: i64,
@@ -952,7 +653,6 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[instrument(level = "debug", skip(self))]
async fn issued_credentials(
&self,
credential_ids: Vec<i64>,
@@ -36,11 +36,8 @@ pub mod ecash {
}
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 GATEWAY: &str = "gateway";
pub const NYM_NODES: &str = "nym-nodes";
pub const CORE_STATUS_COUNT: &str = "core-status-count";
pub const SINCE_ARG: &str = "since";
@@ -55,6 +52,5 @@ pub const STAKE_SATURATION: &str = "stake-saturation";
pub const INCLUSION_CHANCE: &str = "inclusion-probability";
pub const SUBMIT_GATEWAY: &str = "submit-gateway-monitoring-results";
pub const SUBMIT_NODE: &str = "submit-node-monitoring-results";
pub const PERFORMANCE: &str = "performance";
pub const SERVICE_PROVIDERS: &str = "services";
@@ -8,9 +8,9 @@ use crate::nyxd::CosmWasmClient;
use async_trait::async_trait;
use cosmrs::AccountId;
use cosmwasm_std::Addr;
use log::trace;
use nym_coconut_dkg_common::types::{ChunkIndex, NodeIndex, StateAdvanceResponse};
use serde::Deserialize;
use tracing::trace;
use nym_coconut_dkg_common::dealer::RegisteredDealerDetails;
pub use nym_coconut_dkg_common::{
@@ -8,33 +8,28 @@ use crate::nyxd::CosmWasmClient;
use async_trait::async_trait;
use cosmrs::AccountId;
use nym_contracts_common::signing::Nonce;
use nym_mixnet_contract_common::gateway::{PreassignedGatewayIdsResponse, PreassignedId};
use nym_mixnet_contract_common::nym_node::{
EpochAssignmentResponse, NodeDetailsByIdentityResponse, NodeOwnershipResponse,
NodeRewardingDetailsResponse, PagedNymNodeBondsResponse, PagedNymNodeDetailsResponse,
PagedUnbondedNymNodesResponse, Role, RolesMetadataResponse, StakeSaturationResponse,
UnbondedNodeResponse, UnbondedNymNode,
};
use nym_mixnet_contract_common::reward_params::WorkFactor;
use nym_mixnet_contract_common::{
delegation,
delegation::{NodeDelegationResponse, OwnerProxySubKey},
delegation::{MixNodeDelegationResponse, OwnerProxySubKey},
families::{Family, FamilyHead},
mixnode::{
MixStakeSaturationResponse, MixnodeRewardingDetailsResponse, PagedMixnodesDetailsResponse,
PagedUnbondedMixnodesResponse, UnbondedMixnodeResponse,
MixnodeRewardingDetailsResponse, PagedMixnodesDetailsResponse,
PagedUnbondedMixnodesResponse, StakeSaturationResponse, UnbondedMixnodeResponse,
},
reward_params::{Performance, RewardingParams},
rewarding::{EstimatedCurrentEpochRewardResponse, PendingRewardResponse},
ContractBuildInformation, ContractState, ContractStateParams, CurrentIntervalResponse,
Delegation, EpochEventId, EpochStatus, GatewayBond, GatewayBondResponse,
GatewayOwnershipResponse, IdentityKey, IdentityKeyRef, IntervalEventId, MixNodeBond,
MixNodeDetails, MixOwnershipResponse, MixnodeDetailsByIdentityResponse, MixnodeDetailsResponse,
NodeId, NumberOfPendingEventsResponse, NymNodeBond, NymNodeDetails,
PagedAllDelegationsResponse, PagedDelegatorDelegationsResponse, PagedGatewayResponse,
PagedMixnodeBondsResponse, PagedNodeDelegationsResponse, PendingEpochEvent,
PendingEpochEventResponse, PendingEpochEventsResponse, PendingIntervalEvent,
PendingIntervalEventResponse, PendingIntervalEventsResponse, QueryMsg as MixnetQueryMsg,
RewardedSet, UnbondedMixnode,
Delegation, EpochEventId, EpochStatus, FamilyByHeadResponse, FamilyByLabelResponse,
FamilyMembersByHeadResponse, FamilyMembersByLabelResponse, GatewayBond, GatewayBondResponse,
GatewayOwnershipResponse, IdentityKey, IdentityKeyRef, IntervalEventId, LayerDistribution,
MixId, MixNodeBond, MixNodeDetails, MixOwnershipResponse, MixnodeDetailsByIdentityResponse,
MixnodeDetailsResponse, NumberOfPendingEventsResponse, PagedAllDelegationsResponse,
PagedDelegatorDelegationsResponse, PagedFamiliesResponse, PagedGatewayResponse,
PagedMembersResponse, PagedMixNodeDelegationsResponse, PagedMixnodeBondsResponse,
PagedRewardedSetResponse, PendingEpochEvent, PendingEpochEventResponse,
PendingEpochEventsResponse, PendingIntervalEvent, PendingIntervalEventResponse,
PendingIntervalEventsResponse, QueryMsg as MixnetQueryMsg, RewardedSetNodeStatus,
UnbondedMixnode,
};
use serde::Deserialize;
@@ -96,11 +91,56 @@ pub trait MixnetQueryClient {
.await
}
async fn get_rewarded_set_paged(
&self,
start_after: Option<MixId>,
limit: Option<u32>,
) -> Result<PagedRewardedSetResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetRewardedSet { limit, start_after })
.await
}
async fn get_all_node_families_paged(
&self,
start_after: Option<String>,
limit: Option<u32>,
) -> Result<PagedFamiliesResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetAllFamiliesPaged { limit, start_after })
.await
}
async fn get_all_family_members_paged(
&self,
start_after: Option<String>,
limit: Option<u32>,
) -> Result<PagedMembersResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetAllMembersPaged { limit, start_after })
.await
}
async fn get_family_members_by_head<S: Into<String> + Send>(
&self,
head: S,
) -> Result<FamilyMembersByHeadResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetFamilyMembersByHead { head: head.into() })
.await
}
async fn get_family_members_by_label<S: Into<String> + Send>(
&self,
label: S,
) -> Result<FamilyMembersByLabelResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetFamilyMembersByLabel {
label: label.into(),
})
.await
}
// mixnode-related:
async fn get_mixnode_bonds_paged(
&self,
start_after: Option<NodeId>,
start_after: Option<MixId>,
limit: Option<u32>,
) -> Result<PagedMixnodeBondsResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetMixNodeBonds { limit, start_after })
@@ -109,26 +149,26 @@ pub trait MixnetQueryClient {
async fn get_mixnodes_detailed_paged(
&self,
start_after: Option<NodeId>,
start_after: Option<MixId>,
limit: Option<u32>,
) -> Result<PagedMixnodesDetailsResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetMixNodesDetailed { limit, start_after })
.await
}
async fn get_unbonded_mixnodes_paged(
async fn get_unbonded_paged(
&self,
start_after: Option<NodeId>,
start_after: Option<MixId>,
limit: Option<u32>,
) -> Result<PagedUnbondedMixnodesResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetUnbondedMixNodes { limit, start_after })
.await
}
async fn get_unbonded_mixnodes_by_owner_paged(
async fn get_unbonded_by_owner_paged(
&self,
owner: &AccountId,
start_after: Option<NodeId>,
start_after: Option<MixId>,
limit: Option<u32>,
) -> Result<PagedUnbondedMixnodesResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetUnbondedMixNodesByOwner {
@@ -139,10 +179,10 @@ pub trait MixnetQueryClient {
.await
}
async fn get_unbonded_mixnodes_by_identity_paged(
async fn get_unbonded_by_identity_paged(
&self,
identity_key: IdentityKeyRef<'_>,
start_after: Option<NodeId>,
start_after: Option<MixId>,
limit: Option<u32>,
) -> Result<PagedUnbondedMixnodesResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetUnbondedMixNodesByIdentityKey {
@@ -165,7 +205,7 @@ pub trait MixnetQueryClient {
async fn get_mixnode_details(
&self,
mix_id: NodeId,
mix_id: MixId,
) -> Result<MixnodeDetailsResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetMixnodeDetails { mix_id })
.await
@@ -183,7 +223,7 @@ pub trait MixnetQueryClient {
async fn get_mixnode_rewarding_details(
&self,
mix_id: NodeId,
mix_id: MixId,
) -> Result<MixnodeRewardingDetailsResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetMixnodeRewardingDetails { mix_id })
.await
@@ -191,24 +231,24 @@ pub trait MixnetQueryClient {
async fn get_mixnode_stake_saturation(
&self,
mix_id: NodeId,
) -> Result<MixStakeSaturationResponse, NyxdError> {
mix_id: MixId,
) -> Result<StakeSaturationResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetStakeSaturation { mix_id })
.await
}
async fn get_unbonded_mixnode_information(
&self,
mix_id: NodeId,
mix_id: MixId,
) -> Result<UnbondedMixnodeResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetUnbondedMixNodeInformation { mix_id })
.await
}
// async fn get_layer_distribution(&self) -> Result<LayerDistribution, NyxdError> {
// self.query_mixnet_contract(MixnetQueryMsg::GetRoleDistribution {})
// .await
// }
async fn get_layer_distribution(&self) -> Result<LayerDistribution, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetLayerDistribution {})
.await
}
// gateway-related:
@@ -241,142 +281,17 @@ pub trait MixnetQueryClient {
.await
}
async fn get_preassigned_gateway_ids_paged(
&self,
start_after: Option<IdentityKey>,
limit: Option<u32>,
) -> Result<PreassignedGatewayIdsResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetPreassignedGatewayIds { start_after, limit })
.await
}
// nym-nodes related:
async fn get_nymnode_bonds_paged(
&self,
start_after: Option<NodeId>,
limit: Option<u32>,
) -> Result<PagedNymNodeBondsResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetNymNodeBondsPaged { limit, start_after })
.await
}
async fn get_nymnodes_detailed_paged(
&self,
start_after: Option<NodeId>,
limit: Option<u32>,
) -> Result<PagedNymNodeDetailsResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetNymNodesDetailedPaged { limit, start_after })
.await
}
async fn get_unbonded_nymnodes_paged(
&self,
start_after: Option<NodeId>,
limit: Option<u32>,
) -> Result<PagedUnbondedNymNodesResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetUnbondedNymNodesPaged { limit, start_after })
.await
}
async fn get_unbonded_nymnodes_by_owner_paged(
&self,
owner: &AccountId,
start_after: Option<NodeId>,
limit: Option<u32>,
) -> Result<PagedUnbondedNymNodesResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetUnbondedNymNodesByOwnerPaged {
owner: owner.to_string(),
limit,
start_after,
})
.await
}
async fn get_unbonded_nymnodes_by_identity_paged(
&self,
identity_key: IdentityKeyRef<'_>,
start_after: Option<NodeId>,
limit: Option<u32>,
) -> Result<PagedUnbondedNymNodesResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetUnbondedNymNodesByIdentityKeyPaged {
identity_key: identity_key.to_string(),
limit,
start_after,
})
.await
}
async fn get_owned_nymnode(
&self,
address: &AccountId,
) -> Result<NodeOwnershipResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetOwnedNymNode {
address: address.to_string(),
})
.await
}
async fn get_nymnode_details(
&self,
node_id: NodeId,
) -> Result<NodeOwnershipResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetNymNodeDetails { node_id })
.await
}
async fn get_nymnode_details_by_identity(
&self,
node_identity: IdentityKey,
) -> Result<NodeDetailsByIdentityResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetNymNodeDetailsByIdentityKey { node_identity })
.await
}
async fn get_nymnode_rewarding_details(
&self,
node_id: NodeId,
) -> Result<NodeRewardingDetailsResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetNodeRewardingDetails { node_id })
.await
}
async fn get_node_stake_saturation(
&self,
node_id: NodeId,
) -> Result<StakeSaturationResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetNodeStakeSaturation { node_id })
.await
}
async fn get_unbonded_nymnode_information(
&self,
node_id: NodeId,
) -> Result<UnbondedNodeResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetUnbondedNymNode { node_id })
.await
}
async fn get_role_assignment(&self, role: Role) -> Result<EpochAssignmentResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetRoleAssignment { role })
.await
}
async fn get_rewarded_set_metadata(&self) -> Result<RolesMetadataResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetRewardedSetMetadata {})
.await
}
// delegation-related:
/// Gets list of all delegations towards particular mixnode on particular page.
async fn get_mixnode_delegations_paged(
&self,
node_id: NodeId,
mix_id: MixId,
start_after: Option<String>,
limit: Option<u32>,
) -> Result<PagedNodeDelegationsResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetNodeDelegations {
node_id,
) -> Result<PagedMixNodeDelegationsResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetMixnodeDelegations {
mix_id,
start_after,
limit,
})
@@ -387,7 +302,7 @@ pub trait MixnetQueryClient {
async fn get_delegator_delegations_paged(
&self,
delegator: &AccountId,
start_after: Option<(NodeId, OwnerProxySubKey)>,
start_after: Option<(MixId, OwnerProxySubKey)>,
limit: Option<u32>,
) -> Result<PagedDelegatorDelegationsResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetDelegatorDelegations {
@@ -401,12 +316,12 @@ pub trait MixnetQueryClient {
/// Checks value of delegation of given client towards particular mixnode.
async fn get_delegation_details(
&self,
node_id: NodeId,
mix_id: MixId,
delegator: &AccountId,
proxy: Option<String>,
) -> Result<NodeDelegationResponse, NyxdError> {
) -> Result<MixNodeDelegationResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetDelegationDetails {
node_id,
mix_id,
delegator: delegator.to_string(),
proxy,
})
@@ -436,21 +351,21 @@ pub trait MixnetQueryClient {
async fn get_pending_mixnode_operator_reward(
&self,
node_id: NodeId,
mix_id: MixId,
) -> Result<PendingRewardResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetPendingNodeOperatorReward { node_id })
self.query_mixnet_contract(MixnetQueryMsg::GetPendingMixNodeOperatorReward { mix_id })
.await
}
async fn get_pending_delegator_reward(
&self,
delegator: &AccountId,
node_id: NodeId,
mix_id: MixId,
proxy: Option<String>,
) -> Result<PendingRewardResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetPendingDelegatorReward {
address: delegator.to_string(),
node_id,
mix_id,
proxy,
})
.await
@@ -459,14 +374,12 @@ pub trait MixnetQueryClient {
// given the provided performance, estimate the reward at the end of the current epoch
async fn get_estimated_current_epoch_operator_reward(
&self,
node_id: NodeId,
mix_id: MixId,
estimated_performance: Performance,
estimated_work: Option<WorkFactor>,
) -> Result<EstimatedCurrentEpochRewardResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetEstimatedCurrentEpochOperatorReward {
node_id,
mix_id,
estimated_performance,
estimated_work,
})
.await
}
@@ -475,15 +388,15 @@ pub trait MixnetQueryClient {
async fn get_estimated_current_epoch_delegator_reward(
&self,
delegator: &AccountId,
node_id: NodeId,
mix_id: MixId,
proxy: Option<String>,
estimated_performance: Performance,
estimated_work: Option<WorkFactor>,
) -> Result<EstimatedCurrentEpochRewardResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetEstimatedCurrentEpochDelegatorReward {
address: delegator.to_string(),
node_id,
mix_id,
proxy,
estimated_performance,
estimated_work,
})
.await
}
@@ -537,6 +450,22 @@ pub trait MixnetQueryClient {
})
.await
}
async fn get_node_family_by_label(
&self,
label: String,
) -> Result<FamilyByLabelResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetFamilyByLabel { label })
.await
}
async fn get_node_family_by_head(
&self,
head: String,
) -> Result<FamilyByHeadResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetFamilyByHead { head })
.await
}
}
// extension trait to the query client to deal with the paged queries
@@ -544,35 +473,18 @@ pub trait MixnetQueryClient {
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
pub trait PagedMixnetQueryClient: MixnetQueryClient {
async fn get_all_nymnode_bonds(&self) -> Result<Vec<NymNodeBond>, NyxdError> {
collect_paged!(self, get_nymnode_bonds_paged, nodes)
async fn get_all_node_families(&self) -> Result<Vec<Family>, NyxdError> {
collect_paged!(self, get_all_node_families_paged, families)
}
async fn get_all_nymnodes_detailed(&self) -> Result<Vec<NymNodeDetails>, NyxdError> {
collect_paged!(self, get_nymnodes_detailed_paged, nodes)
async fn get_all_family_members(&self) -> Result<Vec<(IdentityKey, FamilyHead)>, NyxdError> {
collect_paged!(self, get_all_family_members_paged, members)
}
async fn get_all_unbonded_nymnodes(&self) -> Result<Vec<UnbondedNymNode>, NyxdError> {
collect_paged!(self, get_unbonded_nymnodes_paged, nodes)
}
async fn get_all_unbonded_nymnodes_by_owner(
async fn get_all_rewarded_set_mixnodes(
&self,
owner: &AccountId,
) -> Result<Vec<UnbondedNymNode>, NyxdError> {
collect_paged!(self, get_unbonded_nymnodes_by_owner_paged, nodes, owner)
}
async fn get_all_unbonded_nymnodes_by_identity(
&self,
identity_key: IdentityKeyRef<'_>,
) -> Result<Vec<UnbondedNymNode>, NyxdError> {
collect_paged!(
self,
get_unbonded_nymnodes_by_identity_paged,
nodes,
identity_key
)
) -> Result<Vec<(MixId, RewardedSetNodeStatus)>, NyxdError> {
collect_paged!(self, get_rewarded_set_paged, nodes)
}
async fn get_all_mixnode_bonds(&self) -> Result<Vec<MixNodeBond>, NyxdError> {
@@ -583,40 +495,31 @@ pub trait PagedMixnetQueryClient: MixnetQueryClient {
collect_paged!(self, get_mixnodes_detailed_paged, nodes)
}
async fn get_all_unbonded_mixnodes(&self) -> Result<Vec<(NodeId, UnbondedMixnode)>, NyxdError> {
collect_paged!(self, get_unbonded_mixnodes_paged, nodes)
async fn get_all_unbonded_mixnodes(&self) -> Result<Vec<(MixId, UnbondedMixnode)>, NyxdError> {
collect_paged!(self, get_unbonded_paged, nodes)
}
async fn get_all_unbonded_mixnodes_by_owner(
&self,
owner: &AccountId,
) -> Result<Vec<(NodeId, UnbondedMixnode)>, NyxdError> {
collect_paged!(self, get_unbonded_mixnodes_by_owner_paged, nodes, owner)
) -> Result<Vec<(MixId, UnbondedMixnode)>, NyxdError> {
collect_paged!(self, get_unbonded_by_owner_paged, nodes, owner)
}
async fn get_all_unbonded_mixnodes_by_identity(
&self,
identity_key: IdentityKeyRef<'_>,
) -> Result<Vec<(NodeId, UnbondedMixnode)>, NyxdError> {
collect_paged!(
self,
get_unbonded_mixnodes_by_identity_paged,
nodes,
identity_key
)
) -> Result<Vec<(MixId, UnbondedMixnode)>, NyxdError> {
collect_paged!(self, get_unbonded_by_identity_paged, nodes, identity_key)
}
async fn get_all_gateways(&self) -> Result<Vec<GatewayBond>, NyxdError> {
collect_paged!(self, get_gateways_paged, nodes)
}
async fn get_all_preassigned_gateway_ids(&self) -> Result<Vec<PreassignedId>, NyxdError> {
collect_paged!(self, get_preassigned_gateway_ids_paged, ids)
}
async fn get_all_single_mixnode_delegations(
&self,
mix_id: NodeId,
mix_id: MixId,
) -> Result<Vec<Delegation>, NyxdError> {
collect_paged!(self, get_mixnode_delegations_paged, delegations, mix_id)
}
@@ -651,65 +554,6 @@ pub trait PagedMixnetQueryClient: MixnetQueryClient {
#[async_trait]
impl<T> PagedMixnetQueryClient for T where T: MixnetQueryClient {}
// extension help to provide extra functionalities based on existing queries:
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
pub trait MixnetQueryClientExt: MixnetQueryClient {
async fn get_rewarded_set(&self) -> Result<RewardedSet, NyxdError> {
let error_response = |message| Err(NyxdError::extension_query_failure("mixnet", message));
let metadata = self.get_rewarded_set_metadata().await?;
if !metadata.metadata.fully_assigned {
return error_response("the rewarded set hasn't been fully assigned for this epoch");
}
let expected_epoch_id = metadata.metadata.epoch_id;
// if we have to query those things more frequently, we could do it concurrently,
// but as it stands now, it happens so infrequently it might as well be sequential
let entry = self.get_role_assignment(Role::EntryGateway).await?;
if entry.epoch_id != expected_epoch_id {
return error_response("the nodes assigned for 'entry' returned unexpected epoch_id");
}
let exit = self.get_role_assignment(Role::ExitGateway).await?;
if exit.epoch_id != expected_epoch_id {
return error_response("the nodes assigned for 'exit' returned unexpected epoch_id");
}
let layer1 = self.get_role_assignment(Role::Layer1).await?;
if layer1.epoch_id != expected_epoch_id {
return error_response("the nodes assigned for 'layer1' returned unexpected epoch_id");
}
let layer2 = self.get_role_assignment(Role::Layer2).await?;
if layer2.epoch_id != expected_epoch_id {
return error_response("the nodes assigned for 'layer2' returned unexpected epoch_id");
}
let layer3 = self.get_role_assignment(Role::Layer3).await?;
if layer3.epoch_id != expected_epoch_id {
return error_response("the nodes assigned for 'layer3' returned unexpected epoch_id");
}
let standby = self.get_role_assignment(Role::Standby).await?;
if standby.epoch_id != expected_epoch_id {
return error_response("the nodes assigned for 'standby' returned unexpected epoch_id");
}
Ok(RewardedSet {
entry_gateways: entry.nodes,
exit_gateways: exit.nodes,
layer1: layer1.nodes,
layer2: layer2.nodes,
layer3: layer3.nodes,
standby: standby.nodes,
})
}
}
#[async_trait]
impl<T> MixnetQueryClientExt for T where T: MixnetQueryClient {}
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
impl<C> MixnetQueryClient for C
@@ -741,6 +585,24 @@ mod tests {
) -> u32 {
match msg {
MixnetQueryMsg::Admin {} => client.admin().ignore(),
MixnetQueryMsg::GetAllFamiliesPaged { limit, start_after } => client
.get_all_family_members_paged(start_after, limit)
.ignore(),
MixnetQueryMsg::GetAllMembersPaged { limit, start_after } => client
.get_all_family_members_paged(start_after, limit)
.ignore(),
MixnetQueryMsg::GetFamilyByHead { head } => {
client.get_node_family_by_head(head).ignore()
}
MixnetQueryMsg::GetFamilyByLabel { label } => {
client.get_node_family_by_label(label).ignore()
}
MixnetQueryMsg::GetFamilyMembersByHead { head } => {
client.get_family_members_by_head(head).ignore()
}
MixnetQueryMsg::GetFamilyMembersByLabel { label } => {
client.get_family_members_by_label(label).ignore()
}
MixnetQueryMsg::GetContractVersion {} => client.get_mixnet_contract_version().ignore(),
MixnetQueryMsg::GetCW2ContractVersion {} => {
client.get_mixnet_contract_cw2_version().ignore()
@@ -755,28 +617,31 @@ mod tests {
MixnetQueryMsg::GetCurrentIntervalDetails {} => {
client.get_current_interval_details().ignore()
}
MixnetQueryMsg::GetRewardedSet { limit, start_after } => {
client.get_rewarded_set_paged(start_after, limit).ignore()
}
MixnetQueryMsg::GetMixNodeBonds { limit, start_after } => {
client.get_mixnode_bonds_paged(start_after, limit).ignore()
}
MixnetQueryMsg::GetMixNodesDetailed { limit, start_after } => client
.get_mixnodes_detailed_paged(start_after, limit)
.ignore(),
MixnetQueryMsg::GetUnbondedMixNodes { limit, start_after } => client
.get_unbonded_mixnodes_paged(start_after, limit)
.ignore(),
MixnetQueryMsg::GetUnbondedMixNodes { limit, start_after } => {
client.get_unbonded_paged(start_after, limit).ignore()
}
MixnetQueryMsg::GetUnbondedMixNodesByOwner {
owner,
limit,
start_after,
} => client
.get_unbonded_mixnodes_by_owner_paged(&owner.parse().unwrap(), start_after, limit)
.get_unbonded_by_owner_paged(&owner.parse().unwrap(), start_after, limit)
.ignore(),
MixnetQueryMsg::GetUnbondedMixNodesByIdentityKey {
identity_key,
limit,
start_after,
} => client
.get_unbonded_mixnodes_by_identity_paged(&identity_key, start_after, limit)
.get_unbonded_by_identity_paged(&identity_key, start_after, limit)
.ignore(),
MixnetQueryMsg::GetOwnedMixnode { address } => {
client.get_owned_mixnode(&address.parse().unwrap()).ignore()
@@ -796,6 +661,7 @@ mod tests {
MixnetQueryMsg::GetBondedMixnodeDetailsByIdentity { mix_identity } => client
.get_mixnode_details_by_identity(mix_identity)
.ignore(),
MixnetQueryMsg::GetLayerDistribution {} => client.get_layer_distribution().ignore(),
MixnetQueryMsg::GetGateways { start_after, limit } => {
client.get_gateways_paged(start_after, limit).ignore()
}
@@ -805,8 +671,8 @@ mod tests {
MixnetQueryMsg::GetOwnedGateway { address } => {
client.get_owned_gateway(&address.parse().unwrap()).ignore()
}
MixnetQueryMsg::GetNodeDelegations {
node_id: mix_id,
MixnetQueryMsg::GetMixnodeDelegations {
mix_id,
start_after,
limit,
} => client
@@ -820,7 +686,7 @@ mod tests {
.get_delegator_delegations_paged(&delegator.parse().unwrap(), start_after, limit)
.ignore(),
MixnetQueryMsg::GetDelegationDetails {
node_id: mix_id,
mix_id,
delegator,
proxy,
} => client
@@ -832,38 +698,33 @@ mod tests {
MixnetQueryMsg::GetPendingOperatorReward { address } => client
.get_pending_operator_reward(&address.parse().unwrap())
.ignore(),
MixnetQueryMsg::GetPendingNodeOperatorReward { node_id: mix_id } => {
MixnetQueryMsg::GetPendingMixNodeOperatorReward { mix_id } => {
client.get_pending_mixnode_operator_reward(mix_id).ignore()
}
MixnetQueryMsg::GetPendingDelegatorReward {
address,
node_id: mix_id,
mix_id,
proxy,
} => client
.get_pending_delegator_reward(&address.parse().unwrap(), mix_id, proxy)
.ignore(),
MixnetQueryMsg::GetEstimatedCurrentEpochOperatorReward {
node_id,
mix_id,
estimated_performance,
estimated_work,
} => client
.get_estimated_current_epoch_operator_reward(
node_id,
estimated_performance,
estimated_work,
)
.get_estimated_current_epoch_operator_reward(mix_id, estimated_performance)
.ignore(),
MixnetQueryMsg::GetEstimatedCurrentEpochDelegatorReward {
address,
node_id,
mix_id,
proxy,
estimated_performance,
estimated_work,
} => client
.get_estimated_current_epoch_delegator_reward(
&address.parse().unwrap(),
node_id,
mix_id,
proxy,
estimated_performance,
estimated_work,
)
.ignore(),
MixnetQueryMsg::GetPendingEpochEvents { limit, start_after } => client
@@ -884,54 +745,6 @@ mod tests {
MixnetQueryMsg::GetSigningNonce { address } => {
client.get_signing_nonce(&address.parse().unwrap()).ignore()
}
MixnetQueryMsg::GetPreassignedGatewayIds { start_after, limit } => client
.get_preassigned_gateway_ids_paged(start_after, limit)
.ignore(),
MixnetQueryMsg::GetNymNodeBondsPaged { limit, start_after } => {
client.get_nymnode_bonds_paged(limit, start_after).ignore()
}
MixnetQueryMsg::GetNymNodesDetailedPaged { limit, start_after } => client
.get_nymnodes_detailed_paged(limit, start_after)
.ignore(),
MixnetQueryMsg::GetUnbondedNymNode { node_id } => {
client.get_unbonded_nymnode_information(node_id).ignore()
}
MixnetQueryMsg::GetUnbondedNymNodesPaged { limit, start_after } => client
.get_unbonded_nymnodes_paged(limit, start_after)
.ignore(),
MixnetQueryMsg::GetUnbondedNymNodesByOwnerPaged {
owner,
limit,
start_after,
} => client
.get_unbonded_nymnodes_by_owner_paged(&owner.parse().unwrap(), limit, start_after)
.ignore(),
MixnetQueryMsg::GetUnbondedNymNodesByIdentityKeyPaged {
identity_key,
limit,
start_after,
} => client
.get_unbonded_nymnodes_by_identity_paged(&identity_key, limit, start_after)
.ignore(),
MixnetQueryMsg::GetOwnedNymNode { address } => {
client.get_owned_nymnode(&address.parse().unwrap()).ignore()
}
MixnetQueryMsg::GetNymNodeDetails { node_id } => {
client.get_nymnode_details(node_id).ignore()
}
MixnetQueryMsg::GetNymNodeDetailsByIdentityKey { node_identity } => client
.get_nymnode_details_by_identity(node_identity)
.ignore(),
MixnetQueryMsg::GetNodeRewardingDetails { node_id } => {
client.get_nymnode_rewarding_details(node_id).ignore()
}
MixnetQueryMsg::GetNodeStakeSaturation { node_id } => {
client.get_node_stake_saturation(node_id).ignore()
}
MixnetQueryMsg::GetRoleAssignment { role } => client.get_role_assignment(role).ignore(),
MixnetQueryMsg::GetRewardedSetMetadata {} => {
client.get_rewarded_set_metadata().ignore()
}
}
}
}
@@ -10,15 +10,13 @@ use crate::signing::signer::OfflineSigner;
use async_trait::async_trait;
use cosmrs::AccountId;
use nym_contracts_common::signing::MessageSignature;
use nym_mixnet_contract_common::families::FamilyHead;
use nym_mixnet_contract_common::gateway::GatewayConfigUpdate;
use nym_mixnet_contract_common::mixnode::{MixNodeConfigUpdate, NodeCostParams};
use nym_mixnet_contract_common::nym_node::NodeConfigUpdate;
use nym_mixnet_contract_common::reward_params::{
ActiveSetUpdate, IntervalRewardingParamsUpdate, NodeRewardingParameters,
};
use nym_mixnet_contract_common::mixnode::{MixNodeConfigUpdate, MixNodeCostParams};
use nym_mixnet_contract_common::reward_params::{IntervalRewardingParamsUpdate, Performance};
use nym_mixnet_contract_common::{
ContractStateParams, ExecuteMsg as MixnetExecuteMsg, Gateway, MixNode, NodeId, NymNode,
RoleAssignment,
ContractStateParams, ExecuteMsg as MixnetExecuteMsg, Gateway, Layer, LayerAssignment, MixId,
MixNode,
};
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
@@ -72,14 +70,14 @@ pub trait MixnetSigningClient {
async fn update_active_set_size(
&self,
update: ActiveSetUpdate,
active_set_size: u32,
force_immediately: bool,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract(
fee,
MixnetExecuteMsg::UpdateActiveSetDistribution {
update,
MixnetExecuteMsg::UpdateActiveSetSize {
active_set_size,
force_immediately,
},
vec![],
@@ -128,6 +126,37 @@ pub trait MixnetSigningClient {
.await
}
async fn advance_current_epoch(
&self,
new_rewarded_set: Vec<LayerAssignment>,
expected_active_set_size: u32,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract(
fee,
MixnetExecuteMsg::AdvanceCurrentEpoch {
new_rewarded_set,
expected_active_set_size,
},
vec![],
)
.await
}
async fn assign_node_layer(
&self,
mix_id: MixId,
layer: Layer,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract(
fee,
MixnetExecuteMsg::AssignNodeLayer { mix_id, layer },
vec![],
)
.await
}
async fn reconcile_epoch_events(
&self,
limit: Option<u32>,
@@ -141,21 +170,126 @@ pub trait MixnetSigningClient {
.await
}
async fn assign_roles(
// family related
async fn create_family(
&self,
assignment: RoleAssignment,
label: String,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract(fee, MixnetExecuteMsg::AssignRoles { assignment }, vec![])
self.execute_mixnet_contract(fee, MixnetExecuteMsg::CreateFamily { label }, vec![])
.await
}
async fn create_family_on_behalf(
&self,
owner_address: String,
label: String,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract(
fee,
MixnetExecuteMsg::CreateFamilyOnBehalf {
owner_address,
label,
},
vec![],
)
.await
}
async fn join_family(
&self,
join_permit: MessageSignature,
family_head: FamilyHead,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract(
fee,
MixnetExecuteMsg::JoinFamily {
join_permit,
family_head,
},
vec![],
)
.await
}
async fn join_family_on_behalf(
&self,
member_address: String,
join_permit: MessageSignature,
family_head: FamilyHead,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract(
fee,
MixnetExecuteMsg::JoinFamilyOnBehalf {
member_address,
join_permit,
family_head,
},
vec![],
)
.await
}
async fn leave_family(
&self,
family_head: FamilyHead,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract(fee, MixnetExecuteMsg::LeaveFamily { family_head }, vec![])
.await
}
async fn leave_family_on_behalf(
&self,
member_address: String,
family_head: FamilyHead,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract(
fee,
MixnetExecuteMsg::LeaveFamilyOnBehalf {
member_address,
family_head,
},
vec![],
)
.await
}
async fn kick_family_member(
&self,
member: String,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract(fee, MixnetExecuteMsg::KickFamilyMember { member }, vec![])
.await
}
async fn kick_family_member_on_behalf(
&self,
head_address: String,
member: String,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract(
fee,
MixnetExecuteMsg::KickFamilyMemberOnBehalf {
head_address,
member,
},
vec![],
)
.await
}
// mixnode-related:
async fn bond_mixnode(
&self,
mix_node: MixNode,
cost_params: NodeCostParams,
cost_params: MixNodeCostParams,
owner_signature: MessageSignature,
pledge: Coin,
fee: Option<Fee>,
@@ -176,7 +310,7 @@ pub trait MixnetSigningClient {
&self,
owner: AccountId,
mix_node: MixNode,
cost_params: NodeCostParams,
cost_params: MixNodeCostParams,
owner_signature: MessageSignature,
pledge: Coin,
fee: Option<Fee>,
@@ -275,14 +409,14 @@ pub trait MixnetSigningClient {
.await
}
async fn update_cost_params(
async fn update_mixnode_cost_params(
&self,
new_costs: NodeCostParams,
new_costs: MixNodeCostParams,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract(
fee,
MixnetExecuteMsg::UpdateCostParams { new_costs },
MixnetExecuteMsg::UpdateMixnodeCostParams { new_costs },
vec![],
)
.await
@@ -291,7 +425,7 @@ pub trait MixnetSigningClient {
async fn update_mixnode_cost_params_on_behalf(
&self,
owner: AccountId,
new_costs: NodeCostParams,
new_costs: MixNodeCostParams,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract(
@@ -425,75 +559,26 @@ pub trait MixnetSigningClient {
.await
}
// nym-node related:
async fn migrate_legacy_mixnode(&self, fee: Option<Fee>) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract(fee, MixnetExecuteMsg::MigrateMixnode {}, vec![])
.await
}
async fn migrate_legacy_gateway(
&self,
cost_params: Option<NodeCostParams>,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract(
fee,
MixnetExecuteMsg::MigrateGateway { cost_params },
vec![],
)
.await
}
async fn bond_nymnode(
&self,
node: NymNode,
cost_params: NodeCostParams,
owner_signature: MessageSignature,
pledge: Coin,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract(
fee,
MixnetExecuteMsg::BondNymNode {
node,
cost_params,
owner_signature,
},
vec![pledge],
)
.await
}
async fn unbond_nymnode(&self, fee: Option<Fee>) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract(fee, MixnetExecuteMsg::UnbondNymNode {}, vec![])
.await
}
async fn update_nymnode_config(
&self,
update: NodeConfigUpdate,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract(fee, MixnetExecuteMsg::UpdateNodeConfig { update }, vec![])
.await
}
// delegation-related:
async fn delegate(
async fn delegate_to_mixnode(
&self,
node_id: NodeId,
mix_id: MixId,
amount: Coin,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract(fee, MixnetExecuteMsg::Delegate { node_id }, vec![amount])
.await
self.execute_mixnet_contract(
fee,
MixnetExecuteMsg::DelegateToMixnode { mix_id },
vec![amount],
)
.await
}
async fn delegate_to_mixnode_on_behalf(
&self,
delegate: AccountId,
mix_id: NodeId,
mix_id: MixId,
amount: Coin,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
@@ -508,19 +593,23 @@ pub trait MixnetSigningClient {
.await
}
async fn undelegate(
async fn undelegate_from_mixnode(
&self,
node_id: NodeId,
mix_id: MixId,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract(fee, MixnetExecuteMsg::Undelegate { node_id }, vec![])
.await
self.execute_mixnet_contract(
fee,
MixnetExecuteMsg::UndelegateFromMixnode { mix_id },
vec![],
)
.await
}
async fn undelegate_to_mixnode_on_behalf(
&self,
delegate: AccountId,
mix_id: NodeId,
mix_id: MixId,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract(
@@ -536,15 +625,18 @@ pub trait MixnetSigningClient {
// reward-related
async fn reward_node(
async fn reward_mixnode(
&self,
node_id: NodeId,
params: NodeRewardingParameters,
mix_id: MixId,
performance: Performance,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract(
fee,
MixnetExecuteMsg::RewardNode { node_id, params },
MixnetExecuteMsg::RewardMixnode {
mix_id,
performance,
},
vec![],
)
.await
@@ -572,12 +664,12 @@ pub trait MixnetSigningClient {
async fn withdraw_delegator_reward(
&self,
node_id: NodeId,
mix_id: MixId,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract(
fee,
MixnetExecuteMsg::WithdrawDelegatorReward { node_id },
MixnetExecuteMsg::WithdrawDelegatorReward { mix_id },
vec![],
)
.await
@@ -586,7 +678,7 @@ pub trait MixnetSigningClient {
async fn withdraw_delegator_reward_on_behalf(
&self,
owner: AccountId,
mix_id: NodeId,
mix_id: MixId,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract(
@@ -607,7 +699,7 @@ pub trait MixnetSigningClient {
async fn migrate_vested_delegation(
&self,
mix_id: NodeId,
mix_id: MixId,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract(
@@ -669,7 +761,6 @@ where
mod tests {
use super::*;
use crate::nyxd::contract_traits::tests::{mock_coin, IgnoreValue};
use nym_mixnet_contract_common::ExecuteMsg;
// it's enough that this compiles and clippy is happy about it
#[allow(dead_code)]
@@ -679,17 +770,56 @@ mod tests {
) {
match msg {
MixnetExecuteMsg::UpdateAdmin { admin } => client.update_admin(admin, None).ignore(),
MixnetExecuteMsg::AssignNodeLayer { mix_id, layer } => {
client.assign_node_layer(mix_id, layer, None).ignore()
}
MixnetExecuteMsg::CreateFamily { label } => client.create_family(label, None).ignore(),
MixnetExecuteMsg::JoinFamily {
join_permit,
family_head,
} => client.join_family(join_permit, family_head, None).ignore(),
MixnetExecuteMsg::LeaveFamily { family_head } => {
client.leave_family(family_head, None).ignore()
}
MixnetExecuteMsg::KickFamilyMember { member } => {
client.kick_family_member(member, None).ignore()
}
MixnetExecuteMsg::CreateFamilyOnBehalf {
owner_address,
label,
} => client
.create_family_on_behalf(owner_address, label, None)
.ignore(),
MixnetExecuteMsg::JoinFamilyOnBehalf {
member_address,
join_permit,
family_head,
} => client
.join_family_on_behalf(member_address, join_permit, family_head, None)
.ignore(),
MixnetExecuteMsg::LeaveFamilyOnBehalf {
member_address,
family_head,
} => client
.leave_family_on_behalf(member_address, family_head, None)
.ignore(),
MixnetExecuteMsg::KickFamilyMemberOnBehalf {
head_address,
member,
} => client
.kick_family_member_on_behalf(head_address, member, None)
.ignore(),
MixnetExecuteMsg::UpdateRewardingValidatorAddress { address } => client
.update_rewarding_validator_address(address.parse().unwrap(), None)
.ignore(),
MixnetExecuteMsg::UpdateContractStateParams { updated_parameters } => client
.update_contract_state_params(updated_parameters, None)
.ignore(),
MixnetExecuteMsg::UpdateActiveSetDistribution {
update,
MixnetExecuteMsg::UpdateActiveSetSize {
active_set_size,
force_immediately,
} => client
.update_active_set_size(update, force_immediately, None)
.update_active_set_size(active_set_size, force_immediately, None)
.ignore(),
MixnetExecuteMsg::UpdateRewardingParams {
updated_params,
@@ -712,6 +842,12 @@ mod tests {
MixnetExecuteMsg::BeginEpochTransition {} => {
client.begin_epoch_transition(None).ignore()
}
MixnetExecuteMsg::AdvanceCurrentEpoch {
new_rewarded_set,
expected_active_set_size,
} => client
.advance_current_epoch(new_rewarded_set, expected_active_set_size, None)
.ignore(),
MixnetExecuteMsg::ReconcileEpochEvents { limit } => {
client.reconcile_epoch_events(limit, None).ignore()
}
@@ -751,8 +887,8 @@ mod tests {
MixnetExecuteMsg::UnbondMixnodeOnBehalf { owner } => client
.unbond_mixnode_on_behalf(owner.parse().unwrap(), None)
.ignore(),
MixnetExecuteMsg::UpdateCostParams { new_costs } => {
client.update_cost_params(new_costs, None).ignore()
MixnetExecuteMsg::UpdateMixnodeCostParams { new_costs } => {
client.update_mixnode_cost_params(new_costs, None).ignore()
}
MixnetExecuteMsg::UpdateMixnodeCostParamsOnBehalf { new_costs, owner } => client
.update_mixnode_cost_params_on_behalf(owner.parse().unwrap(), new_costs, None)
@@ -792,28 +928,29 @@ mod tests {
MixnetExecuteMsg::UpdateGatewayConfigOnBehalf { new_config, owner } => client
.update_gateway_config_on_behalf(owner.parse().unwrap(), new_config, None)
.ignore(),
MixnetExecuteMsg::Delegate { node_id: mix_id } => {
client.delegate(mix_id, mock_coin(), None).ignore()
}
MixnetExecuteMsg::DelegateToMixnode { mix_id } => client
.delegate_to_mixnode(mix_id, mock_coin(), None)
.ignore(),
MixnetExecuteMsg::DelegateToMixnodeOnBehalf { mix_id, delegate } => client
.delegate_to_mixnode_on_behalf(delegate.parse().unwrap(), mix_id, mock_coin(), None)
.ignore(),
MixnetExecuteMsg::Undelegate { node_id: mix_id } => {
client.undelegate(mix_id, None).ignore()
MixnetExecuteMsg::UndelegateFromMixnode { mix_id } => {
client.undelegate_from_mixnode(mix_id, None).ignore()
}
MixnetExecuteMsg::UndelegateFromMixnodeOnBehalf { mix_id, delegate } => client
.undelegate_to_mixnode_on_behalf(delegate.parse().unwrap(), mix_id, None)
.ignore(),
MixnetExecuteMsg::RewardNode { node_id, params } => {
client.reward_node(node_id, params, None).ignore()
}
MixnetExecuteMsg::RewardMixnode {
mix_id,
performance,
} => client.reward_mixnode(mix_id, performance, None).ignore(),
MixnetExecuteMsg::WithdrawOperatorReward {} => {
client.withdraw_operator_reward(None).ignore()
}
MixnetExecuteMsg::WithdrawOperatorRewardOnBehalf { owner } => client
.withdraw_operator_reward_on_behalf(owner.parse().unwrap(), None)
.ignore(),
MixnetExecuteMsg::WithdrawDelegatorReward { node_id: mix_id } => {
MixnetExecuteMsg::WithdrawDelegatorReward { mix_id } => {
client.withdraw_delegator_reward(mix_id, None).ignore()
}
MixnetExecuteMsg::WithdrawDelegatorRewardOnBehalf { mix_id, owner } => client
@@ -826,25 +963,6 @@ mod tests {
client.migrate_vested_delegation(mix_id, None).ignore()
}
ExecuteMsg::AssignRoles { assignment } => {
client.assign_roles(assignment, None).ignore()
}
ExecuteMsg::MigrateMixnode {} => client.migrate_legacy_mixnode(None).ignore(),
ExecuteMsg::MigrateGateway { cost_params } => {
client.migrate_legacy_gateway(cost_params, None).ignore()
}
ExecuteMsg::BondNymNode {
node,
cost_params,
owner_signature,
} => client
.bond_nymnode(node, cost_params, owner_signature, mock_coin(), None)
.ignore(),
ExecuteMsg::UnbondNymNode {} => client.unbond_nymnode(None).ignore(),
ExecuteMsg::UpdateNodeConfig { update } => {
client.update_nymnode_config(update, None).ignore()
}
#[cfg(feature = "contract-testing")]
MixnetExecuteMsg::TestingResolveAllPendingEvents { .. } => {
client.testing_resolve_all_pending_events(None).ignore()
@@ -9,7 +9,7 @@ use crate::nyxd::CosmWasmClient;
use async_trait::async_trait;
use cosmwasm_std::{Coin as CosmWasmCoin, Timestamp};
use nym_contracts_common::ContractBuildInformation;
use nym_mixnet_contract_common::NodeId;
use nym_mixnet_contract_common::MixId;
use nym_vesting_contract_common::{
messages::QueryMsg as VestingQueryMsg, Account, AccountVestingCoins, AccountsResponse,
AllDelegationsResponse, BaseVestingAccountInfo, DelegationTimesResponse,
@@ -238,7 +238,7 @@ pub trait VestingQueryClient {
async fn get_vesting_delegation(
&self,
address: &str,
mix_id: NodeId,
mix_id: MixId,
block_timestamp_secs: u64,
) -> Result<VestingDelegation, NyxdError> {
self.query_vesting_contract(VestingQueryMsg::GetDelegation {
@@ -252,7 +252,7 @@ pub trait VestingQueryClient {
async fn get_total_delegation_amount(
&self,
address: &str,
mix_id: NodeId,
mix_id: MixId,
) -> Result<Coin, NyxdError> {
self.query_vesting_contract(VestingQueryMsg::GetTotalDelegationAmount {
address: address.to_string(),
@@ -264,7 +264,7 @@ pub trait VestingQueryClient {
async fn get_delegation_timestamps(
&self,
address: &str,
mix_id: NodeId,
mix_id: MixId,
) -> Result<DelegationTimesResponse, NyxdError> {
self.query_vesting_contract(VestingQueryMsg::GetDelegationTimes {
address: address.to_string(),
@@ -275,7 +275,7 @@ pub trait VestingQueryClient {
async fn get_all_vesting_delegations_paged(
&self,
start_after: Option<(u32, NodeId, u64)>,
start_after: Option<(u32, MixId, u64)>,
limit: Option<u32>,
) -> Result<AllDelegationsResponse, NyxdError> {
self.query_vesting_contract(VestingQueryMsg::GetAllDelegations { start_after, limit })
@@ -9,9 +9,10 @@ use crate::signing::signer::OfflineSigner;
use async_trait::async_trait;
use cosmrs::AccountId;
use nym_contracts_common::signing::MessageSignature;
use nym_mixnet_contract_common::families::FamilyHead;
use nym_mixnet_contract_common::gateway::GatewayConfigUpdate;
use nym_mixnet_contract_common::mixnode::{MixNodeConfigUpdate, NodeCostParams};
use nym_mixnet_contract_common::{Gateway, MixNode, NodeId};
use nym_mixnet_contract_common::mixnode::{MixNodeConfigUpdate, MixNodeCostParams};
use nym_mixnet_contract_common::{Gateway, MixId, MixNode};
use nym_vesting_contract_common::messages::ExecuteMsg as VestingExecuteMsg;
use nym_vesting_contract_common::{PledgeCap, VestingSpecification};
@@ -27,7 +28,7 @@ pub trait VestingSigningClient {
async fn vesting_update_mixnode_cost_params(
&self,
new_costs: NodeCostParams,
new_costs: MixNodeCostParams,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_vesting_contract(
@@ -123,7 +124,7 @@ pub trait VestingSigningClient {
async fn vesting_bond_mixnode(
&self,
mix_node: MixNode,
cost_params: NodeCostParams,
cost_params: MixNodeCostParams,
owner_signature: MessageSignature,
pledge: Coin,
fee: Option<Fee>,
@@ -203,7 +204,7 @@ pub trait VestingSigningClient {
async fn vesting_track_undelegation(
&self,
address: &str,
mix_id: NodeId,
mix_id: MixId,
amount: Coin,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
@@ -221,7 +222,7 @@ pub trait VestingSigningClient {
async fn vesting_delegate_to_mixnode(
&self,
mix_id: NodeId,
mix_id: MixId,
amount: Coin,
on_behalf_of: Option<String>,
fee: Option<Fee>,
@@ -240,7 +241,7 @@ pub trait VestingSigningClient {
async fn vesting_undelegate_from_mixnode(
&self,
mix_id: NodeId,
mix_id: MixId,
on_behalf_of: Option<String>,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
@@ -300,7 +301,7 @@ pub trait VestingSigningClient {
async fn vesting_withdraw_delegator_reward(
&self,
mix_id: NodeId,
mix_id: MixId,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_vesting_contract(
@@ -353,6 +354,50 @@ pub trait VestingSigningClient {
)
.await
}
async fn vesting_create_family(
&self,
label: String,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_vesting_contract(fee, VestingExecuteMsg::CreateFamily { label }, vec![])
.await
}
async fn vesting_join_family(
&self,
join_permit: MessageSignature,
family_head: FamilyHead,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_vesting_contract(
fee,
VestingExecuteMsg::JoinFamily {
join_permit,
family_head,
},
vec![],
)
.await
}
async fn vesting_leave_family(
&self,
family_head: FamilyHead,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_vesting_contract(fee, VestingExecuteMsg::LeaveFamily { family_head }, vec![])
.await
}
async fn vesting_kick_family_member(
&self,
member: String,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_vesting_contract(fee, VestingExecuteMsg::KickFamilyMember { member }, vec![])
.await
}
}
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
@@ -401,6 +446,21 @@ mod tests {
msg: VestingExecuteMsg,
) {
match msg {
VestingExecuteMsg::CreateFamily { label } => {
client.vesting_create_family(label, None).ignore()
}
VestingExecuteMsg::JoinFamily {
join_permit,
family_head,
} => client
.vesting_join_family(join_permit, family_head, None)
.ignore(),
VestingExecuteMsg::LeaveFamily { family_head } => {
client.vesting_leave_family(family_head, None).ignore()
}
VestingExecuteMsg::KickFamilyMember { member } => {
client.vesting_kick_family_member(member, None).ignore()
}
VestingExecuteMsg::TrackReward { amount, address } => client
.vesting_track_reward(amount.into(), address, None)
.ignore(),
@@ -29,6 +29,7 @@ use cosmrs::proto::cosmwasm::wasm::v1::{
};
use cosmrs::tendermint::{block, chain, Hash};
use cosmrs::{AccountId, Coin as CosmosCoin, Tx};
use log::trace;
use prost::Message;
use serde::{Deserialize, Serialize};
@@ -67,7 +68,7 @@ pub trait CosmWasmClient: TendermintRpcClient {
Res: Message + Default,
{
if let Some(ref abci_path) = path {
tracing::trace!("performing query on abci path {abci_path}")
trace!("performing query on abci path {abci_path}")
}
let mut buf = Vec::with_capacity(req.encoded_len());
req.encode(&mut buf)?;
@@ -296,7 +297,7 @@ pub trait CosmWasmClient: TendermintRpcClient {
let start = Instant::now();
loop {
tracing::debug!(
log::debug!(
"Polling for result of including {} in a block...",
broadcasted.hash
);
@@ -521,7 +522,7 @@ pub trait CosmWasmClient: TendermintRpcClient {
.make_abci_query::<_, QuerySmartContractStateResponse>(path, req)
.await?;
tracing::trace!("raw query response: {}", String::from_utf8_lossy(&res.data));
trace!("raw query response: {}", String::from_utf8_lossy(&res.data));
Ok(serde_json::from_slice(&res.data)?)
}
@@ -25,12 +25,12 @@ use cosmrs::proto::cosmos::tx::signing::v1beta1::SignMode;
use cosmrs::staking::{MsgDelegate, MsgUndelegate};
use cosmrs::tx::{self, Msg};
use cosmrs::{cosmwasm, AccountId, Any, Tx};
use log::debug;
use serde::Serialize;
use sha2::Digest;
use sha2::Sha256;
use std::time::SystemTime;
use tendermint_rpc::endpoint::broadcast;
use tracing::debug;
fn empty_fee() -> tx::Fee {
tx::Fee {
@@ -7,9 +7,9 @@ use base64::Engine;
use cosmrs::abci::TxMsgData;
use cosmrs::cosmwasm::MsgExecuteContractResponse;
use cosmrs::proto::cosmos::base::query::v1beta1::{PageRequest, PageResponse};
use log::error;
use prost::bytes::Bytes;
use tendermint_rpc::endpoint::broadcast;
use tracing::error;
pub use cosmrs::abci::MsgResponse;
@@ -154,23 +154,6 @@ pub enum NyxdError {
#[error("the response data has invalid size. got {got} bytes, but expected {expected} bytes instead")]
MalformedResponseData { got: usize, expected: usize },
#[error(
"one of the extension query for {contract} failed with the following message: {message}"
)]
ExtensionQueryFailure { contract: String, message: String },
}
impl NyxdError {
pub fn extension_query_failure(
contract: impl Into<String>,
message: impl Into<String>,
) -> Self {
NyxdError::ExtensionQueryFailure {
contract: contract.into(),
message: message.into(),
}
}
}
// The purpose of parsing the abci query result is that we want to generate the `pretty_log` if
@@ -4,7 +4,6 @@
use clap::Parser;
use cosmwasm_std::Decimal;
use log::{debug, info};
use nym_mixnet_contract_common::reward_params::RewardedSetParams;
use nym_mixnet_contract_common::{
InitialRewardingParams, InstantiateMsg, OperatingCostRange, Percent, ProfitMarginRange,
};
@@ -57,17 +56,11 @@ pub struct Args {
#[clap(long, default_value_t = 2)]
pub interval_pool_emission: u64,
#[clap(long, default_value_t = 50)]
pub(crate) entry_gateways: u32,
#[clap(long, default_value_t = 240)]
pub rewarded_set_size: u32,
#[clap(long, default_value_t = 70)]
pub(crate) exit_gateways: u32,
#[clap(long, default_value_t = 120)]
pub(crate) mixnodes: u32,
#[clap(long, default_value_t = 0)]
pub(crate) standby: u32,
#[clap(long, default_value_t = 240)]
pub active_set_size: u32,
#[clap(long, default_value_t = Percent::zero())]
pub minimum_profit_margin_percent: Percent,
@@ -102,13 +95,8 @@ pub async fn generate(args: Args) {
.expect("active_set_work_factor can't be converted to Decimal"),
interval_pool_emission: Percent::from_percentage_value(args.interval_pool_emission)
.expect("interval_pool_emission can't be converted to Percent"),
rewarded_set_params: RewardedSetParams {
entry_gateways: args.entry_gateways,
exit_gateways: args.exit_gateways,
mixnodes: args.mixnodes,
standby: args.standby,
},
rewarded_set_size: args.rewarded_set_size,
active_set_size: args.active_set_size,
};
debug!("initial_rewarding_params: {:?}", initial_rewarding_params);
@@ -4,13 +4,13 @@
use crate::context::SigningClient;
use clap::Parser;
use log::info;
use nym_mixnet_contract_common::{Coin, NodeId};
use nym_mixnet_contract_common::{Coin, MixId};
use nym_validator_client::nyxd::contract_traits::{MixnetQueryClient, MixnetSigningClient};
#[derive(Debug, Parser)]
pub struct Args {
#[clap(long)]
pub mix_id: Option<NodeId>,
pub mix_id: Option<MixId>,
#[clap(long)]
pub identity_key: Option<String>,
@@ -43,7 +43,7 @@ pub async fn delegate_to_mixnode(args: Args, client: SigningClient) {
let coin = Coin::new(args.amount, denom);
let res = client
.delegate(mix_id, coin.into(), None)
.delegate_to_mixnode(mix_id, coin.into(), None)
.await
.expect("failed to delegate to mixnode!");
@@ -1,18 +1,21 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use std::cmp::Ordering;
use std::collections::{HashMap, HashSet};
use std::fs;
use std::fs::OpenOptions;
use clap::Parser;
use comfy_table::Table;
use csv::WriterBuilder;
use log::info;
use nym_mixnet_contract_common::ExecuteMsg;
use nym_mixnet_contract_common::PendingEpochEventKind;
use nym_mixnet_contract_common::ExecuteMsg::{DelegateToMixnode, UndelegateFromMixnode};
use nym_mixnet_contract_common::PendingEpochEventKind::{Delegate, Undelegate};
use nym_validator_client::nyxd::contract_traits::{NymContractsProvider, PagedMixnetQueryClient};
use nym_validator_client::nyxd::Coin;
use std::cmp::Ordering;
use std::collections::{HashMap, HashSet};
use std::fs;
use std::fs::OpenOptions;
use crate::context::SigningClient;
use crate::utils::pretty_coin;
@@ -37,7 +40,7 @@ pub struct Args {
#[derive(Debug)]
pub struct InputFileRow {
pub node_id: String,
pub mix_id: String,
pub amount: Coin,
}
#[derive(Debug)]
@@ -73,7 +76,7 @@ impl InputFileReader {
}
rows.push(InputFileRow {
node_id: mix_id,
mix_id,
amount: Coin {
amount: micro_nym_amount,
denom: "unym".to_string(),
@@ -137,10 +140,8 @@ async fn fetch_delegation_data(
let mut pending_delegation_map: HashMap<String, Coin> = HashMap::new();
for delegation in delegations {
existing_delegation_map.insert(
delegation.node_id.to_string(),
Coin::from(delegation.amount),
);
existing_delegation_map
.insert(delegation.mix_id.to_string(), Coin::from(delegation.amount));
}
// Look for pending delegate / undelegate events which might be of interest to us
@@ -154,27 +155,27 @@ async fn fetch_delegation_data(
for event in pending_events {
match event.event.kind {
// If a pending undelegate tx is found, remove it from delegation map
PendingEpochEventKind::Undelegate { owner, node_id, .. } => {
Undelegate { owner, mix_id, .. } => {
if owner == address.as_ref()
&& existing_delegation_map.contains_key(&node_id.to_string())
&& existing_delegation_map.contains_key(&mix_id.to_string())
{
existing_delegation_map.remove(&node_id.to_string());
existing_delegation_map.remove(&mix_id.to_string());
}
}
// If a pending delegation event is found, gather them to consolidate later
PendingEpochEventKind::Delegate {
Delegate {
owner,
node_id,
mix_id,
amount,
..
} => {
if owner == address.as_ref() {
let mut amount = Coin::from(amount);
if let Some(pending_record) = pending_delegation_map.get(&node_id.to_string()) {
if let Some(pending_record) = pending_delegation_map.get(&mix_id.to_string()) {
amount.amount += pending_record.amount;
}
pending_delegation_map.insert(node_id.to_string(), amount);
pending_delegation_map.insert(mix_id.to_string(), amount);
}
}
_ => {}
@@ -216,7 +217,7 @@ pub async fn delegate_to_multiple_mixnodes(args: Args, client: SigningClient) {
for row in &records.rows {
let input_amount = row.amount.amount;
let existing_delegation_amount = existing_delegation_map
.get(&row.node_id)
.get(&row.mix_id)
.map_or(0, |coin| coin.amount);
match existing_delegation_amount.cmp(&input_amount) {
@@ -228,26 +229,25 @@ pub async fn delegate_to_multiple_mixnodes(args: Args, client: SigningClient) {
amount: input_amount - existing_delegation_amount,
denom: row.amount.denom.clone(),
};
let node_id = row.node_id.clone().parse::<u32>().unwrap();
delegation_msgs.push((ExecuteMsg::Delegate { node_id }, vec![difference.clone()]));
let mix_id = row.mix_id.clone().parse::<u32>().unwrap();
delegation_msgs.push((DelegateToMixnode { mix_id }, vec![difference.clone()]));
delegation_table.add_row(&[
row.node_id.clone(),
row.mix_id.clone(),
pretty_coin(&row.amount),
pretty_coin(&difference),
]);
}
Ordering::Greater => {
let node_id = row.node_id.clone().parse::<u32>().unwrap();
let mix_id = row.mix_id.clone().parse::<u32>().unwrap();
let coins: Vec<Coin> = vec![];
undelegation_msgs.push((ExecuteMsg::Undelegate { node_id }, coins));
undelegation_table.add_row(&[row.node_id.clone()]);
undelegation_msgs.push((UndelegateFromMixnode { mix_id }, coins));
undelegation_table.add_row(&[row.mix_id.clone()]);
if row.amount.amount > 0 {
delegation_msgs
.push((ExecuteMsg::Delegate { node_id }, vec![row.amount.clone()]));
delegation_msgs.push((DelegateToMixnode { mix_id }, vec![row.amount.clone()]));
delegation_table.add_row(&[
row.node_id.clone(),
row.mix_id.clone(),
pretty_coin(&row.amount),
pretty_coin(&row.amount),
]);
@@ -4,13 +4,13 @@
use crate::context::SigningClient;
use clap::Parser;
use log::info;
use nym_mixnet_contract_common::NodeId;
use nym_mixnet_contract_common::MixId;
use nym_validator_client::nyxd::contract_traits::{MixnetQueryClient, MixnetSigningClient};
#[derive(Debug, Parser)]
pub struct Args {
#[clap(long)]
pub mix_id: Option<NodeId>,
pub mix_id: Option<MixId>,
#[clap(long)]
pub identity_key: Option<String>,
@@ -66,7 +66,7 @@ async fn print_delegations(delegations: Vec<Delegation>, client: &SigningClientW
for delegation in delegations {
table.add_row(vec![
to_iso_timestamp(delegation.height as u32, client).await,
delegation.node_id.to_string(),
delegation.mix_id.to_string(),
pretty_cosmwasm_coin(&delegation.amount),
delegation
.proxy
@@ -93,7 +93,7 @@ async fn print_delegation_events(events: Vec<PendingEpochEvent>, client: &Signin
match event.event.kind {
PendingEpochEventKind::Delegate {
owner,
node_id: mix_id,
mix_id,
amount,
proxy,
..
@@ -110,7 +110,7 @@ async fn print_delegation_events(events: Vec<PendingEpochEvent>, client: &Signin
}
PendingEpochEventKind::Undelegate {
owner,
node_id: mix_id,
mix_id,
proxy,
..
} => {
@@ -4,13 +4,13 @@
use crate::context::SigningClient;
use clap::Parser;
use log::info;
use nym_mixnet_contract_common::NodeId;
use nym_mixnet_contract_common::MixId;
use nym_validator_client::nyxd::contract_traits::{MixnetQueryClient, MixnetSigningClient};
#[derive(Debug, Parser)]
pub struct Args {
#[clap(long)]
pub mix_id: Option<NodeId>,
pub mix_id: Option<MixId>,
#[clap(long)]
pub identity_key: Option<String>,
@@ -4,13 +4,13 @@
use crate::context::SigningClient;
use clap::Parser;
use log::info;
use nym_mixnet_contract_common::NodeId;
use nym_mixnet_contract_common::MixId;
use nym_validator_client::nyxd::contract_traits::{MixnetQueryClient, MixnetSigningClient};
#[derive(Debug, Parser)]
pub struct Args {
#[clap(long)]
pub mix_id: Option<NodeId>,
pub mix_id: Option<MixId>,
#[clap(long)]
pub identity_key: Option<String>,
@@ -4,13 +4,13 @@
use crate::context::SigningClient;
use clap::Parser;
use log::info;
use nym_mixnet_contract_common::NodeId;
use nym_mixnet_contract_common::MixId;
use nym_validator_client::nyxd::contract_traits::{MixnetQueryClient, MixnetSigningClient};
#[derive(Debug, Parser)]
pub struct Args {
#[clap(long)]
pub mix_id: Option<NodeId>,
pub mix_id: Option<MixId>,
#[clap(long)]
pub identity_key: Option<String>,
@@ -36,7 +36,7 @@ pub async fn undelegate_from_mixnode(args: Args, client: SigningClient) {
};
let res = client
.undelegate(mix_id, None)
.undelegate_from_mixnode(mix_id, None)
.await
.expect("failed to remove stake from mixnode!");
@@ -4,7 +4,7 @@
use clap::Parser;
use log::info;
use nym_mixnet_contract_common::{Coin, NodeId};
use nym_mixnet_contract_common::{Coin, MixId};
use nym_validator_client::nyxd::contract_traits::MixnetQueryClient;
use nym_validator_client::nyxd::contract_traits::VestingSigningClient;
@@ -13,7 +13,7 @@ use crate::context::SigningClient;
#[derive(Debug, Parser)]
pub struct Args {
#[clap(long)]
pub mix_id: Option<NodeId>,
pub mix_id: Option<MixId>,
#[clap(long)]
pub identity_key: Option<String>,
@@ -3,7 +3,7 @@
use clap::Parser;
use log::info;
use nym_mixnet_contract_common::NodeId;
use nym_mixnet_contract_common::MixId;
use nym_validator_client::nyxd::contract_traits::MixnetQueryClient;
use nym_validator_client::nyxd::contract_traits::VestingSigningClient;
@@ -12,7 +12,7 @@ use crate::context::SigningClient;
#[derive(Debug, Parser)]
pub struct Args {
#[clap(long)]
pub mix_id: Option<NodeId>,
pub mix_id: Option<MixId>,
#[clap(long)]
pub identity_key: Option<String>,
@@ -5,7 +5,6 @@ use clap::{Args, Subcommand};
pub mod bond_gateway;
pub mod gateway_bonding_sign_payload;
pub mod nymnode_migration;
pub mod settings;
pub mod unbond_gateway;
pub mod vesting_bond_gateway;
@@ -32,6 +31,4 @@ pub enum MixnetOperatorsGatewayCommands {
VestingUnbond(vesting_unbond_gateway::Args),
/// Create base58-encoded payload required for producing valid bonding signature.
CreateGatewayBondingSignPayload(gateway_bonding_sign_payload::Args),
/// Migrate the gateway into a Nym Node
MigrateToNymnode(nymnode_migration::Args),
}
@@ -1,56 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::context::SigningClient;
use clap::Parser;
use cosmwasm_std::Uint128;
use log::info;
use nym_contracts_common::Percent;
use nym_mixnet_contract_common::{
NodeCostParams, DEFAULT_INTERVAL_OPERATING_COST_AMOUNT, DEFAULT_PROFIT_MARGIN_PERCENT,
};
use nym_validator_client::nyxd::contract_traits::MixnetSigningClient;
use nym_validator_client::nyxd::CosmWasmCoin;
#[derive(Debug, Parser)]
pub struct Args {
#[clap(long)]
pub profit_margin_percent: Option<u64>,
#[clap(
long,
help = "operating cost in current DENOMINATION (so it would be 'unym', rather than 'nym')"
)]
pub interval_operating_cost: Option<u128>,
}
pub async fn migrate_to_nymnode(args: Args, client: SigningClient) {
let denom = client.current_chain_details().mix_denom.base.as_str();
let cost_params =
if args.profit_margin_percent.is_some() || args.interval_operating_cost.is_some() {
Some(NodeCostParams {
profit_margin_percent: Percent::from_percentage_value(
args.profit_margin_percent
.unwrap_or(DEFAULT_PROFIT_MARGIN_PERCENT),
)
.unwrap(),
interval_operating_cost: CosmWasmCoin {
denom: denom.into(),
amount: Uint128::new(
args.interval_operating_cost
.unwrap_or(DEFAULT_INTERVAL_OPERATING_COST_AMOUNT),
),
},
})
} else {
None
};
let res = client
.migrate_legacy_gateway(cost_params, None)
.await
.expect("failed to migrate gateway!");
info!("migration result: {:?}", res)
}
@@ -1,21 +1,20 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::context::SigningClient;
use clap::Parser;
use cosmwasm_std::Uint128;
use log::{info, warn};
use nym_contracts_common::signing::MessageSignature;
use nym_mixnet_contract_common::{
Coin, NodeCostParams, Percent, DEFAULT_INTERVAL_OPERATING_COST_AMOUNT,
DEFAULT_PROFIT_MARGIN_PERCENT,
};
use nym_mixnet_contract_common::{Coin, MixNodeCostParams, Percent};
use nym_network_defaults::{
DEFAULT_HTTP_API_LISTENING_PORT, DEFAULT_MIX_LISTENING_PORT, DEFAULT_VERLOC_LISTENING_PORT,
};
use nym_validator_client::nyxd::contract_traits::MixnetSigningClient;
use nym_validator_client::nyxd::CosmWasmCoin;
use crate::context::SigningClient;
#[derive(Debug, Parser)]
pub struct Args {
#[clap(long)]
@@ -43,7 +42,7 @@ pub struct Args {
pub version: String,
#[clap(long)]
pub profit_margin_percent: Option<u64>,
pub profit_margin_percent: Option<u8>,
#[clap(
long,
@@ -86,18 +85,14 @@ pub async fn bond_mixnode(args: Args, client: SigningClient) {
let coin = Coin::new(args.amount, denom);
let cost_params = NodeCostParams {
let cost_params = MixNodeCostParams {
profit_margin_percent: Percent::from_percentage_value(
args.profit_margin_percent
.unwrap_or(DEFAULT_PROFIT_MARGIN_PERCENT),
args.profit_margin_percent.unwrap_or(10) as u64,
)
.unwrap(),
interval_operating_cost: CosmWasmCoin {
denom: denom.into(),
amount: Uint128::new(
args.interval_operating_cost
.unwrap_or(DEFAULT_INTERVAL_OPERATING_COST_AMOUNT),
),
amount: Uint128::new(args.interval_operating_cost.unwrap_or(40_000_000)),
},
};
@@ -0,0 +1,25 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::context::SigningClient;
use clap::Parser;
use log::info;
use nym_validator_client::nyxd::contract_traits::MixnetSigningClient;
#[derive(Debug, Parser)]
pub struct Args {
/// Label that is going to be used for creating the family
#[arg(long)]
pub family_label: String,
}
pub async fn create_family(args: Args, client: SigningClient) {
info!("Create family");
let res = client
.create_family(args.family_label, None)
.await
.expect("failed to create family");
info!("Family creation result: {:?}", res);
}
@@ -0,0 +1,72 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::context::QueryClient;
use crate::utils::DataWrapper;
use clap::Parser;
use cosmrs::AccountId;
use log::info;
use nym_bin_common::output_format::OutputFormat;
use nym_crypto::asymmetric::identity;
use nym_mixnet_contract_common::construct_family_join_permit;
use nym_mixnet_contract_common::families::FamilyHead;
use nym_validator_client::nyxd::contract_traits::MixnetQueryClient;
#[derive(Debug, Parser)]
pub struct Args {
/// Account address (i.e. owner of the family head) which will be used for issuing the permit
#[arg(long)]
pub address: AccountId,
// might as well validate the value when parsing the arguments
/// Identity of the member for whom we're issuing the permit
#[arg(long)]
pub member: identity::PublicKey,
#[clap(short, long, default_value_t = OutputFormat::default())]
output: OutputFormat,
}
pub async fn create_family_join_permit_sign_payload(args: Args, client: QueryClient) {
info!("Create family join permit sign payload");
// get the address of our mixnode to recover the family head information
let Some(mixnode) = client
.get_owned_mixnode(&args.address)
.await
.unwrap()
.mixnode_details
else {
eprintln!("{} does not seem to even own a mixnode!", args.address);
return;
};
// make sure this mixnode is actually a family head
if client
.get_node_family_by_head(mixnode.bond_information.identity().to_string())
.await
.unwrap()
.family
.is_none()
{
eprintln!("{} does not even seem to own a family!", args.address);
return;
}
let nonce = match client.get_signing_nonce(&args.address).await {
Ok(nonce) => nonce,
Err(err) => {
eprint!(
"failed to query for the signing nonce of {}: {err}",
args.address
);
return;
}
};
let head = FamilyHead::new(mixnode.bond_information.identity());
let payload = construct_family_join_permit(nonce, head, args.member.to_base58_string());
let wrapper = DataWrapper::new(payload.to_base58_string().unwrap());
println!("{}", args.output.format(&wrapper))
}
@@ -0,0 +1,34 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::context::SigningClient;
use clap::Parser;
use log::info;
use nym_contracts_common::signing::MessageSignature;
use nym_crypto::asymmetric::identity;
use nym_mixnet_contract_common::families::FamilyHead;
use nym_validator_client::nyxd::contract_traits::MixnetSigningClient;
#[derive(Debug, Parser)]
pub struct Args {
/// The head of the family that we intend to join
#[arg(long)]
pub family_head: identity::PublicKey,
/// Permission, as provided by the family head, for joining the family
#[arg(long)]
pub join_permit: MessageSignature,
}
pub async fn join_family(args: Args, client: SigningClient) {
info!("Join family");
let family_head = FamilyHead::new(args.family_head.to_base58_string());
let res = client
.join_family(args.join_permit, family_head, None)
.await
.expect("failed to join family");
info!("Family join result: {:?}", res);
}
@@ -0,0 +1,40 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::context::SigningClient;
use clap::Parser;
use log::info;
use nym_crypto::asymmetric::identity;
use nym_validator_client::nyxd::contract_traits::MixnetSigningClient;
use nym_validator_client::nyxd::contract_traits::VestingSigningClient;
#[derive(Debug, Parser)]
pub struct Args {
/// The member of the family that we intend to kick
#[arg(long)]
pub member: identity::PublicKey,
/// Indicates whether the family was created (and managed) via the vesting contract
#[arg(long)]
pub with_vesting_account: bool,
}
pub async fn kick_family_member(args: Args, client: SigningClient) {
info!("Leave family");
let member = args.member.to_base58_string();
let res = if args.with_vesting_account {
client
.vesting_kick_family_member(member, None)
.await
.expect("failed to kick family member with vesting account")
} else {
client
.kick_family_member(member, None)
.await
.expect("failed to kick family member")
};
info!("Family leave result: {:?}", res);
}
@@ -0,0 +1,29 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::context::SigningClient;
use clap::Parser;
use log::info;
use nym_crypto::asymmetric::identity;
use nym_mixnet_contract_common::families::FamilyHead;
use nym_validator_client::nyxd::contract_traits::MixnetSigningClient;
#[derive(Debug, Parser)]
pub struct Args {
/// The head of the family that we intend to leave
#[arg(long)]
pub family_head: identity::PublicKey,
}
pub async fn leave_family(args: Args, client: SigningClient) {
info!("Leave family");
let family_head = FamilyHead::new(args.family_head.to_base58_string());
let res = client
.leave_family(family_head, None)
.await
.expect("failed to leave family");
info!("Family leave result: {:?}", res);
}
@@ -0,0 +1,35 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use clap::{Args, Subcommand};
pub mod create_family;
pub mod create_family_join_permit_sign_payload;
pub mod join_family;
pub mod kick_family_member;
pub mod leave_family;
#[derive(Debug, Args)]
#[clap(args_conflicts_with_subcommands = true, subcommand_required = true)]
pub struct MixnetOperatorsMixnodeFamilies {
#[clap(subcommand)]
pub command: MixnetOperatorsMixnodeFamiliesCommands,
}
#[derive(Debug, Subcommand)]
pub enum MixnetOperatorsMixnodeFamiliesCommands {
/// Create family
CreateFamily(create_family::Args),
/// Join family
JoinFamily(join_family::Args),
/// Leave family,
LeaveFamily(leave_family::Args),
/// Kick family member
KickFamilyMember(kick_family_member::Args),
/// Create a message payload that is required to get signed in order to obtain a permit for joining family
CreateFamilyJoinPermitSignPayload(create_family_join_permit_sign_payload::Args),
}
@@ -8,8 +8,7 @@ use cosmwasm_std::{Coin, Uint128};
use nym_bin_common::output_format::OutputFormat;
use nym_contracts_common::Percent;
use nym_mixnet_contract_common::{
construct_legacy_mixnode_bonding_sign_payload, NodeCostParams,
DEFAULT_INTERVAL_OPERATING_COST_AMOUNT, DEFAULT_PROFIT_MARGIN_PERCENT,
construct_legacy_mixnode_bonding_sign_payload, MixNodeCostParams,
};
use nym_network_defaults::{
DEFAULT_HTTP_API_LISTENING_PORT, DEFAULT_MIX_LISTENING_PORT, DEFAULT_VERLOC_LISTENING_PORT,
@@ -41,7 +40,7 @@ pub struct Args {
pub version: String,
#[clap(long)]
pub profit_margin_percent: Option<u64>,
pub profit_margin_percent: Option<u8>,
#[clap(
long,
@@ -76,18 +75,14 @@ pub async fn create_payload(args: Args, client: SigningClient) {
let coin = Coin::new(args.amount, denom);
let cost_params = NodeCostParams {
let cost_params = MixNodeCostParams {
profit_margin_percent: Percent::from_percentage_value(
args.profit_margin_percent
.unwrap_or(DEFAULT_PROFIT_MARGIN_PERCENT),
args.profit_margin_percent.unwrap_or(10) as u64,
)
.unwrap(),
interval_operating_cost: CosmWasmCoin {
denom: denom.into(),
amount: Uint128::new(
args.interval_operating_cost
.unwrap_or(DEFAULT_INTERVAL_OPERATING_COST_AMOUNT),
),
amount: Uint128::new(args.interval_operating_cost.unwrap_or(40_000_000)),
},
};
@@ -5,10 +5,10 @@ use clap::{Args, Subcommand};
pub mod bond_mixnode;
pub mod decrease_pledge;
pub mod families;
pub mod keys;
pub mod migrate_vested_mixnode;
pub mod mixnode_bonding_sign_payload;
pub mod nymnode_migration;
pub mod pledge_more;
pub mod rewards;
pub mod settings;
@@ -33,6 +33,8 @@ pub enum MixnetOperatorsMixnodeCommands {
Rewards(rewards::MixnetOperatorsMixnodeRewards),
/// Manage your mixnode settings stored in the directory
Settings(settings::MixnetOperatorsMixnodeSettings),
/// Operations for mixnode families
Families(families::MixnetOperatorsMixnodeFamilies),
/// Bond to a mixnode
Bond(bond_mixnode::Args),
/// Unbond from a mixnode
@@ -53,6 +55,4 @@ pub enum MixnetOperatorsMixnodeCommands {
DecreasePledgeVesting(vesting_decrease_pledge::Args),
/// Migrate the mixnode to use liquid tokens
MigrateVestedNode(migrate_vested_mixnode::Args),
/// Migrate the mixnode into a Nym Node
MigrateToNymnode(nymnode_migration::Args),
}
@@ -1,19 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::context::SigningClient;
use clap::Parser;
use log::info;
use nym_validator_client::nyxd::contract_traits::MixnetSigningClient;
#[derive(Debug, Parser)]
pub struct Args {}
pub async fn migrate_to_nymnode(_args: Args, client: SigningClient) {
let res = client
.migrate_legacy_mixnode(None)
.await
.expect("failed to migrate mixnode!");
info!("migration result: {:?}", res)
}
@@ -2,8 +2,12 @@
// SPDX-License-Identifier: Apache-2.0
use crate::context::SigningClient;
use crate::validator::mixnet::operators::nymnode;
use clap::Parser;
use cosmwasm_std::Uint128;
use log::info;
use nym_mixnet_contract_common::{MixNodeCostParams, Percent};
use nym_validator_client::nyxd::contract_traits::{MixnetQueryClient, MixnetSigningClient};
use nym_validator_client::nyxd::CosmWasmCoin;
#[derive(Debug, Parser)]
pub struct Args {
@@ -20,14 +24,62 @@ pub struct Args {
pub interval_operating_cost: Option<u128>,
}
pub async fn update_cost_params(args: Args, client: SigningClient) -> anyhow::Result<()> {
// the below can handle both, nymnode and legacy mixnode
nymnode::settings::update_cost_params::update_cost_params(
nymnode::settings::update_cost_params::Args {
profit_margin_percent: args.profit_margin_percent,
interval_operating_cost: args.interval_operating_cost,
pub async fn update_cost_params(args: Args, client: SigningClient) {
let denom = client.current_chain_details().mix_denom.base.as_str();
fn convert_to_percent(value: u64) -> Percent {
Percent::from_percentage_value(value).expect("Invalid value")
}
let default_profit_margin: Percent = convert_to_percent(20);
let mixownership_response = match client.get_owned_mixnode(&client.address()).await {
Ok(response) => response,
Err(_) => {
eprintln!("Failed to obtain owned mixnode");
return;
}
};
let mix_id = match mixownership_response.mixnode_details {
Some(details) => details.bond_information.mix_id,
None => {
eprintln!("Failed to obtain mixnode details");
return;
}
};
let rewarding_response = match client.get_mixnode_rewarding_details(mix_id).await {
Ok(details) => details,
Err(_) => {
eprintln!("Failed to obtain rewarding details");
return;
}
};
let profit_margin_percent = rewarding_response
.rewarding_details
.map(|rd| rd.cost_params.profit_margin_percent)
.unwrap_or(default_profit_margin);
let profit_margin_value = args
.profit_margin_percent
.map(|pm| convert_to_percent(pm as u64))
.unwrap_or(profit_margin_percent);
let cost_params = MixNodeCostParams {
profit_margin_percent: profit_margin_value,
interval_operating_cost: CosmWasmCoin {
denom: denom.into(),
amount: Uint128::new(args.interval_operating_cost.unwrap_or(40_000_000)),
},
client,
)
.await
};
info!("Starting mixnode params updating!");
let res = client
.update_mixnode_cost_params(cost_params, None)
.await
.expect("failed to update cost params");
info!("Cost params result: {:?}", res)
}
@@ -6,9 +6,7 @@ use clap::Parser;
use cosmwasm_std::Uint128;
use log::{info, warn};
use nym_contracts_common::signing::MessageSignature;
use nym_mixnet_contract_common::{
Coin, NodeCostParams, DEFAULT_INTERVAL_OPERATING_COST_AMOUNT, DEFAULT_PROFIT_MARGIN_PERCENT,
};
use nym_mixnet_contract_common::{Coin, MixNodeCostParams};
use nym_mixnet_contract_common::{MixNode, Percent};
use nym_network_defaults::{
DEFAULT_HTTP_API_LISTENING_PORT, DEFAULT_MIX_LISTENING_PORT, DEFAULT_VERLOC_LISTENING_PORT,
@@ -42,7 +40,7 @@ pub struct Args {
pub version: String,
#[clap(long)]
pub profit_margin_percent: Option<u64>,
pub profit_margin_percent: Option<u8>,
#[clap(
long,
@@ -86,18 +84,14 @@ pub async fn vesting_bond_mixnode(client: SigningClient, args: Args, denom: &str
let coin = Coin::new(args.amount, denom);
let cost_params = NodeCostParams {
let cost_params = MixNodeCostParams {
profit_margin_percent: Percent::from_percentage_value(
args.profit_margin_percent
.unwrap_or(DEFAULT_PROFIT_MARGIN_PERCENT),
args.profit_margin_percent.unwrap_or(10) as u64,
)
.unwrap(),
interval_operating_cost: CosmWasmCoin {
denom: denom.into(),
amount: Uint128::new(
args.interval_operating_cost
.unwrap_or(DEFAULT_INTERVAL_OPERATING_COST_AMOUNT),
),
amount: Uint128::new(args.interval_operating_cost.unwrap_or(40_000_000)),
},
};
@@ -6,7 +6,6 @@ use clap::{Args, Subcommand};
pub mod gateway;
pub mod identity_key;
pub mod mixnode;
pub mod nymnode;
#[derive(Debug, Args)]
#[clap(args_conflicts_with_subcommands = true, subcommand_required = true)]
@@ -18,11 +17,9 @@ pub struct MixnetOperators {
#[allow(clippy::large_enum_variant)]
#[derive(Debug, Subcommand)]
pub enum MixnetOperatorsCommands {
/// Manage your Nym Node
Nymnode(nymnode::MixnetOperatorsNymNode),
/// Manage your legacy mixnode
/// Manage your mixnode
Mixnode(mixnode::MixnetOperatorsMixnode),
/// Manage your legacy gateway
/// Manage your gateway
Gateway(gateway::MixnetOperatorsGateway),
/// Sign messages using your private identity key
IdentityKey(identity_key::MixnetOperatorsIdentityKey),
@@ -1,89 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::context::SigningClient;
use clap::Parser;
use cosmwasm_std::Uint128;
use log::{info, warn};
use nym_contracts_common::signing::MessageSignature;
use nym_mixnet_contract_common::{
Coin, NodeCostParams, Percent, DEFAULT_INTERVAL_OPERATING_COST_AMOUNT,
DEFAULT_PROFIT_MARGIN_PERCENT,
};
use nym_validator_client::nyxd::contract_traits::MixnetSigningClient;
use nym_validator_client::nyxd::CosmWasmCoin;
#[derive(Debug, Parser)]
pub struct Args {
#[clap(long)]
pub host: String,
#[clap(long)]
pub signature: MessageSignature,
#[clap(long)]
pub http_api_port: Option<u16>,
#[clap(long)]
pub identity_key: String,
#[clap(long)]
pub profit_margin_percent: Option<u64>,
#[clap(
long,
help = "operating cost in current DENOMINATION (so it would be 'unym', rather than 'nym')"
)]
pub interval_operating_cost: Option<u128>,
#[clap(
long,
help = "bonding amount in current DENOMINATION (so it would be 'unym', rather than 'nym')"
)]
pub amount: u128,
#[clap(short, long)]
pub force: bool,
}
pub async fn bond_nymnode(args: Args, client: SigningClient) {
let denom = client.current_chain_details().mix_denom.base.as_str();
info!("Starting nym node bonding!");
// if we're trying to bond less than 1 token
if args.amount < 1_000_000 && !args.force {
warn!("You're trying to bond only {}{} which is less than 1 full token. Are you sure that's what you want? If so, run with `--force` or `-f` flag", args.amount, denom);
return;
}
let nymnode = nym_mixnet_contract_common::NymNode {
host: args.host,
custom_http_port: args.http_api_port,
identity_key: args.identity_key,
};
let coin = Coin::new(args.amount, denom);
let cost_params = NodeCostParams {
profit_margin_percent: Percent::from_percentage_value(
args.profit_margin_percent
.unwrap_or(DEFAULT_PROFIT_MARGIN_PERCENT),
)
.unwrap(),
interval_operating_cost: CosmWasmCoin {
denom: denom.into(),
amount: Uint128::new(
args.interval_operating_cost
.unwrap_or(DEFAULT_INTERVAL_OPERATING_COST_AMOUNT),
),
},
};
let res = client
.bond_nymnode(nymnode, cost_params, args.signature, coin.into(), None)
.await
.expect("failed to bond nymnode!");
info!("Bonding result: {:?}", res)
}
@@ -1,20 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use base64::Engine;
use clap::Parser;
#[derive(Debug, Parser)]
pub struct Args {
#[clap(short, long)]
pub key: String,
}
pub fn decode_node_key(args: Args) {
let b64_decoded = base64::prelude::BASE64_STANDARD
.decode(args.key)
.expect("failed to decode base64 string");
let b58_encoded = bs58::encode(&b64_decoded).into_string();
println!("{b58_encoded}")
}
@@ -1,19 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use clap::{Args, Subcommand};
pub mod decode_node_key;
#[derive(Debug, Args)]
#[clap(args_conflicts_with_subcommands = true, subcommand_required = true)]
pub struct MixnetOperatorsNymNodeKeys {
#[clap(subcommand)]
pub command: MixnetOperatorsNymNodeKeysCommands,
}
#[derive(Debug, Subcommand)]
pub enum MixnetOperatorsNymNodeKeysCommands {
/// Decode a Nym Node key
DecodeNodeKey(decode_node_key::Args),
}
@@ -1,43 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use clap::{Args, Subcommand};
pub mod bond_nymnode;
pub mod keys;
pub mod nymnode_bonding_sign_payload;
pub mod pledge;
pub mod rewards;
pub mod settings;
pub mod unbond_nymnode;
#[derive(Debug, Args)]
#[clap(args_conflicts_with_subcommands = true, subcommand_required = true)]
pub struct MixnetOperatorsNymNode {
#[clap(subcommand)]
pub command: MixnetOperatorsNymNodeCommands,
}
#[derive(Debug, Subcommand)]
pub enum MixnetOperatorsNymNodeCommands {
/// Operations for Nym Node keys
Keys(keys::MixnetOperatorsNymNodeKeys),
/// Manage your Nym Node operator rewards
Rewards(rewards::MixnetOperatorsNymNodeRewards),
/// Manage your Nym Node settings stored in the directory
Settings(settings::MixnetOperatorsNymNodeSettings),
/// Manage your Nym Node pledge
Pledge(pledge::MixnetOperatorsNymNodePledge),
/// Bond to a Nym Node
Bond(bond_nymnode::Args),
/// Unbond from a Nym Node
Unbond(unbond_nymnode::Args),
/// Create base58-encoded payload required for producing valid bonding signature.
CreateNodeBondingSignPayload(nymnode_bonding_sign_payload::Args),
}
@@ -1,90 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::context::SigningClient;
use crate::utils::{account_id_to_cw_addr, DataWrapper};
use clap::Parser;
use cosmwasm_std::{Coin, Uint128};
use nym_bin_common::output_format::OutputFormat;
use nym_contracts_common::Percent;
use nym_mixnet_contract_common::{
construct_nym_node_bonding_sign_payload, NodeCostParams,
DEFAULT_INTERVAL_OPERATING_COST_AMOUNT, DEFAULT_PROFIT_MARGIN_PERCENT,
};
use nym_validator_client::nyxd::contract_traits::MixnetQueryClient;
use nym_validator_client::nyxd::CosmWasmCoin;
#[derive(Debug, Parser)]
pub struct Args {
#[clap(long)]
pub host: String,
#[clap(long)]
pub identity_key: String,
#[clap(long)]
pub custom_http_api_port: Option<u16>,
#[clap(long)]
pub profit_margin_percent: Option<u64>,
#[clap(
long,
help = "operating cost in current DENOMINATION (so it would be 'unym', rather than 'nym')"
)]
pub interval_operating_cost: Option<u128>,
#[clap(
long,
help = "bonding amount in current DENOMINATION (so it would be 'unym', rather than 'nym')"
)]
pub amount: u128,
#[clap(short, long, default_value_t = OutputFormat::default())]
pub output: OutputFormat,
}
pub async fn create_payload(args: Args, client: SigningClient) {
let denom = client.current_chain_details().mix_denom.base.as_str();
let mixnode = nym_mixnet_contract_common::NymNode {
host: args.host,
custom_http_port: args.custom_http_api_port,
identity_key: args.identity_key,
};
let coin = Coin::new(args.amount, denom);
let cost_params = NodeCostParams {
profit_margin_percent: Percent::from_percentage_value(
args.profit_margin_percent
.unwrap_or(DEFAULT_PROFIT_MARGIN_PERCENT),
)
.unwrap(),
interval_operating_cost: CosmWasmCoin {
denom: denom.into(),
amount: Uint128::new(
args.interval_operating_cost
.unwrap_or(DEFAULT_INTERVAL_OPERATING_COST_AMOUNT),
),
},
};
let nonce = match client.get_signing_nonce(&client.address()).await {
Ok(nonce) => nonce,
Err(err) => {
eprint!(
"failed to query for the signing nonce of {}: {err}",
client.address()
);
return;
}
};
let address = account_id_to_cw_addr(&client.address());
let payload =
construct_nym_node_bonding_sign_payload(nonce, address, coin, mixnode, cost_params);
let wrapper = DataWrapper::new(payload.to_base58_string().unwrap());
println!("{}", args.output.format(&wrapper))
}
@@ -1,29 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::context::SigningClient;
use clap::Parser;
use log::info;
use nym_mixnet_contract_common::Coin;
use nym_validator_client::nyxd::contract_traits::MixnetSigningClient;
#[derive(Debug, Parser)]
pub struct Args {
#[clap(long)]
pub decrease_by: u128,
}
pub async fn decrease_pledge(args: Args, client: SigningClient) {
let denom = client.current_chain_details().mix_denom.base.as_str();
info!("Starting to decrease pledge");
let coin = Coin::new(args.decrease_by, denom);
let res = client
.pledge_more(coin.into(), None)
.await
.expect("failed to decrease pledge!");
info!("decreasing pledge: {:?}", res);
}
@@ -1,29 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::context::SigningClient;
use clap::Parser;
use log::info;
use nym_mixnet_contract_common::Coin;
use nym_validator_client::nyxd::contract_traits::MixnetSigningClient;
#[derive(Debug, Parser)]
pub struct Args {
#[clap(long)]
pub amount: u128,
}
pub async fn increase_pledge(args: Args, client: SigningClient) {
let denom = client.current_chain_details().mix_denom.base.as_str();
info!("Starting to pledge more");
let coin = Coin::new(args.amount, denom);
let res = client
.pledge_more(coin.into(), None)
.await
.expect("failed to pledge more!");
info!("pledging more: {:?}", res);
}
@@ -1,22 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use clap::{Args, Subcommand};
pub mod decrease_pledge;
pub mod increase_pledge;
#[derive(Debug, Args)]
#[clap(args_conflicts_with_subcommands = true, subcommand_required = true)]
pub struct MixnetOperatorsNymNodePledge {
#[clap(subcommand)]
pub command: MixnetOperatorsNymNodePledgeCommands,
}
#[derive(Debug, Subcommand)]
pub enum MixnetOperatorsNymNodePledgeCommands {
/// Increase current pledge
Increase(increase_pledge::Args),
/// decrease current pledge
Decrease(decrease_pledge::Args),
}
@@ -1,21 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::context::SigningClient;
use clap::Parser;
use log::info;
use nym_validator_client::nyxd::contract_traits::MixnetSigningClient;
#[derive(Debug, Parser)]
pub struct Args {}
pub async fn claim_operator_reward(_args: Args, client: SigningClient) {
info!("Claim operator reward");
let res = client
.withdraw_operator_reward(None)
.await
.expect("failed to claim operator reward");
info!("Claiming operator reward: {:?}", res)
}
@@ -1,19 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use clap::{Args, Subcommand};
pub mod claim_operator_reward;
#[derive(Debug, Args)]
#[clap(args_conflicts_with_subcommands = true, subcommand_required = true)]
pub struct MixnetOperatorsNymNodeRewards {
#[clap(subcommand)]
pub command: MixnetOperatorsNymNodeRewardsCommands,
}
#[derive(Debug, Subcommand)]
pub enum MixnetOperatorsNymNodeRewardsCommands {
/// Claim rewards
Claim(claim_operator_reward::Args),
}
@@ -1,22 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use clap::{Args, Subcommand};
pub mod update_config;
pub mod update_cost_params;
#[derive(Debug, Args)]
#[clap(args_conflicts_with_subcommands = true, subcommand_required = true)]
pub struct MixnetOperatorsNymNodeSettings {
#[clap(subcommand)]
pub command: MixnetOperatorsNymNodeSettingsCommands,
}
#[derive(Debug, Subcommand)]
pub enum MixnetOperatorsNymNodeSettingsCommands {
/// Update Nym Node configuration
UpdateConfig(update_config::Args),
/// Update Nym Node cost parameters
UpdateCostParameters(update_cost_params::Args),
}
@@ -1,50 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::context::SigningClient;
use clap::Parser;
use log::info;
use nym_mixnet_contract_common::nym_node::NodeConfigUpdate;
use nym_validator_client::nyxd::contract_traits::{MixnetQueryClient, MixnetSigningClient};
#[derive(Debug, Parser)]
pub struct Args {
#[clap(long)]
pub host: Option<String>,
// ideally this would have been `Option<Option<u16>>`, but not sure if clap would have recognised it
#[clap(long)]
pub custom_http_port: Option<u16>,
// equivalent to setting `custom_http_port` to `None`
#[clap(long)]
pub restore_default_http_port: bool,
}
pub async fn update_config(args: Args, client: SigningClient) {
info!("Update nym node config!");
if client
.get_owned_nymnode(&client.address())
.await
.expect("failed to query the chain for nym node details")
.details
.is_none()
{
log::warn!("this operator does not own a nym node to update");
return;
}
let update = NodeConfigUpdate {
host: args.host,
custom_http_port: args.custom_http_port,
restore_default_http_port: args.restore_default_http_port,
};
let res = client
.update_nymnode_config(update, None)
.await
.expect("updating nym node config");
info!("nym node config updated: {:?}", res)
}
@@ -1,73 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::context::SigningClient;
use anyhow::anyhow;
use clap::Parser;
use cosmwasm_std::Uint128;
use log::info;
use nym_mixnet_contract_common::{NodeCostParams, Percent};
use nym_validator_client::nyxd::contract_traits::{MixnetQueryClient, MixnetSigningClient};
use nym_validator_client::nyxd::CosmWasmCoin;
#[derive(Debug, Parser)]
pub struct Args {
#[clap(
long,
help = "input your profit margin as follows; (so it would be 20, rather than 0.2)"
)]
pub profit_margin_percent: Option<u8>,
#[clap(
long,
help = "operating cost in current DENOMINATION (so it would be 'unym', rather than 'nym')"
)]
pub interval_operating_cost: Option<u128>,
}
pub async fn update_cost_params(args: Args, client: SigningClient) -> anyhow::Result<()> {
let denom = client.current_chain_details().mix_denom.base.as_str();
let current_parameters = if let Some(client_mixnode) = client
.get_owned_mixnode(&client.address())
.await?
.mixnode_details
{
client_mixnode.rewarding_details.cost_params
} else {
client
.get_owned_nymnode(&client.address())
.await?
.details
.ok_or_else(|| anyhow!("the client does not own any nodes"))?
.rewarding_details
.cost_params
};
let profit_margin_percent = args
.profit_margin_percent
.map(|pm| Percent::from_percentage_value(pm as u64))
.unwrap_or(Ok(current_parameters.profit_margin_percent))?;
let interval_operating_cost = args
.interval_operating_cost
.map(|oc| CosmWasmCoin {
denom: denom.into(),
amount: Uint128::new(oc),
})
.unwrap_or(current_parameters.interval_operating_cost);
let cost_params = NodeCostParams {
profit_margin_percent,
interval_operating_cost,
};
info!("Starting cost params updating using {cost_params:?} !");
let res = client
.update_cost_params(cost_params, None)
.await
.expect("failed to update cost params");
info!("Cost params result: {:?}", res);
Ok(())
}
@@ -1,22 +0,0 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use clap::Parser;
use log::info;
use nym_validator_client::nyxd::contract_traits::MixnetSigningClient;
use crate::context::SigningClient;
#[derive(Debug, Parser)]
pub struct Args {}
pub async fn unbond_nymnode(_args: Args, client: SigningClient) {
info!("Starting Nym Node unbonding!");
let res = client
.unbond_nymnode(None)
.await
.expect("failed to unbond Nym Node!");
info!("Unbonding result: {:?}", res)
}
@@ -2,9 +2,10 @@
// SPDX-License-Identifier: Apache-2.0
use crate::context::QueryClientWithNyxd;
use crate::utils::show_error;
use crate::utils::{pretty_cosmwasm_coin, show_error};
use clap::Parser;
use comfy_table::Table;
use nym_validator_client::client::NymApiClientExt;
#[derive(Debug, Parser)]
pub struct Args {
@@ -14,11 +15,12 @@ pub struct Args {
}
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 {
Some(identity_key) => {
let node = res.iter().find(|node| {
node.ed25519_identity_key()
node.gateway
.identity_key
.to_string()
.eq_ignore_ascii_case(&identity_key)
});
@@ -30,16 +32,14 @@ pub async fn query(args: Args, client: &QueryClientWithNyxd) {
None => {
let mut table = Table::new();
table.set_header(vec!["Node Id", "Identity Key", "Version", "Is Legacy"]);
for node in res
.into_iter()
.filter(|node| node.description.declared_role.entry)
{
table.set_header(vec!["Identity Key", "Owner", "Host", "Bond", "Version"]);
for node in res {
table.add_row(vec![
node.node_id.to_string(),
node.ed25519_identity_key().to_base58_string(),
node.description.build_information.build_version,
(!node.contract_node_type.is_nym_node()).to_string(),
node.gateway.identity_key.to_string(),
node.owner.to_string(),
node.gateway.host.to_string(),
pretty_cosmwasm_coin(&node.pledge_amount),
node.gateway.version,
]);
}
@@ -2,9 +2,10 @@
// SPDX-License-Identifier: Apache-2.0
use crate::context::QueryClientWithNyxd;
use crate::utils::show_error;
use crate::utils::{pretty_decimal_with_denom, show_error};
use clap::Parser;
use comfy_table::Table;
use nym_validator_client::client::NymApiClientExt;
#[derive(Debug, Parser)]
pub struct Args {
@@ -14,11 +15,13 @@ pub struct Args {
}
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 {
Some(identity_key) => {
let node = res.iter().find(|node| {
node.ed25519_identity_key()
node.bond_information
.mix_node
.identity_key
.to_string()
.eq_ignore_ascii_case(&identity_key)
});
@@ -30,16 +33,25 @@ pub async fn query(args: Args, client: &QueryClientWithNyxd) {
None => {
let mut table = Table::new();
table.set_header(vec!["Node Id", "Identity Key", "Version", "Is Legacy"]);
for node in res
.into_iter()
.filter(|node| node.description.declared_role.mixnode)
{
table.set_header(vec![
"Mix id",
"Identity Key",
"Owner",
"Host",
"Bond",
"Total Delegations",
"Version",
]);
for node in res {
let denom = &node.bond_information.original_pledge().denom;
table.add_row(vec![
node.node_id.to_string(),
node.ed25519_identity_key().to_base58_string(),
node.description.build_information.build_version,
(!node.contract_node_type.is_nym_node()).to_string(),
node.mix_id().to_string(),
node.bond_information.mix_node.identity_key.clone(),
node.bond_information.owner.clone().into_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,27 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use cosmwasm_std::{BankMsg, Coin, CosmosMsg, Response};
pub trait ResponseExt<T> {
fn add_optional_message(self, msg: Option<impl Into<CosmosMsg<T>>>) -> Self;
fn send_tokens(self, to: impl AsRef<str>, amount: Coin) -> Self;
}
impl<T> ResponseExt<T> for Response<T> {
fn add_optional_message(self, msg: Option<impl Into<CosmosMsg<T>>>) -> Self {
if let Some(msg) = msg {
self.add_message(msg)
} else {
self
}
}
fn send_tokens(self, to: impl AsRef<str>, amount: Coin) -> Self {
self.add_message(BankMsg::Send {
to_address: to.as_ref().to_string(),
amount: vec![amount],
})
}
}
@@ -10,6 +10,4 @@ pub mod events;
pub mod signing;
pub mod types;
pub mod helpers;
pub use types::*;
@@ -8,7 +8,7 @@ use cosmwasm_std::Uint128;
use serde::de::Error;
use serde::{Deserialize, Deserializer};
use std::fmt::{self, Display, Formatter};
use std::ops::{Deref, Mul};
use std::ops::Mul;
use std::str::FromStr;
use thiserror::Error;
@@ -23,7 +23,7 @@ pub fn truncate_decimal(amount: Decimal) -> Uint128 {
#[derive(Error, Debug)]
pub enum ContractsCommonError {
#[error("Provided percent value ({0}) is greater than 100%")]
InvalidPercent(String),
InvalidPercent(Decimal),
#[error("{source}")]
StdErr {
@@ -41,7 +41,7 @@ pub struct Percent(#[serde(deserialize_with = "de_decimal_percent")] Decimal);
impl Percent {
pub fn new(value: Decimal) -> Result<Self, ContractsCommonError> {
if value > Decimal::one() {
Err(ContractsCommonError::InvalidPercent(value.to_string()))
Err(ContractsCommonError::InvalidPercent(value))
} else {
Ok(Percent(value))
}
@@ -51,15 +51,11 @@ impl Percent {
self.0 == Decimal::zero()
}
pub fn is_hundred(&self) -> bool {
self == &Self::hundred()
}
pub const fn zero() -> Self {
pub fn zero() -> Self {
Self(Decimal::zero())
}
pub const fn hundred() -> Self {
pub fn hundred() -> Self {
Self(Decimal::one())
}
@@ -121,70 +117,6 @@ impl Mul<Uint128> for Percent {
}
}
impl Deref for Percent {
type Target = Decimal;
fn deref(&self) -> &Self::Target {
&self.0
}
}
// this is not implemented via From traits due to its naive nature and loss of precision
#[cfg(not(target_arch = "wasm32"))]
pub trait NaiveFloat {
fn naive_to_f64(&self) -> f64;
fn naive_try_from_f64(val: f64) -> Result<Self, ContractsCommonError>
where
Self: Sized;
}
#[cfg(not(target_arch = "wasm32"))]
impl NaiveFloat for Percent {
fn naive_to_f64(&self) -> f64 {
use cosmwasm_std::Fraction;
// note: this conversion loses precision with too many decimal places,
// but for the purposes of displaying basic performance, that's not an issue
self.numerator().u128() as f64 / self.denominator().u128() as f64
}
fn naive_try_from_f64(val: f64) -> Result<Self, ContractsCommonError>
where
Self: Sized,
{
// we are only interested in positive values between 0 and 1
if !(0. ..=1.).contains(&val) {
return Err(ContractsCommonError::InvalidPercent(val.to_string()));
}
fn gcd(mut x: u64, mut y: u64) -> u64 {
while y > 0 {
let rem = x % y;
x = y;
y = rem;
}
x
}
fn to_rational(x: f64) -> (u64, u64) {
let log = x.log2().floor();
if log >= 0.0 {
(x as u64, 1)
} else {
let num: u64 = (x / f64::EPSILON) as _;
let den: u64 = (1.0 / f64::EPSILON) as _;
let gcd = gcd(num, den);
(num / gcd, den / gcd)
}
}
let (n, d) = to_rational(val);
Percent::new(Decimal::from_ratio(n, d))
}
}
// implement custom Deserialize because we want to validate Percent has the correct range
fn de_decimal_percent<'de, D>(deserializer: D) -> Result<Decimal, D::Error>
where
@@ -311,19 +243,4 @@ mod tests {
let p = serde_json::from_str::<'_, Percent>("\"1.00\"").unwrap();
assert_eq!(p.round_to_integer(), 100);
}
#[test]
fn naive_float_conversion() {
// around 15 decimal places is the maximum precision we can handle
// which is still way more than enough for what we use it for
let float: f64 = "0.546295475423853".parse().unwrap();
let percent: Percent = "0.546295475423853".parse().unwrap();
assert_eq!(float, percent.naive_to_f64());
let epsilon = Decimal::from_ratio(1u64, 1000000000000000u64);
let converted = Percent::naive_try_from_f64(float).unwrap();
assert!(converted.0 - converted.0 < epsilon);
}
}

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