Compare commits

..

3 Commits

Author SHA1 Message Date
Jędrzej Stuczyński 69a34418ab ignore precommits from missing validators 2025-06-23 10:46:01 +01:00
Jędrzej Stuczyński fd00405245 allow conversion from CometBFT block subscription 2025-02-19 14:56:40 +00:00
Jędrzej Stuczyński 7d77a9231c old validator rewarder with updated cosmrs 2025-02-19 14:33:37 +00:00
1012 changed files with 20176 additions and 58286 deletions
+22 -1
View File
@@ -5,7 +5,7 @@ on:
jobs: jobs:
build: build:
runs-on: arc-ubuntu-20.04 runs-on: ubuntu-20.04-16-core
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Install Dependencies (Linux) - name: Install Dependencies (Linux)
@@ -99,3 +99,24 @@ jobs:
run: vercel deploy --prebuilt --prod --token=${{ secrets.VERCEL_TOKEN }} run: vercel deploy --prebuilt --prod --token=${{ secrets.VERCEL_TOKEN }}
working-directory: dist/docs working-directory: dist/docs
continue-on-error: false continue-on-error: false
- name: Matrix - Node Install
run: npm install
working-directory: .github/workflows/support-files
- name: Matrix - Send Notification
env:
NYM_NOTIFICATION_KIND: cd-docs
NYM_PROJECT_NAME: "Docs CD"
NYM_CI_WWW_BASE: "${{ secrets.NYM_CD_WWW_BASE }}"
NYM_CI_WWW_LOCATION: "${{ env.GITHUB_REF_SLUG }}"
GIT_COMMIT_MESSAGE: "${{ github.event.head_commit.message }}"
GIT_BRANCH: "${GITHUB_REF##*/}"
MATRIX_SERVER: "${{ secrets.MATRIX_SERVER }}"
MATRIX_ROOM: "${{ secrets.MATRIX_ROOM_DOCS }}"
MATRIX_USER_ID: "${{ secrets.MATRIX_USER_ID }}"
MATRIX_TOKEN: "${{ secrets.MATRIX_TOKEN }}"
MATRIX_DEVICE_ID: "${{ secrets.MATRIX_DEVICE_ID }}"
IS_SUCCESS: "${{ job.status == 'success' }}"
uses: docker://keybaseio/client:stable-node
with:
args: .github/workflows/support-files/notifications/entry_point.sh
+21 -2
View File
@@ -1,7 +1,6 @@
name: ci-build-ts name: ci-build-ts
on: on:
workflow_dispatch:
pull_request: pull_request:
paths: paths:
- "ts-packages/**" - "ts-packages/**"
@@ -10,7 +9,7 @@ on:
jobs: jobs:
build: build:
runs-on: arc-ubuntu-20.04 runs-on: ubuntu-20.04-16-core
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Install rsync - name: Install rsync
@@ -46,3 +45,23 @@ jobs:
REMOTE_USER: ${{ secrets.CI_WWW_REMOTE_USER }} REMOTE_USER: ${{ secrets.CI_WWW_REMOTE_USER }}
TARGET: ${{ secrets.CI_WWW_REMOTE_TARGET }}/ts-${{ env.GITHUB_REF_SLUG }}-example TARGET: ${{ secrets.CI_WWW_REMOTE_TARGET }}/ts-${{ env.GITHUB_REF_SLUG }}-example
EXCLUDE: "/dist/, /node_modules/" 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: "ts-packages"
NYM_CI_WWW_BASE: "${{ secrets.NYM_CI_WWW_BASE }}"
NYM_CI_WWW_LOCATION: "ts-${{ env.GITHUB_REF_SLUG }}"
GIT_COMMIT_MESSAGE: "${{ github.event.head_commit.message }}"
GIT_BRANCH: "${GITHUB_REF##*/}"
IS_SUCCESS: "${{ job.status == 'success' }}"
MATRIX_SERVER: "${{ secrets.MATRIX_SERVER }}"
MATRIX_ROOM: "${{ secrets.MATRIX_ROOM }}"
MATRIX_USER_ID: "${{ secrets.MATRIX_USER_ID }}"
MATRIX_TOKEN: "${{ secrets.MATRIX_TOKEN }}"
MATRIX_DEVICE_ID: "${{ secrets.MATRIX_DEVICE_ID }}"
uses: docker://keybaseio/client:stable-node
with:
args: .github/workflows/support-files/notifications/entry_point.sh
@@ -1,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: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
os: [ arc-ubuntu-20.04, custom-runner-mac-m1 ] os: [arc-ubuntu-20.04, custom-runner-mac-m1]
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
env: env:
CARGO_TERM_COLOR: always CARGO_TERM_COLOR: always
@@ -57,17 +57,19 @@ jobs:
command: fmt command: fmt
args: --all -- --check args: --all -- --check
- name: Clippy
uses: actions-rs/cargo@v1
with:
command: clippy
args: --workspace --all-targets -- -D warnings
- name: Build all binaries - name: Build all binaries
uses: actions-rs/cargo@v1 uses: actions-rs/cargo@v1
with: with:
command: build 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 - name: Build all examples
if: contains(matrix.os, 'ubuntu') if: contains(matrix.os, 'ubuntu')
uses: actions-rs/cargo@v1 uses: actions-rs/cargo@v1
@@ -88,3 +90,9 @@ jobs:
with: with:
command: test command: test
args: --workspace -- --ignored 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: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
platform: [ arc-ubuntu-20.04 ] platform: arc-ubuntu-20.04
runs-on: ${{ matrix.platform }} runs-on: ${{ matrix.platform }}
env: env:
+22 -1
View File
@@ -10,7 +10,7 @@ on:
jobs: jobs:
build: build:
runs-on: arc-ubuntu-20.04 runs-on: ubuntu-20.04-16-core
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Install Dependencies (Linux) - name: Install Dependencies (Linux)
@@ -70,3 +70,24 @@ jobs:
REMOTE_USER: ${{ secrets.CI_WWW_REMOTE_USER }} REMOTE_USER: ${{ secrets.CI_WWW_REMOTE_USER }}
TARGET: ${{ secrets.CI_WWW_REMOTE_TARGET }}/docs-${{ env.GITHUB_REF_SLUG }} TARGET: ${{ secrets.CI_WWW_REMOTE_TARGET }}/docs-${{ env.GITHUB_REF_SLUG }}
EXCLUDE: "/node_modules/" EXCLUDE: "/node_modules/"
- name: Matrix - Node Install
run: npm install
working-directory: .github/workflows/support-files
- name: Matrix - Send Notification
env:
NYM_NOTIFICATION_KIND: ci-docs
NYM_PROJECT_NAME: "Docs CI"
NYM_CI_WWW_BASE: "${{ secrets.NYM_CI_WWW_BASE }}"
NYM_CI_WWW_LOCATION: "docs-${{ env.GITHUB_REF_SLUG }}"
GIT_COMMIT_MESSAGE: "${{ github.event.head_commit.message }}"
GIT_BRANCH: "${GITHUB_REF##*/}"
MATRIX_SERVER: "${{ secrets.MATRIX_SERVER }}"
MATRIX_ROOM: "${{ secrets.MATRIX_ROOM_DOCS }}"
MATRIX_USER_ID: "${{ secrets.MATRIX_USER_ID }}"
MATRIX_TOKEN: "${{ secrets.MATRIX_TOKEN }}"
MATRIX_DEVICE_ID: "${{ secrets.MATRIX_DEVICE_ID }}"
IS_SUCCESS: "${{ job.status == 'success' }}"
uses: docker://keybaseio/client:stable-node
with:
args: .github/workflows/support-files/notifications/entry_point.sh
+22 -2
View File
@@ -1,7 +1,6 @@
name: ci-lint-typescript name: ci-lint-typescript
on: on:
workflow_dispatch:
pull_request: pull_request:
paths: paths:
- "ts-packages/**" - "ts-packages/**"
@@ -15,7 +14,7 @@ on:
jobs: jobs:
build: build:
runs-on: arc-ubuntu-20.04 runs-on: ubuntu-20.04-16-core
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: rlespinasse/github-slug-action@v3.x - uses: rlespinasse/github-slug-action@v3.x
@@ -54,3 +53,24 @@ jobs:
run: yarn lint run: yarn lint
- name: Typecheck with tsc - name: Typecheck with tsc
run: yarn tsc run: yarn tsc
- 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: "ts-packages"
NYM_CI_WWW_BASE: "${{ secrets.NYM_CI_WWW_BASE }}"
NYM_CI_WWW_LOCATION: "ts-${{ env.GITHUB_REF_SLUG }}"
GIT_COMMIT_MESSAGE: "${{ github.event.head_commit.message }}"
GIT_BRANCH: "${GITHUB_REF##*/}"
IS_SUCCESS: "${{ job.status == 'success' }}"
MATRIX_SERVER: "${{ secrets.MATRIX_SERVER }}"
MATRIX_ROOM: "${{ secrets.MATRIX_ROOM }}"
MATRIX_USER_ID: "${{ secrets.MATRIX_USER_ID }}"
MATRIX_TOKEN: "${{ secrets.MATRIX_TOKEN }}"
MATRIX_DEVICE_ID: "${{ secrets.MATRIX_DEVICE_ID }}"
uses: docker://keybaseio/client:stable-node
with:
args: .github/workflows/support-files/notifications/entry_point.sh
@@ -1,45 +0,0 @@
name: ci-nym-credential-proxy
on:
pull_request:
paths:
- 'common/**'
- 'nym-credential-proxy/**'
- '.github/workspace/ci-nym-credential-proxy.yml'
workflow_dispatch:
jobs:
build:
runs-on: arc-ubuntu-22.04
env:
CARGO_TERM_COLOR: always
MANIFEST_PATH: "--manifest-path nym-credential-proxy/Cargo.toml"
steps:
- name: Check out repository code
uses: actions/checkout@v4
- name: Install rust toolchain
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
override: true
components: rustfmt, clippy
- name: Check formatting
uses: actions-rs/cargo@v1
with:
command: fmt
args: ${{ env.MANIFEST_PATH }} --all -- --check
- name: Build
uses: actions-rs/cargo@v1
with:
command: build
args: ${{ env.MANIFEST_PATH }} --workspace --all-targets
- name: Clippy
uses: actions-rs/cargo@v1
with:
command: clippy
args: ${{ env.MANIFEST_PATH }} --workspace --all-targets -- -D warnings
-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 -1
View File
@@ -4,7 +4,7 @@ on:
jobs: jobs:
publish: publish:
runs-on: arc-ubuntu-20.04 runs-on: ubuntu-20.04-16-core
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
@@ -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
-74
View File
@@ -4,80 +4,6 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
## [Unreleased] ## [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) ## [2024.11-wedel] (2024-09-23)
- Backport #4894 to fix ci ([#4899]) - Backport #4894 to fix ci ([#4899])
Generated
+748 -1594
View File
File diff suppressed because it is too large Load Diff
+20 -47
View File
@@ -54,14 +54,12 @@ members = [
"common/exit-policy", "common/exit-policy",
"common/gateway-requests", "common/gateway-requests",
"common/gateway-storage", "common/gateway-storage",
"common/gateway-stats-storage",
"common/http-api-client", "common/http-api-client",
"common/http-api-common", "common/http-api-common",
"common/inclusion-probability", "common/inclusion-probability",
"common/ip-packet-requests", "common/ip-packet-requests",
"common/ledger", "common/ledger",
"common/mixnode-common", "common/mixnode-common",
"common/models",
"common/network-defaults", "common/network-defaults",
"common/node-tester-utils", "common/node-tester-utils",
"common/nonexhaustive-delayqueue", "common/nonexhaustive-delayqueue",
@@ -87,7 +85,6 @@ members = [
"common/socks5-client-core", "common/socks5-client-core",
"common/socks5/proxy-helpers", "common/socks5/proxy-helpers",
"common/socks5/requests", "common/socks5/requests",
"common/statistics",
"common/store-cipher", "common/store-cipher",
"common/task", "common/task",
"common/topology", "common/topology",
@@ -121,8 +118,6 @@ members = [
"nym-node", "nym-node",
"nym-node/nym-node-http-api", "nym-node/nym-node-http-api",
"nym-node/nym-node-requests", "nym-node/nym-node-requests",
"nym-node-status-api",
"nym-node-status-agent",
"nym-outfox", "nym-outfox",
"nym-validator-rewarder", "nym-validator-rewarder",
"tools/echo-server", "tools/echo-server",
@@ -143,23 +138,18 @@ members = [
"tools/internal/testnet-manager", "tools/internal/testnet-manager",
"tools/internal/testnet-manager/dkg-bypass-contract", "tools/internal/testnet-manager/dkg-bypass-contract",
"tools/echo-server", "tools/echo-server",
"tools/internal/contract-state-importer/importer-cli",
"tools/internal/contract-state-importer/importer-contract",
] ]
default-members = [ default-members = [
"clients/native", "clients/native",
"clients/socks5", "clients/socks5",
"common/models",
"explorer-api", "explorer-api",
"gateway", "gateway",
"mixnode", "mixnode",
"nym-api", "nym-api",
"nym-data-observatory", "nym-data-observatory",
"nym-node", "nym-node",
"nym-node-status-api",
"nym-validator-rewarder", "nym-validator-rewarder",
"nym-node-status-api",
"service-providers/authenticator", "service-providers/authenticator",
"service-providers/ip-packet-router", "service-providers/ip-packet-router",
"service-providers/network-requester", "service-providers/network-requester",
@@ -190,11 +180,11 @@ aes = "0.8.1"
aes-gcm = "0.10.1" aes-gcm = "0.10.1"
aes-gcm-siv = "0.11.1" aes-gcm-siv = "0.11.1"
aead = "0.5.2" aead = "0.5.2"
anyhow = "1.0.90" anyhow = "1.0.89"
argon2 = "0.5.0" argon2 = "0.5.0"
async-trait = "0.1.83" async-trait = "0.1.82"
axum = "0.7.5" axum = "0.7.5"
axum-extra = "0.9.4" axum-extra = "0.9.3"
base64 = "0.22.1" base64 = "0.22.1"
bincode = "1.3.3" bincode = "1.3.3"
bip39 = { version = "2.0.0", features = ["zeroize"] } bip39 = { version = "2.0.0", features = ["zeroize"] }
@@ -207,7 +197,7 @@ blake3 = "1.5.4"
bloomfilter = "1.0.14" bloomfilter = "1.0.14"
bs58 = "0.5.1" bs58 = "0.5.1"
bytecodec = "0.4.15" bytecodec = "0.4.15"
bytes = "1.7.2" bytes = "1.7.1"
cargo_metadata = "0.18.1" cargo_metadata = "0.18.1"
celes = "2.4.0" celes = "2.4.0"
cfg-if = "1.0.0" cfg-if = "1.0.0"
@@ -215,7 +205,7 @@ chacha20 = "0.9.0"
chacha20poly1305 = "0.10.1" chacha20poly1305 = "0.10.1"
chrono = "0.4.31" chrono = "0.4.31"
cipher = "0.4.3" cipher = "0.4.3"
clap = "4.5.20" clap = "4.5.17"
clap_complete = "4.5" clap_complete = "4.5"
clap_complete_fig = "4.5" clap_complete_fig = "4.5"
colored = "2.0" colored = "2.0"
@@ -240,12 +230,10 @@ dotenvy = "0.15.6"
ecdsa = "0.16" ecdsa = "0.16"
ed25519-dalek = "2.1" ed25519-dalek = "2.1"
etherparse = "0.13.0" etherparse = "0.13.0"
envy = "0.4"
eyre = "0.6.9" eyre = "0.6.9"
fastrand = "2.1.1" fastrand = "2.1.1"
flate2 = "1.0.34" flate2 = "1.0.33"
futures = "0.3.28" futures = "0.3.28"
futures-util = "0.3"
generic-array = "0.14.7" generic-array = "0.14.7"
getrandom = "0.2.10" getrandom = "0.2.10"
getset = "0.1.3" getset = "0.1.3"
@@ -275,7 +263,6 @@ ledger-transport-hid = "0.10.0"
log = "0.4" log = "0.4"
maxminddb = "0.23.0" maxminddb = "0.23.0"
mime = "0.3.17" mime = "0.3.17"
moka = { version = "0.12", features = ["future"] }
nix = "0.27.1" nix = "0.27.1"
notify = "5.1.0" notify = "5.1.0"
okapi = "0.7.0" okapi = "0.7.0"
@@ -285,8 +272,7 @@ opentelemetry-jaeger = "0.18.0"
parking_lot = "0.12.3" parking_lot = "0.12.3"
pem = "0.8" pem = "0.8"
petgraph = "0.6.5" petgraph = "0.6.5"
pin-project = "1.1" pin-project = "1.0"
pin-project-lite = "0.2.14"
pretty_env_logger = "0.4.0" pretty_env_logger = "0.4.0"
publicsuffix = "2.2.3" publicsuffix = "2.2.3"
quote = "1" quote = "1"
@@ -305,27 +291,25 @@ rocket_okapi = "0.8.0"
safer-ffi = "0.1.13" safer-ffi = "0.1.13"
schemars = "0.8.21" schemars = "0.8.21"
semver = "1.0.23" semver = "1.0.23"
serde = "1.0.211" serde = "1.0.210"
serde_bytes = "0.11.15" serde_bytes = "0.11.15"
serde_derive = "1.0" serde_derive = "1.0"
serde_json = "1.0.132" serde_json = "1.0.128"
serde_json_path = "0.6.7"
serde_repr = "0.1" serde_repr = "0.1"
serde_with = "3.9.0" serde_with = "3.9.0"
serde_yaml = "0.9.25" serde_yaml = "0.9.25"
sha2 = "0.10.8" sha2 = "0.10.8"
si-scale = "0.2.3" si-scale = "0.2.3"
sphinx-packet = "0.1.1" sphinx-packet = "0.1.1"
sqlx = "0.7.4" sqlx = "0.6.3"
strum = "0.26" strum = "0.26"
strum_macros = "0.26"
subtle-encoding = "0.5" subtle-encoding = "0.5"
syn = "1" syn = "1"
sysinfo = "0.30.13" sysinfo = "0.30.13"
tap = "1.0.1" tap = "1.0.1"
tar = "0.4.42" tar = "0.4.41"
tempfile = "3.5.0" tempfile = "3.5.0"
thiserror = "1.0.64" thiserror = "1.0.63"
time = "0.3.30" time = "0.3.30"
tokio = "1.39" tokio = "1.39"
tokio-stream = "0.1.16" tokio-stream = "0.1.16"
@@ -340,8 +324,7 @@ tracing = "0.1.37"
tracing-opentelemetry = "0.19.0" tracing-opentelemetry = "0.19.0"
tracing-subscriber = "0.3.16" tracing-subscriber = "0.3.16"
tracing-tree = "0.2.2" tracing-tree = "0.2.2"
tracing-log = "0.2" ts-rs = "7.0.0"
ts-rs = "10.0.0"
tungstenite = { version = "0.20.1", default-features = false } tungstenite = { version = "0.20.1", default-features = false }
url = "2.5" url = "2.5"
utoipa = "4.2" utoipa = "4.2"
@@ -363,7 +346,6 @@ prometheus = { version = "0.13.0" }
bls12_381 = { git = "https://github.com/jstuczyn/bls12_381", default-features = false, branch = "temp/experimental-serdect" } bls12_381 = { git = "https://github.com/jstuczyn/bls12_381", default-features = false, branch = "temp/experimental-serdect" }
group = { version = "0.13.0", default-features = false } group = { version = "0.13.0", default-features = false }
ff = { version = "0.13.0", default-features = false } ff = { version = "0.13.0", default-features = false }
subtle = "2.5.0"
# cosmwasm-related # cosmwasm-related
cosmwasm-schema = "=1.4.3" cosmwasm-schema = "=1.4.3"
@@ -383,13 +365,10 @@ cw-controllers = { version = "=1.1.0" }
# cosmrs-related # cosmrs-related
bip32 = { version = "0.5.2", default-features = false } bip32 = { version = "0.5.2", default-features = false }
# temporarily using a fork again (yay.) because we need staking and slashing support (which are already on main but not released) cosmrs = { version = "0.21.1" }
# plus response message parsing (which is, as of the time of writing this message, waiting to get merged) tendermint = "0.40.0"
#cosmrs = { path = "../cosmos-rust-fork/cosmos-rust/cosmrs" } tendermint-rpc = "0.40.0"
cosmrs = { git = "https://github.com/cosmos/cosmos-rust", rev = "4b1332e6d8258ac845cef71589c8d362a669675a" } # unfortuntely we need a fork by yours truly to get the staking support prost = { version = "0.13", default-features = false }
tendermint = "0.37.0" # same version as used by cosmrs
tendermint-rpc = "0.37.0" # same version as used by cosmrs
prost = { version = "0.12", default-features = false }
# wasm-related dependencies # wasm-related dependencies
gloo-utils = "0.2.0" gloo-utils = "0.2.0"
@@ -402,20 +381,14 @@ indexed_db_futures = { git = "https://github.com/TiemenSch/rust-indexed-db", bra
js-sys = "0.3.70" js-sys = "0.3.70"
serde-wasm-bindgen = "0.6.5" serde-wasm-bindgen = "0.6.5"
tsify = "0.4.5" tsify = "0.4.5"
wasm-bindgen = "0.2.95" wasm-bindgen = "0.2.93"
wasm-bindgen-futures = "0.4.45" wasm-bindgen-futures = "0.4.43"
wasmtimer = "0.2.0" wasmtimer = "0.2.0"
web-sys = "0.3.72" web-sys = "0.3.70"
# Profile settings for individual crates # 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] [profile.release.package.nym-socks5-listener]
strip = true strip = true
codegen-units = 1 codegen-units = 1
+1 -1
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "nym-client" 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>"] authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"]
description = "Implementation of the Nym Client" description = "Implementation of the Nym Client"
edition = "2021" edition = "2021"
+1 -1
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "nym-socks5-client" name = "nym-socks5-client"
version = "1.1.42" version = "1.1.41"
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"] authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
description = "A SOCKS5 localhost proxy that converts incoming messages to Sphinx and sends them to a Nym address" description = "A SOCKS5 localhost proxy that converts incoming messages to Sphinx and sends them to a Nym address"
edition = "2021" edition = "2021"
@@ -19,7 +19,4 @@ pub enum Error {
#[source] #[source]
source: hmac::digest::MacError, source: hmac::digest::MacError,
}, },
#[error("conversion: {0}")]
Conversion(String),
} }
+2 -3
View File
@@ -3,14 +3,13 @@
pub mod v1; pub mod v1;
pub mod v2; pub mod v2;
pub mod v3;
mod error; mod error;
pub use error::Error; pub use error::Error;
pub use v3 as latest; pub use v2 as latest;
pub const CURRENT_VERSION: u8 = 3; pub const CURRENT_VERSION: u8 = 2;
fn make_bincode_serializer() -> impl bincode::Options { fn make_bincode_serializer() -> impl bincode::Options {
use bincode::Options; use bincode::Options;
@@ -1,188 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use nym_service_provider_requests_common::{Protocol, ServiceProviderType};
use crate::{v2, v3};
impl From<v2::request::AuthenticatorRequest> for v3::request::AuthenticatorRequest {
fn from(authenticator_request: v2::request::AuthenticatorRequest) -> Self {
Self {
protocol: Protocol {
version: 2,
service_provider_type: ServiceProviderType::Authenticator,
},
data: authenticator_request.data.into(),
reply_to: authenticator_request.reply_to,
request_id: authenticator_request.request_id,
}
}
}
impl From<v2::request::AuthenticatorRequestData> for v3::request::AuthenticatorRequestData {
fn from(authenticator_request_data: v2::request::AuthenticatorRequestData) -> Self {
match authenticator_request_data {
v2::request::AuthenticatorRequestData::Initial(init_msg) => {
v3::request::AuthenticatorRequestData::Initial(init_msg.into())
}
v2::request::AuthenticatorRequestData::Final(gw_client) => {
v3::request::AuthenticatorRequestData::Final(gw_client.into())
}
v2::request::AuthenticatorRequestData::QueryBandwidth(pub_key) => {
v3::request::AuthenticatorRequestData::QueryBandwidth(pub_key)
}
}
}
}
impl From<v2::registration::InitMessage> for v3::registration::InitMessage {
fn from(init_msg: v2::registration::InitMessage) -> Self {
Self {
pub_key: init_msg.pub_key,
}
}
}
impl From<Box<v2::registration::FinalMessage>> for Box<v3::registration::FinalMessage> {
fn from(gw_client: Box<v2::registration::FinalMessage>) -> Self {
Box::new(v3::registration::FinalMessage {
gateway_client: gw_client.gateway_client.into(),
credential: gw_client.credential,
})
}
}
impl From<v2::registration::GatewayClient> for v3::registration::GatewayClient {
fn from(gw_client: v2::registration::GatewayClient) -> Self {
Self {
pub_key: gw_client.pub_key,
private_ip: gw_client.private_ip,
mac: gw_client.mac.into(),
}
}
}
impl From<v3::registration::GatewayClient> for v2::registration::GatewayClient {
fn from(gw_client: v3::registration::GatewayClient) -> Self {
Self {
pub_key: gw_client.pub_key,
private_ip: gw_client.private_ip,
mac: gw_client.mac.into(),
}
}
}
impl From<v2::registration::ClientMac> for v3::registration::ClientMac {
fn from(mac: v2::registration::ClientMac) -> Self {
Self::new(mac.to_vec())
}
}
impl From<v3::registration::ClientMac> for v2::registration::ClientMac {
fn from(mac: v3::registration::ClientMac) -> Self {
Self::new(mac.to_vec())
}
}
impl TryFrom<v3::response::AuthenticatorResponse> for v2::response::AuthenticatorResponse {
type Error = crate::Error;
fn try_from(
authenticator_response: v3::response::AuthenticatorResponse,
) -> Result<Self, Self::Error> {
Ok(Self {
data: authenticator_response.data.try_into()?,
reply_to: authenticator_response.reply_to,
protocol: authenticator_response.protocol,
})
}
}
impl TryFrom<v3::response::AuthenticatorResponseData> for v2::response::AuthenticatorResponseData {
type Error = crate::Error;
fn try_from(
authenticator_response_data: v3::response::AuthenticatorResponseData,
) -> Result<Self, Self::Error> {
match authenticator_response_data {
v3::response::AuthenticatorResponseData::PendingRegistration(
pending_registration_response,
) => Ok(
v2::response::AuthenticatorResponseData::PendingRegistration(
pending_registration_response.into(),
),
),
v3::response::AuthenticatorResponseData::Registered(registered_response) => Ok(
v2::response::AuthenticatorResponseData::Registered(registered_response.into()),
),
v3::response::AuthenticatorResponseData::RemainingBandwidth(
remaining_bandwidth_response,
) => Ok(v2::response::AuthenticatorResponseData::RemainingBandwidth(
remaining_bandwidth_response.into(),
)),
v3::response::AuthenticatorResponseData::TopUpBandwidth(_) => {
Err(Self::Error::Conversion(
"a v2 request couldn't produce a v3 only type of response".to_string(),
))
}
}
}
}
impl From<v3::response::PendingRegistrationResponse> for v2::response::PendingRegistrationResponse {
fn from(value: v3::response::PendingRegistrationResponse) -> Self {
Self {
request_id: value.request_id,
reply_to: value.reply_to,
reply: value.reply.into(),
}
}
}
impl From<v3::response::RegisteredResponse> for v2::response::RegisteredResponse {
fn from(value: v3::response::RegisteredResponse) -> Self {
Self {
request_id: value.request_id,
reply_to: value.reply_to,
reply: value.reply.into(),
}
}
}
impl From<v3::response::RemainingBandwidthResponse> for v2::response::RemainingBandwidthResponse {
fn from(value: v3::response::RemainingBandwidthResponse) -> Self {
Self {
request_id: value.request_id,
reply_to: value.reply_to,
reply: value.reply.map(Into::into),
}
}
}
impl From<v3::registration::RegistrationData> for v2::registration::RegistrationData {
fn from(value: v3::registration::RegistrationData) -> Self {
Self {
nonce: value.nonce,
gateway_data: value.gateway_data.into(),
wg_port: value.wg_port,
}
}
}
impl From<v3::registration::RegistredData> for v2::registration::RegistredData {
fn from(value: v3::registration::RegistredData) -> Self {
Self {
pub_key: value.pub_key,
private_ip: value.private_ip,
wg_port: value.wg_port,
}
}
}
impl From<v3::registration::RemainingBandwidthData> for v2::registration::RemainingBandwidthData {
fn from(value: v3::registration::RemainingBandwidthData) -> Self {
Self {
available_bandwidth: value.available_bandwidth,
}
}
}
@@ -1,10 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
pub mod conversion;
pub mod registration;
pub mod request;
pub mod response;
pub mod topup;
pub const VERSION: u8 = 3;
@@ -1,227 +0,0 @@
// -2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::error::Error;
use base64::{engine::general_purpose, Engine};
use nym_credentials_interface::CredentialSpendingData;
use nym_wireguard_types::PeerPublicKey;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::net::IpAddr;
use std::time::SystemTime;
use std::{fmt, ops::Deref, str::FromStr};
#[cfg(feature = "verify")]
use hmac::{Hmac, Mac};
#[cfg(feature = "verify")]
use nym_crypto::asymmetric::encryption::PrivateKey;
#[cfg(feature = "verify")]
use sha2::Sha256;
pub type PendingRegistrations = HashMap<PeerPublicKey, RegistrationData>;
pub type PrivateIPs = HashMap<IpAddr, Taken>;
#[cfg(feature = "verify")]
pub type HmacSha256 = Hmac<Sha256>;
pub type Nonce = u64;
pub type Taken = Option<SystemTime>;
pub const BANDWIDTH_CAP_PER_DAY: u64 = 1024 * 1024 * 1024; // 1 GB
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct InitMessage {
/// Base64 encoded x25519 public key
pub pub_key: PeerPublicKey,
}
impl InitMessage {
pub fn new(pub_key: PeerPublicKey) -> Self {
InitMessage { pub_key }
}
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct FinalMessage {
/// Gateway client data
pub gateway_client: GatewayClient,
/// Ecash credential
pub credential: Option<CredentialSpendingData>,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct RegistrationData {
pub nonce: u64,
pub gateway_data: GatewayClient,
pub wg_port: u16,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct RegistredData {
pub pub_key: PeerPublicKey,
pub private_ip: IpAddr,
pub wg_port: u16,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct RemainingBandwidthData {
pub available_bandwidth: i64,
}
/// Client that wants to register sends its PublicKey bytes mac digest encrypted with a DH shared secret.
/// Gateway/Nym node can then verify pub_key payload using the same process
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct GatewayClient {
/// Base64 encoded x25519 public key
pub pub_key: PeerPublicKey,
/// Assigned private IP
pub private_ip: IpAddr,
/// Sha256 hmac on the data (alongside the prior nonce)
pub mac: ClientMac,
}
impl GatewayClient {
#[cfg(feature = "verify")]
pub fn new(
local_secret: &PrivateKey,
remote_public: x25519_dalek::PublicKey,
private_ip: IpAddr,
nonce: u64,
) -> Self {
// convert from 1.0 x25519-dalek private key into 2.0 x25519-dalek
#[allow(clippy::expect_used)]
let static_secret = x25519_dalek::StaticSecret::from(local_secret.to_bytes());
let local_public: x25519_dalek::PublicKey = (&static_secret).into();
let dh = static_secret.diffie_hellman(&remote_public);
// TODO: change that to use our nym_crypto::hmac module instead
#[allow(clippy::expect_used)]
let mut mac = HmacSha256::new_from_slice(dh.as_bytes())
.expect("x25519 shared secret is always 32 bytes long");
mac.update(local_public.as_bytes());
mac.update(private_ip.to_string().as_bytes());
mac.update(&nonce.to_le_bytes());
GatewayClient {
pub_key: PeerPublicKey::new(local_public),
private_ip,
mac: ClientMac(mac.finalize().into_bytes().to_vec()),
}
}
// Reusable secret should be gateways Wireguard PK
// Client should perform this step when generating its payload, using its own WG PK
#[cfg(feature = "verify")]
pub fn verify(&self, gateway_key: &PrivateKey, nonce: u64) -> Result<(), Error> {
// convert from 1.0 x25519-dalek private key into 2.0 x25519-dalek
#[allow(clippy::expect_used)]
let static_secret = x25519_dalek::StaticSecret::from(gateway_key.to_bytes());
let dh = static_secret.diffie_hellman(&self.pub_key);
// TODO: change that to use our nym_crypto::hmac module instead
#[allow(clippy::expect_used)]
let mut mac = HmacSha256::new_from_slice(dh.as_bytes())
.expect("x25519 shared secret is always 32 bytes long");
mac.update(self.pub_key.as_bytes());
mac.update(self.private_ip.to_string().as_bytes());
mac.update(&nonce.to_le_bytes());
mac.verify_slice(&self.mac)
.map_err(|source| Error::FailedClientMacVerification {
client: self.pub_key.to_string(),
source,
})
}
pub fn pub_key(&self) -> PeerPublicKey {
self.pub_key
}
}
// TODO: change the inner type into generic array of size HmacSha256::OutputSize
// TODO2: rely on our internal crypto/hmac
#[derive(Debug, Clone)]
pub struct ClientMac(Vec<u8>);
impl fmt::Display for ClientMac {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", general_purpose::STANDARD.encode(&self.0))
}
}
impl ClientMac {
#[allow(dead_code)]
pub fn new(mac: Vec<u8>) -> Self {
ClientMac(mac)
}
}
impl Deref for ClientMac {
type Target = Vec<u8>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl FromStr for ClientMac {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let mac_bytes: Vec<u8> =
general_purpose::STANDARD
.decode(s)
.map_err(|source| Error::MalformedClientMac {
mac: s.to_string(),
source,
})?;
Ok(ClientMac(mac_bytes))
}
}
impl Serialize for ClientMac {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let encoded_key = general_purpose::STANDARD.encode(self.0.clone());
serializer.serialize_str(&encoded_key)
}
}
impl<'de> Deserialize<'de> for ClientMac {
fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
let encoded_key = String::deserialize(deserializer)?;
ClientMac::from_str(&encoded_key).map_err(serde::de::Error::custom)
}
}
#[cfg(test)]
mod tests {
use super::*;
use nym_crypto::asymmetric::encryption;
#[test]
#[cfg(feature = "verify")]
fn client_request_roundtrip() {
let mut rng = rand::thread_rng();
let gateway_key_pair = encryption::KeyPair::new(&mut rng);
let client_key_pair = encryption::KeyPair::new(&mut rng);
let nonce = 1234567890;
let client = GatewayClient::new(
client_key_pair.private_key(),
x25519_dalek::PublicKey::from(gateway_key_pair.public_key().to_bytes()),
"10.0.0.42".parse().unwrap(),
nonce,
);
assert!(client.verify(gateway_key_pair.private_key(), nonce).is_ok())
}
}
@@ -1,136 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use super::{
registration::{FinalMessage, InitMessage},
topup::TopUpMessage,
};
use nym_service_provider_requests_common::{Protocol, ServiceProviderType};
use nym_sphinx::addressing::Recipient;
use nym_wireguard_types::PeerPublicKey;
use serde::{Deserialize, Serialize};
use crate::make_bincode_serializer;
use super::VERSION;
fn generate_random() -> u64 {
use rand::RngCore;
let mut rng = rand::rngs::OsRng;
rng.next_u64()
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct AuthenticatorRequest {
pub protocol: Protocol,
pub data: AuthenticatorRequestData,
pub reply_to: Recipient,
pub request_id: u64,
}
impl AuthenticatorRequest {
pub fn from_reconstructed_message(
message: &nym_sphinx::receiver::ReconstructedMessage,
) -> Result<Self, bincode::Error> {
use bincode::Options;
make_bincode_serializer().deserialize(&message.message)
}
pub fn new_initial_request(init_message: InitMessage, reply_to: Recipient) -> (Self, u64) {
let request_id = generate_random();
(
Self {
protocol: Protocol {
service_provider_type: ServiceProviderType::Authenticator,
version: VERSION,
},
data: AuthenticatorRequestData::Initial(init_message),
reply_to,
request_id,
},
request_id,
)
}
pub fn new_final_request(final_message: FinalMessage, reply_to: Recipient) -> (Self, u64) {
let request_id = generate_random();
(
Self {
protocol: Protocol {
service_provider_type: ServiceProviderType::Authenticator,
version: VERSION,
},
data: AuthenticatorRequestData::Final(Box::new(final_message)),
reply_to,
request_id,
},
request_id,
)
}
pub fn new_query_request(peer_public_key: PeerPublicKey, reply_to: Recipient) -> (Self, u64) {
let request_id = generate_random();
(
Self {
protocol: Protocol {
service_provider_type: ServiceProviderType::Authenticator,
version: VERSION,
},
data: AuthenticatorRequestData::QueryBandwidth(peer_public_key),
reply_to,
request_id,
},
request_id,
)
}
pub fn new_topup_request(top_up_message: TopUpMessage, reply_to: Recipient) -> (Self, u64) {
let request_id = generate_random();
(
Self {
protocol: Protocol {
service_provider_type: ServiceProviderType::Authenticator,
version: VERSION,
},
data: AuthenticatorRequestData::TopUpBandwidth(Box::new(top_up_message)),
reply_to,
request_id,
},
request_id,
)
}
pub fn to_bytes(&self) -> Result<Vec<u8>, bincode::Error> {
use bincode::Options;
make_bincode_serializer().serialize(self)
}
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub enum AuthenticatorRequestData {
Initial(InitMessage),
Final(Box<FinalMessage>),
QueryBandwidth(PeerPublicKey),
TopUpBandwidth(Box<TopUpMessage>),
}
#[cfg(test)]
mod tests {
use super::*;
use std::str::FromStr;
#[test]
fn check_first_bytes_protocol() {
let version = 2;
let data = AuthenticatorRequest {
protocol: Protocol { version, service_provider_type: ServiceProviderType::Authenticator },
data: AuthenticatorRequestData::Initial(InitMessage::new(
PeerPublicKey::from_str("yvNUDpT5l7W/xDhiu6HkqTHDQwbs/B3J5UrLmORl1EQ=").unwrap(),
)),
reply_to: Recipient::try_from_base58_string("D1rrpsysCGCYXy9saP8y3kmNpGtJZUXN9SvFoUcqAsM9.9Ssso1ea5NfkbMASdiseDSjTN1fSWda5SgEVjdSN4CvV@GJqd3ZxpXWSNxTfx7B1pPtswpetH4LnJdFeLeuY5KUuN").unwrap(),
request_id: 1,
};
let bytes = *data.to_bytes().unwrap().first_chunk::<2>().unwrap();
assert_eq!(bytes, [version, ServiceProviderType::Authenticator as u8]);
}
}
@@ -1,157 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use super::registration::{RegistrationData, RegistredData, RemainingBandwidthData};
use nym_service_provider_requests_common::{Protocol, ServiceProviderType};
use nym_sphinx::addressing::Recipient;
use serde::{Deserialize, Serialize};
use crate::make_bincode_serializer;
use super::VERSION;
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct AuthenticatorResponse {
pub protocol: Protocol,
pub data: AuthenticatorResponseData,
pub reply_to: Recipient,
}
impl AuthenticatorResponse {
pub fn new_pending_registration_success(
registration_data: RegistrationData,
request_id: u64,
reply_to: Recipient,
) -> Self {
Self {
protocol: Protocol {
service_provider_type: ServiceProviderType::Authenticator,
version: VERSION,
},
data: AuthenticatorResponseData::PendingRegistration(PendingRegistrationResponse {
reply: registration_data,
reply_to,
request_id,
}),
reply_to,
}
}
pub fn new_registered(
registred_data: RegistredData,
reply_to: Recipient,
request_id: u64,
) -> Self {
Self {
protocol: Protocol {
service_provider_type: ServiceProviderType::Authenticator,
version: VERSION,
},
data: AuthenticatorResponseData::Registered(RegisteredResponse {
reply: registred_data,
reply_to,
request_id,
}),
reply_to,
}
}
pub fn new_remaining_bandwidth(
remaining_bandwidth_data: Option<RemainingBandwidthData>,
reply_to: Recipient,
request_id: u64,
) -> Self {
Self {
protocol: Protocol {
service_provider_type: ServiceProviderType::Authenticator,
version: VERSION,
},
data: AuthenticatorResponseData::RemainingBandwidth(RemainingBandwidthResponse {
reply: remaining_bandwidth_data,
reply_to,
request_id,
}),
reply_to,
}
}
pub fn new_topup_bandwidth(
remaining_bandwidth_data: RemainingBandwidthData,
reply_to: Recipient,
request_id: u64,
) -> Self {
Self {
protocol: Protocol {
service_provider_type: ServiceProviderType::Authenticator,
version: VERSION,
},
data: AuthenticatorResponseData::TopUpBandwidth(TopUpBandwidthResponse {
reply: remaining_bandwidth_data,
reply_to,
request_id,
}),
reply_to,
}
}
pub fn recipient(&self) -> Recipient {
self.reply_to
}
pub fn to_bytes(&self) -> Result<Vec<u8>, bincode::Error> {
use bincode::Options;
make_bincode_serializer().serialize(self)
}
pub fn from_reconstructed_message(
message: &nym_sphinx::receiver::ReconstructedMessage,
) -> Result<Self, bincode::Error> {
use bincode::Options;
make_bincode_serializer().deserialize(&message.message)
}
pub fn id(&self) -> Option<u64> {
match &self.data {
AuthenticatorResponseData::PendingRegistration(response) => Some(response.request_id),
AuthenticatorResponseData::Registered(response) => Some(response.request_id),
AuthenticatorResponseData::RemainingBandwidth(response) => Some(response.request_id),
AuthenticatorResponseData::TopUpBandwidth(response) => Some(response.request_id),
}
}
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub enum AuthenticatorResponseData {
PendingRegistration(PendingRegistrationResponse),
Registered(RegisteredResponse),
RemainingBandwidth(RemainingBandwidthResponse),
TopUpBandwidth(TopUpBandwidthResponse),
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct PendingRegistrationResponse {
pub request_id: u64,
pub reply_to: Recipient,
pub reply: RegistrationData,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct RegisteredResponse {
pub request_id: u64,
pub reply_to: Recipient,
pub reply: RegistredData,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct RemainingBandwidthResponse {
pub request_id: u64,
pub reply_to: Recipient,
pub reply: Option<RemainingBandwidthData>,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct TopUpBandwidthResponse {
pub request_id: u64,
pub reply_to: Recipient,
pub reply: RemainingBandwidthData,
}
@@ -1,15 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use nym_credentials_interface::CredentialSpendingData;
use nym_wireguard_types::PeerPublicKey;
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct TopUpMessage {
/// Base64 encoded x25519 public key
pub pub_key: PeerPublicKey,
/// Ecash credential
pub credential: CredentialSpendingData,
}
+4 -8
View File
@@ -16,7 +16,7 @@ use nym_credential_storage::models::RetrievedTicketbook;
use nym_credential_storage::storage::Storage; use nym_credential_storage::storage::Storage;
use nym_credentials::ecash::bandwidth::CredentialSpendingData; use nym_credentials::ecash::bandwidth::CredentialSpendingData;
use nym_credentials_interface::{ use nym_credentials_interface::{
AnnotatedCoinIndexSignature, AnnotatedExpirationDateSignature, TicketType, VerificationKeyAuth, AnnotatedCoinIndexSignature, AnnotatedExpirationDateSignature, VerificationKeyAuth,
}; };
use nym_ecash_time::Date; use nym_ecash_time::Date;
use nym_validator_client::nym_api::EpochId; use nym_validator_client::nym_api::EpochId;
@@ -64,10 +64,9 @@ impl<C, St: Storage> BandwidthController<C, St> {
BandwidthController { storage, client } BandwidthController { storage, client }
} }
/// Tries to retrieve one of the stored, unused credentials for the given type that hasn't yet expired. /// Tries to retrieve one of the stored, unused credentials that hasn't yet expired.
pub async fn get_next_usable_ticketbook( pub async fn get_next_usable_ticketbook(
&self, &self,
ticketbook_type: TicketType,
tickets: u32, tickets: u32,
) -> Result<RetrievedTicketbook, BandwidthControllerError> ) -> Result<RetrievedTicketbook, BandwidthControllerError>
where where
@@ -75,7 +74,7 @@ impl<C, St: Storage> BandwidthController<C, St> {
{ {
let Some(ticketbook) = self let Some(ticketbook) = self
.storage .storage
.get_next_unspent_usable_ticketbook(ticketbook_type.to_string(), tickets) .get_next_unspent_usable_ticketbook(tickets)
.await .await
.map_err(BandwidthControllerError::credential_storage_error)? .map_err(BandwidthControllerError::credential_storage_error)?
else { else {
@@ -182,7 +181,6 @@ impl<C, St: Storage> BandwidthController<C, St> {
pub async fn prepare_ecash_ticket( pub async fn prepare_ecash_ticket(
&self, &self,
ticketbook_type: TicketType,
provider_pk: [u8; 32], provider_pk: [u8; 32],
tickets_to_spend: u32, tickets_to_spend: u32,
) -> Result<PreparedCredential, BandwidthControllerError> ) -> Result<PreparedCredential, BandwidthControllerError>
@@ -190,9 +188,7 @@ impl<C, St: Storage> BandwidthController<C, St> {
C: DkgQueryClient + Sync + Send, C: DkgQueryClient + Sync + Send,
<St as Storage>::StorageError: Send + Sync + 'static, <St as Storage>::StorageError: Send + Sync + 'static,
{ {
let retrieved_ticketbook = self let retrieved_ticketbook = self.get_next_usable_ticketbook(tickets_to_spend).await?;
.get_next_usable_ticketbook(ticketbook_type, tickets_to_spend)
.await?;
let ticketbook_id = retrieved_ticketbook.ticketbook_id; let ticketbook_id = retrieved_ticketbook.ticketbook_id;
let epoch_id = retrieved_ticketbook.ticketbook.epoch_id(); let epoch_id = retrieved_ticketbook.ticketbook.epoch_id();
-1
View File
@@ -45,4 +45,3 @@ tracing = [
"opentelemetry", "opentelemetry",
] ]
clap = [ "dep:clap", "dep:clap_complete", "dep:clap_complete_fig" ] 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) .filename(database_path)
.create_if_missing(true) .create_if_missing(true);
.disable_statement_logging();
opts.disable_statement_logging();
let connection_pool = sqlx::SqlitePool::connect_with(opts) let connection_pool = sqlx::SqlitePool::connect_with(opts)
.await .await
@@ -81,7 +82,7 @@ impl StorageManager {
sqlx::query!("SELECT EXISTS (SELECT 1 FROM registered_gateway WHERE gateway_id_bs58 = ?) AS 'exists'", gateway_id) sqlx::query!("SELECT EXISTS (SELECT 1 FROM registered_gateway WHERE gateway_id_bs58 = ?) AS 'exists'", gateway_id)
.fetch_one(&self.connection_pool) .fetch_one(&self.connection_pool)
.await .await
.map(|result| result.exists == Some(1)) .map(|result| result.exists == 1)
} }
pub(crate) async fn maybe_get_registered_gateway( pub(crate) async fn maybe_get_registered_gateway(
@@ -3,11 +3,11 @@ use log::{debug, error};
use nym_explorer_client::{ExplorerClient, PrettyDetailedMixNodeBond}; use nym_explorer_client::{ExplorerClient, PrettyDetailedMixNodeBond};
use nym_network_defaults::var_names::EXPLORER_API; use nym_network_defaults::var_names::EXPLORER_API;
use nym_topology::{ use nym_topology::{
nym_topology_from_basic_info, nym_topology_from_detailed,
provider_trait::{async_trait, TopologyProvider}, provider_trait::{async_trait, TopologyProvider},
NymTopology, NymTopology,
}; };
use nym_validator_client::client::NodeId; use nym_validator_client::client::MixId;
use rand::{prelude::SliceRandom, thread_rng}; use rand::{prelude::SliceRandom, thread_rng};
use std::collections::HashMap; use std::collections::HashMap;
use tap::TapOptional; use tap::TapOptional;
@@ -39,10 +39,10 @@ fn create_explorer_client() -> Option<ExplorerClient> {
fn group_mixnodes_by_country_code( fn group_mixnodes_by_country_code(
mixnodes: Vec<PrettyDetailedMixNodeBond>, mixnodes: Vec<PrettyDetailedMixNodeBond>,
) -> HashMap<CountryGroup, Vec<NodeId>> { ) -> HashMap<CountryGroup, Vec<MixId>> {
mixnodes mixnodes
.into_iter() .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 { if let Some(ref location) = m.location {
let country_code = location.two_letter_iso_country_code.clone(); let country_code = location.two_letter_iso_country_code.clone();
let group_code = CountryGroup::new(country_code.as_str()); 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 let mixnode_distribution = mixnodes
.iter() .iter()
.map(|(k, v)| format!("{}: {}", k, v.len())) .map(|(k, v)| format!("{}: {}", k, v.len()))
@@ -110,11 +110,7 @@ impl GeoAwareTopologyProvider {
} }
async fn get_topology(&self) -> Option<NymTopology> { async fn get_topology(&self) -> Option<NymTopology> {
let mixnodes = match self let mixnodes = match self.validator_client.get_cached_active_mixnodes().await {
.validator_client
.get_basic_active_mixing_assigned_nodes(Some(self.client_version.clone()))
.await
{
Err(err) => { Err(err) => {
error!("failed to get network mixnodes - {err}"); error!("failed to get network mixnodes - {err}");
return None; return None;
@@ -122,11 +118,7 @@ impl GeoAwareTopologyProvider {
Ok(mixes) => mixes, Ok(mixes) => mixes,
}; };
let gateways = match self let gateways = match self.validator_client.get_cached_gateways().await {
.validator_client
.get_all_basic_entry_assigned_nodes(Some(self.client_version.clone()))
.await
{
Err(err) => { Err(err) => {
error!("failed to get network gateways - {err}"); error!("failed to get network gateways - {err}");
return None; return None;
@@ -190,10 +182,11 @@ impl GeoAwareTopologyProvider {
let mixnodes = mixnodes let mixnodes = mixnodes
.into_iter() .into_iter()
.filter(|m| filtered_mixnode_ids.contains(&m.node_id)) .filter(|m| filtered_mixnode_ids.contains(&m.mix_id()))
.collect::<Vec<_>>(); .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 // TODO: return real error type
check_layer_integrity(topology.clone()).ok()?; check_layer_integrity(topology.clone()).ok()?;
@@ -98,7 +98,7 @@ impl NymApiTopologyProvider {
async fn get_current_compatible_topology(&mut self) -> Option<NymTopology> { async fn get_current_compatible_topology(&mut self) -> Option<NymTopology> {
let mixnodes = match self let mixnodes = match self
.validator_client .validator_client
.get_basic_active_mixing_assigned_nodes(Some(self.client_version.clone())) .get_basic_mixnodes(Some(self.client_version.clone()))
.await .await
{ {
Err(err) => { Err(err) => {
@@ -110,7 +110,7 @@ impl NymApiTopologyProvider {
let gateways = match self let gateways = match self
.validator_client .validator_client
.get_all_basic_entry_assigned_nodes(Some(self.client_version.clone())) .get_basic_gateways(Some(self.client_version.clone()))
.await .await
{ {
Err(err) => { Err(err) => {
@@ -134,6 +134,7 @@ impl NymApiTopologyProvider {
g.performance.round_to_integer() >= self.config.min_gateway_performance g.performance.round_to_integer() >= self.config.min_gateway_performance
}), }),
); );
if let Err(err) = self.check_layer_distribution(&topology) { 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}"); warn!("The current filtered active topology has extremely skewed layer distribution. It cannot be used: {err}");
self.use_next_nym_api(); self.use_next_nym_api();
+10
View File
@@ -187,6 +187,16 @@ pub enum ClientCoreError {
source: Ed25519RecoveryError, 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( #[error(
"the listening address of gateway {gateway_id} ({raw_listener}) is malformed: {source}" "the listening address of gateway {gateway_id} ({raw_listener}) is malformed: {source}"
)] )]
+26 -19
View File
@@ -7,7 +7,7 @@ use futures::{SinkExt, StreamExt};
use log::{debug, info, trace, warn}; use log::{debug, info, trace, warn};
use nym_crypto::asymmetric::identity; use nym_crypto::asymmetric::identity;
use nym_gateway_client::GatewayClient; 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::client::IdentityKeyRef;
use nym_validator_client::UserAgent; use nym_validator_client::UserAgent;
use rand::{seq::SliceRandom, Rng}; use rand::{seq::SliceRandom, Rng};
@@ -53,7 +53,7 @@ pub trait ConnectableGateway {
fn is_wss(&self) -> bool; fn is_wss(&self) -> bool;
} }
impl ConnectableGateway for gateway::LegacyNode { impl ConnectableGateway for gateway::Node {
fn identity(&self) -> &identity::PublicKey { fn identity(&self) -> &identity::PublicKey {
self.identity() self.identity()
} }
@@ -82,7 +82,7 @@ pub async fn current_gateways<R: Rng>(
rng: &mut R, rng: &mut R,
nym_apis: &[Url], nym_apis: &[Url],
user_agent: Option<UserAgent>, user_agent: Option<UserAgent>,
) -> Result<Vec<gateway::LegacyNode>, ClientCoreError> { ) -> Result<Vec<gateway::Node>, ClientCoreError> {
let nym_api = nym_apis let nym_api = nym_apis
.choose(rng) .choose(rng)
.ok_or(ClientCoreError::ListOfNymApisIsEmpty)?; .ok_or(ClientCoreError::ListOfNymApisIsEmpty)?;
@@ -94,26 +94,31 @@ pub async fn current_gateways<R: Rng>(
log::debug!("Fetching list of gateways from: {nym_api}"); 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::debug!("Found {} gateways", gateways.len());
log::trace!("Gateways: {:#?}", gateways); log::trace!("Gateways: {:#?}", gateways);
let valid_gateways = gateways let valid_gateways = gateways
.iter() .into_iter()
.filter_map(|gateway| gateway.try_into().ok()) .filter_map(|gateway| gateway.try_into().ok())
.collect::<Vec<gateway::LegacyNode>>(); .collect::<Vec<gateway::Node>>();
log::debug!("After checking validity: {}", valid_gateways.len()); log::debug!("Ater checking validity: {}", valid_gateways.len());
log::trace!("Valid gateways: {:#?}", valid_gateways); 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>( pub async fn current_mixnodes<R: Rng>(
rng: &mut R, rng: &mut R,
nym_apis: &[Url], nym_apis: &[Url],
) -> Result<Vec<mix::LegacyNode>, ClientCoreError> { ) -> Result<Vec<mix::Node>, ClientCoreError> {
let nym_api = nym_apis let nym_api = nym_apis
.choose(rng) .choose(rng)
.ok_or(ClientCoreError::ListOfNymApisIsEmpty)?; .ok_or(ClientCoreError::ListOfNymApisIsEmpty)?;
@@ -121,13 +126,15 @@ pub async fn current_mixnodes<R: Rng>(
log::trace!("Fetching list of mixnodes from: {nym_api}"); log::trace!("Fetching list of mixnodes from: {nym_api}");
let mixnodes = client.get_basic_active_mixing_assigned_nodes(None).await?; let mixnodes = client.get_cached_mixnodes().await?;
let valid_mixnodes = mixnodes let valid_mixnodes = mixnodes
.iter() .into_iter()
.filter_map(|mixnode| mixnode.try_into().ok()) .filter_map(|mixnode| (&mixnode.bond_information).try_into().ok())
.collect::<Vec<mix::LegacyNode>>(); .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"))] #[cfg(not(target_arch = "wasm32"))]
@@ -266,9 +273,9 @@ fn filter_by_tls<G: ConnectableGateway>(
pub(super) fn uniformly_random_gateway<R: Rng>( pub(super) fn uniformly_random_gateway<R: Rng>(
rng: &mut R, rng: &mut R,
gateways: &[gateway::LegacyNode], gateways: &[gateway::Node],
must_use_tls: bool, must_use_tls: bool,
) -> Result<gateway::LegacyNode, ClientCoreError> { ) -> Result<gateway::Node, ClientCoreError> {
filter_by_tls(gateways, must_use_tls)? filter_by_tls(gateways, must_use_tls)?
.choose(rng) .choose(rng)
.ok_or(ClientCoreError::NoGatewaysOnNetwork) .ok_or(ClientCoreError::NoGatewaysOnNetwork)
@@ -277,9 +284,9 @@ pub(super) fn uniformly_random_gateway<R: Rng>(
pub(super) fn get_specified_gateway( pub(super) fn get_specified_gateway(
gateway_identity: IdentityKeyRef, gateway_identity: IdentityKeyRef,
gateways: &[gateway::LegacyNode], gateways: &[gateway::Node],
must_use_tls: bool, must_use_tls: bool,
) -> Result<gateway::LegacyNode, ClientCoreError> { ) -> Result<gateway::Node, ClientCoreError> {
log::debug!("Requesting specified gateway: {}", gateway_identity); log::debug!("Requesting specified gateway: {}", gateway_identity);
let user_gateway = identity::PublicKey::from_base58_string(gateway_identity) let user_gateway = identity::PublicKey::from_base58_string(gateway_identity)
.map_err(ClientCoreError::UnableToCreatePublicKeyFromGatewayId)?; .map_err(ClientCoreError::UnableToCreatePublicKeyFromGatewayId)?;
+1 -1
View File
@@ -50,7 +50,7 @@ async fn setup_new_gateway<K, D>(
key_store: &K, key_store: &K,
details_store: &D, details_store: &D,
selection_specification: GatewaySelectionSpecification, selection_specification: GatewaySelectionSpecification,
available_gateways: Vec<gateway::LegacyNode>, available_gateways: Vec<gateway::Node>,
) -> Result<InitialisationResult, ClientCoreError> ) -> Result<InitialisationResult, ClientCoreError>
where where
K: KeyStore, K: KeyStore,
+18 -3
View File
@@ -18,6 +18,7 @@ use nym_validator_client::client::IdentityKey;
use nym_validator_client::nyxd::AccountId; use nym_validator_client::nyxd::AccountId;
use serde::Serialize; use serde::Serialize;
use std::fmt::Display; use std::fmt::Display;
use std::str::FromStr;
use std::sync::Arc; use std::sync::Arc;
use time::OffsetDateTime; use time::OffsetDateTime;
use url::Url; use url::Url;
@@ -38,7 +39,7 @@ pub enum SelectedGateway {
impl SelectedGateway { impl SelectedGateway {
pub fn from_topology_node( pub fn from_topology_node(
node: gateway::LegacyNode, node: gateway::Node,
must_use_tls: bool, must_use_tls: bool,
) -> Result<Self, ClientCoreError> { ) -> Result<Self, ClientCoreError> {
let gateway_listener = if must_use_tls { let gateway_listener = if must_use_tls {
@@ -50,6 +51,20 @@ impl SelectedGateway {
node.clients_address() 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 = let gateway_listener =
Url::parse(&gateway_listener).map_err(|source| ClientCoreError::MalformedListener { Url::parse(&gateway_listener).map_err(|source| ClientCoreError::MalformedListener {
gateway_id: node.identity_key.to_base58_string(), gateway_id: node.identity_key.to_base58_string(),
@@ -59,7 +74,7 @@ impl SelectedGateway {
Ok(SelectedGateway::Remote { Ok(SelectedGateway::Remote {
gateway_id: node.identity_key, gateway_id: node.identity_key,
gateway_owner_address: None, gateway_owner_address,
gateway_listener, gateway_listener,
}) })
} }
@@ -200,7 +215,7 @@ pub enum GatewaySetup {
specification: GatewaySelectionSpecification, specification: GatewaySelectionSpecification,
// TODO: seems to be a bit inefficient to pass them by value // TODO: seems to be a bit inefficient to pass them by value
available_gateways: Vec<gateway::LegacyNode>, available_gateways: Vec<gateway::Node>,
}, },
ReuseConnection { ReuseConnection {
@@ -1,12 +1,9 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net> // Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
use crate::backend::fs_backend::{ use crate::backend::fs_backend::error::StorageError;
error::StorageError, use crate::backend::fs_backend::models::{
models::{ ReplySurbStorageMetadata, StoredReplyKey, StoredReplySurb, StoredSenderTag, StoredSurbSender,
ReplySurbStorageMetadata, StoredReplyKey, StoredReplySurb, StoredSenderTag,
StoredSurbSender,
},
}; };
use log::{error, info}; use log::{error, info};
use sqlx::ConnectOptions; 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) .filename(database_path)
.create_if_missing(fresh) .create_if_missing(fresh);
.disable_statement_logging();
opts.disable_statement_logging();
let connection_pool = match sqlx::SqlitePool::connect_with(opts).await { let connection_pool = match sqlx::SqlitePool::connect_with(opts).await {
Ok(pool) => pool, Ok(pool) => pool,
@@ -24,7 +24,6 @@ zeroize.workspace = true
nym-bandwidth-controller = { path = "../../bandwidth-controller" } nym-bandwidth-controller = { path = "../../bandwidth-controller" }
nym-credentials = { path = "../../credentials" } nym-credentials = { path = "../../credentials" }
nym-credential-storage = { path = "../../credential-storage" } nym-credential-storage = { path = "../../credential-storage" }
nym-credentials-interface = { path = "../../credentials-interface" }
nym-crypto = { path = "../../crypto" } nym-crypto = { path = "../../crypto" }
nym-gateway-requests = { path = "../../gateway-requests" } nym-gateway-requests = { path = "../../gateway-requests" }
nym-network-defaults = { path = "../../network-defaults" } nym-network-defaults = { path = "../../network-defaults" }
@@ -16,7 +16,6 @@ use nym_bandwidth_controller::{BandwidthController, BandwidthStatusMessage};
use nym_credential_storage::ephemeral_storage::EphemeralStorage as EphemeralCredentialStorage; use nym_credential_storage::ephemeral_storage::EphemeralStorage as EphemeralCredentialStorage;
use nym_credential_storage::storage::Storage as CredentialStorage; use nym_credential_storage::storage::Storage as CredentialStorage;
use nym_credentials::CredentialSpendingData; use nym_credentials::CredentialSpendingData;
use nym_credentials_interface::TicketType;
use nym_crypto::asymmetric::identity; use nym_crypto::asymmetric::identity;
use nym_gateway_requests::registration::handshake::client_handshake; use nym_gateway_requests::registration::handshake::client_handshake;
use nym_gateway_requests::{ use nym_gateway_requests::{
@@ -749,11 +748,7 @@ impl<C, St> GatewayClient<C, St> {
} }
let prepared_credential = self let prepared_credential = self
.unchecked_bandwidth_controller() .unchecked_bandwidth_controller()
.prepare_ecash_ticket( .prepare_ecash_ticket(self.gateway_identity.to_bytes(), TICKETS_TO_SPEND)
TicketType::V1MixnetEntry,
self.gateway_identity.to_bytes(),
TICKETS_TO_SPEND,
)
.await?; .await?;
match self.claim_ecash_bandwidth(prepared_credential.data).await { match self.claim_ecash_bandwidth(prepared_credential.data).await {
@@ -25,6 +25,7 @@ serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true } serde_json = { workspace = true }
nym-http-api-client = { path = "../../../common/http-api-client" } nym-http-api-client = { path = "../../../common/http-api-client" }
thiserror = { workspace = true } thiserror = { workspace = true }
log = { workspace = true }
tracing = { workspace = true } tracing = { workspace = true }
url = { workspace = true, features = ["serde"] } url = { workspace = true, features = ["serde"] }
tokio = { workspace = true, features = ["sync", "time"] } tokio = { workspace = true, features = ["sync", "time"] }
@@ -17,11 +17,11 @@ use nym_api_requests::ecash::{
BlindSignRequestBody, BlindedSignatureResponse, PartialCoinIndicesSignatureResponse, BlindSignRequestBody, BlindedSignatureResponse, PartialCoinIndicesSignatureResponse,
PartialExpirationDateSignatureResponse, VerificationKeyResponse, PartialExpirationDateSignatureResponse, VerificationKeyResponse,
}; };
use nym_api_requests::models::{DescribedGateway, MixNodeBondAnnotated};
use nym_api_requests::models::{ use nym_api_requests::models::{
GatewayCoreStatusResponse, MixnodeCoreStatusResponse, MixnodeStatusResponse, GatewayCoreStatusResponse, MixnodeCoreStatusResponse, MixnodeStatusResponse,
RewardEstimationResponse, StakeSaturationResponse, RewardEstimationResponse, StakeSaturationResponse,
}; };
use nym_api_requests::models::{LegacyDescribedGateway, MixNodeBondAnnotated};
use nym_api_requests::nym_nodes::SkimmedNode; use nym_api_requests::nym_nodes::SkimmedNode;
use nym_coconut_dkg_common::types::EpochId; use nym_coconut_dkg_common::types::EpochId;
use nym_http_api_client::UserAgent; use nym_http_api_client::UserAgent;
@@ -31,7 +31,7 @@ use url::Url;
pub use crate::nym_api::NymApiClientExt; pub use crate::nym_api::NymApiClientExt;
pub use nym_mixnet_contract_common::{ 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 // re-export the type to not break existing imports
@@ -265,13 +265,6 @@ impl NymApiClient {
NymApiClient { nym_api } 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 { pub fn new_with_user_agent(api_url: Url, user_agent: UserAgent) -> Self {
let nym_api = nym_api::Client::builder::<_, ValidatorClientError>(api_url) let nym_api = nym_api::Client::builder::<_, ValidatorClientError>(api_url)
.expect("invalid api url") .expect("invalid api url")
@@ -290,7 +283,6 @@ impl NymApiClient {
self.nym_api.change_base_url(new_endpoint); self.nym_api.change_base_url(new_endpoint);
} }
#[deprecated(note = "use get_basic_active_mixing_assigned_nodes instead")]
pub async fn get_basic_mixnodes( pub async fn get_basic_mixnodes(
&self, &self,
semver_compatibility: Option<String>, semver_compatibility: Option<String>,
@@ -302,7 +294,6 @@ impl NymApiClient {
.nodes) .nodes)
} }
#[deprecated(note = "use get_all_basic_entry_assigned_nodes instead")]
pub async fn get_basic_gateways( pub async fn get_basic_gateways(
&self, &self,
semver_compatibility: Option<String>, semver_compatibility: Option<String>,
@@ -314,70 +305,6 @@ impl NymApiClient {
.nodes) .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_all_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_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)
}
pub async fn get_cached_active_mixnodes( pub async fn get_cached_active_mixnodes(
&self, &self,
) -> Result<Vec<MixNodeDetails>, ValidatorClientError> { ) -> Result<Vec<MixNodeDetails>, ValidatorClientError> {
@@ -400,7 +327,7 @@ impl NymApiClient {
pub async fn get_cached_described_gateways( pub async fn get_cached_described_gateways(
&self, &self,
) -> Result<Vec<LegacyDescribedGateway>, ValidatorClientError> { ) -> Result<Vec<DescribedGateway>, ValidatorClientError> {
Ok(self.nym_api.get_gateways_described().await?) Ok(self.nym_api.get_gateways_described().await?)
} }
@@ -417,7 +344,7 @@ impl NymApiClient {
pub async fn get_mixnode_core_status_count( pub async fn get_mixnode_core_status_count(
&self, &self,
mix_id: NodeId, mix_id: MixId,
since: Option<i64>, since: Option<i64>,
) -> Result<MixnodeCoreStatusResponse, ValidatorClientError> { ) -> Result<MixnodeCoreStatusResponse, ValidatorClientError> {
Ok(self Ok(self
@@ -428,21 +355,21 @@ impl NymApiClient {
pub async fn get_mixnode_status( pub async fn get_mixnode_status(
&self, &self,
mix_id: NodeId, mix_id: MixId,
) -> Result<MixnodeStatusResponse, ValidatorClientError> { ) -> Result<MixnodeStatusResponse, ValidatorClientError> {
Ok(self.nym_api.get_mixnode_status(mix_id).await?) Ok(self.nym_api.get_mixnode_status(mix_id).await?)
} }
pub async fn get_mixnode_reward_estimation( pub async fn get_mixnode_reward_estimation(
&self, &self,
mix_id: NodeId, mix_id: MixId,
) -> Result<RewardEstimationResponse, ValidatorClientError> { ) -> Result<RewardEstimationResponse, ValidatorClientError> {
Ok(self.nym_api.get_mixnode_reward_estimation(mix_id).await?) Ok(self.nym_api.get_mixnode_reward_estimation(mix_id).await?)
} }
pub async fn get_mixnode_stake_saturation( pub async fn get_mixnode_stake_saturation(
&self, &self,
mix_id: NodeId, mix_id: MixId,
) -> Result<StakeSaturationResponse, ValidatorClientError> { ) -> Result<StakeSaturationResponse, ValidatorClientError> {
Ok(self.nym_api.get_mixnode_stake_saturation(mix_id).await?) Ok(self.nym_api.get_mixnode_stake_saturation(mix_id).await?)
} }
@@ -121,36 +121,36 @@ async fn test_nyxd_connection(
{ {
Ok(Err(NyxdError::TendermintErrorRpc(e))) => { Ok(Err(NyxdError::TendermintErrorRpc(e))) => {
// If we get a tendermint-rpc error, we classify the node as not contactable // 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 false
} }
Ok(Err(NyxdError::AbciError { code, log, .. })) => { Ok(Err(NyxdError::AbciError { code, log, .. })) => {
// We accept the mixnet contract not found as ok from a connection standpoint. This happens // We accept the mixnet contract not found as ok from a connection standpoint. This happens
// for example on a pre-launch network. // for example on a pre-launch network.
tracing::debug!( log::debug!(
"Checking: nyxd url: {url}: {}, but with abci error: {code}: {log}", "Checking: nyxd url: {url}: {}, but with abci error: {code}: {log}",
"success".green() "success".green()
); );
code == 18 code == 18
} }
Ok(Err(error @ NyxdError::NoContractAddressAvailable(_))) => { Ok(Err(error @ NyxdError::NoContractAddressAvailable(_))) => {
tracing::warn!("Checking: nyxd url: {url}: {}: {error}", "failed".red()); log::warn!("Checking: nyxd url: {url}: {}: {error}", "failed".red());
false false
} }
Ok(Err(e)) => { Ok(Err(e)) => {
// For any other error, we're optimistic and just try anyway. // For any other error, we're optimistic and just try anyway.
tracing::warn!( log::warn!(
"Checking: nyxd_url: {url}: {}, but with error: {e}", "Checking: nyxd_url: {url}: {}, but with error: {e}",
"success".green() "success".green()
); );
true true
} }
Ok(Ok(_)) => { Ok(Ok(_)) => {
tracing::debug!("Checking: nyxd_url: {url}: {}", "success".green()); log::debug!("Checking: nyxd_url: {url}: {}", "success".green());
true true
} }
Err(e) => { Err(e) => {
tracing::warn!("Checking: nyxd_url: {url}: {}: {e}", "failed".red()); log::warn!("Checking: nyxd_url: {url}: {}: {e}", "failed".red());
false false
} }
}; };
@@ -169,15 +169,15 @@ async fn test_nym_api_connection(
.await .await
{ {
Ok(Ok(_)) => { Ok(Ok(_)) => {
tracing::debug!("Checking: api_url: {url}: {}", "success".green()); log::debug!("Checking: api_url: {url}: {}", "success".green());
true true
} }
Ok(Err(e)) => { Ok(Err(e)) => {
tracing::debug!("Checking: api_url: {url}: {}: {e}", "failed".red()); log::debug!("Checking: api_url: {url}: {}: {e}", "failed".red());
false false
} }
Err(e) => { Err(e) => {
tracing::debug!("Checking: api_url: {url}: {}: {e}", "failed".red()); log::debug!("Checking: api_url: {url}: {}: {e}", "failed".red());
false false
} }
}; };
@@ -10,10 +10,8 @@ use nym_api_requests::ecash::models::{
VerifyEcashTicketBody, VerifyEcashTicketBody,
}; };
use nym_api_requests::ecash::VerificationKeyResponse; use nym_api_requests::ecash::VerificationKeyResponse;
use nym_api_requests::models::{ use nym_api_requests::models::DescribedMixNode;
AnnotationResponse, LegacyDescribedMixNode, NodePerformanceResponse, use nym_api_requests::nym_nodes::{CachedNodesResponse, SkimmedNode};
};
use nym_api_requests::nym_nodes::PaginatedCachedNodesResponse;
pub use nym_api_requests::{ pub use nym_api_requests::{
ecash::{ ecash::{
models::{ models::{
@@ -25,23 +23,21 @@ pub use nym_api_requests::{
VerifyEcashCredentialBody, VerifyEcashCredentialBody,
}, },
models::{ models::{
ComputeRewardEstParam, GatewayBondAnnotated, GatewayCoreStatusResponse, ComputeRewardEstParam, DescribedGateway, GatewayBondAnnotated, GatewayCoreStatusResponse,
GatewayStatusReportResponse, GatewayUptimeHistoryResponse, InclusionProbabilityResponse, GatewayStatusReportResponse, GatewayUptimeHistoryResponse, InclusionProbabilityResponse,
LegacyDescribedGateway, MixNodeBondAnnotated, MixnodeCoreStatusResponse, MixNodeBondAnnotated, MixnodeCoreStatusResponse, MixnodeStatusReportResponse,
MixnodeStatusReportResponse, MixnodeStatusResponse, MixnodeUptimeHistoryResponse, MixnodeStatusResponse, MixnodeUptimeHistoryResponse, RewardEstimationResponse,
RewardEstimationResponse, StakeSaturationResponse, UptimeResponse, StakeSaturationResponse, UptimeResponse,
}, },
nym_nodes::{CachedNodesResponse, SkimmedNode},
}; };
pub use nym_coconut_dkg_common::types::EpochId; pub use nym_coconut_dkg_common::types::EpochId;
use nym_contracts_common::IdentityKey; use nym_contracts_common::IdentityKey;
pub use nym_http_api_client::Client; pub use nym_http_api_client::Client;
use nym_http_api_client::{ApiClient, NO_PARAMS}; use nym_http_api_client::{ApiClient, NO_PARAMS};
use nym_mixnet_contract_common::mixnode::MixNodeDetails; use nym_mixnet_contract_common::mixnode::MixNodeDetails;
use nym_mixnet_contract_common::{GatewayBond, IdentityKeyRef, NodeId}; use nym_mixnet_contract_common::{GatewayBond, IdentityKeyRef, MixId};
use time::format_description::BorrowedFormatItem; use time::format_description::BorrowedFormatItem;
use time::Date; use time::Date;
use tracing::instrument;
pub mod error; pub mod error;
pub mod routes; pub mod routes;
@@ -53,13 +49,11 @@ pub fn rfc_3339_date() -> Vec<BorrowedFormatItem<'static>> {
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))] #[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)] #[cfg_attr(not(target_arch = "wasm32"), async_trait)]
pub trait NymApiClientExt: ApiClient { pub trait NymApiClientExt: ApiClient {
#[instrument(level = "debug", skip(self))]
async fn get_mixnodes(&self) -> Result<Vec<MixNodeDetails>, NymAPIError> { async fn get_mixnodes(&self) -> Result<Vec<MixNodeDetails>, NymAPIError> {
self.get_json(&[routes::API_VERSION, routes::MIXNODES], NO_PARAMS) self.get_json(&[routes::API_VERSION, routes::MIXNODES], NO_PARAMS)
.await .await
} }
#[instrument(level = "debug", skip(self))]
async fn get_mixnodes_detailed(&self) -> Result<Vec<MixNodeBondAnnotated>, NymAPIError> { async fn get_mixnodes_detailed(&self) -> Result<Vec<MixNodeBondAnnotated>, NymAPIError> {
self.get_json( self.get_json(
&[ &[
@@ -73,7 +67,6 @@ pub trait NymApiClientExt: ApiClient {
.await .await
} }
#[instrument(level = "debug", skip(self))]
async fn get_gateways_detailed(&self) -> Result<Vec<GatewayBondAnnotated>, NymAPIError> { async fn get_gateways_detailed(&self) -> Result<Vec<GatewayBondAnnotated>, NymAPIError> {
self.get_json( self.get_json(
&[ &[
@@ -87,7 +80,6 @@ pub trait NymApiClientExt: ApiClient {
.await .await
} }
#[instrument(level = "debug", skip(self))]
async fn get_mixnodes_detailed_unfiltered( async fn get_mixnodes_detailed_unfiltered(
&self, &self,
) -> Result<Vec<MixNodeBondAnnotated>, NymAPIError> { ) -> Result<Vec<MixNodeBondAnnotated>, NymAPIError> {
@@ -103,14 +95,12 @@ pub trait NymApiClientExt: ApiClient {
.await .await
} }
#[instrument(level = "debug", skip(self))]
async fn get_gateways(&self) -> Result<Vec<GatewayBond>, NymAPIError> { async fn get_gateways(&self) -> Result<Vec<GatewayBond>, NymAPIError> {
self.get_json(&[routes::API_VERSION, routes::GATEWAYS], NO_PARAMS) self.get_json(&[routes::API_VERSION, routes::GATEWAYS], NO_PARAMS)
.await .await
} }
#[instrument(level = "debug", skip(self))] async fn get_gateways_described(&self) -> Result<Vec<DescribedGateway>, NymAPIError> {
async fn get_gateways_described(&self) -> Result<Vec<LegacyDescribedGateway>, NymAPIError> {
self.get_json( self.get_json(
&[routes::API_VERSION, routes::GATEWAYS, routes::DESCRIBED], &[routes::API_VERSION, routes::GATEWAYS, routes::DESCRIBED],
NO_PARAMS, NO_PARAMS,
@@ -118,8 +108,7 @@ pub trait NymApiClientExt: ApiClient {
.await .await
} }
#[instrument(level = "debug", skip(self))] async fn get_mixnodes_described(&self) -> Result<Vec<DescribedMixNode>, NymAPIError> {
async fn get_mixnodes_described(&self) -> Result<Vec<LegacyDescribedMixNode>, NymAPIError> {
self.get_json( self.get_json(
&[routes::API_VERSION, routes::MIXNODES, routes::DESCRIBED], &[routes::API_VERSION, routes::MIXNODES, routes::DESCRIBED],
NO_PARAMS, NO_PARAMS,
@@ -127,7 +116,6 @@ pub trait NymApiClientExt: ApiClient {
.await .await
} }
#[tracing::instrument(level = "debug", skip_all)]
async fn get_basic_mixnodes( async fn get_basic_mixnodes(
&self, &self,
semver_compatibility: Option<String>, semver_compatibility: Option<String>,
@@ -151,7 +139,6 @@ pub trait NymApiClientExt: ApiClient {
.await .await
} }
#[instrument(level = "debug", skip(self))]
async fn get_basic_gateways( async fn get_basic_gateways(
&self, &self,
semver_compatibility: Option<String>, semver_compatibility: Option<String>,
@@ -175,91 +162,6 @@ pub trait NymApiClientExt: ApiClient {
.await .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_all_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
}
#[instrument(level = "debug", skip(self))]
async fn get_active_mixnodes(&self) -> Result<Vec<MixNodeDetails>, NymAPIError> { async fn get_active_mixnodes(&self) -> Result<Vec<MixNodeDetails>, NymAPIError> {
self.get_json( self.get_json(
&[routes::API_VERSION, routes::MIXNODES, routes::ACTIVE], &[routes::API_VERSION, routes::MIXNODES, routes::ACTIVE],
@@ -268,7 +170,6 @@ pub trait NymApiClientExt: ApiClient {
.await .await
} }
#[instrument(level = "debug", skip(self))]
async fn get_active_mixnodes_detailed(&self) -> Result<Vec<MixNodeBondAnnotated>, NymAPIError> { async fn get_active_mixnodes_detailed(&self) -> Result<Vec<MixNodeBondAnnotated>, NymAPIError> {
self.get_json( self.get_json(
&[ &[
@@ -283,7 +184,6 @@ pub trait NymApiClientExt: ApiClient {
.await .await
} }
#[instrument(level = "debug", skip(self))]
async fn get_rewarded_mixnodes(&self) -> Result<Vec<MixNodeDetails>, NymAPIError> { async fn get_rewarded_mixnodes(&self) -> Result<Vec<MixNodeDetails>, NymAPIError> {
self.get_json( self.get_json(
&[routes::API_VERSION, routes::MIXNODES, routes::REWARDED], &[routes::API_VERSION, routes::MIXNODES, routes::REWARDED],
@@ -292,10 +192,9 @@ pub trait NymApiClientExt: ApiClient {
.await .await
} }
#[instrument(level = "debug", skip(self))]
async fn get_mixnode_report( async fn get_mixnode_report(
&self, &self,
mix_id: NodeId, mix_id: MixId,
) -> Result<MixnodeStatusReportResponse, NymAPIError> { ) -> Result<MixnodeStatusReportResponse, NymAPIError> {
self.get_json( self.get_json(
&[ &[
@@ -310,7 +209,6 @@ pub trait NymApiClientExt: ApiClient {
.await .await
} }
#[instrument(level = "debug", skip(self))]
async fn get_gateway_report( async fn get_gateway_report(
&self, &self,
identity: IdentityKeyRef<'_>, identity: IdentityKeyRef<'_>,
@@ -328,10 +226,9 @@ pub trait NymApiClientExt: ApiClient {
.await .await
} }
#[instrument(level = "debug", skip(self))]
async fn get_mixnode_history( async fn get_mixnode_history(
&self, &self,
mix_id: NodeId, mix_id: MixId,
) -> Result<MixnodeUptimeHistoryResponse, NymAPIError> { ) -> Result<MixnodeUptimeHistoryResponse, NymAPIError> {
self.get_json( self.get_json(
&[ &[
@@ -346,7 +243,6 @@ pub trait NymApiClientExt: ApiClient {
.await .await
} }
#[instrument(level = "debug", skip(self))]
async fn get_gateway_history( async fn get_gateway_history(
&self, &self,
identity: IdentityKeyRef<'_>, identity: IdentityKeyRef<'_>,
@@ -364,7 +260,6 @@ pub trait NymApiClientExt: ApiClient {
.await .await
} }
#[instrument(level = "debug", skip(self))]
async fn get_rewarded_mixnodes_detailed( async fn get_rewarded_mixnodes_detailed(
&self, &self,
) -> Result<Vec<MixNodeBondAnnotated>, NymAPIError> { ) -> Result<Vec<MixNodeBondAnnotated>, NymAPIError> {
@@ -381,7 +276,6 @@ pub trait NymApiClientExt: ApiClient {
.await .await
} }
#[instrument(level = "debug", skip(self))]
async fn get_gateway_core_status_count( async fn get_gateway_core_status_count(
&self, &self,
identity: IdentityKeyRef<'_>, identity: IdentityKeyRef<'_>,
@@ -413,10 +307,9 @@ pub trait NymApiClientExt: ApiClient {
} }
} }
#[instrument(level = "debug", skip(self))]
async fn get_mixnode_core_status_count( async fn get_mixnode_core_status_count(
&self, &self,
mix_id: NodeId, mix_id: MixId,
since: Option<i64>, since: Option<i64>,
) -> Result<MixnodeCoreStatusResponse, NymAPIError> { ) -> Result<MixnodeCoreStatusResponse, NymAPIError> {
if let Some(since) = since { if let Some(since) = since {
@@ -446,10 +339,9 @@ pub trait NymApiClientExt: ApiClient {
} }
} }
#[instrument(level = "debug", skip(self))]
async fn get_mixnode_status( async fn get_mixnode_status(
&self, &self,
mix_id: NodeId, mix_id: MixId,
) -> Result<MixnodeStatusResponse, NymAPIError> { ) -> Result<MixnodeStatusResponse, NymAPIError> {
self.get_json( self.get_json(
&[ &[
@@ -464,10 +356,9 @@ pub trait NymApiClientExt: ApiClient {
.await .await
} }
#[instrument(level = "debug", skip(self))]
async fn get_mixnode_reward_estimation( async fn get_mixnode_reward_estimation(
&self, &self,
mix_id: NodeId, mix_id: MixId,
) -> Result<RewardEstimationResponse, NymAPIError> { ) -> Result<RewardEstimationResponse, NymAPIError> {
self.get_json( self.get_json(
&[ &[
@@ -482,10 +373,9 @@ pub trait NymApiClientExt: ApiClient {
.await .await
} }
#[instrument(level = "debug", skip(self))]
async fn compute_mixnode_reward_estimation( async fn compute_mixnode_reward_estimation(
&self, &self,
mix_id: NodeId, mix_id: MixId,
request_body: &ComputeRewardEstParam, request_body: &ComputeRewardEstParam,
) -> Result<RewardEstimationResponse, NymAPIError> { ) -> Result<RewardEstimationResponse, NymAPIError> {
self.post_json( self.post_json(
@@ -502,10 +392,9 @@ pub trait NymApiClientExt: ApiClient {
.await .await
} }
#[instrument(level = "debug", skip(self))]
async fn get_mixnode_stake_saturation( async fn get_mixnode_stake_saturation(
&self, &self,
mix_id: NodeId, mix_id: MixId,
) -> Result<StakeSaturationResponse, NymAPIError> { ) -> Result<StakeSaturationResponse, NymAPIError> {
self.get_json( self.get_json(
&[ &[
@@ -520,10 +409,9 @@ pub trait NymApiClientExt: ApiClient {
.await .await
} }
#[instrument(level = "debug", skip(self))]
async fn get_mixnode_inclusion_probability( async fn get_mixnode_inclusion_probability(
&self, &self,
mix_id: NodeId, mix_id: MixId,
) -> Result<InclusionProbabilityResponse, NymAPIError> { ) -> Result<InclusionProbabilityResponse, NymAPIError> {
self.get_json( self.get_json(
&[ &[
@@ -538,24 +426,7 @@ pub trait NymApiClientExt: ApiClient {
.await .await
} }
#[instrument(level = "debug", skip(self))] async fn get_mixnode_avg_uptime(&self, mix_id: MixId) -> Result<UptimeResponse, NymAPIError> {
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
}
async fn get_mixnode_avg_uptime(&self, mix_id: NodeId) -> Result<UptimeResponse, NymAPIError> {
self.get_json( self.get_json(
&[ &[
routes::API_VERSION, routes::API_VERSION,
@@ -569,8 +440,7 @@ pub trait NymApiClientExt: ApiClient {
.await .await
} }
#[instrument(level = "debug", skip(self))] async fn get_mixnodes_blacklisted(&self) -> Result<Vec<MixId>, NymAPIError> {
async fn get_mixnodes_blacklisted(&self) -> Result<Vec<NodeId>, NymAPIError> {
self.get_json( self.get_json(
&[routes::API_VERSION, routes::MIXNODES, routes::BLACKLISTED], &[routes::API_VERSION, routes::MIXNODES, routes::BLACKLISTED],
NO_PARAMS, NO_PARAMS,
@@ -578,7 +448,6 @@ pub trait NymApiClientExt: ApiClient {
.await .await
} }
#[instrument(level = "debug", skip(self))]
async fn get_gateways_blacklisted(&self) -> Result<Vec<IdentityKey>, NymAPIError> { async fn get_gateways_blacklisted(&self) -> Result<Vec<IdentityKey>, NymAPIError> {
self.get_json( self.get_json(
&[routes::API_VERSION, routes::GATEWAYS, routes::BLACKLISTED], &[routes::API_VERSION, routes::GATEWAYS, routes::BLACKLISTED],
@@ -587,7 +456,6 @@ pub trait NymApiClientExt: ApiClient {
.await .await
} }
#[instrument(level = "debug", skip(self, request_body))]
async fn blind_sign( async fn blind_sign(
&self, &self,
request_body: &BlindSignRequestBody, request_body: &BlindSignRequestBody,
@@ -604,7 +472,6 @@ pub trait NymApiClientExt: ApiClient {
.await .await
} }
#[instrument(level = "debug", skip(self, request_body))]
async fn verify_ecash_ticket( async fn verify_ecash_ticket(
&self, &self,
request_body: &VerifyEcashTicketBody, request_body: &VerifyEcashTicketBody,
@@ -621,7 +488,6 @@ pub trait NymApiClientExt: ApiClient {
.await .await
} }
#[instrument(level = "debug", skip(self, request_body))]
async fn batch_redeem_ecash_tickets( async fn batch_redeem_ecash_tickets(
&self, &self,
request_body: &BatchRedeemTicketsBody, request_body: &BatchRedeemTicketsBody,
@@ -638,7 +504,6 @@ pub trait NymApiClientExt: ApiClient {
.await .await
} }
#[instrument(level = "debug", skip(self))]
async fn double_spending_filter_v1(&self) -> Result<SpentCredentialsResponse, NymAPIError> { async fn double_spending_filter_v1(&self) -> Result<SpentCredentialsResponse, NymAPIError> {
self.get_json( self.get_json(
&[ &[
@@ -651,7 +516,6 @@ pub trait NymApiClientExt: ApiClient {
.await .await
} }
#[instrument(level = "debug", skip(self))]
async fn partial_expiration_date_signatures( async fn partial_expiration_date_signatures(
&self, &self,
expiration_date: Option<Date>, expiration_date: Option<Date>,
@@ -675,7 +539,6 @@ pub trait NymApiClientExt: ApiClient {
.await .await
} }
#[instrument(level = "debug", skip(self))]
async fn partial_coin_indices_signatures( async fn partial_coin_indices_signatures(
&self, &self,
epoch_id: Option<EpochId>, epoch_id: Option<EpochId>,
@@ -696,7 +559,6 @@ pub trait NymApiClientExt: ApiClient {
.await .await
} }
#[instrument(level = "debug", skip(self))]
async fn global_expiration_date_signatures( async fn global_expiration_date_signatures(
&self, &self,
expiration_date: Option<Date>, expiration_date: Option<Date>,
@@ -720,7 +582,6 @@ pub trait NymApiClientExt: ApiClient {
.await .await
} }
#[instrument(level = "debug", skip(self))]
async fn global_coin_indices_signatures( async fn global_coin_indices_signatures(
&self, &self,
epoch_id: Option<EpochId>, epoch_id: Option<EpochId>,
@@ -741,7 +602,6 @@ pub trait NymApiClientExt: ApiClient {
.await .await
} }
#[instrument(level = "debug", skip(self))]
async fn master_verification_key( async fn master_verification_key(
&self, &self,
epoch_id: Option<EpochId>, epoch_id: Option<EpochId>,
@@ -761,7 +621,6 @@ pub trait NymApiClientExt: ApiClient {
.await .await
} }
#[instrument(level = "debug", skip(self))]
async fn epoch_credentials( async fn epoch_credentials(
&self, &self,
dkg_epoch: EpochId, dkg_epoch: EpochId,
@@ -778,7 +637,6 @@ pub trait NymApiClientExt: ApiClient {
.await .await
} }
#[instrument(level = "debug", skip(self))]
async fn issued_credential( async fn issued_credential(
&self, &self,
credential_id: i64, credential_id: i64,
@@ -795,7 +653,6 @@ pub trait NymApiClientExt: ApiClient {
.await .await
} }
#[instrument(level = "debug", skip(self))]
async fn issued_credentials( async fn issued_credentials(
&self, &self,
credential_ids: Vec<i64>, credential_ids: Vec<i64>,
@@ -38,7 +38,6 @@ pub mod ecash {
pub const STATUS_ROUTES: &str = "status"; pub const STATUS_ROUTES: &str = "status";
pub const MIXNODE: &str = "mixnode"; pub const MIXNODE: &str = "mixnode";
pub const GATEWAY: &str = "gateway"; pub const GATEWAY: &str = "gateway";
pub const NYM_NODES: &str = "nym-nodes";
pub const CORE_STATUS_COUNT: &str = "core-status-count"; pub const CORE_STATUS_COUNT: &str = "core-status-count";
pub const SINCE_ARG: &str = "since"; pub const SINCE_ARG: &str = "since";
@@ -53,6 +52,5 @@ pub const STAKE_SATURATION: &str = "stake-saturation";
pub const INCLUSION_CHANCE: &str = "inclusion-probability"; pub const INCLUSION_CHANCE: &str = "inclusion-probability";
pub const SUBMIT_GATEWAY: &str = "submit-gateway-monitoring-results"; pub const SUBMIT_GATEWAY: &str = "submit-gateway-monitoring-results";
pub const SUBMIT_NODE: &str = "submit-node-monitoring-results"; pub const SUBMIT_NODE: &str = "submit-node-monitoring-results";
pub const PERFORMANCE: &str = "performance";
pub const SERVICE_PROVIDERS: &str = "services"; pub const SERVICE_PROVIDERS: &str = "services";
@@ -8,9 +8,9 @@ use crate::nyxd::CosmWasmClient;
use async_trait::async_trait; use async_trait::async_trait;
use cosmrs::AccountId; use cosmrs::AccountId;
use cosmwasm_std::Addr; use cosmwasm_std::Addr;
use log::trace;
use nym_coconut_dkg_common::types::{ChunkIndex, NodeIndex, StateAdvanceResponse}; use nym_coconut_dkg_common::types::{ChunkIndex, NodeIndex, StateAdvanceResponse};
use serde::Deserialize; use serde::Deserialize;
use tracing::trace;
use nym_coconut_dkg_common::dealer::RegisteredDealerDetails; use nym_coconut_dkg_common::dealer::RegisteredDealerDetails;
pub use nym_coconut_dkg_common::{ pub use nym_coconut_dkg_common::{
@@ -8,33 +8,28 @@ use crate::nyxd::CosmWasmClient;
use async_trait::async_trait; use async_trait::async_trait;
use cosmrs::AccountId; use cosmrs::AccountId;
use nym_contracts_common::signing::Nonce; 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::{ use nym_mixnet_contract_common::{
delegation, delegation,
delegation::{NodeDelegationResponse, OwnerProxySubKey}, delegation::{MixNodeDelegationResponse, OwnerProxySubKey},
families::{Family, FamilyHead},
mixnode::{ mixnode::{
MixStakeSaturationResponse, MixnodeRewardingDetailsResponse, PagedMixnodesDetailsResponse, MixnodeRewardingDetailsResponse, PagedMixnodesDetailsResponse,
PagedUnbondedMixnodesResponse, UnbondedMixnodeResponse, PagedUnbondedMixnodesResponse, StakeSaturationResponse, UnbondedMixnodeResponse,
}, },
reward_params::{Performance, RewardingParams}, reward_params::{Performance, RewardingParams},
rewarding::{EstimatedCurrentEpochRewardResponse, PendingRewardResponse}, rewarding::{EstimatedCurrentEpochRewardResponse, PendingRewardResponse},
ContractBuildInformation, ContractState, ContractStateParams, CurrentIntervalResponse, ContractBuildInformation, ContractState, ContractStateParams, CurrentIntervalResponse,
Delegation, EpochEventId, EpochStatus, GatewayBond, GatewayBondResponse, Delegation, EpochEventId, EpochStatus, FamilyByHeadResponse, FamilyByLabelResponse,
GatewayOwnershipResponse, IdentityKey, IdentityKeyRef, IntervalEventId, MixNodeBond, FamilyMembersByHeadResponse, FamilyMembersByLabelResponse, GatewayBond, GatewayBondResponse,
MixNodeDetails, MixOwnershipResponse, MixnodeDetailsByIdentityResponse, MixnodeDetailsResponse, GatewayOwnershipResponse, IdentityKey, IdentityKeyRef, IntervalEventId, LayerDistribution,
NodeId, NumberOfPendingEventsResponse, NymNodeBond, NymNodeDetails, MixId, MixNodeBond, MixNodeDetails, MixOwnershipResponse, MixnodeDetailsByIdentityResponse,
PagedAllDelegationsResponse, PagedDelegatorDelegationsResponse, PagedGatewayResponse, MixnodeDetailsResponse, NumberOfPendingEventsResponse, PagedAllDelegationsResponse,
PagedMixnodeBondsResponse, PagedNodeDelegationsResponse, PendingEpochEvent, PagedDelegatorDelegationsResponse, PagedFamiliesResponse, PagedGatewayResponse,
PendingEpochEventResponse, PendingEpochEventsResponse, PendingIntervalEvent, PagedMembersResponse, PagedMixNodeDelegationsResponse, PagedMixnodeBondsResponse,
PendingIntervalEventResponse, PendingIntervalEventsResponse, QueryMsg as MixnetQueryMsg, PagedRewardedSetResponse, PendingEpochEvent, PendingEpochEventResponse,
RewardedSet, UnbondedMixnode, PendingEpochEventsResponse, PendingIntervalEvent, PendingIntervalEventResponse,
PendingIntervalEventsResponse, QueryMsg as MixnetQueryMsg, RewardedSetNodeStatus,
UnbondedMixnode,
}; };
use serde::Deserialize; use serde::Deserialize;
@@ -96,11 +91,56 @@ pub trait MixnetQueryClient {
.await .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: // mixnode-related:
async fn get_mixnode_bonds_paged( async fn get_mixnode_bonds_paged(
&self, &self,
start_after: Option<NodeId>, start_after: Option<MixId>,
limit: Option<u32>, limit: Option<u32>,
) -> Result<PagedMixnodeBondsResponse, NyxdError> { ) -> Result<PagedMixnodeBondsResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetMixNodeBonds { limit, start_after }) self.query_mixnet_contract(MixnetQueryMsg::GetMixNodeBonds { limit, start_after })
@@ -109,26 +149,26 @@ pub trait MixnetQueryClient {
async fn get_mixnodes_detailed_paged( async fn get_mixnodes_detailed_paged(
&self, &self,
start_after: Option<NodeId>, start_after: Option<MixId>,
limit: Option<u32>, limit: Option<u32>,
) -> Result<PagedMixnodesDetailsResponse, NyxdError> { ) -> Result<PagedMixnodesDetailsResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetMixNodesDetailed { limit, start_after }) self.query_mixnet_contract(MixnetQueryMsg::GetMixNodesDetailed { limit, start_after })
.await .await
} }
async fn get_unbonded_mixnodes_paged( async fn get_unbonded_paged(
&self, &self,
start_after: Option<NodeId>, start_after: Option<MixId>,
limit: Option<u32>, limit: Option<u32>,
) -> Result<PagedUnbondedMixnodesResponse, NyxdError> { ) -> Result<PagedUnbondedMixnodesResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetUnbondedMixNodes { limit, start_after }) self.query_mixnet_contract(MixnetQueryMsg::GetUnbondedMixNodes { limit, start_after })
.await .await
} }
async fn get_unbonded_mixnodes_by_owner_paged( async fn get_unbonded_by_owner_paged(
&self, &self,
owner: &AccountId, owner: &AccountId,
start_after: Option<NodeId>, start_after: Option<MixId>,
limit: Option<u32>, limit: Option<u32>,
) -> Result<PagedUnbondedMixnodesResponse, NyxdError> { ) -> Result<PagedUnbondedMixnodesResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetUnbondedMixNodesByOwner { self.query_mixnet_contract(MixnetQueryMsg::GetUnbondedMixNodesByOwner {
@@ -139,10 +179,10 @@ pub trait MixnetQueryClient {
.await .await
} }
async fn get_unbonded_mixnodes_by_identity_paged( async fn get_unbonded_by_identity_paged(
&self, &self,
identity_key: IdentityKeyRef<'_>, identity_key: IdentityKeyRef<'_>,
start_after: Option<NodeId>, start_after: Option<MixId>,
limit: Option<u32>, limit: Option<u32>,
) -> Result<PagedUnbondedMixnodesResponse, NyxdError> { ) -> Result<PagedUnbondedMixnodesResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetUnbondedMixNodesByIdentityKey { self.query_mixnet_contract(MixnetQueryMsg::GetUnbondedMixNodesByIdentityKey {
@@ -165,7 +205,7 @@ pub trait MixnetQueryClient {
async fn get_mixnode_details( async fn get_mixnode_details(
&self, &self,
mix_id: NodeId, mix_id: MixId,
) -> Result<MixnodeDetailsResponse, NyxdError> { ) -> Result<MixnodeDetailsResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetMixnodeDetails { mix_id }) self.query_mixnet_contract(MixnetQueryMsg::GetMixnodeDetails { mix_id })
.await .await
@@ -183,7 +223,7 @@ pub trait MixnetQueryClient {
async fn get_mixnode_rewarding_details( async fn get_mixnode_rewarding_details(
&self, &self,
mix_id: NodeId, mix_id: MixId,
) -> Result<MixnodeRewardingDetailsResponse, NyxdError> { ) -> Result<MixnodeRewardingDetailsResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetMixnodeRewardingDetails { mix_id }) self.query_mixnet_contract(MixnetQueryMsg::GetMixnodeRewardingDetails { mix_id })
.await .await
@@ -191,24 +231,24 @@ pub trait MixnetQueryClient {
async fn get_mixnode_stake_saturation( async fn get_mixnode_stake_saturation(
&self, &self,
mix_id: NodeId, mix_id: MixId,
) -> Result<MixStakeSaturationResponse, NyxdError> { ) -> Result<StakeSaturationResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetStakeSaturation { mix_id }) self.query_mixnet_contract(MixnetQueryMsg::GetStakeSaturation { mix_id })
.await .await
} }
async fn get_unbonded_mixnode_information( async fn get_unbonded_mixnode_information(
&self, &self,
mix_id: NodeId, mix_id: MixId,
) -> Result<UnbondedMixnodeResponse, NyxdError> { ) -> Result<UnbondedMixnodeResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetUnbondedMixNodeInformation { mix_id }) self.query_mixnet_contract(MixnetQueryMsg::GetUnbondedMixNodeInformation { mix_id })
.await .await
} }
// async fn get_layer_distribution(&self) -> Result<LayerDistribution, NyxdError> { async fn get_layer_distribution(&self) -> Result<LayerDistribution, NyxdError> {
// self.query_mixnet_contract(MixnetQueryMsg::GetRoleDistribution {}) self.query_mixnet_contract(MixnetQueryMsg::GetLayerDistribution {})
// .await .await
// } }
// gateway-related: // gateway-related:
@@ -241,142 +281,17 @@ pub trait MixnetQueryClient {
.await .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: // delegation-related:
/// Gets list of all delegations towards particular mixnode on particular page. /// Gets list of all delegations towards particular mixnode on particular page.
async fn get_mixnode_delegations_paged( async fn get_mixnode_delegations_paged(
&self, &self,
node_id: NodeId, mix_id: MixId,
start_after: Option<String>, start_after: Option<String>,
limit: Option<u32>, limit: Option<u32>,
) -> Result<PagedNodeDelegationsResponse, NyxdError> { ) -> Result<PagedMixNodeDelegationsResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetNodeDelegations { self.query_mixnet_contract(MixnetQueryMsg::GetMixnodeDelegations {
node_id, mix_id,
start_after, start_after,
limit, limit,
}) })
@@ -387,7 +302,7 @@ pub trait MixnetQueryClient {
async fn get_delegator_delegations_paged( async fn get_delegator_delegations_paged(
&self, &self,
delegator: &AccountId, delegator: &AccountId,
start_after: Option<(NodeId, OwnerProxySubKey)>, start_after: Option<(MixId, OwnerProxySubKey)>,
limit: Option<u32>, limit: Option<u32>,
) -> Result<PagedDelegatorDelegationsResponse, NyxdError> { ) -> Result<PagedDelegatorDelegationsResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetDelegatorDelegations { self.query_mixnet_contract(MixnetQueryMsg::GetDelegatorDelegations {
@@ -401,12 +316,12 @@ pub trait MixnetQueryClient {
/// Checks value of delegation of given client towards particular mixnode. /// Checks value of delegation of given client towards particular mixnode.
async fn get_delegation_details( async fn get_delegation_details(
&self, &self,
node_id: NodeId, mix_id: MixId,
delegator: &AccountId, delegator: &AccountId,
proxy: Option<String>, proxy: Option<String>,
) -> Result<NodeDelegationResponse, NyxdError> { ) -> Result<MixNodeDelegationResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetDelegationDetails { self.query_mixnet_contract(MixnetQueryMsg::GetDelegationDetails {
node_id, mix_id,
delegator: delegator.to_string(), delegator: delegator.to_string(),
proxy, proxy,
}) })
@@ -436,21 +351,21 @@ pub trait MixnetQueryClient {
async fn get_pending_mixnode_operator_reward( async fn get_pending_mixnode_operator_reward(
&self, &self,
node_id: NodeId, mix_id: MixId,
) -> Result<PendingRewardResponse, NyxdError> { ) -> Result<PendingRewardResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetPendingNodeOperatorReward { node_id }) self.query_mixnet_contract(MixnetQueryMsg::GetPendingMixNodeOperatorReward { mix_id })
.await .await
} }
async fn get_pending_delegator_reward( async fn get_pending_delegator_reward(
&self, &self,
delegator: &AccountId, delegator: &AccountId,
node_id: NodeId, mix_id: MixId,
proxy: Option<String>, proxy: Option<String>,
) -> Result<PendingRewardResponse, NyxdError> { ) -> Result<PendingRewardResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetPendingDelegatorReward { self.query_mixnet_contract(MixnetQueryMsg::GetPendingDelegatorReward {
address: delegator.to_string(), address: delegator.to_string(),
node_id, mix_id,
proxy, proxy,
}) })
.await .await
@@ -459,14 +374,12 @@ pub trait MixnetQueryClient {
// given the provided performance, estimate the reward at the end of the current epoch // given the provided performance, estimate the reward at the end of the current epoch
async fn get_estimated_current_epoch_operator_reward( async fn get_estimated_current_epoch_operator_reward(
&self, &self,
node_id: NodeId, mix_id: MixId,
estimated_performance: Performance, estimated_performance: Performance,
estimated_work: Option<WorkFactor>,
) -> Result<EstimatedCurrentEpochRewardResponse, NyxdError> { ) -> Result<EstimatedCurrentEpochRewardResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetEstimatedCurrentEpochOperatorReward { self.query_mixnet_contract(MixnetQueryMsg::GetEstimatedCurrentEpochOperatorReward {
node_id, mix_id,
estimated_performance, estimated_performance,
estimated_work,
}) })
.await .await
} }
@@ -475,15 +388,15 @@ pub trait MixnetQueryClient {
async fn get_estimated_current_epoch_delegator_reward( async fn get_estimated_current_epoch_delegator_reward(
&self, &self,
delegator: &AccountId, delegator: &AccountId,
node_id: NodeId, mix_id: MixId,
proxy: Option<String>,
estimated_performance: Performance, estimated_performance: Performance,
estimated_work: Option<WorkFactor>,
) -> Result<EstimatedCurrentEpochRewardResponse, NyxdError> { ) -> Result<EstimatedCurrentEpochRewardResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetEstimatedCurrentEpochDelegatorReward { self.query_mixnet_contract(MixnetQueryMsg::GetEstimatedCurrentEpochDelegatorReward {
address: delegator.to_string(), address: delegator.to_string(),
node_id, mix_id,
proxy,
estimated_performance, estimated_performance,
estimated_work,
}) })
.await .await
} }
@@ -537,6 +450,22 @@ pub trait MixnetQueryClient {
}) })
.await .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 // 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(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)] #[cfg_attr(not(target_arch = "wasm32"), async_trait)]
pub trait PagedMixnetQueryClient: MixnetQueryClient { pub trait PagedMixnetQueryClient: MixnetQueryClient {
async fn get_all_nymnode_bonds(&self) -> Result<Vec<NymNodeBond>, NyxdError> { async fn get_all_node_families(&self) -> Result<Vec<Family>, NyxdError> {
collect_paged!(self, get_nymnode_bonds_paged, nodes) collect_paged!(self, get_all_node_families_paged, families)
} }
async fn get_all_nymnodes_detailed(&self) -> Result<Vec<NymNodeDetails>, NyxdError> { async fn get_all_family_members(&self) -> Result<Vec<(IdentityKey, FamilyHead)>, NyxdError> {
collect_paged!(self, get_nymnodes_detailed_paged, nodes) collect_paged!(self, get_all_family_members_paged, members)
} }
async fn get_all_unbonded_nymnodes(&self) -> Result<Vec<UnbondedNymNode>, NyxdError> { async fn get_all_rewarded_set_mixnodes(
collect_paged!(self, get_unbonded_nymnodes_paged, nodes)
}
async fn get_all_unbonded_nymnodes_by_owner(
&self, &self,
owner: &AccountId, ) -> Result<Vec<(MixId, RewardedSetNodeStatus)>, NyxdError> {
) -> Result<Vec<UnbondedNymNode>, NyxdError> { collect_paged!(self, get_rewarded_set_paged, nodes)
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
)
} }
async fn get_all_mixnode_bonds(&self) -> Result<Vec<MixNodeBond>, NyxdError> { 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) collect_paged!(self, get_mixnodes_detailed_paged, nodes)
} }
async fn get_all_unbonded_mixnodes(&self) -> Result<Vec<(NodeId, UnbondedMixnode)>, NyxdError> { async fn get_all_unbonded_mixnodes(&self) -> Result<Vec<(MixId, UnbondedMixnode)>, NyxdError> {
collect_paged!(self, get_unbonded_mixnodes_paged, nodes) collect_paged!(self, get_unbonded_paged, nodes)
} }
async fn get_all_unbonded_mixnodes_by_owner( async fn get_all_unbonded_mixnodes_by_owner(
&self, &self,
owner: &AccountId, owner: &AccountId,
) -> Result<Vec<(NodeId, UnbondedMixnode)>, NyxdError> { ) -> Result<Vec<(MixId, UnbondedMixnode)>, NyxdError> {
collect_paged!(self, get_unbonded_mixnodes_by_owner_paged, nodes, owner) collect_paged!(self, get_unbonded_by_owner_paged, nodes, owner)
} }
async fn get_all_unbonded_mixnodes_by_identity( async fn get_all_unbonded_mixnodes_by_identity(
&self, &self,
identity_key: IdentityKeyRef<'_>, identity_key: IdentityKeyRef<'_>,
) -> Result<Vec<(NodeId, UnbondedMixnode)>, NyxdError> { ) -> Result<Vec<(MixId, UnbondedMixnode)>, NyxdError> {
collect_paged!( collect_paged!(self, get_unbonded_by_identity_paged, nodes, identity_key)
self,
get_unbonded_mixnodes_by_identity_paged,
nodes,
identity_key
)
} }
async fn get_all_gateways(&self) -> Result<Vec<GatewayBond>, NyxdError> { async fn get_all_gateways(&self) -> Result<Vec<GatewayBond>, NyxdError> {
collect_paged!(self, get_gateways_paged, nodes) 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( async fn get_all_single_mixnode_delegations(
&self, &self,
mix_id: NodeId, mix_id: MixId,
) -> Result<Vec<Delegation>, NyxdError> { ) -> Result<Vec<Delegation>, NyxdError> {
collect_paged!(self, get_mixnode_delegations_paged, delegations, mix_id) collect_paged!(self, get_mixnode_delegations_paged, delegations, mix_id)
} }
@@ -651,65 +554,6 @@ pub trait PagedMixnetQueryClient: MixnetQueryClient {
#[async_trait] #[async_trait]
impl<T> PagedMixnetQueryClient for T where T: MixnetQueryClient {} 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(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)] #[cfg_attr(not(target_arch = "wasm32"), async_trait)]
impl<C> MixnetQueryClient for C impl<C> MixnetQueryClient for C
@@ -741,6 +585,24 @@ mod tests {
) -> u32 { ) -> u32 {
match msg { match msg {
MixnetQueryMsg::Admin {} => client.admin().ignore(), 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::GetContractVersion {} => client.get_mixnet_contract_version().ignore(),
MixnetQueryMsg::GetCW2ContractVersion {} => { MixnetQueryMsg::GetCW2ContractVersion {} => {
client.get_mixnet_contract_cw2_version().ignore() client.get_mixnet_contract_cw2_version().ignore()
@@ -755,28 +617,31 @@ mod tests {
MixnetQueryMsg::GetCurrentIntervalDetails {} => { MixnetQueryMsg::GetCurrentIntervalDetails {} => {
client.get_current_interval_details().ignore() 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 } => { MixnetQueryMsg::GetMixNodeBonds { limit, start_after } => {
client.get_mixnode_bonds_paged(start_after, limit).ignore() client.get_mixnode_bonds_paged(start_after, limit).ignore()
} }
MixnetQueryMsg::GetMixNodesDetailed { limit, start_after } => client MixnetQueryMsg::GetMixNodesDetailed { limit, start_after } => client
.get_mixnodes_detailed_paged(start_after, limit) .get_mixnodes_detailed_paged(start_after, limit)
.ignore(), .ignore(),
MixnetQueryMsg::GetUnbondedMixNodes { limit, start_after } => client MixnetQueryMsg::GetUnbondedMixNodes { limit, start_after } => {
.get_unbonded_mixnodes_paged(start_after, limit) client.get_unbonded_paged(start_after, limit).ignore()
.ignore(), }
MixnetQueryMsg::GetUnbondedMixNodesByOwner { MixnetQueryMsg::GetUnbondedMixNodesByOwner {
owner, owner,
limit, limit,
start_after, start_after,
} => client } => 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(), .ignore(),
MixnetQueryMsg::GetUnbondedMixNodesByIdentityKey { MixnetQueryMsg::GetUnbondedMixNodesByIdentityKey {
identity_key, identity_key,
limit, limit,
start_after, start_after,
} => client } => client
.get_unbonded_mixnodes_by_identity_paged(&identity_key, start_after, limit) .get_unbonded_by_identity_paged(&identity_key, start_after, limit)
.ignore(), .ignore(),
MixnetQueryMsg::GetOwnedMixnode { address } => { MixnetQueryMsg::GetOwnedMixnode { address } => {
client.get_owned_mixnode(&address.parse().unwrap()).ignore() client.get_owned_mixnode(&address.parse().unwrap()).ignore()
@@ -796,6 +661,7 @@ mod tests {
MixnetQueryMsg::GetBondedMixnodeDetailsByIdentity { mix_identity } => client MixnetQueryMsg::GetBondedMixnodeDetailsByIdentity { mix_identity } => client
.get_mixnode_details_by_identity(mix_identity) .get_mixnode_details_by_identity(mix_identity)
.ignore(), .ignore(),
MixnetQueryMsg::GetLayerDistribution {} => client.get_layer_distribution().ignore(),
MixnetQueryMsg::GetGateways { start_after, limit } => { MixnetQueryMsg::GetGateways { start_after, limit } => {
client.get_gateways_paged(start_after, limit).ignore() client.get_gateways_paged(start_after, limit).ignore()
} }
@@ -805,8 +671,8 @@ mod tests {
MixnetQueryMsg::GetOwnedGateway { address } => { MixnetQueryMsg::GetOwnedGateway { address } => {
client.get_owned_gateway(&address.parse().unwrap()).ignore() client.get_owned_gateway(&address.parse().unwrap()).ignore()
} }
MixnetQueryMsg::GetNodeDelegations { MixnetQueryMsg::GetMixnodeDelegations {
node_id: mix_id, mix_id,
start_after, start_after,
limit, limit,
} => client } => client
@@ -820,7 +686,7 @@ mod tests {
.get_delegator_delegations_paged(&delegator.parse().unwrap(), start_after, limit) .get_delegator_delegations_paged(&delegator.parse().unwrap(), start_after, limit)
.ignore(), .ignore(),
MixnetQueryMsg::GetDelegationDetails { MixnetQueryMsg::GetDelegationDetails {
node_id: mix_id, mix_id,
delegator, delegator,
proxy, proxy,
} => client } => client
@@ -832,38 +698,33 @@ mod tests {
MixnetQueryMsg::GetPendingOperatorReward { address } => client MixnetQueryMsg::GetPendingOperatorReward { address } => client
.get_pending_operator_reward(&address.parse().unwrap()) .get_pending_operator_reward(&address.parse().unwrap())
.ignore(), .ignore(),
MixnetQueryMsg::GetPendingNodeOperatorReward { node_id: mix_id } => { MixnetQueryMsg::GetPendingMixNodeOperatorReward { mix_id } => {
client.get_pending_mixnode_operator_reward(mix_id).ignore() client.get_pending_mixnode_operator_reward(mix_id).ignore()
} }
MixnetQueryMsg::GetPendingDelegatorReward { MixnetQueryMsg::GetPendingDelegatorReward {
address, address,
node_id: mix_id, mix_id,
proxy, proxy,
} => client } => client
.get_pending_delegator_reward(&address.parse().unwrap(), mix_id, proxy) .get_pending_delegator_reward(&address.parse().unwrap(), mix_id, proxy)
.ignore(), .ignore(),
MixnetQueryMsg::GetEstimatedCurrentEpochOperatorReward { MixnetQueryMsg::GetEstimatedCurrentEpochOperatorReward {
node_id, mix_id,
estimated_performance, estimated_performance,
estimated_work,
} => client } => client
.get_estimated_current_epoch_operator_reward( .get_estimated_current_epoch_operator_reward(mix_id, estimated_performance)
node_id,
estimated_performance,
estimated_work,
)
.ignore(), .ignore(),
MixnetQueryMsg::GetEstimatedCurrentEpochDelegatorReward { MixnetQueryMsg::GetEstimatedCurrentEpochDelegatorReward {
address, address,
node_id, mix_id,
proxy,
estimated_performance, estimated_performance,
estimated_work,
} => client } => client
.get_estimated_current_epoch_delegator_reward( .get_estimated_current_epoch_delegator_reward(
&address.parse().unwrap(), &address.parse().unwrap(),
node_id, mix_id,
proxy,
estimated_performance, estimated_performance,
estimated_work,
) )
.ignore(), .ignore(),
MixnetQueryMsg::GetPendingEpochEvents { limit, start_after } => client MixnetQueryMsg::GetPendingEpochEvents { limit, start_after } => client
@@ -884,54 +745,6 @@ mod tests {
MixnetQueryMsg::GetSigningNonce { address } => { MixnetQueryMsg::GetSigningNonce { address } => {
client.get_signing_nonce(&address.parse().unwrap()).ignore() 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 async_trait::async_trait;
use cosmrs::AccountId; use cosmrs::AccountId;
use nym_contracts_common::signing::MessageSignature; 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::gateway::GatewayConfigUpdate;
use nym_mixnet_contract_common::mixnode::{MixNodeConfigUpdate, NodeCostParams}; use nym_mixnet_contract_common::mixnode::{MixNodeConfigUpdate, MixNodeCostParams};
use nym_mixnet_contract_common::nym_node::NodeConfigUpdate; use nym_mixnet_contract_common::reward_params::{IntervalRewardingParamsUpdate, Performance};
use nym_mixnet_contract_common::reward_params::{
ActiveSetUpdate, IntervalRewardingParamsUpdate, NodeRewardingParameters,
};
use nym_mixnet_contract_common::{ use nym_mixnet_contract_common::{
ContractStateParams, ExecuteMsg as MixnetExecuteMsg, Gateway, MixNode, NodeId, NymNode, ContractStateParams, ExecuteMsg as MixnetExecuteMsg, Gateway, Layer, LayerAssignment, MixId,
RoleAssignment, MixNode,
}; };
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))] #[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
@@ -72,14 +70,14 @@ pub trait MixnetSigningClient {
async fn update_active_set_size( async fn update_active_set_size(
&self, &self,
update: ActiveSetUpdate, active_set_size: u32,
force_immediately: bool, force_immediately: bool,
fee: Option<Fee>, fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> { ) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract( self.execute_mixnet_contract(
fee, fee,
MixnetExecuteMsg::UpdateActiveSetDistribution { MixnetExecuteMsg::UpdateActiveSetSize {
update, active_set_size,
force_immediately, force_immediately,
}, },
vec![], vec![],
@@ -128,6 +126,37 @@ pub trait MixnetSigningClient {
.await .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( async fn reconcile_epoch_events(
&self, &self,
limit: Option<u32>, limit: Option<u32>,
@@ -141,21 +170,126 @@ pub trait MixnetSigningClient {
.await .await
} }
async fn assign_roles( // family related
async fn create_family(
&self, &self,
assignment: RoleAssignment, label: String,
fee: Option<Fee>, fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> { ) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract(fee, MixnetExecuteMsg::AssignRoles { assignment }, vec![]) self.execute_mixnet_contract(fee, MixnetExecuteMsg::CreateFamily { label }, vec![])
.await .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: // mixnode-related:
async fn bond_mixnode( async fn bond_mixnode(
&self, &self,
mix_node: MixNode, mix_node: MixNode,
cost_params: NodeCostParams, cost_params: MixNodeCostParams,
owner_signature: MessageSignature, owner_signature: MessageSignature,
pledge: Coin, pledge: Coin,
fee: Option<Fee>, fee: Option<Fee>,
@@ -176,7 +310,7 @@ pub trait MixnetSigningClient {
&self, &self,
owner: AccountId, owner: AccountId,
mix_node: MixNode, mix_node: MixNode,
cost_params: NodeCostParams, cost_params: MixNodeCostParams,
owner_signature: MessageSignature, owner_signature: MessageSignature,
pledge: Coin, pledge: Coin,
fee: Option<Fee>, fee: Option<Fee>,
@@ -275,14 +409,14 @@ pub trait MixnetSigningClient {
.await .await
} }
async fn update_cost_params( async fn update_mixnode_cost_params(
&self, &self,
new_costs: NodeCostParams, new_costs: MixNodeCostParams,
fee: Option<Fee>, fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> { ) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract( self.execute_mixnet_contract(
fee, fee,
MixnetExecuteMsg::UpdateCostParams { new_costs }, MixnetExecuteMsg::UpdateMixnodeCostParams { new_costs },
vec![], vec![],
) )
.await .await
@@ -291,7 +425,7 @@ pub trait MixnetSigningClient {
async fn update_mixnode_cost_params_on_behalf( async fn update_mixnode_cost_params_on_behalf(
&self, &self,
owner: AccountId, owner: AccountId,
new_costs: NodeCostParams, new_costs: MixNodeCostParams,
fee: Option<Fee>, fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> { ) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract( self.execute_mixnet_contract(
@@ -425,75 +559,26 @@ pub trait MixnetSigningClient {
.await .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: // delegation-related:
async fn delegate( async fn delegate_to_mixnode(
&self, &self,
node_id: NodeId, mix_id: MixId,
amount: Coin, amount: Coin,
fee: Option<Fee>, fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> { ) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract(fee, MixnetExecuteMsg::Delegate { node_id }, vec![amount]) self.execute_mixnet_contract(
.await fee,
MixnetExecuteMsg::DelegateToMixnode { mix_id },
vec![amount],
)
.await
} }
async fn delegate_to_mixnode_on_behalf( async fn delegate_to_mixnode_on_behalf(
&self, &self,
delegate: AccountId, delegate: AccountId,
mix_id: NodeId, mix_id: MixId,
amount: Coin, amount: Coin,
fee: Option<Fee>, fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> { ) -> Result<ExecuteResult, NyxdError> {
@@ -508,19 +593,23 @@ pub trait MixnetSigningClient {
.await .await
} }
async fn undelegate( async fn undelegate_from_mixnode(
&self, &self,
node_id: NodeId, mix_id: MixId,
fee: Option<Fee>, fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> { ) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract(fee, MixnetExecuteMsg::Undelegate { node_id }, vec![]) self.execute_mixnet_contract(
.await fee,
MixnetExecuteMsg::UndelegateFromMixnode { mix_id },
vec![],
)
.await
} }
async fn undelegate_to_mixnode_on_behalf( async fn undelegate_to_mixnode_on_behalf(
&self, &self,
delegate: AccountId, delegate: AccountId,
mix_id: NodeId, mix_id: MixId,
fee: Option<Fee>, fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> { ) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract( self.execute_mixnet_contract(
@@ -536,15 +625,18 @@ pub trait MixnetSigningClient {
// reward-related // reward-related
async fn reward_node( async fn reward_mixnode(
&self, &self,
node_id: NodeId, mix_id: MixId,
params: NodeRewardingParameters, performance: Performance,
fee: Option<Fee>, fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> { ) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract( self.execute_mixnet_contract(
fee, fee,
MixnetExecuteMsg::RewardNode { node_id, params }, MixnetExecuteMsg::RewardMixnode {
mix_id,
performance,
},
vec![], vec![],
) )
.await .await
@@ -572,12 +664,12 @@ pub trait MixnetSigningClient {
async fn withdraw_delegator_reward( async fn withdraw_delegator_reward(
&self, &self,
node_id: NodeId, mix_id: MixId,
fee: Option<Fee>, fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> { ) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract( self.execute_mixnet_contract(
fee, fee,
MixnetExecuteMsg::WithdrawDelegatorReward { node_id }, MixnetExecuteMsg::WithdrawDelegatorReward { mix_id },
vec![], vec![],
) )
.await .await
@@ -586,7 +678,7 @@ pub trait MixnetSigningClient {
async fn withdraw_delegator_reward_on_behalf( async fn withdraw_delegator_reward_on_behalf(
&self, &self,
owner: AccountId, owner: AccountId,
mix_id: NodeId, mix_id: MixId,
fee: Option<Fee>, fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> { ) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract( self.execute_mixnet_contract(
@@ -607,7 +699,7 @@ pub trait MixnetSigningClient {
async fn migrate_vested_delegation( async fn migrate_vested_delegation(
&self, &self,
mix_id: NodeId, mix_id: MixId,
fee: Option<Fee>, fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> { ) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract( self.execute_mixnet_contract(
@@ -669,7 +761,6 @@ where
mod tests { mod tests {
use super::*; use super::*;
use crate::nyxd::contract_traits::tests::{mock_coin, IgnoreValue}; 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 // it's enough that this compiles and clippy is happy about it
#[allow(dead_code)] #[allow(dead_code)]
@@ -679,17 +770,56 @@ mod tests {
) { ) {
match msg { match msg {
MixnetExecuteMsg::UpdateAdmin { admin } => client.update_admin(admin, None).ignore(), 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 MixnetExecuteMsg::UpdateRewardingValidatorAddress { address } => client
.update_rewarding_validator_address(address.parse().unwrap(), None) .update_rewarding_validator_address(address.parse().unwrap(), None)
.ignore(), .ignore(),
MixnetExecuteMsg::UpdateContractStateParams { updated_parameters } => client MixnetExecuteMsg::UpdateContractStateParams { updated_parameters } => client
.update_contract_state_params(updated_parameters, None) .update_contract_state_params(updated_parameters, None)
.ignore(), .ignore(),
MixnetExecuteMsg::UpdateActiveSetDistribution { MixnetExecuteMsg::UpdateActiveSetSize {
update, active_set_size,
force_immediately, force_immediately,
} => client } => client
.update_active_set_size(update, force_immediately, None) .update_active_set_size(active_set_size, force_immediately, None)
.ignore(), .ignore(),
MixnetExecuteMsg::UpdateRewardingParams { MixnetExecuteMsg::UpdateRewardingParams {
updated_params, updated_params,
@@ -712,6 +842,12 @@ mod tests {
MixnetExecuteMsg::BeginEpochTransition {} => { MixnetExecuteMsg::BeginEpochTransition {} => {
client.begin_epoch_transition(None).ignore() 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 } => { MixnetExecuteMsg::ReconcileEpochEvents { limit } => {
client.reconcile_epoch_events(limit, None).ignore() client.reconcile_epoch_events(limit, None).ignore()
} }
@@ -751,8 +887,8 @@ mod tests {
MixnetExecuteMsg::UnbondMixnodeOnBehalf { owner } => client MixnetExecuteMsg::UnbondMixnodeOnBehalf { owner } => client
.unbond_mixnode_on_behalf(owner.parse().unwrap(), None) .unbond_mixnode_on_behalf(owner.parse().unwrap(), None)
.ignore(), .ignore(),
MixnetExecuteMsg::UpdateCostParams { new_costs } => { MixnetExecuteMsg::UpdateMixnodeCostParams { new_costs } => {
client.update_cost_params(new_costs, None).ignore() client.update_mixnode_cost_params(new_costs, None).ignore()
} }
MixnetExecuteMsg::UpdateMixnodeCostParamsOnBehalf { new_costs, owner } => client MixnetExecuteMsg::UpdateMixnodeCostParamsOnBehalf { new_costs, owner } => client
.update_mixnode_cost_params_on_behalf(owner.parse().unwrap(), new_costs, None) .update_mixnode_cost_params_on_behalf(owner.parse().unwrap(), new_costs, None)
@@ -792,28 +928,29 @@ mod tests {
MixnetExecuteMsg::UpdateGatewayConfigOnBehalf { new_config, owner } => client MixnetExecuteMsg::UpdateGatewayConfigOnBehalf { new_config, owner } => client
.update_gateway_config_on_behalf(owner.parse().unwrap(), new_config, None) .update_gateway_config_on_behalf(owner.parse().unwrap(), new_config, None)
.ignore(), .ignore(),
MixnetExecuteMsg::Delegate { node_id: mix_id } => { MixnetExecuteMsg::DelegateToMixnode { mix_id } => client
client.delegate(mix_id, mock_coin(), None).ignore() .delegate_to_mixnode(mix_id, mock_coin(), None)
} .ignore(),
MixnetExecuteMsg::DelegateToMixnodeOnBehalf { mix_id, delegate } => client MixnetExecuteMsg::DelegateToMixnodeOnBehalf { mix_id, delegate } => client
.delegate_to_mixnode_on_behalf(delegate.parse().unwrap(), mix_id, mock_coin(), None) .delegate_to_mixnode_on_behalf(delegate.parse().unwrap(), mix_id, mock_coin(), None)
.ignore(), .ignore(),
MixnetExecuteMsg::Undelegate { node_id: mix_id } => { MixnetExecuteMsg::UndelegateFromMixnode { mix_id } => {
client.undelegate(mix_id, None).ignore() client.undelegate_from_mixnode(mix_id, None).ignore()
} }
MixnetExecuteMsg::UndelegateFromMixnodeOnBehalf { mix_id, delegate } => client MixnetExecuteMsg::UndelegateFromMixnodeOnBehalf { mix_id, delegate } => client
.undelegate_to_mixnode_on_behalf(delegate.parse().unwrap(), mix_id, None) .undelegate_to_mixnode_on_behalf(delegate.parse().unwrap(), mix_id, None)
.ignore(), .ignore(),
MixnetExecuteMsg::RewardNode { node_id, params } => { MixnetExecuteMsg::RewardMixnode {
client.reward_node(node_id, params, None).ignore() mix_id,
} performance,
} => client.reward_mixnode(mix_id, performance, None).ignore(),
MixnetExecuteMsg::WithdrawOperatorReward {} => { MixnetExecuteMsg::WithdrawOperatorReward {} => {
client.withdraw_operator_reward(None).ignore() client.withdraw_operator_reward(None).ignore()
} }
MixnetExecuteMsg::WithdrawOperatorRewardOnBehalf { owner } => client MixnetExecuteMsg::WithdrawOperatorRewardOnBehalf { owner } => client
.withdraw_operator_reward_on_behalf(owner.parse().unwrap(), None) .withdraw_operator_reward_on_behalf(owner.parse().unwrap(), None)
.ignore(), .ignore(),
MixnetExecuteMsg::WithdrawDelegatorReward { node_id: mix_id } => { MixnetExecuteMsg::WithdrawDelegatorReward { mix_id } => {
client.withdraw_delegator_reward(mix_id, None).ignore() client.withdraw_delegator_reward(mix_id, None).ignore()
} }
MixnetExecuteMsg::WithdrawDelegatorRewardOnBehalf { mix_id, owner } => client MixnetExecuteMsg::WithdrawDelegatorRewardOnBehalf { mix_id, owner } => client
@@ -826,25 +963,6 @@ mod tests {
client.migrate_vested_delegation(mix_id, None).ignore() 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")] #[cfg(feature = "contract-testing")]
MixnetExecuteMsg::TestingResolveAllPendingEvents { .. } => { MixnetExecuteMsg::TestingResolveAllPendingEvents { .. } => {
client.testing_resolve_all_pending_events(None).ignore() client.testing_resolve_all_pending_events(None).ignore()
@@ -9,7 +9,7 @@ use crate::nyxd::CosmWasmClient;
use async_trait::async_trait; use async_trait::async_trait;
use cosmwasm_std::{Coin as CosmWasmCoin, Timestamp}; use cosmwasm_std::{Coin as CosmWasmCoin, Timestamp};
use nym_contracts_common::ContractBuildInformation; use nym_contracts_common::ContractBuildInformation;
use nym_mixnet_contract_common::NodeId; use nym_mixnet_contract_common::MixId;
use nym_vesting_contract_common::{ use nym_vesting_contract_common::{
messages::QueryMsg as VestingQueryMsg, Account, AccountVestingCoins, AccountsResponse, messages::QueryMsg as VestingQueryMsg, Account, AccountVestingCoins, AccountsResponse,
AllDelegationsResponse, BaseVestingAccountInfo, DelegationTimesResponse, AllDelegationsResponse, BaseVestingAccountInfo, DelegationTimesResponse,
@@ -238,7 +238,7 @@ pub trait VestingQueryClient {
async fn get_vesting_delegation( async fn get_vesting_delegation(
&self, &self,
address: &str, address: &str,
mix_id: NodeId, mix_id: MixId,
block_timestamp_secs: u64, block_timestamp_secs: u64,
) -> Result<VestingDelegation, NyxdError> { ) -> Result<VestingDelegation, NyxdError> {
self.query_vesting_contract(VestingQueryMsg::GetDelegation { self.query_vesting_contract(VestingQueryMsg::GetDelegation {
@@ -252,7 +252,7 @@ pub trait VestingQueryClient {
async fn get_total_delegation_amount( async fn get_total_delegation_amount(
&self, &self,
address: &str, address: &str,
mix_id: NodeId, mix_id: MixId,
) -> Result<Coin, NyxdError> { ) -> Result<Coin, NyxdError> {
self.query_vesting_contract(VestingQueryMsg::GetTotalDelegationAmount { self.query_vesting_contract(VestingQueryMsg::GetTotalDelegationAmount {
address: address.to_string(), address: address.to_string(),
@@ -264,7 +264,7 @@ pub trait VestingQueryClient {
async fn get_delegation_timestamps( async fn get_delegation_timestamps(
&self, &self,
address: &str, address: &str,
mix_id: NodeId, mix_id: MixId,
) -> Result<DelegationTimesResponse, NyxdError> { ) -> Result<DelegationTimesResponse, NyxdError> {
self.query_vesting_contract(VestingQueryMsg::GetDelegationTimes { self.query_vesting_contract(VestingQueryMsg::GetDelegationTimes {
address: address.to_string(), address: address.to_string(),
@@ -275,7 +275,7 @@ pub trait VestingQueryClient {
async fn get_all_vesting_delegations_paged( async fn get_all_vesting_delegations_paged(
&self, &self,
start_after: Option<(u32, NodeId, u64)>, start_after: Option<(u32, MixId, u64)>,
limit: Option<u32>, limit: Option<u32>,
) -> Result<AllDelegationsResponse, NyxdError> { ) -> Result<AllDelegationsResponse, NyxdError> {
self.query_vesting_contract(VestingQueryMsg::GetAllDelegations { start_after, limit }) self.query_vesting_contract(VestingQueryMsg::GetAllDelegations { start_after, limit })
@@ -9,9 +9,10 @@ use crate::signing::signer::OfflineSigner;
use async_trait::async_trait; use async_trait::async_trait;
use cosmrs::AccountId; use cosmrs::AccountId;
use nym_contracts_common::signing::MessageSignature; 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::gateway::GatewayConfigUpdate;
use nym_mixnet_contract_common::mixnode::{MixNodeConfigUpdate, NodeCostParams}; use nym_mixnet_contract_common::mixnode::{MixNodeConfigUpdate, MixNodeCostParams};
use nym_mixnet_contract_common::{Gateway, MixNode, NodeId}; use nym_mixnet_contract_common::{Gateway, MixId, MixNode};
use nym_vesting_contract_common::messages::ExecuteMsg as VestingExecuteMsg; use nym_vesting_contract_common::messages::ExecuteMsg as VestingExecuteMsg;
use nym_vesting_contract_common::{PledgeCap, VestingSpecification}; use nym_vesting_contract_common::{PledgeCap, VestingSpecification};
@@ -27,7 +28,7 @@ pub trait VestingSigningClient {
async fn vesting_update_mixnode_cost_params( async fn vesting_update_mixnode_cost_params(
&self, &self,
new_costs: NodeCostParams, new_costs: MixNodeCostParams,
fee: Option<Fee>, fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> { ) -> Result<ExecuteResult, NyxdError> {
self.execute_vesting_contract( self.execute_vesting_contract(
@@ -123,7 +124,7 @@ pub trait VestingSigningClient {
async fn vesting_bond_mixnode( async fn vesting_bond_mixnode(
&self, &self,
mix_node: MixNode, mix_node: MixNode,
cost_params: NodeCostParams, cost_params: MixNodeCostParams,
owner_signature: MessageSignature, owner_signature: MessageSignature,
pledge: Coin, pledge: Coin,
fee: Option<Fee>, fee: Option<Fee>,
@@ -203,7 +204,7 @@ pub trait VestingSigningClient {
async fn vesting_track_undelegation( async fn vesting_track_undelegation(
&self, &self,
address: &str, address: &str,
mix_id: NodeId, mix_id: MixId,
amount: Coin, amount: Coin,
fee: Option<Fee>, fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> { ) -> Result<ExecuteResult, NyxdError> {
@@ -221,7 +222,7 @@ pub trait VestingSigningClient {
async fn vesting_delegate_to_mixnode( async fn vesting_delegate_to_mixnode(
&self, &self,
mix_id: NodeId, mix_id: MixId,
amount: Coin, amount: Coin,
on_behalf_of: Option<String>, on_behalf_of: Option<String>,
fee: Option<Fee>, fee: Option<Fee>,
@@ -240,7 +241,7 @@ pub trait VestingSigningClient {
async fn vesting_undelegate_from_mixnode( async fn vesting_undelegate_from_mixnode(
&self, &self,
mix_id: NodeId, mix_id: MixId,
on_behalf_of: Option<String>, on_behalf_of: Option<String>,
fee: Option<Fee>, fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> { ) -> Result<ExecuteResult, NyxdError> {
@@ -300,7 +301,7 @@ pub trait VestingSigningClient {
async fn vesting_withdraw_delegator_reward( async fn vesting_withdraw_delegator_reward(
&self, &self,
mix_id: NodeId, mix_id: MixId,
fee: Option<Fee>, fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> { ) -> Result<ExecuteResult, NyxdError> {
self.execute_vesting_contract( self.execute_vesting_contract(
@@ -353,6 +354,50 @@ pub trait VestingSigningClient {
) )
.await .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))] #[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
@@ -401,6 +446,21 @@ mod tests {
msg: VestingExecuteMsg, msg: VestingExecuteMsg,
) { ) {
match msg { 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 VestingExecuteMsg::TrackReward { amount, address } => client
.vesting_track_reward(amount.into(), address, None) .vesting_track_reward(amount.into(), address, None)
.ignore(), .ignore(),
@@ -153,13 +153,20 @@ pub trait CosmWasmClient: TendermintRpcClient {
let req = QueryAllBalancesRequest { let req = QueryAllBalancesRequest {
address: address.to_string(), address: address.to_string(),
pagination, pagination,
resolve_denom: false,
}; };
let mut res = self let mut res = self
.make_abci_query::<_, QueryAllBalancesResponse>(path.clone(), req) .make_abci_query::<_, QueryAllBalancesResponse>(path.clone(), req)
.await?; .await?;
let early_break = res.balances.is_empty();
raw_balances.append(&mut res.balances); raw_balances.append(&mut res.balances);
if early_break {
break;
}
if let Some(next_key) = next_page_key(res.pagination) { if let Some(next_key) = next_page_key(res.pagination) {
pagination = Some(create_pagination(next_key)) pagination = Some(create_pagination(next_key))
} else { } else {
@@ -187,7 +194,13 @@ pub trait CosmWasmClient: TendermintRpcClient {
.make_abci_query::<_, QueryTotalSupplyResponse>(path.clone(), req) .make_abci_query::<_, QueryTotalSupplyResponse>(path.clone(), req)
.await?; .await?;
let early_break = res.supply.is_empty();
supply.append(&mut res.supply); supply.append(&mut res.supply);
if early_break {
break;
}
if let Some(next_key) = next_page_key(res.pagination) { if let Some(next_key) = next_page_key(res.pagination) {
pagination = Some(create_pagination(next_key)) pagination = Some(create_pagination(next_key))
} else { } else {
@@ -328,7 +341,13 @@ pub trait CosmWasmClient: TendermintRpcClient {
.make_abci_query::<_, QueryCodesResponse>(path.clone(), req) .make_abci_query::<_, QueryCodesResponse>(path.clone(), req)
.await?; .await?;
let early_break = res.code_infos.is_empty();
raw_codes.append(&mut res.code_infos); raw_codes.append(&mut res.code_infos);
if early_break {
break;
}
if let Some(next_key) = next_page_key(res.pagination) { if let Some(next_key) = next_page_key(res.pagination) {
pagination = Some(create_pagination(next_key)) pagination = Some(create_pagination(next_key))
} else { } else {
@@ -373,7 +392,13 @@ pub trait CosmWasmClient: TendermintRpcClient {
.make_abci_query::<_, QueryContractsByCodeResponse>(path.clone(), req) .make_abci_query::<_, QueryContractsByCodeResponse>(path.clone(), req)
.await?; .await?;
let early_break = res.contracts.is_empty();
raw_contracts.append(&mut res.contracts); raw_contracts.append(&mut res.contracts);
if early_break {
break;
}
if let Some(next_key) = next_page_key(res.pagination) { if let Some(next_key) = next_page_key(res.pagination) {
pagination = Some(create_pagination(next_key)) pagination = Some(create_pagination(next_key))
} else { } else {
@@ -429,7 +454,13 @@ pub trait CosmWasmClient: TendermintRpcClient {
.make_abci_query::<_, QueryContractHistoryResponse>(path.clone(), req) .make_abci_query::<_, QueryContractHistoryResponse>(path.clone(), req)
.await?; .await?;
let early_break = res.entries.is_empty();
raw_entries.append(&mut res.entries); raw_entries.append(&mut res.entries);
if early_break {
break;
}
if let Some(next_key) = next_page_key(res.pagination) { if let Some(next_key) = next_page_key(res.pagination) {
pagination = Some(create_pagination(next_key)) pagination = Some(create_pagination(next_key))
} else { } else {
@@ -25,12 +25,12 @@ use cosmrs::proto::cosmos::tx::signing::v1beta1::SignMode;
use cosmrs::staking::{MsgDelegate, MsgUndelegate}; use cosmrs::staking::{MsgDelegate, MsgUndelegate};
use cosmrs::tx::{self, Msg}; use cosmrs::tx::{self, Msg};
use cosmrs::{cosmwasm, AccountId, Any, Tx}; use cosmrs::{cosmwasm, AccountId, Any, Tx};
use log::debug;
use serde::Serialize; use serde::Serialize;
use sha2::Digest; use sha2::Digest;
use sha2::Sha256; use sha2::Sha256;
use std::time::SystemTime; use std::time::SystemTime;
use tendermint_rpc::endpoint::broadcast; use tendermint_rpc::endpoint::broadcast;
use tracing::debug;
fn empty_fee() -> tx::Fee { fn empty_fee() -> tx::Fee {
tx::Fee { tx::Fee {
@@ -7,9 +7,9 @@ use base64::Engine;
use cosmrs::abci::TxMsgData; use cosmrs::abci::TxMsgData;
use cosmrs::cosmwasm::MsgExecuteContractResponse; use cosmrs::cosmwasm::MsgExecuteContractResponse;
use cosmrs::proto::cosmos::base::query::v1beta1::{PageRequest, PageResponse}; use cosmrs::proto::cosmos::base::query::v1beta1::{PageRequest, PageResponse};
use log::error;
use prost::bytes::Bytes; use prost::bytes::Bytes;
use tendermint_rpc::endpoint::broadcast; use tendermint_rpc::endpoint::broadcast;
use tracing::error;
pub use cosmrs::abci::MsgResponse; 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")] #[error("the response data has invalid size. got {got} bytes, but expected {expected} bytes instead")]
MalformedResponseData { got: usize, expected: usize }, 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 // The purpose of parsing the abci query result is that we want to generate the `pretty_log` if
@@ -4,9 +4,11 @@
use crate::rpc::TendermintRpcClient; use crate::rpc::TendermintRpcClient;
use async_trait::async_trait; use async_trait::async_trait;
use base64::Engine; use base64::Engine;
use cosmrs::tendermint;
use cosmrs::tendermint::{block::Height, evidence::Evidence, Hash}; use cosmrs::tendermint::{block::Height, evidence::Evidence, Hash};
use reqwest::header::HeaderMap; use reqwest::header::HeaderMap;
use reqwest::{header, RequestBuilder}; use reqwest::{header, RequestBuilder};
use tendermint_rpc::dialect::{v0_34, v0_37, v0_38, LatestDialect};
use tendermint_rpc::{ use tendermint_rpc::{
client::CompatMode, client::CompatMode,
dialect::{self, Dialect}, dialect::{self, Dialect},
@@ -21,8 +23,21 @@ macro_rules! perform_with_compat {
($self:expr, $request:expr) => {{ ($self:expr, $request:expr) => {{
let request = $request; let request = $request;
match $self.compat { match $self.compat {
CompatMode::V0_37 => $self.perform_v0_37(request).await, CompatMode::V0_38 => {
CompatMode::V0_34 => $self.perform_v0_34(request).await, $self
.perform_request_with_dialect(request, dialect::v0_38::Dialect)
.await
}
CompatMode::V0_37 => {
$self
.perform_request_with_dialect(request, dialect::v0_37::Dialect)
.await
}
CompatMode::V0_34 => {
$self
.perform_request_with_dialect(request, dialect::v0_34::Dialect)
.await
}
} }
}}; }};
} }
@@ -70,7 +85,11 @@ impl ReqwestRpcClient {
.headers(headers) .headers(headers)
} }
async fn perform_request<R, S>(&self, request: R) -> Result<R::Output, Error> async fn perform_request_with_dialect<R, S>(
&self,
request: R,
_dialect: S,
) -> Result<R::Output, Error>
where where
R: SimpleRequest<S>, R: SimpleRequest<S>,
S: Dialect, S: Dialect,
@@ -81,26 +100,25 @@ impl ReqwestRpcClient {
.send() .send()
.await .await
.map_err(TendermintRpcErrorMap::into_rpc_err)?; .map_err(TendermintRpcErrorMap::into_rpc_err)?;
let response_status = response.status();
let bytes = response let bytes = response
.bytes() .bytes()
.await .await
.map_err(TendermintRpcErrorMap::into_rpc_err)?; .map_err(TendermintRpcErrorMap::into_rpc_err)?;
// Successful JSON-RPC requests are expected to return a 200 OK HTTP status.
// Otherwise, this means that the HTTP request failed as a whole,
// as opposed to the JSON-RPC request returning an error,
// and we cannot expect the response body to be a valid JSON-RPC response.
if response_status != reqwest::StatusCode::OK {
// hehe, that's so nasty but we have to somehow convert between different versions of the same lib
return Err(Error::http_request_failed(
response_status.as_u16().try_into().unwrap(),
));
}
R::Response::from_string(bytes).map(Into::into) R::Response::from_string(bytes).map(Into::into)
} }
async fn perform_v0_34<R>(&self, request: R) -> Result<R::Output, Error>
where
R: SimpleRequest<dialect::v0_34::Dialect>,
{
self.perform_request(request).await
}
async fn perform_v0_37<R>(&self, request: R) -> Result<R::Output, Error>
where
R: SimpleRequest<dialect::v0_37::Dialect>,
{
self.perform_request(request).await
}
} }
trait TendermintRpcErrorMap { trait TendermintRpcErrorMap {
@@ -120,18 +138,50 @@ impl TendermintRpcClient for ReqwestRpcClient {
where where
R: SimpleRequest, R: SimpleRequest,
{ {
self.perform_request(request).await self.perform_request_with_dialect(request, LatestDialect)
.await
} }
async fn block_results<H>(&self, height: H) -> Result<block_results::Response, Error> async fn block<H>(&self, height: H) -> Result<endpoint::block::Response, Error>
where where
H: Into<Height> + Send, H: Into<Height> + Send,
{ {
perform_with_compat!(self, block_results::Request::new(height.into())) perform_with_compat!(self, endpoint::block::Request::new(height.into()))
} }
async fn latest_block_results(&self) -> Result<block_results::Response, Error> { async fn block_by_hash(
perform_with_compat!(self, block_results::Request::default()) &self,
hash: tendermint::Hash,
) -> Result<endpoint::block_by_hash::Response, Error> {
perform_with_compat!(self, endpoint::block_by_hash::Request::new(hash))
}
async fn latest_block(&self) -> Result<endpoint::block::Response, Error> {
perform_with_compat!(self, endpoint::block::Request::default())
}
async fn block_results<H>(&self, height: H) -> Result<endpoint::block_results::Response, Error>
where
H: Into<Height> + Send,
{
perform_with_compat!(self, endpoint::block_results::Request::new(height.into()))
}
async fn latest_block_results(&self) -> Result<endpoint::block_results::Response, Error> {
perform_with_compat!(self, endpoint::block_results::Request::default())
}
async fn block_search(
&self,
query: Query,
page: u32,
per_page: u8,
order: Order,
) -> Result<endpoint::block_search::Response, Error> {
perform_with_compat!(
self,
endpoint::block_search::Request::new(query, page, per_page, order)
)
} }
async fn header<H>(&self, height: H) -> Result<endpoint::header::Response, Error> async fn header<H>(&self, height: H) -> Result<endpoint::header::Response, Error>
@@ -140,11 +190,26 @@ impl TendermintRpcClient for ReqwestRpcClient {
{ {
let height = height.into(); let height = height.into();
match self.compat { match self.compat {
CompatMode::V0_37 => self.perform(endpoint::header::Request::new(height)).await, CompatMode::V0_38 => {
self.perform_request_with_dialect(
endpoint::header::Request::new(height),
v0_38::Dialect,
)
.await
}
CompatMode::V0_37 => {
self.perform_request_with_dialect(
endpoint::header::Request::new(height),
v0_37::Dialect,
)
.await
}
CompatMode::V0_34 => { CompatMode::V0_34 => {
// Back-fill with a request to /block endpoint and // Back-fill with a request to /block endpoint and
// taking just the header from the response. // taking just the header from the response.
let resp = self.perform_v0_34(block::Request::new(height)).await?; let resp = self
.perform_request_with_dialect(block::Request::new(height), v0_34::Dialect)
.await?;
Ok(resp.into()) Ok(resp.into())
} }
} }
@@ -152,12 +217,25 @@ impl TendermintRpcClient for ReqwestRpcClient {
async fn header_by_hash(&self, hash: Hash) -> Result<header_by_hash::Response, Error> { async fn header_by_hash(&self, hash: Hash) -> Result<header_by_hash::Response, Error> {
match self.compat { match self.compat {
CompatMode::V0_37 => self.perform(header_by_hash::Request::new(hash)).await, CompatMode::V0_38 => {
self.perform_request_with_dialect(
header_by_hash::Request::new(hash),
v0_38::Dialect,
)
.await
}
CompatMode::V0_37 => {
self.perform_request_with_dialect(
header_by_hash::Request::new(hash),
v0_37::Dialect,
)
.await
}
CompatMode::V0_34 => { CompatMode::V0_34 => {
// Back-fill with a request to /block_by_hash endpoint and // Back-fill with a request to /block_by_hash endpoint and
// taking just the header from the response. // taking just the header from the response.
let resp = self let resp = self
.perform_v0_34(block_by_hash::Request::new(hash)) .perform_request_with_dialect(block_by_hash::Request::new(hash), v0_34::Dialect)
.await?; .await?;
Ok(resp.into()) Ok(resp.into())
} }
@@ -167,8 +245,18 @@ impl TendermintRpcClient for ReqwestRpcClient {
/// `/broadcast_evidence`: broadcast an evidence. /// `/broadcast_evidence`: broadcast an evidence.
async fn broadcast_evidence(&self, e: Evidence) -> Result<evidence::Response, Error> { async fn broadcast_evidence(&self, e: Evidence) -> Result<evidence::Response, Error> {
match self.compat { match self.compat {
CompatMode::V0_37 => self.perform(evidence::Request::new(e)).await, CompatMode::V0_38 => {
CompatMode::V0_34 => self.perform_v0_34(evidence::Request::new(e)).await, self.perform_request_with_dialect(evidence::Request::new(e), v0_38::Dialect)
.await
}
CompatMode::V0_37 => {
self.perform_request_with_dialect(evidence::Request::new(e), v0_37::Dialect)
.await
}
CompatMode::V0_34 => {
self.perform_request_with_dialect(evidence::Request::new(e), v0_34::Dialect)
.await
}
} }
} }
+1 -6
View File
@@ -9,15 +9,10 @@ use comfy_table::Table;
use nym_credential_storage::initialise_persistent_storage; use nym_credential_storage::initialise_persistent_storage;
use nym_credential_storage::storage::Storage; use nym_credential_storage::storage::Storage;
use nym_credentials::ecash::bandwidth::serialiser::VersionedSerialise; use nym_credentials::ecash::bandwidth::serialiser::VersionedSerialise;
use nym_credentials_interface::TicketType;
use std::path::PathBuf; use std::path::PathBuf;
#[derive(Debug, Parser)] #[derive(Debug, Parser)]
pub struct Args { pub struct Args {
/// Specify which type of ticketbook
#[clap(long, default_value_t = TicketType::V1MixnetEntry)]
pub(crate) ticketbook_type: TicketType,
/// Specify the index of the ticket to retrieve from the ticketbook. /// Specify the index of the ticket to retrieve from the ticketbook.
/// By default, the current unspent value is used. /// By default, the current unspent value is used.
#[clap(long, group = "output")] #[clap(long, group = "output")]
@@ -67,7 +62,7 @@ pub async fn execute(args: Args) -> anyhow::Result<()> {
let persistent_storage = initialise_persistent_storage(&credentials_store).await; let persistent_storage = initialise_persistent_storage(&credentials_store).await;
let Some(mut next_ticketbook) = persistent_storage let Some(mut next_ticketbook) = persistent_storage
.get_next_unspent_usable_ticketbook(args.ticketbook_type.to_string(), 0) .get_next_unspent_usable_ticketbook(0)
.await? .await?
else { else {
bail!( bail!(
@@ -1,6 +1,8 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net> // Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
use crate::utils::CommonConfigsWrapper;
use anyhow::bail;
use clap::ArgGroup; use clap::ArgGroup;
use clap::Parser; use clap::Parser;
use nym_credential_storage::initialise_persistent_storage; use nym_credential_storage::initialise_persistent_storage;
@@ -29,7 +31,7 @@ impl FromStr for CredentialDataWrapper {
pub struct Args { pub struct Args {
/// Config file of the client that is supposed to use the credential. /// Config file of the client that is supposed to use the credential.
#[clap(long)] #[clap(long)]
pub(crate) credentials_store: PathBuf, pub(crate) client_config: PathBuf,
/// Explicitly provide the encoded credential data (as base58) /// Explicitly provide the encoded credential data (as base58)
#[clap(long, group = "cred_data")] #[clap(long, group = "cred_data")]
@@ -68,7 +70,21 @@ impl Args {
} }
pub async fn execute(args: Args) -> anyhow::Result<()> { pub async fn execute(args: Args) -> anyhow::Result<()> {
let credentials_store = initialise_persistent_storage(args.credentials_store.clone()).await; let loaded = CommonConfigsWrapper::try_load(&args.client_config)?;
if let Ok(id) = loaded.try_get_id() {
println!("loaded config file for client '{id}'");
}
let Ok(credentials_store) = loaded.try_get_credentials_store() else {
bail!("the loaded config does not have a credentials store information")
};
println!(
"using credentials store at '{}'",
credentials_store.display()
);
let credentials_store = initialise_persistent_storage(credentials_store).await;
let version = args.version; let version = args.version;
let standalone = args.standalone; let standalone = args.standalone;
@@ -107,7 +107,7 @@ async fn issue_to_file(args: Args, client: SigningClient) -> anyhow::Result<()>
utils::issue_credential(&client, &credentials_store, &secret, args.ticketbook_type).await?; utils::issue_credential(&client, &credentials_store, &secret, args.ticketbook_type).await?;
let ticketbook = credentials_store let ticketbook = credentials_store
.get_next_unspent_usable_ticketbook(args.ticketbook_type.to_string(), 0) .get_next_unspent_usable_ticketbook(0)
.await? .await?
.ok_or(anyhow!("we just issued a ticketbook, it must be present!"))? .ok_or(anyhow!("we just issued a ticketbook, it must be present!"))?
.ticketbook; .ticketbook;
@@ -4,7 +4,6 @@
use clap::Parser; use clap::Parser;
use cosmwasm_std::Decimal; use cosmwasm_std::Decimal;
use log::{debug, info}; use log::{debug, info};
use nym_mixnet_contract_common::reward_params::RewardedSetParams;
use nym_mixnet_contract_common::{ use nym_mixnet_contract_common::{
InitialRewardingParams, InstantiateMsg, OperatingCostRange, Percent, ProfitMarginRange, InitialRewardingParams, InstantiateMsg, OperatingCostRange, Percent, ProfitMarginRange,
}; };
@@ -57,17 +56,11 @@ pub struct Args {
#[clap(long, default_value_t = 2)] #[clap(long, default_value_t = 2)]
pub interval_pool_emission: u64, pub interval_pool_emission: u64,
#[clap(long, default_value_t = 50)] #[clap(long, default_value_t = 240)]
pub(crate) entry_gateways: u32, pub rewarded_set_size: u32,
#[clap(long, default_value_t = 70)] #[clap(long, default_value_t = 240)]
pub(crate) exit_gateways: u32, pub active_set_size: 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 = Percent::zero())] #[clap(long, default_value_t = Percent::zero())]
pub minimum_profit_margin_percent: Percent, 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"), .expect("active_set_work_factor can't be converted to Decimal"),
interval_pool_emission: Percent::from_percentage_value(args.interval_pool_emission) interval_pool_emission: Percent::from_percentage_value(args.interval_pool_emission)
.expect("interval_pool_emission can't be converted to Percent"), .expect("interval_pool_emission can't be converted to Percent"),
rewarded_set_size: args.rewarded_set_size,
rewarded_set_params: RewardedSetParams { active_set_size: args.active_set_size,
entry_gateways: args.entry_gateways,
exit_gateways: args.exit_gateways,
mixnodes: args.mixnodes,
standby: args.standby,
},
}; };
debug!("initial_rewarding_params: {:?}", initial_rewarding_params); debug!("initial_rewarding_params: {:?}", initial_rewarding_params);
@@ -7,14 +7,13 @@ pub mod execute_contract;
pub mod generators; pub mod generators;
pub mod init_contract; pub mod init_contract;
pub mod migrate_contract; pub mod migrate_contract;
pub mod raw_contract_state;
pub mod upload_contract; pub mod upload_contract;
#[derive(Debug, Args)] #[derive(Debug, Args)]
#[clap(args_conflicts_with_subcommands = true, subcommand_required = true)] #[clap(args_conflicts_with_subcommands = true, subcommand_required = true)]
pub struct Cosmwasm { pub struct Cosmwasm {
#[clap(subcommand)] #[clap(subcommand)]
pub command: CosmwasmCommands, pub command: Option<CosmwasmCommands>,
} }
#[derive(Debug, Subcommand)] #[derive(Debug, Subcommand)]
@@ -29,6 +28,4 @@ pub enum CosmwasmCommands {
Migrate(crate::validator::cosmwasm::migrate_contract::Args), Migrate(crate::validator::cosmwasm::migrate_contract::Args),
/// Execute a WASM smart contract method /// Execute a WASM smart contract method
Execute(crate::validator::cosmwasm::execute_contract::Args), Execute(crate::validator::cosmwasm::execute_contract::Args),
/// Obtain raw contract state of a cosmwasm smart contract
RawContractState(crate::validator::cosmwasm::raw_contract_state::Args),
} }
@@ -1,39 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::context::QueryClient;
use clap::Parser;
use cosmrs::AccountId;
use log::trace;
use nym_validator_client::nyxd::CosmWasmClient;
use std::fs;
use std::fs::File;
use std::path::PathBuf;
#[derive(Debug, Parser)]
pub struct Args {
#[clap(long, value_parser)]
#[clap(help = "The address of contract to get the state of")]
pub contract: AccountId,
#[clap(short, long)]
#[clap(help = "Output file for the retrieved contract state")]
pub output: PathBuf,
}
pub async fn execute(args: Args, client: QueryClient) -> anyhow::Result<()> {
trace!("args: {args:?}");
let output = File::create(&args.output)?;
let raw = client.query_all_contract_state(&args.contract).await?;
serde_json::to_writer(output, &raw)?;
println!(
"wrote {} key-value from {} pairs into '{}'",
raw.len(),
args.contract,
fs::canonicalize(args.output)?.display()
);
Ok(())
}
@@ -4,13 +4,13 @@
use crate::context::SigningClient; use crate::context::SigningClient;
use clap::Parser; use clap::Parser;
use log::info; 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}; use nym_validator_client::nyxd::contract_traits::{MixnetQueryClient, MixnetSigningClient};
#[derive(Debug, Parser)] #[derive(Debug, Parser)]
pub struct Args { pub struct Args {
#[clap(long)] #[clap(long)]
pub mix_id: Option<NodeId>, pub mix_id: Option<MixId>,
#[clap(long)] #[clap(long)]
pub identity_key: Option<String>, 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 coin = Coin::new(args.amount, denom);
let res = client let res = client
.delegate(mix_id, coin.into(), None) .delegate_to_mixnode(mix_id, coin.into(), None)
.await .await
.expect("failed to delegate to mixnode!"); .expect("failed to delegate to mixnode!");
@@ -1,18 +1,21 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net> // Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
use std::cmp::Ordering;
use std::collections::{HashMap, HashSet};
use std::fs;
use std::fs::OpenOptions;
use clap::Parser; use clap::Parser;
use comfy_table::Table; use comfy_table::Table;
use csv::WriterBuilder; use csv::WriterBuilder;
use log::info; use log::info;
use nym_mixnet_contract_common::ExecuteMsg; 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::contract_traits::{NymContractsProvider, PagedMixnetQueryClient};
use nym_validator_client::nyxd::Coin; 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::context::SigningClient;
use crate::utils::pretty_coin; use crate::utils::pretty_coin;
@@ -37,7 +40,7 @@ pub struct Args {
#[derive(Debug)] #[derive(Debug)]
pub struct InputFileRow { pub struct InputFileRow {
pub node_id: String, pub mix_id: String,
pub amount: Coin, pub amount: Coin,
} }
#[derive(Debug)] #[derive(Debug)]
@@ -73,7 +76,7 @@ impl InputFileReader {
} }
rows.push(InputFileRow { rows.push(InputFileRow {
node_id: mix_id, mix_id,
amount: Coin { amount: Coin {
amount: micro_nym_amount, amount: micro_nym_amount,
denom: "unym".to_string(), denom: "unym".to_string(),
@@ -137,10 +140,8 @@ async fn fetch_delegation_data(
let mut pending_delegation_map: HashMap<String, Coin> = HashMap::new(); let mut pending_delegation_map: HashMap<String, Coin> = HashMap::new();
for delegation in delegations { for delegation in delegations {
existing_delegation_map.insert( existing_delegation_map
delegation.node_id.to_string(), .insert(delegation.mix_id.to_string(), Coin::from(delegation.amount));
Coin::from(delegation.amount),
);
} }
// Look for pending delegate / undelegate events which might be of interest to us // 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 { for event in pending_events {
match event.event.kind { match event.event.kind {
// If a pending undelegate tx is found, remove it from delegation map // 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() 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 // If a pending delegation event is found, gather them to consolidate later
PendingEpochEventKind::Delegate { Delegate {
owner, owner,
node_id, mix_id,
amount, amount,
.. ..
} => { } => {
if owner == address.as_ref() { if owner == address.as_ref() {
let mut amount = Coin::from(amount); 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; 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 { for row in &records.rows {
let input_amount = row.amount.amount; let input_amount = row.amount.amount;
let existing_delegation_amount = existing_delegation_map let existing_delegation_amount = existing_delegation_map
.get(&row.node_id) .get(&row.mix_id)
.map_or(0, |coin| coin.amount); .map_or(0, |coin| coin.amount);
match existing_delegation_amount.cmp(&input_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, amount: input_amount - existing_delegation_amount,
denom: row.amount.denom.clone(), denom: row.amount.denom.clone(),
}; };
let node_id = row.node_id.clone().parse::<u32>().unwrap(); let mix_id = row.mix_id.clone().parse::<u32>().unwrap();
delegation_msgs.push((ExecuteMsg::Delegate { node_id }, vec![difference.clone()])); delegation_msgs.push((DelegateToMixnode { mix_id }, vec![difference.clone()]));
delegation_table.add_row(&[ delegation_table.add_row(&[
row.node_id.clone(), row.mix_id.clone(),
pretty_coin(&row.amount), pretty_coin(&row.amount),
pretty_coin(&difference), pretty_coin(&difference),
]); ]);
} }
Ordering::Greater => { 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![]; let coins: Vec<Coin> = vec![];
undelegation_msgs.push((ExecuteMsg::Undelegate { node_id }, coins)); undelegation_msgs.push((UndelegateFromMixnode { mix_id }, coins));
undelegation_table.add_row(&[row.node_id.clone()]); undelegation_table.add_row(&[row.mix_id.clone()]);
if row.amount.amount > 0 { if row.amount.amount > 0 {
delegation_msgs delegation_msgs.push((DelegateToMixnode { mix_id }, vec![row.amount.clone()]));
.push((ExecuteMsg::Delegate { node_id }, vec![row.amount.clone()]));
delegation_table.add_row(&[ delegation_table.add_row(&[
row.node_id.clone(), row.mix_id.clone(),
pretty_coin(&row.amount), pretty_coin(&row.amount),
pretty_coin(&row.amount), pretty_coin(&row.amount),
]); ]);
@@ -4,13 +4,13 @@
use crate::context::SigningClient; use crate::context::SigningClient;
use clap::Parser; use clap::Parser;
use log::info; use log::info;
use nym_mixnet_contract_common::NodeId; use nym_mixnet_contract_common::MixId;
use nym_validator_client::nyxd::contract_traits::{MixnetQueryClient, MixnetSigningClient}; use nym_validator_client::nyxd::contract_traits::{MixnetQueryClient, MixnetSigningClient};
#[derive(Debug, Parser)] #[derive(Debug, Parser)]
pub struct Args { pub struct Args {
#[clap(long)] #[clap(long)]
pub mix_id: Option<NodeId>, pub mix_id: Option<MixId>,
#[clap(long)] #[clap(long)]
pub identity_key: Option<String>, pub identity_key: Option<String>,
@@ -66,7 +66,7 @@ async fn print_delegations(delegations: Vec<Delegation>, client: &SigningClientW
for delegation in delegations { for delegation in delegations {
table.add_row(vec![ table.add_row(vec![
to_iso_timestamp(delegation.height as u32, client).await, to_iso_timestamp(delegation.height as u32, client).await,
delegation.node_id.to_string(), delegation.mix_id.to_string(),
pretty_cosmwasm_coin(&delegation.amount), pretty_cosmwasm_coin(&delegation.amount),
delegation delegation
.proxy .proxy
@@ -93,7 +93,7 @@ async fn print_delegation_events(events: Vec<PendingEpochEvent>, client: &Signin
match event.event.kind { match event.event.kind {
PendingEpochEventKind::Delegate { PendingEpochEventKind::Delegate {
owner, owner,
node_id: mix_id, mix_id,
amount, amount,
proxy, proxy,
.. ..
@@ -110,7 +110,7 @@ async fn print_delegation_events(events: Vec<PendingEpochEvent>, client: &Signin
} }
PendingEpochEventKind::Undelegate { PendingEpochEventKind::Undelegate {
owner, owner,
node_id: mix_id, mix_id,
proxy, proxy,
.. ..
} => { } => {
@@ -4,13 +4,13 @@
use crate::context::SigningClient; use crate::context::SigningClient;
use clap::Parser; use clap::Parser;
use log::info; use log::info;
use nym_mixnet_contract_common::NodeId; use nym_mixnet_contract_common::MixId;
use nym_validator_client::nyxd::contract_traits::{MixnetQueryClient, MixnetSigningClient}; use nym_validator_client::nyxd::contract_traits::{MixnetQueryClient, MixnetSigningClient};
#[derive(Debug, Parser)] #[derive(Debug, Parser)]
pub struct Args { pub struct Args {
#[clap(long)] #[clap(long)]
pub mix_id: Option<NodeId>, pub mix_id: Option<MixId>,
#[clap(long)] #[clap(long)]
pub identity_key: Option<String>, pub identity_key: Option<String>,
@@ -4,13 +4,13 @@
use crate::context::SigningClient; use crate::context::SigningClient;
use clap::Parser; use clap::Parser;
use log::info; use log::info;
use nym_mixnet_contract_common::NodeId; use nym_mixnet_contract_common::MixId;
use nym_validator_client::nyxd::contract_traits::{MixnetQueryClient, MixnetSigningClient}; use nym_validator_client::nyxd::contract_traits::{MixnetQueryClient, MixnetSigningClient};
#[derive(Debug, Parser)] #[derive(Debug, Parser)]
pub struct Args { pub struct Args {
#[clap(long)] #[clap(long)]
pub mix_id: Option<NodeId>, pub mix_id: Option<MixId>,
#[clap(long)] #[clap(long)]
pub identity_key: Option<String>, pub identity_key: Option<String>,
@@ -4,13 +4,13 @@
use crate::context::SigningClient; use crate::context::SigningClient;
use clap::Parser; use clap::Parser;
use log::info; use log::info;
use nym_mixnet_contract_common::NodeId; use nym_mixnet_contract_common::MixId;
use nym_validator_client::nyxd::contract_traits::{MixnetQueryClient, MixnetSigningClient}; use nym_validator_client::nyxd::contract_traits::{MixnetQueryClient, MixnetSigningClient};
#[derive(Debug, Parser)] #[derive(Debug, Parser)]
pub struct Args { pub struct Args {
#[clap(long)] #[clap(long)]
pub mix_id: Option<NodeId>, pub mix_id: Option<MixId>,
#[clap(long)] #[clap(long)]
pub identity_key: Option<String>, pub identity_key: Option<String>,
@@ -36,7 +36,7 @@ pub async fn undelegate_from_mixnode(args: Args, client: SigningClient) {
}; };
let res = client let res = client
.undelegate(mix_id, None) .undelegate_from_mixnode(mix_id, None)
.await .await
.expect("failed to remove stake from mixnode!"); .expect("failed to remove stake from mixnode!");
@@ -4,7 +4,7 @@
use clap::Parser; use clap::Parser;
use log::info; 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::MixnetQueryClient;
use nym_validator_client::nyxd::contract_traits::VestingSigningClient; use nym_validator_client::nyxd::contract_traits::VestingSigningClient;
@@ -13,7 +13,7 @@ use crate::context::SigningClient;
#[derive(Debug, Parser)] #[derive(Debug, Parser)]
pub struct Args { pub struct Args {
#[clap(long)] #[clap(long)]
pub mix_id: Option<NodeId>, pub mix_id: Option<MixId>,
#[clap(long)] #[clap(long)]
pub identity_key: Option<String>, pub identity_key: Option<String>,
@@ -3,7 +3,7 @@
use clap::Parser; use clap::Parser;
use log::info; 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::MixnetQueryClient;
use nym_validator_client::nyxd::contract_traits::VestingSigningClient; use nym_validator_client::nyxd::contract_traits::VestingSigningClient;
@@ -12,7 +12,7 @@ use crate::context::SigningClient;
#[derive(Debug, Parser)] #[derive(Debug, Parser)]
pub struct Args { pub struct Args {
#[clap(long)] #[clap(long)]
pub mix_id: Option<NodeId>, pub mix_id: Option<MixId>,
#[clap(long)] #[clap(long)]
pub identity_key: Option<String>, pub identity_key: Option<String>,
@@ -5,7 +5,6 @@ use clap::{Args, Subcommand};
pub mod bond_gateway; pub mod bond_gateway;
pub mod gateway_bonding_sign_payload; pub mod gateway_bonding_sign_payload;
pub mod nymnode_migration;
pub mod settings; pub mod settings;
pub mod unbond_gateway; pub mod unbond_gateway;
pub mod vesting_bond_gateway; pub mod vesting_bond_gateway;
@@ -32,6 +31,4 @@ pub enum MixnetOperatorsGatewayCommands {
VestingUnbond(vesting_unbond_gateway::Args), VestingUnbond(vesting_unbond_gateway::Args),
/// Create base58-encoded payload required for producing valid bonding signature. /// Create base58-encoded payload required for producing valid bonding signature.
CreateGatewayBondingSignPayload(gateway_bonding_sign_payload::Args), 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> // Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
use crate::context::SigningClient;
use clap::Parser; use clap::Parser;
use cosmwasm_std::Uint128; use cosmwasm_std::Uint128;
use log::{info, warn}; use log::{info, warn};
use nym_contracts_common::signing::MessageSignature; use nym_contracts_common::signing::MessageSignature;
use nym_mixnet_contract_common::{ use nym_mixnet_contract_common::{Coin, MixNodeCostParams, Percent};
Coin, NodeCostParams, Percent, DEFAULT_INTERVAL_OPERATING_COST_AMOUNT,
DEFAULT_PROFIT_MARGIN_PERCENT,
};
use nym_network_defaults::{ use nym_network_defaults::{
DEFAULT_HTTP_API_LISTENING_PORT, DEFAULT_MIX_LISTENING_PORT, DEFAULT_VERLOC_LISTENING_PORT, 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::contract_traits::MixnetSigningClient;
use nym_validator_client::nyxd::CosmWasmCoin; use nym_validator_client::nyxd::CosmWasmCoin;
use crate::context::SigningClient;
#[derive(Debug, Parser)] #[derive(Debug, Parser)]
pub struct Args { pub struct Args {
#[clap(long)] #[clap(long)]
@@ -43,7 +42,7 @@ pub struct Args {
pub version: String, pub version: String,
#[clap(long)] #[clap(long)]
pub profit_margin_percent: Option<u64>, pub profit_margin_percent: Option<u8>,
#[clap( #[clap(
long, long,
@@ -86,18 +85,14 @@ pub async fn bond_mixnode(args: Args, client: SigningClient) {
let coin = Coin::new(args.amount, denom); let coin = Coin::new(args.amount, denom);
let cost_params = NodeCostParams { let cost_params = MixNodeCostParams {
profit_margin_percent: Percent::from_percentage_value( profit_margin_percent: Percent::from_percentage_value(
args.profit_margin_percent args.profit_margin_percent.unwrap_or(10) as u64,
.unwrap_or(DEFAULT_PROFIT_MARGIN_PERCENT),
) )
.unwrap(), .unwrap(),
interval_operating_cost: CosmWasmCoin { interval_operating_cost: CosmWasmCoin {
denom: denom.into(), denom: denom.into(),
amount: Uint128::new( amount: Uint128::new(args.interval_operating_cost.unwrap_or(40_000_000)),
args.interval_operating_cost
.unwrap_or(DEFAULT_INTERVAL_OPERATING_COST_AMOUNT),
),
}, },
}; };
@@ -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_bin_common::output_format::OutputFormat;
use nym_contracts_common::Percent; use nym_contracts_common::Percent;
use nym_mixnet_contract_common::{ use nym_mixnet_contract_common::{
construct_legacy_mixnode_bonding_sign_payload, NodeCostParams, construct_legacy_mixnode_bonding_sign_payload, MixNodeCostParams,
DEFAULT_INTERVAL_OPERATING_COST_AMOUNT, DEFAULT_PROFIT_MARGIN_PERCENT,
}; };
use nym_network_defaults::{ use nym_network_defaults::{
DEFAULT_HTTP_API_LISTENING_PORT, DEFAULT_MIX_LISTENING_PORT, DEFAULT_VERLOC_LISTENING_PORT, DEFAULT_HTTP_API_LISTENING_PORT, DEFAULT_MIX_LISTENING_PORT, DEFAULT_VERLOC_LISTENING_PORT,
@@ -41,7 +40,7 @@ pub struct Args {
pub version: String, pub version: String,
#[clap(long)] #[clap(long)]
pub profit_margin_percent: Option<u64>, pub profit_margin_percent: Option<u8>,
#[clap( #[clap(
long, long,
@@ -76,18 +75,14 @@ pub async fn create_payload(args: Args, client: SigningClient) {
let coin = Coin::new(args.amount, denom); let coin = Coin::new(args.amount, denom);
let cost_params = NodeCostParams { let cost_params = MixNodeCostParams {
profit_margin_percent: Percent::from_percentage_value( profit_margin_percent: Percent::from_percentage_value(
args.profit_margin_percent args.profit_margin_percent.unwrap_or(10) as u64,
.unwrap_or(DEFAULT_PROFIT_MARGIN_PERCENT),
) )
.unwrap(), .unwrap(),
interval_operating_cost: CosmWasmCoin { interval_operating_cost: CosmWasmCoin {
denom: denom.into(), denom: denom.into(),
amount: Uint128::new( amount: Uint128::new(args.interval_operating_cost.unwrap_or(40_000_000)),
args.interval_operating_cost
.unwrap_or(DEFAULT_INTERVAL_OPERATING_COST_AMOUNT),
),
}, },
}; };
@@ -5,10 +5,10 @@ use clap::{Args, Subcommand};
pub mod bond_mixnode; pub mod bond_mixnode;
pub mod decrease_pledge; pub mod decrease_pledge;
pub mod families;
pub mod keys; pub mod keys;
pub mod migrate_vested_mixnode; pub mod migrate_vested_mixnode;
pub mod mixnode_bonding_sign_payload; pub mod mixnode_bonding_sign_payload;
pub mod nymnode_migration;
pub mod pledge_more; pub mod pledge_more;
pub mod rewards; pub mod rewards;
pub mod settings; pub mod settings;
@@ -33,6 +33,8 @@ pub enum MixnetOperatorsMixnodeCommands {
Rewards(rewards::MixnetOperatorsMixnodeRewards), Rewards(rewards::MixnetOperatorsMixnodeRewards),
/// Manage your mixnode settings stored in the directory /// Manage your mixnode settings stored in the directory
Settings(settings::MixnetOperatorsMixnodeSettings), Settings(settings::MixnetOperatorsMixnodeSettings),
/// Operations for mixnode families
Families(families::MixnetOperatorsMixnodeFamilies),
/// Bond to a mixnode /// Bond to a mixnode
Bond(bond_mixnode::Args), Bond(bond_mixnode::Args),
/// Unbond from a mixnode /// Unbond from a mixnode
@@ -53,6 +55,4 @@ pub enum MixnetOperatorsMixnodeCommands {
DecreasePledgeVesting(vesting_decrease_pledge::Args), DecreasePledgeVesting(vesting_decrease_pledge::Args),
/// Migrate the mixnode to use liquid tokens /// Migrate the mixnode to use liquid tokens
MigrateVestedNode(migrate_vested_mixnode::Args), 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 // SPDX-License-Identifier: Apache-2.0
use crate::context::SigningClient; use crate::context::SigningClient;
use crate::validator::mixnet::operators::nymnode;
use clap::Parser; 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)] #[derive(Debug, Parser)]
pub struct Args { pub struct Args {
@@ -20,14 +24,62 @@ pub struct Args {
pub interval_operating_cost: Option<u128>, pub interval_operating_cost: Option<u128>,
} }
pub async fn update_cost_params(args: Args, client: SigningClient) -> anyhow::Result<()> { pub async fn update_cost_params(args: Args, client: SigningClient) {
// the below can handle both, nymnode and legacy mixnode let denom = client.current_chain_details().mix_denom.base.as_str();
nymnode::settings::update_cost_params::update_cost_params(
nymnode::settings::update_cost_params::Args { fn convert_to_percent(value: u64) -> Percent {
profit_margin_percent: args.profit_margin_percent, Percent::from_percentage_value(value).expect("Invalid value")
interval_operating_cost: args.interval_operating_cost, }
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 cosmwasm_std::Uint128;
use log::{info, warn}; use log::{info, warn};
use nym_contracts_common::signing::MessageSignature; use nym_contracts_common::signing::MessageSignature;
use nym_mixnet_contract_common::{ use nym_mixnet_contract_common::{Coin, MixNodeCostParams};
Coin, NodeCostParams, DEFAULT_INTERVAL_OPERATING_COST_AMOUNT, DEFAULT_PROFIT_MARGIN_PERCENT,
};
use nym_mixnet_contract_common::{MixNode, Percent}; use nym_mixnet_contract_common::{MixNode, Percent};
use nym_network_defaults::{ use nym_network_defaults::{
DEFAULT_HTTP_API_LISTENING_PORT, DEFAULT_MIX_LISTENING_PORT, DEFAULT_VERLOC_LISTENING_PORT, DEFAULT_HTTP_API_LISTENING_PORT, DEFAULT_MIX_LISTENING_PORT, DEFAULT_VERLOC_LISTENING_PORT,
@@ -42,7 +40,7 @@ pub struct Args {
pub version: String, pub version: String,
#[clap(long)] #[clap(long)]
pub profit_margin_percent: Option<u64>, pub profit_margin_percent: Option<u8>,
#[clap( #[clap(
long, 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 coin = Coin::new(args.amount, denom);
let cost_params = NodeCostParams { let cost_params = MixNodeCostParams {
profit_margin_percent: Percent::from_percentage_value( profit_margin_percent: Percent::from_percentage_value(
args.profit_margin_percent args.profit_margin_percent.unwrap_or(10) as u64,
.unwrap_or(DEFAULT_PROFIT_MARGIN_PERCENT),
) )
.unwrap(), .unwrap(),
interval_operating_cost: CosmWasmCoin { interval_operating_cost: CosmWasmCoin {
denom: denom.into(), denom: denom.into(),
amount: Uint128::new( amount: Uint128::new(args.interval_operating_cost.unwrap_or(40_000_000)),
args.interval_operating_cost
.unwrap_or(DEFAULT_INTERVAL_OPERATING_COST_AMOUNT),
),
}, },
}; };
@@ -6,7 +6,6 @@ use clap::{Args, Subcommand};
pub mod gateway; pub mod gateway;
pub mod identity_key; pub mod identity_key;
pub mod mixnode; pub mod mixnode;
pub mod nymnode;
#[derive(Debug, Args)] #[derive(Debug, Args)]
#[clap(args_conflicts_with_subcommands = true, subcommand_required = true)] #[clap(args_conflicts_with_subcommands = true, subcommand_required = true)]
@@ -18,11 +17,9 @@ pub struct MixnetOperators {
#[allow(clippy::large_enum_variant)] #[allow(clippy::large_enum_variant)]
#[derive(Debug, Subcommand)] #[derive(Debug, Subcommand)]
pub enum MixnetOperatorsCommands { pub enum MixnetOperatorsCommands {
/// Manage your Nym Node /// Manage your mixnode
Nymnode(nymnode::MixnetOperatorsNymNode),
/// Manage your legacy mixnode
Mixnode(mixnode::MixnetOperatorsMixnode), Mixnode(mixnode::MixnetOperatorsMixnode),
/// Manage your legacy gateway /// Manage your gateway
Gateway(gateway::MixnetOperatorsGateway), Gateway(gateway::MixnetOperatorsGateway),
/// Sign messages using your private identity key /// Sign messages using your private identity key
IdentityKey(identity_key::MixnetOperatorsIdentityKey), 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),
}

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